Commit 7d9cde10 authored by Stefan Roese's avatar Stefan Roese Committed by Tom Rini

lib/tiny-printf.c: Add tiny printf function for space limited environments

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-mv784mp-gp
(Marvell AXP) SPL:

Without this patch:
  58963   18536    1928   79427   13643 ./spl/u-boot-spl

With this patch:
  56542   18536    1956   77034   12cea ./spl/u-boot-spl

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: default avatarStefan Roese <sr@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Tom Rini <trini@konsulko.com>
Cc: Albert Aribaud <albert.u.boot@aribaud.net>
parent ddf7355a
......@@ -558,42 +558,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];
/*
* 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;
}
#ifdef CONFIG_CONSOLE_RECORD
int console_record_init(void)
{
......
......@@ -16,46 +16,14 @@
#include "glue.h"
/*
* printf() and vprintf() are stolen from u-boot/common/console.c
*/
int printf (const char *fmt, ...)
{
va_list args;
uint i;
char printbuffer[256];
va_start (args, fmt);
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
i = vsprintf (printbuffer, fmt, args);
va_end (args);
/* Print the string */
ub_puts (printbuffer);
return i;
}
int vprintf (const char *fmt, va_list args)
void putc(const char c)
{
uint i;
char printbuffer[256];
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
i = vsprintf (printbuffer, fmt, args);
/* Print the string */
ub_puts (printbuffer);
return i;
ub_putc(c);
}
void putc (const char c)
void puts(const char *s)
{
ub_putc(c);
ub_puts(s);
}
void __udelay(unsigned long usec)
......
......@@ -36,6 +36,16 @@ 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.
The supported format specifiers are %c, %s, %u/%d and %x.
config REGEX
bool "Enable regular expression support"
default y if NET
......
......@@ -80,7 +80,18 @@ 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
ifdef CONFIG_SPL_BUILD
# SPL U-Boot may use full-printf, tiny-printf or none at all
ifdef CONFIG_USE_TINY_PRINTF
obj-$(CONFIG_SPL_SERIAL_SUPPORT) += tiny-printf.o
else
obj-$(CONFIG_SPL_SERIAL_SUPPORT) += vsprintf.o
endif
else
# Main U-Boot always uses the full printf support
obj-y += vsprintf.o
endif
subdir-ccflags-$(CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED) += -O2
/*
* 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;
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';
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);
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);
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--;
while (w-- > 0)
putc(lz ? '0' : ' ');
while ((ch = *p++))
putc(ch);
}
}
abort:
va_end(va);
return 0;
}
......@@ -861,6 +861,42 @@ 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];
/*
* 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;
}
static void panic_finish(void) __attribute__ ((noreturn));
static void panic_finish(void)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment