|
|
@ -0,0 +1,500 @@ |
|
|
|
;---------------------------------------------------------------------------; |
|
|
|
; 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 prog_char *str // 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 prog_char *format, ...); |
|
|
|
; void xsprintf(char*, const prog_char *format, ...); |
|
|
|
; void xfprintf(void(*func)(char), const prog_char *format, ...); |
|
|
|
; |
|
|
|
|
|
|
|
#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 |
|
|
|
|
|
|
|
|