IRQ-Kurs Teil 4 .2
Wollen wir uns nun einmal anschauen, wie
unser NMI-Programm aufgebaut ist. Die
NMIs werden übrigens über Timer A der
CIA2 ausgelöst, der denselben Wert wie
der Timer des System-IRQs als Startwert
bekommt ( das wäre der Wert 16420=$4024) .
Hier also das Programm:
---------- NMI vorbereiten LDA $7F "NMI-Quellen sperren" laden, STA DD0D und in ICR von CIA2. LDX #$2B Zeiger auf eigene... LDY #$90 ...Routinen laden, STX 0318 und NMI-Vektor... STY 0319 ...setzen. LDX #$24 Timerwert LO-Byte. LDY #$40 Timerwert HI-Byte. STX DD04 In TALO und... STY DD05 ...in TAHI schreiben. LDA #$81 Wert laden... STA DD0D Timer A als Interruptquelle festlegen. STA DD0E Timer A starten. ---------- SID einstellen.
LDA #$0 F Wert 15 für volle Lautstärke
STA D418 . . . ins Lautstärkeregister.
LDA #$00 Zählregister für Tonfrequenz
STA 02 initialisieren.
RTS Und zurück.
---------- NMI-Routine CLI IRQs wieder freigeben. PHA Akku, TXA X-, PHA TYA und Y-Register auf Stapel PHA retten.
LDA #16 Wert für " Dreieckswelle aus" STA D404 . . . in SID schreiben
LDA 02 Zähler für Frequenz lesen. . .
STA D401 und in Frequenz-HI schreiben
INC 02 Zähler um 1 erhöhen.
LDA #17 Wert für " Dreieckswelle an" STA D404 . . . in SID schreiben.
LDA DD0D NMIs wieder freigeben PLA Akku, TAY X-, PLA TAX und Y-Register wieder vom PLA Stapel zurückholen. RTI Und Interrupt verlassen
----------
Im ersten Teil dieses Listings haben wir
die Initialisierungsroutine für unseren
NMI. Hier werden zunächst auf die schon
beschriebene Art und Weise alle Interruptquellen die von der CIA2 kommen, gesperrt. Anschließend wird der NMI-Vektor
bei $0318/$0319 auf unsere eigene Routi- ne verbogen ( die Routine beginnt bei
$9000 im Speicher, weshalb die eigentliche Interruptroutine bei $902 B beginnt) .
Ist dies getan, müssen wir als nächstes
den Timerwert in die Timerregister für
Timer A laden ( wie bei CIA1 sind dies
die Register 4 und 5- TALO und TAHI) .
Dies ist der wie oben schon beschriebene
Wert $4024 . Jetzt müssen wir nur noch
den Timer A als NMI-Interruptquelle setzen und ihn anschließend starten. Dies
geschieht in den folgenden 3 Zeilen. Was
der Wert $81 für Register 13( ICR) und
14( CRA) bedeutet wissen Sie ja schon
aus Teil 1 dieses Kurses, als ich Ihnen
die Funktionen dieser Register genauer
erläutert habe.
Zum Abschluß der Initialisierungsroutine
müssen wir auch noch den SID darauf vorbereiten, Sound auszugeben. Dazu haben
wir auch noch genug Zeit, da der schon
laufende Timer zum nächsten Interrupt
noch lange genug zählen wird ( ich hätte die SID-Initialisierung auch vorher anbringen können) . Also wird erst einmal
die Lautstärke des Soundchips eingeschaltet, sowie den Anfangsfrequenzwert
für unseren Soundeffekt in Adresse $02 in der Zeropage geschrieben.
Diese Adresse wird als Zählregister benutzt, da man auf die Register des SID
leider nicht zum Lesen zugreifen kann.
Somit sind sie also auch nicht mittels
INC hochzählbar. Nun sind alle Voreinstellungen getätigt, und wir können wieder zum aufrufenden Programm zurückverzweigen.
Im zweiten Teil des Listings sehen Sie
nun die NMi-Routine selbst. Als erstes
erlauben wir hier wieder das Auftreten
von IRQs ( sie erinnern sich, das Betriebssystem hatte sie ja gesperrt) . Nun
werden nach der mittlerweile schon altbekannten Methode die Prozessorregister
auf den Stapel gerettet, was wir bei
NMIs ja IMMER von Hand machen müssen, da das Betriebssystem uns diese Arbeit
leider nicht abnimmt.
Nun kommt der Teil, in dem der nächste
Ton gespielt wird. Hierzu wird erst einmal die Stimme 1 des SID abgeschaltet.
Dies ist notwendig, weil wir keine Hüllkurve vorher festgelegt hatten, die einen Ton möglicherweise dauerhaft spielen
würde. Deshalb befinden sich in den
Hüllkurvenregistern die Werte 0, was
bedeutet, daß ein Ton nur ganz kurz angeschlagen wird und gleich wieder verstummt. Damit man aber die nächste Frequenz nun hört müssen wir die Stimme
also erst noch ausschalten. Anschließend
wird der Inhalt des Zählregisters $02 in
das HI-Byte- Frequenzregister von Stimme
1 geschrieben ($ D401), und der Zähler
für den nächsten Interrupt um 1 erhöht.
Nun schalten wir Stimme 1 wieder an, und
zwar mit einer Dreieckswellenform - der
Ton wird nun gespielt.
Die Arbeit des NMIs ist getan, machen
wir uns also daran, den Interrupt zu
beenden. Ebenso altbekannt werden also
das ICR wieder freigegeben, die Prozessorregister zurückgeholt und mittels RTI
der NMI beendet.
So. Nun wissen Sie also alles wissenwerte über NMIs. Bis auf einige kleine Ausnahmen, können Sie diese Interruptart
genauso behandeln, wie einen IRQ. Da die
CIAs ja baugleich sind, fällt die CIAgesteuterte Programmierung von NMIs ja
ebenso aus, wie beim IRQ.
Ein ebenfalls ganz interessantes Anwendungsgebiet von NMIs ist die Steuerung
von gewiseen Funktionen über einen Druck
auf die RESTORE-Taste. Ich habe dies
einmal bei einem Apfelmännchenprogramm
benutzt. Diese Programme berechnen ja
bekanntermaßen Grafiken aus der Mandelbrotmenge, die zwar ganz ansehlich sind, deren Berechnung jedoch oft Stunden,
wenn nicht sogar Tage dauern kann. Ich
wollte nun eben jenes Programm beschleunigen, indem ich den Bildschirm abschalte. Wie Sie vielleicht wissen, kann
durch diese Maßnahme eine Geschwingigkeitssteigerung von 5% erzielt werden, da der VIC bei abgeschaltetem Bildschirm
micht mehr auf den Speicher des Computers zugreifen muß, um die Daten für
Grafiken, Zeichen, Sprites und ähnliches
zu holen. Dadurch stört er den Prozessor
nicht mehr beim Zugriff, wodurch dieser
schneller arbeiten kann. Das Problem war
nun jedoch, daß ich weiterhin sehen
wollte, wie weit der Rechner nun mit der
Grafikberechnung fortgefahren ist. Mit
einer einfachen NMI-Routine war dies
möglich. Ohne noch zeitraubend die Tastatur abzufragen, habe ich einfach einen neuen NMI " eingekoppelt", der nichts
anderes tut, als den Bildschirm aus-, bzw. einzuschalten, wenn man die RESTO-RE- Taste drückt. Dieser Trick läßt sich
vielfältig anwenden und ist einfach zu programmieren, hier das kleine Programm:
----------------- Initialisierung MAIN LDA #$7F CIA2-NMIs... STA CIA2+13 sperren. LDX #<(NMI) NMI-RAM-Vektor LDY #>(NMI) ...auf eigene STX $0318 ...NMI-Routine STY $0319 ...verbiegen. RTS Tschüß! ----------------- NMI-Routine NMI PHA Akku retten. LDA $D011 Register laden, EOR #16 Bildschirmbit inver- tieren. STA $D011 Und wieder speichern. PLA Akku zurückholen. RTI NMI-Ende. -----------------
Das ist tatsächlich alles! Das Programm
ist im " Hypra-Ass"- Quellcode angegeben, dessen Sonderfunktionen ich Ihnen letzen
Monat ja schon erklärte. Hier eine Dokumentation:
Im ersten Teil wird zunächst einmal die
CIA2 als Interruptquelle gesperrt. Dies
ist nicht unbedingt notwendig, da sie
sowieso ausgeschaltet sein sollte, jedoch habe ich es hier zur Sicherheit
einmal gemacht. Desweiteren wird der
NMI-Vektor auf unseren eigenen NMI verbogen, und die Initialisierung ist beendet.
Nun zum zweiten Teil: Zunächst einmal
rette ich hier nur den Akku. Xund Y-Register werden in der NMI-Routine sowieso nicht benutzt, weshalb wir sie
nicht unbedingt auch noch retten müssen.
Als nächstes laden wir den Inhalt von
Register 17 des VIC ($ D011= dez.53265) in
den Akku, da mit dem 4 . Bit dieses Regi- sters der Bildschirm einund ausgeschaltet wird. Der Inhalt dieses Registers wird nun einfach mit dem Wert des
4 . Bits geEORt. Dabei wird der Wert des
Bits immer invertiert. Ist es 1(= Bildschirm an), so wird es nach dem EOR-Befehl 0(= Bildschirm aus) sein und umgekehrt. Der neue Wert muß nun nur noch
wieder in $ D011 zurückwandern, und wir
können den NMI beenden.
Das Programm finden Sie übrigens auch
auf dieser MD unter dem Namen " NMI-SCREENOFF" . Es muß absolut (",8,1") geladen werden und wird mit SYS 49152 gestartet. Ab dann können Sie per Tastendruck auf RESTORE den Bildschirm nach
Belieben einund ausschalten.
Das war es dann man wieder für diesen
Monat. Ich wünsche Ihnen noch viel Spaß
beim herumexperimentieren mit den NMIs
und seien Sie nicht enttäuscht, wenns mal nicht auf Anhieb klappen sollte, denn: Wer noch nie einen Rechnerabsturz
erlebt hat, ist kein wahrer Programmierer!
In diesem Sinne bis nächsten Monat,
Ihr Uli Basters (ub).