267 lines
5.2 KiB
C
267 lines
5.2 KiB
C
|
|
||
|
typedef unsigned long va_list;
|
||
|
|
||
|
#define ACC 4
|
||
|
#define __read(source) \
|
||
|
({ va_list __res; \
|
||
|
__asm__ __volatile__( \
|
||
|
"move\t%0, " #source "\n\t" \
|
||
|
: "=r" (__res)); \
|
||
|
__res; \
|
||
|
})
|
||
|
|
||
|
enum format_type {
|
||
|
FORMAT_TYPE_NONE,
|
||
|
FORMAT_TYPE_HEX,
|
||
|
FORMAT_TYPE_ULONG,
|
||
|
FORMAT_TYPE_FLOAT
|
||
|
};
|
||
|
|
||
|
struct printf_spec {
|
||
|
char type;
|
||
|
};
|
||
|
|
||
|
static int format_decode(char *fmt, struct printf_spec *spec)
|
||
|
{
|
||
|
char *start = fmt;
|
||
|
|
||
|
for (; *fmt ; ++fmt) {
|
||
|
if (*fmt == '%') {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (*++fmt) {
|
||
|
case 'x':
|
||
|
spec->type = FORMAT_TYPE_HEX;
|
||
|
break;
|
||
|
|
||
|
case 'd':
|
||
|
spec->type = FORMAT_TYPE_ULONG;
|
||
|
break;
|
||
|
|
||
|
case 'f':
|
||
|
spec->type = FORMAT_TYPE_FLOAT;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
spec->type = FORMAT_TYPE_NONE;
|
||
|
}
|
||
|
|
||
|
return ++fmt - start;
|
||
|
}
|
||
|
|
||
|
void *memcpy(void *dest, void *src, int n)
|
||
|
{
|
||
|
int i;
|
||
|
char *s = src;
|
||
|
char *d = dest;
|
||
|
|
||
|
for (i = 0; i < n; i++) {
|
||
|
d[i] = s[i];
|
||
|
}
|
||
|
return dest;
|
||
|
}
|
||
|
|
||
|
char *number(char *buf, va_list num)
|
||
|
{
|
||
|
int i;
|
||
|
char *str = buf;
|
||
|
static char digits[16] = "0123456789abcdef";
|
||
|
str = str + sizeof(num) * 2;
|
||
|
|
||
|
for (i = 0; i < sizeof(num) * 2; i++) {
|
||
|
*--str = digits[num & 15];
|
||
|
num >>= 4;
|
||
|
}
|
||
|
|
||
|
return buf + sizeof(num) * 2;
|
||
|
}
|
||
|
|
||
|
char *__number(char *buf, va_list num)
|
||
|
{
|
||
|
int i;
|
||
|
va_list mm = num;
|
||
|
char *str = buf;
|
||
|
|
||
|
if (!num) {
|
||
|
*str++ = '0';
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
for (i = 0; mm; mm = mm/10, i++) {
|
||
|
/* Do nothing. */
|
||
|
}
|
||
|
|
||
|
str = str + i;
|
||
|
|
||
|
while (num) {
|
||
|
*--str = num % 10 + 48;
|
||
|
num = num / 10;
|
||
|
}
|
||
|
|
||
|
return str + i;
|
||
|
}
|
||
|
|
||
|
va_list modf(va_list args, va_list *integer, va_list *num)
|
||
|
{
|
||
|
int i;
|
||
|
double dot_v = 0;
|
||
|
va_list E, DOT, DOT_V;
|
||
|
|
||
|
if (!args) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
for (i = 0, args = args << 1 >> 1; i < 52; i++) {
|
||
|
if ((args >> i) & 0x1) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*integer = 0;
|
||
|
|
||
|
if ((args >> 56 != 0x3f) || (args >> 52 == 0x3ff)) {
|
||
|
E = (args >> 52) - 1023;
|
||
|
DOT = 52 - E - i;
|
||
|
DOT_V = args << (12 + E) >> (12 + E) >> i;
|
||
|
*integer = ((args << 12 >> 12) >> (i + DOT)) | (1 << E);
|
||
|
} else {
|
||
|
E = ~((args >> 52) - 1023) + 1;
|
||
|
DOT_V = args << 12 >> 12;
|
||
|
|
||
|
dot_v += 1.0 / (1 << E);
|
||
|
|
||
|
for (i = 1; i <= 16; i++) {
|
||
|
if ((DOT_V >> (52 - i)) & 0x1) {
|
||
|
dot_v += 1.0 / (1 << E + i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 1, E = 0; i <= ACC; i++) {
|
||
|
dot_v *= 10;
|
||
|
if (!(va_list)dot_v) {
|
||
|
E++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*num = E;
|
||
|
|
||
|
return dot_v;
|
||
|
}
|
||
|
|
||
|
if (args & 0xf) {
|
||
|
for (i = 1; i <= 16; i++) {
|
||
|
if ((DOT_V >> (DOT - i)) & 0x1) {
|
||
|
dot_v += 1.0 / (1 << i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 1, E = 0; i <= ACC; i++) {
|
||
|
dot_v *= 10;
|
||
|
if (!(va_list)dot_v) {
|
||
|
E++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*num = E;
|
||
|
|
||
|
return dot_v;
|
||
|
} else if (DOT) {
|
||
|
for (i = 1; i <= DOT; i++) {
|
||
|
if ((DOT_V >> (DOT - i)) & 0x1) {
|
||
|
dot_v += 1.0 / (1 << i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 1; i <= ACC; i++) {
|
||
|
dot_v = dot_v * 10;
|
||
|
}
|
||
|
|
||
|
return dot_v;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int vsnprintf(char *buf, int size, char *fmt, va_list args)
|
||
|
{
|
||
|
char *str, *mm;
|
||
|
struct printf_spec spec = {0};
|
||
|
|
||
|
str = mm = buf;
|
||
|
|
||
|
while (*fmt) {
|
||
|
char *old_fmt = fmt;
|
||
|
int read = format_decode(fmt, &spec);
|
||
|
|
||
|
fmt += read;
|
||
|
|
||
|
switch (spec.type) {
|
||
|
case FORMAT_TYPE_NONE: {
|
||
|
memcpy(str, old_fmt, read);
|
||
|
str += read;
|
||
|
break;
|
||
|
}
|
||
|
case FORMAT_TYPE_HEX: {
|
||
|
memcpy(str, old_fmt, read);
|
||
|
str = number(str + read, args);
|
||
|
for (; *mm ; ++mm) {
|
||
|
if (*mm == '%') {
|
||
|
*mm = '0';
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case FORMAT_TYPE_ULONG: {
|
||
|
memcpy(str, old_fmt, read - 2);
|
||
|
str = __number(str + read - 2, args);
|
||
|
break;
|
||
|
}
|
||
|
case FORMAT_TYPE_FLOAT: {
|
||
|
va_list integer, dot_v, num;
|
||
|
dot_v = modf(args, &integer, &num);
|
||
|
memcpy(str, old_fmt, read - 2);
|
||
|
str += read - 2;
|
||
|
if ((args >> 63 & 0x1)) {
|
||
|
*str++ = '-';
|
||
|
}
|
||
|
str = __number(str, integer);
|
||
|
if (dot_v) {
|
||
|
*str++ = '.';
|
||
|
while (num--) {
|
||
|
*str++ = '0';
|
||
|
}
|
||
|
str = __number(str, dot_v);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*str = '\0';
|
||
|
|
||
|
return str - buf;
|
||
|
}
|
||
|
|
||
|
static void serial_out(char *str)
|
||
|
{
|
||
|
while (*str) {
|
||
|
*(char *)0xffffffffb80003f8 = *str++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int vprintf(char *fmt, va_list args)
|
||
|
{
|
||
|
int printed_len = 0;
|
||
|
static char printf_buf[512];
|
||
|
printed_len = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
|
||
|
serial_out(printf_buf);
|
||
|
return printed_len;
|
||
|
}
|
||
|
|
||
|
int printf(char *fmt, ...)
|
||
|
{
|
||
|
return vprintf(fmt, __read($5));
|
||
|
}
|