Kommen wir nun zu dem Programm selbst. Hier ist der kommentierte Source-Code:
**************************************** start sei IRQs sperren ldx #<(irq) IRQ-Vektor ldy #>(irq) auf neue stx $0314 IRQ-Routine sty $0315 verbiegen. ldx #<(nmi) NMI-Vektor ldy #>(nmi) auf neue stx $0318 NMI-Routine sty $0319 verbiegen.
ldx #$83 Timer A und B als stx cia1+13 Interruptquelle für stx cia2+13 beide CIAs setzen
lda #00 Timer B von sta cia1+6 CIA1 sta cia1+7 und sta cia2+6 CIA2 mit dem Wert sta cia2+7 0 initialisieren. ldy #$90 Timer A von CIA2 sta cia2+4 initialisieren sty cia2+5 ($9000=27 IRQs/s) lda #$21 Trigger=CNT und "T mer Start" sta cia1+15 in Control-Regist sta cia2+15 für Timer B von CIA1 und CIA2. lda #$81 Timer A von CIA2 sta cia2+14 mit SysTakt als Trigger starten lda #00 Bildschirm- sta 53280 farben lda #11 setzen sta 53281 und lda #<(text) Begrüßungs- ldy #>(text) Text jsr strout ausgeben. lda #01 Sprite 0 sta vic+39 als sta vic+21 Maus- lda #150 pfeil sta vic ini- sta vic+1 tiali- lda #41 sieren. sta 2040 cli IRQs freigeben rts und ENDE. **************************************** nmi pha Alle txa Prozessorregister pha erstmal tya auf Stapel pha retten. cli IRQs freigeben. lda $dd01 Datenport sporadis eor #$ff laden und invertie sta mem merken. lda cia2+13 ICR von CIA2 holen and #$02 Bit 1 isolieren beq buttons Wenn =0, dann war Timer A der NMI- Auslöser, also Knopfabfrage. lda mem Sonst H-Bewegung.. and #$08 Bit für HQ-Signal aus Datenport iso lieren beq moveleft Wenn 0 war ->links bne moveright Wenn 1 war ->rechs buttons lda mem Aus Datenport die and #$30 Bits 4 und 5 (Mau knöpfe) isolieren beq bye Wenn =0, dann war ner gedrückt. and #$20 Sonst Bit5 isolier beq leftone Wenn =0, war der linke gedrückt lda #42 Spritepointer ldx #01 und Timerwert lad l8 sta 2040 und setzen. stx cia1+6 (Timerwert in BEI stx cia2+6 CIAs!) jmp bye NMI beenden. leftone lda #41 Spritepointer und ldx #00 Timerwert für link jmp l8 Taste setzen **************************************** irq lda cia1+13 ICR von CIA1 laden and #$02 Bit 1 isolieren bne ok Wenn =1, dann wars ein Maus-IRQ jmp sysirq Sonst auf SysIRQ springen ok cli IRQs freigeben lda $dd01 Datenport laden und eor #$ff invertieren. and #$04 Bit für VQ-Signal isolieren beq moveup Wenn 0 war -> hoch bne movedown Wenn 1 war -> runter ****************************************
Hier nun noch einige Erläuterungen: 1)Wie Sie sehen, müssen wir bei NMIs den Prozessorregister "von Hand" auf den Stapel retten. Bei NMIs geschieht dies nicht durch eine Routine im Betriebs- system, so wie es bei den IRQs der Fall war. 2)Nachdem eine der beiden Interrupt- routinen aufgerufen wurde, wird so früh wie möglich das IRQ-Flag wieder gelöscht und die IRQs zugelassen. Das ist deshalb so wichtig, weil die IRQs beim Auftreten eines Interrupts (sei das ein IRQ oder ein NMI) gesperrt werde.Befindet sich nun aber der Rech- ner gerade in einem NMI, während die Maus der Vertikalen bewegt wird, so wird kein IRQ ausgelöst, weil dieser ja noch gesperrt ist. Um das doch noch zu ermöglichen müssen wir den IRQ ex- plizit freigeben. Bei NMIs brauchen wir darauf nicht zu achten, weil NMIs ja nicht maskierbar sind.Das heißt,daß ein NMI immer einen NMI unterbrechen kann! 3)Denken Sie bitte nach wie vor daran daß die Daten der Datenports inver- tiert in den CIA-Registern stehen. Wir müssen sie beim Lesen deshalb gleich nochmal invertieren.Das ist gerade bei der Maustastenabfrage sehr wichtig, weshalb der Datenport in jedem Fall erst einmal invertiert wird,bevor eine Entscheidung getroffen wird, woher der NMI überhaupt kam. Bei der Vertikalabfrage, hätte ich den Datenport nicht unbedingt invertieren müssen. Da hier lediglich nur ein eim- ziges Bit abgefragt wird,hätte ich die Branchbefehle zu den Bewegungsroutinen ebenso vertauschen k nnen. Der Voll- ständigkeit halber wird hier der Wert jedoch ebenfalls invertiert. 4)Sicher hat Sie die merkwürdige Maus- button abfrage etwas verwirrt.Ich habe hier noch eine kleine Funktion einge- baut die durch die Art unserer Abfrage ganz einfach zu programmieren wurde. Zunächst einmal wird durch den Druck auf einen der Mausknöpfe der Sprit- pointer zwischen den Spriteblöcken 00 und 42 hin- und hergeschaltet. Dies nur, um Ihnen die Mausbuttonabfrage optisch zu signalisieren. Zusätzlich wird, je nach dem welchen Knopf sie noch drücken, ein anderer Wert in die Timer-Register geschrieben.Drücken Sie die linke Taste,so ist das der Wert 0, wie wir es für die Abfrage ja schon vereinbart hatten. Drücken Sie jedoch die rechte Maustaste, so wird der Wert 1 in die Timer geladen. Durch diesen kleinen, aber effektiven Trick können wir die Mausauflösung halbieren. Da- durch, daß nun 2 Impulse von der Maus kommen müssen, bis ein Interrupt auf- tritt müssen Sie die Maus doppelt wait über den Tisch bewegen, um den Maus- pfeil eine bestimmte Strecke weg zu bewegen.Das kann oftmals kanz nützlich sein, z.B.wenn man genau zeichnen muß. Wenn Sie brigens den Wert 2 die Timer schreiben, so verkleinet sich die Auf- lösung um ein Drittel und so fort... 5)Achten Sie bitte auch auf die Abfragen in den Interruptroutinen, von welchen Quelle der Interrupt kam. Im ICR sind dann n mlich die entsprechenden Bits die auch beim Einstellen der Interrup- quellen benutzt werden gesetzt.So kön- nen wir also unterscheiden, von wo ein Interrupt kam. 6)Die Routinen MOVELEFT, MOVERIGHT,MOVE- UP und MOVEDOWN sind Routinen die den Mauspfeil bewegen und sollen hier nicht näher erläutert werden. Sie kön- nen Sie sich aber gerne im Source- Listing "AM GA-MAUS3.SRC" auf dieser MD anschauen 7)Das Label ENDIRQ enthüllt die Adresse $EA7E. Ab dieser Adresse stehen im Be- triebssystem die Befehle, mit denen jeder Interrupt (auch NMIs) beendet werden.Es werden einfach die Prozesor- register wieder vom Stapel geholt. Um unsere eigenen Interrupts zu be- enden springe ich also der Einfachheit halber gleich diese Adresse an. Natürlich brauchen Sie zum Betrieb der neuen Mausabfrage einen neuen Adapter- stecker. Damit das nicht allzu umständ- lich wird, habe ich die Belegungen im Großen und Ganzen so gelassen wie sie beim erst Adapterstecker waren. Sie müssen lediglich zwei Leitungen umlöten: * Das V-Signal (Pin 1 an der Joyport- buchse) kommt jetzt an CNT1 (=Pin 4 am Userport - vorher Pin C). * Das H-Signal (Pin 2 an der Joyport- buchse) kommt jetzt an CNT2 (=Pin 6 am Userport - vorher Pin D). Schließen Sie den neuen Stecker nun bei abgeschaltetem 64er am Userport an, und stecken Sie eine AMIGA-Maus am anderen Ende ein. Jetzt können Sie das Programm "AMIGA-MAUS3"von dieser MD laden und mit RUN starten. Wie Sie sehen, können Sie nun auch weiterhin Eingaben machen, da der Cursor weiterhin blinkt. Denken Sie nun daran, daß es bei Diskettenzugriffen Probleme geben wird, da die NMIs den Datenverkehr stören(sollten Sie noch aus dem ersten Teilen dieses Kurses wissen). In solchen Fällen ist es ratsam die Ab- frage doch abzuschalten (z.B. indem man die Timer einfach anhält, oder sie als Interruptquellen sperrt). Zum Schluß möchte ich Ihnen noch eine weitere Funktion der CIAs erklären. Nur mit dem Userport erhält sie überhaupt einen Sinn, weshalb ich sie bis jetzt auslassen mußte. Vielleicht erinnern Sie sich noch daran, daß das Register 12 einer CIA das soge- nannte "Serial-Data-Register" ist. Mit diesem Register kann über die SP-Leitung (die ja von beiden CIAs am Userport an- liegt) ein einfacher serieller Datenaus- tausch mit einem anderen Rechner(im ein- fachsten Fall ebenfalls ein 64'er statt- finden. Das kann sehr nützlich sein wenn man z.B. ein Spiel programmieren möchte, bei dem zwei Spieler an jeweils einem eigenen Rechner gegeneinander spielen Wenn das Spielprogramm also Daten über die Tätigkeiten und Bewegungen des ande- ren Spielers benötigt. Über das SD-Register wird dieser Daten- austausch stark vereinfacht und ist fast noch unkomplzierter, als wenn man sich der normal Seriellen Schnittstelle (RS232) des Betriebssystems bedient. Bei der Datenübertragung müssen wir un- terscheiden, ob die SP-Leitung nun auf Ein oder Ausgang geschaltet ist. Dies wird mit Bit 6 des Control-Registers- Timer A (Reg.14) angegeben.Ist es auf 1, so ist SP auf Ausgang, ist es auf 0, so ist SP auf Eingang geschaltet. Je nach Betriebsart verhält sich die Benutzung von SDR wie folgt: * Wenn SP Ausgang ist, so wird ein Wert, der in das SDR geschrieben wird mit der halben Unterlauffrequenz von Timer A in den entsprechenden CIA an SP "herausgesch ben". Das heißt, daß der Wert Bit für Bit, bei jedem Timerunter lauf an SP e scheint. Nach 8 Unter- läufen ist SDR wi der leer und es wird ein Interrupt ausgelöst. Bit3 im ICR zeigt an, daß der Interrupt von dem leeren SDR-Regist kommt. * Wenn SP Eingang ist, so wird mit jeder steigenden Flanke an CNT der entspre- chende CIA der Wert,der gerade anliegt (0 oder 1) in ein internes Schiebere- gister übernommen. Ist dies Mal ge- schehen, so wird der Wert in das SDR übertragen und ebenfalls ein Interrupt ausgelöst.Hier erkennt man ebefalls an Bit 3 im ICR, daß das SDR voll ist und ausgelesen werden kann. Kombiniert man das Ganze jetzt noch mit der Möglichkeit, daß die CIA bei einem Timerunterlauf ein Signal an PB6 anlegen kann,so kann man sehr einfach Daten aus- tauschen. Möchten Sie z.B.Daten an einen anderen C64 senden, so müssen Sie sich ein Kabel bauen, daß die Userporte der beiden Rechner miteinander verbindet. Dabei sollte der SP-Ausgang von Rechnern mit dem SP-Eingang von Rechner 2 verbun- den sein und die Leitung PB6 von Recher1 mit der Leitung CNT von Rechner2 (ob SP1 oder SP2, bzw.CNT1 oder CNT2 hängt davon ab mit welcher CIA sie die Daten über- tragen wollen). Jetzt müssen Sie im Control-Register von Timer A (des sendenden Rechners) noch festlegen, daß das Signal an PB6 bei jedem Timerunterlauf in die jeweils an- dere Lage gekippt werden soll. Das ge- schieht, indem Sie die Bits 1 und 2 dieses Registers auf 1 setzen. Dadurch erscheint nämlich ebenfalls mit der halben Unterlauffrequenz von Timer A(des sendenden Rechners) ein Signal an PB6 und läst somit die Datenübernahme am empfangenden Rechner aus! Das war es dann endgültig mit dem CIA- Kurs. Ich hoffe, daß Sie nun einen bes- seren Einblick in die Funktionen dieser beiden kleinen, aber extrem mächtigen Bausteine innerhalb unseres Rechners haben. Wie Sie sehen lassen sich sehr viele Probleme mit Interrupts leichter lösen (wie die Mausabfrage beweist). Zu- sätzlich können Sie mit dem Userport vielf ltige Har wareerweiterungen leicht und einfach bedienen. Ich freue mich also, wenn es Ihnen ein wenig Spaß gemacht hat und bi n für Kritik und Anregungen zu neuen Kursen immer zu haben (auch ein kleiner Kurs- autor kriegt gerne Leserpost).
Bis auf Weiteres also ein letztes Mal "Servus" Ihr Uli Basters (ub)