![]() |
MikrocomputertechnikProf. Jürgen Plate |

16-Bit-Instruktionen
Vorteile bei der Programmierung
(z. B. bei Schleife: A zum Rechnen, B als Schleifenzähler)
64 K Adreßraum
I-Bit auf 0 setzen). Bleibt
solange gesperrt, solange der Stackpointer nicht initialisiert wurde.

Der 68HC11 kennt 59 verschiedene Grundbefehle
überschaubarer Befehlssatz.
Anwendung der Befehle mit unterschiedlichen Registern und Adressierungsarten führt
zu 1464 verschiedenen OP-Codes. Der OP-Code besteht (einschließlich Angabe
über Adressierungart) aus einem, zwei oder drei Bytes:
Der Adreßteil (falls vorhanden) besteht aus einem oder zwei Bytes; es gibt
also 1-, 2-, 3-, 4- und 5-Byte-Befehle. Das Befehlsformat kann also sein:

Das "prebyte" erweitert den Befehlsumfang, so daß mehr als 256 Befehle möglich sind. Der Nachteil dabei ist, daß die Abarbeitung des Befehls länger dauert und der Befehl natürlich auch ein Byte mehr an Speicher braucht.
Adressen werden in zwei aufeinanderfolgenden Speicherbytes abgelegt und zwar in der Form
| AH | AL |
| ea | ea+1 |
|---|
Mit "ea" wird die effektive Adresse = echte Adresse = Adresse des Operanden im Speicher bezeichnet. Je nach Adressierungsart (siehe unten) ist eine Adreßberechnung notwendig. Das Ergebnis der Adreßrechnung landet im Adreßregister und wird dann zur Adressierung des Speichers verwendet.

LDAA #20 - Lade Akku A mit dem Wert 20

LDAA $A174 - Lade Akku A mit dem Inhalt der Speicherzelle $A174

LDAA <$80 - Lade Akku A mit dem Inhalt der Speicherzelle $80


CLR 5,X (ergibt als Code: 6F 05) CLR -5,X (ergibt als Code: 6F FB)

Befehlsaufbau: offset = Zieladresse - Befehlsadresse - Befehlslänge
Befehlsausführung: Zieladresse = Befehlszählerstand + offset


