|
Programmbeispiele
Beispiel: Die größere von zwei Zahlen finden
Vergleichen ($40) und ($41), Ergebnis in $42 LDAA $40 1. Zahl holenCMPA $41 2. Zahl größer?BHSWEITER1. Zahl ist größerLDAA $41 2. Zahl ladenWEITERSTAA $42 Abspeichern Beispiel: 16-Bit-Addition (Prüfsumme) Addition eines Feldes von 8-Bit-Werten. Die Anzahl der Werte steht in Speicherbyte$42, die zu addierenden Werte folgen ab Adresse $43. Das 16-Bit-Ergebnis wirdin $40 (MSB) und $41 (LSB) abgelegt. CHECKSUMCLRA Summe in A und B, RegisterCLRB zuerst mal löschenLDX#$0043Adresse erster Summand (Feldanfang)CSUMADDB ,XFeldelement addieren ADCA #0Übertrag im MSB aufaddierenINXX inkrementierenDEC$42 Elementezähler vermindernBNECSUMWiederholen, solange Zähler > 0 istSTD$40 Checksumme speichernRTS Beispiel: Quadrate von 0 - 15 über Tabelle ermitteln Wert in $41, Ergebnis in $42
LDAB $41 Operanden holen
LDX #TABELLE X-Register auf Tabellenanfang
ABX X und B addieren
LDAA 0,X B-ten Eintrag aus Tabelle holen
STAA $42 und abspeichern
TABELLE DC.B 0,1,4,9,16,25,36,49,64,81,100
DC.B 121,144,169,196,225
Addition von 8-stelligen BCD-Zahlen
Die 1. Zahl belegt den Speicherbereich $41 - $44 (LSB zuerst)
Die 2. Zahl -"- $51 - $54 -"-
Das Ergebnis wird auf die erste Zahl gespeichert
LDAB #4 Zahlen sind 4 Byte lang = 8 Stellen
LDX #$41 1. Operand
LDY #$51 2. Operand
CLRA Akku A (und Carry-Flag) löschen
BCDADD LDAA ,X zwei Ziffern des 1.Operanden holen
ADCA ,Y+ zwei Ziffern des 2.Operanden addieren
DAA Dezimalkorrektur für BCD
STAA ,X+ Ergebnis abspeichern
DECB
BNE BCDADD solange, bis alle Stellen bearbeitet
Beispiel: Zählen der negativen Elemente in einem Feld
ANZAHL EQU 20 z.B. 20 Feldelemente
FELD RMB 20 Platz für 20 Werte
COUNT RMB 1 1 Byte Zähler
.
.
.
*
* Unterprogramm zum Zählen der negativen Elemente
*
COUNTNEG PSHA Register retten
PSHB
PSHX
CLRB Zähler für neg. Elemente löschen
LDX #FELD X auf Feldanfang
LDAA ANZAHL
STAA COUNT Zähler setzen
LOOP LDAA ,X+ nächstes Feldelement
BPL WEITER wenn positiv weiter
INCB negative Elemente zählen
WEITER DEC COUNT
BNE LOOP bis alle Elemente getestet sind
STAB COUNT Ergebnis in COUNT speichern
PULX Register restaurieren
PULB
PULA
RTS
Beispiel: Dezimal zu Siebensegment Codierung
Der Inhalt von Akkumulator B soll in die Siebensegmentdarstellung gemäß
untenstehender Abbildung umcodiert werden. Der erzeugte Code wird ebenfalls in
Akku B zurückgegeben. Bei Werten größer 9, soll B mit $FF besetzt
werden.
UMCO CMPB #9 größer als 9?
BHI ERR ja: -- Fehleranzeige
LDX #UCTAB Adresse Tabellenanfang in X
ABX X und B addieren
LDAB 0,X Eintrag aus Tabelle holen
RTS Rücksprung
* Codetabelle gleich an das UP anhängen
UCTAB DC.B $3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$6F
Beispiel: Binär zu ASCII konvertieren
Unterprogramm zur Konvertierung eines Binärwertes (0 - 15) in die ASCII-Darstellung
(z.B. für die Ausgabe am Terminal). Der Wert wird in Register A an das UP
übergeben und das entsprechende ASCII-Zeichen wird vom UP wieder in A zurückgegeben.
*
* Konvertierung Binär zu ASCII
* Parameter in Akku A
*
BINASC CMPA #9 0 bis 9 ?
BLS ZIF ja, dann direkt umwandeln
ADDA #7 "A" - "9" - 1 = $41 - $39 - 1 = 7
ZIF ADDA #$30 $30 = "0" (ASCII-Wert)
RET
Beispiel: ASCII-Zeichen zu Binär konvertieren
Unterprogramm zur Konvertierung eines ASCII-Zeichens (0 - 9, A - F) in einen Binärwert,
z.B. bei der Eingabe von Zahlen über das Terminal. Das Zeichen wird in Akku
A übergeben und der Wert wieder in A zurückgegeben. Bei Fehleingabe (keine
Ziffer) wird A auf $FF gesetzt.
*
* Unterprogramm ASCII-Binär-Konvertierung (0 - 9, A - F)
* Parameter in A
*
ASCBIN SUBA #$30 $30 = ASCII "0"
BLO FEHL Erg. negativ keine Ziffer
CMPA #9 kleiner oder gleich 9?
BLS DONE dann fertig
SUBA #7 "A" - "F" 10 - 15
CMPA #10 kleiner als 10?
BLO FEHL dann Fehler
CMPA #15 größer 15?
BLS DONE nein, fertig
FEHL LDAA #$FF Fehlerflag setzen
DONE RTS
Beispiel: Überlesen von Leerzeichen am Anfang einer Zeichenkette
Nach Ausführung zeigt X auf das erste Zeichen != ' '.
Der String muß mit einem Zeichen != ' ' abgeschlossen sein.
LDX #STRING Beginn der Zeichenkette
CHECK LDAA 0,X Zeichen lesen
INX X erhoehen
CHECK CMPA #$20 Leerzeichen?
BEQ CHECK Ja, weiter testen
DEX nein, Zeiger korrigieren
STRING DC.B ' Zeichenkette mit 4 Leerz.'
DC.B 0 Abschlußzeichen ETX
Beispiel: Vergleich zweier Zeichenketten (Strings)
LAENGE1 RMB 1 Länge erster String
TEXT1 RMB 80 erster String (max. 80 Zeichen)
LAENGE2 RMB 1 Länge zweiter String
TEXT2 RMB 80 zweiter String (max. 80 Zeichen)
FLAG RMB 1 Ergebnis (FF=ungleich, 00=gleich)
.
.
.
*
* Unterprogramm Stringvergleich
*
VERGLEICH LDAA $FF erst einmal auf "ungleich" (FF) setzen
STAA FLAG
LDAB LAENGE1 B als Zähler für den Vergleich
CMPB LAENGE2 Längen vergleichen
BNE DONE wenn Längen ungleich, fertig (Erg. FF)
LDX #TEXT1 X -> String 1
LDY #TEXT2 Y -> String 2
CHECK LDAA 0,X Zeichen aus String 1 vergleichen
CMPA 0,Y mit Zeichen aus String 2
BNE DONE wenn ungleich, fertig (Erg. FF)
INX
INY
DECB runterzählen
BNE CHECK weiter, bis Stringende erreicht
CLR FLAG alle Zeichen gleich, Flag := 0
DONE RTS fertig
Ergänzen eines ASCII-Codewortes auf gerade Parität
EVENPAR PSHB Codewort zwischenspeichern
CLRA Zaehler = 0
ZHL LSRB naechstes Bit ins Carry holen
ADCA #0 Carry zu A ddieren
TSTB Restwort = 0?
BNE ZHL nein, weiter
PULB Codewort holen
ASLB links schieben
LSRA Parity-Bit ins Carry
RORB Parity-Bit ins MSB vom Codewort
RTS
Beispiel: Software-Uhr
Eine Software-Uhr wird in der Regel durch einen periodischen Interrupt (z.B. vom
Timer) unterstützt. Bei jedem Interrupt wird ein Zähler incrementiert.
Die Zählung erfolgt in Sekunden, Minuten und Stunden. Das im Vordergrund arbeitende
Programm kann auf die Zeitinformation zugreifen.
Die Bedienung des Timer-Interrupts wird hier nur angedeutet. Der CLOCK-Interrupt
wird alle 100 ms ausgelöst = 10 Tics/s.
ZEHNTEL DC.B 0 1/10 Sekunden
SEKUNDEN DC.B 0 Sekunden
MINUTEN DC.B 0 Minuten
STUNDEN DC.B 0 Stunden
ORG $8000 Startadresse ISR (willkürlich gewählt)
CLOCK
* An dieser Stelle muß die
* Timer-Hardware bedient werden
INC ZEHNTEL 1/10 Sekunden erhöhen
LDAA #10
CMPA ZEHNTEL Sekunde erreicht?
BNE ENDCLOCK nein - fertig
CLR ZEHNTEL sonst 1/10 Sekunden auf 0 setzen
INC SEKUNDEN und Sekunden erhöhen
LDAA #60
CMPA SEKUNDEN Minute erreicht?
BNE ENDCLOCK nein - fertig
CLR SEKUNDEN sonst Sekunden auf 0 setzen
INC MINUTEN und Minuten erhöhen
CMPA MINUTEN Stunden erreicht?
BNE ENDCLOCK nein - fertig
CLR MINUTEN sonst Minuten auf 0 setzen
INC STUNDEN und Stunden erhöhen
LDAA #24
CMPA STUNDEN Tageswechsel?
BNE ENDCLOCK nein - fertig
CLR STUNDEN sonst Stunden auf 0 setzen
ENDCLOCK RTI Rücksprung
Die Dauer der ISR beträgt im schlechtesten Fall weniger als 150 Taktzyklen.
Da die ISR nur alle 100 ms ausgelöst wird, ist die zusätzliche Belastung
des Systems relativ gering (ca. 0,1%).
Binär zu ASCII-Decodierung
Im Speicher liegen die Werte bekanntermaßen binär vor. Um einen
Speicherinhalt oder ene Adresse auf der seriellen Schnittstelle (Terminal) oder
einem LC-Display ausgeben zu können, müsen die Werte als ASCII-Zeichen
dargestellt werden.
Die folgenden vier miteinander verbundendnene Unterprogramme wandeln einen 16-Bit-Wert,
einen 8-Bit-Wert oder einen 4-Bit-Wert in eine Hexadezimalzahl in ASCII-Darstellung
um (4, 2, oder 1 Stelle):
- hx4a wandelt den Inhalt von Akku D in vier ASCII-Zeichen, die
in einem 4 Byte langen Puffer abgelegt werden. Beim Unterprogrammaufruf muß
das Indexregister Y auf die letzte Stelle des Puffers zeigen.
- hx2a wandelt den Inhalt von Akku B in zwei ASCII-Zeichen, die
in einem 2 Byte langen Puffer abgelegt werden. Beim Unterprogrammaufruf muß
das Indexregister Y auf die letzte Stelle des Puffers zeigen.
- hx1a wandelt den Inhalt von Akku B (Bits 0-3) in ein ASCII-Zeichen,
das in einem 1 Byte langen Puffer abgelegt wird. Beim Unterprogrammaufruf muß
das Indexregister Y auf den Puffers zeigen.
Diese Unterprogramme werden beim vierten Praktikumstermin benötigt.
hx4a psha // Akku A auf dem Stack ablegen
bsr hx2a // Akku B umwandeln (Stelle 3 und 4)
pulb // Akku A vom Stack holen, in Akku B ablegen
// Nun einfach in hx2a fallen und Akku B
// umwandeln (Stelle 1 und 2)
hx2a pshb // Akku B aud dem Stack sichern
bsr hx1a // Bits 0-3 von Akku B umwandeln
pulb // Original-Akku B wieder holen
lsrb // viermal schieben (Bits 4-7 --> 0-3)
lsrb
lsrb // und nun die obere Haelfte umwandeln
lsrb // indem einfach in hx1a gefallen wird
// Nun wird die eigentliche Arbeit gemacht:
hx1a andb #$0F // die oberen 4 Bita ausmaskieren
addb #48 // ASCII-Wert von "0" addieren
cmpb #57 // groesser als "9"?
bls hx1b // nein, dann speichern
addb #7 // sonst die Distanz zwischen "9" und "a" addieren
hx1b stab 0,y // Im Speicher ablegen, auf den Y zeigt
dey // Y zeigt jetzt auf die Stelle davor
rts // und weg
|
|
|