501 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			501 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
;---------------------------------------------------------------------------;
 | 
						|
; Extended itoa, puts, printf and atoi                     (C)ChaN, 2011
 | 
						|
;---------------------------------------------------------------------------;
 | 
						|
 | 
						|
				// Base size is 152 bytes
 | 
						|
#define	CR_CRLF		0	// Convert \n to \r\n (+10 bytes)
 | 
						|
#define USE_XPRINTF	1	// Enable xprintf function (+194 bytes)
 | 
						|
#define USE_XSPRINTF	0	// Add xsprintf function (+78 bytes)
 | 
						|
#define USE_XFPRINTF	0	// Add xfprintf function (+54 bytes)
 | 
						|
#define USE_XATOI	0	// Enable xatoi function (+182 bytes)
 | 
						|
 | 
						|
 | 
						|
#if FLASHEND > 0x1FFFF
 | 
						|
#error xitoa module does not support 256K devices
 | 
						|
#endif
 | 
						|
 | 
						|
.nolist
 | 
						|
#include <avr/io.h>	// Include device specific definitions.
 | 
						|
.list
 | 
						|
 | 
						|
#ifdef SPM_PAGESIZE	// Recent devices have "lpm Rd,Z+" and "movw".
 | 
						|
.macro	_LPMI	reg
 | 
						|
	lpm	\reg, Z+
 | 
						|
.endm
 | 
						|
.macro	_MOVW	dh,dl, sh,sl
 | 
						|
	movw	\dl, \sl
 | 
						|
.endm
 | 
						|
#else			// Earlier devices do not have "lpm Rd,Z+" nor "movw".
 | 
						|
.macro	_LPMI	reg
 | 
						|
	lpm
 | 
						|
	mov	\reg, r0
 | 
						|
	adiw	ZL, 1
 | 
						|
.endm
 | 
						|
.macro	_MOVW	dh,dl, sh,sl
 | 
						|
	mov	\dl, \sl
 | 
						|
	mov	\dh, \sh
 | 
						|
.endm
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;---------------------------------------------------------------------------
 | 
						|
; Stub function to forward to user output function
 | 
						|
;
 | 
						|
;Prototype: void xputc (char chr	// a character to be output
 | 
						|
;			);
 | 
						|
;Size: 12/12 words
 | 
						|
 | 
						|
.section .bss
 | 
						|
.global xfunc_out	; xfunc_out must be initialized before using this module.
 | 
						|
xfunc_out:	.ds.w	1
 | 
						|
.section .text
 | 
						|
 | 
						|
 | 
						|
.func xputc
 | 
						|
.global xputc
 | 
						|
xputc:
 | 
						|
#if CR_CRLF
 | 
						|
	cpi	r24, 10		;LF --> CRLF
 | 
						|
	brne	1f		;
 | 
						|
	ldi	r24, 13		;
 | 
						|
	rcall	1f		;
 | 
						|
	ldi	r24, 10		;/
 | 
						|
1:
 | 
						|
#endif
 | 
						|
	push	ZH
 | 
						|
	push	ZL
 | 
						|
	lds	ZL, xfunc_out+0	;Pointer to the registered output function.
 | 
						|
	lds	ZH, xfunc_out+1	;/
 | 
						|
	sbiw	ZL, 0		;Skip if null
 | 
						|
	breq	2f		;/
 | 
						|
	icall
 | 
						|
2:	pop	ZL
 | 
						|
	pop	ZH
 | 
						|
	ret
 | 
						|
.endfunc
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;---------------------------------------------------------------------------
 | 
						|
; Direct ROM string output
 | 
						|
;
 | 
						|
;Prototype: void xputs (const char *str_p // rom string to be output
 | 
						|
;			);
 | 
						|
 | 
						|
.func xputs
 | 
						|
.global xputs
 | 
						|
xputs:
 | 
						|
	_MOVW	ZH,ZL, r25,r24	; Z = pointer to rom string
 | 
						|
