Ein erster NMI

Für diesen Beitrag wurde das CBM prg Studio verwendet.
weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

CBM prg StudioDen NMI hält keiner auf

Wie bereits bei der Einleitung zu den ‚Interrupts‚ (ich gehe davon aus, dass ihr den Beitrag bereits gelesen habt)  erwähnt, handelt es sich beim NMI (None Maskable Interrupt) um einen Interrupt, der nicht mit  SEI/ CLI unterdrückt werden kann. Wie ihr wisst, sind die einzigen Quellen für einen NMI die <RESTORE>-Taste und der CIA-2.
Die beiden CIAs sind übrigens fast identisch und unterscheiden sich nur durch wenige Register und durch das Auslösen von IRQ (CIA-1) und NMI (CIA-2).

Bevor wir jetzt einen NMI programmieren, sollten wir mal wieder einen Blick auf den ROM-Vector werfen. Der NMI springt zur Adresse $FE43, die wir im ROM-Vector unter $FFFA finden. Schauen wir mit WinVICE mal nach, was unter  $FE43 genau gemacht wird, so stossen wir auf nur zwei Befehle.

Es werden also erstmal weitere IRQs gesperrt (warum es hier einen  SEI gibt ist mir allerdings nicht ganz klar, das I-Flag wurde ja bereits gesetzt, aber doppelt hält wohl einfach besser 😉 ) und dann wird über den RAM-Vector an $0318 zur dort hinterlegten Adresse gesprungen. Wie ihr seht, werden hier, im Gegensatz zum ‘normalen‚ IRQ weder der Akku, noch das X-/Y-Register gesichert. Darum müssen wir uns bei Bedarf also selbst kümmern. Wir können also unter $0318/19 wieder die Adresse für unsere eigene NMI-Routine eintragen.

 

NMI durch den Timer-A vom CIA-2
Unser kleines Testprogramm wird einen NMI und einen IRQ verwenden. Damit könnt ihr dann kontrollieren, dass der NMI tatsächlich nicht durch ein SEI verhindert werden kann. Der NMI wird über den Timer des CIA-2 den Rahmen blinken lassen, der IRQ verändert die Hintergrundfarbe.

Wir beginnen wieder mit der BASIC-Zeile 2013 SYS 49152:NEW, da wir die Interrupts weiter nach hinten verschoben haben, um das BASIC benutzen zu können.

Ab *=$C000 beginnen wir mit der Einrichtung unseres NMIs. Da wir NMIs nicht mit SEI verhindern können, müssen wir einen anderen Weg finden. Sonst droht wieder ein Absturz, wenn wir bereits das LSB in $0318 geändert haben und ausgerechnet dann ein NMI auftritt. NMIs lassen sich über das Register 13 des CIA-2 unterbinden. Ihr findet es an der Adresse $DD0D. Wer jetzt denkt es würde reichen dort einfach eine 0 einzutragen, der irrt. Das Register ist (so wie auch das Gegenstück, an der Adresse  $DC0D, vom CIA-1) sehr speziell. Beim Schreiben bestimmt ihr über BIT-7, ob ihr BITs auf 0 oder 1 setzen möchtet. Dann setzt ihr die BITs 4-0 auf 1 (die BITs 6 & 5 sind unbenutzt), die ihr auf den Wert aus BIT-7 ändern möchtet. Wir merken uns die aktuellen Interrupts des CIA-2 im X-Register und deaktivieren dann alle. Jetzt können wir die Adresse unserer NMI-Routine im RAM-Vector für den NMI ab $0318 eintragen. Wir möchten den Timer-A des CIA-2 verwenden, also legen wir an den Adressen $DD04 / $DD05 das LO- & HI-BYTE für unseren Timer ab. Hier könnt ihr später mit anderen Intervallen testen, wie die sich auf die Rahmenfarbe auswirken. Jetzt müssen wir noch den Timer starten, das erreichen wir durchs setzten von BIT-0 im 14. Register ( $DD0E) des CIA-2. Die anderen BITs setzen wir auf 0, somit beginnt unser Timer immer wieder von vorne. Jetzt sind wir fertig und müssen die NMIs wieder erlauben. Also holen wir die gemerkten Interrupts aus dem X-Register in den Akku und setzen BIT-0, damit wird es dem Timer-A erlaubt Interrupts auszulösen (hier NMIs). Denkt dran, dass wir wieder das Register 13 beschreiben und daher auch BIT-7 auf 1 setzen müssen!

Um die Auswirkung von SEI/CLI zu beobachten, richten wir noch einen eigenen IRQ fest.

Wir sperren die Interrupts mit SEI und verbiegen dann den RAM-Vector. Die Schleife ab @loop: dient nun dazu, zu demonstrieren, dass der NMI läuft (der Rahmen blinkt), der IRQ aber nicht. Was kein Wunder ist, da wir die Interrupts ja noch unterbunden haben. Sobald ihr die <SPACE>-Taste betätigt erlauben wir die Interrupts duch  CLI wieder und kehren zum BASIC zurück. Hier könnt ihr nun (ob wohl es durchs Blinken eigentlich kaum möglich ist) weiterarbeiten und z. B. etwas programmieren.

Wir benötigen noch unsere beiden Interrupt-Routinen, fangen wir mit dem irq: an, der besteht nur aus zwei Zeilen.

Das solltet nichts Neues für euch sein. Wenn ihr wollt, könnt ihr später ; jmp irq: einkommentieren, um nochmal zu sehen, dass NMIs auch auftreten, während ein IRQ läuft.

Abschließend brauchen wir noch unseren NMI.

Da die ROM-Routine den Akku und die Register nicht sichert, kümmern wir uns zu Beginn darum und legen diese auf den Stack. Dann müssen wir den Interrupt bestätigen, dies geschieht einfach durchs lesen von Register 13 ( $DD0D). Wir prüfen dann, ob es sich um den Timer-Interrupt gehandet hat, falls nicht verlassen wir den NMI, sonst erhöhen wir die Rahmenfarbe. Beim Verlassen holen wir den Akku und die Register vom Stack und kehren per RTI zurück zum unterbrochenen Programm.
Da wir hier nicht zur ROM-Routine springen, werden SYSTEM-NMIs erfolglosbleiben. Beachtet das beim Testen bitte.

Wenn ihr das Programm nun startet, dann sollte zunächst nur der Rahmenblinken. Sobald ihr <SPACE> betätigt werden die IRQs erlaubt und auch die Hintergrundfarbe ändert sich. Außerdem kehren wir dann auch zurück ins BASIC.

 

 

NMI und IRQ in Aktion.
NMI und IRQ in Aktion.

 


So, dass soll es zu den NMIs gewesen sein. Ihr könnt jetzt mit IRQs und NMIs etwas experimentieren, bevor wir als nächstes endlich zu den Rasterzeileninterrupts kommen.

 


Schrott!!Naja...Geht so...Ganz gut...SUPER! (5 Bewertungen | Ø 5,00 von 5 | 100,00%)

Loading...


 

<<< zurück | weiter >>>

 

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

Schreibe einen Kommentar


Beachtet bitte, dass ich eure Kommentare erst manuell freigegeben muß, bevor sie auf der Seite erscheinen! Da ich nicht pausenlos am Rechner sitze, kann es schon mal etwas dauern, bis ein Kommentar für alle sichtbar ist.

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Protected by WP Anti Spam