Maschinensprache:
| Marke | OP-Code | Operand/Adresse | Kommentar |
Beispiel:
START LDAA DAT1 ; Zähler initialisieren
Anweisung
für den Assembler, Genaueres später.
Zusätzlich sind auch reine Kommentarzeilen möglich, die mit einem "*" in Spalte 1 beginnen.
| Adresse | Inhalt | Marke | Befehl | Operand | Kommentar |
| ORG | $8000 | In den Speicher ab $8000 | |||
| MAIN | BRA | MARKE | relativer Vorwärtssprung | ||
| JMP | MARKE | absoluter Vorwärtssprung | |||
| BRA | MAIN | relativer Rückwärtssprung | |||
| MARKE | JMP | MAIN | absoluter Rückwärtssprung | ||
| END |
| Adresse | Inhalt | Marke | Befehl | Operand | Kommentar |
| ORG | $8000 | In den Speicher ab $8000 | |||
| 8000 | 20 ?? | MAIN | BRA | MARKE | relativer Vorwärtssprung |
| 8002 | 7E ?? ?? | JMP | MARKE | absoluter Vorwärtssprung | |
| 8005 | 20 ?? | BRA | MAIN | relativer Rückwärtssprung | |
| 8007 | 7E ?? ?? | MARKE | JMP | MAIN | absoluter Rückwärtssprung |
| END |
| Adresse | Inhalt | Marke | Befehl | Operand | Kommentar |
| ORG | $8000 | In den Speicher ab $8000 | |||
| 8000 | 20 05 | MAIN | BRA | MARKE | relativer Vorwärtssprung |
| 8002 | 7E 80 07 | JMP | MARKE | absoluter Vorwärtssprung | |
| 8005 | 20 F9 | BRA | MAIN | relativer Rückwärtssprung | |
| 8007 | 7E 80 00 | MARKE | JMP | MAIN | absoluter Rückwärtssprung |
| END |
Der Assembler führt einen Zähler, der Auskunft über den aktuellen Adreßpegel gibt. Dieser 'Location Counter' dient beispielsweise zum Berechnern von Sprungadressen. Die Pseudobefehle werden im OP-Code-Feld einer Assemblerzeile angegeben. Unser Assembler kennt folgende Direktiven:
| ORG | Origin Der Location Counter wird auf die im Operandenfeld angegebene Adresse gesetzt, z. B.:
ORG $8000
|
| EQU | Equate Definition eines Namens (Konstante, Marke). Der im Operandenfeld angegebene Wert wird dem im Markenfeld angegebenen Namen gleichgesetzt, z. B.: ETX EQU 3 CR EQU $D LF EQU $A PUFL EQU $100 |
| DC.B | Define Constant Byte Reservierung von Speicherplatz und Belegung mit den im Operandenfeld angegebenen konstanten Byte-Werten. Mehrere Operanden durch Komma trennen! Z. B.: TAB DC.B $0D,$0A,$03Neben einfachen Konstanten sind in (einfache oder doppelte) Hochkomma eingeschlossene Zeichenketten möglich. Die Hochkommas gehören dabei nicht zur Zeichenkette. In den Zeichenketten sind folgende Sonderzeichen erlaubt:
TEXT DC.B "Hello World!\n\r" |
| DC.W | Define Constant Word Reservierung von Speicherplatz und Belegung mit den im Operandenfeld angegebenen konstanten 16-Bit-Werten. Mehrere Operanden durch Komma trennen, z. B.: ATAB DC.W $FF30,$FF45,$FFA0 |
| DC.L | Define Constant Longword Reservierung von Speicherplatz und Belegung mit den im Operandenfeld angegebenen konstanten 32-Bit-Werten. Mehrere Operanden durch Komma trennen, z. B.: XTAB DC.L $FF30FF45,$F000FFA0 |
| DS.B DS.W DS.L |
Define Storage Bytes/Words/Longwords Reservieren von Speicherbytes, Speicherworten (16 Bit) oder Langworten (32 Bit) ohne Vorbelegung. Der Operand gibt die Anzahl der zu reservierenden Bytes an, z. B.: PUFFER DS.B 100 ADRTAB DS.W 23 |
| INCLUDE |
Einfügen einer Quelldatei an der entsprechenden Stelle. Der Dateiname
wird entweder in < ... > (voreingestelltes Include-Verzeichnis)
oder " ... " (beliebiger Dateipfad) eingeschlossen, z. B.:
INCLUDE "definitionen.a"
INCLUDE <HC11.h>
|
| NOLIST | Unterdrücken der Erzeugung eines Programmlistings bis zum nächsten LIST-Befehl. |
| LIST | Fortsetzen des Listings nach einem voher pazierten NOLIST-Befehl. |
| END | Ende des Assemblerprogramms. Optionaler Befehl am Programmende. Wird aus Gründen der Kompatibilität vom Assembler akzeptiert, kann aber weggelassen werden. |
Anmerkung: Da bei einem Microcontroller zwischen ROM bzw. EEPROM-Speicher und RAM unterschieden werden muß, ist auch die Reservierung von Speicher von dieser Unterscheidung betroffen. Mit DC.B; DC.W oder DC.L vordefinierte Konstante liegen im ROM/EEPROM-Bereich, Mit DS.B, DS.W oder DS.L reservierter Speicher im RAM-Bereich.
STACK EQU $7FFF Stackbereich PROG EQU $8000 Programmbereich DATA EQU $2000 Datenbereich (auch Adr. 0 möglich) RVECT EQU $FFFE Reset-Vektor SCCR1 EQU $102C SCCR2 EQU $102D CR EQU 13 Carriage-Return-Zeichen LF EQU 10 Linefeed-Zeichen ETX EQU 3 Textende MAXDATA EQU 100Wichtig sind die ersten fünf Zeilen, die bei keinem Programm fehlen dürfen. Sie legen die Adressbereiche für RAM und EEPROM fest und definieren die Adressen der beiden Vektoren, die immer gesetzt werden müssen.
ORG DATA Datenbereich z.B. ab Adresse $2000
COUNT DC.B 0 Wert mit Null vorbelegen
PUFFER DS.B 80 80 Byte Pufferbereich reservieren
TEXT DC.B 'Hello World' Text, abgeschlossen durch Zeilen-
DC.B CR, LF, ETX wechsel und Nullbyte
Achtung: Der Assembler kümmert sich nicht um die Adreßlage des Programms,
auch Überlappungen mit dem Datenbereich werden nicht als Fehler gemeldet
aufpassen.
Es gibt zwei Möglichkeiten der Anordnung von Haupt- und Unterprogrammen. Üblich ist es, das Hauptprogramm am Anfang zu postieren und dann die Unterprogramme folgen zu lassen. Wer lieber die UP zuerst stehen hat, muß das HP mit einer Marke versehen (z. B. "MAIN") und nach der ORG-Anweisung als erste Anweisung einen Sprung zum HP eintragen, z. B.:
....... Definitionen (1. und 2.)
ORG PROG Programmbereich, z. B. $8000
JMP MAIN
....... Unterprogramme
MAIN LDS #STACK Stackpointer setzen, sonst geht nichts
.
.
.
.
ORG RVECT
DC.W MAIN Reset-Vektor auf Programmanfang setzen
.
. ggf. weitere Vektoren setzen
. (z. B. INT)
.
END

