;h#s Makrosammlung 01/06
#ifndef MAKROS_I90
#define MAKROS_I90
;Diese Makros sollen das Schreiben von Assemblerprogrammen erleichtern
;und unterstützen insbesondere 16-bit-Operationen.
;Die Endung "I90" ("Include für AT90-Architektur") statt "ASM" ermöglicht
;plattformspezifische Dateiverknüpfung und Syntaxhervorhebung.
;#########################
;## Register-Festlegung ##
;#########################
;R16 wird immer als allgemeines Arbeitsregister verwendet.
;Für die Arbeit mit schnellen Interruptserviceroutinen sowie allgemeinen
;Aufgaben sollten folgende Registerbereiche freigehalten werden:
;R20-R26, zumindest R22-R23, für alles, wo Konstantenvergleich oder
; Bitsetzoperationen vorherrschen (Bit-Register, UART_InChar u.ä.)
;R8-R15, zumindest R12-R15, für alles andere
; (Zähler, Software-PWM-Werte u.ä.)
;YH Es wird empfohlen, YH zur Adressierung der meisten "kleinen"
; Variablen permanent auf Null zu halten, dann genügt das Laden
; von YL in Interruptserviceroutinen usw.
; Der Zugriff auf memory-mapped Register des ATmega128
; (mit LDD/STD) verkürzt sich wesentlich.
; Für einige meiner Routinen ist YH=0 Voraussetzung!
;P.S.: Beim ATmega128 entfällt der Vorteil der Adressierbarkeit
; kleiner Variablen.
;Faustregel: Globale Register, die in ISRs verwendet werden, dürfen
; niemals gePUSHt werden! (YH braucht nie gePUSHt zu werden.)
;Die Register R0-R7 sind für umfangreichere Mathematik unabdingbar;
; in R16-R19 ist schlicht zu wenig Platz.
;R5:R4:R3:R2 ist allgemein ein 32-bit-Akkumulator, weil R1:R0
; bereits vom MUL-Befehl okkupiert ist und man gelegentlich
; (siehe MulAdd) noch einige Bits mehr braucht (R6 -> 40bit).
; Dieser Akkumulator heißt bei mir abgekürzt R32.
;Als allgemeines Zeigerregister wird vorrangig Z verwendet.
; Weil LPM nur mit Z funktioniert, YH=0 festgelegt ist
; und X kein LDD/STD unterstützt.
;Die Makronamen haben in etwa folgenden Grundaufbau
;<befehl>w = 2-Byte-Zugriff, Angabe zweier Register oder I/Os
;<befehl>hl = 2-Byte-Zugriff, Angabe eines Präfixes, mit "H" und "L" definiert
#ifndef ZERO
# define ZERO YH
#endif
;################
;## IN und OUT ##
;################
;8-bit-Konstante auf Ausgabeport, benutzt R16
.macro outi ;Ausgabeport, Konstante
ldi r16,@1
out @0,r16
.endm
;16-bit-Konstante auf zwei Ausgabeports, benutzt R16
.macro outiw ;High-I/O, Low-I/O, Konstante
outi @0,HIGH(@2)
outi @1,LOW(@2)
.endm
;16-bit-Konstante auf ein Doppel-Ausgabeport mit Endungen "H" und "L", via R16
.macro outihl ;I/O-Präfix, Konstante
outiw @0H,@0L, @1
.endm
;16-bit-Zahl (2 Register) auf Doppel-Ausgabeport
.macro outhl ;I/O-Präfix, RegH,RegL
out @0H,@1 ;Erst High
out @0L,@2 ;Dann Low
.endm
;16-bit-Zahl (Präfix) auf Doppel-Ausgabeport
.macro out2 ;I/O-Präfix, Reg-Präfix
out @0H,@1H ;Erst High
out @0L,@1L ;Dann Low
.endm
;16-bit-Zahl (2 Register) von Doppel-Eingabeport
.macro inhl ;RegH,RegL, I/O-Präfix
in @1,@2L ;Erst Low
in @0,@2H ;Dann High
.endm
;16-bit-Zahl (Präfix) von Doppel-Eingabeport
.macro in2 ;Reg-Präfix, I/O-Präfix
in @0L,@1L ;Erst Low
in @0H,@1H ;Dann High
.endm
;################
;## Konstanten ##
;################
;Konstanten-Operationen für "unzugängliche" Register (<R16)
.macro i_ ;Op(ohne "i"), Reg, Konstante
ldi r16,@2
@0 @1,r16
.endm
;8-bit-Konstante in "unzugängliches" Register (<R16) laden, benutzt R16
.macro ldi_ ;Reg, Konstante
i_ mov, @0,@1
.endm
;16-bit-Konstante in zwei Register laden, Reg >= R16
.macro ldiw ;RegH,RegL, Konstante
ldi @0,HIGH(@2)
ldi @1,LOW(@2)
.endm
;16-bit-Konstante in Doppelregister mit "H" und "L" laden, wie ZH, ZL u.ä.
.macro ldihl ;Reg-Präfix, Konstante
ldiw @0H,@0L, @1
.endm
;#####################
;## Speicherzugriff ##
;#####################
;=== LDD/STD ===
;8-bit-Konstante speichern (via STD, nur mit Y oder Z möglich), benutzt R16
.macro stdi ;Speicherziel, Konstante
ldi r16,@1
std @0,r16
.endm
;16-bit-Konstante speichern (via STD, nur mit Y oder Z möglich), benutzt R16
.macro stdiw ;Speicherziel, Konstante
stdi @0+1,HIGH(@1)
stdi @0+0,LOW(@1)
.endm
;16-bit-Zahl speichern (via STD, nur mit Y oder Z möglich)
.macro stdw ;Speicherziel, RegH,RegL
std @0+1,@1 ;falls I/O, erst High-Teil
std @0+0,@2
.endm
.macro stdhl ;Speicherziel, Reg-Präfix
stdw @0, @1H,@1L
.endm
;16-bit-Zahl lesen (via LDD, nur mit Y oder Z möglich)
.macro lddw ;RegH,RegL, Speicherquelle
ldd @1,@2+0 ;erst Low-Teil
ldd @0,@2+1
.endm
.macro lddhl ;Reg-Präfix, Speicherquelle
lddw @0H,@0L, @1
.endm
;=== LDS/STS ===
;8-bit-Konstante speichern (via STS), benutzt R16
.macro stsi ;Speicherziel, Konstante
ldi r16,@1
sts @0,r16
.endm
;16-bit-Konstante speichern (via STS), benutzt R16
.macro stsiw ;Speicherziel, Konstante, bspw. "stsiw StrPtr,StrAnfang"
stsi @0+1,HIGH(@1)
stsi @0+0,LOW(@1)
.endm
;16-bit-Zahl speichern (via STS)
.macro stsw ;Speicherziel, RegH,RegL
sts @0+1,@1 ;falls I/O, erst High-Teil
sts @0+0,@2
.endm
.macro stshl ;Speicherziel, Reg-Präfix, bspw. "stshl StrPtr,Z"
stsw @0, @1H,@1L
.endm
;16-bit-Zahl lesen (via LDS)
.macro ldsw ;RegH,RegL, Speicherquelle
lds @1,@2+0 ;erst Low-Teil
lds @0,@2+1
.endm
.macro ldshl ;Reg-Präfix, Speicherquelle, bspw. "ldshl Z,StrPtr"
ldsw @0H,@0L, @1
.endm
;=== PUSH/POP ===
.macro pushi ;Konstante, bspw. "pushi '-'"
ldi r16,@0
push r16
.endm
.macro pushiw ;Konstante (16bit), bspw. "pushiw 0x1234"
pushi LOW(@0)
pushi HIGH(@0)
.endm
.macro pushw ;RegH,RegL, bspw. "pushw r17,r16"
push @1
push @0
.endm
.macro pushhl ;Reg-Präfix, bspw. "pushhl Z"
pushw @0H,@0L
.endm
.macro popw ;RegH,RegL, bspw. "popw r17,r16"
pop @0
pop @1
.endm
.macro pophl ;Reg-Präfix, bspw. "pophl Z"
popw @0H,@0L
.endm
;###############
;## Schleifen ##
;###############
;Dekrementieren und springen (wie 8051)
.macro djnz ;Register, Sprungziel
dec @0
brne @1
.endm
;Doppelregister dekrementieren und springen
;Es wird empfohlen, R25:R24 als WH:WL zu .DEF-inieren.
.macro djnzhl ;Doppelregister, Sprungziel
subiw @0H:@0L,1
brne @1
.endm
;##############
;## Bit-Test ##
;##############
;Springe wenn Bit im Register gesetzt
.macro jbrs ;Register, Bitnummer, Sprungziel
sbrc @0,@1
rjmp @2
.endm
;Springe wenn Bit im Register gelöscht
.macro jbrc ;Register, Bitnummer, Sprungziel
sbrs @0,@1
rjmp @2
.endm
;Springe wenn Bit im Eingabeport gesetzt
.macro jbis ;Port, Bitnummer, Sprungziel
sbic @0,@1
rjmp @2
.endm
;Springe wenn Bit im Eingabeport gelöscht
.macro jbic ;Port, Bitnummer, Sprungziel
sbis @0,@1
rjmp @2
.endm
;################
;## Mathematik ##
;################
;Negation mit eingehendem Übertrag, R16 wird zerstört
.macro negc ;Register
ldi r16,0
sbc r16,@0
mov @0,r16
.endm
;Addition einer Null mit Übertrag, ohne Verkettung!
.macro adc0 ;Register
#ifdef ZERO
adc @0,ZERO
#else
adc @0,ZL ;Problem 1: @0 darf nicht ZL sein
sub @0,ZL ;Problem 2: C-Flag nicht für Verkettung geeignet
#endif
.endm
;Subtraktion einer Null mit Übertrag, ohne Verkettung!
.macro sbc0 ;Register - für >=R16 gibts aber auch SBCI!
#ifdef ZERO
sbc @0,ZERO
#else
sbc @0,ZL ;Problem 1: @0 darf nicht ZL sein
add @0,ZL ;Problem 2: C-Flag nicht für Verkettung geeignet
#endif
.endm
;Addition einer Konstanten
.macro addi
subi @0,-(@1)
.endm
;Konvertiere "char" zu "short" (Byte zu Wort) vzb.
.macro cbw ;RegH,RegL
lsl @1 ;Vorzeichenbit ausschieben (C)
sbc @0,@0 ;0 oder FF draus machen, C unverändert
lsr @1 ;C zurück
.endm
;Konvertiere "short" zu "long" (Wort zu DWord) vzb.
.macro cwd ;Reg3,Reg2,RegH,RegL
lsl @2 ;das gleiche Strickmuster, RegL wird nicht verwendet
sbc @1,@1
sbc @0,@0
lsr @2
.endm
;Konvertiere "char" zu "long" (Byte zu DWord) vzb.
.macro cbd ;Reg3,Reg2,RegH,RegL
lsl @3
sbc @2,@2
sbc @1,@1
sbc @0,@0
lsr @3
.endm
;Vorzeichenlose Erweiterungen sind keine Makros wert!
;Einfach High-Bytes nullsetzen.
;=== 16-bit-Schiebeoperationen ===
.macro lslw ;RegH,RegL
lsl @1
rol @0
.endm
.macro lslhl ;Reg-Präfix
lslw @0H,@0L
.endm
.macro rolw ;RegH,RegL
rol @1
rol @0
.endm
.macro rolhl ;Reg-Präfix
rolw @0H,@0L
.endm
.macro lsrw ;RegH,RegL
lsr @0
ror @1
.endm
.macro lsrhl ;Reg-Präfix
lsrw @0H,@0L
.endm
.macro rorw ;RegH,RegL
ror @0
ror @1
.endm
.macro rorhl ;Reg-Präfix
rorw @0H,@0L
.endm
.macro asrw ;RegH,RegL
asr @0
ror @1
.endm
.macro asrhl ;Reg-Präfix
asrw @0H,@0L
.endm
;##############
;## Push/Pop ## für Interruptserviceroutinen
;##############
.macro EnterPush4 ;Start einer ISR, Retten von SREG, R16-R19
push r16
in r16,SREG
push r16
push r17
push r18
push r19
.endm
.macro Pop4Leave ;Ende einer ISR, Restaurieren von R16-R19, SREG
pop r19
pop r18
pop r17
pop r16
out SREG,r16
pop r16
.endm ;KEIN "reti" hier!
#endif
Detected encoding: UTF-8 | 0
|