ctr_firmware/trunk/bootrom/build/libraries/os/common/os_printf.c
nakasima b84675780d デバッグプリント関数追加。
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_firmware@145 b871894f-2f95-9b40-918c-086798483c85
2008-12-26 04:06:25 +00:00

834 lines
27 KiB
C
Raw Blame History

/*---------------------------------------------------------------------------*
Project: CtrBrom - libraries - OS
File: os_printf.c
Copyright 2008 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Date:: $
$Rev$
$Author$
*---------------------------------------------------------------------------*/
#include <string.h>
#include <brom/os.h>
#include <brom/vlink.h>
#ifndef SDK_FINALROM
static char common_buffer[256]; // thread unsafe, but less use of stack
#endif
#if !defined(SDK_FINALROM) && defined(SDK_NO_MESSAGE)
#undef i_osWarning
#undef i_osTWarning
#undef i_osPanic
#undef i_osTPanic
void i_osWarning(const char *file, int line, const char *fmt, ...);
void i_osTWarning(const char *file, int line, const char *fmt, ...);
void i_osPanic(const char *file, int line, const char *fmt, ...);
void i_osTPanic(const char *file, int line, const char *fmt, ...);
#endif /* SDK_NO_MESSAGE */
/*---------------------------------------------------------------------------*
Name: osPutChar
Description: put a letter for debug console
Arguments: c : char code , shuild be 0x01-0xff
Returns: None.
*---------------------------------------------------------------------------*/
#ifndef SDK_FINALROM
SDK_WEAK_SYMBOL void osPutChar(char c)
{
char str[2];
str[0] = c;
str[1] = '\0';
// Because of no putchar-type function on ISDebugger library,
// use 'putstring' for a single letter outputting
osPutString(str);
}
#endif
/*---------------------------------------------------------------------------*
Name: osPutString
Description: put a string to debug console.
console port are automatically switched depends on emu/hw
Arguments: str : string
Returns: None.
*---------------------------------------------------------------------------*/
static void osPutStringInit(const char *str);
#ifndef SDK_FINALROM
static void osPutStringKMC(const char *str);
void osPutStringARM(const char *str);
#ifdef SDK_ARM7
static void osPutStringPrnSrv(const char *str);
#endif
#endif
#ifndef SDK_FINALROM
void (*osPutString) (const char *str) = osPutStringInit;
#endif
/*---------------------------------------------------------------------------*
Name: osPutStringInit
Description: osPutString initializer
*---------------------------------------------------------------------------*/
static void osPutStringInit(const char *str)
{
#ifndef SDK_FINALROM
OSIntrMode intr = osDisableInterrupts();
{
#ifdef SDK_DEBUGGER_KMC
osPutString = osPutStringKMC;
#else // SDK_DEBUGGER_ARM
osPutString = osPutStringARM;
#endif
}
osPutString(str);
(void)osRestoreInterrupts(intr);
#else
(void)str; // avoiding to unused warning
#endif
}
/*---------------------------------------------------------------------------*
Name: osPutStringKMC
Description: osPutString for hardware emulator called KMC Debugger
*---------------------------------------------------------------------------*/
#ifndef SDK_FINALROM
static void osPutStringKMC(const char *str)
{
vlink_dos_putstring_console((char *)str, strlen(str)); // STD_GetStringLength(str));
}
#endif
/*---------------------------------------------------------------------------*
Name: osPutStringARM
Description: osPutString for hardware emulator called ARM Debugger
*---------------------------------------------------------------------------*/
#ifndef SDK_FINALROM
#include <brom/code32.h>
asm void osPutStringARM(const char *str)
{
mov r1, r0
mov r0, #0x04
swi 0x123456
bx lr
}
#include <brom/codereset.h>
#endif
/*---------------------------------------------------------------------------*
Name: osVPrintf/osTVPrintf
Description: print formatted strings (vprintf ver.)
Arguments: fmt : format string
vlist : parameters
Returns: None.
*---------------------------------------------------------------------------*/
// If you want to use "vsnprintf()" in ARM7, define SDK_USE_VSNPRINTF.
// "vsnprintf()" is able to print float format but the code size become hugely bigger.
// #define SDK_USE_VSNPRINTF
#ifndef SDK_FINALROM
#if defined(SDK_USE_VSNPRINTF)
SDK_WEAK_SYMBOL void osVPrintf(const char *fmt, va_list vlist)
{
(void)vsnprintf(common_buffer, sizeof(common_buffer), fmt, vlist);
osPutString(common_buffer);
}
#else
SDK_WEAK_SYMBOL void osVPrintf(const char *fmt, va_list vlist)
{
osTVPrintf(fmt, vlist);
}
#endif
SDK_WEAK_SYMBOL void osTVPrintf(const char *fmt, va_list vlist)
{
(void)osVSNPrintf(common_buffer, sizeof(common_buffer), fmt, vlist);
osPutString(common_buffer);
}
#endif
/*---------------------------------------------------------------------------*
Name: osPrintf/osTPrintf
Description: print formatted strings.
Arguments: fmt : format string
... and parameters
Returns: None.
*---------------------------------------------------------------------------*/
#ifndef SDK_FINALROM
SDK_WEAK_SYMBOL void osPrintf(const char *fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
osVPrintf(fmt, vlist);
va_end(vlist);
}
SDK_WEAK_SYMBOL void osTPrintf(const char *fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
osTVPrintf(fmt, vlist);
va_end(vlist);
}
#endif
/*---------------------------------------------------------------------------*
Name: i_osWarning / i_osTWarning
Description: print warning message.
Arguments: file : filename of warning location
line : line number of warning location
fmt : format string
... and parameters
Returns: None.
*---------------------------------------------------------------------------*/
#ifndef SDK_FINALROM
SDK_WEAK_SYMBOL void i_osWarning(const char *file, int line, const char *fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
osPrintf("%s:%d Warning:", file, line);
osVPrintf(fmt, vlist);
osPrintf("\n");
va_end(vlist);
}
SDK_WEAK_SYMBOL void i_osTWarning(const char *file, int line, const char *fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
osTPrintf("%s:%d Warning:", file, line);
osTVPrintf(fmt, vlist);
osTPrintf("\n");
va_end(vlist);
}
#endif
/*---------------------------------------------------------------------------*
Name: i_osPanic/i_osTPanic
Description: print panic message and halt cpu.
Arguments: file : filename of panic location
line : line number of panic location
fmt : format string
... and parameters
Returns: None.
*---------------------------------------------------------------------------*/
#ifndef SDK_FINALROM
void (*i_osFuncTerminate) (void) = osTerminate;
SDK_WEAK_SYMBOL void i_osPanic(const char *file, int line, const char *fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
(void)osDisableInterrupts();
osPrintf("%s:%d Panic:", file, line);
osVPrintf(fmt, vlist);
osPrintf("\n");
i_osFuncTerminate(); // Never Returns
}
SDK_WEAK_SYMBOL void i_osTPanic(const char *file, int line, const char *fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
(void)osDisableInterrupts();
osTPrintf("%s:%d Panic:", file, line);
osTVPrintf(fmt, vlist);
osTPrintf("\n");
i_osFuncTerminate(); // Never Returns
}
#endif
#if defined(SDK_CW_WARNOFF_SAFESTRB)
#include <brom/code32.h>
#endif
/* inner function for sized-buffer output */
typedef struct dst_string_tag
{
size_t len;
char *cur;
char *base;
}
dst_string;
static void string_put_char(dst_string * p, char c)
{
if (p->len > 0)
*p->cur = c, --p->len;
++p->cur;
}
static void string_fill_char(dst_string * p, char c, int n)
{
if (n > 0)
{
size_t i, k = p->len;
if (k > (size_t) n)
k = (size_t) n;
for (i = 0; i < k; ++i)
p->cur[i] = c;
p->len -= k;
p->cur += n;
}
}
static void string_put_string(dst_string * p, const char *s, int n)
{
if (n > 0)
{
size_t i, k = p->len;
if (k > (size_t) n)
k = (size_t) n;
for (i = 0; i < k; ++i)
p->cur[i] = s[i];
p->len -= k;
p->cur += n;
}
}
/*---------------------------------------------------------------------------*
Name: osSPrintf
Description: equal to 'osVSPrintf' except argument style.
Arguments: dst : destination buffer.
fmt : format string.
Returns: length of the generated string.
*---------------------------------------------------------------------------*/
SDK_WEAK_SYMBOL int osSPrintf(char *dst, const char *fmt, ...)
{
int ret;
va_list va;
va_start(va, fmt);
ret = osVSPrintf(dst, fmt, va);
va_end(va);
return ret;
}
/*---------------------------------------------------------------------------*
Name: osVSPrintf
Description: equal to 'osVSNPrintf' except buffer size argument.
Arguments: dst : destination buffer.
fmt : format string.
vlist : parameters.
Returns: length of the generated string.
*---------------------------------------------------------------------------*/
SDK_WEAK_SYMBOL int osVSPrintf(char *dst, const char *fmt, va_list vlist)
{
return osVSNPrintf(dst, 0x7FFFFFFF, fmt, vlist);
}
/*---------------------------------------------------------------------------*
Name: osSNPrintf
Description: equal to 'osVSNPrintf' except argument style.
Arguments: dst : destination buffer.
len : destination buffer size.
fmt : format string.
Returns: length of the generated string. (except '\0')
if(result < len),
put NUL in dst[result].
else if(len > 0),
put NUL in dst[len - 1].
else,
do nothing.
*---------------------------------------------------------------------------*/
SDK_WEAK_SYMBOL int osSNPrintf(char *dst, size_t len, const char *fmt, ...)
{
int ret;
va_list va;
va_start(va, fmt);
ret = osVSNPrintf(dst, len, fmt, va);
va_end(va);
return ret;
}
/*---------------------------------------------------------------------------*
Name: osVSNPrintf
Description: small-size vsnprintf which is similar to 'vsnprintf'
without following supports.
* CodeWarrior Extensions (#s)
* MSL AltiVec Extensions (v, vh, vl, hv, lv, @)
* indexed argments (%m$, *m$)
* floating-point
* wchar_t
Note: '+' and '#' do not work, MSL's sprintf().
to keep same result, they are no implement.
{ // exsample
char buf[5];
sprintf(buf, "%-i\n", 45); // "45" (OK)
sprintf(buf, "%0i\n", 45); // "45" (OK)
sprintf(buf, "% i\n", 45); // " 45" (OK)
sprintf(buf, "%+i\n", 45); // "%+i" ("+45" expected)
sprintf(buf, "%#x\n", 45); // "%#x" ("0x2d" expected)
// but, this works correctly!
sprintf(buf, "% +i\n", 45); // "+45" (OK)
}
Arguments: dst : destination buffer.
len : destination buffer size.
fmt : format string.
vlist : parameters.
Returns: length of the generated string. (except '\0')
if(result < len),
put NUL in dst[result].
else if(len > 0),
put NUL in dst[len - 1].
else,
do nothing.
*---------------------------------------------------------------------------*/
SDK_WEAK_SYMBOL int osVSNPrintf(char *dst, size_t len, const char *fmt, va_list vlist)
{
char buf[24];
int n_buf;
char prefix[2];
int n_prefix;
const char *s = fmt;
dst_string str;
str.len = len, str.cur = str.base = dst;
while (*s)
{
if ((unsigned int)(((unsigned char)*s ^ 0x20) - 0xA1) < 0x3C)
{
/* Shift JIS character */
string_put_char(&str, *s++);
if (*s)
string_put_char(&str, *s++);
}
else if (*s != '%')
{
/* normal ASCII character */
string_put_char(&str, *s++);
}
else
{
/* output with format */
enum
{
flag_blank = 000001, /* ' ' */
flag_plus = 000002, /* '+' */
flag_sharp = 000004, /* '#' */
flag_minus = 000010, /* '-' */
flag_zero = 000020, /* '0' */
flag_l1 = 000040, /* "l" */
flag_h1 = 000100, /* "h" */
flag_l2 = 000200, /* "ll" */
flag_h2 = 000400, /* "hh" */
flag_unsigned = 010000, /* 'o', 'u', ... */
flag_end
};
int flag = 0, width = 0, precision = -1, radix = 10;
char hex_char = 'a' - 10;
const char *p_start = s;
/* flags */
for (;;)
{
switch (*++s)
{
case '+':
if (s[-1] != ' ')
break;
flag |= flag_plus;
continue;
case ' ':
flag |= flag_blank;
continue;
case '-':
flag |= flag_minus;
continue;
case '0':
flag |= flag_zero;
continue;
}
break;
}
/* width */
if (*s == '*')
{
++s, width = va_arg(vlist, int);
if (width < 0)
width = -width, flag |= flag_minus;
}
else
{
while ((*s >= '0') && (*s <= '9'))
width = (width * 10) + *s++ - '0';
}
/* precision */
if (*s == '.')
{
++s, precision = 0;
if (*s == '*')
{
++s, precision = va_arg(vlist, int);
if (precision < 0)
precision = -1;
}
else
{
while ((*s >= '0') && (*s <= '9'))
precision = (precision * 10) + *s++ - '0';
}
}
/* option */
switch (*s)
{
case 'h':
if (*++s != 'h')
flag |= flag_h1;
else
++s, flag |= flag_h2;
break;
case 'l':
if (*++s != 'l')
flag |= flag_l1;
else
++s, flag |= flag_l2;
break;
}
/* type */
switch (*s)
{
case 'd': /* signed decimal */
case 'i': /* signed decimal */
goto put_integer;
case 'o': /* unsigned octal */
radix = 8;
flag |= flag_unsigned;
goto put_integer;
case 'u': /* unsigned decimal */
flag |= flag_unsigned;
goto put_integer;
case 'X': /* unsigned hexadecimal */
hex_char = 'A' - 10;
goto put_hexadecimal;
case 'x': /* unsigned hexadecimal */
goto put_hexadecimal;
case 'p': /* pointer */
/* equal to code warrior */
flag |= flag_sharp;
precision = 8;
goto put_hexadecimal;
case 'c': /* character */
if (precision >= 0)
goto put_invalid;
{
int c = va_arg(vlist, int);
width -= 1;
if (flag & flag_minus)
{
string_put_char(&str, (char)c);
string_fill_char(&str, ' ', width);
}
else
{
char pad = (char)((flag & flag_zero) ? '0' : ' ');
string_fill_char(&str, pad, width);
string_put_char(&str, (char)c);
}
++s;
}
break;
case 's': /* string */
{
int n_buf = 0;
const char *p_buf = va_arg(vlist, const char *);
if (precision < 0)
{
while (p_buf[n_buf])
++n_buf;
}
else
{
while ((n_buf < precision) && p_buf[n_buf])
++n_buf;
}
width -= n_buf;
if (flag & flag_minus)
{
string_put_string(&str, p_buf, n_buf);
string_fill_char(&str, ' ', width);
}
else
{
char pad = (char)((flag & flag_zero) ? '0' : ' ');
string_fill_char(&str, pad, width);
string_put_string(&str, p_buf, n_buf);
}
++s;
}
break;
case 'n': /* store the number of output */
{
int pos = str.cur - str.base;
if (flag & flag_h2)
;
else if (flag & flag_h1)
*va_arg(vlist, signed short *) = (signed short)pos;
else if (flag & flag_l2)
*va_arg(vlist, u64 *) = (u64)pos;
else
*va_arg(vlist, signed int *) = (signed int)pos;
}
++s;
break;
case '%': /* output '%' */
if (p_start + 1 != s)
goto put_invalid;
string_put_char(&str, *s++);
break;
default: /* invalid type */
goto put_invalid;
put_invalid:
string_put_string(&str, p_start, s - p_start);
break;
put_hexadecimal:
radix = 16;
flag |= flag_unsigned;
put_integer:
{
u64 val = 0;
n_prefix = 0;
if (flag & flag_minus)
flag &= ~flag_zero;
if (precision < 0)
precision = 1;
else
flag &= ~flag_zero;
if (flag & flag_unsigned)
{
if (flag & flag_h2)
val = va_arg(vlist, unsigned char);
else if (flag & flag_h1)
val = va_arg(vlist, unsigned short);
else if (flag & flag_l2)
val = va_arg(vlist, u64);
else
val = va_arg(vlist, unsigned long);
flag &= ~(flag_plus | flag_blank);
if (flag & flag_sharp)
{
if (radix == 16)
{
if (val != 0)
{
prefix[0] = (char)(hex_char + (10 + 'x' - 'a'));
prefix[1] = '0';
n_prefix = 2;
}
}
else if (radix == 8)
{
prefix[0] = '0';
n_prefix = 1;
}
}
}
else
{
if (flag & flag_h2)
val = va_arg(vlist, char);
else if (flag & flag_h1)
val = va_arg(vlist, short);
else if (flag & flag_l2)
val = va_arg(vlist, u64);
else
val = va_arg(vlist, long);
if ((val >> 32) & 0x80000000)
{
val = ~val + 1;
prefix[0] = '-';
n_prefix = 1;
}
else
{
if (val || precision)
{
if (flag & flag_plus)
{
prefix[0] = '+';
n_prefix = 1;
}
else if (flag & flag_blank)
{
prefix[0] = ' ';
n_prefix = 1;
}
}
}
}
n_buf = 0;
switch (radix)
{
case 8:
while (val != 0)
{
int d = (int)(val & 0x07);
val >>= 3;
buf[n_buf++] = (char)(d + '0');
}
break;
case 10:
if ((val >> 32) == 0)
{
#if defined(SDK_CW) || defined(__MWERKS__)
#pragma optimize_for_size off
#endif
u32 v = (u32)val;
while (v != 0)
{
// u32 <20>ƒ萔<C692>̏<EFBFBD><CC8F>Z<EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD>΁A<CE81>R<EFBFBD><52><EFBFBD>p<EFBFBD>C<EFBFBD><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD><49>
// <20>}<7D>W<EFBFBD>b<EFBFBD>N<EFBFBD>i<EFBFBD><69><EFBFBD>o<EFBFBD>[<5B><><EFBFBD>g<EFBFBD>p<EFBFBD><70><EFBFBD><EFBFBD><EFBFBD>ώZ<CF8E>ɕϊ<C995><CF8A><EFBFBD><EFBFBD><EFBFBD>
u32 r = v / 10;
int d = (int)(v - (r * 10));
v = r;
buf[n_buf++] = (char)(d + '0');
}
}
else
{
while (val != 0)
{
u64 r = val / 10;
int d = (int)(val - (r * 10));
val = r;
buf[n_buf++] = (char)(d + '0');
}
}
break;
case 16:
while (val != 0)
{
int d = (int)(val & 0x0f);
val >>= 4;
buf[n_buf++] = (char)((d < 10) ? (d + '0') : (d + hex_char));
}
break;
}
if ((n_prefix > 0) && (prefix[0] == '0'))
{
n_prefix = 0;
buf[n_buf++] = '0';
}
}
goto put_to_stream;
put_to_stream:
{
int n_pad = precision - n_buf;
if (flag & flag_zero)
{
if (n_pad < width - n_buf - n_prefix)
n_pad = width - n_buf - n_prefix;
}
if (n_pad > 0)
width -= n_pad;
width -= n_prefix + n_buf;
if (!(flag & flag_minus))
string_fill_char(&str, ' ', width);
while (n_prefix > 0)
string_put_char(&str, prefix[--n_prefix]);
string_fill_char(&str, '0', n_pad);
while (n_buf > 0)
string_put_char(&str, buf[--n_buf]);
if (flag & flag_minus)
string_fill_char(&str, ' ', width);
++s;
}
break;
}
}
}
if (str.len > 0)
*str.cur = '\0';
else if (len > 0)
str.base[len - 1] = '\0';
return str.cur - str.base;
}
#if defined(SDK_CW_WARNOFF_SAFESTRB)
#include <nitro/codereset.h>
#endif
//================================================================================
// DUMMY PRINT (stub for FINALROM)
//================================================================================
#ifdef SDK_FINALROM
#ifdef osPrintf
#undef osPrintf
#endif
void osPrintf(const char *fmt, ...);
void osPrintf(const char *fmt, ...)
{
//#pragma unused( fmt )
}
#endif