Load Register from Memory or Constant
CLR Clear Akkumulator: 0
Akkumulator-Register

Store Register into Memory (8 Bit/16 Bit)
adr.
adr., adr+1
Clear Memory

Kopie des Inhalts eines Registers in ein anderes (transfer)
(A)
B
(A)
Statusregister
(B)
A
(Statusregister)
A
(S)
X
(S)
Y
(X)
S
(Y)
S
Austausch von Registerinhalten (exchange)
D
X
D
Y
Beispiel: Tausch A
B
Benötigt wird eine Hilfsvariable im Daten-Speicherbereich
STAA HILF
TBA
LDAB HILF
Beispiel: Tausch X
Y
* Beispielbelegung X Y D
* 1 2 3
XGDX 3 2 1
XGDY 3 1 2
XGDX 2 1 3

(A) + (adr.)
A
(B) + (adr.)
B
(D) + (adr., adr+1)
D (16-Bit-Addition)

(A) + (B)
A
(X) + (B)
X (Adreßrechnung),
B als vorzeichenlose Zahl aufgefaßt
(Y) + (B)
Y (Adreßrechnung),
B als vorzeichenlose Zahl aufgefaßt
Addieren mit Übertrag (add with carry)
(A) + (adr.) + C
A
(B) + (adr.) + C
B
Beispiel: Addition zweier 4-Byte-Zahlen
1. Operand: Adresse $41 - $44
2. Operand: Adresse $45 - $48
Ergebnis: Adresse $49 - $4C
LDAA $44 Niederwertiges Byte addieren
ADDA $48
STAA $4C
LDAA $43 Zweites Byte addieren
ADCA $47
STAA $4B
LDAA $42 Drittes Byte addieren
ADCA $46
STAA $4A
LDAA $41 Höchstwertiges Byte addieren
ADCA $45
STAA $49
Erhöhen (increment)
(A) + 1
A
(B) + 1
B
(S) + 1
S
(kein Flag beeinflußt)
(X) + 1
X
(nur Z-Flag beeinflußt)
(Y) + 1
Y
(nur Z-Flag beeinflußt)
(adr.) + 1
adr.
(Increment eines Speicherbytes)
(A) - (adr.)
A
(B) - (adr.)
B
Subtraktion mit Übertrag (subtract with carry)
(A) - (adr.) + C
A
(B) - (adr.) + C
B
Erniedrigen (decrement)
(A) - 1
A
(B) - 1
B
(S) - 1
S
(kein Flag beeinflußt)
(X) - 1
X
(nur Z-Flag beeinflußt)
(Y) - 1
Y
(nur Z-Flag beeinflußt)
(adr.) - 1
adr.
(Decrement eines Speicherbytes)
Vorzeichenwechsel (negate)
A komplementieren
B komplementieren
adr. komplementieren
Vorzeichenlose Multiplikation (A) * (B)
D
Dividieren (divide)
Vorzeichenlose Division, ganzzahliger Anteil (integer divide)
für D > X: (D) / (X)
X, Rest in D
Vorzeichenlose Division, Quotient echter Bruch (fractional divide)
für D < X: (D) / (X)
X, Rest in D
Beispiele:
IDIV: FDIV: $8421 : $0004 = $2108 R $0001 $1000 : $2000 = $.8000 R $0000 $0001 : $FFFF = $0000 R $0001 $0001 : $FFFF = $.0001 R $0001 $FFFF : $0001 = $FFFF R $0000 $FFFF : $0001 = unzulässig, V=1
Decimal Adjust A
Akku enthält zwei BCD-Ziffern
$98,
-3
$97, usw.).

Beispiel: Addition zweier 4-stelligen BCD-Zahlen
1. Zahl: Adr. $31-$32
2. Zahl: Adr. $33-$34
Ergebnis: Adr. $35-$36
LDAA $32 niederwertige 2 Ziffern
ADDA $34 binär addieren
DAA BCD-Justage
STAA $36
LDAA $31 höherwertige 2 Ziffern
ADCA $34 binär addieren mit Carry!
DAA BCD-Justage
STAA $35

(A) and (adr.)
A
(B) and (adr.)
B
Beispiele:
1) Löschen der 4 höherwertigen Bits von Akku A ANDA #$0F 2) Rücksetzen des 5. Bits ANDA #%11101111
(A) or (adr.)
A
(B) or (adr.)
B
Beispiele:
1) Setzen der 4 höherwertigen Bits von Akku A
ORA #$F0
2) Setzen des 5. Bits
ORAA #%00010000
(A) exor (adr.)
A
(B) exor (adr.)
B
Beispiel:
Invertieren der 4 höherwertigen Bits von Akku A
EORA #%11110000
(A) and (adm.)
Nur Flags neu setzen, A bleibt unverändert
(B) and (adm.)
Nur Flags neu setzen, B bleibt unverändert
Invertieren aller Bits
not (A)
A
not (B)
B
not (adr.)
adr.
Beispiel: Verwendung des Speicher-Bytes $41 als Software-Flip-Flop. Zu Beginn des Programms muß der Inhalt von $41 gelöscht werden!
COM $41 Inhalt wird $FF . . COM $41 Inhalt wird wieder 0 . . usw.

MSB
C-Flag
Akku A nach rechts schieben
Akku B nach rechts schieben
Akku D nach rechts schieben
Speicherwort adr. nach rechts schieben
LSLx Logical Shift Left:
von rechts wird 0 nachgeschoben: 0
LSB
MSB
C-Flag
Akku A nach links schieben
Akku B nach links schieben
Akku D nach links schieben
Speicherwort adr. nach links schieben
MSB (Vorzeichen bleibt erhalten)
Akku A nach rechts schieben
Akku B nach rechts schieben
Speicherwort adr. nach rechts schieben
ASLx Arithmetic Shift Left:
von rechts wird 0 nachgeschoben: 0
LSB
MSB
C-Flag
Identisch mit LSL!
Akku A nach links schieben
Akku B nach links schieben
Akku D nach links schieben
Speicherwort adr. nach links schieben
ROLx Rotate Left
C-Flag
LSB
MSB
C-Flag
Akku A linksrotieren
Akku B linksrotieren
Speicherwort adr. linksrotieren
RORx Rotate Right
C-Flag
MSB
LSB
C-Flag
Akku A rechtsrotieren
Akku B rechtsrotieren
Speicherwort adr. rechtsrotieren
Beispiele:
1) Multiplikation von Akku A mit 10: (A) * 10A ASLA (A)*2
A STAA $40 Erg. zwischenspeichern ASLA (A)*4
A ASLA (A)*8
A ADDA $40 (A)*8 + (A)*2
A 2) Akku D nach links schieben: A C B ASLB MSB von B --> Carry +----------+__+-+__+----------+ ROLA Carry --> LSB von A +----------+ +-+ +----------+ 3) Zerlegung eines Bytes in zwei Halbbytes: Die Halbbytes sind in getrennten Speicherzellen als niederwertiges Halbbyte zu speichern (höherwertiges Halbbyte ist auf 0 zu setzen). $70: zu zerlegendes Byte $71: höherwertiges Nibble $72: niederwetiges Nibble LDAA $70 Byte holen (binär: xxxxyyyy) ANDA #$0F niederwertiges Nibble maskieren STAA $72 speichern (binär: 0000yyyy) LDAA $70 Byte nochmal holen LSRA 4 x nach rechts schieben (0xxxxyyy) LSRA (00xxxxyy) LSRA (000xxxxy) LSRA (0000xxxx) STAA $71 höherwertiges Nibble speichern
Programmfortsetzung abhängig
von Dateneigenschaften
Steuerbefehle.
Beispiele bei den Sprungbefehlen.
Akku A = 0 ?
Akku B = 0 ?
(adr.) = 0 ?
| X1 = X2 | X1 - X2 = 0 |
| X1 < X2 | X1 - X2 < 0 |
| X1 > X2 | X1 - X2 > 0 |
Durch bedingte Sprungbefehle kann dann abhängig vom Ergebnis im Programm verzweigt werden. Es gibt 8-Bit- und 16-Bit-Vergleiche (je nach Wortbreite des Registers).
(A) - (adr.)
Flags
(B) - (adr.)
Flags
(D) - (adr., adr.+1)
Flags
(X) - (adr., adr.+1)
Flags
(Y) - (adr., adr.+1)
Flags
(A) - (B)
Flags
| clear carry flag | X X X X X X X 0 |
| clear interrupt flag | X X X 0 X X X X |
| clear overflow flag | X X X X X X 0 X |
| set carry flag | X X X X X X X 1 |
| set interrupt flag | X X X 1 X X X X |
| set overflow flag | X X X X X X 1 X |
LDAA #mask
ORAA adr.
STAA adr.
LDAA #mask
COMA
ANDA adr.
STAA adr.
XIRQ & X=1: next instruction
XIRQ & X=0: service interrupt
IRQ & I=1: no activity
IRQ & I=0: service interrupt
TPA Statusreg. nach Akku A
ANDA #$7F Freigabe (S-Flag auf 0)
TAP Akku A nach Statusreg.
Für den Fall S=0 und X=1 wird beim Aktivieren des XIRQ-Eingangs der
Prozessor nach einem STOP-Befehl "aufgeweckt" und er macht im Programm
ganz normal weiter.
Programmausführung
wird an anderer Stelle fortgesetzt. Das Statusregister wird nicht beeinflußt.
Einige Befehle speichern Registerinhalte auf dem Stack oder holen Registerinhalte
von dort wieder zurück.

adr.
PC
BRA dest.
Verzweigung
abhängig vom Ergebnis der vorhergehenden Operation
ist die Bedingung erfüllt, erfolgt ein Sprung;
im anderen Fall wird die Programmausführung beim nächsten Befehl fortgesetzt.
Der Assembler übernimmt die Offset-Berechnung.
| Befehl | Bedeutung | Sprungbedingung |
|---|---|---|
| einfach (simple) | ||
| BCC dest. | carry clear | C=0 |
| BCS dest. | carry set | C=1 |
| BVC dest. | overflow clear | V=0 |
| BVS dest. | overflow set | V=1 |
| BNE dest. | result not equal zero | Z=0 (BZC) |
| BEQ dest. | result equal zero | Z=1 (BZS) |
| BPL dest. | result plus | N=0 (BNC) |
| BMI dest. | result minus | N=1 (BNS) |
| natürlich (unsigned) | ||
| BHI dest. | higher | Op1 > Op2 |
| BLS dest. | lower or same | Op1 <= Op2 |
| BLO dest. | lower | OP1 < Op2 |
| BHS dest. | higher or same | Op1 >= Op2 |
| konegativ (signed) | ||
| BGT dest. | greater than | Op1 > Op2 |
| BLE dest. | less or equal | Op1 <= Op2 |
| BLT dest. | less than | Op1 < Op2 |
| BGE dest. | greater or equal | Op1 >= Op2 |
| bitabhängig | ||
| BRCLR | adr. mask dest | springe, wenn die in der Maske mit "1" markierten
Bits alle "0" sind alle Bits des Speicherbytes adr.
werden mit der Maske UND-verknüpft und wenn das Ergebnis 0 ist, wird
gesprungen. |
| BRSET | adr. mask dest | springe, wenn die in der Maske mit "1" markierten
Bits alle "1" sind alle Bits des Speicherbytes adr.
werden mit der Maske UND-verknüpft und wenn das Ergebnis gleich der
Maske ist, wird gesprungen. |

