Source file: /~heha/Mikrocontroller/avr-inc.zip/makros.i90

;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-80