Assembler ist keine Alchimie — Teil 12

Im Gegensatz zum sonstigen Sprachgebrauch erregt das Kürzel CIA bei Commodore 64-Kennern angenehme Assoziationen. Die beiden CIAs (Complex Interface Adapter) unseres Computers und ihre Rolle bei der Unterbrechungs-Programmierung sollen in dieser Folge entschleiert werden.

Lassen Sie uns kurz rekapitulieren: Als primäre Unterbrechungsanforderer hatten wir drei Bausteine unseres Computers benannt, nämlich den VIC-II-Chip und die beiden CIA-Bausteine. CIA kommt von »Complex Interface Adapter« und ist die Bezeichnung für die beiden Ein- und Ausgabe-Bausteine, die den gesamten Verkehr zwischen dem zentralen Gehirn unseres C 64 und der Peripherie managen. Wir hatten bemerkt, daß ein CIA, der IRQ-CIA (Adressen von 56320 bis 56575), ausschließlich für die maskierbaren Unterbrechungen zuständig ist. Dazu gehören die 60mal pro Sekunde stattfindenden »Timer-Interrupts«, die die Cursorbehandlung, die TI$-Uhr, die Tastaturabfrage etc. bearbeiten. Der andere CIA, genannt NMI-CIA, (Adressenraum 56576-56831) ist nur für die nicht maskierbaren Unterbrechungen verantwortlich und wird bei normaler Nutzung des C 64 so gut wie nie eingesetzt. Ich gehe im folgenden davon aus, daß Sie keine RS232C-Schnittstelle in Ihren Computer eingesetzt haben. Sollte das aber der Fall sein, dann müßten Sie darauf achten, die folgenden Beispiele — die den NMI-CIA betreffen — ohne gleichzeitigen Betrieb dieser Schnittstelle anzuwenden, weil sich sonst Störungen ergeben könnten.