1:	_LPMI	r24
 | 
						|
	cpi	r24, 0
 | 
						|
	breq	2f
 | 
						|
	rcall	xputc
 | 
						|
	rjmp	1b
 | 
						|
2:	ret
 | 
						|
.endfunc
 | 
						|
 | 
						|
 | 
						|
;---------------------------------------------------------------------------
 | 
						|
; Extended direct numeral string output (32bit version)
 | 
						|
;
 | 
						|
;Prototype: void xitoa (long value,	// value to be output
 | 
						|
;                       char radix,	// radix
 | 
						|
;                       char width);	// minimum width
 | 
						|
;
 | 
						|
 | 
						|
.func xitoa
 | 
						|
.global xitoa
 | 
						|
xitoa:
 | 
						|
				;r25:r22 = value, r20 = base, r18 = digits
 | 
						|
	clr	r31		;r31 = stack level
 | 
						|
	ldi	r30, ' '	;r30 = sign
 | 
						|
	ldi	r19, ' '	;r19 = filler
 | 
						|
	sbrs	r20, 7		;When base indicates signd format and the value
 | 
						|
	rjmp	0f		;is minus, add a '-'.
 | 
						|
	neg	r20		;
 | 
						|
	sbrs	r25, 7		;
 | 
						|
	rjmp	0f		;
 | 
						|
	ldi	r30, '-'	;
 | 
						|
	com	r22		;
 | 
						|
	com	r23		;
 | 
						|
	com	r24		;
 | 
						|
	com	r25		;
 | 
						|
	adc	r22, r1		;
 | 
						|
	adc	r23, r1		;
 | 
						|
	adc	r24, r1		;
 | 
						|
	adc	r25, r1		;/
 | 
						|
0:	sbrs	r18, 7		;When digits indicates zero filled,
 | 
						|
	rjmp	1f		;filler is '0'.
 | 
						|
	neg	r18		;
 | 
						|
	ldi	r19, '0'	;/
 | 
						|
				;----- string conversion loop
 | 
						|
1:	ldi	r21, 32		;r26 = r25:r22 % r20
 | 
						|
	clr	r26		;r25:r22 /= r20
 | 
						|
2:	lsl	r22		;
 | 
						|
	rol	r23		;
 | 
						|
	rol	r24		;
 | 
						|
	rol	r25		;
 | 
						|
	rol	r26		;
 | 
						|
	cp	r26, r20	;
 | 
						|
	brcs	3f		;
 | 
						|
	sub	r26, r20	;
 | 
						|
	inc	r22		;
 | 
						|
3:	dec	r21		;
 | 
						|
	brne	2b		;/
 | 
						|
	cpi	r26, 10		;r26 is a numeral digit '0'-'F'
 | 
						|
	brcs	4f		;
 | 
						|
	subi	r26, -7		;
 | 
						|
4:	subi	r26, -'0'	;/
 | 
						|
	push	r26		;Stack it
 | 
						|
	inc	r31		;/
 | 
						|
	cp	r22, r1		;Repeat until r25:r22 gets zero
 | 
						|
	cpc	r23, r1		;
 | 
						|
	cpc	r24, r1		;
 | 
						|
	cpc	r25, r1		;
 | 
						|
	brne	1b		;/
 | 
						|
 | 
						|
	cpi	r30, '-'	;Minus sign if needed
 | 
						|
	brne	5f		;
 | 
						|
	push	r30		;
 | 
						|
	inc	r31		;/
 | 
						|
5:	cp	r31, r18	;Filler
 | 
						|
	brcc	6f		;
 | 
						|
	push	r19		;
 | 
						|
	inc	r31		;
 | 
						|
	rjmp	5b		;/
 | 
						|
 | 
						|
