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 |
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:
| 56324 | dezimal 37 | LSB |
| 56325 | dezimal 64 | MSB |
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:
- Bit 0
an dieser Stelle führt zum sofortigen Anhalten des Timers. 1 in diesem Bit startet das Herunterzählen. - Bits 1 und 2
Diese beiden Bits hängen mit dem externen Signalverkehr zusammen und sollen für uns außer acht bleiben.
- Bit 3
Ist dieses Bit = 1, dann ist der sogenannte »One Shot«-Betrieb des Timers aktiv. Das bedeutet, daß vom Startwert an heruntergezählt wird bis auf Null. Es findet nun das programmierte Ereignis statt (zum Beispiel ein IRQ). Anschließend wird der Startwert wieder eingeladen und der Timer gestoppt.
Im Gegensatz dazu läuft der »Continuous«-Betrieb, wenn das Bit den Wert 0 enthält. Dabei geschieht zunächst dasselbe wie beim One Shot Modus, der Timer wird aber nicht angehalten, sondern der ganze Vorgang wiederholt sich in einer Endlosschleife.
- Bit 4
Ein Hineinschreiben einer 1 in dieses Bit erzeugt ein sofortiges Neuladen der Timer-Register mit dem Startwert. Dabei ist es gleichgültig, ob der Timer gerade läuft oder nicht. Schreibt man eine Null ein, hat das keine Wirkung.
Beim Lesen des Registers ist dieses Bit immer 0.
Zu diesem Bit und seiner Wirkung ist noch etwas zu sagen. Das Neuladen des Timers geschieht
- immer dann, wenn ein Unterlauf stattgefunden hat oder
- falls der Timer steht und in die Register ein Startwert geschrieben wird. Dabei ist der CIA so konstruiert, daß man kein zwangsweises Laden (also mit Bit 4 = 1) braucht, wenn man den Startwert in der Reihenfolge LSB MSB in die Register bringt.
Die Bits 5 bis 7 haben nun unterschiedliche Bedeutung im CRA und im CRB:
Register CRA ($0E)
- Bit 5:
Ist dieses Bit gleich Null, dann wird im Systemtakt gezählt. Den hatten wir vorhin zur Zeitberechnung schon verwendet. Wenn das Bit auf 1 gesetzt ist, zählt der Timer externe Signale.
- Bit 6:
Spielt für den Signalverkehr über den seriellen Port eine Rolle und soll uns hier nicht weiter beschäftigen.
- Bit 7:
Damit steuert man nicht den Timer A, sondern dieses Bit bezieht sich auf die gleich noch zu behandelnde Echtzeituhr.
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.


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
- Bit 0 = 1 Start Timer A
- Bit 3 = 0 Dauerlauf
- Bit 5 = 0 Systemtakt
CRB
- Bit 0 = 1 Start Timer B
- Bit 3 = 0 Dauerlauf
- Bit 5 = 0
- Bit 6 = 1 Timer B zählt Unterläufe von Timer A.
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.

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är | Dezimal |
| 0000 | 0 |
| 0001 | 1 |
| 0010 | 2 |
| 0011 | 3 |
| 0100 | 4 |
| 0101 | 5 |
| 0110 | 6 |
| 0111 | 7 |
| 1000 | 8 |
| 1001 | 9 |
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:
| 0010 | 0101 |
| ^ | ^ |
| 2 | 5 |
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
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
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
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