6502 Programmieren, Teil 13#
von Uwe Röder
In dieser Folge möchte ich Ihnen zeigen, wie man einen Input in Maschinensprache realisiert und wie ein Programm gegen RESET geschützt werden kann.
Zuerst zum Input. Wie üblich für alle Input/Output - Operationen, ermöglicht die CIO natürlich auch die Ein- und Ausgaben an den Editor. Nach Einschalten des Computers und nach jedem RESET wird dem Editor der Kanal 0 zugewiesen. Um nun einen Input auszuführen, müssen wir also nicht erst einen Kanal öffnen.
Für einen Text-Input benutzen wir das CIO-Kommando 5 für GET-Record. Dies bedeutet, daß die Eingabe-Zeile solange editiert werden kann bis Return gedrückt wird. Bei dem Druck auf Return werden maximal soviele Zeichen wie in ICBLEN festgelegt ab ICBADR abgelegt.
Es müssen also folgende Werte im IO-Kontrollblock gesetzt werden:
ICCOM $342 :5 für Get Record ICBADR $344/$345 :Adresse für Daten ICBLEN $348/$349 :maximale Anzahl
Beispiel:
00010 .LI OFF 00020 ------------------------------ 00030 ICCOM .EQ $342 00040 ICBADR .EQ $344 00050 ICBLEN .EQ $348 00060 CIO .EQ $E456 00070 Y .EQ $680 00080 ------------------------------ 00090 S LDX #0 ; KANAL 0 00100 LDA #5 ; GET RECORD 00110 STA ICCOM,X 00120 LDA #20 ; LEN=20 00130 STA ICBLEN,X 00140 LDA #0 00150 STA ICBLEN+1 00160 STA ICBADR,X 00170 LDA #6 ; ADR=$600 00180 STA ICBADR+1,X 00190 JSR CIO 00200 ------------------------------ 00210 OUTPUT LDA #$9B 00220 JSR PUTCHAR 00230 LDY #0 00240 .1 LDA $600,Y 00250 STY Y 00260 JSR PUTCHAR 00270 LDY Y 00280 INY 00290 CMP #$9B 00300 BNE .1 00310 RTS 00320 ------------------------------ 00330 PUTCHAR TAX 00340 LDA $E407 00350 PHA 00360 LDA $E406 00370 PHA 00380 TXA 00390 RTS 00400 ------------------------------
Mehr Aufwand ist nicht erforderlich. Die Routine Output dient hier nur dazu, um die Daten wieder mit hilfe des Editors auszugeben, um die korrekte Funktion zu zeigen.
Wenn Sie Zahleneingaben haben, müssen Sie je nachdem was Sie mit den Zahlen machen wollen die Floating-Point Routinen benutzen. Sie können den ASCII-Text umwandeln in Zahlen im 6-Byte Floating-Point-Format und diese Zahlen dann wieder in das zwei Byte Integer-Format verwandeln. Wie dies geht wurde in einer der vorherigen Ausgaben des Magazins erklärt, weshalb ich an dieser Stelle nicht weiter darauf eingehe.
Nun zum Thema RESET-Schutz.
Es gibt einige wichtige Speicherstellen in Bezug auf den Reset-Schutz. Dies sind folgende:
$09 Boot? $0A/$0B DOSVEC $0244 COLDSTDie letzte Adresse kennen wohl die meisten User. Ist der Inhalt dieser Adresse ungleich 0, so wird beim Drücken von Reset neu gebootet.
Um ein Programm vor Reset zu schützen ist also erst einmal unbedingt notwendig, diese Speicherstelle auf 0 zu setzen. Steht in der Speicherstelle Boot? eine 1, so wird nach einem Druck auf RESET der Vektor DOSVEC $A/$B benutzt. Diesen Vektor müssen wir also benutzen, damit unser Programm nach einem RESET wieder fortgesetzt wird.
Wenn das zu schützende Programm kein DOS benötigt, so können wir in DOSVEC einfach die Startadresse des Programms eintragen, $0244 gleich 0 und $09 gleich 1 setzen. Jeder Druck auf RESET startet das Programm dann von neuem.
Bei Programmen, die ein DOS benötigen, ist dies nicht so leicht, da das DOS nach jedem Reset selbst neu initialisiert werden muß und sich dazu eben unseres Vektors DOSVEC bedient.
Wir müssen also zuerst den Inhalt von DOSVEC in eine Zero-Page Adresse retten und dann später in unserer Reset-Routine dafür sorgen, daß ein JSR an diese Adresse ausgeführt wird.
Desweiteren müssen wir darauf achten, daß die Routine, die den Inhalt von DOSVEC rettet, nur genau einmal, nämlich ganz zu Beginn des Programmes, aufgerufen wird und dann nie wieder, auch nicht nach einem RESET. In einem solchen Falle würde nämlich unser eigener RESET Vektor geschützt werden. Die Reset-Routine würde sich dann immer wieder selbst aufrufen und das DOS wäre verloren. Beispiel:
00010 .LI OFF 00020 ------------------------------ 00030 DOSV .EQ $D8 00040 ------------------------------ 00050 START LDA $C 00060 STA DOSV 00070 LDA $D 00080 STA DOSV+1 00090 LDA #0 00100 STA $244 00110 LDA #1 00120 STA 9 00150 LDA #RESET 00160 STA $C 00170 LDA /RESET 00180 STA $D 00190 LDA DOSV 00200 BNE S 00210 LDA DOSVEC+1 00220 BNE S 00270 .1 LDA #S 00280 STA $C 00290 LDA /S 00300 STA $D 00290 LDA /S 00300 STA $D 00310 JMP S 00320 ------------------------------ 00330 RESET JSR DOSINIT 00340 JMP S 00350 ------------------------------ 00360 DOSINIT JMP (DOSV) 00370 ------------------------------ 00380 S ... Start des eigentlichen Programmes.Eine solche Routine könnte dem eigentlichen Programm vorangestellt werden, um es wirksam zu schützen.
Hier wird erst der Inhalt von DOSVEC gesichert und dann DOSVEC auf eine RESET-Routine gesetzt, die erst das "alte" DOS-Init aufruft und dann zum eigentlichen Programmstart S springt.