In der Folge 10 dieser Serie (64'er, Ausgabe 7/85) haben wir uns ein Register (das Register 13, Interrupt-Kontrollregister) der CIAs schon genauer angesehen und auch die Unterschiede beider Bausteine festgestellt. Dort war dann die Rede von Timern, Echtzeituhren, Alarm-Funktionen etc. Was es damit auf sich hat und wie man diese Möglichkeiten nutzen kann, das soll diesmal unser Thema sein. Wir werden uns dazu alle Register der CIAs genauer ansehen, die für die von uns ausgewählten Unterbrechungsoptionen eine Rolle spielen. Dabei fallen einige unter den Tisch — das habe ich aber schon in Folge 10 angekündigt —, nämlich diejenigen, die mit dem Verkehr über den seriellen Port, beziehungsweise über die RS232C-Schnittstelle, zu tun haben. Es bleibt dann anderen — kompetenteren — überlassen, darüber zu schreiben. Wie wäre es zum Beispiel mit Ihnen ?

Auch so bleibt uns genug zu tun. In Tabelle 1 finden Sie zunächst eine Übersicht der von uns behandelten Register.

Register Adresse (dez.) Name Funktion
Nr. ($) CIA-1 CIA-2
04 56324 56580 TALO TIMER A LSB
05 56325 56581 TAHI TIMER A MSB
06 56326 56582 TBLO TIMER B LSB
07 56327 56583 TBHI TIMER B MSB
08 56328 56584 TOD10THS 1/10-Sekunden-Register
09 56329 56585 TODSEC Sekunden-Register
0A 56330 56586 TODMIN Minuten-Register
0B 56331 56587 TODHR Stunden-Register, AM/PM-Flagge
0D 56333 56589 JCR Unterbrechungs-Kontrollregister
0E 56334 56590 CRA Kontrollregister A
0F 56335 56591 CRB Kontrollregister B
Tabelle 1. Die wichtigen Register der beiden CIAs

Sie sehen darin, daß jeder CIA über zwei sogenannte Timer (A und B) verfügt, sodann über die »Time of Day« (zu deutsch etwa »Tageszeit«) genannte Echtzeituhr mit vier Registern und schließlich noch über drei Kontrollregister, zu denen auch das schon erwähnte Register 13 gehört. Sehen wir uns zunächst die Timer an.

Die Timer der CIAs.

Insgesamt verfügen wir über vier dieser Timer: Timer A und B im CIA1 und dasselbe nochmal im CIA2. Es handelt sich dabei um 16-Bit-Register, in die ein Startwert geschrieben werden kann, von dem an dann heruntergezählt wird. Jedesmal, wenn dann der Wert 0 unterschritten ist, gibt es für uns die Möglichkeit, bestimmte Ereignisse stattfinden zu lassen. Man kann diese Register unabhängig voneinander, aber auch kombiniert, benutzen. Ein Lesen des Registers liefert immer den momentan gerade aktuellen Wert. Ein Schreiben in das Register führt automatisch zum Festlegen eines Startwertes. Was an Optionen mit diesen Timern möglich ist, wird über Kontrollregister gesteuert. Das CRA (Register $ 0E) bezieht sich vor allem auf den Timer A, das CRB (Register $ 0F) auf Timer B. Die 16-Bit-Register werden — wie gewohnt — in der Form LSB/MSB betrieben. In den Timer A des CIA1 wird bei jedem I/O-Reset folgendes Wertepaar eingetragen:

56324dezimal 37LSB
56325dezimal 64MSB

Das entspricht einem Startwert von 16421. Im PAL-System hat der Quarz, der die Taktfrequenz bestimmt, eine Frequenz von 17.734472 MHz. Die Prozessorfrequenz errechnet sich daraus mittels Division durch 18 zu 985248.4 Hz (also etwas weniger als 1 MHz, was den europäischen C 64 langsamer macht als den amerikanischen, der etwas mehr als 1 MHz verwendet). Wenn mit dieser Geschwindigkeit der Timer heruntergezählt wird, erhält man genau einen Unterlauf alle 1/60 Sekunden. Das ist der Weg, eine kontrollierte Zeitspanne durch den Timer zählen zu lassen. Sei X der gesuchte Startwert, der zu einer Spanne von T Sekunden führt, dann kann man X berechnen mittels:> X = 985248.4 * T

Der Integerwert von X ist dann in ein LSB und ein MSB zu teilen und in die Timer-Register einzutragen. Allerdings ergibt sich so eine natürliche Grenze. Die höchste durch 2 Bytes darstellbare Zahl ist ja 65535. Wenn wir diesen Wert in den Timer schreiben, dann ist er alle 1/15 Sekunden auf 0 heruntergezählt. Für längere Zeiten ist aber vorgesorgt. Die beiden Timer A und B sind kombinierbar (wie, dazu kommen wir gleich noch) zu einem 32-Bit-Register. Die höchste Zahl X ist dann: 4 294 967 296 = 232

Damit kann im Extremfall eine Herabzählzeit von 1 Stunde, 12 Minuten und zirka 40 Sekunden eingeplant werden, was für die meisten Zwecke ausreichen dürfte.

Möchten Sie also genau eine Sekunde Spielraum haben beim Herunterzählen, dann muß die Zahl 985248 als 4-Byte-Integer-Wert in die Speicher von Timer A und Timer B gebracht werden. Das führt dann zu den Werten 0, 15, 8, 160 (weil 985248 = 0*16777216 + 15*65536 + 8*256 + 160). 0 und 15 gelangen als MSB beziehungsweise LSB in Timer B (also Register 07 und 06), 8 und 160 sind MSB und LSB für den Timer A (Register 05 und 04). Sehen wir uns nun an, wie wir dem Computer sagen, was mit diesen Startwerten in den Timer-Registern geschehen soll. Die beiden Kontrollregister CRA und CRB beziehen sich weitgehend auf die gleichnamigen Timer. Im Bild 1 finden Sie das Register $0E, also CRA und in Bild 2 das andere Kontrollregister CRB ($0F):

Die Bedeutung der Bits 0 bis 4 ist — jeweils für den dazugehörigen Timer — identisch:

Die Bits 5 bis 7 haben nun unterschiedliche Bedeutung im CRA und im CRB:

Register CRA ($0E)

Register CRB ($0F)

Die Bits 5 und 6 sind hier im Zusammenhang von Bedeutung. Es gibt vier Kombinationsmöglichkeiten:

Bit 6 — Bit 5

0 — 0

Der Timer B wird — wie vorhin der Timer A — im Systemtakt heruntergezählt.

0 — 1

Der Timer B wird durch externe Signale heruntergezählt.

1 — 0

Der Timer B zählt die Unterläufe von Timer A. Das ist der vorhin erwähnte Punkt, der beide Timer kombiniert zum 32-Bit-Zähler. Man kann also im Extremfall 65536 mal 65536 Takte zählen lassen.

1 — 1

Auch in diesem Fall zählt Timer B die Unterläufe von Timer A. Er tut das aber nur, wenn ein bestimmtes externes Signal vorhanden ist.

Bit 7:

Auch beim Register CRB steuert dieses Bit bestimmte Möglichkeiten der Echtzeituhr. Deshalb haben Sie noch ein wenig Geduld, bis wir diese Uhr behandeln.

Bild 1. Das Kontrollregister des Timer A
Bild 2. Dasselbe für den Timer B

Wir kennen uns nun ganz gut aus, wie wir mit den Timern umzugehen haben. Unser Wissen soll in einem kleinen Test erprobt werden. Dazu bedienen wir uns des ⅟60 Sekunden IRQ. Wir verändern diese regelmäßige Unterbrechung derart, daß sie nur noch einmal in der Sekunde geschieht. Welche Zahlen dazu in ein 32-Bit-Register gepackt werden müssen, haben wir schon vorhin berechnet. Jeweils in der Reihenfolge LSB/MSB müssen wir sie einschreiben und vorher die Timer anhalten, indem die Bits 0 der Kontrollregister CRA und CRB auf 0 gesetzt werden. Nach dem Einschreiben und Starten der beiden Timer müssen folgende Bitmuster in CRA und CRB stehen:

CRA

CRB

Bevor wir die Timer starten, muß auch noch das Interrupt-Kontrollregister verändert werden (das hatten wir uns in der 10. Folge genauer angesehen). Bislang erzeugt ein Unterlauf des Timer A eine Unterbrechung. Wir möchten aber, daß der Timer B (damit wir das 32-Bit-Register voll ausnutzen) der Auslöser ist. Dazu muß Bit 0 des ICR gelöscht und statt dessen Bit 1 gesetzt werden.

Im Programm »Timer-Test« (siehe Listing 1 und 2) ist all das realisiert. Mit SYS 49152 gestartet, zeigt sich sofort ein deutlich verlangsamter Cursor. Noch langsamer kann alles werden, indem Sie höhere Werte in die Timer-Register schreiben. Den Normalzustand stellen Sie einfach durch Drücken der RUN/ STOP- und der RESTORE-Tasten her. Dabei wird ja — wie Sie aus der letzten Folge her wissen, auch ein I/O-Reset ausgeführt, der den Ausgangszustand wiederherstellt.

Die Verlängerung des IRQ-Zyklus hat übrigens noch einen sinnvollen Nebeneffekt. Je seltener ein laufendes Programm unterbrochen wird, desto schneller wird es mit seinen Jobs fertig. Das kann man immer dann tun — im Extremfall sogar den IRQ ganz ausschalten — wenn man die Möglichkeiten, die der Computer während des normalen IRQ anbietet, nur selten oder aber gar nicht braucht.

Die Echtzeituhren

Wir kennen nun fünf Uhren in unserem Computer: Die vier Timer (jeweils A und B im CIA1 und CIA2), die wir, weil wir die Impulszahlen in Zeiteinheiten umrechnen können, zur Zeitmessung einsetzen könnten und die im Basic verfügbare Uhr TI$, die aber — wie wir nun wissen — lediglich die Umsetzung des Timer A im CIA1 in ein bequemer handhabbares Software-Instrument ist. Zudem ist die Ganggenauigkeit dieser Uhr recht gering. Schon einige Kassettenoperationen genügen, sie völlig aus dem Takt zu bringen.

Um so mehr verwundert es, daß zwei hervorragende Echtzeituhren im Commodore 64 so gut wie nie benutzt werden, ja nicht einmal in irgendeiner Weise softwaremäßig unterstützt werden. Vielleicht ist das ein bißchen zuviel »mehr sein als scheinen«, was Commodore da betreibt, wenn man bedenkt, welche verborgenen Schätze da alle zutage gefördert werden können (man denke nur an die hochauflösende Grafik) bei genauer Untersuchung des Computers.

Jeder der beiden CIAs verfügt über solch eine Uhr, die direkt von der Netzfrequenz getaktet wird. Die Zählung der Zeit geschieht in vier Registern (Register $08 bis $0B), die in Bild 3 gezeigt sind.

Bild 3. Die Register der Echtzeituhren

Vielleicht fällt Ihnen etwas auf, wenn Sie sich diese vier Bytes mal genauer ansehen: Die Speicherung geschieht in Form von Einer- und Zehnerstellen. Das kann also weder im Binärformat noch als ASCII-Zeichen funktionieren. Hier werden die Ziffern als BCD-Zahlen abgelegt. In der 3.Folge dieser Serie wurde dieses »binary coded decimal«-Format erklärt. Das ist lange her (64’er, Ausgabe 11/84) und soll deshalb hier nochmal vorgestellt werden, damit alle wissen, wovon die Rede ist.

In dieser Zahlendarstellung wird jede Dezimalstelle einer Zahl gesondert in eine Binärzahl umgewandelt. Dann ergibt sich der folgende Zusammenhang:

BinärDezimal
00000
00011
00102
00113
01004
01015
01106
01117
10008
10019

Das war’s! Die anderen möglichen Binärkombinationen (also zum Beispiel 1010 etc.) werden nicht benutzt. Die Zahl 25 beispielsweise lautet im BCD-Format:

00100101
^^
25

Jetzt ist es Ihnen sicherlich verständlich, warum für die Sekunden- und Minuten-Zehnerstellen nicht mehr als drei Bits reserviert wurden: größer als 6 wird die Zehnerstelle nicht.

Zum Stundenregister TODHR ist aber noch etwas zu sagen: Dort ist nur ein Bit reserviert für die Stunden-Zehnerstelle. Die Uhr läuft nicht bis 24 Uhr, sondern lediglich bis 12 Uhr. Zur Unterscheidung, ob vor- oder nachmittags gemeint ist, dient das Bit 7. Dieses sogenannte AM/PM-Flag ist orientiert an der angelsächsischen Gewohnheit, zum Beispiel für 16 Uhr den Ausdruck 4 PM zu verwenden. PM kommt vom lateinischen »post meridiem«, was übersetzt heißt »nach dem Mittag«, wohingegen AM steht für »ante meridiem«, also »vor dem Mittag«. Meint man nun AM, dann muß diese Flagge auf 0, bei PM aber auf 1 gesetzt sein.

Beim Stellen der Uhren sollte eine Reihenfolge eingehalten werden. Sobald nämlich in das Stundenregister geschrieben wird, hält die Zählung automatisch an. Man kann nun die anderen Werte in die Register schreiben. Den Startschuß liefert das Schreiben in das Register TOD10TH: von nun an tickt die Uhr wieder.

Ähnlich funktioniert das Lesen der Uhrzeit. Sobald das Stundenregister gelesen wird, führt das zum Anhalten der Uhr, so daß die restlichen Register reibungslos auslesbar sind. Wieder ist es das Zehntelsekundenregister, das beim Auslesen ein Weiterlaufen der Uhr bewirkt. Aber, so werden Sie bemerken, wenn der Auslesevorgang eine bestimmte Zeit beansprucht, führt das zu Verzögerungen? Die Lösung ist, daß der gesamte Inhalt der vier Register gleichzeitig mit dem Auslesen des Stundenwertes in einen internen Speicher transferiert wird und dort weiterläuft. Nach dem Lesen des TOD10TH kommt der aktuelle Wert zurück in die Register und dieser wird weitergezählt.

Nun wird es höchste Zeit, daß wir uns die beiden Bits im CRA und im CRB ansehen, die wir vorhin bei der Timer-Behandlung links liegen ließen. Bit 7 im CRA kündigt der Echtzeituhr an, welche Netzfrequenz zu erwarten ist. Eine 1 an dieser Stelle steht für 50 Hz, eine 0 für 60 Hz. Unser Stromnetz in Deutschland liefert einen Wechselstrom mit 50 Hz, weshalb wir dann dort die 1 setzen sollten. Da gibt es ein kleines Problem: Beim I/O-Reset, der durch Drücken der RUN/STOP- und der RESTORE-Tasten zusammen ausgelöst wird, schreibt der Computer immer den amerikanischen Wert für 60 Hz in dieses Bit. Dann geht die Uhr aber empfindlich nach. Man muß also einen Weg finden, der erlaubt, dort in diesem Fall wieder eine 1 einzuschreiben. Das ist durch eine eigene NMI-Routine möglich. Sie sehen schon, der Weg zur Nutzung dieser verlockenden Uhren ist ziemlich dornenreich!

Noch interessanter ist das Bit 7 im CRB. Das Setzen der Uhrzeit ist nämlich nur möglich, wenn dieses Bit den Inhalt 0 hat. Was geschieht, wenn dort eine 1 steht? Dann bestimmt man nicht die aktuelle Uhrzeit, sondern man stellt einen Wecker (das ist die Alarmzeit). Das geschieht nach dem Setzen dieses Bits genauso wie vorhin das Einschreiben der Uhrzeit (also erstaunlicherweise auch in genau dieselben Register!). Im Unterschied dazu ist allerdings ein Lesen der Alarmzeit nicht möglich — das ergibt immer die aktuelle Uhrzeit. Man muß für diesen Fall die Weckzeit irgendwo abspeichern und bei Bedarf dann von dort lesen.

Weil man ja meistens nach dem Erreichen der Alarmzeit irgendeine Reaktion erwartet, ist im ICR (also dem Unterbrechungskontrollregister 13) jedes CIA noch ein Bit reserviert — das Bit 2 —, mit dessen Hilfe der Alarm per IRQ oder NMI wie auch immer geartet losbrechen kann. Der Phantasie sind hier nur wenige Grenzen gesetzt. Wie man mit diesem ICR umgeht, ist Ihnen noch aus der Folge 10 geläufig.

Damit sind wir durch die Eigenheiten der CIAs durch. Man braucht tatsächlich keine Scheu zu haben, diese Echtzeituhren zu nutzen. Lediglich die Uhr im CIA1 wird manchmal verwendet, einen bestimmten Wert für die Zufallszahlenerzeugung zu generieren. Aber das sollte einer eigenen Uhren-Routine nicht in die Quere kommen. Solch eine Echtzeituhr finden Sie im beiliegenden Listing 3 und 4.

Durch SYS49152 aktivieren Sie die Uhr, die Sie mit SYS49261 auch wieder abschalten können. Durch ein USR-Kommando A = USR (String) stellen Sie die Startzeit ein. String kann dabei eine Stringvariable sein oder auch direkt ein String der Form »HHMMSST« (also Stunden, Minuten, Sekunden, Zehntelsekunden). In A steht eine 0, wenn kein Fehler, aber eine -1, wenn ein Fehler aufgetreten ist. Das Lesen der Uhr erfolgt über ein zweites USR-Kommando: PRINTUSR(Zahl). Dabei kann Zahl eine beliebige Zahl oder Variable sein. Eine Alarmzeit ist ebenfalls einstellbar durch ein USR-Kommando, in dem vor der Zeiteingabe noch ein Buchstabe steht. Beispielsweise stellt A = USR(»A1200000«) einen Wecker auf 12 Uhr. Der Alarm im Programm läßt den Bildschirmrahmen blinken. Abstellen kann man das durch Auslösen eines RESTORE-NMI (also RUN/STOP und RESTORE). Sollten Sie vor dem eingestellten Alarm mal solch einen NMI auslösen, dann muß die Alarmzeit neu gestellt werden. Als Basis für dieses Programm diente ein Listing aus dem schon oft erwähnten Buch von Babel/Krause/Dripke »Das Interface Age Systemhandbuch zum Commodore 64«.

Die Unterbrechungs-Programmierung ist damit abgeschlossen — ebenso diese Serie, die als Einführung in die Assembler-Alchimie nun alle Geheimnisse der Kunst aufgedeckt hat. In den letzten Folgen sind wir schon in die Meistergrade der Zunft aufgestiegen. Vielleicht ging es manchem etwas zu schnell? Dann wird Ihnen der anschließende Kurs »Von Basic zu Assembler« eine Hilfe sein, der behutsam und mit vielen an Basic angelehnten Beispielen die nötige Programmierpraxis vermitteln wird. So wie die Segler sich oft »Mast- und Schotbruch« wünschen, verabschiede ich mich, indem ich Ihnen viele grandiose Abstürze wünsche.

(Heimo Ponnath/gk)
PROGRAMM : PRG.TIMER-TEST C000 C052
-----------------------------------
C000 : 78 AD 0E DC 29 FE 8D 0E   4B
C008 : DC AD 0F DC 29 FE 8D 0F   F9
C010 : DC A9 0F 8D 06 DC A9 00   24
C018 : 8D 07 DC A9 A0 8D 04 DC   D5
C020 : A9 08 8D 05 DC A9 1F 8D   84
C028 : 0D DC A9 82 8D 0D DC AD   6E
C030 : 0E DC 29 D7 8D 0E DC AD   0A
C038 : 0F DC 29 D7 8D 0F DC AD   1B
C040 : 0E DC 09 01 8D 0E DC AD   37
C048 : 0F DC 09 41 8D 0F DC 58   A5
C050 : 60 6F                     A2
Listing 1. Programm Timer-Test, ein Beispiel für die Anwendung eines 32-Bit-Timers
PASS 1



PASS 2
7000           0823 ;
7000           084C ;**************************************
7000           0875 ;*                                    *
7000           089E ;*             TIMER-TEST             *
7000           08C7 ;*                                    *
7000           08F0 ;* TIMER A UND B DES CIA1 WERDEN SO   *
7000           0919 ;* GESCHALTET, DASS NUR NOCH 1 MAL    *
7000           0942 ;* PRO SEKUNDE DER TIMER-IRQ AUFTRITT *
7000           096B ;*                                    *
7000           0994 ;*    HEIMO PONNATH  HAMBURG  1985    *
7000           09BD ;*                                    *
7000           09E6 ;**************************************
7000           09E9 ;
7000           09EC ;
C000           09F8              .BA $C000
C000           09FE              .OS
C000           0A01 ;
C000           0A27 ;+++ BENUTZTE ADRESSEN DES CIA 1 +++
C000           0A2A ;
C000           0A3A TALO         .DE $DC04
C000           0A4A TAHI         .DE $DC05
C000           0A5A TBLO         .DE $DC06
C000           0A6A TBHI         .DE $DC07
C000           0A79 ICR          .DE $DC0D
C000           0A88 CRA          .DE $DC0E
C000           0A97 CRB          .DE $DC0F
C000           0A9A ;
C000           0AC3 ;+++ EINSCHALTEN DES 1 SEKUNDEN IRQ +++
C000           0AC6 ;
C000 78        0AE5 START        SEI                ;SPERREN ALLER IRQS
C001           0AE8 ;
C001 AD 0E DC  0AF2              LDA CRA
C004 29 FE     0B03              AND #%11111110
C006 8D 0E DC  0B1B              STA CRA            ;STOP TIMER A
C009 AD 0F DC  0B25              LDA CRB
C00C 29 FE     0B36              AND #%11111110
C00E 8D 0F DC  0B4E              STA CRB            ;STOP TIMER B
C011           0B51 ;
C011 A9 0F     0B6F              LDA #15            ;NEUER STARTWERT IN
C013 8D 06 DC  0B8A              STA TBLO           ;32-BIT-REGISTER
C016 A9 00     0B94              LDA #00
C018 8D 07 DC  0B9F              STA TBHI
C01B A9 A0     0BAA              LDA #160
C01D 8D 04 DC  0BB5              STA TALO
C020 A9 08     0BBF              LDA #08
C022 8D 05 DC  0BCA              STA TAHI
C025           0BCD ;
C025 A9 1F     0BDE              LDA #%00011111
C027 8D 0D DC  0BFB              STA ICR            ;ALLE IRQ VERBOTEN
C02A A9 82     0C0C              LDA #%10000010
C02C 8D 0D DC  0C27              STA ICR            ;NUR TIMER B IRQ
C02F           0C2A ;
C02F AD 0E DC  0C34              LDA CRA
C032 29 D7     0C45              AND #%11010111
C034 8D 0E DC  0C61              STA CRA            ;BITS 3 UND 5 = 0
C037           0C64 ;
C037 AD 0F DC  0C6E              LDA CRB
C03A 29 D7     0C7F              AND #%11010111
C03C 9D 0F DC  0C8F              STA CRB            ;DITO
C03F           0C92 ;
C03F AD 0E DC  0C9C              LDA CRA
C042 09 01     0CAD              ORA #%00000001
C044 8D 0E DC  0CC6              STA CRA            ;TIMER A START
C047           0CC9 ;
C047 AD 0F DC  0CD3              LDA CRB
C04A 09 41     0CE4              ORA #%01000001
C04C 8D 0F DC  0D01              STA CRB            ;TIMER B START MIT
C04F           0D24 ;                TIMER A UNTERLAUF
C04F           0D27 ;
C04F 58        0D3D              CLI                ;IRQS FREIGEBEN
C050           0D40 ;
C050 60        0D46              RTS
C051           0D49 ;
C051           0D4F              .EN
Listing 2. Der Quelltext zum Timer-Set.
PROGRAMM : OBJ.ALARMUHR   C000 C18E
-----------------------------------
C000 : A9 8E 8D 11 03 A9 C0 8D   11
C008 : 12 03 A9 1D 8D 18 03 A9   A3
C010 : C0 8D 19 03 AD 0E DD 09   12
C018 : 80 8D 0E DD 60 48 8A 48   A1
C020 : 98 48 A9 7F 8D 0D DD AC   49
C028 : 0D DD 10 06 4C 6A C1 4C   A0
C030 : 72 FE 20 BC F6 20 E1 FF   B9
C038 : D0 F5 A2 04 BD 2F FD 9D   B4
C040 : 13 03 CA D0 F7 A2 1A BD   1A
C048 : 35 FD 9D 19 03 CA D0 F7   C0
C050 : A9 7F 8D 0D DC 8D 0D DD   E8
C058 : 8D 00 DC A9 08 8D 0E DC   30
C060 : A9 88 8D 0E DD A9 08 20   FE
C068 : B6 FD 4C 6C FE A9 48 8D   37
C070 : 11 03 A9 B2 8D 12 03 78   2A
C078 : A9 47 8D 18 03 A9 FE 8D   C0
C080 : 19 03 A9 31 8D 14 03 A9   84
C088 : EA 8D 15 03 58 60 24 0D   12
C090 : 30 03 4C 20 C1 20 82 B7   F0
C098 : C0 07 D0 40 AD 0F DD 29   35
C0A0 : 7F 8D 0F DD A0 00 A9 24   5E
C0A8 : 20 FE C0 D0 02 A9 24 C9   23
C0B0 : 13 90 07 F8 38 E9 12 D8   B9
C0B8 : 09 80 8D 0B DD 20 FC C0   1A
C0C0 : 8D 0A DD 20 FC C0 8D 09   EC
C0C8 : DD 20 66 C1 8D 08 DD A9   6B
C0D0 : 00 4C 3C BC 68 68 68 68   D9
C0D8 : A9 FF D0 F5 C0 08 D0 F8   F5
C0E0 : AD 0F DD 09 80 8D 0F DD   1A
C0E8 : A9 84 8D 0D DD A9 3C 85   FF
C0F0 : 04 85 02 A9 FF 85 03 A0   E6
C0F8 : 01 4C A6 C0 A9 60 85 24   DD
C100 : 20 13 C1 0A 0A 0A 0A 85   80
C108 : 25 20 13 C1 05 25 C5 24   13
C110 : B0 C4 60 B1 22 38 E9 30   5D
C118 : 90 BA C9 0A B0 B6 C8 60   5E
C120 : A9 07 20 7D B4 A0 00 AD   B0
C128 : 0B DD 08 29 1F C9 12 D0   73
C130 : 02 A9 00 28 10 05 F8 18   49
C138 : 69 12 D8 20 55 C1 AD 0A   13
C140 : DD 20 55 C1 AD 09 DD 20   96
C148 : 55 C1 AD 08 DD 20 60 C1   CE
C150 : 68 68 4C CA B4 48 4A 4A   A4
C158 : 4A 4A 20 60 C1 68 29 0F   FE
C160 : 09 30 91 62 C8 60 20 13   68
C168 : C1 60 A9 77 8D 14 03 A9   8B
C170 : C1 8D 15 03 4C BC FE C6   D2
C178 : 02 F0 03 4C 31 EA A5 04   46
C180 : 85 02 AD 20 D0 45 03 8D   D4
C188 : 20 D0 4C 31 EA 2D         99
Listing 3. Eine Echtzeituhr. Bitte beachten Sie die Eingabehinweise auf Seite 54
7000           0823 ;
7000           084C ;**************************************
7000           0875 ;*                                    *
7000           089E ;*  ECHTZEITUHR MIT ALARMFUNKTION     *
7000           08C7 ;*                                    *
7000           08F0 ;*  LAEUFT MIT DEM NMI-CIA            *
7000           0919 ;*  IN VERBINDUNG MIT DEM IRQ FUER    *
7000           0942 ;*  DEN ALARM                         *
7000           096B ;*                                    *
7000           0994 ;*    HEIMO PONNATH  HAMBURG  1985    *
7000           09BD ;*                                    *
7000           09E6 ;*  (TEILWEISE WURDE EIN PROGRAMM AUS *
7000           0A0F ;*  DEM INTERFACE AGE SYSTEMHANDBUCH  *
7000           0A3B ;*  ZUM COMMODORE 64 , SEITE 114      *
7000           0A61 ;*  ALS BASIS VERWENDET )             *
7000           0A8A ;*                                    *
7000           0AB3 ;**************************************
7000           0AB6 ;
C000           0AC2             .BA $C000
C000           0ACB             .OS
C000           0ACB ;
C000           0AF4 ;********** ZEROPAGE-LABELS ***********
C000           0AF7 ;
C000           0B18 VERZ        .DE $02             ;AKTUELLE VERZOEG.
C000           0B3B FARB        .DE $03             ;WERT FUER RAHMEN
C000           0B57 ;               EOR-OPERATION
C000           0B78 VORW        .DE $04             ;VERZOEGERUNGSWERT
C000           0B9B VALTYP      .DE $0D             ;INHALT:F=STR 0=N
C000           0B9E ;
C000           0BAD INDEX       .DE $22
C000           0BC6 INDEX3      .DE $24             ;POINTER
C000           0BD6 INDEX4      .DE $25
C000           0BF5 FAC1        .DE $62             ;1.MANTISSENBYTE
C000           0BF8 ;
C000           0C21 ;********** LABELS PAGES 3 ************
C000           0C24 ;
C000           0C44 USRADDL     .DE $0311           ;USR-POINTER
C000           0C57 USRADDH     .DE $0312
C000           0C5A ;
C000           0C6A FREI        .DE $0313
C000           0C6D ;
C000           0C8A IRQVL       .DE $0314           ;IRQ-VEKTOR
C000           0C9B IRQVH       .DE $0315
C000           0C9E ;
C000           0CBC NMINVL      .DE $0318           ;NMI-VEKTOR
C000           0CCE NMINVH      .DE $0319
C000           0CD1 ;
C000           0CFA ;********** LABELS INTERPRETER ********
C000           0CFD ;
C000           0D23 ILLQUERR    .DE $B248           ;ILLEGAL QUANTITY
C000           0D4B ;          ERROR=NORMALWERT USR-VEKTOR
C000           0D4E ;
C000           0D70 STRIN18     .DE $B47D           ;SPEICHERPLATZ
C000           0D99 ;          PRUEFEN,STRINGPOINTER SETZEN
C000           0DBF STRLIT67    .DE $B4CA           ;REST DER STRING-
C000           0DD8 ;          LESE-ROUTINE
C000           0DF7 LEN1        .DE $B782           ;STRINGLAENGE
C000           0E11 ;          IN Y-REGISTER
C000           0E32 ACTOFC      .DE $BC3C           ;AKKU NACH FAC
C000           0E35 ;
C000           0E5E ;********** LABELS VIC-II-CHIP ********
C000           0E61 ;
C000           0E7E RAND        .DE $D020           ;RAHMENFARBE
C000           0E81 ;
C000           0EAA ;********** LABELS CIA-BAUSTEINE ******
C000           0EAD ;
C000           0ECA CIA1        .DE $DC00           ;START CIA-1
C000           0EEC ICR1        .DE $DC0D           ;IRQ-KONTROLLREG.
C000           0F0E CRA1        .DE $DC0E           ;TIMER-A KONTRREG
C000           0F11 ;
C000           0F34 TOD10TH2    .DE $DD08           ;1/10 SEKUNDEN
C000           0F51 TODSEC2     .DE $DD09           ;SEKUNDEN
C000           0F6D TODMIN2     .DE $DD0A           ;MINUTEN
C000           0F8F TODHR       .DE $DD0B           ;STUNDEN + AM/PM
C000           0FB1 ICR2        .DE $DD0D           ;NMI-KONTROLLREG.
C000           0FD3 CRA2        .DE $DD0E           ;TIMER-A KONTRREG
C000           0FF5 CRB2        .DE $DD0F           ;TIMER-B KONTRREG
C000           0FF8 ;
C000           0FFB ;
C000           1024 ;********** LABELS OBERES ROM *********
C000           1027 ;
C000           1045 NORM        .DE $EA31           ;NORMALER IRQ
C000           1048 ;
C000           106B TASTFLAG    .DE $F6BC           ;TEIL DER NMI-
C000           108E ;            ROUTINE (KEIN MODUL)
C000           10AD VECTAB      .DE $F02F           ;TABELLE DER
C000           10C8 ;            ROM-VEKTOREN
C000           10E9 VECTAB7     .DE $FD35           ;MSB DES NMI-
C000           110E ;            VEKTORS IN DER TABELLE
C000           1132 IORESET19   .DE $FDB6           ;I/O-RESET:BEI
C000           1157 ;            SETZEN DES CRA IRQ-CIA
C000           117B NMIXCT16    .DE $FE6C           ;NMI-ROUTINE AB
C000           119D ;            SCREEN-EDITOR-RESET
C000           11C1 NMIRS232    .DE $FE72           ;NMI-ROUTINE AB
C000           11DE ;            RS232-HANDLING
C000           11FF NMIEND      .DE $FEBC           ;ENDE DER NMI-
C000           1215 ;            ROUTINE
C000           1237 STOP        .DE $FFE1           ;KERNAL STOP SPRG
C000           1254 ;            NACH JMP($328)
C000           1257 ;
C000           125A ;
C000           1283 ;********** AKTIVIEREN ****************
C000           1286 ;
C000 A9 8E     12A2 INIT        LDA #L,USR          ;USR-VEKTOR
C002 8D 11 03  12B7             STA USRADDL         ;LADEN
C005 A9 C0     12C4             LDA #H,USR
C007 8D 12 03  12D2             STA USRADDH
C00A           12D5 ;
C00A A9 1D     12F2             LDA #L,NMI          ;NMI-VEKTOR MIT
C00C 8D 18 03  130D             STA NMINVL          ;STARTADRESSE
C00F A9 C0     1327             LDA #H,NMI          ;DER EIGENEN
C011 8D 19 03  1345             STA NMINVH          ;NMI-ROUTINE LAD
C014           1348 ;
C014 AD 0E DD  1365             LDA CRA2            ;BIT7 CRA SETZEN:
C017 09 80     137C             ORA #$80            ;%1000 0000
C019 8D 0E DD  1397             STA CRA2            ;NETZFREQ.=50HZ
C01C           139A ;
C01C 60        13A0             RTS
C01D           13A3 ;
C01D           13CC ;********** EIGENE NMI-ROUTINE ********
C01D           13CF ;
C01D 48        13EF NMI         PHA                 ;ANFANG NORMALE NMI-R.
C01E 8A        1406             TXA                 ;REGISTER RETTEN
C01F 48        140C             PHA
C020 98        1412             TYA
C021 48        1418             PHA
C022           141B ;
C022 A9 7F     1439             LDA #7F             ;SPERREN ALLER NMI
C024 8D 0D DD  1444             STA DD0D
C027           1447 ;
C027 AC 0D DD  1462             LDY DD0D            ;PRUEFEN OB NMI
C02A 10 06     1481             BPL RESTNMI         ;VOM CIA2 KOMMT.
C02C           14A4 ;                WENN NEIN=SPRUNG
C02C 4C 6A C1  14C1             JMP ALARM           ;WENN JA, ALARM
C02F 4C 72 FE  14E1 CIANMI      JMP NMIRS232        ;REST DER
C032           1508 ;                NORMALEN NMI-ROUTINE
C032           150B ;
C032           1534 ;***** EIGENE RESTORE-NMI-ROUTINE *****
C032           1537 ;
C032           155F ;   DIE MODULPRUEFUNG WIRD AUSGELASSEN
C032           1562 ;
C032 20 BC F6  1587 RESTNMI     JSR TASTFLAG        ;TEIL DER NMI-
C035 20 E1 FF  15A5             JSR STOP            ;ROUTINE ZUR STOP-
C038 D0 F5     15C2             BNE CIANMI          ;TASTEN-ABFRAGE
C03A           15C5 ;
C03A A2 04     15E3             LDX #$04            ;IRQ UND BRK VEKT.
C03C BD 2F FD  1606 UMLAD1      LDA VECTAB,X        ;RESTAURIEREN
C03F 9D 13 03  1613             STA FREI,X
C042 CA        1619             DEX
C043 D0 F7     1626             BNE UMLAD1
C045           1629 ;
C045           1651 ;   DER NMI-VEKTOR WIRD UEBERSPRUNGEN
C045           1654 ;
C045 A2 1A     1671             LDX #$1A            ;RESTAURIEREN DER
C047 BD 35 FD  1693 UMLAD2      LDA VECTAB7,X       ;RESTLICHEN
C04A 9D 19 03  16AC             STA NMINVH,X        ;VEKTOREN
C04D CA        16B2             DEX
C04E D0 F7     16BF             BNE UMLAD2
C050           16C2 ;
C050           16E3 ;  ZUNAECHST NORMALER I/O-RESET
C050           16E6 ;
C050 A9 7F     16FD             LDA #$7F            ;= 0111 111
C052 8D 0D DC  171B             STA ICR1            ;SPERREN ALLER IRQ
C055 8D 0D DD  1739             STA ICR2            ;SPERREN ALLER NMI
C058 8D 00 DC  1753             STA CIA1            ;DATENREGISTER
C05B           177A ;               PORT A AUF NORMALWERT
C05B A9 08     1791             LDA #$08            ;=0000 1000
C05D 8D 0E DC  17AD             STA CRA1            ;TIMER A IM CIA1
C060           17B0 ;
C060           17D2 ;  ERSATZ FUER BELEGUNG DES CRA2
C060           17D5 ;
C060 A9 88     17EC             LDA #$88            ;=1000 1000
C062 8D 0E DD  1809             STA CRA2            ;TIMER A IM CIA2:
C065           1829 ;               BIT 0 AUF STOP
C065           184F ;               BIT 3 AUF EINZELLAUF
C065           1875 ;               BIT 5 SYSTEMTAKT EIN
C065           189D ;               BIT 7 ECHTZEITUHR=50HZ
C065           18A0 ;
C065           18C0 ;  REST DES NORMALEN I/O-RESET
C065           18C3 ;
C065           18C6 ;
C065 A9 08     18DE             LDA #$08            ;= 0000 1000
C067 20 B6 FD  18EE             JSR IORESET19
C06A           18F1 ;
C06A           1919 ;  REST DER NORMALEN RESTORE-NMI-ROUT.
C06A           191C ;
C06A 4C 6C FE  193A             JMP NMIXCT16        ;EINSPRUNG BEI
C06D           195F ;               SCREEN EDITOR RESET
C06D           1962 ;
C06D           198B ;**** ABSCHALTEN DER TIME OF DAY UHR **
C06D           198E ;
C06D           19AD ;          DURCH SYS-KOMMANDO
C06D           19B0 ;
C06D A9 48     19D1 AUS         LDA #L,ILLQUERR     ;USR-VEKTOR
C06F 8D 11 03  19EF             STA USRADDL         ;AUF NORMALWERT
C072 A9 B2     1A01             LDA #H,ILLQUERR
C074 8D 12 03  1A0F             STA USRADDH
C077           1A12 ;
C077 78        1A18             SEI
C078 A9 47     1A35             LDA #$47            ;RESTAURIEREN DES
C07A 8D 18 03  1A4F             STA NMINVL          ;NMI-VEKTORS
C07D A9 FE     1A5A             LDA #$FE
C07F 8D 19 03  1A67             STA NMINVH
C082           1A6A ;
C082 A9 31     1A87             LDA #L,NORM         ;RESTAURIEREN
C084 8D 14 03  1AA4             STA IRQVL           ;DES IRQ-VEKTORS
C087 A9 EA     1AB2             LDA #H,NORM
C089 8D 15 03  1ABE             STA IRQVH
C08C           1AC1 ;
C08C 58        1AC7             CLI
C08D 60        1ACD             RTS
C08E           1AD0 ;
C08E           1AF9 ;**** DURCH USR AUFRUFBARE ROUTINE ****
C08E           1AFC ;
C08E 24 0D     1B1D USR         BIT VALTYP          ;WELCHER TYP VON
C090           1B44 ;               VARIABLEN LIEGT VOR ?
C090 30 03     1B5F             BMI STRING          ;WENN STRING
C092           1B83 ;               DANN UEBERSPRINGEN
C092 4C 20 C1  1B9F             JMP ZAHLVAR         ;SONST SPRUNG
C095           1BA2 ;
C095           1BC8 ;****** STELLEN DER ECHTZEITUHR *******
C095           1BEB ;         DURCH USR("HHMMSST")
C095           1BEE ;
C095 20 82 B7  1C0F STRING      JSR LEN1            ;Y=STRINGLAENGE
C098 C0 07     1C2C             CPY #$07            ;STRING=7ZEICHEN?
C09A D0 40     1C4A             BNE ALSET           ;NEIN DANN ALARM
C09C           1C69 ;               ZEIT STELLEN?
C09C           1C6C ;
C09C AD 0F DD  1C88             LDA CRB2            ;TIMER B IN CIA2
C09F 29 7F     1CA3             AND #$7F            ;BIT7 LOESCHEN:
C0A1 8D 0F DD  1CBF             STA CRB2            ;NORMALE UHRZEIT
C0A4           1CE4 ;               IN ECHTZEITUHR CIA2
C0A4           1CE7 ;
C0A4           1D05 ;  AUSLESEN DES ZEIT-STRINGS
C0A4           1D09 ;
C0A4 A0 00     1D22             LDY #$00            ;ZAEHLER AUF 0
C0A6 A9 24     1D47 STELLEN     LDA #$24            ;BCD 24 STD-VERGL.
C0A8 20 FE C0  1D65             JSR ASCBCD          ;ZEICHENTEST UND
C0AB           1D8D ;               UMWANDLUNG IN BCD-ZAHL
C0AB D0 02     1DAB             BNE STD12           ;STUNDEN UNGLEICH
C0AD           1DCF ;               NULL ? DANN SPRUNG
C0AD A9 24     1DE6             LDA #$24            ;SONST = 24
C0AF           1DE9 ;
C0AF C9 13     1E0B STD12       CMP #$13            ;STUNDEN GROESSER
C0B1 90 07     1E2A             BCC STDSET          ;ODER GLEICH 12 ?
C0B3           1E4D ;               NEIN, DANN SPRUNG
C0B3 F8        1E67             SED                 ;SONST DAVON BCD 12
C0B4 38        1E7B             SEC                 ;SUBTRAHIEREN
C0B5 E9 12     1E8B             SBC #$12            ;UND
C0B7 D8        1E91             CLD
C0B8 09 80     1EA9             ORA #$80            ;BIT7 SETZEN
C0BA           1EAC ;
C0BA 8D 0B DD  1ECF STDSET      STA TODHR           ;BCD-STUNDEN UND
C0BD           1EF7 ;               AM/PM-FLAG IN TOD-CIA2
C0BD           1EFA ;
C0BD 20 FC C0  1F18             JSR ASCBCD1         ;ZEICHENTEST U.
COC0           1F3F ;               UMWANDELN IN BCD-ZAHL
C0C0 8D 0A DD  1F5A             STA TODMIN2         ;ERGEBNIS IN
C0C3           1F7F ;               TOD-MIINUTENREGISTER
C0C3           1F82 ;
C0C3 20 FC C0  1F9F             JSR ASCBCD1         ;DASSELBE
C0C6 8D 09 DD  1FBB             STA TODSEC2         ;DIE SEKUNDEN
C0C9           1FBE ;
C0C9 20 66 C1  1FDA             JSR TEST            ;PRUEFEN,OB 1/10
C0CC           1FF9 ;               SEKUNDEN=ZAHL
C0CC 8D 08 DD  2017             STA TOD10TH2        ;UND EINTRAGEN
C0CF           2039 ;               INS TOD-REGISTER
C0CF           205D ;  DIE UHR BEGINNT JETZT ZU LAUFEN
C0CF           2060 ;
C0CF A9 00     207D             LDA #$00            ;KENNUNG FUER OK.
C0D1 4C 3C BC  20A2 AKKUFAC     JMP ACTOFC          ;AKKU ZUR UEBER-
C0D4           20C9 ;               GABE INS BASIC IN FAC
C0D4           20CC ;
C0D4           20F5 ;********** FEHLER AUFGETRETEN ********
C0D4           20F8 ;
C0D4 68        2116 FEHLER      PLA                 ;JSR-ADRESSEN VOM
C0D5 68        212A             PLA                 ;STAPEL HOLEN
C0D6           212D ;
C0D6 68        2138 ERROR       PLA
C0D7 68        213E             PLA
C0D8           2141 ;
C0D8 A9 FF     2164 ERROR       LDA #$FF            ;FEHLERKENNUNG IN
C0DA D0 F5     2180             BNE AKKUFAC         ;AKKU UND FAC
C0DC           2183 ;
C0DC           21AC ;ENDE DIESES TEILS D. UNBEDINGTEN SPRG.
C0DC           21D5 ;--------------------------------------
C0DC           21D8 ;
C0DC           2201 ;**** ALARMZEIT EINLESEN **************
C0DC           2204 ;
C0DC           222A ;  AUFRUF DURCH Z.B. USR("AHHMMSSTT")
C0DC           222D ;
C0DC C0 08     224B ALSET       CPY #$08            ; 8 ZEICHEN ?
C0DE D0 F8     2265             BNE ERROR1          ;NEIN=FEHLER
C0E0           2268 ;
C0E0 AD 0F DD  2273             LDA CRB2
C0E3 09 80     228E             ORA #%10000000      ;ALARMBIT
C0E5 8D 0F DD  22A1             STA CRB2            ;SETZEN
C0E8           22A4 ;
C0E8 A9 84     22C0             LDA #%10000100      ;ALARM-NMI
C0EA 8D 0D DD  22D5             STA ICR2            ;ZULASSEN
C0ED           22D8 ;
C0ED A9 3C     22F3             LDA #$3C            ;VERZOEGERUNGS-
C0EF 85 04     230D             STA VORW            ;WERT VORGEBEN
C0F1 85 02     2318             STA VERZ
C0F3 A9 FF     2336             LDA #$FF            ;EOR-WERT VORGEBEN
C0F5 85 03     2341             STA FARB
C0F7 A0 01     235F             LDY #$01            ;BUCHSTABE UEBERL.
C0F9 4C A6 C0  236D             JMP STELLEN
C0FC           2370 ;
C0FC           2373 ;
C0FC           239C ;**************************************
C0FC           23C5 ;UNTERPROGRAMM ZUR UMWANDLUNG DER ASCII
C0FC           23EC ;CODES IN BCD-ZAHLEN UND PRUEFUNG DER
C0FC           23FF ;EINGABE-ZEICHEN.
C0FC           2402 ;
C0FC A9 60     2427 ASCBCD1     LDA #$60            ;BCD 60 ALS GRENZE
C0FE           244F ;               FUER MIN UND SEK WERTE
C0FE           2452 ;
C0FE 85 24     2465 ASCBCD      STA INDEX3
C100 20 13 C1  2482             JSR TEST1           ;PRUEFEN OB ZAHL
C103 0A        249A             ASL                 ;AUS LSB INS MSB
C104 0A        24AB             ASL                 ;SCHIEBEN
C105 0A        24B2             ASL
C106 0A        24B9             ASL
C107 85 25     24D7             STA INDEX4          ;UND ZW.SPEICHER
C109           24DA ;
C109 20 13 C1  24F7             JSR TEST1           ;NAECHSTE ZIFFER
C10C           2510 ;               PRUEFEN
C10C 05 25     252C             ORA INDEX4          ;MSB AUS ZWSP.
C10E           2552 ;               UND LSB ZUSAMMENOREN
C10E C5 24     256F             CMP INDEX3          ;UNTER GRENZW.?
C110 B0 C4     258D             BCS ERROR           ;NEIN=FEHLERAUSG.
C112           2590 ;
C112 60        2596             RTS
C113           2599 ;
C113           25C2 ;** PRUEFUNG OB ASCII-ZAHL VORLIEGT ***
C113           25C5 ;
C113 B1 22     25E8 TEST1       LDA (INDEX),Y       ;ZEICHEN EIN-
C115           2607 ;               LESEN IN AKKU
C115 38        260D             SEC
C116 E9 30     2625             SBC #$30            ;< ASCII 0 ?
C118 90 BA     263D             BCC FEHLER          ;JA=FEHLER
C11A           2640 ;
C11A C9 0A     2659             CMP #$0A            ;>= ASCII : ?
C11C B0 B6     2671             BCS FEHLER          ;JA=FEHLER
C11E           2674 ;
C11E C8        2690             INY                 ;SCHLEIFENZAEHLER + 1
C11F 60        2696             RTS
C120           2699 ;
C120           26C2 ;**** ENDE PROGRAMMTEIL UHR STELLEN ***
C120           26C5 ;
C120           26EE ;--------------------------------------
C120           26F1 ;
C120           271A ;********** UHR LESEN *****************
C120           271D ;
C120           273E ;     GESCHIEHT DURCH USR(ZAHL)
C120           2741 ;
C120 A9 07     2761 ZAHLVAR     LDA #$07            ;STRINGLAENGE
C122 20 7D B4  277F             JSR STRINI8         ;SCHAFFT 7 BYTE
C125           27A7 ;               PLATZ FUER STRING UND
C125           27CF ;               LEGT START NACH $62/63
C125           27F6 ;               SOWIE LAENGE NACH $61
C125           2814 ;               (FAC $61-66)
C125           2817 ;
C125 A0 00     2831             LDY #$00            ;ZAEHLER AUF 0
C127 AD 0B DD  284F             LDA TODHR           ;STUNDE AUSLESEN,
C12A           2878 ;               DABEI WIRD GESAMTE ZEIT
C12A           28A1 ;               ZWISCHENGESPEICHERT UND
C12A           28C7 ;               ERST NACH LESEN DER
C12A           28EF ;               1/10-SEK ZURUECKGEHOLT
C12A           2914 ;               MIT AKTUELLEN WERT.
C12A           2917 ;
C12A 08        2935             PHP                 ;STATUS ZWISCHENSPEICH.
C12B           2938 ;
C12B 29 1F     294F             AND #$1F            ;=0001 1111
C12D           2978 ;               LOESCHEN DER AM/PM-FLAG
C12D C9 12     2996             CMP #$12            ;=0001 0010 =BCD12
C12F D0 02     29B0             BNE NO12            ;<>DANN SPRUNG
C131 A9 00     29CE             LDA #$00            ;SONST STATTDESSEN
C133           29D1 ;
C133 28        29F0 NO12        PLP                 ;STATUS ZURUECKHOLEN
C134 10 05     2A0A             BPL AM              ;FALLS KEINE AM/
C136           2A2F ;               PM-FLAG GESETZT WAR
C136           2A32 ;
C136 F8        2A4C             SED                 ;SONST ADDIEREN VON
C137 18        2A62             CLC                 ;BCD 12 WEIL PM
C138 69 12     2A6D             ADC #$12
C13A D8        2A73             CLD
C13B           2A76 ;
C13B 20 55 C1  2A96 AM          JSR BCDASC          ;UP ZUR UMRECHNG
C13E           2ABC ;               VOM BCD IN ASCII UND
C13E           2AE5 ;               ABLEGEN IM STRING. HIER
C13E           2B02 ;               STUNDENWERT
C13E           2B05 ;
C13E AD 0A DD  2B22             LDA TODMIN2         ;DASSELBE FUER
C141 20 55 C1  2B3C             JSR BCDASC          ;MINUTENWERT
C144           2B3F ;
C144 AD 09 DD  2B5C             LDA TODSEC2         ;UND SEKUNDEN-
C147 20 55 C1  2B6F             JSR BCDASC          ;WERT
C14A           2B72 ;
C14A AD 08 DD  2B8C             LDA TOD10TH2        ;UND 1/10-
C14D 20 60 C1  2BA8             JSR BCDASC1         ;SEKUNDENWERT
C150           2BAB ;
C150 68        2BC7             PLA                 ;USR-STRING-ARGUMENT-
C151 68        2BE5             PLA                 ;RUECKSPRUNG VORBEREIT.
C152           2BE8 ;
C152 4C CA B4  2C06             JMP STRLIT67        ;BRINGT STRING
C155           2C29 ;               DESCRIPTOR IN DIE
C155           2C52 ;               DESCRIPTORTABELLE ($19-
C155           2C79 ;               $21),SETZT POINTER IN
C155           2CA2 ;               FAC(HIER $64/65) DARAUF
C155           2CC8 ;               SETZT STRING-FLAGGE,
C155           2CE9 ;               ERHOEHT LETZTEN
C155           2D10 ;               DESCRIPTOR-INDEX UM 3
C155           2D38 ;               ROUTINE ENDET MIT RTS.
C155           2D3B ;
C155           2D64 ;**** ENDE DES LESENS DER UHR *********
C155           2D67 ;
C155           2D90 ;--------------------------------------
C155           2D93 ;
C155           2DBC ;* UNTERPROGRAMM Z. UMRECHNUNG BCD IN *
C155           2DE5 ;* ASCII U.EINTRAGEN IN STRINGSPEICHER*
C155           2DE8 ;
C155 48        2E0B BCDASC      PHA                 ;AUF STAPEL ZW.SPEICH.
C156           2E0E ;
C156 4A        2E2A             LSR                 ;MSB INS LSB SCHIEBEN
C157 4A        2E31             LSR
C158 4A        2E38             LSR
C159 4A        2E3F             LSR
C15A           2E42 ;
C15A 20 60 C1  2E5E             JSR BCDASC1         ;IN ASCII UM-
C15D           2E85 ;               RECHNEN UND SPEICHERN
C15D           2E88 ;
C15D 68        2EA5             PLA                 ;ZURUECKHOLEN DER BCD-
C15E 29 0F     2EC3             AND #$0F            ;ZAHL,LOESCHEN DES
C160           2ED8 ;               MSB
C160           2EDB ;
C160 09 30     2F00 BCDASC1     ORA #$30            ;DAZUODERN VON $30
C162           2F28 ;               ERZEUGT (WEIL NUR ZAHL
C162           2F4F ;               ZWISCHEN 0 UND 9) DEN
C162           2F78 ;               ASCII-WERT ($30 BIS 39)
C162           2F7B ;
C162 91 62     2F98             STA (FAC1),Y        ;EINTRAGEN IN
C164           2FB7 ;               STRINGTABELLE
C164           2FBA ;
C164 C8        2FCC             INY                 ;ZAEHLER +1
C165           2FCF ;
C165 60        2FD5             RTS
C166           2FD8 ;
C166           3001 ;****** REST DES UP ASCII-BCD *********
C166           3004 ;
C166 20 13 C1  3020 TEST        JSR TEST1           ;PRUEFT AUF
C169           3042 ;               ASCII-ZAHL (0-9)
C169 60        3048             RTS
C16A           304B ;
C16A           3074 ;****** NMI-REAKTION AUF ALARM ********
C16A           3077 ;
C16A A9 77     3097 ALARM       LDA #L,ALIRQ        ;NEUER IRQ-
C16C 8D 14 03  30AB             STA IRQVL           ;VEKTOR
C16F A9 C1     30BA             LDA #H,ALIRQ
C171 8D 15 03  30C6             STA IRQVH
C174           30C9 ;
C174 4C BC FE  30E5             JMP NMIEND          ;REST DER NOR-
C177           3108 ;               MALEN NMI-ROUTINE
C177           310B ;
C177           3134 ;****** DIE  NEUE IRQ-ROUTINE *********
C177           3151 ;           RAHMENBLINKEN
C177           3154 ;
C177           3157 ;
C177 C6 02     3175 ALIRQ       DEC VERZ            ;ZEITSCHLEIFE
C179 F0 03     3191             BEQ BLINK           ;BLINKEN WENN 0
C17B           3194 ;
C17B 4C 31 EA  31B2             JMP NORM            ;SONST NORMALE IRQ
C17E           31B5 ;
C17E A5 04     31D5 BLINK       LDA VORW            ;ZAEHLER RUECK-
C180 85 02     31E8             STA VERZ            ;SETZEN
C182           31EB ;
C182 AD 20 D0  3203             LDA RAND            ;RAHMENFARBE
C185 45 03     321B             EOR FARB            ;INVERTIEREN
C187 8D 20 D0  3226             STA RAND
C18A           3229 ;
C18A 4C 31 EA  3244             JMP NORM            ;ZUM NORMAL-IRQ
C18D           3247 ;
C18D           324D             .EN
Listing 4. Der Quelltext zur Echtzeituhr
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →