Impressum
< Bitverarbeitung Inhalt Unterprogramme >

Sprungbefehle

Es gibt 4 Sprungbefehle, welche immer springen. Alle anderen Sprungbefehle verzeigen das Programm abhängig von einer Bedingung, d.h. sie springen nur, wenn eine gewisse Bedingung erfüllt ist, ansonsten wird das Programm mit dem nächsten Befehl fortgesetzt.

Unbedingte Sprünge

Die Befehle sjmp rel, ajmp adr11 und ljmp adr16 springen immer an die angegebene Adresse. Der Unterschied zwischen diesen Befehlen ist die Sprungdistanz und somit vor allem bei längeren Programmen relevant.
Die Adressangabe rel stellt eine relative 8-Bit Adresse dar. Dies bedeutet, dass der Parameter eine vorzeichenbehaftete 8-Bit Zahl ist (-128 bis 127). Bei einem Sprung wird PC+rel berechnet und das Programm an dieser Stelle vortgesetzt. Somit kann mit diesem Befehl maximal 128 Byte zurück und 127 Byte nach vor gesprungen werden.
Eine Endlosschleife mit sjmp ergibt sich mit einer Sprungdistanz von -2 (=0FEh), da vor dem Sprung das sjmp Befehlsbyte und der Operand eingelesen wurden. Somit stellt sjmp 0FEh eine Endlosschleife dar.
Die Adressangabe adr11 ist eine 11-Bit Adresse. Bei einem Sprung werden die letzten 11 Bit des PC durch die angegebene Adresse ersetzt. Das Sprungziel von ajmp kann somit überall im aktuellen 2k-Block liegen - allerdings nicht außerhalb, da die ersten 5 Bit des Programm-Counters nicht verändert werden.
Der Befehl ljmp adr16 hat insgesammt eine Länge von 3 Bytes. Die letzten 2 Bytes stellen das Sprungziel als 16-Bit Adresse dar. Bei einem Sprung wird hier der Wert des PC durch die angegebene Adresse ersetzt und somit das Programm an dieser Stelle weiter ausgeführt.
Der letzte unbedingte Sprung ist jmp @A+DPTR. Das Sprungziel liegt hier nicht fest im ROM des Controllers, sondern wird als Summe der in A und DPTR gespeicherten Werten berechnet. Diese Summe stellt eine absolute 16-Bit Adresse dar, an welcher das Programm fortgesetzt wird.
Nur mit diesem Befehl kann ein Sprungziel zur Laufzeit berechnet werden.
Beispiel zu jmp @A+DPTR:
In diesem Programm wird über die Schalter an P0.1 und P0.0 die Zahl fall zwischen 0 und 3 eingegeben. Anhand dieses Wertes wird das Programm verzweigt. Hierzu berechnet das Programm im Accu 2*fall.
In der Sprungtabelle case steht für jeden Fall ein 2 Byte langer Sprungbefehl zur jeweiligen Bearbeitungsroutine (fall0 bis fall3).
Mittels jmp @A+DPTR wird in die richtige Zeile der Sprungtabelle gesprungen, da im dptr die Anfangsadresse der Tabelle steht mit dem Akku 2*fall hinzuaddiert werden.
Dies ist eine Möglichkeit, wie eine switch-case Anweisung aus einer Hochsprache (z.B. Java, C++, Delphi) in Assembler umgesetzen werden kann. Vor allem bei einer großen Anzahl von Fällen (z.B. 256) kann hierdurch der Code deutlich besser strukturiert und lesbarer gehalten werden, als mit einer Reihe von Vergleichen (z.B. cjne). Außerdem ist diese Variante in vielen Fällen erheblich schneller, da man mit 2 Sprüngen (4 MZ) am Ziel ankommt. Bei einer Kette von cjne bräuchte man im Mittel 128 Sprünge und im schlimmsten Fall sogar 256 (512 MZ).
include reg8051.inc
main:
        mov A, P0
        anl A, #11b ; A in {0,1,2,3}
        rl A ; A=A*2 somit A in {0,2,4,6}
        mov DPTR, #case ; DPTR = Start der Sprungtabelle
        jmp @A+DPTR ; springt zu case+A
	
; Sprungtabelle mit je 2 Byte, jmp @A+DPTR 
; erreicht ...
case:   sjmp fall0 ;  ... diese Zeile bei A=0 
        sjmp fall1 ;  ... diese Zeile bei A=2 
        sjmp fall2 ;  ... diese Zeile bei A=4 
        sjmp fall3 ;  ... diese Zeile bei A=6 
	
fall0:  mov P1, #00001111b ;Bearbeitung von Fall 0
        jmp main
fall1:  mov P1, #00011111b ;Bearbeitung von Fall 1
        jmp main
fall2:  mov P1, #00111111b ;Bearbeitung von Fall 2
        jmp main
fall3:  mov P1, #01111111b ;Bearbeitung von Fall 3
        jmp main
end

Bebedingte Sprünge - Akkumulor (un)gleich 0

Der Befehl jz rel (jump if zero) springt genau dann, wenn der Akkumulator den Wert 0 enthält.
Hingegen springt jnz rel (jump if not zero) wenn der Akkumulator nicht den Wert 0 enthält.

Bebedingte Sprünge - Vergleiche

Der cjne op1, op2, rel Befehl springt genau dann, wenn op1 und op2 nicht die gleichen Werte enthalten.
Der erste Operand (op1) kann entweder der Akkumulator, ein Register oder eine @R0 bzw. @R1 sein.
Der zweite Operand (op2) ist eine Konstante. Nur wenn op1 der Akku ist kann op2 auch eine direkt adressierbare Speicherzelle sein.
Der cjne Befehl setzt das Carry Flag, wenn op1<op2 und löscht es wenn op1>=op2. Hierbei werden op1 und op2 als vorzeichenlose Zahlen betrachtet.

Bebedingte Sprünge - DJNZ

Der djnz op1, rel Befehl (decrement and jump if not zero) vermindert den Wert von op1 und springt, wenn der Wert danach nicht 0 ist.
Der erste Operand (op1) kann entweder eine Datenadresse oder ein Register sein. Hierbei ist zu beachten, dass der djnz A, rel kein gültiger Befehl ist. Um den Akku hier verwenden zu können, muss seine Adresse 0E0h verwendet werden: djnz 0E0h, rel ist gültig.
Dass zuerst vermindert und dann überprüft wird ist wichtig. Steht in der Speichezelle 20h der Wert 0, so wird die Schleife
label: djnz 020h, label
256 mal ausgeführt. Dies liegt daran, dass 0-1 = 255 (=0FFh) ergibt und somit nach dem ersten Druchlauf in 020h der Wert 255 steht.

Bebedingte Sprünge für Bits

Mit jc rel und jnc rel kann anhand des Carrys verzweigt werden. Jc rel springt, wenn das Carry gesetzt ist und jnc rel wenn das Carry gelöscht ist.
Die Aquivalente zu jc rel und jnc rel für andere Bits sind jb badr, rel und jnb badr, rel. Diese Befehle springen abhängig vom Inhalt des Bits in badr: jb springt falls das Bit 1 ist und jnb falls das Bit 0 ist.
Der Befehljbc badr, rel springt wenn das Bit in badr gesetzt ist und löscht es gleichzeitig. Somit ist das Bit an badr nach diesem Befehl immer 0, da entweder das Bit 0 war (kein Sprung) oder aber es war 1 (Sprung) und wurde von jbc gelöscht.

Hier die Sprungbefehle in der Übersicht:

MnemonicFunktionBytesMZFlags
AJMP adr11Setze das Programm bei adr11 innerhalb der 2 kByte-Seite fort.22-
LJMP adr16Setze das Programm bei adr16 fort.32-
SJMP relSetze das Programm bei rel, relativ zum Programm-Counter, fort.22-
JMP @A+DPTRSetze das Programm an der Stelle fort, die sich aus der Summe von Akkumulator und DPTR ergibt.12-
JZ relSpringe relativ um die Adresse rel, wenn der Inhalt des Akkus gleich null ist.22-
JNZ relSpringe relativ um die Adresse rel, wenn der Inhalt des Akkus ungleich null ist.22-
JC relSpringe relativ um die Adresse rel, wenn der Inhalt des Carry-Flag gesetzt ist.22-
JNC relSpringe relativ um die Adresse rel, wenn der Inhalt des Carry-Flag nicht gesetzt ist .22-
JB badr, relSpringe relativ um die Adresse rel, wenn der Inhalt von badr gleich eins ist.32-
JNB badr,relSpringe relativ um die Adresse rel, wenn der Inhalt von badr gleich null ist.32-
JBC badr,relSpringe relativ um die Adresse rel, wenn der Inhalt von badr gleich eins ist und lösche den Inhalt von badr.32-
CJNE A,dadr,relSpringe relativ um die Adresse rel, wenn die Inhalte von Akkumulator und dadr ungleich sind.32CY
CJNE A,#konst8,relSpringe relativ um die Adresse rel, wenn der Inhalt des Akkus ungleich der 8-Bit-Konstanten ist.32CY
CJNE Rr,#konst8,relSpringe relativ um die Adresse rel, wenn der Inhalt des Registers Rr ungleich der 8-Bit-Konstanten ist.32CY
CJNE @Ri,#konst8,relSpringe relativ um die Adresse rel, wenn der Inhalt der internen Datenspeicherzelle, die durch Ri adressiert wird, ungleich der 8-Bit-Konstanten ist.32CY
DJNZ Rr,relDer Inhalt von Register Rr wird um eins erniedrigt. Ist dann der Inhalt ungleich null, springe relativ um die Adresse rel.32-
DJNZ dadr,relDer Inhalt von dadr wird um eins erniedrigt. Ist dann der Inhalt ungleich null, springe relativ um die Adresse rel.32-