forked from ACreTeam/ac-decomp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request ACreTeam#6 from Cuyler36/libultra/_Printf
Implement libultra/xprintf.c, libultra/xlitob.c, & libultra/xldtob.c
- Loading branch information
Showing
6 changed files
with
633 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.