Dritter Teil: Als Nächstes wird die absolute Anfangsa- dresse eines Textes, den ich im Speicher abgelegt habe, in LO/HI-Darstellung in A/Y geladen und der Wert 0 in das X- Register. Dies dient der Parameterüber- gabe für die Routine "SETIT", die an- schließend aufgerufen wird. Sie gibt den Text, dessen Anfangsadresse in A/Y steht aus und liest anschließend eine Uhrzeit ein, die sie in den Uhrregistern von CIA1 speichert. Zuvor schreibt sie den übergebenen Wert des X-Registers in CRB und setzt somit den Alarm- oder Uhzeit- Setzen-Modus. Der erste Aufruf von SETIT setzt die aktuelle Uhrzeit, der zweite die Alarmzeit. Anschließend wird der neue Interrupt eingestellt - alle IRQs werden gesperrt und der IRQ-Zeiger des Betriebssysems wird auf unsere neue Interruptroutine mit Namen "NEWIRQ" verbogen. Nun folgen zwei Schleifen, die die Spri- tes, die wir benutzen wollen um die Uhr- zeit auszugeben vorbereiten. Die erste Schleife kopiert eine Liste, die ich etwas weiter hinten im Source-Code abge- legt habe in den Bereich von $D000 bis $D00F. Diese Register des VIC sind für die Koordinaten der Sprites verantwor- lich, die nun entsprechend gesetzt sind. Die zweite Schleife schreibt in die VIC- Register 39 bis 46 den Wert 1, und setzt somit die Farbe für alle Sprites auf Weiß. Nun müssen wir die CIA1 noch darauf vor- bereiten, daß Echtzeituhr-Alarm-IRQs ausgelöst werden sollen. Dies geschieht, indem wir den Wert $85 in das ICR (Reg. 13) von CIA schreiben. Damit lassen wir zum Einen die immer noch gültigen Timer- IRQs zu die von Timer A erzeugt werden zu (für den System-IRQ), zum Anderen haben wir mit dem Wert $85 auch noch das 2. Bit gesetzt, das Alarm-IRQs als In- terruptquelle festlegt. Bit 7 muß wie immer gesetzt sein, damit die übrigen Bits als IRQ-Quelle übernommen werden. Nun müssen wir noch den SID darauf vor- bereiten, einen Piepton auszugeben, wenn ein IRQ auftritt. Deshalb wird das HI- Frequenzregister von Stimme1 (Reg. 1) mit dem Wert $C0 geladen und eine Hüll- kurve in Reg. 5 des SID geschrieben. Register 6, das ja ebenfalls Attribute der Hüllkurve angibt, wird nicht neu beschrieben, da es in der Regel den Wert 0 enthalten sollte, den ich dort auch haben wollte. Zum Abschluß folgen nun noch 5 Befehle, die den Anfang des BASIC-Speichers hö- hersetzen. Dies ist erforderlich, da ich nämlich am normalen Anfang die Sprites und den Code von CLOCK untergebracht habe. Würden Sie nun ein BASIC-Programm eingeben, so würden Sie CLOCK über- schreiben, was nicht sein sollte. In den Adressen $2B und $2C hat das Betriebs- system die Adresse des BASIC-Starts ge- speichert. Wir setzen diese Adressen nun einfach auf die Endadresse von CLOCK und rufen anschließend die Routine bei $A642 auf. Dort steht die BASIC-Routine für den Befehl "NEW". Dies ist notwendig, damit die neue Anfangsadresse des BA- SIC-Speichers auch vom Betriebssystem angenommen wird. Die Initialisierungsroutine gibt nun die IRQs wieder frei und springt zurück. Kommen wir zu der neuen IRQ-Routine, die die Uhr steuert. Sie muß zunächst prü- fen, ob der ausgelöste Interrupt ein Timer-, oder ein Alarm-IRQ war und de- mentsprechend reagieren. Bei Alarm gibt sie einen Piepton aus, bei einem Timer- IRQ wird nur die aktuelle Zeit aus CIA1 ausgelesen und mit Sprites auf dem Bild- schirm dargestellt. Hierbei muß sie un- terscheiden, ob die Zeit nun in 24h- oder AM/PM-Darstellung auf dem Bild- schirm erscheinen soll. Werfen wir doch einfach einmal einen Blick auf diese Routine:
======================================== NEWIRQ ist die IRQ-Routine von CLOCK. Hier wird zunächst einmal die vom Dar- stellungsmodus abhängige Spriteanzahl eingeschaltet. ======================================== newirq lda #$7f Wert für Sprites 0-6 einschalten (für 24h) ldx mode Uhr-Modus prüfen. bne l5 ungleich 0, also 24h lda #$ff Sonst AM/PM, des- halb Wert für "Sprites 0-7 ein- schalten" laden l5 sta v+21 und einschalten === Hier wird geprüft ob ein Alarm-IRQ (Bit2 von ICR=1) Auslöser war. Wenn ja, so wir ein Piepton ausgegeben. === lda cia1+13 ICR auslesen and #$04 Bit2 isolieren beq timeref Wenn =0, dann kei Alarm und weiter lda #15 Sonst Lautstärke sta sid+24 einschalten lda #33 Stimme 1 als "Sä- gezahn" sta sid+4 einschalten ldx #$ff Und warten... loop5 dey (dies... bne loop5 ...ist... dex ...eine... bne loop5 ...Warteschleife) lda #00 Ton gespielt, deshalb sta sid+4 Stimme1 aus sta sid+24 Lautstärke aus ======================================== Dies ist der Teil von NEWIRQ, der die Zeit neu ausgibt. ======================================== timeref ldx #43 Spriteblock "AM" in X laden lda cia1+11 Stunden in Akku bmi l6 Wenn 7.Bit=1 habe wir "PM", dehalb weiter cmp #$12 Akku=12 (in BCD)? bne l2 Nein, also weiter lda #00 12 Uhr AM gibts nicht, deshalb 00 Uhr AM beq l2 Unbedingter Sprun === Hier wird hinverzweigt, wenn PM ist. === l6 inx X-Reg enthält Spriteblock für "AM" - jetzt für "PM" and #$7f Bit7 (=PM) der Stunden löschen ldy mode Modus prüfen beq l2 Wenn AM/PM dann weiter cmp #$12 Akku = 12? beq l3 Ja, dann nicht 12 addieren sed BCD-Mode an clc Weil PM, 12 ad- adc #$12 dieren (für 24h) cld BCD-Mode aus l2 stx sprpoi+7 AM/PM-Sprite schalten
======================================== Nun folgt der Teil von NEWIRQ der die aktuelle Zeit ausgibt. ======================================== l3 jsr getnum Akkuinhalt in Spritepointer um- wandeln stx sprpoi+0 Sprites für Stun- sta sprpoi+1 den setzen
lda cia1+10 Minuten laden jsr getnum ...wandeln stx sprpoi+2 ...und sta sprpoi+3 ...setzen lda cia1+9 Sekunden laden jsr getnum ...wandeln stx sprpoi+4 ...und sta sprpoi+5 ...setzen lda cia1+8 Zehtelsek. laden clc Spritepointer der adc #sprbas Ziffer 0 addiern sta sprpoi+6 und setzen jmp $ea31 IRQ beenden ========================================
Zunächst einmal möchte ich Ihnen die In halte und die Bedeutung verschiedene Labels in diesem Teil des Listings erläu tern: * MODE enthält den Wert 3 und steht fü die Speicherzelle 3, in der wir j festgelegt hatten in welchem Darstel lungsmodus CLOCK arbeiten soll. * SPRPOI enthält den Wert 2040, die Basi sadresse der Spritepointer. In diese Pointern wird angegeben, welcher Spri teblock in einem Sprite dargestell werden soll. * SPRBAS enthät den Wert 33 und steht fü den ersten Spriteblock, den wir verwen den. In ihm steht die Ziffer 0 al Sprite. Addieren wir zu einem Wert i Akku (zwischen 0 und 9) den Wert SPRBA hinzu, so erhalten wir den Zeiger au den Spriteblock mit der entsprechende Ziffer des Wertes, den wir im Akku ste hen hatten. * GETNUM ist eine Routine, die eine BCD Zahl im Akku in die zwei Ziffernwert aufspaltet und SPRBAS zu diesem Wer hinzuaddiert. In X-Register und Akk werden die Spritepointer der beide Ziffern zurückgegeben. (Endgültig Schluß ist erst bei Teil vier...)