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)