Skip to content

Commit

Permalink
Merge pull request ACreTeam#6 from Cuyler36/libultra/_Printf
Browse files Browse the repository at this point in the history
Implement libultra/xprintf.c, libultra/xlitob.c, & libultra/xldtob.c
  • Loading branch information
Prakxo authored Feb 24, 2023
2 parents a0e4071 + 2594b71 commit 861cfcb
Show file tree
Hide file tree
Showing 6 changed files with 633 additions and 7 deletions.
14 changes: 14 additions & 0 deletions config/dol_slices.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ libforest/ReconfigBATs.c:
.text: [0x8005adac, 0x8005aed4]
libc64/aprintf.c:
.text: [0x8005cbdc, 0x8005cc14]
libultra/xldtob.c:
.text: [0x8005e918, 0x8005f2a0]
.rodata: [0x800ab110, 0x800ab158]
.sdata: [0x80217df8, 0x80217e08]
.sdata2: [0x80219210, 0x80219230]
libultra/xlitob.c:
.text: [0x8005f2a0, 0x8005f4cc]
.data: [0x800ddb60, 0x800ddb88]
libultra/xprintf.c:
.text: [0x8005f4cc, 0x8005ff74]
.rodata: [0x800ab158, 0x800ab170]
.data: [0x800ddb88, 0x800ddd20]
.sdata: [0x80217e08, 0x80217e10]
.sdata2: [0x80219230, 0x80219238]
JSystem/JKernel/JKRHeap.cpp:
.text: [0x80063748, 0x80064028]
.data: [0x800ddf20, 0x800ddf98]
Expand Down
34 changes: 32 additions & 2 deletions include/libultra/xprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,40 @@
#include "va_args.h"