6:	pop	r24		;Flush stacked digits and exit
 | 
						|
	rcall	xputc		;
 | 
						|
	dec	r31		;
 | 
						|
	brne	6b		;/
 | 
						|
 | 
						|
	ret
 | 
						|
.endfunc
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;---------------------------------------------------------------------------;
 | 
						|
; Formatted string output (16/32bit version)
 | 
						|
;
 | 
						|
;Prototype:
 | 
						|
; void __xprintf (const char *format_p, ...);
 | 
						|
; void __xsprintf(char*, const char *format_p, ...);
 | 
						|
; void __xfprintf(void(*func)(char), const char *format_p, ...);
 | 
						|
;
 | 
						|
 | 
						|
#if USE_XPRINTF
 | 
						|
 | 
						|
.func xvprintf
 | 
						|
xvprintf:
 | 
						|
	ld	ZL, Y+		;Z = pointer to format string
 | 
						|
	ld	ZH, Y+		;/
 | 
						|
 | 
						|
0:	_LPMI	r24		;Get a format char
 | 
						|
	cpi	r24, 0		;End of format string?
 | 
						|
	breq	90f		;/
 | 
						|
	cpi	r24, '%'	;Is format?
 | 
						|
	breq	20f		;/
 | 
						|
1:	rcall	xputc		;Put a normal character
 | 
						|
	rjmp	0b		;/
 | 
						|
90:	ret
 | 
						|
 | 
						|
20:	ldi	r18, 0		;r18: digits
 | 
						|
	clt			;T: filler
 | 
						|
	_LPMI	r21		;Get flags
 | 
						|
	cpi	r21, '%'	;Is a %?
 | 
						|
	breq	1b		;/
 | 
						|
	cpi	r21, '0'	;Zero filled?
 | 
						|
	brne	23f		;
 | 
						|
	set			;/
 | 
						|
22:	_LPMI	r21		;Get width
 | 
						|
23:	cpi	r21, '9'+1	;
 | 
						|
	brcc	24f		;
 | 
						|
	subi	r21, '0'	;
 | 
						|
	brcs	90b		;
 | 
						|
	lsl	r18		;
 | 
						|
	mov	r0, r18		;
 | 
						|
	lsl	r18		;
 | 
						|
	lsl	r18		;
 | 
						|
	add	r18, r0		;
 | 
						|
	add	r18, r21	;
 | 
						|
	rjmp	22b		;/
 | 
						|
 | 
						|
24:	brtc	25f		;get value (low word)
 | 
						|
	neg	r18		;
 | 
						|
25:	ld	r24, Y+		;
 | 
						|
	ld	r25, Y+		;/
 | 
						|
	cpi	r21, 'c'	;Is type character?
 | 
						|
	breq	1b		;/
 | 
						|
	cpi	r21, 's'	;Is type RAM string?
 | 
						|
	breq	50f		;/
 | 
						|
	cpi	r21, 'S'	;Is type ROM string?
 | 
						|
	breq	60f		;/
 | 
						|
	_MOVW	r23,r22,r25,r24	;r25:r22 = value
 | 
						|
	clr	r24		;
 | 
						|
	clr	r25		;
 | 
						|
	clt			;/
 | 
						|
	cpi	r21, 'l'	;Is long int?
 | 
						|
	brne	26f		;
 | 
						|
	ld	r24, Y+		;get value (high word)
 | 
						|
	ld	r25, Y+		;
 | 
						|
	set			;
 | 
						|
	_LPMI	r21		;/
 | 
						|
26:	cpi	r21, 'd'	;Is type signed decimal?
 | 
						|
	brne	27f		;/
 | 
						|
	ldi	r20, -10	;
 | 
						|
	brts	40f		;
 | 
						|
	sbrs	r23, 7		;
 | 
						|
	rjmp	40f		;
 | 
						|
	ldi	r24, -1		;
 | 
						|
	ldi	r25, -1		;
 | 
						|
	rjmp	40f		;/
 | 
						|
