subrepo:
  subdir:   "lib/n64-libc"
  merged:   "70270d60"
upstream:
  origin:   "https://gitlab.com/mpharoah/n64-libc"
  branch:   "main"
  commit:   "70270d60"
git-subrepo:
  version:  "0.4.9"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "4f60dd7"
This commit is contained in:
a
2025-06-23 20:50:28 -04:00
parent 4c89989f6f
commit 82736c610a
31 changed files with 5435 additions and 0 deletions

2
lib/n64-libc/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/.vscode
*.kate-swp

12
lib/n64-libc/.gitrepo Normal file
View File

@@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme
;
[subrepo]
remote = https://gitlab.com/mpharoah/n64-libc
branch = main
commit = 70270d60f9b13d3cd896eaa8aa0a043992a823fd
parent = 4c89989f6f2ef03e71fc89e33e4e94fa067fda04
method = merge
cmdver = 0.4.9

5
lib/n64-libc/README.md Normal file
View File

@@ -0,0 +1,5 @@
# N64 libc
Provides a partial implementation of the C standard library for N64
WORK IN PROGRESS

View File

@@ -0,0 +1,3 @@
#ifndef n64_alloca
#define n64_alloca( size ) __builtin_alloca_with_align( size, 64 )
#endif

View File

@@ -0,0 +1,9 @@
#include "n64-assert.h"
#include "n64-stdlib.h"
#include "n64-stdio.h"
void __n64_assert_fail( const char *assertion, const char *file, unsigned int line, const char *fcn ) {
n64_printf( "%s:%u: %s: Assertion `%s' failed.\n", file, line, fcn, assertion );
n64_abort();
}

32
lib/n64-libc/n64-assert.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef N64_STDLIB_N64_ASSERT_H_
#define N64_STDLIB_N64_ASSERT_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef NDEBUG
#define n64_assert( expr ) (void)(0)
#else
__attribute__((noreturn))
void __n64_assert_fail( const char *assertion, const char *file, unsigned int line, const char *fcn );
#define n64_assert( expr ) ((expr) ? (void)(0) : __n64_assert_fail( #expr, __FILE__, __LINE__, __func__ ))
#endif
#ifdef __cplusplus
#define n64_static_assert( expr ) static_assert( expr )
#else
#if __STDC_VERSION__ >= 202311L
#define n64_static_assert( expr ) static_assert( expr )
#else
#define n64_static_assert( expr ) _Static_assert( expr )
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

20
lib/n64-libc/n64-ctype.c Normal file
View File