#ifdef __cplusplus
extern "C"{
extern "C" {
#endif

extern int _Printf(void* (*prout_func)(void*, const char*, int), void* arg, const char* fmt, va_list ap);
typedef struct {
/* 0x0 */ union {
/* 0x0 */ s64 ll;
/* 0x0 */ f64 ld;
} v;
/* 0x8 */ char* s;
/* 0xC */ s32 n0;
/* 0x10 */ s32 nz0;
/* 0x14 */ s32 n1;
/* 0x18 */ s32 nz1;
/* 0x1C */ s32 n2;
/* 0x20 */ s32 nz2;
/* 0x24 */ s32 prec;
/* 0x28 */ s32 width;
/* 0x2C */ u32 nchar;
/* 0x30 */ u32 flags;
/* 0x34 */ u8 qual;
} _Pft; // size = 0x38

typedef void* (*PrintCallback)(void*, const char*, int);

#define FLAGS_SPACE 1
#define FLAGS_PLUS 2
#define FLAGS_MINUS 4
#define FLAGS_HASH 8
#define FLAGS_ZERO 16

static void _Litob(_Pft* args, u8 type);
static void _Ldtob(_Pft* args, u8 type);
extern int _Printf(void* (*prout_func)(void*, const char*, int), void* arg,
const char* fmt, va_list ap);

#ifdef __cplusplus
}
Expand Down
288 changes: 288 additions & 0 deletions src/libultra/xldtob.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
#include <stdlib.h> /* ldiv & ldiv_t */
#include <string.h> /* memcpy */

#include "xprintf.h"

#define BUFF_LEN 0x20

s16 _Ldunscale(s16*, _Pft*);
void _Genld(_Pft*, u8, u8*, s16, s16);

const f64 pows[] = {10e0L, 10e1L, 10e3L, 10e7L, 10e15L,
10e31L, 10e63L, 10e127L, 10e255L};

/* float properties */
#define _D0 0
#define _DBIAS 0x3FF
#define _DLONG 1
#define _DOFF 4
#define _FBIAS 0x7E
#define _FOFF 7
#define _FRND 1
#define _LBIAS 0x3FFE
#define _LOFF 15
/* integer properties */
#define _C2 1
#define _CSIGN 1
#define _ILONG 0
#define _MBMAX 8
#define NAN 2
#define INF 1
#define FINITE -1
#define _DFRAC ((1 << _DOFF) - 1)
#define _DMASK (0x7FFF & ~_DFRAC)
#define _DMAX ((1 << (15 - _DOFF)) - 1)
#define _DNAN (0x8000 | _DMAX << _DOFF | 1 << (_DOFF - 1))
#define _DSIGN 0x8000
#if _D0 == 3
#define _D1 2 /* little-endian order */
#define _D2 1
#define _D3 0
#else
#define _D1 1 /* big-endian order */
#define _D2 2
#define _D3 3
#endif

#pragma optimize_for_size off
void _Ldtob(_Pft* args, u8 type) {
u8 buff[BUFF_LEN];
u8* ptr = buff;
u32 sp70;
f64 val = args->v.ld;
/* maybe struct? */
s16 err;
s16 nsig;
s16 exp;

int i;
int n;
f64 factor;
int gen;
int j;
int lo;
u8 drop;
int n2;
f64* pows_p;

if (args->prec < 0) {
args->prec = 6;
} else if (args->prec == 0 && (type == 'g' || type == 'G')) {
args->prec = 1;
}
err = _Ldunscale(&exp, (_Pft*)args);
if (err > 0) {
memcpy(args->s, err == 2 ? "NaN" : "Inf", args->n1 = 3);
return;
}
if (err == 0) {
nsig = 0;
exp = 0;
} else {
if (val < 0) {
val = -val;
}
if ((exp = (exp * 30103) / 100000 - 4) < 0) {
n = (3 - (int)exp) & ~3;
pows_p = (double*)pows;
exp = -n;
for (; n > 0; n >>= 1, pows_p++) {
if ((n & 1) != 0) {
val *= *pows_p;
}
}
} else if (exp > 0) {
factor = 1;
exp &= ~3;

pows_p = (double*)pows;
for (n = exp; n > 0; n >>= 1, pows_p++) {
if ((n & 1) != 0) {
factor *= *pows_p;
}
}
val /= factor;
}
gen = ((type == 'f') ? exp + 10 : 6) + args->prec;
if (gen > 0x13) {
gen = 0x13;
}
*ptr++ = '0';
while (gen > 0 && 0 < val) {
lo = val;
if ((gen -= 8) > 0) {
val = (val - lo) * 1.0e8;
}
ptr = ptr + 8;
for (j = 8; lo > 0 && --j >= 0;) {
const ldiv_t qr = ldiv(lo, 10);
*--ptr = qr.rem + '0';
lo = qr.quot;
}
while (--j >= 0) {
ptr--;
*ptr = '0';
}
ptr += 8;
}

gen = ptr - &buff[1];
for (ptr = &buff[1], exp += 7; *ptr == '0'; ptr++) {
--gen, --exp;
}

nsig = ((type == 'f') ? exp + 1 : ((type == 'e' || type == 'E') ? 1 : 0)) +
args->prec;
if (gen < nsig) {
nsig = gen;
}
if (nsig > 0) {
char drop = nsig < gen && '5' <= ptr[nsig] ? '9' : '0';
int n;

for (n = nsig; ptr[--n] == drop;) {
--nsig;
}

if (drop == '9') {
++ptr[n];
}

if (n < 0) {
--ptr, ++nsig, ++exp;
}
}
}
_Genld((_Pft*)args, type, ptr, nsig, exp);
}

s16 _Ldunscale(s16* pex, _Pft* px) {
u16* ps = (u16*)px;
s16 xchar = (ps[_D0] & _DMASK) >> _DOFF;

if (xchar == _DMAX) { /* NaN or INF */
*pex = 0;
return (s16)(ps[_D0] & _DFRAC || ps[_D1] || ps[_D2] || ps[_D3] ? NAN : INF);
} else if (0 < xchar) {
ps[_D0] = (ps[_D0] & ~_DMASK) | (_DBIAS << _DOFF);
*pex = xchar - (_DBIAS - 1);
return FINITE;
}
if (0 > xchar) {
return NAN;
} else {
*pex = 0;
return 0;
}
}

void _Genld(_Pft* px, u8 code, u8* p, s16 nsig, s16 xexp) {
u8 point = '.';

if (nsig <= 0) {
nsig = 1,

p = (u8*)"0";
}

if (code == 'f' || ((code == 'g' || code == 'G') && (-4 <= xexp) &&
(xexp < px->prec))) { /* 'f' format */
int x;

++xexp; /* change to leading digit count */
if (code != 'f') { /* fixup for 'g' */
if (!(px->flags & FLAGS_HASH) && nsig < px->prec) {
px->prec = nsig;
}
if ((px->prec -= xexp) < 0) {
px->prec = 0;
}
}
if (xexp <= 0) { /* digits only to right of point */
px->s[px->n1++] = '0';
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1++] = point;
}
if (px->prec < -xexp) {
xexp = -px->prec;
}
px->nz1 = -xexp;
px->prec += xexp;
if (px->prec < nsig) {
nsig = px->prec;
}
memcpy(&px->s[px->n1], p, x = px->n2 = nsig);
px->nz2 = px->prec - x;
} else if (nsig < xexp) { /* zeros before point */
memcpy(&px->s[px->n1], p, nsig);
px->n1 += nsig;
px->nz1 = xexp - nsig;
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1] = point, ++px->n2;
}
px->nz2 = px->prec;
} else { /* enough digits before point */
memcpy(&px->s[px->n1], p, xexp);
px->n1 += xexp;
nsig -= xexp;
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1++] = point;
}
if (px->prec < nsig) {
nsig = px->prec;
}
memcpy(&px->s[px->n1], p + (int)xexp, nsig);
px->n1 += nsig;
px->nz1 = px->prec - nsig;
}
} else { /* 'e' format */
if (code == 'g' || code == 'G') { /* fixup for 'g' */
if (nsig < px->prec) {
px->prec = nsig;
}
if (--px->prec < 0) {
px->prec = 0;
}
code = code == 'g' ? 'e' : 'E';
}
px->s[px->n1++] = *p++;
if (0 < px->prec || px->flags & FLAGS_HASH) {
px->s[px->n1++] = point;
}
if (0 < px->prec) { /* put fraction digits */
if (px->prec < --nsig) {
nsig = px->prec;
}
memcpy(&px->s[px->n1], p, nsig);
px->n1 += nsig;
px->nz1 = px->prec - nsig;
}
p = (u8*)&px->s[px->n1]; /* put exponent */
*p++ = code;
if (0 <= xexp) {
*p++ = '+';
} else { /* negative exponent */
*p++ = '-';
xexp = -xexp;
}
if (100 <= xexp) { /* put oversize exponent */
if (1000 <= xexp) {
*p++ = xexp / 1000 + '0', xexp %= 1000;
}
*p++ = xexp / 100 + '0', xexp %= 100;
}
*p++ = xexp / 10 + '0', xexp %= 10;
*p++ = xexp + '0';
px->n2 = p - (u8*)&px->s[px->n1];
}
if ((px->flags & (FLAGS_ZERO | FLAGS_MINUS)) ==
FLAGS_ZERO) { /* pad with leading zeros */
s32 n = px->n0 + px->n1 + px->nz1 + px->n2 + px->nz2;

if (n < px->width) {
px->nz0 = px->width - n;
}
}
}

#pragma optimize_for_size reset
Loading

0 comments on commit 861cfcb

Please sign in to comment.