27:	cpi	r21, 'u'	;Is type unsigned decimal?
 | 
						|
	ldi	r20, 10		;
 | 
						|
	breq	40f		;/
 | 
						|
	cpi	r21, 'X'	;Is type hexdecimal?
 | 
						|
	ldi	r20, 16		;
 | 
						|
	breq	40f		;/
 | 
						|
	cpi	r21, 'b'	;Is type binary?
 | 
						|
	ldi	r20, 2		;
 | 
						|
	breq	40f		;/
 | 
						|
	ret			;abort
 | 
						|
40:	push	ZH		;Output the value
 | 
						|
	push	ZL		;
 | 
						|
	rcall	xitoa		;
 | 
						|
42:	pop	ZL		;
 | 
						|
	pop	ZH		;
 | 
						|
	rjmp	0b		;/
 | 
						|
 | 
						|
50:	push	ZH		;Put a string on the RAM
 | 
						|
	push	ZL
 | 
						|
	_MOVW	ZH,ZL, r25,r24
 | 
						|
51:	ld	r24, Z+
 | 
						|
	cpi	r24, 0
 | 
						|
	breq	42b
 | 
						|
	rcall	xputc
 | 
						|
	rjmp	51b
 | 
						|
 | 
						|
60:	push	ZH		;Put a string on the ROM
 | 
						|
	push	ZL
 | 
						|
	rcall	xputs
 | 
						|
	rjmp	42b
 | 
						|
.endfunc
 | 
						|
 | 
						|
 | 
						|
.func __xprintf
 | 
						|
.global __xprintf
 | 
						|
__xprintf:
 | 
						|
	push	YH
 | 
						|
	push	YL
 | 
						|
	in	YL, _SFR_IO_ADDR(SPL)
 | 
						|
#ifdef SPH
 | 
						|
	in	YH, _SFR_IO_ADDR(SPH)
 | 
						|
#else
 | 
						|
	clr	YH
 | 
						|
#endif
 | 
						|
	adiw	YL, 5		;Y = pointer to arguments
 | 
						|
	rcall	xvprintf
 | 
						|
	pop	YL
 | 
						|
	pop	YH
 | 
						|
	ret
 | 
						|
.endfunc
 | 
						|
 | 
						|
 | 
						|
#if USE_XSPRINTF
 | 
						|
 | 
						|
.func __xsprintf
 | 
						|
putram:
 | 
						|
	_MOVW	ZH,ZL, r15,r14
 | 
						|
	st	Z+, r24
 | 
						|
	_MOVW	r15,r14, ZH,ZL
 | 
						|
	ret
 | 
						|
.global __xsprintf
 | 
						|
__xsprintf:
 | 
						|
	push	YH
 | 
						|
	push	YL
 | 
						|
	in	YL, _SFR_IO_ADDR(SPL)
 | 
						|
#ifdef SPH
 | 
						|
	in	YH, _SFR_IO_ADDR(SPH)
 | 
						|
#else
 | 
						|
	clr	YH
 | 
						|
#endif
 | 
						|
	adiw	YL, 5		;Y = pointer to arguments
 | 
						|
	lds	ZL, xfunc_out+0	;Save registered output function
 | 
						|
	lds	ZH, xfunc_out+1	;
 | 
						|
	push	ZL		;
 | 
						|
	push	ZH		;/
 | 
						|
	ldi	ZL, lo8(pm(putram));Set local output function
 | 
						|
	ldi	ZH, hi8(pm(putram));
 | 
						|
	sts	xfunc_out+0, ZL	;
 | 
						|
	sts	xfunc_out+1, ZH	;/
 | 
						|
	push	r15		;Initialize pointer to string buffer
 | 
						|
	push	r14		;
 | 
						|
	ld	r14, Y+		;
 | 
						|
	ld	r15, Y+		;/
 | 
						|
	rcall	xvprintf
 | 
						|
	_MOVW	ZH,ZL, r15,r14	;Terminate string
 | 
						|
	st	Z, r1		;
 | 
						|
	pop	r14		;
 | 
						|
	pop	r15		;/
 | 
						|
	pop	ZH		;Restore registered output function
 | 
						|
	pop	ZL		;
 | 
						|
	sts	xfunc_out+0, ZL	;
 | 
						|
	sts	xfunc_out+1, ZH	;/
 | 
						|
	pop	YL
 | 
						|
	pop	YH
 | 
						|
	ret
 | 
						|
