Hi Stefan, On 11 November 2015 at 07:25, Stefan Roese <[email protected]> wrote: > This patch adds a small printf() version that supports all basic formats. > Its intented to be used in U-Boot SPL versions on platforms with very > limited internal RAM sizes. > > To enable it, just define CONFIG_USE_TINY_PRINTF in your defconfig. This > will result in the SPL using this tiny function and the main U-Boot > still using the full-blown printf() function. > > This code was copied from: > http://www.sparetimelabs.com/printfrevisited > With mostly only coding style related changes so that its checkpatch > clean. > > The size reduction is about 2.5KiB. Here a comparison for the db-88f6820-gp > (Marvell A38x) SPL: > > Without this patch: > 108075 13298 2824 124197 1e525 ./spl/u-boot-spl > > With this patch: > 105398 13298 2852 121548 1dacc ./spl/u-boot-spl
Great! > > Note: > To make it possible to compile tiny-printf.c instead of vsprintf.c when > CONFIG_USE_TINY_PRINTF is defined, the functions printf() and vprintf() are > moved from common/console.c into vsprintf.c in this patch. > > Signed-off-by: Stefan Roese <[email protected]> > Cc: Simon Glass <[email protected]> > Cc: Hans de Goede <[email protected]> > Cc: Tom Rini <[email protected]> > --- > common/console.c | 39 ---------------- > lib/Kconfig | 8 ++++ > lib/Makefile | 7 ++- > lib/tiny-printf.c | 130 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/vsprintf.c | 39 ++++++++++++++++ > 5 files changed, 183 insertions(+), 40 deletions(-) > create mode 100644 lib/tiny-printf.c > > diff --git a/common/console.c b/common/console.c > index ace206c..2bfd59f 100644 > --- a/common/console.c > +++ b/common/console.c > @@ -535,45 +535,6 @@ void puts(const char *s) > } > } > > -int printf(const char *fmt, ...) > -{ > - va_list args; > - uint i; > - char printbuffer[CONFIG_SYS_PBSIZE]; > - > - va_start(args, fmt); > - > - /* For this to work, printbuffer must be larger than > - * anything we ever want to print. > - */ > - i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); > - va_end(args); > - > - /* Print the string */ > - puts(printbuffer); > - return i; > -} > - > -int vprintf(const char *fmt, va_list args) > -{ > - uint i; > - char printbuffer[CONFIG_SYS_PBSIZE]; > - > -#if defined(CONFIG_PRE_CONSOLE_BUFFER) && !defined(CONFIG_SANDBOX) > - if (!gd->have_console) > - return 0; > -#endif > - > - /* For this to work, printbuffer must be larger than > - * anything we ever want to print. > - */ > - i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); > - > - /* Print the string */ > - puts(printbuffer); > - return i; > -} > - > /* test if ctrl-c was pressed */ > static int ctrlc_disabled = 0; /* see disable_ctrl() */ > static int ctrlc_was_pressed = 0; > diff --git a/lib/Kconfig b/lib/Kconfig > index 30e84ed..faf3de3 100644 > --- a/lib/Kconfig > +++ b/lib/Kconfig > @@ -36,6 +36,14 @@ config SYS_VSNPRINTF > Thumb-2, about 420 bytes). Enable this option for safety when > using sprintf() with data you do not control. > > +config USE_TINY_PRINTF > + bool "Enable tiny printf() version" > + help > + This option enables a tiny, stripped down printf version. > + This should only be used in space limited environments, > + like SPL versions with hard memory limits. This version > + reduces the code size by about 2.5KiB on armv7. > + > config REGEX > bool "Enable regular expression support" > default y if NET > diff --git a/lib/Makefile b/lib/Makefile > index 3eecefa..54b6555 100644 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -79,7 +79,12 @@ obj-y += string.o > obj-y += time.o > obj-$(CONFIG_TRACE) += trace.o > obj-$(CONFIG_LIB_UUID) += uuid.o > -obj-y += vsprintf.o > obj-$(CONFIG_LIB_RAND) += rand.o > > +ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_USE_TINY_PRINTF),yy) > +obj-y += tiny-printf.o > +else > +obj-y += vsprintf.o > +endif > + > subdir-ccflags-$(CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED) += -O2 > diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c > new file mode 100644 > index 0000000..d743a36 > --- /dev/null > +++ b/lib/tiny-printf.c > @@ -0,0 +1,130 @@ > +/* > + * Tiny printf version for SPL > + * > + * Copied from: > + * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php > + * > + * Copyright (C) 2004,2008 Kustaa Nyholm > + * > + * SPDX-License-Identifier: LGPL-2.1+ > + */ > + > +#include <common.h> > +#include <stdarg.h> > +#include <serial.h> > + > +static char *bf; > +static char buf[12]; > +static unsigned int num; > +static char uc; > +static char zs; Do we need all these variables? Perhaps some of them could become parameters instead? > + > +static void out(char c) > +{ > + *bf++ = c; > +} > + > +static void out_dgt(char dgt) > +{ > + out(dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10)); > + zs = 1; > +} > + > +static void div_out(unsigned int div) > +{ > + unsigned char dgt = 0; > + > + num &= 0xffff; /* just for testing the code with 32 bit ints */ > + while (num >= div) { > + num -= div; > + dgt++; > + } > + > + if (zs || dgt > 0) > + out_dgt(dgt); > +} > + > +int printf(const char *fmt, ...) > +{ > + va_list va; > + char ch; > + char *p; > + > + va_start(va, fmt); > + > + while ((ch = *(fmt++))) { > + if (ch != '%') { > + putc(ch); > + } else { > + char lz = 0; > + char w = 0; > + > + ch = *(fmt++); > + if (ch == '0') { > + ch = *(fmt++); > + lz = 1; > + } > + > + if (ch >= '0' && ch <= '9') { > + w = 0; > + while (ch >= '0' && ch <= '9') { > + w = (((w << 2) + w) << 1) + ch - '0'; Doesn't the compiler do the right thing if you say: w = (w * 10) + ch - '0' > + ch = *fmt++; > + } > + } > + bf = buf; > + p = bf; > + zs = 0; > + > + switch (ch) { > + case 0: > + goto abort; > + case 'u': > + case 'd': > + num = va_arg(va, unsigned int); > + if (ch == 'd' && (int)num < 0) { > + num = -(int)num; > + out('-'); > + } > + div_out(10000); Does this mean it cannot output numbers larger than 99999? > + div_out(1000); > + div_out(100); > + div_out(10); > + out_dgt(num); > + break; > + case 'x': > + case 'X': > + uc = ch == 'X'; > + num = va_arg(va, unsigned int); > + div_out(0x1000); How about: for (div = 0x1000; div; div >>= 4) div_out(div) > + div_out(0x100); > + div_out(0x10); > + out_dgt(num); > + break; > + case 'c': > + out((char)(va_arg(va, int))); > + break; > + case 's': > + p = va_arg(va, char*); > + break; > + case '%': > + out('%'); > + default: > + break; > + } > + > + *bf = 0; > + bf = p; > + while (*bf++ && w > 0) > + w--; I wonder if the digits could be written to the buffer in reverse order, thus allowing something like this for the decimal case: for (div = 10; div <= 10000; div *= 10) div_out(div) > + while (w-- > 0) > + putc(lz ? '0' : ' '); > + while ((ch = *p++)) and here you could work backwards. > + putc(ch); > + } > + } > + > +abort: > + va_end(va); > + return 0; > +} > diff --git a/lib/vsprintf.c b/lib/vsprintf.c > index 4c82837..8cc5b38 100644 > --- a/lib/vsprintf.c > +++ b/lib/vsprintf.c > @@ -861,6 +861,45 @@ int sprintf(char *buf, const char *fmt, ...) > return i; > } > > +int printf(const char *fmt, ...) > +{ > + va_list args; > + uint i; > + char printbuffer[CONFIG_SYS_PBSIZE]; > + > + va_start(args, fmt); > + > + /* For this to work, printbuffer must be larger than > + * anything we ever want to print. > + */ > + i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); > + va_end(args); > + > + /* Print the string */ > + puts(printbuffer); > + return i; > +} > + > +int vprintf(const char *fmt, va_list args) > +{ > + uint i; > + char printbuffer[CONFIG_SYS_PBSIZE]; > + > +#if defined(CONFIG_PRE_CONSOLE_BUFFER) && !defined(CONFIG_SANDBOX) > + if (!gd->have_console) > + return 0; > +#endif Hmm, that code in the #if should be removed. I did it for printf() but forgot vprintf(). If you have time you could add a patch for this. > + > + /* For this to work, printbuffer must be larger than /* * For this to work... */ > + * anything we ever want to print. > + */ > + i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); > + > + /* Print the string */ > + puts(printbuffer); > + return i; > +} > + > static void panic_finish(void) __attribute__ ((noreturn)); > > static void panic_finish(void) > -- > 2.6.3 > Regards, Simon _______________________________________________ U-Boot mailing list [email protected] http://lists.denx.de/mailman/listinfo/u-boot