@@ -0,0 +1,20 @@
#include "n64-ctype.h"
unsigned short __n64_internal_charflag_table[256] = {
/* 0x00 - 0x08 : control codes */ 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020,
/* 0x09 : tab */ 0x0E0,
/* 0x0A - 0x0D : whitespaces */ 0x060, 0x060, 0x060, 0x060,
/* 0x0E - 0x1F : control codes */ 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020, 0x020,
/* 0x20 : space */ 0x1C0,
/* 0x21 - 0x2F : punctuation */ 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300,
/* 0x30 - 0x39 : digits */ 0x105, 0x105, 0x105, 0x105, 0x105, 0x105, 0x105, 0x105, 0x105, 0x105,
/* 0x3A - 0x40 : punctuation */ 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300,
/* 0x41 - 0x46 : hex letters (U) */ 0x116, 0x116, 0x116, 0x116, 0x116, 0x116,
/* 0x47 - 0x5A : letters (U) */ 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112, 0x112,
/* 0x5B - 0x60 : punctuation */ 0x300, 0x300, 0x300, 0x300, 0x300, 0x300,
/* 0x61 - 0x66 : hex letters (L) */ 0x10E, 0x10E, 0x10E, 0x10E, 0x10E, 0x10E,
/* 0x67 - 0x7A : letters (L) */ 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A, 0x10A,
/* 0x7B - 0x7E : punctuation */ 0x300, 0x300, 0x300, 0x300,
/* 0x7F : backspace */ 0x020,
/* 0x80 - 0xFF : non-ASCII */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

89
lib/n64-libc/n64-ctype.h Normal file
View File

@@ -0,0 +1,89 @@
#ifndef N64_STDLIB_N64_CTYPE_H_
#define N64_STDLIB_N64_CTYPE_H_
#ifdef __cplusplus
extern "C" {
#endif
extern unsigned short __n64_internal_charflag_table[256];
__attribute__((const, always_inline))
static inline int __n64_internal_has_charflag( int ch, unsigned short flag ) {
return __n64_internal_charflag_table[(unsigned int)ch & 0xFFu] & (int)flag;
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isalnum( int ch ) {
return __n64_internal_has_charflag( ch, 0x003 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isalpha( int ch ) {
return __n64_internal_has_charflag( ch, 0x002 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_islower( int ch ) {
return __n64_internal_has_charflag( ch, 0x008 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isupper( int ch ) {
return __n64_internal_has_charflag( ch, 0x010 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isdigit( int ch ) {
return __n64_internal_has_charflag( ch, 0x001 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isxdigit( int ch ) {
return __n64_internal_has_charflag( ch, 0x004 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_iscntrl( int ch ) {
return __n64_internal_has_charflag( ch, 0x020 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isgraph( int ch ) {
return __n64_internal_has_charflag( ch, 0x203 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isspace( int ch ) {
return __n64_internal_has_charflag( ch, 0x040 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isblank( int ch ) {
return __n64_internal_has_charflag( ch, 0x080 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_isprint( int ch ) {
return __n64_internal_has_charflag( ch, 0x100 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_ispunct( int ch ) {
return __n64_internal_has_charflag( ch, 0x200 );
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_tolower( int ch ) {
return (ch >= (int)'A' && ch <= (int)'Z') ? (ch + 32) : ch;
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_toupper( int ch ) {
return (ch >= (int)'a' && ch <= (int)'z') ? (ch - 32) : ch;
}
#ifdef __cplusplus
}
#endif
#endif

72
lib/n64-libc/n64-fenv.c Normal file
View File

@@ -0,0 +1,72 @@
#include "n64-fenv.h"
int n64_feclearexcept( int excepts ) {
if( excepts & ~FE_ALL_EXCEPT ) return excepts;
register unsigned int fcr31 = __builtin_mips_get_fcsr();
fcr31 &= ~((unsigned int)excepts << 2);
__builtin_mips_set_fcsr( fcr31 );
return ((int)__builtin_mips_get_fcsr() >> 2) & excepts;
}
int n64_fetestexcept( int excepts ) {
return (int)(__builtin_mips_get_fcsr() >> 2) & FE_ALL_EXCEPT & excepts;
}
int n64_feraiseexcept( int excepts ) {
if( excepts & ~FE_ALL_EXCEPT ) return excepts;
register unsigned int fcr31 = __builtin_mips_get_fcsr();
fcr31 |= (unsigned int)excepts << 12;
__builtin_mips_set_fcsr( fcr31 );
return (((int)__builtin_mips_get_fcsr() >> 2) & excepts) ^ excepts;
}
int n64_fegetexceptflag( n64_fexcept_t *flagp, int excepts ) {
if( excepts & ~FE_ALL_EXCEPT ) return excepts;
*flagp = (n64_fexcept_t)((__builtin_mips_get_fcsr() >> 2) & (unsigned int)excepts);
return 0;
}
int n64_fesetexceptflag( const n64_fexcept_t *flagp, int excepts ) {
if( excepts & ~FE_ALL_EXCEPT ) return excepts;
register unsigned int fcr31 = __builtin_mips_get_fcsr();
fcr31 &= ~((unsigned int)excepts << 2);
fcr31 |= ((unsigned int)*flagp & (unsigned int)excepts) << 2;
__builtin_mips_set_fcsr( fcr31 );
return (((int)__builtin_mips_get_fcsr() >> 2) & excepts) ^ ((int)*flagp & excepts);
}
int n64_fesetround( int round ) {
if( round < 0 || round > 3 ) return round;
register unsigned int fcr31 = __builtin_mips_get_fcsr() & ~3u;
__builtin_mips_set_fcsr( fcr31 | (unsigned int)round );
return (int)(__builtin_mips_get_fcsr() & 3u) ^ round;
}
int n64_fegetround() {
return (unsigned int)__builtin_mips_get_fcsr() & 3u;
}
int n64_fegetenv( n64_fenv_t* envp ) {
*envp = __builtin_mips_get_fcsr();
return 0;
}
int n64_fesetenv( const n64_fenv_t* envp ) {
register const unsigned int c = __builtin_mips_get_fcsr() & 0x00800000u;
__builtin_mips_set_fcsr( (*envp & 0x01000FFFu) | c );
return (int)((*envp ^ __builtin_mips_get_fcsr()) & 0x01000FFFu);
}
int n64_feholdexcept( n64_fenv_t* envp ) {
*envp = (n64_fenv_t)__builtin_mips_get_fcsr() & 0x0103FFFFu;
__builtin_mips_set_fcsr( *envp & 0x01800003u );
return (int)(__builtin_mips_get_fcsr() & 0x0003FFFCu);
}
int n64_feupdateenv( const n64_fenv_t* envp ) {
register const unsigned int e = __builtin_mips_get_fcsr() & 0x0083F000u;
register const unsigned int c = e & 0x00800000u;
__builtin_mips_set_fcsr( (*envp & 0x01000FFFu) | c );
__builtin_mips_set_fcsr( (*envp & 0x01000FFFu) | e );
return (int)((*envp ^ __builtin_mips_get_fcsr()) & 0x0103FFFFu);
}

39
lib/n64-libc/n64-fenv.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef N64_STDLIB_N64_FENV_H_
#define N64_STDLIB_N64_FENV_H_
#ifdef __cplusplus
extern "C" {
#endif
#define FE_DIVBYZERO 0x08
#define FE_INEXACT 0x01
#define FE_INVALID 0x10
#define FE_OVERFLOW 0x04
#define FE_UNDERFLOW 0x02
#define FE_ALL_EXCEPT 0x1F
#define FE_DOWNWARD 0x3
#define FE_TONEAREST 0x0
#define FE_TOWARDZERO 0x1
#define FE_UPWARD 0x2
typedef unsigned int n64_fenv_t;
typedef unsigned char n64_fexcept_t;
int n64_feclearexcept( int excepts );
int n64_fetestexcept( int excepts ) __attribute__((warn_unused_result));
int n64_feraiseexcept( int excepts );
int n64_fegetexceptflag( n64_fexcept_t *flagp, int excepts ) __attribute__((nonnull(1), access(write_only, 1)));
int n64_fesetexceptflag( const n64_fexcept_t *flagp, int excepts ) __attribute__((nonnull(1)));
int n64_fesetround( int round );
int n64_fegetround() __attribute__((warn_unused_result));
int n64_fegetenv( n64_fenv_t* envp ) __attribute__((nonnull(1), access(write_only, 1)));
int n64_fesetenv( const n64_fenv_t* envp ) __attribute__((nonnull(1)));
int n64_feholdexcept( n64_fenv_t* envp ) __attribute__((nonnull(1), access(write_only, 1)));
int n64_feupdateenv( const n64_fenv_t* envp ) __attribute__((nonnull(1)));
#ifdef __cplusplus
}
#endif
#endif

111
lib/n64-libc/n64-float.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef FLT_RADIX
#define FLT_RADIX 2
#endif
#ifndef FLT_DECIMAL_DIG
#define FLT_DECIMAL_DIG 9
#endif
#ifndef DBL_DECIMAL_DIG
#define DBL_DECIMAL_DIG 17
#endif
#ifndef FLT_MIN
#define FLT_MIN 1.1754944e-38f
#endif
#ifndef DBL_MIN
#define DBL_MIN 2.2250738585072014e-308
#endif
#ifndef FLT_TRUE_MIN
#define FLT_TRUE_MIN 1e-45f
#endif
#ifndef DBL_TRUE_MIN
#define DBL_TRUE_MIN 5e-324
#endif
#ifndef FLT_MAX
#define FLT_MAX 3.4028235e+38f
#endif
#ifndef DBL_MAX
#define DBL_MAX 1.7976931348623157e+308
#endif
#ifndef FLT_EPSILON
#define FLT_EPSILON 1.1920929e-07f
#endif
#ifndef DBL_EPSILON
#define DBL_EPSILON 2.220446049250313e-16
#endif
#ifndef FLT_DIG
#define FLT_DIG 6
#endif
#ifndef DBL_DIG
#define DBL_DIG 15
#endif
#ifndef FLT_MANT_DIG
#define FLT_MANT_DIG 24
#endif
#ifndef DBL_MANT_DIG
#define DBL_MANT_DIG 53
#endif
#ifndef FLT_MIN_EXP
#define FLT_MIN_EXP -125
#endif
#ifndef DBL_MIN_EXP
#define DBL_MIN_EXP -1021
#endif
#ifndef FLT_MIN_10_EXP
#define FLT_MIN_10_EXP -37
#endif
#ifndef DBL_MIN_10_EXP
#define DBL_MIN_10_EXP -307
#endif
#ifndef FLT_MAX_EXP
#define FLT_MAX_EXP 128
#endif
#ifndef DBL_MAX_EXP
#define DBL_MAX_EXP 1024
#endif
#ifndef FLT_MAX_10_EXP
#define FLT_MAX_10_EXP 38
#endif
#ifndef DBL_MAX_10_EXP
#define DBL_MAX_10_EXP 308
#endif
#ifndef FLT_EVAL_METHOD
#define FLT_EVAL_METHOD 0
#endif
#ifndef FLT_HAS_SUBNORM
#define FLT_HAS_SUBNORM 1
#endif
#ifndef DBL_HAS_SUBNORM
#define DBL_HAS_SUBNORM 1
#endif
#ifndef DECIMAL_DIG
#if defined(_ABIO64) || defined(_ABIO32)
#define DECIMAL_DIG DBL_DECIMAL_DIG
#else
#define DECIMAL_DIG 36
#endif
#endif

15
lib/n64-libc/n64-libc.h Normal file
View File

@@ -0,0 +1,15 @@
#include "n64-alloca.h"
#include "n64-assert.h"
#include "n64-ctype.h"
#include "n64-fenv.h"
#include "n64-float.h"
#include "n64-math.h"
#include "n64-numbers.h"
#include "n64-stdbool.h"
#include "n64-stdckdint.h"
#include "n64-stddef.h"
#include "n64-stdio.h"
#include "n64-stdlib.h"
#include "n64-string.h"
#include "n64-time.h"
#include "n64-util.h"

558
lib/n64-libc/n64-math.c Normal file

File diff suppressed because it is too large Load Diff

275
lib/n64-libc/n64-math.h Normal file
View File

@@ -0,0 +1,275 @@
#ifndef N64_STDLIB_N64_MATH_H_
#define N64_STDLIB_N64_MATH_H_
/* Only a subset of math.h is currently implemented */
#define N64_NAN __builtin_nanf( "0" )
#define N64_HUGE_VALF __builtin_inff()
#define N64_HUGE_VAL __builtin_inf()
#define N64_INFINITY N64_HUGE_VALF
#ifndef NAN
#define NAN N64_NAN
#endif
#ifndef HUGE_VALF
#define HUGE_VALF N64_HUGE_VALF
#endif
#ifndef HUGE_VAL
#define HUGE_VAL N64_HUGE_VAL
#endif
#ifndef INFINITY
#define INFINITY N64_INFINITY
#endif
__attribute__((const, warn_unused_result))
float n64_expf( float arg );
__attribute__((const, warn_unused_result))
float n64_exp2f( float arg );
__attribute__((const, warn_unused_result))
float n64_logf( float arg );
__attribute__((const, warn_unused_result))
float n64_log10f( float arg );
__attribute__((const, warn_unused_result))
float n64_log2f( float arg );
__attribute__((const, warn_unused_result))
float n64_powf( float base, float exponent );
__attribute__((const, warn_unused_result))
float n64_cbrtf( float arg );
__attribute__((const, warn_unused_result))
float n64_hypotf( float x, float y );
__attribute__((const, warn_unused_result))
double n64_hypot( double x, double y );
__attribute__((const, warn_unused_result))
float n64_sinf( float arg );
__attribute__((const, warn_unused_result))
float n64_cosf( float arg );
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_sqrtf( float arg ) {
float result;
asm volatile( "sqrt.s %0, %1" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_sqrt( double arg ) {
double result;
asm volatile( "sqrt.d %0, %1" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_fabsf( float arg ) {
float result;
asm volatile( "abs.s %0, %1" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_fabs( double arg ) {
double result;
asm volatile( "abs.d %0, %1" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_floor( double arg ) {
if( arg > 4503599627370496.0 || arg < -4503599627370496.0 ) return arg;
double result;
asm volatile( "floor.l.d %0, %1 \n\t cvt.d.l %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_ceil( double arg ) {
if( arg > 4503599627370496.0 || arg < -4503599627370496.0 ) return arg;
double result;
asm volatile( "ceil.l.d %0, %1 \n\t cvt.d.l %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_trunc( double arg ) {
if( arg > 4503599627370496.0 || arg < -4503599627370496.0 ) return arg;
double result;
asm volatile( "trunc.l.d %0, %1 \n\t cvt.d.l %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_round( double arg ) {
if( arg > 4503599627370496.0 || arg < -4503599627370496.0 ) return arg;
double result;
asm volatile( "round.l.d %0, %1 \n\t cvt.d.l %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline double n64_rint( double arg ) {
if( arg > 4503599627370496.0 || arg < -4503599627370496.0 ) return arg;
double result;
asm volatile( "cvt.l.d %0, %1 \n\t cvt.d.l %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_floorf( float arg ) {
if( arg > 8388608.f || arg < -8388608.f ) return arg;
float result;
asm volatile( "floor.w.s %0, %1 \n\t cvt.s.w %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_ceilf( float arg ) {
if( arg > 8388608.f || arg < -8388608.f ) return arg;
float result;
asm volatile( "ceil.w.s %0, %1 \n\t cvt.s.w %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_truncf( float arg ) {
if( arg > 8388608.f || arg < -8388608.f ) return arg;
float result;
asm volatile( "trunc.w.s %0, %1 \n\t cvt.s.w %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_roundf( float arg ) {
if( arg > 8388608.f || arg < -8388608.f ) return arg;
float result;
asm volatile( "round.w.s %0, %1 \n\t cvt.s.w %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline float n64_rintf( float arg ) {
if( arg > 8388608.f || arg < -8388608.f ) return arg;
float result;
asm volatile( "cvt.w.s %0, %1 \n\t cvt.s.w %0, %0" : "=f"( result ) : "f"( arg ) );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline long long n64_llround( double arg ) {
#ifdef _ABIO32
double bits;
asm volatile( "round.l.d %0, %1" : "=f"( bits ) : "f"( arg ) );
union { double f; long long i; } b = { bits };
return b.i;
#else
long long result;
asm volatile( "round.l.d $f10, %1 \n\t dmfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
#endif
}
__attribute__((const, warn_unused_result, always_inline))
static inline long long n64_llrint( double arg ) {
#ifdef _ABIO32
double bits;
asm volatile( "cvt.l.d %0, %1" : "=f"( bits ) : "f"( arg ) );
union { double f; long long i; } b = { bits };
return b.i;
#else
long long result;
asm volatile( "cvt.l.d $f10, %1 \n\t dmfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
#endif
}
// Extensions: fill in gaps in the C standard for rounding functions
__attribute__((const, warn_unused_result, always_inline))
static inline long long n64_llfloor( double arg ) {
#ifdef _ABIO32
double bits;
asm volatile( "floor.l.d %0, %1" : "=f"( bits ) : "f"( arg ) );
union { double f; long long i; } b = { bits };
return b.i;
#else
long long result;
asm volatile( "floor.l.d $f10, %1 \n\t dmfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
#endif
}
__attribute__((const, warn_unused_result, always_inline))
static inline long long n64_llceil( double arg ) {
#ifdef _ABIO32
double bits;
asm volatile( "ceil.l.d %0, %1" : "=f"( bits ) : "f"( arg ) );
union { double f; long long i; } b = { bits };
return b.i;
#else
long long result;
asm volatile( "ceil.l.d $f10, %1 \n\t dmfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
#endif
}
__attribute__((const, warn_unused_result, always_inline))
static inline long long n64_lltrunc( double arg ) {
#ifdef _ABIO32
double bits;
asm volatile( "trunc.l.d %0, %1" : "=f"( bits ) : "f"( arg ) );
union { double f; long long i; } b = { bits };
return b.i;
#else
long long result;
asm volatile( "trunc.l.d $f10, %1 \n\t dmfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
#endif
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_ifloorf( float arg ) {
int result;
asm volatile( "floor.w.s $f10, %1 \n\t mfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_iceilf( float arg ) {
int result;
asm volatile( "ceil.w.s $f10, %1 \n\t mfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_itruncf( float arg ) {
int result;
asm volatile( "trunc.w.s $f10, %1 \n\t mfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_iroundf( float arg ) {
int result;
asm volatile( "round.w.s $f10, %1 \n\t mfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
}
__attribute__((const, warn_unused_result, always_inline))
static inline int n64_irintf( float arg ) {
int result;
asm volatile( "cvt.w.s $f10, %1 \n\t mfc1 %0, $f10" : "=r"( result ) : "f"( arg ) : "f10" );
return result;
}
#endif

View File

@@ -0,0 +1,43 @@
#ifndef N64_STDLIB_N64_NUMBERS_H_
#define N64_STDLIB_N64_NUMBERS_H_
#define N64_E 2.7182818284590452
#define N64_Ef 2.71828183f
#define N64_LOG2E 1.4426950408889634
#define N64_LOG2Ef 1.44269504f
#define N64_LOG10E 0.43429448190325183
#define N64_LOG10Ef 0.434294481f
#define N64_PI 3.1415926535897932
#define N64_PIf 3.14159265f
#define N64_INV_PI 0.31830988618379067
#define N64_INV_PIf 0.318309886f
#define N64_INV_SQRTPI 0.56418958354775629
#define N64_INV_SQRTPIf 0.564189584f
#define N64_LN2 0.69314718055994531
#define N64_LN2f 0.693147181f
#define N64_LN10 2.3025850929940457
#define N64_LN10f 2.30258509f
#define N64_SQRT2 1.414213562373095
#define N64_SQRT2f 1.41421356f
#define N64_SQRT3 1.7320508075688773
#define N64_SQRT3f 1.73205081f
#define N64_INV_SQRT3 0.57735026918962576
#define N64_INV_SQRT3f 0.577350269f
#define N64_EGAMMA 0.57721566490153286
#define N64_EGAMMAf 0.577215665f
#define N64_PHI 1.6180339887498948
#define N64_PHIf 1.61803399f
#endif

View File

@@ -0,0 +1,34 @@
#ifndef N64_STDLIB_N64_STDBOOL_H_
#define N64_STDLIB_N64_STDBOOL_H_
#ifdef __cplusplus
typedef bool n64_bool;
#else
#if __STDC_VERSION__ >= 202311L
typedef bool n64_bool;
#else
#if __STDC_VERSION__ >= 199901L
typedef _Bool n64_bool;
#elif __GNUC__ >= 15
typedef unsigned char __attribute__((hardbool(0, 1))) n64_bool;
#else
typedef unsigned char n64_bool;
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif
#endif
#ifndef __bool_true_false_are_defined
#define __bool_true_false_are_defined 1
#endif
#endif

View File

@@ -0,0 +1,8 @@
#ifndef N64_STDLIB_N64_STDCKDINT_H_
#define N64_STDLIB_N64_STDCKDINT_H_
#define n64_ckd_add( result, a, b ) __builtin_add_overflow( a, b, result )
#define n64_ckd_sub( result, a, b ) __builtin_sub_overflow( a, b, result )
#define n64_ckd_mul( result, a, b ) __builtin_mul_overflow( a, b, result )
#endif

15
lib/n64-libc/n64-stddef.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef NULL
#ifdef __cplusplus
#if __cplusplus >= 199711L
#define NULL nullptr
#else
#define NULL 0
#endif
#else
#if __STDC_VERSION__ >= 202311L
#define NULL nullptr
#else
#define NULL ((void*)0)
#endif
#endif
#endif

View File

@@ -0,0 +1,432 @@
#include "n64-stddef.h"
#include "n64-stdio-format.c.inc"
typedef enum {
CSI_ALIGNMENT,
CSI_SIGN,
CSI_SPACE,
CSI_ALTERNATE,
CSI_ZEROPAD,
CSI_WIDTH,
CSI_PRECISION,
CSI_LENGTH,
CSI_FORMAT
} n64_csi;
#define PCS_VARIABLE 0xAAAAAAAAu
#define PCS_DEFAULT 0xBBBBBBBBu
static const char *parse_conversion_specifier( const char *format, n64_format_args *args ) {
n64_bool isLong = false;
args->width = 0u;
args->dataSize = 4u;
args->precision = PCS_DEFAULT;
args->defaultPrecision = 1u;
args->leftAligned = false;
args->alternate = false;
args->capitalize = false;
args->padchar = ' ';
args->poschar = '\0';
n64_csi csi = CSI_ALIGNMENT;
while( *format != '\0' ) {
switch( csi ) {
case CSI_ALIGNMENT:
if( *format == '-' ) {
args->leftAligned = true;
format++;
}
csi = CSI_SIGN;
__attribute__((fallthrough));
case CSI_SIGN:
if( *format == '+' ) {
args->poschar = '+';
format++;
}
csi = CSI_SPACE;
__attribute__((fallthrough));
case CSI_SPACE:
if( *format == ' ' ) {
if( args->poschar != '+' ) args->poschar = ' ';
format++;
}
csi = CSI_ALTERNATE;
__attribute__((fallthrough));
case CSI_ALTERNATE:
if( *format == '#' ) {
args->alternate = true;
format++;
}
csi = CSI_ZEROPAD;
__attribute__((fallthrough));
case CSI_ZEROPAD:
if( *format == '0' ) {
args->padchar = '0';
format++;
}
csi = CSI_WIDTH;
__attribute__((fallthrough));
case CSI_WIDTH:
if( *format == '-' ) {
args->leftAligned = true;
format++;
continue;
} else if( *format == '0' ) {
format++;
continue;
} else if( *format == '*' ) {
args->width = PCS_VARIABLE;
format++;
} else if( *format > '0' && *format <= '9' ) {
int w = 0;
while( *format >= '0' && *format <= '9' ) {
w *= 10;
if( w < 0 ) return NULL;
w += (int)*format - (int)'0';
format++;
}
args->width = (unsigned int)w;
}
csi = CSI_PRECISION;
__attribute__((fallthrough));
case CSI_PRECISION:
if( *format == '.' ) {
format++;
if( *format == '-' ) {
format++;
while( *format >= '0' && *format <= '9' ) format++;
} else if( *format == '*' ) {
args->precision = PCS_VARIABLE;
format++;
} else if( *format >= '0' && *format <= '9' ) {
int p = 0;
while( *format >= '0' && *format <= '9' ) {
p *= 10;
if( p < 0 ) return NULL;
p += (int)*format - (int)'0';
format++;
}
args->precision = (unsigned int)p;
} else {
return NULL;
}
}
csi = CSI_LENGTH;
__attribute__((fallthrough));
case CSI_LENGTH:
switch( *format ) {
case 'h':
format++;
if( *format == 'h' ) {
args->dataSize = 1u;
format++;
} else {
args->dataSize = 2u;
}
break;
case 'l':
isLong = true;
args->dataSize = __SIZEOF_LONG__;
format++;
if( *format == 'l' ) {
args->dataSize = 8u;
format++;
}
break;
case 'j':
case 'L':
isLong = true;
args->dataSize = 8u;
format++;
break;
case 'z':
args->dataSize = __SIZEOF_SIZE_T__;
format++;
break;
case 't':
args->dataSize = __SIZEOF_PTRDIFF_T__;
format++;
break;
default:
break;
}
csi = CSI_FORMAT;
__attribute__((fallthrough));
case CSI_FORMAT:
switch( *format ) {
case 'c':
args->type = 'c';
args->dataSize = 1;
break;
case 's':
args->type = 's';
args->dataSize = 1;
args->defaultPrecision = 0xFFFFFFFFu;
break;
case 'd':
case 'i':
args->type = 'd';
if( args->precision != PCS_DEFAULT ) args->padchar = ' ';
break;
case 'o':
args->type = 'o';
args->poschar = '\0';
if( args->precision != PCS_DEFAULT ) args->padchar = ' ';
break;
case 'X':
args->capitalize = true;
__attribute__((fallthrough));
case 'x':
args->type = 'x';
args->poschar = '\0';
if( args->precision != PCS_DEFAULT ) args->padchar = ' ';
break;
case 'B':
args->capitalize = true;
__attribute__((fallthrough));
case 'b':
args->type = 'b';
args->poschar = '\0';
if( args->precision != PCS_DEFAULT ) args->padchar = ' ';
break;
case 'u':
args->type = 'u';
args->poschar = '\0';
if( args->precision != PCS_DEFAULT ) args->padchar = ' ';
break;
case 'F':
args->capitalize = true;
__attribute__((fallthrough));
case 'f':
args->type = 'f';
args->dataSize = isLong ? 8u : 4u;
args->defaultPrecision = 6u;
break;
case 'E':
args->capitalize = true;
__attribute__((fallthrough));
case 'e':
args->type = 'e';
args->dataSize = isLong ? 8u : 4u;
args->defaultPrecision = 6u;
break;
case 'A':
args->capitalize = true;
__attribute__((fallthrough));
case 'a':
args->type = 'a';
args->dataSize = isLong ? 8u : 4u;
args->defaultPrecision = 0xffffffffu;
break;
case 'G':
args->capitalize = true;
__attribute__((fallthrough));
case 'g':
args->type = 'g';
args->dataSize = isLong ? 8u : 4u;
args->defaultPrecision = 6u;
break;
case 'n':
args->type = 'n';
break;
case 'p':
args->type = 'p';
args->dataSize = 4u;
break;
default:
return NULL;
}
return ++format;
default:
return NULL;
}
}
return NULL;
}
int n64_vbprintf( char *_buffer, unsigned int bufsz, n64_bool(*callback)(void*, unsigned int), void *state, const char *format, __builtin_va_list args ) {
n64_bprint_buffer buff = {
/* start */ _buffer,
/* head */ _buffer,
/* end */ _buffer + bufsz,
callback,
state,
0u
};
while( *format != '\0' ) {
if( *format != '%' ) {
n64_putc( &buff, *format );
format++;
continue;
}
if( format[1] == '%' ) {
n64_putc( &buff, '%' );
format += 2;
continue;
}
n64_format_args fmt;
format = parse_conversion_specifier( ++format, &fmt );
if( !format ) return -1;
if( fmt.width == PCS_VARIABLE ) {
const int w = __builtin_va_arg( args, int );
if( w < 0 ) {
fmt.leftAligned = true;
fmt.width = (unsigned int)-w;
} else {
fmt.width = (unsigned int)w;
}
}
if( fmt.precision == PCS_VARIABLE ) {
const int p = __builtin_va_arg( args, int );
fmt.precision = (p < 0) ? fmt.defaultPrecision : (unsigned int)p;
} else if( fmt.precision == PCS_DEFAULT ) {
fmt.precision = fmt.defaultPrecision;
}
switch( fmt.type ) {
case 'c': {
const char c = (char)__builtin_va_arg( args, int );
n64_format_char( &buff, &fmt, c );
break;
}
case 's': {
const char *str = (const char*)__builtin_va_arg( args, const char* );
n64_format_string( &buff, &fmt, str );
break;
}
case 'd': {
if( fmt.dataSize == 8 ) {
const long long val = __builtin_va_arg( args, long long );
n64_format_sdec64( &buff, &fmt, val );
} else {
int val = __builtin_va_arg( args, int );
if( fmt.dataSize == 2 ) {
val = (int)(short)val;
} else if( fmt.dataSize == 1 ) {
val = (int)(signed char)val;
}
n64_format_sdec32( &buff, &fmt, val );
}
break;
}
case 'u': {
if( fmt.dataSize == 8 ) {
const unsigned long long val = __builtin_va_arg( args, unsigned long long );
n64_format_udec64( &buff, &fmt, val );
} else {
unsigned int val = __builtin_va_arg( args, unsigned int );
if( fmt.dataSize == 2 ) {
val &= 0xFFFFu;
} else if( fmt.dataSize == 1 ) {
val &= 0xFFu;
}
n64_format_udec32( &buff, &fmt, val );
}
break;
}
case 'o': {
if( fmt.dataSize == 8 ) {
const unsigned long long val = __builtin_va_arg( args, unsigned long long );
n64_format_oct64( &buff, &fmt, val );
} else {
unsigned int val = __builtin_va_arg( args, unsigned int );
if( fmt.dataSize == 2 ) {
val &= 0xFFFFu;
} else if( fmt.dataSize == 1 ) {
val &= 0xFFu;
}
n64_format_oct32( &buff, &fmt, val );
}
break;
}
case 'x': {
if( fmt.dataSize == 8 ) {
const unsigned long long val = __builtin_va_arg( args, unsigned long long );
n64_format_hex64( &buff, &fmt, val );
} else {
unsigned int val = __builtin_va_arg( args, unsigned int );
if( fmt.dataSize == 2 ) {
val &= 0xFFFFu;
} else if( fmt.dataSize == 1 ) {
val &= 0xFFu;
}
n64_format_hex32( &buff, &fmt, val );
}
break;
}
case 'b': {
if( fmt.dataSize == 8 ) {
const unsigned long long val = __builtin_va_arg( args, unsigned long long );
n64_format_bin64( &buff, &fmt, val );
} else {
unsigned int val = __builtin_va_arg( args, unsigned int );
if( fmt.dataSize == 2 ) {
val &= 0xFFFFu;
} else if( fmt.dataSize == 1 ) {
val &= 0xFFu;
}
n64_format_bin32( &buff, &fmt, val );
}
break;
}
case 'f':
case 'e':
case 'g': {
const double val = __builtin_va_arg( args, double );
if( fmt.dataSize == 8 ) {
n64_format_double( &buff, &fmt, val );
} else {
n64_format_float( &buff, &fmt, (float)val );
}
break;
}
case 'a': {
const double val = __builtin_va_arg( args, double );
if( fmt.dataSize == 8 ) {
n64_format_hexdouble( &buff, &fmt, val );
} else {
n64_format_hexfloat( &buff, &fmt, (float)val );
}
break;
}
case 'p': {
const void *ptr = __builtin_va_arg( args, const void* );
n64_format_pointer( &buff, &fmt, ptr );
break;
}
case 'n': {
switch( fmt.dataSize ) {
case 1: *__builtin_va_arg( args, signed char* ) = (signed char)buff.total; break;
case 2: *__builtin_va_arg( args, short* ) = (short)buff.total; break;
case 4: *__builtin_va_arg( args, int* ) = (int)buff.total; break;
case 8: *__builtin_va_arg( args, long long* ) = (long long)buff.total; break;
default: return -1;
}
break;
}
default:
return -1;
}
}
if( buff.start != buff.end ) {
buff.callback( buff.userdata, (unsigned int)(buff.head - buff.start) );
}
return (int)buff.total;
}
int n64_bprintf( char *buffer, unsigned int bufsz, n64_bool(*callback)(void*, unsigned int), void *state, const char *format, ... ) {
__builtin_va_list args;
__builtin_va_start( args, format );
register const int result = n64_vbprintf( buffer, bufsz, callback, state, format, args );
__builtin_va_end( args );
return result;
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More