6502 Programmieren - Teil 14#
von Uwe Röder#
In dieser Folge möchte ich Ihnen die Programmierung von Interrupts zeigen, die ja eh nur in Maschinensprache zu realisieren ist.
Es ist zwar in meiner Artikelserie über das Betriebssystem und die Hardwarefähigkeiten der Ataris auch schon auf diese Thema eingegangen worden, doch rechtfertigt der enorme Nutzen der Interrupts die mehrmalige Behandlung dieses Themas.
Da ich hier sowohl auf den DLI, die VBIs und den Timer-Interrupt eingehen möchte, werde ich immer nur kurze allgemein gefasste Beispiele geben und die Interrupts nur einführend vorstellen.
Zuerst zu den einfachen Interrupts.
Dies sind erst einmal die beiden Vertical Blank Interrupts. Ein solcher Interrupt wird jedesmal nach dem Aufbau eines Bildschirms also immer nach 1/50 Sekunde ausgeführt.
Es gibt, wie gesagt, zwei verschiedene VBIs, den Immediate und den Deferred VBI. Der Immediate VBI wird immer, auch während zeitkritischer Operationen durchgeführt. Im Gegensatz dazu wird der deferred VBI bei zeitkritischen Operationen (wenn CRITIC $42/66 <>0) nicht ausgeführt.
Um einen VBI zu setzen muss der ACCU eine Kennung für die Art des VBI enthalten. 6=immediate 7=deferred
Das X-Register muss das High-Byte und das Y-Register das Low-Byte der Adresse der Interrupt-Routine enthalten. Dann braucht nur noch ein JSR nach SETVBV ($E45C) ausgeführt zu werden. Bei den VBI-Routinen muss nicht, wie bei einem DLI, darauf geachtet werden, dass die Register bei Eintritt und Verlassen der Routine die gleichen Inhalte aufweisen. Dafür muss man aber anstelle des RTI-Befehls als Endkennung der Interrupt-Routine zu einem je nach Interrupt verschiedenen Rücksprungvektor springen.
Immediate VBI: SYSVBV $E45F
Deferred VBI: XITVBV $E462
Dies sieht dann im Programm so aus:
00010 .LI OFF 00020 ------------------------------ 00030 START LDA #6 ; IMMEDIATE 00040 LDX /IVBI 00050 LDY #IVBI 00060 JSR $E45C 00070 ------------------------------ 00080 ; IMMEDIATE IST JETZT GESETZT 00090 ------------------------------ 00100 LDA #7 ; DEFFERED 00110 LDX /DVBI 00120 LDY #DVBI 00130 JSR $E45C 00140 ------------------------------ 00150 ; DEFERRED IST JETZT GESETZT 00160 ; 00170 ; FORTFUEHRUNG DES HAUPTPROG. 00180 ; ODER EINFACH RTS 00190 ------------------------------ 00200 RTS 00210 ------------------------------ 00220 IVBI ... ;IMMEDIATE-ROUTINE 00230 ... 00240 ... 00250 JMP $E45F ;ENDE 00260 ; WICHTIG !!! 00270 ------------------------------ 00280 DVBI ... ;DEFERRED-ROUTINE 00290 ... 00300 ... 00310 JMP $E462 ;ENDE 00320 ; WICHTIG !!! 00330 ------------------------------Soviel zu den VBIs. Wenden wir uns jetzt den fünf SYSTEM-Timern zu. Diese Timer bestehen aus je zwei Bytes und werden jede 1/50 Sekunde um eins vermindert.
Der erste Timer ist dabei der einzige, der auch während zeitkritischer Operationen vermindert wird.
Die ersten zwei Timer verfügen über einen Sprungvektor durch den gesprungen wird wenn der Timer von 1 auf 0 herunter gezählt wurde. Die dadurch ausgelöste Routine muss mit einem RTS enden. Bei den anderen drei Timern wird dafür nur ein Flag gesetzt. Die Handhabung ist damit also klar:
- Sprungvektor einrichten oder Flag=0
- Timer setzen
Die Adressen der Timer lauten wie folgt:
CDTMV1 $218/$219
CDTMV2 $21A/$21B
CDTMV3 $21C/$21D
CDTMV4 $21E/$21F
CDTMV5 $220/$221
Die beiden Sprungvektoren für die ersten zwei Timer sind:
CDTMA1 $226/$227
CDTMA2 $228/$229
Die drei Flags für die Timer 3 bis 5 sind:
CDTMF3 $22A
CDTMF4 $22C
CDTMF5 $22E
Die einzelnen Timer können auch über die schon oben erwähnte Routine SETVBV gesetzt werden. Der ACCU muss dafür die Timernummer (1-5), das X-Register das High-Byte und das Y-Register das Low-Byte der Zeitspanne in 1/50 Sekunden enthalten.
00010 .LI OFF 00020 ------------------------------ 00030 SETVBV .EQ $E45C 00040 CDTMA2 .EQ $228 00050 ------------------------------ 00060 S LDA #TIM 00070 STA CDTMA2 00080 LDA /TIM 00090 STA CDTMA2+1 00100 LDA #2 00110 LDX #1 ;10 SEK. 00120 LDY #244 00130 JSR SETVBV 00140 RTS 00150 ------------------------------ 00160 TIM LDA #$30 00170 STA $2C6 00180 RTS 00190 ------------------------------
Bei diesem Beispiel kehrt die Kontrolle sofort nach Ausführung des kurzen Hauptprogramms wieder an den Assembler zurück, so dass man wieder etwas anderes machen kann. Nach 10 Sekunden ändert sich dann 'spontan' die Hintergrundfarbe von blau in rot.
Der letzte und wohl auch am häufigsten verwendete Interrupt, den ich hier besprechen möchte, ist der Display List Interrupt, kurz DLI. Mit Hilfe des DLI können wir bekanntlich während des Bildschirmaufbaus die Farben ändern oder den Zeichensatz wechseln.
Der Vektor für den DLI ist VDSLST $200/$201. Um einen DLI zu nutzen muss in der Display List ($230/$231) in der entsprechenden Zeile das höchstwertige Bit (7) gesetzt werden. Dies kann durch eine "Oderierung" mit #$80 geschehen. Des weiteren muss in NMIEN $D40E ebenfalls Bit 7 gesetzt werden. Dies erreicht man durch Einschreiben von #$C0. Um einen DLI einzurichten muss man erst den Interrupt sperren (NMIEN=0), dann müssen die Adresse der DLI-Routine in VDSLST eingetragen und die entsprechenden Bits in der Display List gesetzt werden. Der letzte Schritt besteht nun darin den DLI freizugeben (NMIEN=#$C0).
Bei der DLI-Routine ist zu beachten, dass die drei Register (A,X,Y) vor und nach Eintritt der Routine die gleichen Inhalte haben. Man muss diese Inhalte also direkt am Anfang der Routine auf dem Stapel ablegen und später am Ende der Routine wieder einlesen. Die DLI Routine muss mit einem RTI enden.
Beispiel:
00010 .LI OFF 00020 ------------------------------ 00030 NMIEN .EQ $D40E 00040 VDSLST .EQ $200 00050 SDLSTL .EQ $230 00060 COLOR .EQ $D018 00070 DLV .EQ $D0 00080 WSYNC .EQ $D40A 00090 ------------------------------ 00100 START LDA #0 00110 STA NMIEN 00120 LDA #DLI 00130 STA VDSLST 00140 LDA /DLI 00150 STA VDSLST+1 00160 LDA SDLSTL 00170 STA DLV 00180 LDA SDLSTL+1 00190 STA DLV+1 00200 LDY #15 00210 LDA (DLV),Y 00220 ORA #$80 00230 STA (DLV),Y 00240 LDA #$C0 00250 STA NMIEN 00260 RTS 00270 ------------------------------ 00280 DLI PHA ;REGISTER 00290 TXA ;RETTEN 00300 PHA 00310 TYA 00320 PHA 00330 ------------------------------ 00340 LDA #$30 00350 STA WSYNC ;SYNCHRON. 00360 STA COLOR ;FARBE 00370 ------------------------------ 00380 PLA ;REGISTER 00390 TAY ;ZURUECKHOLEN 00400 PLA 00410 TAX 00420 PLA 00430 RTI 00440 ------------------------------
So, das war's dann wieder mal.
Ihr Uwe Röder
CSM 09/1989
Der Artikel entstammt der Kursreihe „6502 Programmieren“ des Compy Shop Diskettenmagazins. Die Kursreihe besteht aus 14 Kursen, die im Laufe des Jahres 2011 in unregelmäßigen Abständen einzeln veröffentlicht werden, bzw. anschließend als Zusammenzug als ABBUC-Buch „6502 Programmieren“ erscheinen.
Koordination: Volkert Barr (volkert@nivoba.de)
Version 1.1 / 2011-01-23