Möglichkeit der Rückkehr

No Operation
Branch Never
LIFO-Speicher (Lat In First Out). Die
Realisierung beim 68HC11 erfolgt als externer Stack (Software-Stack).
Er ist Teil des Arbeitsspeichers, Die automatische Adressierung erfolgt
über den Stapelzeiger (Stackpointer, S). Der Stackpointer ist ein
16-Bit-Register und zeigt immer auf die nächste freie Zelle. Der
Stack wächst zu kleiner werdenden Adressen ("nach unten").

Am Programmanfang muß der Stack mit einem sinnvollen Wert besetzt werden.
Die Vorteile des SW-Stacks mit Stackpointer-Adressierung sind unter anderem:

MSB wird beim PUL zuerst geladen
Schreiben in den Stack:
Register A
Stack
Register B
Stack
Register X
Stack
Register Y
Stack
Lesen aus dem Stack:
Stack
Register A
Stack
Register B
Stack
Register X
Stack
Register Y
Wichtig ist der sorgfältige und überlegte Umgang mit Stack- und SP-Operationen. Damit kein Stack-Überlauf(-Unterlauf) auftritt:
PSHA
PSHB
.
.
.
PULB
PULA
UP-Bibliotheken.
Sie sollen möglichst universell programmiert (und damit für wechselnde
Datenwerte) sein
Parameter müssen
übergeben werden (Eingabe- und Ausgabeparameter).
Subroutines müssen am beliebiger Stelle des Hauptprogramms aufgerufen
werden können (und damit auch an mehreren Stellen), sie sollten daher
den Inhalt derjenigen Register sichern (z. B. auf dem Stack), die
innerhalb des UP verändert werden. Typische Anwendungen der UP-Technik sind:
Programmerstellung durch mehrere Programmierer möglich
Anmerkungen zur Dokumentation:
Aufgaben des aufrufenden Programms:
Sprung in das UP: JSR, BSR
Unterscheidung in der Adressierungsart. Wirkung:
Rücksprung aus dem UP: RTS
Letzter Befehl des UP, Wirkung:
Sorgfalt
bei Stackoperationen notwendig! Beim UP-Sprung (und Rücksprung) wird nur
der PC-Inhalt geändert, der Inhalt aller anderen Register bleibt erhalten.
Register können zur Parameterübergabe
verwendet werden
Im UP verwendete Register müssen gegebenenfalls
gesichert werden
Vorteil der Speicherung der Rücksprungadresse auf dem Stack:
verschachtelte UP
UP
UP
Möglichkeiten der Parameterübergabe:
indirekte Parameterübergabe
Beispiel: Verzögerungsroutine
Es soll eine Verzögerung von 1 ms erreicht werden. Das Prinzip der Routine ist recht einfach: Ein Akkumulator wird mit einem Anfangswert besetzt und dann in einer Schleife solange dekrementiert, bis sein Wert Null geworden ist.
ORG PROG Programm soll bei Adresse PROG beginnen
MAIN BSR VERZ Aufruf Unterprogramm
STOP BRA STOP Endlosschleife, stoppt Programm
("Wiederbeleben" des Computers mit Reset)
* Verzögerungs-Unterprogramm
* Verzögerungszeit: 1 ms
* Keine Parameter
*
VERZ LDAA #221 Anfangswert (Konstante) laden (siehe unten)
VZ NOP No Operation (Zeitverzoegerung)
NOP No Operation (Zeitverzoegerung)
DECA A runterzählen bis 0
BNE VZ solange A != 0, weiterer Durchlauf
RTS Verzögerung erreicht (A = 0)
END
Berechnung der Verzögerungszeit: Aus der Befehlstabelle kann man die Anzahl
der Taktzyklen für jeden Befehl entnehmen. Wenn man nun noch die Taktfrequenz
weiß, kann man die Ablaufzeit eines Programms ausrechnen. Wir müssen
vier Zeiten wissen:
tl Ausführungszeit LDAA 2 Taktzyklen
td -"- DECA + 2 NOP 6 -"-
tb -"- BNE 3 -"-
tr -"- RTS 5 -"-
Bei unserem Praktikumsrecher dauert ein Taktzyklus 0,5 Mikrosekunden. Die Gesamtzeit tg ergibt
sich zu:
tg = 0,5 * n * (td + tb) + tl + tr
= 0,5 * n * (6 + 3 ) + 2 + 5
= 0,5 * (n * 9 + 7)
Da tg = 1 ms = 1000 Mikrosekunden sein soll, berechnet sich n zu
n = (1000 - 3,5) / 4,5
= 996,5 / 4,5
= 221,44
n = 221
Es ergibt sich also ein kleiner Fehler; unsere Schleife ist einen knappen Taktzyklus zu langsam. Will man wiklich genaue Zeitintervalle, greift man auf den integrierten Timer zurück (siehe später).
Im gezeigten Beispiel "Verzögerungsroutine" ist die maximale Verzögerungszeit
durch die Wortbreite des Akku A (8 Bit
0..255) auf
etwas mehr als 1 ms begrenzt.
Für größere Verzögerungen:
Beispiel: Gegeben ist folgende Verzögerungsroutine mit 16-Bit-Register:
* Verzögerungs-Unterprogramm
* Verzögerungszeit: 500 ms
* Keine Parameter
*
VERZ LDX #ANF Anfangswert (Konstante) laden
VZ NOP No Operation (Zeitverzoegerung)
NOP No Operation (Zeitverzoegerung)
DEX X runterzählen bis 0
BNE solange X != 0, weiterer Durchlauf
RTS Verzögerung erreicht (X = 0)
Frage: Welchen Wert muß ANF haben, um eine Verzögerung von
500 ms zu erreichen?

