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 Betriebssystem, so wie es bei den IRQs der
Fall war.
2) Nachdem eine der beiden Interruptroutinen 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 Rechner 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 explizit 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 invertiert 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 eimziges Bit abgefragt wird, hätte ich die
Branchbefehle zu den Bewegungsroutinen
ebenso vertauschen k nnen. Der Vollständigkeit halber wird hier der Wert
jedoch ebenfalls invertiert.
4) Sicher hat Sie die merkwürdige Mausbutton abfrage etwas verwirrt. Ich habe
hier noch eine kleine Funktion eingebaut die durch die Art unserer Abfrage
ganz einfach zu programmieren wurde.
Zunächst einmal wird durch den Druck
auf einen der Mausknöpfe der Spritpointer zwischen den Spriteblöcken 00 und 42 hinund 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. Dadurch, daß nun 2 Impulse von der Maus
kommen müssen, bis ein Interrupt auftritt müssen Sie die Maus doppelt wait über den Tisch bewegen, um den Mauspfeil 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 Auflö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 Interrupquellen benutzt werden gesetzt. So können 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önnen Sie sich aber gerne im Source-Listing " AM GA-MAUS3 . SRC" auf dieser
MD anschauen
7) Das Label ENDIRQ enthüllt die Adresse
$ EA7 E. Ab dieser Adresse stehen im Betriebssystem die Befehle, mit denen
jeder Interrupt ( auch NMIs) beendet
werden. Es werden einfach die Prozesorregister wieder vom Stapel geholt.
Um unsere eigenen Interrupts zu beenden springe ich also der Einfachheit
halber gleich diese Adresse an.
Natürlich brauchen Sie zum Betrieb der
neuen Mausabfrage einen neuen Adapterstecker. Damit das nicht allzu umständlich 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 Joyportbuchse) kommt jetzt an CNT1(= Pin 4 am
Userport - vorher Pin C) .
* Das H-Signal ( Pin 2 an der Joyportbuchse) kommt jetzt an CNT2(= Pin 6 am
Userport - vorher Pin D) .
Schließen Sie den neuen Stecker nun bei
abgeschaltetem 64 er 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 Abfrage 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 sogenannte " Serial-Data- Register" ist. Mit
diesem Register kann über die SP-Leitung
( die ja von beiden CIAs am Userport anliegt) ein einfacher serieller Datenaustausch mit einem anderen Rechner( im einfachsten Fall ebenfalls ein 64' er stattfinden. 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 anderen Spielers benötigt.
Über das SD-Register wird dieser Datenaustausch 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 unterscheiden, 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 Unterlä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 entsprechende CIA der Wert, der gerade anliegt
(0 oder 1) in ein internes Schieberegister ü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 austauschen. 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 verbunden 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 übertragen 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 andere Lage gekippt werden soll. Das geschieht, 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 besseren 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) . Zusä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 Kursautor kriegt gerne Leserpost) .
Bis auf Weiteres also ein letztes Mal "Servus" Ihr Uli Basters (ub)