Magic Disk 64

home to index to text: MD9102-KURSE-CIA-KURS_TEIL_4.2.txt

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).

Valid HTML 4.0 Transitional Valid CSS!