From d9c06db60006e2191d8b86e34f651644a54426b4 Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 14 May 2013 16:16:57 +0900 Subject: [PATCH] Add xprintf(xitoa) from elm-chan.org --- common.mk | 1 + common/debug.h | 63 +----- common/debug_config.h | 51 +++++ common/nodebug.h | 49 +++++ common/print.c | 147 +------------ common/print.h | 71 +++--- common/util.c | 22 ++ common/util.h | 4 + common/xprintf.S | 500 ++++++++++++++++++++++++++++++++++++++++++ common/xprintf.h | 103 +++++++++ 10 files changed, 789 insertions(+), 222 deletions(-) create mode 100644 common/debug_config.h create mode 100644 common/nodebug.h create mode 100644 common/xprintf.S create mode 100644 common/xprintf.h diff --git a/common.mk b/common.mk index 810f802c..5f47e5c1 100644 --- a/common.mk +++ b/common.mk @@ -11,6 +11,7 @@ SRC += $(COMMON_DIR)/host.c \ $(COMMON_DIR)/print.c \ $(COMMON_DIR)/bootloader.c \ $(COMMON_DIR)/suspend.c \ + $(COMMON_DIR)/xprintf.S \ $(COMMON_DIR)/util.c diff --git a/common/debug.h b/common/debug.h index cac68270..8aaa5ed9 100644 --- a/common/debug.h +++ b/common/debug.h @@ -18,14 +18,20 @@ along with this program. If not, see . #ifndef DEBUG_H #define DEBUG_H 1 -#include #include "print.h" +#include "debug_config.h" #ifndef NO_DEBUG +#define dprint(s) do { if (debug_enable) print(s); } while (0) +#define dprintln() do { if (debug_enable) print_crlf(); } while (0) +#define dprintf(fmt, ...) do { if (debug_enable) __xprintf(PSTR(fmt), ##__VA_ARGS__); } while (0) +#define dmsg(s) dprintf("%s at %s: %S\n", __FILE__, __LINE__, PSTR(s)) + +/* DO NOT USE these anymore */ #define debug(s) do { if (debug_enable) print(s); } while (0) -#define debugln(s) do { if (debug_enable) println(s); } while (0) +#define debugln(s) do { if (debug_enable) print_crlf(); } while (0) #define debug_S(s) do { if (debug_enable) print_S(s); } while (0) #define debug_P(s) do { if (debug_enable) print_P(s); } while (0) #define debug_msg(s) do { \ @@ -50,58 +56,7 @@ along with this program. If not, see . #define debug_bin_reverse(data) debug_bin8(data) #else - -#define debug(s) -#define debugln(s) -#define debug_S(s) -#define debug_P(s) -#define debug_msg(s) -#define debug_dec(data) -#define debug_decs(data) -#define debug_hex4(data) -#define debug_hex8(data) -#define debug_hex16(data) -#define debug_hex32(data) -#define debug_bin8(data) -#define debug_bin16(data) -#define debug_bin32(data) -#define debug_bin_reverse8(data) -#define debug_bin_reverse16(data) -#define debug_bin_reverse32(data) -#define debug_hex(data) -#define debug_bin(data) -#define debug_bin_reverse(data) - -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - - -/* NOTE: Not portable. Bit field order depends on implementation */ -typedef union { - uint8_t raw; - struct { - bool enable:1; - bool matrix:1; - bool keyboard:1; - bool mouse:1; - uint8_t reserved:4; - }; -} debug_config_t; -debug_config_t debug_config; - -/* for backward compatibility */ -#define debug_enable (debug_config.enable) -#define debug_matrix (debug_config.matrix) -#define debug_keyboard (debug_config.keyboard) -#define debug_mouse (debug_config.mouse) - - -#ifdef __cplusplus -} +#include "nodebug.h" #endif #endif diff --git a/common/debug_config.h b/common/debug_config.h new file mode 100644 index 00000000..e00fd103 --- /dev/null +++ b/common/debug_config.h @@ -0,0 +1,51 @@ +/* +Copyright 2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef DEBUG_CONFIG_H +#define DEBUG_CONFIG_H 1 + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: Not portable. Bit field order depends on implementation */ +typedef union { + uint8_t raw; + struct { + bool enable:1; + bool matrix:1; + bool keyboard:1; + bool mouse:1; + uint8_t reserved:4; + }; +} debug_config_t; +debug_config_t debug_config; + +/* for backward compatibility */ +#define debug_enable (debug_config.enable) +#define debug_matrix (debug_config.matrix) +#define debug_keyboard (debug_config.keyboard) +#define debug_mouse (debug_config.mouse) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/common/nodebug.h b/common/nodebug.h new file mode 100644 index 00000000..aec790bb --- /dev/null +++ b/common/nodebug.h @@ -0,0 +1,49 @@ +/* +Copyright 2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef NODEBUG_H +#define NODEBUG_H 1 + +#include "debug_config.h" + +#define dprint(s) +#define dprintln(s) +#define dprintf(fmt, ...) +#define dmsg(s) + +#define debug(s) +#define debugln(s) +#define debug_S(s) +#define debug_P(s) +#define debug_msg(s) +#define debug_dec(data) +#define debug_decs(data) +#define debug_hex4(data) +#define debug_hex8(data) +#define debug_hex16(data) +#define debug_hex32(data) +#define debug_bin8(data) +#define debug_bin16(data) +#define debug_bin32(data) +#define debug_bin_reverse8(data) +#define debug_bin_reverse16(data) +#define debug_bin_reverse32(data) +#define debug_hex(data) +#define debug_bin(data) +#define debug_bin_reverse(data) + +#endif diff --git a/common/print.c b/common/print.c index 329f8351..783bb4e9 100644 --- a/common/print.c +++ b/common/print.c @@ -1,4 +1,4 @@ -/* Copyright 2012 Jun Wako */ +/* Copyright 2012,2013 Jun Wako */ /* Very basic print functions, intended to be used with usb_debug_only.c * http://www.pjrc.com/teensy/ * Copyright (c) 2008 PJRC.COM, LLC @@ -29,20 +29,14 @@ #ifndef NO_PRINT -#define sendchar(c) do { if (print_sendchar_func) (print_sendchar_func)(c); } while (0) +#define sendchar(c) xputc(c) -static int8_t (*print_sendchar_func)(uint8_t) = 0; - void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { - print_sendchar_func = sendchar_func; + xdev_out(sendchar_func); } -/* print string stored in data memory(SRAM) - * print_P("hello world"); - * This consumes precious SRAM memory space for string. - */ void print_S(const char *s) { uint8_t c; @@ -54,140 +48,15 @@ void print_S(const char *s) } } -/* print string stored in program memory(FLASH) - * print_P(PSTR("hello world"); - * This consumes relatively abundant FLASH memory area not SRAM. - */ -void print_P(const char *s) -{ - uint8_t c; - while (1) { - c = pgm_read_byte(s++); - if (!c) break; - if (c == '\n') sendchar('\r'); - sendchar(c); - } -} - -void print_CRLF(void) -{ - sendchar('\r'); sendchar('\n'); -} - - -#define SIGNED 0x80 -#define BIN 2 -#define OCT 8 -#define DEC 10 -#define HEX 16 - -static inline -char itoc(uint8_t i) -{ - return (i < 10 ? '0' + i : 'A' + i - 10); -} - -static inline -void print_int(uint16_t data, uint8_t base) -{ - char buf[7] = {'\0'}; - char *p = &buf[6]; - if ((base & SIGNED) && (data & 0x8000)) { - data = -data; - buf[0] = '-'; - } - base &= ~SIGNED; - uint16_t n; - do { - n = data; - data /= base; - *(--p) = itoc(n - data*base); - } while (data); - if (buf[0]) *(--p) = buf[0]; - print_S(p); -} - -void print_dec(uint16_t data) -{ - print_int(data, DEC); -} - -void print_decs(int16_t data) -{ - print_int(data, DEC|SIGNED); -} - - -void print_hex4(uint8_t data) -{ - sendchar(data + ((data < 10) ? '0' : 'A' - 10)); -} - -void print_hex8(uint8_t data) -{ - print_hex4(data>>4); - print_hex4(data&0x0F); -} - -void print_hex16(uint16_t data) -{ - print_hex8(data>>8); - print_hex8(data); -} - -void print_hex32(uint32_t data) -{ - print_hex16(data>>16); - print_hex16(data); -} - -void print_bin4(uint8_t data) -{ - for (int i = 4; i >= 0; i--) { - sendchar((data & (1<= 0; i--) { - sendchar((data & (1<>8); - print_bin8(data); -} - -void print_bin32(uint32_t data) -{ - print_bin8(data>>24); - print_bin8(data>>16); - print_bin8(data>>8); - print_bin8(data); -} - -void print_bin_reverse8(uint8_t data) -{ - for (int i = 0; i < 8; i++) { - sendchar((data & (1<>8); + sendchar('\n'); } -void print_bin_reverse32(uint32_t data) +void print_crlf(void) { - print_bin_reverse8(data); - print_bin_reverse8(data>>8); - print_bin_reverse8(data>>16); - print_bin_reverse8(data>>24); + sendchar('\r'); + sendchar('\n'); } #endif diff --git a/common/print.h b/common/print.h index 80858b3b..930e84be 100644 --- a/common/print.h +++ b/common/print.h @@ -28,6 +28,8 @@ #include #include #include +#include "xprintf.h" +#include "util.h" // this macro allows you to write print("some text") and @@ -49,17 +51,17 @@ #define pbin_reverse16(data) print_bin_reverse16(data) /* print value utility */ -#define print_val_dec(v) do { print_P(PSTR(#v ": ")); print_dec(v); print_P(PSTR("\n")); } while (0) -#define print_val_decs(v) do { print_P(PSTR(#v ": ")); print_decs(v); print_P(PSTR("\n")); } while (0) -#define print_val_hex8(v) do { print_P(PSTR(#v ": ")); print_hex8(v); print_P(PSTR("\n")); } while (0) -#define print_val_hex16(v) do { print_P(PSTR(#v ": ")); print_hex16(v); print_P(PSTR("\n")); } while (0) -#define print_val_hex32(v) do { print_P(PSTR(#v ": ")); print_hex32(v); print_P(PSTR("\n")); } while (0) -#define print_val_bin8(v) do { print_P(PSTR(#v ": ")); print_bin8(v); print_P(PSTR("\n")); } while (0) -#define print_val_bin16(v) do { print_P(PSTR(#v ": ")); print_bin16(v); print_P(PSTR("\n")); } while (0) -#define print_val_bin32(v) do { print_P(PSTR(#v ": ")); print_bin32(v); print_P(PSTR("\n")); } while (0) -#define print_val_bin_reverse8(v) do { print_P(PSTR(#v ": ")); print_bin_reverse8(v); print_P(PSTR("\n")); } while (0) -#define print_val_bin_reverse16(v) do { print_P(PSTR(#v ": ")); print_bin_reverse16(v); print_P(PSTR("\n")); } while (0) -#define print_val_bin_reverse32(v) do { print_P(PSTR(#v ": ")); print_bin_reverse32(v); print_P(PSTR("\n")); } while (0) +#define print_val_dec(v) xprintf(#v ": %u\n", v) +#define print_val_decs(v) xprintf(#v ": %d\n", v) +#define print_val_hex8(v) xprintf(#v ": %X\n", v) +#define print_val_hex16(v) xprintf(#v ": %02X\n", v) +#define print_val_hex32(v) xprintf(#v ": %04lX\n", v) +#define print_val_bin8(v) xprintf(#v ": %08b\n", v) +#define print_val_bin16(v) xprintf(#v ": %016b\n", v) +#define print_val_bin32(v) xprintf(#v ": %032lb\n", v) +#define print_val_bin_reverse8(v) xprintf(#v ": %08b\n", bitrev(v)) +#define print_val_bin_reverse16(v) xprintf(#v ": %016b\n", bitrev16(v)) +#define print_val_bin_reverse32(v) xprintf(#v ": %032lb\n", bitrev32(v)) @@ -68,34 +70,46 @@ #ifdef __cplusplus extern "C" { #endif + /* function pointer of sendchar to be used by print utility */ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); -/* print string stored in data memory(SRAM) */ +/* print string stored in data memory(SRAM) + * print_S("hello world"); + * This consumes precious SRAM memory space for string. + */ void print_S(const char *s); -/* print string stored in program memory(FLASH) */ -void print_P(const char *s); -void print_CRLF(void); +void print_lf(void); +void print_crlf(void); + + +/* print string stored in program memory(FLASH) + * print_P(PSTR("hello world"); + * This consumes relatively abundant FLASH memory area not SRAM. + */ +#define print_P(s) xputs(s) /* decimal */ -void print_dec(uint16_t data); -void print_decs(int16_t data); +#define print_dec(i) xprintf("%u", i) +#define print_decs(i) xprintf("%d", i) /* hex */ -void print_hex4(uint8_t data); -void print_hex8(uint8_t data); -void print_hex16(uint16_t data); -void print_hex32(uint32_t data); +#define print_hex4(i) xprintf("%X", i) +#define print_hex8(i) xprintf("%02X", i) +#define print_hex16(i) xprintf("%04X", i) +#define print_hex32(i) xprintf("%08lX", i) /* binary */ -void print_bin4(uint8_t data); -void print_bin8(uint8_t data); -void print_bin16(uint16_t data); -void print_bin32(uint32_t data); -void print_bin_reverse8(uint8_t data); -void print_bin_reverse16(uint16_t data); -void print_bin_reverse32(uint32_t data); +#define print_bin4(i) xprintf("%04b", i) +#define print_bin8(i) xprintf("%08b", i) +#define print_bin16(i) xprintf("%016b", i) +#define print_bin32(i) xprintf("%032lb", i) + +#define print_bin_reverse8(i) xprintf("%08b", bitrev(i)) +#define print_bin_reverse16(i) xprintf("%016b", bitrev16(i)) +#define print_bin_reverse32(i) xprintf("%032lb", bitrev32(i)) + #ifdef __cplusplus } #endif @@ -105,7 +119,6 @@ void print_bin_reverse32(uint32_t data); #define print_set_sendchar(func) #define print_S(s) #define print_P(s) -#define print_CRLF() #define print_dec(data) #define print_decs(data) #define print_hex4(data) diff --git a/common/util.c b/common/util.c index 6d4d6bfd..7e0d5429 100644 --- a/common/util.c +++ b/common/util.c @@ -77,3 +77,25 @@ uint8_t biton32(uint32_t bits) if (bits >> 1) { bits >>= 1; n += 1;} return n; } + + + +uint8_t bitrev(uint8_t bits) +{ + bits = (bits & 0x0f)<<4 | (bits & 0xf0)>>4; + bits = (bits & 0b00110011)<<2 | (bits & 0b11001100)>>2; + bits = (bits & 0b01010101)<<1 | (bits & 0b10101010)>>1; + return bits; +} + +uint16_t bitrev16(uint16_t bits) +{ + bits = bitrev(bits & 0x00ff)<<8 | bitrev((bits & 0xff00)>>8); + return bits; +} + +uint32_t bitrev32(uint32_t bits) +{ + bits = (uint32_t)bitrev16(bits & 0x0000ffff)<<16 | bitrev16((bits & 0xffff0000)>>16); + return bits; +} diff --git a/common/util.h b/common/util.h index 4b8b5ca3..7451cc08 100644 --- a/common/util.h +++ b/common/util.h @@ -36,4 +36,8 @@ uint8_t biton(uint8_t bits); uint8_t biton16(uint16_t bits); uint8_t biton32(uint32_t bits); +uint8_t bitrev(uint8_t bits); +uint16_t bitrev16(uint16_t bits); +uint32_t bitrev32(uint32_t bits); + #endif diff --git a/common/xprintf.S b/common/xprintf.S new file mode 100644 index 00000000..b5a97b20 --- /dev/null +++ b/common/xprintf.S @@ -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 // 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 + + diff --git a/common/xprintf.h b/common/xprintf.h new file mode 100644 index 00000000..cddec994 --- /dev/null +++ b/common/xprintf.h @@ -0,0 +1,103 @@ +/*--------------------------------------------------------------------------- + Extended itoa, puts and printf (C)ChaN, 2011 +-----------------------------------------------------------------------------*/ + +#ifndef XPRINTF_H +#define XPRINTF_H + +#include +#include + +extern void (*xfunc_out)(uint8_t); +#define xdev_out(func) xfunc_out = (void(*)(uint8_t))(func) + +/* This is a pointer to user defined output function. It must be initialized + before using this modle. +*/ + +void xputc(char chr); + +/* This is a stub function to forward outputs to user defined output function. + All outputs from this module are output via this function. +*/ + + +/*-----------------------------------------------------------------------------*/ +void xputs(const prog_char *string); + +/* The string placed in the ROM is forwarded to xputc() directly. +*/ + + +/*-----------------------------------------------------------------------------*/ +void xitoa(long value, char radix, char width); + +/* Extended itoa(). + + value radix width output + 100 10 6 " 100" + 100 10 -6 "000100" + 100 10 0 "100" + 4294967295 10 0 "4294967295" + 4294967295 -10 0 "-1" + 655360 16 -8 "000A0000" + 1024 16 0 "400" + 0x55 2 -8 "01010101" +*/ + + +/*-----------------------------------------------------------------------------*/ +#define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__) +#define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__) +#define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__) + +void __xprintf(const prog_char *format, ...); /* Send formatted string to the registered device */ +void __xsprintf(char*, const prog_char *format, ...); /* Put formatted string to the memory */ +void __xfprintf(void(*func)(uint8_t), const prog_char *format, ...); /* Send formatted string to the specified device */ + +/* Format string is placed in the ROM. The format flags is similar to printf(). + + %[flag][width][size]type + + flag + A '0' means filled with '0' when output is shorter than width. + ' ' is used in default. This is effective only numeral type. + width + Minimum width in decimal number. This is effective only numeral type. + Default width is zero. + size + A 'l' means the argument is long(32bit). Default is short(16bit). + This is effective only numeral type. + type + 'c' : Character, argument is the value + 's' : String placed on the RAM, argument is the pointer + 'S' : String placed on the ROM, argument is the pointer + 'd' : Signed decimal, argument is the value + 'u' : Unsigned decimal, argument is the value + 'X' : Hexdecimal, argument is the value + 'b' : Binary, argument is the value + '%' : '%' + +*/ + + +/*-----------------------------------------------------------------------------*/ +char xatoi(char **str, long *ret); + +/* Get value of the numeral string. + + str + Pointer to pointer to source string + + "0b11001010" binary + "0377" octal + "0xff800" hexdecimal + "1250000" decimal + "-25000" decimal + + ret + Pointer to return value +*/ + +#endif +