.endfunc
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if USE_XFPRINTF
 | 
						|
.func __xfprintf
 | 
						|
.global __xfprintf
 | 
						|
__xfprintf:
 | 
						|
	push	YH
 | 
						|
	push	YL
 | 
						|
	in	YL, _SFR_IO_ADDR(SPL)
 | 
						|
#ifdef SPH
 | 
						|
	in	YH, _SFR_IO_ADDR(SPH)
 | 
						|
#else
 | 
						|
	clr	YH
 | 
						|
#endif
 | 
						|
	adiw	YL, 5		;Y = pointer to arguments
 | 
						|
	lds	ZL, xfunc_out+0	;Save registered output function
 | 
						|
	lds	ZH, xfunc_out+1	;
 | 
						|
	push	ZL		;
 | 
						|
	push	ZH		;/
 | 
						|
	ld	ZL, Y+		;Set output function
 | 
						|
	ld	ZH, Y+		;
 | 
						|
	sts	xfunc_out+0, ZL	;
 | 
						|
	sts	xfunc_out+1, ZH	;/
 | 
						|
	rcall	xvprintf
 | 
						|
	pop	ZH		;Restore registered output function
 | 
						|
	pop	ZL		;
 | 
						|
	sts	xfunc_out+0, ZL	;
 | 
						|
	sts	xfunc_out+1, ZH	;/
 | 
						|
	pop	YL
 | 
						|
	pop	YH
 | 
						|
	ret
 | 
						|
.endfunc
 | 
						|
#endif
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;---------------------------------------------------------------------------
 | 
						|
; Extended numeral string input
 | 
						|
;
 | 
						|
;Prototype:
 | 
						|
; char xatoi (           /* 1: Successful, 0: Failed */
 | 
						|
;      const char **str, /* pointer to pointer to source string */
 | 
						|
;      long *res         /* result */
 | 
						|
; );
 | 
						|
;
 | 
						|
 | 
						|
 | 
						|
#if USE_XATOI
 | 
						|
.func xatoi
 | 
						|
.global xatoi
 | 
						|
xatoi:
 | 
						|
	_MOVW	r1, r0, r23, r22
 | 
						|
	_MOVW	XH, XL, r25, r24
 | 
						|
	ld	ZL, X+
 | 
						|
	ld	ZH, X+
 | 
						|
	clr	r18		;r21:r18 = 0;
 | 
						|
	clr	r19		;
 | 
						|
	clr	r20		;
 | 
						|
	clr	r21		;/
 | 
						|
	clt			;T = 0;
 | 
						|
 | 
						|
	ldi	r25, 10		;r25 = 10;
 | 
						|
	rjmp	41f		;/
 | 
						|
40:	adiw	ZL, 1		;Z++;
 | 
						|
41:	ld	r22, Z		;r22 = *Z;
 | 
						|
	cpi	r22, ' '	;if(r22 == ' ') continue
 | 
						|
	breq	40b		;/
 | 
						|
	brcs	70f		;if(r22 < ' ') error;
 | 
						|
	cpi	r22, '-'	;if(r22 == '-') {
 | 
						|
	brne	42f		; T = 1;
 | 
						|
	set			; continue;
 | 
						|
	rjmp	40b		;}
 | 
						|