Anwendungen:
Aufgaben der CPU bei einen Interrupt:

Start der ISR
Im allgemeinen wird ein Hardware-IRQ erst am Ende eine Befehlszyklus bedient. Außer dem PC und dem Stackpointer werden keine Register beeinflußt. Interrupts können geschachtelt werden (3 Ebenen).
| Signal | RESET | Unbedinger Abbruch und Neustart |
| Signal | XIRQ & (X-Bit = 0) | Unbedingte Unterbrechung (non maskable interrupt) |
| Signal | IRQ & (I-Bit = 0) | Bedingte Unterbrechung
(interrupt request) (kann auch interne Ursachen haben) I-Bit beeinflußbar durch die Befehle SEI/CLI |
| Befehl | SWI | Befehlsgesteuerte Unterbrechung (software interrupt) |
| Befehl | Illegal Opcode | Nicht implementierter Befehl |
Beim Auftreten eines Interrupts wird das I-Bit auf 1 gesetzt (Sperren IRQ), bei Reset und XIRQ auch das X-Bit. Beim RTI wird durch das Zurückschreiben des Statusregisters diese Sperre automatisch wieder aufgehoben. Das X-Bit kann nicht per Programm beeinflußt werden.
Jedem dieser Interrupts ist eine eindeutige Interrupt-Vektor-Adresse (= Adresse, unter welcher der Interrupt-Vektor, also die Adresse der Interrupt-Serviceroutine, zu finden ist) zugeordnet:

Zu jeder Interrupt-Art ist eine eigene ISR möglich.
Zumindest der RESET-Vektor muß bei Einschalten vohanden sein
ROM im höchsten Adreßbereich nötig.
Beispiel: Starten der Interrupt-Service-Routine für XIRQ

Grundsätzlich gilt für Programme mit Interrupt-Serviceroutinen, daß vier Schritte für die Initialisierung (zu Beginn des Hauptprogramms) nötig sind:
Zum vorhergehenden Abschnitt |
Zum Inhaltsverzeichnis |
Zum nächsten Abschnitt |