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