42:	cpi	r22, '9'+1	;if(r22 > '9') error;
 | 
						|
	brcc	70f		;/
 | 
						|
	cpi	r22, '0'	;if(r22 < '0') error;
 | 
						|
	brcs	70f		;/
 | 
						|
	brne	51f		;if(r22 > '0') cv_start;
 | 
						|
	ldi	r25, 8		;r25 = 8;
 | 
						|
	adiw	ZL, 1		;r22 = *(++Z);
 | 
						|
	ld	r22, Z		;/
 | 
						|
	cpi	r22, ' '+1	;if(r22 <= ' ') exit;
 | 
						|
	brcs	80f		;/
 | 
						|
	cpi	r22, 'b'	;if(r22 == 'b') {
 | 
						|
	brne	43f		; r25 = 2;
 | 
						|
	ldi	r25, 2		; cv_start;
 | 
						|
	rjmp	50f		;}
 | 
						|
43:	cpi	r22, 'x'	;if(r22 != 'x') error;
 | 
						|
	brne	51f		;/
 | 
						|
	ldi	r25, 16		;r25 = 16;
 | 
						|
 | 
						|
50:	adiw	ZL, 1		;Z++;
 | 
						|
	ld	r22, Z		;r22 = *Z;
 | 
						|
51:	cpi	r22, ' '+1	;if(r22 <= ' ') break;
 | 
						|
	brcs	80f		;/
 | 
						|
	cpi	r22, 'a'	;if(r22 >= 'a') r22 =- 0x20;
 | 
						|
	brcs	52f		;
 | 
						|
	subi	r22, 0x20	;/
 | 
						|
52:	subi	r22, '0'	;if((r22 -= '0') < 0) error;
 | 
						|
	brcs	70f		;/
 | 
						|
	cpi	r22, 10		;if(r22 >= 10) {
 | 
						|
	brcs	53f		; r22 -= 7;
 | 
						|
	subi	r22, 7		; if(r22 < 10) 
 | 
						|
	cpi	r22, 10		;
 | 
						|
	brcs	70f		;}
 | 
						|
53:	cp	r22, r25	;if(r22 >= r25) error;
 | 
						|
	brcc	70f		;/
 | 
						|
60:	ldi	r24, 33		;r21:r18 *= r25;
 | 
						|
	sub	r23, r23	;
 | 
						|
61:	brcc	62f		;
 | 
						|
	add	r23, r25	;
 | 
						|
62:	lsr	r23		;
 | 
						|
	ror	r21		;
 | 
						|
	ror	r20		;
 | 
						|
	ror	r19		;
 | 
						|
	ror	r18		;
 | 
						|
	dec	r24		;
 | 
						|
	brne	61b		;/
 | 
						|
	add	r18, r22	;r21:r18 += r22;
 | 
						|
	adc	r19, r24	;
 | 
						|
	adc	r20, r24	;
 | 
						|
	adc	r21, r24	;/
 | 
						|
	rjmp	50b		;repeat
 | 
						|
 | 
						|
70:	ldi	r24, 0
 | 
						|
	rjmp	81f
 | 
						|
80:	ldi	r24, 1
 | 
						|
81:	brtc	82f
 | 
						|
	clr	r22
 | 
						|
	com	r18
 | 
						|
	com	r19
 | 
						|
	com	r20
 | 
						|
	com	r21
 | 
						|
	adc	r18, r22
 | 
						|
	adc	r19, r22
 | 
						|
	adc	r20, r22
 | 
						|
	adc	r21, r22
 | 
						|
82:	st	-X, ZH
 | 
						|
	st	-X, ZL
 | 
						|
	_MOVW	XH, XL, r1, r0
 | 
						|
	st	X+, r18
 | 
						|
	st	X+, r19
 | 
						|
	st	X+, r20
 | 
						|
	st	X+, r21
 | 
						|
	clr	r1
 | 
						|
	ret
 | 
						|
.endfunc
 | 
						|
#endif
 | 
						|
 | 
						|
 |