summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
-rw-r--r--BUGS5
-rw-r--r--Changelog268
-rw-r--r--Makefile73
-rw-r--r--Makefile.cfg90
-rw-r--r--cxx/Makefile19
-rwxr-xr-xcxx/new.cc29
-rw-r--r--cxx/virtual.cc11
-rw-r--r--doxygen.conf1808
-rw-r--r--examples/Makefile25
-rw-r--r--examples/gtecube/Makefile8
-rw-r--r--examples/gtecube/gtecube.c448
-rw-r--r--examples/mandel/Makefile7
-rw-r--r--examples/mandel/mandel.c347
-rw-r--r--examples/memview/Makefile7
-rw-r--r--examples/memview/memview.c249
-rw-r--r--examples/memview/memview.txt70
-rw-r--r--examples/project.mk18
-rw-r--r--examples/psxmod/Makefile16
-rw-r--r--examples/psxmod/psxmod.c472
-rw-r--r--examples/psxpaint/Makefile7
-rw-r--r--examples/psxpaint/cursor.h20
-rw-r--r--examples/psxpaint/psxpaint.c371
-rw-r--r--examples/psxs3m/Makefile10
-rw-r--r--examples/psxs3m/mods/mario2_2.s3mbin0 -> 17808 bytes
-rw-r--r--examples/psxs3m/mods/mario3.s3mbin0 -> 9920 bytes
-rw-r--r--examples/psxs3m/psxs3m.c412
-rw-r--r--examples/psxsnake/Makefile12
-rw-r--r--examples/psxsnake/data/Makefile21
-rw-r--r--examples/psxsnake/data/apple.txt14
-rw-r--r--examples/psxsnake/data/apple.wavbin0 -> 57204 bytes
-rw-r--r--examples/psxsnake/data/backgrnd.bmpbin0 -> 230454 bytes
-rw-r--r--examples/psxsnake/data/bomb.wavbin0 -> 43436 bytes
-rw-r--r--examples/psxsnake/data/font.bmpbin0 -> 830 bytes
-rw-r--r--examples/psxsnake/data/music.wavbin0 -> 376798 bytes
-rw-r--r--examples/psxsnake/psxsnake.c666
-rw-r--r--examples/puzzle/Makefile9
-rw-r--r--examples/puzzle/puzzle.bmpbin0 -> 150582 bytes
-rw-r--r--examples/puzzle/puzzle.c216
-rw-r--r--examples/rottest/Makefile9
-rw-r--r--examples/rottest/image.bmpbin0 -> 32694 bytes
-rw-r--r--examples/rottest/rottest.c104
-rw-r--r--libadpcm/Makefile26
-rw-r--r--libadpcm/adpcm.c251
-rw-r--r--libadpcm/adpcm.h13
-rw-r--r--libf3m/Makefile20
-rwxr-xr-xlibf3m/f3m.c1068
-rw-r--r--libf3m/f3m.h172
-rwxr-xr-xlibfixmath/Makefile50
-rwxr-xr-xlibfixmath/fix16.c484
-rwxr-xr-xlibfixmath/fix16_exp.c48
-rwxr-xr-xlibfixmath/fix16_sqrt.c83
-rwxr-xr-xlibfixmath/fix16_trig.c171
-rwxr-xr-xlibfixmath/fixmath.h23
-rwxr-xr-xlibfixmath/fixmath/fix16.h167
-rwxr-xr-xlibfixmath/fixmath/fract32.h38
-rwxr-xr-xlibfixmath/fixmath/int64.h162
-rwxr-xr-xlibfixmath/fixmath/uint32.h19
-rwxr-xr-xlibfixmath/fract32.c27
-rwxr-xr-xlibfixmath/uint32.c15
-rw-r--r--libhuff/Makefile23
-rw-r--r--libhuff/huff.c119
-rw-r--r--libhuff/huff.h19
-rw-r--r--libm/Makefile116
-rw-r--r--libm/README261
-rw-r--r--libm/e_acos.c105
-rw-r--r--libm/e_acosh.c65
-rw-r--r--libm/e_asin.c115
-rw-r--r--libm/e_atan2.c123
-rw-r--r--libm/e_atanh.c68
-rw-r--r--libm/e_cosh.c89
-rw-r--r--libm/e_exp.c156
-rw-r--r--libm/e_fmod.c140
-rw-r--r--libm/e_gamma.c33
-rw-r--r--libm/e_gamma_r.c32
-rw-r--r--libm/e_hypot.c115
-rw-r--r--libm/e_j0.c478
-rw-r--r--libm/e_j1.c477
-rw-r--r--libm/e_jn.c272
-rw-r--r--libm/e_lgamma.c33
-rw-r--r--libm/e_lgamma_r.c304
-rw-r--r--libm/e_log.c145
-rw-r--r--libm/e_log10.c91
-rw-r--r--libm/e_pow.c309
-rw-r--r--libm/e_rem_pio2.c175
-rw-r--r--libm/e_remainder.c77
-rw-r--r--libm/e_scalb.c51
-rw-r--r--libm/e_sinh.c82
-rw-r--r--libm/e_sqrt.c450
-rw-r--r--libm/float_wrapper.c90
-rw-r--r--libm/k_cos.c92
-rw-r--r--libm/k_rem_pio2.c319
-rw-r--r--libm/k_sin.c74
-rw-r--r--libm/k_standard.c740
-rw-r--r--libm/k_tan.c148
-rw-r--r--libm/math.h319
-rw-r--r--libm/s_asinh.c61
-rw-r--r--libm/s_atan.c134
-rw-r--r--libm/s_cbrt.c87
-rw-r--r--libm/s_ceil.c78
-rw-r--r--libm/s_copysign.c31
-rw-r--r--libm/s_cos.c78
-rw-r--r--libm/s_erf.c310
-rw-r--r--libm/s_expm1.c217
-rw-r--r--libm/s_fabs.c29
-rw-r--r--libm/s_finite.c31
-rw-r--r--libm/s_floor.c79
-rw-r--r--libm/s_frexp.c56
-rw-r--r--libm/s_ilogb.c46
-rw-r--r--libm/s_isnan.c34
-rw-r--r--libm/s_ldexp.c28
-rw-r--r--libm/s_lib_version.c35
-rw-r--r--libm/s_log1p.c169
-rw-r--r--libm/s_logb.c38
-rw-r--r--libm/s_matherr.c26
-rw-r--r--libm/s_modf.c80
-rw-r--r--libm/s_nextafter.c78
-rw-r--r--libm/s_rint.c84
-rw-r--r--libm/s_scalbn.c66
-rw-r--r--libm/s_signgam.c2
-rw-r--r--libm/s_significand.c30
-rw-r--r--libm/s_sin.c78
-rw-r--r--libm/s_tan.c72
-rw-r--r--libm/s_tanh.c82
-rw-r--r--libm/w_acos.c39
-rw-r--r--libm/w_acosh.c39
-rw-r--r--libm/w_asin.c41
-rw-r--r--libm/w_atan2.c40
-rw-r--r--libm/w_atanh.c42
-rw-r--r--libm/w_cosh.c38
-rw-r--r--libm/w_exp.c52
-rw-r--r--libm/w_fmod.c39
-rw-r--r--libm/w_gamma.c46
-rw-r--r--libm/w_gamma_r.c42
-rw-r--r--libm/w_hypot.c39
-rw-r--r--libm/w_j0.c65
-rw-r--r--libm/w_j1.c66
-rw-r--r--libm/w_jn.c88
-rw-r--r--libm/w_lgamma.c46
-rw-r--r--libm/w_lgamma_r.c42
-rw-r--r--libm/w_log.c39
-rw-r--r--libm/w_log10.c42
-rw-r--r--libm/w_pow.c60
-rw-r--r--libm/w_remainder.c38
-rw-r--r--libm/w_scalb.c56
-rw-r--r--libm/w_sinh.c38
-rw-r--r--libm/w_sqrt.c38
-rw-r--r--libm/wrappers.c90
-rw-r--r--libmeidogte/Makefile26
-rw-r--r--libmeidogte/applymatrixlv.s40
-rw-r--r--libmeidogte/compmatrixlv.s100
-rw-r--r--libmeidogte/gtereg.h80
-rw-r--r--libmeidogte/hirotmatrix.c35
-rw-r--r--libmeidogte/hisin.c33
-rw-r--r--libmeidogte/initgeom.s45
-rw-r--r--libmeidogte/inline_s.h227
-rw-r--r--libmeidogte/isin.c34
-rw-r--r--libmeidogte/matrix.c45
-rw-r--r--libmeidogte/meidogte.h170
-rw-r--r--libmeidogte/meidogte_inline.h433
-rw-r--r--libmeidogte/mulmatrix.s74
-rw-r--r--libmeidogte/mulmatrix0.s74
-rw-r--r--libmeidogte/pushpopmatrix.s68
-rw-r--r--libmeidogte/scalematrix.s68
-rw-r--r--libmeidogte/square0.s27
-rw-r--r--libmeidogte/squareroot.s121
-rw-r--r--libmeidogte/vectornormals.s107
-rw-r--r--libmodplay/Makefile38
-rw-r--r--libmodplay/mod.c328
-rw-r--r--libmodplay/modplay.c290
-rw-r--r--libmodplay/modplay.h222
-rw-r--r--libmodplay/modplay_int.h20
-rw-r--r--libmodplay/modtbl.h62
-rw-r--r--libpsx/Makefile49
-rw-r--r--libpsx/include/bitstring.h78
-rw-r--r--libpsx/include/ctype.h25
-rw-r--r--libpsx/include/errno.h167
-rw-r--r--libpsx/include/fcntl.h72
-rw-r--r--libpsx/include/inttypes.h68
-rw-r--r--libpsx/include/memcard.h74
-rw-r--r--libpsx/include/psx.h406
-rw-r--r--libpsx/include/psxbios.h215
-rw-r--r--libpsx/include/psxcdrom.h82
-rw-r--r--libpsx/include/psxgpu.h1142
-rw-r--r--libpsx/include/psxgte.h196
-rw-r--r--libpsx/include/psxpad.h178
-rw-r--r--libpsx/include/psxsio.h121
-rw-r--r--libpsx/include/psxspu.h225
-rw-r--r--libpsx/include/psxutil.h20
-rw-r--r--libpsx/include/runexe.h17
-rw-r--r--libpsx/include/search.h14
-rw-r--r--libpsx/include/stdint.h14
-rw-r--r--libpsx/include/stdio.h170
-rw-r--r--libpsx/include/stdlib.h66
-rw-r--r--libpsx/include/string.h64
-rw-r--r--libpsx/include/strings.h37
-rw-r--r--libpsx/include/sys/stat.h19
-rw-r--r--libpsx/include/sys/types.h11
-rw-r--r--libpsx/include/types.h10
-rw-r--r--libpsx/include/unistd.h22
-rw-r--r--libpsx/src/atexit.c23
-rw-r--r--libpsx/src/cdrom.c240
-rw-r--r--libpsx/src/cdromh.s109
-rw-r--r--libpsx/src/cop.c111
-rw-r--r--libpsx/src/costbl.h26
-rw-r--r--libpsx/src/exc1.s96
-rw-r--r--libpsx/src/exception.c178
-rw-r--r--libpsx/src/exception.h14
-rw-r--r--libpsx/src/font.h266
-rw-r--r--libpsx/src/gpu.c1507
-rw-r--r--libpsx/src/libc.c705
-rw-r--r--libpsx/src/libc/error.c19
-rw-r--r--libpsx/src/libc/misc.c106
-rw-r--r--libpsx/src/libc/printf.c899
-rw-r--r--libpsx/src/libc/qsort.c65
-rw-r--r--libpsx/src/libc/scanf.c425
-rw-r--r--libpsx/src/libc/stat.c31
-rw-r--r--libpsx/src/libc/string.c706
-rw-r--r--libpsx/src/libc/strings.c41
-rw-r--r--libpsx/src/libc/unistd.c17
-rw-r--r--libpsx/src/memcard.c87
-rw-r--r--libpsx/src/memory.c215
-rw-r--r--libpsx/src/memory.h6
-rw-r--r--libpsx/src/pad.c163
-rw-r--r--libpsx/src/psxsdk.c542
-rw-r--r--libpsx/src/runexe/runexe.c76
-rw-r--r--libpsx/src/runexe/stage2.s40
-rw-r--r--libpsx/src/setup.c50
-rw-r--r--libpsx/src/sio.c64
-rw-r--r--libpsx/src/spu.c269
-rwxr-xr-xlibpsx/src/start/start.s322
-rw-r--r--libpsx/src/syscalls.s344
-rw-r--r--libpsx/src/util.c42
-rw-r--r--license.txt40
-rw-r--r--licenses/Makefile7
-rw-r--r--licenses/infoeur.datbin0 -> 37632 bytes
-rw-r--r--licenses/infojap.datbin0 -> 37632 bytes
-rw-r--r--licenses/infousa.datbin0 -> 37632 bytes
-rw-r--r--misc/Makefile16
-rwxr-xr-xmisc/genscripts.sh82
-rw-r--r--modplay.txt42
-rw-r--r--nobios.txt7
-rw-r--r--readme.txt287
-rw-r--r--realhw.txt136
-rw-r--r--repair.txt26
-rw-r--r--toolchain.txt64
-rw-r--r--tools/Makefile77
-rw-r--r--tools/adpcm.c259
-rw-r--r--tools/adpcm.h14
-rw-r--r--tools/bin2c.c30
-rwxr-xr-xtools/bmp2tim.c895
-rw-r--r--tools/cdcat.c373
-rwxr-xr-xtools/elf2exe.c231
-rw-r--r--tools/endian.c52
-rw-r--r--tools/exefixup.c204
-rw-r--r--tools/getpsxiso.c55
-rw-r--r--tools/huff.c555
-rw-r--r--tools/lictool.c100
-rw-r--r--tools/mkpsxiso.c250
-rw-r--r--tools/mod4psx.c164
-rw-r--r--tools/psfex.c113
-rw-r--r--tools/spasm/Makefile17
-rw-r--r--tools/spasm/codegen.c144
-rw-r--r--tools/spasm/codegen.h33
-rw-r--r--tools/spasm/error.c58
-rw-r--r--tools/spasm/error.h10
-rw-r--r--tools/spasm/eval.c130
-rw-r--r--tools/spasm/eval.h6
-rwxr-xr-xtools/spasm/fcaseopen.c137
-rwxr-xr-xtools/spasm/fcaseopen.h40
-rw-r--r--tools/spasm/opcode.c2214
-rw-r--r--tools/spasm/opcode.h108
-rw-r--r--tools/spasm/parser.c478
-rw-r--r--tools/spasm/parser.h29
-rw-r--r--tools/spasm/readme.txt120
-rw-r--r--tools/spasm/spasm.c167
-rw-r--r--tools/spasm/spasm.h20
-rw-r--r--tools/systemcnf.c50
-rw-r--r--tools/tim2bmp.c390
-rwxr-xr-xtools/vag2wav.c202
-rw-r--r--tools/wav2vag.c431
280 files changed, 41283 insertions, 0 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..a4528c7
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,5 @@
+- Root counter handling doesn't currently work in No-Bios mode.
+- SetRCntHandler() and RemoveRCntHandler() can set and manage only a single root counter,
+ despite the function prototypes indicating otherwise.
+
+ \ No newline at end of file
diff --git a/Changelog b/Changelog
new file mode 100644
index 0000000..a7a08dd
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,268 @@
+2019-04-10 (0.6.2):
+- Included GTE library by LameGuy64/Meido-Tek as 'libmeidogte'
+- New example: gtecube. Demonstrates libmeidogte
+- The 'rottest' and 'puzzle' examples always set a PAL video mode regardless of the setting in Makefile.cfg
+ Fixed.
+- Removed unused macro code from spasm
+
+2018-01-15 (0.6.1) :
+- Fixed bug where LO and HI registers were not saved and restored by the NoBIOS exception handler
+- Some definitions (like the ones for the interrupt controller and the GPU) moved out of
+library source code to public headers, so they are available to all applications that may need them
+- Fixes in pad.c so that compiler optimizations do not generate code with bad behavior
+- Fixed crash when using a GCC 7.x+ compiler when calling static constructors during initialization.
+- Static constructors are now called in backwards order. (as they are on most systems)
+- Fixed bug where the __ctor_list symbol wouldn't have the address of the constructor list,
+but would have its address offset unpredictably (leading to the crash mentioned above).
+- Integrated upstream changes from F3M in libf3m
+- Removed all references to Composer 669 music format in the sources and
+ documentation of libmodplay, as support for the format was never
+ implemented.
+- Added psxs3m example. Mostly the same as psxmod but using libf3m
+instead of libmodplay
+- Fixed some issues in the psxmod example.
+
+2016-06-03 (0.6):
+- size_t and ssize_t definitions moved from stdio.h to types.h, and types.h is included automatically by stdio.h
+- Added strcoll() - as a wrapper to strcmp()
+- File device enum is now public and moved to stdio.h
+ It was incorrectly private and in libpsx/src/libc.c before
+- fopen(): path argument is now const char*
+- rename() and remove(): both arguments are now const char*
+- open(): filename argument is now const char*
+- get_real_file_size() and get_file_size(): argument is now const char*
+- firstfile(): name argument is now const char*
+- Added stdin, stdout and stderr FILE structures
+- Implemented fwrite(). Only works with stdout and stderr
+- Implemented fputs(). Only works with stdout and stderr
+- Implemented freopen()
+- Implemented clearerr(), feof(), ferror() and fileno()
+- Implemented placeholders for strerror() and strerror_r()
+- Added libf3m, to playback S3M module files, adapted to PSXSDK from GreaseMonkey's F3M
+- libm/k_rem_pio2.c: fixed misleading indentation at line 188.
+ libm/e_asin.c: fixed misleading indentation at line 89.
+ libm/w_exp.c: o_threshold and u_threshold variables only defined when
+ _IEEE_LIBM is not defined
+ Fixed warnings with GCC 6.1.0
+- Compilation warnings fixed for some tools, and some cleanup in spasm/parser.c
+- Fixed warnings with psxgte.h - specifier was put after and not before enumeration
+- Fixed warnings in the examples
+
+2015-07-29 (0.5.99):
+- Added PSX_WarmReboot()
+- Fixed extern directive for GsCurDrawEnvH: was wrongly specified for GsCurDrawEnvY
+- NORMAL_LUMINOSITY is now an alias for NORMAL_LUMINANCE: "luminosity" is an incorrect term for the meaning
+- Added PRFONT_RL(f), PRFONT_GL(f), RLFONT_BL(f) attributes to GsSetFontAttrib(). These allow to adjust the luminance factor for the color components used when drawing the font: in few words, when used correctly, the attributes can be used to change the color of the font on the fly, without using another color look-up table.
+- Added set_cop_register(), get_cop_register() and run_cop_instruction().
+ set_cop0_register() and get_cop0_register() are now aliases for set_cop_register() and
+ get_cop_register() respectively.
+- Added set_cop_ctrl_register() and get_cop_ctrl_register()
+- Fixed some bugs in the Makefiles, thanks to rsoft and Missingno_force for providing patches
+- Fixed a bug in bmp2tim where 4-bit images with a width not a multiply of 4, or 8-bit images with a width
+ not a multiply of 8 were erronously generated and thus contained invalid data.
+ It should not have been possible to generate such images in the first place.
+- Fixed a bug in bmp2tim where unnecessary debug messages were printed on screen when converting an image.
+- The path for objcopy hardcoded inside elf2exe is now taken from the OBJCOPY variable specified in Makefile.cfg,
+ and not from the OBJCOPY_PATH define in the source code itself
+- Added -fno-strict-overflow flag by default to Makefile.cfg and to the psx-gcc and psx-g++ scripts
+- Multiplication registers HI and LO are now saved and restored by the vblank and root counter handlers -
+ this could give problems if any division or multiplication instruction was used inside a handler.
+ Fortunately no such instructions are used inside handlers most times.
+- Greatly improved nv-SPASM - now it should be fully compatible (maybe save some quirks)
+ with the Hitmen assembler
+- Added GsVPrintFont()
+
+2014-04-22 (0.4.99):
+- Fixed the Makefile for the tools, now it considers the HOST_* variables and removes executables
+ correctly under Windows
+- added --enable-languages=c to the command line to build GCC, in toolchain.txt
+- Added abort() to libc
+- Fixed Makefile for misc directory
+- Fixed genscript.sh: generated link script playstation.x now correctly
+ includes libgcc and does not rely on EXTERN directives
+- New SsUpload() implementation contributed by Shendo, which contains workarounds for emulators.
+ Also works on ePSXe.
+- Fixed wrong return value for McWriteSector()
+- Introduced debug build, that can be built by specifying the PSXSDK_DEBUG
+ flag at compile time - it has more verbose messages, diagnostics, etc.
+- Very verbose messages are now only compiled in for the debug builds.
+- Added support for the 1KB scratchpad, which is the data cache that went
+ unused in the PlayStation - it acts as a kind of "fast RAM";
+ it is accessible as the byte array __scratchpad
+- Added RemoveRCntHandler()
+- Removed the InitCARD() - StartCARD() - StopCARD() sequence in PSXSDK_Init() when using BIOS mode,
+ so that the vblank handler would not crash - the fix was acknowledging the interrupt in psxsdk's internal handler
+ (in start/start.s). Thanks to Shendo for reporting this.
+- The shell to use when executing scripts can now be specified in Makefile.cfg by changing the HOST_SHELL variable
+- Moved the prototypes for index(), rindex(), strcasecmp() and strncasecmp()
+ from string.h to strings.h, to be more standard
+- Implemented the ffs*() and the popcount*() family of functions
+ (the prototypes are in string.h or strings.h)
+- string.h now includes strings.h for backward compatibility - advice: do not rely on this.
+ when you use something whose prototype is in strings.h, ALSO include strings.h!
+- implemented bitstring.h, bit string manipulation macros
+- implemented memccpy()
+- index() and rindex() were wrongly implemented both in libpsx/src/libc/string.c and as
+ macros in strings.h; now they are only implemented as macros in strings.h
+- added swab()
+- added defines for EXIT_SUCCESS and EXIT_FAILURE in stdlib.h
+- __PSXSDK__ is now defined by psx-gcc, this makes easier for code
+ to detect it is being compiled for the PSXSDK
+- added defines for O_RDLOCK, O_WRLOCK, O_SCAN, O_RCOM, O_EXCL, O_ASYNC, O_NOWAIT
+ and O_NOBUF, and corrected define for O_APPEND (it is now correctly 256, not 8) in fcntl.h
+- Added a very simple implementation of stat().
+ Only the st_size, st_blksize and st_blocks fields are available in struct stat (sys/stat.h)
+- Added exit() and atexit() (stdlib.h)
+- Added vprintf()
+- Added GsSetListEx()
+- Added C++ support. Thanks to Mauro Persano (fzort) for contributing this the initialization code.
+- Fixed linked list corruption bug in GSTPoly3()
+- Added GsPolyLine() and GsGPolyLine() to draw non-graduated and graduated poly lines.
+- Added GsGTPoly3() and GsGTPoly4() to draw graduated (shaded) textured 3-point and 4-point polygons
+- Added nv-SPASM to PSXSDK, a free and open source implementation of the Hitmen's spASM assembler, written by nextvolume.
+ It will be installed as `spasm'.
+
+2013-11-09 (0.3.99):
+- Added GsRotateVector(). It is a wrapper to internal libpsx functions.
+- Added prototype to nextfile() in psxbios.h, it was missing.
+- Added documentation for SetVBlankHandler(), it was missing.
+- Fixed bug in modplay where instruments with an empty sample were played
+ with the sample of the immediately next instrument; now they are not
+ played at all, which is the correct behaviour.
+- libmodplay and its tools now ignore "useless" samples (less than 32 bytes)
+ when loading MOD files.
+- Added Doxygen documentation for libmodplay.
+- Removed division by zero bug in the MOD playing code in libmodplay.
+ Fixes crashing on real hardware.
+- libmodplay now supports only MOD files, as the old saying goes
+ "do one thing and do it well".
+- Implemented ctype completely in the libc. The is*() family of functions was
+ notably missing.
+- Implemented atoi() and atol() in the libc.
+- Fixed the issue of strtol() returning 0 for strings beginning with whitespace.
+- Added PRFONT_UNIXLF attribute to built-in font rendering functions.
+ With PRFONT_UNIXLF, the writing goes to the new line and *also* to the beginning of the new line.
+ When not using PRFONT_UNIXLF, the '\r\n' sequence has the same effect as '\n' when using PRFONT_UNIXLF.
+- Carriage return was ignored by GsPrintFont(). This is now fixed.
+- Fixed bad code in libc/string.c
+- Added strcasestr(), stpcpy(), stpncpy(), strnlen(), memrchr() to libc
+- Added and adapted serial port library by Shendo.
+- Added and adapted new pad reading code and memory card code by Shendo.
+ The memory card filesystem is not yet implemented! You can only use raw sector reads and writes for now.
+- libadpcm is now at least eight times faster. There were some implicit floating point operations left which have been removed.
+- SsAdpcmPack() now supports non-ending and non-looping samples, useful to generate sound data at runtime.
+- Added experimental "NoBIOS" mode, where no BIOS calls and exception handlers are used.
+ It is accessed by passing the PSX_INIT_NOBIOS flag to PSX_InitEx(). Support for many things is missing or doesn't work as well
+ as the "BIOS" mode.
+- [REALLY IMPORTANT]
+ The compiling and installation phases are now separate; i.e. to build and install the new SDK libraries and tools,
+ use "make" then "make install", instead of just "make" like it used to be.
+- Added support for 'j', 't', 'z', 'q' length identifiers to vsnprintf()
+- vsnprintf() now honors the space flag.
+- [vsnprintf()]
+ The behavior when handling an unknown character in the format after '%' is now correct,
+ i.e. the character is added to the output string, and the format specification is escaped.
+ The previous, incorrect behavior was ignoring the character and staying in format
+ specification until the character for a known type was found.
+- Added missing prototypes for strdup() and strndup() to string.h
+- Now string functions use size_t instead of int for lengths and counts
+- Added memmem(), lltoa(), ltoa(), itoa(), ulltoa(), ultoa() and utoa() to libc
+
+2013-05-14 (0.2.99):
+- Changed internal version to 0.2.99 (was 0.1.99)
+- Implemented PSX_PollPad() which is similar to PSX_ReadPad() but much more advanced.
+ Analog sticks and NeGCon are now supported.
+- Updated information about reading CD-RWs in the readme.
+- Added --showoffset option in cdcat
+- Added -removelogo option in lictool
+- Added runexe.h and prototype for PSX_RunEXE(), which was missing
+- Added GsDrawListPIO(), that uses GPU port I/O access instead of GPU DMA to transfer primitive data to the GPU.
+- Added GsInitEx(), which allows to specify flags for GPU initilization.
+ GsInit() is now a wrapper to GsInitEx(), and it is the same as calling GsInitEx(0)
+- srand() and rand() are now implemented in the C library and the BIOS versions are no longer used.
+- Changed joypad reading code, now it should work better.
+- Beginnings of XM music file support in libmodplay. Support doesn't really work yet, though.
+- Added Coprocessor 0 register manipulation functions get_cop0_register() and set_cop0_register()
+
+From 0.1 to 2013-01-14:
+- Added several math constants (such as M_PI) to math.h
+- Added GsSetDispEnvSimple() and GsSetDrawEnvSimple() prototypes to psxgpu.h. The functions already existed in 0.1 but they were not prototyped and a warning was given by the compiler when they were used in a program.
+- Added sys/types.h
+- [SERIOUS] Fixed GsSpriteFromImage() - the v value when the pixel mode was 4-bit or 8-bit was incorrect
+- Added GetSystemRomVersion() function
+- [SERIOUS] As many functions provided by the BIOS which handled memory did not work correctly or at all,
+ memcmp(), memcpy(), memmove(), memcmp(), memchr(), bzero(), bcopy() and bcmp() have been implemented in
+ PSXSDK's libc. This fixes a lot of problems.
+- Fixed GsPrintFont(), the x position was incremented before drawing a character.
+ Now it is incremented after drawing a character.
+- Now the joysticks/joypads are read using low-level routines instead of using BIOS routines.
+ This is more versatile and allows the implementation of things such as vibration.
+ On the other hand, this can cause conflicts with the BIOS' memory card handling routines.
+ If you don't do directly file manipulation calls on the memory card there should be no problem, however,
+ as the PSXSDK functions to read/write the memory card take care of that already.
+ The functions added are: QueryPAD(), pad_read_raw(), pad_escape_mode().
+- Implemented vibration for DualShock-compatible controllers.
+ The functions added are: pad_enable_vibration(), pad_set_vibration()
+- The PSXSnake example now vibrates your joystick when you die.
+- Fixed calculate_real_padding_hex() in libc.c. This should fix padding with hexadecimal
+ numbers in vsnprintf based functions (sprintf() / GsPrintFont() / etc.).
+- SetVBlankHandler() and SetRCntHandler() now change handler if they're called after an handler
+ has already been set. In 0.1, they did not change handler and kept the old handler.
+- bmp2tim now also supports setting magic pink as transparent (like Allegro).
+- scalex and scaley in the GsSprite structure now act like PsyQ or Blade Libs when they are
+ higher than eight. When they are lower than eight they act like in 0.1.
+- Added scaling, wrapping, and justifying support to GsPrintFont()
+ Attributes can be set by using GsSetFontAttrib()
+- In 0.1 bmp2tim crashed if it didn't find or couldn't read the source bitmap, this is fixed now.
+- Fixed endianness issue for wav2vag on big endian machines.
+- Added GsScreenW and GsScreenH global variables which report the size of the screen
+ in the current video mode so you don't have to keep track of that yourself
+- Added is_load_delay_ok(). This checks if the load delay slot behaves as it does on real hardware.
+ Many emulators do not emulate the load delay slot and show inaccurate behavior.
+ You really need to know this only if you are doing interesting things with opcodes yourself, otherwise the compiler and the assembler will take care of this for you.
+- After returning from main() the empty endless loop wasn't running. This is now fixed.
+- Added %f format to vsnprintf(). This adds floating point support to all functions using the *sprintf() family of functions, including GsPrintFont
+- Added '@' conversion to vsscanf and vsprintf(). It is a base-2 (binary) conversion and it is a psxsdk specific extension.
+- Added support for 64-bit integers in vsnprintf() for binary, decimal, octal and hexadecimal formats.
+- Added 2d rotation support to sprites.
+- Added long file name support (via TRANS.TBL) to fopen() using the cdromL: virtual device
+- Added gs_get_tpage_num, gs_get_tpage_u and gs_get_tpage_v macros to psxgpu.h, with which
+ you can obtain the tpage, u and v parameters for textures knowing the coordinate in the framebuffer
+- Added GsIsWorking() alias for GsIsDrawing()
+- Removed useless jr $ra, nop instruction sequence which was never executed in system calls, and fixed CriticalSection system calls
+- Added GsScreenM to store current video mode (NTSC or PAL)
+- Removed -O0 from the psx-gcc script, you can now specify optimizations on the compiler command line.
+ PSXSDK library code is still compiled without optimizations, though.
+- Fixed a really nasty bug when checking if (input image width + x origin) and (input image height + y origin)
+ were out of boundary in bmp2tim
+- GsPrintFont() now recognizes TAB ('\t') and prints it accordingly (eight white characters)
+- Added the low-level CDROM library.
+- Added PSX_InitEx(). It allows to more strictly control what is initialized compared to PSX_Init()
+- Added -mpink option to tim2bmp. Transparency is rendered as "magic pink" in the output bitmap file.
+- GsSetFont() now keeps the old value for the item related to the argument if -1 is passed as the value of the argument.
+ i.e: GsSetFont(-1, -1, 30, 40) will just change the font clut x and y to 30 and 40, and will keep the font origin x and y unchanged.
+- Fixed some bugs in the huff program which were pointed out by Gemini ages ago, but were never fixed (really).
+- Fixed vsnprintf buffer overflow.
+- Fixed floating point printing bug in vsnprintf.
+- Fixed the bug with GsGPoly4 that happened because the arrays of the colors in the structure were three bytes long
+ instead of correctly being four bytes long. Thanks to Xavier Del Campo Romero for reporting this.
+- Implemented index(), rindex(), strspn(), strcspn(), strtok() and strsep() in the libc.
+- Implemented strlwr() and strupr() in the libc.
+- Implemented qsort() in the libc.
+- Implemented realloc() in the libc.
+- Implemented optional auto-waiting in GsDrawList(). If GsSetAutoWait() is called at any time in the program,
+ after that moment you will not need to wait for the GPU to finish working in your code, everything will be done
+ automatically. Auto-waiting needs to be enabled as it is disabled by default.
+- Removed a totally wrong comment in start.s which said "this might now work on PSOne".
+ It made its way through despite being about some strange things happening when PSXSDK was
+ began to be programmed??
+- Fixed stupid bug in SsUploadVag()
+- Readded abs() to libc.
+- Added PSX_INIT_SAVESTATE flag to PSX_Init() to save the state
+ of the BIOS before initializing the library
+- Added PSX_RestoreBiosState()
+- Added PSX_RunExe() to easily load another exe to run instead of the currently running one
+- Changed the prototype and return value for PSX_GetButtonName() to something sane.
+- GsUploadImage() now has a void return type. It was int before but it never returned anything.
+- Fixed a lot of warnings when compiling libpsx.
+- Fixed an array initialization out of bounds problem in libmodplay.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..52ba632
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,73 @@
+# Makefile to build PSXSDK
+
+include Makefile.cfg
+
+ifeq ($(ENABLE_CXX), yes)
+ BUILD_CXX = $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C cxx SRCROOT=$(PWD)"
+ INSTALL_CXX = $(MAKE_COMMAND) -C cxx install
+ CLEAN_CXX = $(MAKE_COMMAND) -C cxx clean
+endif
+
+build:
+ $(MAKE_COMMAND) -C misc SRCROOT=$(PWD)
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libpsx SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libhuff SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libm SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libadpcm SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libmodplay SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libfixmath SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libf3m SRCROOT=$(PWD)"
+ $(HOST_SHELL) -c "export PATH=\"$$PATH\":$(TOOLCHAIN_PREFIX)/bin;$(MAKE_COMMAND) -C libmeidogte SRCROOT=$(PWD)"
+ $(BUILD_CXX)
+ $(MAKE_COMMAND) -C tools
+
+install: build
+ $(MAKE_COMMAND) -C misc install
+ $(MAKE_COMMAND) -C libpsx install
+ $(MAKE_COMMAND) -C libhuff install
+ $(MAKE_COMMAND) -C libm install
+ $(MAKE_COMMAND) -C libadpcm install
+ $(MAKE_COMMAND) -C libmodplay install
+ $(MAKE_COMMAND) -C libfixmath install
+ $(MAKE_COMMAND) -C libf3m install
+ $(MAKE_COMMAND) -C libmeidogte install
+ $(MAKE_COMMAND) -C tools install
+ $(MAKE_COMMAND) -C licenses install
+ $(INSTALL_CXX)
+
+clean: docs_clean
+ $(MAKE_COMMAND) -C libpsx clean
+ $(MAKE_COMMAND) -C libhuff clean
+ $(MAKE_COMMAND) -C libm clean
+ $(MAKE_COMMAND) -C libadpcm clean
+ $(MAKE_COMMAND) -C libmodplay clean
+ $(MAKE_COMMAND) -C libfixmath clean
+ $(MAKE_COMMAND) -C libf3m clean
+ $(MAKE_COMMAND) -C libmeidogte clean
+ $(MAKE_COMMAND) -C misc clean
+ $(MAKE_COMMAND) -C tools clean
+ $(MAKE_COMMAND) -C examples clean
+ $(CLEAN_CXX)
+
+distclean: docs_clean
+ $(MAKE_COMMAND) -C libpsx distclean
+ $(MAKE_COMMAND) -C libhuff clean
+ $(MAKE_COMMAND) -C libm clean
+ $(MAKE_COMMAND) -C libadpcm clean
+ $(MAKE_COMMAND) -C libmodplay clean
+ $(MAKE_COMMAND) -C libfixmath clean
+ $(MAKE_COMMAND) -C libf3m clean
+ $(MAKE_COMMAND) -C libmeidogte clean
+ $(MAKE_COMMAND) -C misc distclean
+ $(MAKE_COMMAND) -C tools distclean
+ $(MAKE_COMMAND) -C examples distclean
+ $(CLEAN_CXX)
+
+build_examples:
+ $(MAKE_COMMAND) -C examples
+
+docs:
+ $(DOXYGEN) doxygen.conf
+
+docs_clean:
+ rm -fr doc/*
diff --git a/Makefile.cfg b/Makefile.cfg
new file mode 100644
index 0000000..91da0bd
--- /dev/null
+++ b/Makefile.cfg
@@ -0,0 +1,90 @@
+# Prefix of the toolchain
+
+TOOLCHAIN_PREFIX = /usr/local/psxsdk
+
+# Make command
+# Tip: Set to gmake on *BSD
+
+MAKE_COMMAND = gmake
+
+# Build C++ support
+# Set the line below to `no' to disable C++ support
+
+ENABLE_CXX = yes
+
+# Specify how to invoke Doxygen when building documentation
+
+DOXYGEN = doxygen
+
+# Mkisofs command
+# Tip: On some Linux distributions, set to genisoimage
+
+MKISOFS_COMMAND = mkisofs
+
+# Video mode to use in the examples (PAL or NTSC)
+# Tip: most likely if you are in the US or Japan, use VMODE_NTSC
+# most likely if you are in Europe, use VMODE_PAL
+
+EXAMPLES_VMODE = VMODE_PAL
+
+# License file to use to license CD image
+# infousa.dat for US PlayStations
+# infojpn.dat for Japanese PlayStations
+# infoeur.dat for European PlayStations
+
+CDLIC_FILE = $(TOOLCHAIN_PREFIX)/share/licenses/infoeur.dat
+
+# Executable suffix for executable running on the host
+# i.e. suffix for the binaries of the tools
+
+EXE_SUFFIX =
+
+#EXE_SUFFIX = .exe # Use this on Windows
+
+# Development environment variables
+
+CC = mipsel-unknown-elf-gcc
+CXX = mipsel-unknown-elf-g++
+# CFLAGS and CXXFLAGS - do not change if you do not know what you are doing!!!
+INCLUDEDIR = $(SRCROOT)/libpsx/include/
+AFLAGS = -I $(INCLUDEDIR) -G0 -msoft-float
+CFLAGS = -D__PSXSDK__ -fsigned-char -fno-strict-overflow -I$(INCLUDEDIR) -G0 -fno-builtin -mno-gpopt -nostdlib -msoft-float -Wall -Werror
+CXXFLAGS = $(CFLAGS) -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-use-cxa-atexit
+AR = mipsel-unknown-elf-ar
+RANLIB = mipsel-unknown-elf-ranlib
+AS = mipsel-unknown-elf-as
+LD = mipsel-unknown-elf-ld
+CPP = mipsel-unknown-elf-gcc
+OBJCOPY = mipsel-unknown-elf-objcopy
+
+# Uncomment the lines below if you want to have a debug build
+# CFLAGS += -g -DPSXSDK_DEBUG
+# CXXFLAGS += -g -DPSXSDK_DEBUG
+
+# HOST_* variables specify the programs for compiling code on the host computer
+
+HOST_CC = gcc
+HOST_CXX = g++
+HOST_CFLAGS = -g -Wall -Werror
+HOST_CXXFLAGS = -g -Wall -Werror
+HOST_AR = ar
+HOST_RANLIB = ranlib
+HOST_LDFLAGS =
+
+# Flags for the examples
+
+EXAMPLES_CC = psx-gcc
+EXAMPLES_CXX = psx-g++
+EXAMPLES_CFLAGS = -Wall -Werror
+EXAMPLES_CXXFLAGS = -Wall -Werror
+EXAMPLES_LIBS =
+EXAMPLES_LDFLAGS =
+
+# Shell to use when executing scripts
+
+HOST_SHELL = sh
+
+# Do not modify the line below, it is used to specify a default SRCROOT
+# when it is not specified.
+
+SRCROOT = ..
diff --git a/cxx/Makefile b/cxx/Makefile
new file mode 100644
index 0000000..c896a9b
--- /dev/null
+++ b/cxx/Makefile
@@ -0,0 +1,19 @@
+include ../Makefile.cfg
+
+OBJS = $(patsubst %.cc, %.o, $(wildcard *.cc))
+
+all: libstdc++.a
+
+libstdc++.a: $(OBJS)
+ $(AR) r libstdc++.a $(OBJS)
+
+%.o: %.cc
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
+install: libstdc++.a
+ cp libstdc++.a $(TOOLCHAIN_PREFIX)/lib
+
+clean:
+ rm -f $(OBJS) libstdc++.a
+
+distclean: clean
diff --git a/cxx/new.cc b/cxx/new.cc
new file mode 100755
index 0000000..5903faa
--- /dev/null
+++ b/cxx/new.cc
@@ -0,0 +1,29 @@
+extern "C"
+{
+ #include <stdio.h>
+ #include <stdlib.h>
+}
+
+void *
+operator new(size_t size)
+{
+ return malloc(size);
+}
+
+void *
+operator new[](size_t size)
+{
+ return malloc(size);
+}
+
+void
+operator delete(void *ptr)
+{
+ free(ptr);
+}
+
+void
+operator delete[](void *ptr)
+{
+ free(ptr);
+}
diff --git a/cxx/virtual.cc b/cxx/virtual.cc
new file mode 100644
index 0000000..71d8b9a
--- /dev/null
+++ b/cxx/virtual.cc
@@ -0,0 +1,11 @@
+extern "C"
+{
+ #include <stdio.h>
+ #include <stdlib.h>
+}
+
+extern "C" void __cxa_pure_virtual()
+{
+ printf("\nError: Called pure virtual C++ function!\n");
+ exit(-1);
+}
diff --git a/doxygen.conf b/doxygen.conf
new file mode 100644
index 0000000..2b9061c
--- /dev/null
+++ b/doxygen.conf
@@ -0,0 +1,1808 @@
+# Doxyfile 1.8.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = "PSXSDK"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = libpsx libmodplay cxx libadpcm libf3m libfixmath libhuff libm libmeidogte
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..90bb904
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,25 @@
+include ../Makefile.cfg
+
+all:
+ $(MAKE_COMMAND) -C mandel
+ $(MAKE_COMMAND) -C memview
+ $(MAKE_COMMAND) -C psxmod
+ $(MAKE_COMMAND) -C psxpaint
+ $(MAKE_COMMAND) -C psxsnake
+ $(MAKE_COMMAND) -C puzzle
+ $(MAKE_COMMAND) -C rottest
+ $(MAKE_COMMAND) -C psxs3m
+ $(MAKE_COMMAND) -C gtecube
+
+clean:
+ $(MAKE_COMMAND) -C mandel clean
+ $(MAKE_COMMAND) -C memview clean
+ $(MAKE_COMMAND) -C psxmod clean
+ $(MAKE_COMMAND) -C psxpaint clean
+ $(MAKE_COMMAND) -C psxsnake clean
+ $(MAKE_COMMAND) -C puzzle clean
+ $(MAKE_COMMAND) -C rottest clean
+ $(MAKE_COMMAND) -C psxs3m clean
+ $(MAKE_COMMAND) -C gtecube clean
+
+distclean: clean
diff --git a/examples/gtecube/Makefile b/examples/gtecube/Makefile
new file mode 100644
index 0000000..98789d3
--- /dev/null
+++ b/examples/gtecube/Makefile
@@ -0,0 +1,8 @@
+PROJNAME = gtecube
+PROJ_LIBS = -lmeidogte
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/gtecube/gtecube.c b/examples/gtecube/gtecube.c
new file mode 100644
index 0000000..b5dda19
--- /dev/null
+++ b/examples/gtecube/gtecube.c
@@ -0,0 +1,448 @@
+/*
+ * GTE Graphics Example (Spinning Cube)
+ * 2019 Meido-Tek Productions
+ * 2019 modified by nextvolume for PSXSDK
+ *
+ * licensed under Mozilla Public License v2.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <psx.h>
+#include <psxgpu.h>
+#include <meidogte.h>
+
+/* Screen resolution */
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+/* Screen center position */
+#define CENTERX SCREEN_XRES>>1
+#define CENTERY SCREEN_YRES>>1
+
+#define OT_LEN 0x8000
+
+/* For easier handling of vertex indices */
+typedef struct {
+ short v0,v1,v2,v3;
+} INDEX;
+
+/* Cube vertices */
+SVECTOR cube_verts[] = {
+ { -100, -100, -100, 0 },
+ { 100, -100, -100, 0 },
+ { -100, 100, -100, 0 },
+ { 100, 100, -100, 0 },
+ { 100, -100, 100, 0 },
+ { -100, -100, 100, 0 },
+ { 100, 100, 100, 0 },
+ { -100, 100, 100, 0 }
+};
+
+/* Cube face normals */
+SVECTOR cube_norms[] = {
+ { 0, 0, -ONE, 0 },
+ { 0, 0, ONE, 0 },
+ { 0, -ONE, 0, 0 },
+ { 0, ONE, 0, 0 },
+ { -ONE, 0, 0, 0 },
+ { ONE, 0, 0, 0 }
+};
+
+/* Cube vertex indices */
+INDEX cube_indices[] = {
+ { 0, 1, 2, 3 },
+ { 4, 5, 6, 7 },
+ { 5, 4, 0, 1 },
+ { 6, 7, 3, 2 },
+ { 0, 2, 5, 7 },
+ { 3, 1, 6, 4 }
+};
+
+/* Number of faces of cube */
+#define CUBE_FACES 6
+
+/* Light color matrix */
+/* Each column represents the color matrix of each light source and is */
+/* used as material color when using gte_ncs() or multiplied by a */
+/* source color when using gte_nccs(). 4096 is 1.0 in this matrix */
+/* A column of zeroes disables the light source. */
+MATRIX color_mtx = { .m = {
+ {ONE, 0, 0}, /* Red */
+ {ONE, 0, 0}, /* Green */
+ {ONE, 0, 0} /* Blue */ }
+};
+
+/* Light matrix */
+/* Each row represents a vector direction of each light source. */
+/* An entire row of zeroes disables the light source. */
+MATRIX light_mtx = { .m = {
+ /* X, Y, Z */
+ { -2048 , -2048 , -2048},
+ {0 , 0 , 0},
+ {0 , 0 , 0} }
+};
+
+
+/* Function declarations */
+void init(void);
+void display(void);
+
+unsigned int prim_list[OT_LEN];
+int current_buf = 0;
+volatile int vblank_happened = 0;
+
+GsPoly4 poly[CUBE_FACES]; /* Flat shaded quad primitive */
+
+static void program_vblank_handler(void) {
+ vblank_happened = 1;
+}
+
+enum {
+ OP_SPIN,
+ OP_COLORR1, OP_COLORG1, OP_COLORB1,
+ OP_COLORR2, OP_COLORG2, OP_COLORB2,
+ OP_COLORR3, OP_COLORG3, OP_COLORB3,
+ OP_LIGHTX1, OP_LIGHTY1, OP_LIGHTZ1,
+ OP_LIGHTX2, OP_LIGHTY2, OP_LIGHTZ2,
+ OP_LIGHTX3, OP_LIGHTY3, OP_LIGHTZ3,
+ OP_SCRXOFF, OP_SCRYOFF,
+ OP_SCRDEPTH,
+ OP_TRANSVX, OP_TRANSVY, OP_TRANSVZ,
+ OP_END
+};
+
+const char *operationNames[] = {"Change spinning speed",
+ "Change light color R1", "Change light color G1", "Change light color B1",
+ "Change light color R2", "Change light color G2", "Change light color B2",
+ "Change light color R3", "Change light color G3", "Change light color B3",
+ "Change light X1", "Change light Y1", "Change light Z1",
+ "Change light X2", "Change light Y2", "Change light Z2",
+ "Change light X3", "Change light Y3", "Change light Z3",
+ "Change screen X offset", "Change screen Y offset",
+ "Change screen depth",
+ "Change translation vector X", "Change translation vector Y",
+ "Change translation vector Z",
+ };
+
+int stopped = 0;
+int currentOperation = 0;
+
+int spinningSpeed = 16;
+int screenXOffset = CENTERX;
+int screenYOffset = CENTERY;
+int screenDepth = CENTERX;
+
+VECTOR pos = { .vx = 0, .vy = 0, .vz = 400 }; /* Translation vector for TransMatrix */
+
+#define COLOR_STEP 32
+#define LIGHT_STEP 128
+
+/* Main function */
+int main() {
+
+ int i,p,wasStart=0,wasLeft=0,wasRight=0;
+ int a,b;
+ short coord[2];
+ unsigned char rgb[3] = {255, 255, 0};
+ unsigned short padbuf;
+
+ SVECTOR rot; /* Rotation vector for Rotmatrix */
+ MATRIX mtx,lmtx; /* Rotation matrices for geometry and lighting */
+
+ bzero(&rot, sizeof(rot));
+
+ /* Init graphics and GTE */
+ init();
+
+ /* Main loop */
+ while( 1 ) {
+ /* Set GTE offset (recommended method of centering) */
+ gte_SetGeomOffset( screenXOffset, screenYOffset );
+
+ /* Set screen depth (basically FOV control, W/2 works best) */
+ gte_SetGeomScreen(screenDepth);
+
+ /* Set light ambient color and light color matrix */
+ gte_SetBackColor( 63, 63, 63 );
+ gte_SetColorMatrix( &color_mtx );
+
+ /* Set rotation and translation to the matrix */
+ RotMatrix( &rot, &mtx );
+ TransMatrix( &mtx, &pos );
+
+ /* Multiply light matrix by rotation matrix so light source */
+ /* won't appear relative to the model's rotation */
+ MulMatrix0( &light_mtx, &mtx, &lmtx );
+
+ /* Set rotation and translation matrix */
+ gte_SetRotMatrix( &mtx );
+ gte_SetTransMatrix( &mtx );
+
+ /* Set light matrix */
+ gte_SetLightMatrix( &lmtx );
+
+ if (!stopped) {
+ /* Make the cube SPEEN */
+ rot.vx += spinningSpeed;
+ rot.vz += spinningSpeed;
+ }
+
+ for( i=0; i<CUBE_FACES; i++ ) {
+
+ /* Load the first 3 vertices of a quad to the GTE */
+ gte_ldv3(
+ &cube_verts[cube_indices[i].v0],
+ &cube_verts[cube_indices[i].v1],
+ &cube_verts[cube_indices[i].v2] );
+
+ /* Rotation, Translation and Perspective Triple */
+ gte_rtpt();
+
+ /* Compute normal clip for backface culling */
+ gte_nclip();
+
+ /* Get result*/
+ gte_stopz( &p );
+
+ /* Skip this face if backfaced */
+ if( p < 0 ) {
+ poly[i].attribute = -1;
+ continue;
+ }
+
+ /* Calculate average Z for depth sorting */
+ gte_avsz4();
+ gte_stotz( &p );
+
+ /* Skip if clipping off */
+ /* (the shift right operator is to scale the depth precision) */
+ if( (p>>2) > OT_LEN ) {
+ poly[i].attribute = -1;
+ continue;
+ }
+
+ /* Set the projected vertices to the primitive */
+ gte_stsxy0( &coord );
+ poly[i].x[0] = coord[0];
+ poly[i].y[0] = coord[1];
+
+ gte_stsxy1( &coord );
+ poly[i].x[1] = coord[0];
+ poly[i].y[1] = coord[1];
+
+ gte_stsxy2( &coord );
+ poly[i].x[2] = coord[0];
+ poly[i].y[2] = coord[1];
+
+ /* Compute the last vertex and set the result */
+ gte_ldv0( &cube_verts[cube_indices[i].v3] );
+ gte_rtps();
+ gte_stsxy( &coord );
+ poly[i].x[3] = coord[0];
+ poly[i].y[3] = coord[1];
+
+ rgb[0] = 255;
+ rgb[1] = 255;
+ rgb[2] = 255;
+
+ gte_ldrgb( &rgb );
+
+ /* Load the face normal */
+ gte_ldv0( &cube_norms[i] );
+
+ /* Normal Color Single */
+ gte_nccs();
+
+ /* Store result to the primitive */
+ gte_strgb( &rgb );
+
+ poly[i].r = rgb[0];
+ poly[i].g = rgb[1];
+ poly[i].b = rgb[2];
+
+ poly[i].attribute = 0;
+ }
+
+ /* Swap buffers and draw the primitives */
+ display();
+
+ /* Wait for VBlank to happen */
+ vblank_happened = 0;
+ while(!vblank_happened);
+
+ /* Read joypad status */
+ PSX_ReadPad(&padbuf, NULL);
+
+ /* Logic for real-time 'configuration' of the cube */
+ if ((padbuf & PAD_START) && !wasStart) {
+ stopped = !stopped;
+ wasStart = 1;
+ }
+
+ if ((padbuf & PAD_LEFT) && !wasLeft) {
+ currentOperation--;
+
+ if (currentOperation < 0)
+ currentOperation = OP_END - 1;
+
+ wasLeft = 1;
+ }
+
+ if ((padbuf & PAD_RIGHT) && !wasRight) {
+ currentOperation++;
+
+ if (currentOperation >= OP_END)
+ currentOperation = 0;
+
+ wasRight = 1;
+ }
+
+ if (padbuf & PAD_UP) {
+ switch(currentOperation) {
+ case OP_SPIN:
+ spinningSpeed++;
+ break;
+ case OP_COLORR1 ... OP_COLORB3:
+ a = (currentOperation - OP_COLORR1);
+ b = a % 3;
+ a /= 3;
+
+ if(color_mtx.m[b][a] < ONE)
+ color_mtx.m[b][a]+=COLOR_STEP;
+ break;
+ case OP_LIGHTX1 ... OP_LIGHTZ3:
+ a = (currentOperation - OP_LIGHTX1);
+ b = a % 3;
+ a /= 3;
+
+ if(light_mtx.m[a][b] < ONE)
+ light_mtx.m[a][b]+=LIGHT_STEP;
+ break;
+ case OP_SCRXOFF:
+ screenXOffset++;
+ break;
+ case OP_SCRYOFF:
+ screenYOffset++;
+ break;
+ case OP_SCRDEPTH:
+ screenDepth++;
+ break;
+ case OP_TRANSVX:
+ pos.vx++;
+ break;
+ case OP_TRANSVY:
+ pos.vy++;
+ break;
+ case OP_TRANSVZ:
+ pos.vz++;
+ break;
+ }
+ }
+
+ if (padbuf & PAD_DOWN) {
+ switch(currentOperation) {
+ case OP_SPIN:
+ spinningSpeed--;
+ break;
+ case OP_COLORR1 ... OP_COLORB3:
+ a = (currentOperation - OP_COLORR1);
+ b = a % 3;
+ a /= 3;
+
+ if(color_mtx.m[b][a] > 0)
+ color_mtx.m[b][a]-=COLOR_STEP;
+ break;
+ case OP_LIGHTX1 ... OP_LIGHTZ3:
+ a = (currentOperation - OP_LIGHTX1);
+ b = a % 3;
+ a /= 3;
+
+ if(light_mtx.m[a][b] > 0)
+ light_mtx.m[a][b]-=LIGHT_STEP;
+ break;
+ case OP_SCRXOFF:
+ screenXOffset--;
+ break;
+ case OP_SCRYOFF:
+ screenYOffset--;
+ break;
+ case OP_SCRDEPTH:
+ screenDepth--;
+ break;
+ case OP_TRANSVX:
+ pos.vx--;
+ break;
+ case OP_TRANSVY:
+ pos.vy--;
+ break;
+ case OP_TRANSVZ:
+ pos.vz--;
+ break;
+ }
+ }
+
+ if (!(padbuf & PAD_START))
+ wasStart = 0;
+
+ if (!(padbuf & PAD_LEFT))
+ wasLeft = 0;
+
+ if (!(padbuf & PAD_RIGHT))
+ wasRight = 0;
+ }
+
+ return 0;
+}
+
+void init(void) {
+ /* Initialize PSXSDK */
+ PSX_InitEx( 0 );
+ /* Initialize the Graphic Synthesizer */
+ GsInit();
+ /* Clear video memory */
+ GsClearMem();
+ /* Set primitive list pointer */
+ GsSetList( prim_list );
+ /* Set automatic GPU waiting */
+ GsSetAutoWait();
+ /* Set 320x240 video mode */
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+ /* Set VBlank Handler */
+ SetVBlankHandler( program_vblank_handler );
+
+ /* Load text font in video memory */
+ GsLoadFont(768, 0, 768, 256);
+
+ /* Initialize the MeidoGTE library */
+ InitGeom();
+}
+
+void display(void) {
+ int i;
+
+ /* Change display and drawing environment settings */
+ /* for double buffering */
+ GsSetDispEnvSimple(0, current_buf ? 0 : 256);
+ GsSetDrawEnvSimple(0, current_buf ? 256 : 0, SCREEN_XRES, SCREEN_YRES);
+ current_buf = !current_buf;
+
+ /* Clear the screen with the specified color */
+ GsSortCls(63, 0, 127);
+
+ /* Add cube faces to drawing list */
+ for(i=0;i<CUBE_FACES;i++) {
+ if(poly[i].attribute != -1)
+ GsSortPoly4(&poly[i]);
+ }
+
+ /* If stopped, show so on the screen */
+ if (stopped)
+ GsPrintFont(0, 0, "Stopped");
+
+ /* Print current operation name on screen */
+ GsPrintFont(0, GsScreenH-16, "%s", operationNames[currentOperation]);
+
+ /* Draw list */
+ GsDrawList();
+}
diff --git a/examples/mandel/Makefile b/examples/mandel/Makefile
new file mode 100644
index 0000000..74759a0
--- /dev/null
+++ b/examples/mandel/Makefile
@@ -0,0 +1,7 @@
+PROJNAME = mandel
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/mandel/mandel.c b/examples/mandel/mandel.c
new file mode 100644
index 0000000..77eda4e
--- /dev/null
+++ b/examples/mandel/mandel.c
@@ -0,0 +1,347 @@
+/*
+ * Simple fractal generator for the PlayStation
+ *
+ * by Giuseppe Gatta
+ * Placed in the Public Domain.
+ *
+ * Consider enabling compiler optimizations, for instance this code is much faster
+ * if you add -O3 to the gcc command line.
+ *
+ * The fractals are rendered at a 160x120 resolution in an array in memory,
+ * then this array is uploaded to video memory and handled as 8-bit image data.
+ * We render at 160x120 to speed rendering up because the PlayStation is a slow machine
+ * for doing this kind of thing.
+ *
+ * A sprite primitive is used to display the image data on the screen, and the primitive
+ * is scaled twice horizontally and vertically to cover the 320x240 screen with a 160x120
+ * image.
+ *
+ * The fractal drawing code by default also exploits the simmetry of the Mandrelbot
+ * and Tricorn sets to further speed rendering up (2x). To have a real rendering of
+ * the Burning Ship fractal, though, you must disable simmetry because that fractal
+ * does not have this property.
+ *
+ * This is the description of the controls of this program:
+ *
+ * SELECT - Toggle palette (Red->Green->Blue->Yellow->Violet->Red->...)
+ * START - Render fractal
+ * X - Toggle type of fractal to render (Mandelbrot->Tricorn->Burning Ship->Mandelbrot->...)
+ * O - Toggle simmetry (on the screen as 'S')
+ * LEFT - Decrease multibrot power (displayed on the screen as 'M')
+ * RIGHT - Increase multibrot power
+ * UP - Decrease number of maximum iterations (on the screen as 'I')
+ * DOWN - Increase number of maximum iterations
+ */
+
+#include <psx.h>
+#include <stdio.h>
+
+unsigned char fractal_image_data[120][160];
+unsigned int prim_list[0x4000];
+unsigned short clut_buf[256];
+
+volatile int frac_x=0, frac_y=0;
+
+enum
+{
+ FRAC_MANDELBROT, // Normal mandelbrot
+ FRAC_TRICORN,
+ FRAC_BSHIP,
+ FRAC_TF,
+
+ FRAC_NOSIMM = 0x200,
+};
+
+/*
+ * Code based on http://reocities.com/CapeCanaveral/5003/mandel.htm
+ */
+
+void mandrelbrot_int(int width, int height, int maxI, int type, int M)
+{
+ #define FIXSIZE 25
+ #define mul(a,b) ((((long long)a)*(b))>>FIXSIZE)
+ #define fixpt(a) ((int)(((a)*(1<<FIXSIZE))))
+ #define integer(a) (((a)+(1<<(FIXSIZE-1)))>>FIXSIZE)
+
+ int x0,y0,x1,y1,p,q,xn;
+ double xmin=-2.5,ymin=-1.5,xmax=1.5,ymax=1.5,xs,ys;
+ int i,x,y,t;
+ int m;
+
+ xs=(xmax-xmin)/width;
+ ys=(ymax-ymin)/height;
+
+ t = type & 0xff;
+
+ for (y=0;y<((type&FRAC_NOSIMM)?height:(height/2));y++)
+ {
+ for (x=0;x<width;x++)
+ {
+ p=fixpt(xmin+x*xs); // c_re
+ q=fixpt(ymin+y*ys);
+ xn=0;
+ x0=0;
+ y0=0;
+ i=0;
+
+ while ((mul(xn,xn)+mul(y0,y0))<fixpt(4) && ++i<maxI)
+ {
+ switch(t)
+ {
+ case FRAC_BSHIP:
+ if(x0<0)x0=-x0;
+ if(y0<0)y0=-y0;
+ break;
+ case FRAC_TRICORN:
+ y0=-y0;
+ break;
+ }
+
+ x1=x0;
+ y1=y0;
+
+ for(m=1;m<M;m++)
+ {
+ xn=mul(x0,x1) - mul(y0,y1);
+ y0=mul(y0,x1) + mul(x0,y1);
+ x0=xn;
+ }
+
+ x0=xn;
+ x0+=p;
+ y0+=q;
+ }
+
+ if (i==maxI) i=1;
+ fractal_image_data[y][x] = (i*256)/maxI;
+
+ if(!(type & FRAC_NOSIMM))
+ fractal_image_data[(height-1)-y][x] = (i*256)/maxI;
+ }
+ }
+}
+
+volatile int display_is_old = 1;
+volatile int time_counter = 0;
+
+void prog_vblank_handler()
+{
+ display_is_old = 1;
+ time_counter++;
+}
+
+int frac_type = FRAC_MANDELBROT;
+unsigned int frac_maxI = 64;
+int frac_M=2;
+
+const char *frac_type_string[] =
+ { "Mandelbrot",
+ "Tricorn",
+ "BurningShip"};
+
+GsSprite frac_sprite;
+
+int main()
+{
+ int x, dbuf=0;
+
+ int waspal=0;
+ int wastype=0;
+ int wasrender=0;
+ int wassimm=0;
+ int wasMm=0,wasMp=0, wasIm=0, wasIp=0;
+ int rendering_time = -1;
+
+ unsigned short padbuf;
+
+ PSX_InitEx(PSX_INIT_CD);
+
+ GsInit();
+ GsSetList(prim_list);
+ GsClearMem();
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+ GsLoadFont(768, 0, 768, 256);
+ SetVBlankHandler(prog_vblank_handler);
+
+// Fill & upload CLUTs
+
+// Red CLUT
+ for(x = 0; x < 256; x++)
+ clut_buf[x] = ((x*4)>255?255:x*4)>>3;
+
+ LoadImage(clut_buf, 512, 256, 256, 1);
+ while(GsIsDrawing());
+
+// Green CLUT
+ for(x = 0; x < 256; x++)
+ clut_buf[x] = (((x*4)>255?255:x*4)>>3)<<5;
+
+ LoadImage(clut_buf, 512, 257, 256, 1);
+ while(GsIsDrawing());
+
+// Blue CLUT
+ for(x = 0; x < 256; x++)
+ clut_buf[x] = (((x*4)>255?255:x*4)>>3)<<10;
+
+ LoadImage(clut_buf, 512, 258, 256, 1);
+ while(GsIsDrawing());
+
+
+// Yellow CLUT
+ for(x = 0; x < 256; x++)
+ {
+ clut_buf[x] = ((x*4)>255?255:x*4)>>3;
+ clut_buf[x]|= clut_buf[x]<<5;
+ }
+
+ LoadImage(clut_buf, 512, 259, 256, 1);
+ while(GsIsDrawing());
+
+// Violet CLUT
+ for(x = 0; x < 256; x++)
+ {
+ clut_buf[x] = ((x*4)>255?255:x*4)>>3;
+ clut_buf[x]|= clut_buf[x]<<10;
+ }
+
+ LoadImage(clut_buf, 512, 260, 256, 1);
+ while(GsIsDrawing());
+
+ frac_sprite.tpage = 5;
+ frac_sprite.attribute = COLORMODE(COLORMODE_8BPP);
+ frac_sprite.u = 0;
+ frac_sprite.v = 0;
+ frac_sprite.cx = 512;
+ frac_sprite.cy = 256;
+ frac_sprite.x = 0;
+ frac_sprite.y = 0;
+ frac_sprite.w = 160;
+ frac_sprite.h = 120;
+ frac_sprite.r = frac_sprite.g = frac_sprite.b = NORMAL_LUMINOSITY;
+ frac_sprite.scalex = SCALE_ONE*2;
+ frac_sprite.scaley = SCALE_ONE*2;
+
+ time_counter = 0;
+ mandrelbrot_int(160, 120, frac_maxI, frac_type, frac_M);
+ rendering_time = time_counter * (GsScreenM==VMODE_NTSC?17:20);
+ LoadImage(fractal_image_data, 320, 0, 80, 120);
+ while(GsIsDrawing());
+
+ while(1)
+ {
+ if(display_is_old)
+ {
+ dbuf=!dbuf;
+ GsSetDispEnvSimple(0, dbuf?0:256);
+ GsSetDrawEnvSimple(0, dbuf?256:0, 320, 240);
+
+ GsSortCls(0,0,0);
+ GsSortSprite(&frac_sprite);
+
+ GsPrintFont(0, 0, "Type: %s", frac_type_string[(frac_type&0xff)]);
+ GsPrintFont(0, 8, "I=%d, M=%d, S=%c", frac_maxI, frac_M,
+ frac_type&FRAC_NOSIMM?'N':'Y');
+ GsPrintFont(0, 16, "Time: %d.%03d", rendering_time / 1000, rendering_time % 1000);
+
+ GsDrawList();
+ while(GsIsDrawing());
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if((padbuf & PAD_SELECT) && !waspal)
+ {
+ frac_sprite.cy++;
+ if(frac_sprite.cy>260)
+ frac_sprite.cy = 256;
+
+ waspal=1;
+ }
+
+ if((padbuf & PAD_CROSS) && !wastype)
+ {
+ frac_type++;
+ if((frac_type & 0xff) >= FRAC_TF)
+ frac_type&=~0xff;
+
+ wastype=1;
+ }
+
+ if((padbuf & PAD_START) && !wasrender)
+ {
+ GsPrintFont(0, 224, "Rendering...");
+ GsDrawList();
+ while(GsIsDrawing());
+
+ dbuf=!dbuf;
+ GsSetDispEnvSimple(0, dbuf?0:256);
+ GsSetDrawEnvSimple(0, dbuf?256:0, 320, 240);
+
+ time_counter = 0;
+ mandrelbrot_int(160, 120, frac_maxI, frac_type, frac_M);
+ rendering_time = time_counter * (GsScreenM==VMODE_NTSC?17:20);
+ LoadImage(fractal_image_data, 320, 0, 80, 120);
+ while(GsIsDrawing());
+
+ wasrender=1;
+ }
+
+ if((padbuf & PAD_CIRCLE) && !wassimm)
+ {
+ frac_type ^= FRAC_NOSIMM;
+ wassimm=1;
+ }
+
+ if((padbuf & PAD_LEFT) && !wasMm)
+ {
+ if(frac_M>2)frac_M--;
+ wasMm=1;
+ }
+
+ if((padbuf & PAD_RIGHT) && !wasMp)
+ {
+ frac_M++;
+ wasMp=1;
+ }
+
+ if((padbuf & PAD_UP) && !wasIm)
+ {
+ if(frac_maxI>1)frac_maxI--;
+ wasIm=1;
+ }
+
+ if((padbuf & PAD_DOWN) && !wasIp)
+ {
+ frac_maxI++;
+ wasIp=1;
+ }
+
+ if(!(padbuf & PAD_SELECT))
+ waspal=0;
+
+ if(!(padbuf & PAD_CROSS))
+ wastype=0;
+
+ if(!(padbuf & PAD_START))
+ wasrender=0;
+
+ if(!(padbuf & PAD_CIRCLE))
+ wassimm=0;
+
+ if(!(padbuf & PAD_LEFT))
+ wasMm=0;
+
+ if(!(padbuf & PAD_RIGHT))
+ wasMp=0;
+
+ if(!(padbuf & PAD_UP))
+ wasIm=0;
+
+ if(!(padbuf & PAD_DOWN))
+ wasIp=0;
+
+ display_is_old=0;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/memview/Makefile b/examples/memview/Makefile
new file mode 100644
index 0000000..55f05eb
--- /dev/null
+++ b/examples/memview/Makefile
@@ -0,0 +1,7 @@
+PROJNAME = memview
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/memview/memview.c b/examples/memview/memview.c
new file mode 100644
index 0000000..bf2e04a
--- /dev/null
+++ b/examples/memview/memview.c
@@ -0,0 +1,249 @@
+/**
+ * PlayStation Memory Viewer
+ * by Giuseppe Gatta a.k.a. nextvolume
+ *
+ * PSXSDK Example - released to the Public Domain
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <psx.h>
+
+unsigned int cur_addr = 0x80000000;
+unsigned int prim_list[0x20000];
+
+int display_is_old = 1;
+volatile int should_read_pad = 1;
+
+void pshex_vblank_handler()
+{
+ should_read_pad = 1;
+}
+
+int main()
+{
+ unsigned short padbuf;
+ int y, f, x, x1;
+ int highres_mode=0;
+ int srp=0;
+ int wasup=0, wasdown=0, wasleft=0, wasright=0, wasl1=0, wasr1=0,
+ wasl2=0;
+ int wascross=0, wascircle=0, wasstart=0,wasselect=0;
+ unsigned int go_address = 0x80000000;
+ int go_pos = 0;
+ GsRectangle pshex_rect;
+
+
+ PSX_InitEx(0);
+
+ GsInit();
+ GsClearMem();
+
+ GsSetVideoMode(640, 240, VMODE_PAL);
+ GsSetList(prim_list);
+ GsSetDispEnvSimple(0, 0);
+ GsSetDrawEnvSimple(0, 0, 640, 240);
+ GsLoadFont(768, 0, 768, 256);
+
+ SetVBlankHandler(pshex_vblank_handler);
+
+ GsPrintFont(16, 16, "PAL/NTSC SELECTION");
+ GsPrintFont(16, 32, "X - PAL");
+ GsPrintFont(16, 40, "O - NTSC");
+ GsDrawList();
+ while(GsIsDrawing());
+
+ while(1)
+ {
+ if(should_read_pad)
+ {
+ PSX_ReadPad(&padbuf, NULL);
+
+ if((padbuf & PAD_CROSS))
+ {
+ GsSetVideoModeEx(640, 480, VMODE_PAL, 0, 1, 0);
+ wascross=1;
+ break;
+ }
+
+ if((padbuf & PAD_CIRCLE))
+ {
+ GsSetVideoModeEx(640, 480, VMODE_NTSC, 0, 1, 0);
+ wascircle=1;
+ break;
+ }
+
+ should_read_pad=0;
+ }
+ }
+
+ GsSetDrawEnvSimple(0, (GsScreenM==VMODE_PAL?8:0), 640, 480);
+
+ while(1)
+ {
+ if(display_is_old)
+ {
+ GsSortCls(0, 0, 255);
+
+ for(y = 0; y < (highres_mode?58:28); y++)
+ {
+ f = GsPrintFont(24, y*8, "%08x", cur_addr + (y*0x10));
+ x1 = prfont_get_fx(f) + 16;
+
+ for(x = 0; x < 16; x++)
+ {
+ if(( (x&3) == 0) && x>0)
+ x1+=16;
+
+ f = GsPrintFont(x1, y*8, "%02x", *((unsigned char*)(cur_addr + (y*0x10) + x)));
+ x1 = prfont_get_fx(f) + 8;
+ }
+
+ x1+=8;
+
+ for(x=0;x<16;x++)
+ {
+ GsPrintFont(x1, y*8, "%c", *((unsigned char*)(cur_addr + (y*0x10) + x)));
+ x1+=8;
+ }
+ }
+
+ pshex_rect.x = (go_pos * 8)+24;
+ pshex_rect.y = highres_mode?472:232;
+ pshex_rect.r = 255;
+ pshex_rect.g = 69;
+ pshex_rect.b = 0;
+ pshex_rect.attribute = 0;
+ pshex_rect.w = 8;
+ pshex_rect.h = 8;
+ GsSortRectangle(&pshex_rect);
+
+ GsPrintFont(24, highres_mode?472:232, "%08X", go_address);
+
+ GsDrawList();
+ while(GsIsDrawing());
+ display_is_old = 0;
+ }
+
+ if(should_read_pad)
+ {
+ PSX_ReadPad(&padbuf, NULL);
+
+ if((padbuf & PAD_UP) && !wasup)
+ {
+ cur_addr -= 0x10;
+ display_is_old = 1;
+ wasup = 1;
+ }
+
+ if((padbuf & PAD_DOWN) && !wasdown)
+ {
+ cur_addr += 0x10;
+ display_is_old = 1;
+ wasdown = 1;
+ }
+
+ if((padbuf & PAD_LEFT) && !wasleft)
+ {
+ cur_addr -= 0x100;
+ display_is_old = 1;
+ wasleft=1;
+ }
+
+ if((padbuf & PAD_RIGHT) && !wasright)
+ {
+ cur_addr += 0x100;
+ display_is_old = 1;
+ wasright=1;
+ }
+
+ if((padbuf & PAD_L1) && !wasl1)
+ {
+ if(go_pos>0)go_pos--;
+ display_is_old = 1;
+ wasl1=1;
+ }
+
+ if((padbuf & PAD_R1) && !wasr1)
+ {
+ if(go_pos<7)go_pos++;
+ display_is_old = 1;
+ wasr1=1;
+ }
+
+ if((padbuf & PAD_L2) && !wasl2)
+ {
+ go_pos = 0;
+ wasl2 = 1;
+ }
+
+ if((padbuf & PAD_CROSS) && !wascross)
+ {
+ if(((go_address >> ((7-go_pos)<<2))&0xf) < 0xf)
+ go_address += 1 << ((7-go_pos)<<2);
+
+ display_is_old = 1;
+ wascross=1;
+ }
+
+ if((padbuf & PAD_CIRCLE) && !wascircle)
+ {
+ if(((go_address >> ((7-go_pos)<<2))&0xf) > 0)
+ go_address -= 1 << ((7-go_pos)<<2);
+
+ display_is_old = 1;
+ wascircle = 1;
+ }
+
+ if((padbuf & PAD_START) && !wasstart)
+ {
+ cur_addr = go_address;
+ display_is_old = 1;
+ wasstart=1;
+ }
+
+ if((padbuf & PAD_SELECT) && !wasselect)
+ {
+ highres_mode = !highres_mode;
+
+ GsSortCls(0,0,255);
+ GsDrawList();
+ while(GsIsDrawing());
+
+ if(highres_mode)
+ {
+ GsSetVideoModeEx(640, 480, GsScreenM, 0, 1, 0);
+ GsSetDrawEnvSimple(0, (GsScreenM==VMODE_PAL)?8:0, 640, 480);
+ }
+ else
+ {
+ GsSetVideoMode(640, 240, GsScreenM);
+ GsSetDrawEnvSimple(0, (GsScreenM==VMODE_PAL)?8:0, 640, 240);
+ }
+
+ display_is_old = 1;
+ wasselect = 1;
+ }
+
+ if(!(padbuf & PAD_UP) || srp==5)wasup=0;
+ if(!(padbuf & PAD_DOWN) || srp==5)wasdown=0;
+ if(!(padbuf & PAD_LEFT) || srp==5)wasleft=0;
+ if(!(padbuf & PAD_RIGHT) || srp==5)wasright=0;
+ if(!(padbuf & PAD_L1))wasl1=0;
+ if(!(padbuf & PAD_R1))wasr1=0;
+ if(!(padbuf & PAD_L2))wasl2=0;
+ if(!(padbuf & PAD_CROSS) || srp==5)wascross=0;
+ if(!(padbuf & PAD_CIRCLE) || srp==5)wascircle=0;
+ if(!(padbuf & PAD_START)) wasstart=0;
+ if(!(padbuf & PAD_SELECT)) wasselect=0;
+
+ should_read_pad = 0;
+ srp++;
+ if(srp > 5) srp=0;
+ }
+ }
+}
+
+//AAAAAAAA 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF abcd
diff --git a/examples/memview/memview.txt b/examples/memview/memview.txt
new file mode 100644
index 0000000..dd21b57
--- /dev/null
+++ b/examples/memview/memview.txt
@@ -0,0 +1,70 @@
+This is a simple memory viewer for the PlayStation.
+It shows you what is contained at the desired memory addresses in a way similar to that of hex editors.
+
+Obviously it is not as straigthforward to use as similar programs for general purpose computers because the PlayStation lacks a keyboard.
+Also, *remember* that reading certain memory areas will crash the PlayStation hardware, and if that happens the only thing you can do is to reset the console.
+See "Surefire Areas" below for areas which surely won't crash your hardware.
+
+At start, the memory viewer will begin viewing memory at 0x80000000 (start of RAM),
+the resolution will be 640x240 (low-res) and the Go-Address will be 0x80000000.
+
+Terms:
+Go-Address The address that will be used for the
+ "jump-to address" operation
+
+Control:
+UP Decrease current address by 0x10
+DOWN Increase current address by 0x10
+LEFT Decrease current address by 0x100
+RIGHT Increase current address by 0x100
+
+L1 Move to previous location in Go-Address
+R1 Move to next location in Go-Address
+L2 Move to first location in Go-Address
+CROSS Increase nibble at current Go-Address location
+CIRCLE Decrease nibble at current Go-Address location
+
+START Jump to Go-Address,
+ i.e. make the Go-Address the current address
+
+SELECT Switch between hi-res and low-res mode
+ Hi-res mode: 640x480
+ Low-res mode: 640x240 (default)
+
+Surefire areas:
+0x80000000-0x801fffff PlayStation RAM (2 megabytes)
+0xbfc00000-0xbfc7ffff PlayStation BIOS ROM (512 kilobytes)
+
+Example of setting a Go-Address and jumping:
+
+Imagine that the current go-address is 0x80000000 and we want to jump to 0xC001D00D.
+NOTE: A nibble is 4-bits long, and each digit in a hexadecimal number is a nibble.
+
+- Move to the first location in Go-Address -> L2
+- Increase the nibble at current Go-Address location until it is 0xC
+ -> as its current value is 0x8, due to the current go-address being 0x80000000,
+ press CROSS 4 times
+ >> after this operation, the current address is 0xC0000000
+- Move to the next location in Go-Address -> R1
+- The nibble at this location is already 0x0, so move to the next location -> R1
+ >> after this operation, the current address is 0xC0000000
+- The nibble at this location is already 0x0, so move to the next location -> R1
+ >> after this operation, the current address is 0xC0000000
+- Increase the nibble at current Go-Address location until it is 0x1
+ -> as its current value is 0x0, press CROSS once
+ >> after this operation, the current address will be 0xC0010000
+- Move to the next location in Go-Address -> R1
+- Increase the nibble at current Go-Address location until it is 0xD
+ -> as its current value is 0x0, press CROSS 13 times
+ >> after this operation, the current address will be 0xC001D000
+- Move to the next location in Go-Address -> R1
+- The nibble at this location is already 0x0, so move to the next location -> R1
+ >> after this operation, the current address is 0xC001D000
+- The nibble at this location is already 0x0, so move to the next location -> R1
+ >> after this operation, the current address is 0xC001D000
+- Increase the nibble at current Go-Address location until it is 0xD
+ -> as its current value is 0x0, press CROSS 13 times
+ >> after this operation, the current address will be 0xC001D00D
+- Jump to Go-Address -> START
+ >> The current address is now 0xC001D00D
+
diff --git a/examples/project.mk b/examples/project.mk
new file mode 100644
index 0000000..5a72a80
--- /dev/null
+++ b/examples/project.mk
@@ -0,0 +1,18 @@
+# project.mk
+
+include ../../Makefile.cfg
+
+all: $(PROJNAME)_extra
+ mkdir -p cd_root
+ $(EXAMPLES_CC) $(EXAMPLES_CFLAGS) -DEXAMPLES_VMODE=$(EXAMPLES_VMODE) -o $(PROJNAME).elf $(PROJNAME).c \
+ $(EXAMPLES_LIBS) $(PROJ_LIBS) $(EXAMPLES_LDFLAGS)
+ elf2exe $(PROJNAME).elf $(PROJNAME).exe
+ cp $(PROJNAME).exe cd_root
+ systemcnf $(PROJNAME).exe > cd_root/system.cnf
+ $(MKISOFS_COMMAND) -o $(PROJNAME).hsf -V $(PROJNAME) -sysid PLAYSTATION cd_root
+ mkpsxiso $(PROJNAME).hsf $(PROJNAME).bin $(CDLIC_FILE)
+ rm -f $(PROJNAME).hsf
+
+clean: $(PROJNAME)_clean_extra
+ rm -f $(PROJNAME).bin $(PROJNAME).cue $(PROJNAME).exe $(PROJNAME).elf
+ rm -fr cd_root
diff --git a/examples/psxmod/Makefile b/examples/psxmod/Makefile
new file mode 100644
index 0000000..7a410ec
--- /dev/null
+++ b/examples/psxmod/Makefile
@@ -0,0 +1,16 @@
+PROJNAME = psxmod
+PROJ_LIBS = -lmodplay -lm -ladpcm
+
+include ../project.mk
+
+SAMPLES = $(patsubst mods/%.mod, mods/%.smp, $(wildcard mods/*.mod))
+
+$(PROJNAME)_extra: $(SAMPLES)
+ mkdir -p cd_root
+ cp -r mods cd_root
+
+$(PROJNAME)_clean_extra:
+ rm -f mods/*.smp
+
+mods/%.smp: mods/%.mod
+ mod4psx $< $@
diff --git a/examples/psxmod/psxmod.c b/examples/psxmod/psxmod.c
new file mode 100644
index 0000000..f11f164
--- /dev/null
+++ b/examples/psxmod/psxmod.c
@@ -0,0 +1,472 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <psx.h>
+#include <modplay.h>
+
+#if defined(EXAMPLES_VMODE) == VMODE_PAL
+ #define TICKS_PER_SECOND 50
+#else
+ #define TICKS_PER_SECOND 60
+#endif
+
+unsigned char fileBuffer[0x80000]; // 512 kilobytes
+
+unsigned int primList[0x8000];
+int dbuf = 0;
+volatile int display_is_old = 1;
+char current_dir[256] = "cdrom:";
+char name_buf[24];
+char name_buf2[32];
+ModMusic *music = NULL;
+int music_loop;
+char *music_player_fname;
+int music_player_time;
+short music_player_vol;
+int music_player_vol_pc;
+
+GsRectangle prog_rect;
+
+void program_vblank_handler()
+{
+ display_is_old = 1;
+}
+
+struct
+{
+ char name[20];
+ int size;
+ int type; /* 0 = file, 1 = directory */
+}file_list[256];
+
+int file_list_size = 0;
+int file_list_pos = 0;
+
+int wasUp = 0;
+int wasDown = 0;
+int wasEnter = 0;
+int wasLeft = 0;
+int wasRight = 0;
+
+void update_file_list()
+{
+ struct DIRENTRY de;
+ struct DIRENTRY *r;
+ char *cp;
+ int i, k=0;
+
+ if(strcmp(current_dir, "cdrom:") != 0)
+ {
+ strcpy(file_list[0].name, "..");
+ file_list[0].type = 1;
+ k=1;
+ }
+
+ r = firstfile("cdrom:*", &de);
+
+ for(i = k; i < 256 && r; i++)
+ {
+ if(de.name[0] == 0x1)
+ {
+// Throw away useless entry.
+ r = nextfile(&de);
+ i--;
+ continue;
+ }
+
+ memcpy(file_list[i].name, de.name, 20);
+
+ if((cp = strrchr(file_list[i].name, ';')))
+ {
+ *cp = '\0';
+ file_list[i].type = 0;
+ }
+ else
+ file_list[i].type = 1;
+
+ file_list[i].size = de.size;
+
+ r = nextfile(&de);
+ }
+
+ file_list[i].size = -1;
+ file_list_size = i;
+}
+
+void file_browser(int redraw)
+{
+ int i, k, ok, allowed_ext;
+ unsigned short padbuf;
+ char *cp;
+ FILE *f;
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if(wasUp)
+ wasUp++;
+
+ if(wasDown)
+ wasDown++;
+
+ if((padbuf & PAD_UP) && !wasUp)
+ {
+ if(file_list_pos > 0)
+ {
+ file_list_pos--;
+ redraw=1;
+ }
+
+ wasUp=1;
+ }
+
+ if((padbuf & PAD_DOWN) && !wasDown)
+ {
+ file_list_pos++;
+
+ if(file_list[file_list_pos].size == -1)
+ file_list_pos--;
+ else
+ redraw = 1;
+
+ wasDown = 1;
+ }
+
+ if((padbuf & PAD_CROSS) && !wasEnter)
+ {
+ if(file_list[file_list_pos].type == 1)
+ allowed_ext = 1;
+ else
+ allowed_ext = 0;
+
+ if((cp = strchr(file_list[file_list_pos].name, '.')))
+ {
+ if(strcmp(cp+1, "MOD") == 0)
+ allowed_ext = 1;
+ }
+
+ if(allowed_ext)
+ {
+ if(file_list[file_list_pos].type == 0)
+ {
+ if(music != NULL)
+ {
+ MODUnload(music);
+ music = NULL;
+ }
+
+// It is a file, we will play it
+
+// First check if there is a file which contains the
+// samples
+ strcpy(name_buf, file_list[file_list_pos].name);
+
+ if((cp = strchr(name_buf, '.')))
+ *(cp+1) = '\0';
+
+ strcat(name_buf, "SMP");
+
+ ok = 0;
+
+ if(!(padbuf & PAD_SELECT))
+ {
+ for(i = 0; file_list[i].size != -1; i++)
+ {
+ if(strcmp(name_buf, file_list[i].name) == 0)
+ {
+ ok = 1;
+ break;
+ }
+ }
+ }
+
+ if(ok)
+ {
+// We found a sample file
+ printf("Loading sample file for %s...\n",
+ file_list[file_list_pos].name);
+
+ sprintf(name_buf2, "cdrom:%s;1", name_buf);
+ printf("namebuf2=%s\n",name_buf2);
+
+ f = fopen(name_buf2, "rb");
+
+ // printf("SZ = %d\n", file_list[i].size);
+
+ fread(fileBuffer, sizeof(char), file_list[i].size, f);
+ fclose(f);
+
+ memcpy(name_buf, fileBuffer, 8);
+ name_buf[8] = 0;
+
+ MOD4PSX_Upload(fileBuffer, SPU_DATA_BASE_ADDR);
+ }
+ else
+ printf("No sample file found for %s!\n",
+ file_list[file_list_pos].name);
+
+ sprintf(name_buf2, "cdrom:%s;1", file_list[file_list_pos].name);
+
+ f = fopen(name_buf2, "rb");
+
+ fread(fileBuffer, sizeof(char), file_list[file_list_pos].size, f);
+
+ fclose(f);
+
+ music = MODLoadEx(fileBuffer, ok?MODLOAD_NOSAMPLES:0);
+
+ if(!ok)
+ MODUploadSamples(music, SPU_DATA_BASE_ADDR);
+
+ music_player_fname = file_list[file_list_pos].name;
+ music_player_time = 0;
+ music_player_vol = SPU_MAXVOL+1;
+ music_player_vol_pc = 100;
+ MODSetMaxVolume(music_player_vol-1);
+ music_loop = -1;
+ }
+ else
+ {
+// It is a directory, we will go inside it
+ if(strcmp(file_list[file_list_pos].name, "..") == 0)
+ {
+ *(strrchr(current_dir, '\\')) = '\0';
+
+ if(strcmp(current_dir, "cdrom:") == 0)
+ chdir("cdrom:\\");
+ else
+ chdir(current_dir);
+ }
+ else
+ {
+ strcat(current_dir, "\\");
+ strcat(current_dir, file_list[file_list_pos].name);
+ chdir(current_dir);
+ }
+
+ file_list_pos = 0;
+ update_file_list();
+ redraw = 1;
+ }
+ }
+
+ wasEnter = 1;
+ }
+
+ if(!(padbuf & PAD_UP) || wasUp >= 15)
+ wasUp = 0;
+ if(!(padbuf & PAD_DOWN) || wasDown >= 15)
+ wasDown = 0;
+ if(!(padbuf & PAD_CROSS))
+ wasEnter = 0;
+
+ /* Drawing */
+ if(!redraw)
+ return;
+
+
+
+ GsSortCls(0, 0, 0);
+ GsPrintFont(0, 0, "-= PsxMod =-");
+ GsPrintFont(0, 8, "Folder: <root>%s", current_dir + 6);
+ GsPrintFont(0, 16, "X to play, hold SELECT to convert SFX");
+
+ k=0;
+
+ if(file_list_size > 24)
+ {
+ if(file_list_pos > 12)
+ {
+ k = file_list_pos - 12;
+
+ if(k > (file_list_size - 26))
+ k = file_list_size - 26;
+ }
+ }
+
+ prog_rect.x = 0;
+ prog_rect.y = 32 + ((file_list_pos-k) * 8);
+ prog_rect.w = GsScreenW / 2;
+ prog_rect.h = 8;
+ prog_rect.r = 0;
+ prog_rect.g = 0;
+ prog_rect.b = 255;
+ prog_rect.attribute = 0;
+ GsSortRectangle(&prog_rect);
+
+ for(i = 0; file_list[i+k].size != -1; i++)
+ {
+ if(file_list[i+k].type == 1)
+ GsPrintFont(0, 32 + (i * 8), " +- %s", file_list[i+k].name);
+ else
+ GsPrintFont(0, 32 + (i * 8), " %s", file_list[i+k].name);
+ }
+
+ GsDrawList();
+
+ dbuf = !dbuf;
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+}
+
+void music_player_draw()
+{
+ unsigned short padbuf;
+ static int old_song_pos = 10000;
+ int change_vol = 0;
+
+ GsSortCls(0, 0, 0);
+ GsPrintFont(0, 0, "-= PsxMod =-");
+ GsPrintFont(0, 8, "File: %s", music_player_fname);
+ GsPrintFont(0, 16, "Title: %s", music->title);
+ GsPrintFont(0, 24, "pat:%03d/%03d pos:%02X spd:%d/%d",
+ music->song_pos, music->song_pos_num - 1, music->pat_pos,
+ music->ticks_division, music->beats_minute);
+
+ GsPrintFont(0, 32, "vol: %03d%%/100%% time: %d:%02d chn: %d",
+ music_player_vol_pc, music_player_time / (TICKS_PER_SECOND * 60),
+ (music_player_time % (TICKS_PER_SECOND * 60) ) / TICKS_PER_SECOND,
+ music->channel_num);
+
+ GsPrintFont(0, 56, "Press X to change music.");
+
+ dbuf = !dbuf;
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+ GsDrawList();
+
+ if(old_song_pos > music->song_pos)
+ music_player_time = 0;
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if(padbuf & PAD_UP)
+ {
+ music_player_vol+=32;
+ change_vol = 1;
+ }
+
+ if(padbuf & PAD_DOWN)
+ {
+ music_player_vol-=32;
+ change_vol = 1;
+ }
+
+ if(padbuf & PAD_LEFT)
+ {
+ if(!wasLeft)
+ {
+ music->pat_pos = 0;
+
+ if(music->song_pos > 0)
+ music->song_pos--;
+ }
+
+ wasLeft++;
+ }
+
+ if(padbuf & PAD_RIGHT)
+ {
+ if(!wasRight)
+ {
+ music->pat_pos = 0;
+
+ if(music->song_pos < (music->song_pos_num - 1))
+ music->song_pos++;
+ else
+ music->song_pos = 0;
+ }
+
+ wasRight++;
+ }
+
+ if(!(padbuf & PAD_LEFT) || wasLeft >= 15)
+ wasLeft = 0;
+
+ if(!(padbuf & PAD_RIGHT) || wasRight >= 15)
+ wasRight = 0;
+
+ if((padbuf & PAD_CROSS) && !wasEnter)
+ {
+ MODStop(music);
+ MODUnload(music);
+ music = NULL;
+ wasEnter = 1;
+ }
+
+ if(!(padbuf & PAD_CROSS))
+ wasEnter = 0;
+
+ if(music_player_vol < 0)
+ music_player_vol = 0;
+
+ if(music_player_vol > (SPU_MAXVOL+1))
+ music_player_vol = SPU_MAXVOL+1;
+
+ if(change_vol)
+ {
+ music_player_vol_pc = (int)((float)100 * ((float)music_player_vol / (float)(SPU_MAXVOL+1)));
+ MODSetMaxVolume((music_player_vol == 0)?0:(music_player_vol-1));
+ }
+
+ music_player_time++;
+
+ old_song_pos = music->song_pos;
+}
+
+int main()
+{
+ int redraw=1;
+ FILE *f;
+
+ PSX_Init();
+ GsInit();
+ SsInit();
+
+ GsClearMem();
+ GsSetAutoWait();
+ GsSetList(primList);
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+ GsLoadFont(768, 0, 768, 256);
+
+ SetVBlankHandler(program_vblank_handler);
+
+// Open any existing file before calling firstfile() for the first time.
+// If before calling firstfile() for the first time, you have never called open() on an existing file before,
+// every subsequent read will fail but it will report that files are opened ok!
+// This bug happens at least with the SCPH1001 BIOS version.
+// We try to open PSX.EXE and SYSTEM.CNF, as one of them must exist in order to boot from CDROM.
+
+ f = fopen("cdrom:PSX.EXE;1", "rb");
+ if(f)fclose(f);
+
+ f = fopen("cdrom:SYSTEM.CNF;1", "rb");
+ if(f)fclose(f);
+
+ update_file_list();
+
+ dbuf = !dbuf;
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+
+ while(1)
+ {
+ if(display_is_old)
+ {
+ /* Update music */
+ if(music)
+ {
+ redraw = 1;
+ MODPlay(music, &music_loop);
+ music_player_draw();
+ }
+ else
+ {
+ file_browser(redraw);
+ redraw=0;
+ }
+
+ display_is_old = 0;
+ }
+ }
+}
diff --git a/examples/psxpaint/Makefile b/examples/psxpaint/Makefile
new file mode 100644
index 0000000..d1d5698
--- /dev/null
+++ b/examples/psxpaint/Makefile
@@ -0,0 +1,7 @@
+PROJNAME = psxpaint
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/psxpaint/cursor.h b/examples/psxpaint/cursor.h
new file mode 100644
index 0000000..4f1a9cf
--- /dev/null
+++ b/examples/psxpaint/cursor.h
@@ -0,0 +1,20 @@
+unsigned char cursor_tim[] =
+{
+16, 0, 0, 0, 8, 0, 0, 0, 44, 0, 0, 0, 128, 2, 224, 1,
+16, 0, 1, 0,
+0, 0, 0, 128, 255, 127, 0, 128, 0, 128, 0, 128,
+0, 128, 0, 128, 0, 128, 0, 128, 0, 8, 0, 128, 64, 16, 0, 128,
+64, 16, 0, 128, 204, 0, 0, 0, 128, 2, 0, 0, 4, 0, 24, 0,
+1, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0,
+33, 1, 0, 0, 0, 0, 0, 0, 33, 18, 0, 0, 0, 0, 0, 0,
+33, 34, 1, 0, 0, 0, 0, 0, 33, 34, 18, 0, 0, 0, 0, 0,
+33, 34, 34, 1, 0, 0, 0, 0, 33, 34, 34, 18, 0, 0, 0, 0,
+33, 34, 34, 34, 1, 0, 0, 0, 33, 34, 34, 34, 18, 0, 0, 0,
+33, 34, 34, 34, 34, 1, 0, 0, 33, 34, 34, 18, 17, 17, 0, 0,
+33, 34, 33, 18, 0, 0, 0, 0, 33, 18, 33, 18, 0, 0, 0, 0,
+33, 1, 16, 34, 1, 0, 0, 0, 17, 0, 16, 34, 1, 0, 0, 0,
+1, 0, 0, 33, 18, 0, 0, 0, 0, 0, 0, 33, 18, 0, 0, 0,
+0, 0, 0, 16, 34, 1, 0, 0, 0, 0, 0, 16, 34, 1, 0, 0,
+0, 0, 0, 0, 17, 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,
+};
diff --git a/examples/psxpaint/psxpaint.c b/examples/psxpaint/psxpaint.c
new file mode 100644
index 0000000..726b13b
--- /dev/null
+++ b/examples/psxpaint/psxpaint.c
@@ -0,0 +1,371 @@
+/*
+ * PSXPaint
+ */
+
+/*
+ * Video memory layout:
+ *
+ * [0-639],[0-479] - Screen memory
+ * [640-895],[480-511] - Color Look Up Tables
+ * [640-643],[0-23] - Cursor Image (16x24) (4bpp - real width: 16)
+ * [992-1023],[0-31] - Cursor Dirty Rectangle (32x32)
+ */
+
+#include <stdio.h>
+#include <psx.h>
+#include <psxgpu.h>
+#include "cursor.h"
+
+int cursor_x = 0, cursor_y = 0, cursor_speed = 1;
+int old_cursor_x, old_cursor_y;
+volatile unsigned int speed_counter = 0;
+int brush_type = 0;
+
+unsigned int primitive_list[4000];
+
+int paint_colors[20][3] = {
+ { 0, 0, 0 }, // #0 Black
+ { 255, 255, 255 }, // #1 White
+ { 255, 0, 0 }, // #2 Red
+ { 0, 255, 0 }, // #3 Green
+ { 0, 0, 255 }, // #4 Blue
+ { 255, 255, 0}, // #5 Yellow
+ { 255, 0, 255}, // #6 Magenta (Fuchsia)
+ { 0, 255, 255}, // #7 Aqua Green
+ { 255, 128, 0}, // #8 Orange
+ { 128, 255,0}, // #9 Lime Green
+
+ { 192, 192,255},// #10 Sky Blue
+ { 128,128,128}, // #11 Grey
+ { 128, 0,0 }, // #12 Dark Red
+ { 0, 128, 0}, // #13 Dark Green
+ { 0, 0, 128}, // #14 Dark Blue
+ { 128, 128, 0}, // #15 Dark Yellow
+ { 128, 0, 128}, // #16 Purple
+ { 0, 128, 128}, // #17 Dark Aqua
+ { 128, 64, 0}, // #18 Brown
+ { 64, 128, 0}, // #19 Dark Lime Green
+
+ /*{ 128, 0, 255}, // #10 Violet
+ { 128,128,128}, // #11 Grey
+ { 128, 0,0 }, // #12 Dark Red
+ { 0, 128, 0}, // #13 Dark Green
+ { 0, 0, 128}, // #14 Dark Blue
+ { 192, 192,255},// #15 Sky Blue
+ { 128, 128, 0}, // #16 Dark Yellow
+ { 150, 75, 0}, // #17 Brown
+ { 64, 64, 64}, // #18 Dark Grey
+ { 128, 255,0}, // #19 Lime Green
+ */
+};
+
+int current_color[3];
+
+void sort_color_boxes()
+{
+ GsRectangle colorbox;
+ int x, y, c=0;
+
+ for(y = 384; y < (384+32); y+=16)
+ {
+ for(x = 0; x < 640; x+=64)
+ {
+ colorbox.x = x;
+ colorbox.y = y;
+ colorbox.w = 64;
+ colorbox.h = 16;
+ colorbox.r = paint_colors[c][0];
+ colorbox.g = paint_colors[c][1];
+ colorbox.b = paint_colors[c][2];
+ colorbox.attribute = 0;
+
+ GsSortRectangle(&colorbox);
+
+ c++;
+ }
+ }
+}
+
+void load_ui_graphics()
+{
+ GsImage my_image;
+
+ GsImageFromTim(&my_image, cursor_tim);
+ GsUploadImage(&my_image);
+}
+
+void my_vblank_handler();
+
+void my_vblank_handler()
+{
+ speed_counter++;
+}
+
+int main()
+{
+ GsDispEnv my_dispenv;
+ GsDrawEnv my_drawenv;
+ GsSprite my_sprite;
+ GsRectangle colorbox;
+ GsDot my_dot;
+ unsigned short pad1;
+ unsigned int WasL2=0, WasR2=0, WasL1=0, WasR1=0, WasSelect = 0;
+ int x, y;
+
+ PSX_InitEx(PSX_INIT_NOBIOS);
+ GsInit();
+ GsClearMem();
+ SetVBlankHandler(my_vblank_handler);
+
+ // This has to be interlaced
+ GsSetVideoModeEx(640, 480, EXAMPLES_VMODE, 0, 1, 0);
+
+ my_dispenv.x = 0;
+ my_dispenv.y = 0;
+
+ GsSetDispEnv(&my_dispenv);
+
+ my_drawenv.dither = 0;
+ my_drawenv.draw_on_display = 1;
+ my_drawenv.x = 0;
+ my_drawenv.y = 0;
+ my_drawenv.w = 640;
+ my_drawenv.h = 512;
+ my_drawenv.ignore_mask = 0;
+ my_drawenv.set_mask = 0;
+
+ GsSetDrawEnv(&my_drawenv);
+
+ GsSetList(primitive_list);
+
+ load_ui_graphics();
+ while(GsIsDrawing());
+
+ colorbox.x = 0;
+ colorbox.y = 0;
+ colorbox.w = 640;
+ colorbox.h = 511;
+ colorbox.r = 255;
+ colorbox.g = 255;
+ colorbox.b = 255;
+ colorbox.attribute = 0;
+
+ GsSortRectangle(&colorbox);
+
+ sort_color_boxes();
+
+
+ my_sprite.x = 0;
+ my_sprite.y = 0;
+ my_sprite.tpage = 10;
+ my_sprite.u = 0;
+ my_sprite.v = 0;
+ my_sprite.attribute = 0;
+ my_sprite.cx = 640;
+ my_sprite.cy = 480;
+ my_sprite.r = my_sprite.g = my_sprite.b = NORMAL_LUMINOSITY;
+ my_sprite.scalex = my_sprite.scaley = 0;
+ my_sprite.w = 16;
+ my_sprite.h = 24;
+
+ GsDrawList();
+ while(GsIsDrawing());
+
+ // Backup 32x32 area
+ MoveImage(cursor_x, cursor_y, 992, 0, 32, 32);
+
+ my_dot.attribute = 0;
+
+ while(1)
+ {
+ while(speed_counter)
+ {
+ old_cursor_x = cursor_x;
+ old_cursor_y = cursor_y;
+
+ // Restore 32x32 area
+ MoveImage(992, 0, old_cursor_x, old_cursor_y, 32, 32);
+ while(GsIsDrawing());
+
+ PSX_ReadPad(&pad1, NULL);
+
+ if(pad1 & PAD_LEFT)
+ cursor_x-=cursor_speed;
+
+ if(pad1 & PAD_RIGHT)
+ cursor_x+=cursor_speed;
+
+ if(pad1 & PAD_UP)
+ cursor_y-=cursor_speed;
+
+ if(pad1 & PAD_DOWN)
+ cursor_y+=cursor_speed;
+
+ if(cursor_x <= 0)
+ cursor_x = 0;
+
+ if(pad1 & PAD_CROSS)
+ {
+ if(cursor_y >= 384)
+ {
+ y = (cursor_y - 384) >> 4;
+ x = cursor_x >> 6;
+
+ current_color[0] = paint_colors[(y * 10)+x][0];
+ current_color[1] = paint_colors[(y * 10)+x][1];
+ current_color[2] = paint_colors[(y * 10)+x][2];
+ }
+ else
+ {
+
+ switch(brush_type)
+ {
+ case 0:
+ if(cursor_y >= 384)
+ {
+ break;
+ }
+
+ my_dot.r = current_color[0];
+ my_dot.g = current_color[1];
+ my_dot.b = current_color[2];
+ my_dot.x = cursor_x;
+ my_dot.y = cursor_y;
+
+ GsSortDot(&my_dot);
+ break;
+ case 1:
+ if(cursor_y >= 380)
+ {
+ break;
+ }
+
+ my_dot.r = current_color[0];
+ my_dot.g = current_color[1];
+ my_dot.b = current_color[2];
+ my_dot.x = cursor_x + 1;
+ my_dot.y = cursor_y;
+
+ GsSortDot(&my_dot);
+
+ my_dot.x++;
+
+ GsSortDot(&my_dot);
+
+ my_dot.y++;
+ my_dot.x-=2;
+
+ GsSortDot(&my_dot);
+
+ my_dot.x++;
+
+ GsSortDot(&my_dot);
+
+ my_dot.x++;
+
+ GsSortDot(&my_dot);
+
+ my_dot.x++;
+
+ GsSortDot(&my_dot);
+
+ my_dot.y++;
+ my_dot.x-=2;
+
+ GsSortDot(&my_dot);
+
+ my_dot.x++;
+
+ GsSortDot(&my_dot);
+ break;
+ }
+
+ }
+
+ GsDrawList();
+ while(GsIsDrawing());
+ }
+
+ if((pad1 & PAD_R2) && !WasR2)
+ {
+ cursor_speed++;
+ WasR2 = 1;
+ }
+
+ if((pad1 & PAD_L2) && !WasL2)
+ {
+ cursor_speed--;
+ WasL2 = 1;
+ }
+
+ if(!(pad1 & PAD_R2))
+ WasR2 = 0;
+
+ if(!(pad1 & PAD_L2))
+ WasL2 = 0;
+
+ if((pad1 & PAD_R1) && !WasR1)
+ {
+ brush_type++;
+ WasR1 = 1;
+ }
+
+ if((pad1 & PAD_L1) && !WasL1)
+ {
+ brush_type--;
+ WasL1 = 1;
+ }
+
+ if((pad1 & PAD_SELECT) && !WasSelect)
+ {
+ my_sprite.attribute ^= (ENABLE_TRANS | TRANS_MODE(0));
+ my_dot.attribute ^= (ENABLE_TRANS | TRANS_MODE(0));
+ WasSelect = 1;
+ }
+
+ if(!(pad1 & PAD_SELECT))
+ WasSelect = 0;
+
+ if(!(pad1 & PAD_R1))
+ WasR1 = 0;
+
+ if(!(pad1 & PAD_L1))
+ WasL1 = 0;
+
+ if(cursor_speed <= 0)
+ cursor_speed = 1;
+
+ if(cursor_speed >= 8)
+ cursor_speed = 7;
+
+ if(brush_type <= 0)
+ brush_type = 0;
+
+ if(brush_type > 1)
+ brush_type = 1;
+
+ // Backup 32x32 area
+ MoveImage(cursor_x, cursor_y, 992, 0, 32, 32);
+ while(GsIsDrawing());
+
+ // if(cursor_x != old_cursor_x || cursor_y != old_cursor_y)
+ // {
+ // printf("cx = %d, cy = %d, cursor_speed = %d, brush_type = %d\n",
+ // cursor_x, cursor_y, cursor_speed, brush_type);
+
+
+
+
+
+ my_sprite.x = cursor_x;
+ my_sprite.y = cursor_y;
+ GsSortSimpleSprite(&my_sprite);
+
+ GsDrawList();
+ while(GsIsDrawing());
+ // }
+
+ speed_counter--;
+ }
+ }
+}
diff --git a/examples/psxs3m/Makefile b/examples/psxs3m/Makefile
new file mode 100644
index 0000000..81465be
--- /dev/null
+++ b/examples/psxs3m/Makefile
@@ -0,0 +1,10 @@
+PROJNAME = psxs3m
+PROJ_LIBS = -lf3m
+
+include ../project.mk
+
+$(PROJNAME)_extra: $(SAMPLES)
+ mkdir -p cd_root
+ cp -r mods cd_root
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/psxs3m/mods/mario2_2.s3m b/examples/psxs3m/mods/mario2_2.s3m
new file mode 100644
index 0000000..96220e9
--- /dev/null
+++ b/examples/psxs3m/mods/mario2_2.s3m
Binary files differ
diff --git a/examples/psxs3m/mods/mario3.s3m b/examples/psxs3m/mods/mario3.s3m
new file mode 100644
index 0000000..2d2cabc
--- /dev/null
+++ b/examples/psxs3m/mods/mario3.s3m
Binary files differ
diff --git a/examples/psxs3m/psxs3m.c b/examples/psxs3m/psxs3m.c
new file mode 100644
index 0000000..9fe677f
--- /dev/null
+++ b/examples/psxs3m/psxs3m.c
@@ -0,0 +1,412 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <psx.h>
+#include <f3m.h>
+
+#if defined(EXAMPLES_VMODE) == VMODE_PAL
+ #define TICKS_PER_SECOND 50
+#else
+ #define TICKS_PER_SECOND 60
+#endif
+
+unsigned int primList[0x8000];
+int dbuf = 0;
+volatile int display_is_old = 1;
+char current_dir[256] = "cdrom:";
+char name_buf[24];
+char name_buf2[32];
+mod_s *music = NULL;
+player_s player;
+int music_loop;
+char *music_player_fname;
+int music_player_time;
+short music_player_vol;
+int music_player_vol_pc;
+
+GsRectangle prog_rect;
+
+void program_vblank_handler()
+{
+ display_is_old = 1;
+}
+
+struct
+{
+ char name[20];
+ int size;
+ int type; /* 0 = file, 1 = directory */
+}file_list[256];
+
+int file_list_size = 0;
+int file_list_pos = 0;
+
+int wasUp = 0;
+int wasDown = 0;
+int wasEnter = 0;
+int wasLeft = 0;
+int wasRight = 0;
+
+void update_file_list()
+{
+ struct DIRENTRY de;
+ struct DIRENTRY *r;
+ char *cp;
+ int i, k=0;
+
+ if(strcmp(current_dir, "cdrom:") != 0)
+ {
+ strcpy(file_list[0].name, "..");
+ file_list[0].type = 1;
+ k=1;
+ }
+
+ r = firstfile("cdrom:*", &de);
+
+ for(i = k; i < 256 && r; i++)
+ {
+ if(de.name[0] == 0x1)
+ {
+// Throw away useless entry.
+ r = nextfile(&de);
+ i--;
+ continue;
+ }
+
+ memcpy(file_list[i].name, de.name, 20);
+
+ if((cp = strrchr(file_list[i].name, ';')))
+ {
+ *cp = '\0';
+ file_list[i].type = 0;
+ }
+ else
+ file_list[i].type = 1;
+
+ file_list[i].size = de.size;
+
+ r = nextfile(&de);
+ }
+
+ file_list[i].size = -1;
+ file_list_size = i;
+}
+
+void file_browser(int redraw)
+{
+ int i, k, allowed_ext;
+ unsigned short padbuf;
+ char *cp;
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if(wasUp)
+ wasUp++;
+
+ if(wasDown)
+ wasDown++;
+
+ if((padbuf & PAD_UP) && !wasUp)
+ {
+ if(file_list_pos > 0)
+ {
+ file_list_pos--;
+ redraw=1;
+ }
+
+ wasUp=1;
+ }
+
+ if((padbuf & PAD_DOWN) && !wasDown)
+ {
+ file_list_pos++;
+
+ if(file_list[file_list_pos].size == -1)
+ file_list_pos--;
+ else
+ redraw = 1;
+
+ wasDown = 1;
+ }
+
+ if((padbuf & PAD_CROSS) && !wasEnter)
+ {
+ if(file_list[file_list_pos].type == 1)
+ allowed_ext = 1;
+ else
+ allowed_ext = 0;
+
+ if((cp = strchr(file_list[file_list_pos].name, '.')))
+ {
+ if(strcmp(cp+1, "S3M") == 0)
+ allowed_ext = 1;
+ }
+
+ if(allowed_ext)
+ {
+ if(file_list[file_list_pos].type == 0)
+ {
+ if(music != NULL)
+ {
+ f3m_mod_free(music);
+ music = NULL;
+ }
+
+// It is a file, we will play it
+ sprintf(name_buf2, "cdrom:%s;1", file_list[file_list_pos].name);
+
+ music = f3m_mod_load_filename(name_buf2);
+ f3m_player_init(&player, music);
+
+ music_player_fname = file_list[file_list_pos].name;
+ music_player_time = 0;
+ music_player_vol = SPU_MAXVOL+1;
+ music_player_vol_pc = 100;
+
+ f3m_set_max_volume(&player, music_player_vol-1);
+
+ music_loop = -1;
+ }
+ else
+ {
+// It is a directory, we will go inside it
+ if(strcmp(file_list[file_list_pos].name, "..") == 0)
+ {
+ *(strrchr(current_dir, '\\')) = '\0';
+
+ if(strcmp(current_dir, "cdrom:") == 0)
+ chdir("cdrom:\\");
+ else
+ chdir(current_dir);
+ }
+ else
+ {
+ strcat(current_dir, "\\");
+ strcat(current_dir, file_list[file_list_pos].name);
+ chdir(current_dir);
+ }
+
+ file_list_pos = 0;
+ update_file_list();
+ redraw = 1;
+ }
+ }
+
+ wasEnter = 1;
+ }
+
+ if(!(padbuf & PAD_UP) || wasUp >= 15)
+ wasUp = 0;
+ if(!(padbuf & PAD_DOWN) || wasDown >= 15)
+ wasDown = 0;
+ if(!(padbuf & PAD_CROSS))
+ wasEnter = 0;
+
+ /* Drawing */
+ if(!redraw)
+ return;
+
+
+
+ GsSortCls(0, 0, 0);
+ GsPrintFont(0, 0, "-= PsxS3M =-");
+ GsPrintFont(0, 8, "Folder: <root>%s", current_dir + 6);
+ GsPrintFont(0, 16, "X to play, hold SELECT to convert SFX");
+
+ k=0;
+
+ if(file_list_size > 24)
+ {
+ if(file_list_pos > 12)
+ {
+ k = file_list_pos - 12;
+
+ if(k > (file_list_size - 26))
+ k = file_list_size - 26;
+ }
+ }
+
+ prog_rect.x = 0;
+ prog_rect.y = 32 + ((file_list_pos-k) * 8);
+ prog_rect.w = GsScreenW / 2;
+ prog_rect.h = 8;
+ prog_rect.r = 0;
+ prog_rect.g = 0;
+ prog_rect.b = 255;
+ prog_rect.attribute = 0;
+ GsSortRectangle(&prog_rect);
+
+ for(i = 0; file_list[i+k].size != -1; i++)
+ {
+ if(file_list[i+k].type == 1)
+ GsPrintFont(0, 32 + (i * 8), " +- %s", file_list[i+k].name);
+ else
+ GsPrintFont(0, 32 + (i * 8), " %s", file_list[i+k].name);
+ }
+
+ GsDrawList();
+
+ dbuf = !dbuf;
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+}
+
+void music_player_draw()
+{
+ unsigned short padbuf;
+ static int old_song_pos = 10000;
+ int change_vol = 0;
+
+ GsSortCls(0, 0, 0);
+ GsPrintFont(0, 0, "-= PsxS3M =-");
+ GsPrintFont(0, 8, "File: %s", music_player_fname);
+ GsPrintFont(0, 16, "Title: %s", music->name);
+ GsPrintFont(0, 24, "ord:%03d/%03d pat:%03d/%03d pos:%02X spd:%d/%d",
+ player.cord, music->ord_num - 1, player.cpat, music->pat_num - 1, player.crow,
+ music->ispeed, music->itempo);
+ GsPrintFont(0, 32, "vol: %03d%%/100%% time: %d:%02d",
+ music_player_vol_pc, music_player_time / (TICKS_PER_SECOND * 60),
+ (music_player_time % (TICKS_PER_SECOND * 60) ) / TICKS_PER_SECOND);
+
+ GsPrintFont(0, 56, "Press X to change music.");
+
+ dbuf = !dbuf;
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+ GsDrawList();
+
+ if(old_song_pos > player.cord)
+ music_player_time = 0;
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if(padbuf & PAD_UP)
+ {
+ music_player_vol+=32;
+ change_vol = 1;
+ }
+
+ if(padbuf & PAD_DOWN)
+ {
+ music_player_vol-=32;
+ change_vol = 1;
+ }
+
+ if(padbuf & PAD_LEFT)
+ {
+ if(!wasLeft)
+ {
+ player.crow = 0;
+ player.cord--;
+ player.crow = 64;
+
+ if(player.cord > -1)
+ player.cord--;
+ }
+
+ wasLeft++;
+ }
+
+ if(padbuf & PAD_RIGHT)
+ {
+ if(!wasRight)
+ {
+ player.crow = 64;
+ }
+
+ wasRight++;
+ }
+
+ if(!(padbuf & PAD_LEFT) || wasLeft >= 15)
+ wasLeft = 0;
+
+ if(!(padbuf & PAD_RIGHT) || wasRight >= 15)
+ wasRight = 0;
+
+ if((padbuf & PAD_CROSS) && !wasEnter)
+ {
+ f3m_player_stop(&player);
+ f3m_mod_free(music);
+ music = NULL;
+
+ wasEnter = 1;
+ }
+
+ if(!(padbuf & PAD_CROSS))
+ wasEnter = 0;
+
+ if(music_player_vol < 0)
+ music_player_vol = 0;
+
+ if(music_player_vol > (SPU_MAXVOL+1))
+ music_player_vol = SPU_MAXVOL+1;
+
+ if(change_vol)
+ {
+ music_player_vol_pc = (int)((float)100 * ((float)music_player_vol / (float)(SPU_MAXVOL+1)));
+ f3m_set_max_volume(&player, (music_player_vol == 0)?0:(music_player_vol-1));
+ }
+
+ music_player_time++;
+
+ old_song_pos = player.cord;
+}
+
+int main()
+{
+ int redraw=1;
+ FILE *f;
+
+ PSX_Init();
+ GsInit();
+ SsInit();
+
+ GsClearMem();
+ GsSetAutoWait();
+ GsSetList(primList);
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+ GsLoadFont(768, 0, 768, 256);
+
+ SetVBlankHandler(program_vblank_handler);
+
+// Open any existing file before calling firstfile() for the first time.
+// If before calling firstfile() for the first time, you have never called open() on an existing file before,
+// every subsequent read will fail but it will report that files are opened ok!
+// This bug happens at least with the SCPH1001 BIOS version.
+// We try to open PSX.EXE and SYSTEM.CNF, as one of them must exist in order to boot from CDROM.
+
+ f = fopen("cdrom:PSX.EXE;1", "rb");
+ if(f)fclose(f);
+
+ f = fopen("cdrom:SYSTEM.CNF;1", "rb");
+ if(f)fclose(f);
+
+ update_file_list();
+
+ dbuf = !dbuf;
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+
+ while(1)
+ {
+ if(display_is_old)
+ {
+ /* Update music */
+ if(music)
+ {
+ redraw = 1;
+ f3m_player_play(&player);
+ // MODPlay(music, &music_loop);
+ music_player_draw();
+ }
+ else
+ {
+ file_browser(redraw);
+ redraw=0;
+ }
+
+ display_is_old = 0;
+ }
+ }
+}
diff --git a/examples/psxsnake/Makefile b/examples/psxsnake/Makefile
new file mode 100644
index 0000000..033e1bc
--- /dev/null
+++ b/examples/psxsnake/Makefile
@@ -0,0 +1,12 @@
+PROJNAME = psxsnake
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+ $(MAKE_COMMAND) -C data
+ mkdir -p cd_root
+ cp data/*.tim cd_root
+ cp data/*.raw cd_root
+
+$(PROJNAME)_clean_extra:
+ $(MAKE_COMMAND) -C data clean
diff --git a/examples/psxsnake/data/Makefile b/examples/psxsnake/data/Makefile
new file mode 100644
index 0000000..da14ec1
--- /dev/null
+++ b/examples/psxsnake/data/Makefile
@@ -0,0 +1,21 @@
+include ../../../Makefile.cfg
+
+data: backgrnd.tim font.tim music.raw bomb.raw apple.raw
+
+backgrnd.tim: backgrnd.bmp
+ bmp2tim backgrnd.bmp backgrnd.tim 16 -org=320,0
+
+font.tim: font.bmp
+ bmp2tim font.bmp font.tim 4 -org=640,0
+
+music.raw: music.wav
+ wav2vag music.wav music.raw -L -raw
+
+bomb.raw: bomb.wav
+ wav2vag bomb.wav bomb.raw -raw
+
+apple.raw: apple.wav
+ wav2vag apple.wav apple.raw -raw
+
+clean:
+ rm -f *.tim *.raw
diff --git a/examples/psxsnake/data/apple.txt b/examples/psxsnake/data/apple.txt
new file mode 100644
index 0000000..dbcfc27
--- /dev/null
+++ b/examples/psxsnake/data/apple.txt
@@ -0,0 +1,14 @@
+File:
+ Name: "Apple_Crunch_16.wav"
+ Url: http://www.freesound.org/samplesViewSingle.php?id=20279
+ Date of upload: 2006-06-28 11:44:45
+
+Designer / Creator / Uploader:
+ Name: "Koops"
+ Url: http://www.freesound.org/usersViewSingle.php?id=29508
+
+Description:
+ By "Koops" : 16/18 Apple related eating noises. Recorded in my studio with a matched pair of Rode NT5\'s in the XY configuration. Stereo, WAV, 44.1KHz, 16Bit, Unprocessed.
+
+Tags:
+ apple bite crunch eating food snack squelch \ No newline at end of file
diff --git a/examples/psxsnake/data/apple.wav b/examples/psxsnake/data/apple.wav
new file mode 100644
index 0000000..2643783
--- /dev/null
+++ b/examples/psxsnake/data/apple.wav
Binary files differ
diff --git a/examples/psxsnake/data/backgrnd.bmp b/examples/psxsnake/data/backgrnd.bmp
new file mode 100644
index 0000000..d70e1eb
--- /dev/null
+++ b/examples/psxsnake/data/backgrnd.bmp
Binary files differ
diff --git a/examples/psxsnake/data/bomb.wav b/examples/psxsnake/data/bomb.wav
new file mode 100644
index 0000000..a3935e0
--- /dev/null
+++ b/examples/psxsnake/data/bomb.wav
Binary files differ
diff --git a/examples/psxsnake/data/font.bmp b/examples/psxsnake/data/font.bmp
new file mode 100644
index 0000000..070704c
--- /dev/null
+++ b/examples/psxsnake/data/font.bmp
Binary files differ
diff --git a/examples/psxsnake/data/music.wav b/examples/psxsnake/data/music.wav
new file mode 100644
index 0000000..ae5c8df
--- /dev/null
+++ b/examples/psxsnake/data/music.wav
Binary files differ
diff --git a/examples/psxsnake/psxsnake.c b/examples/psxsnake/psxsnake.c
new file mode 100644
index 0000000..c4260b2
--- /dev/null
+++ b/examples/psxsnake/psxsnake.c
@@ -0,0 +1,666 @@
+/*
+ * Snake clone for the PSX
+ */
+
+#include <psx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int vmode;
+volatile int speed_counter = 0;
+volatile int screen_old = 0;
+
+int snake_array[29][40];
+int scc = 0;
+int vibration_cntdown = 0;
+
+int snake_size = 3;
+int game_over = 0;
+
+int rectangle_mode = 0;
+int l1_pressed = 0;
+
+int level_number = 1;
+int score = 0;
+volatile int seed_counter = 0;
+
+int sample_pos[3]; // 0 = music, 1 = collision, 2 = apple
+
+unsigned int game_draw_list[0x4000]; /* 128 kilobytes */
+
+enum
+{
+ SNAKE_DIR_LEFT, SNAKE_DIR_RIGHT, SNAKE_DIR_UP, SNAKE_DIR_DOWN
+};
+
+int snake_dir = SNAKE_DIR_RIGHT;
+
+unsigned char file_buffer[0x30000]; /* 192 kilobytes */
+
+void game_init();
+void game_vblank_handler();
+void game_run();
+void game_run_gameover();
+int pal_or_ntsc_selection();
+int main();
+int check_snake_collision(int x, int y);
+int load_file_into_buffer(char *fname);
+void game_print(char *string, int x, int y);
+void game_center_print(char *string, int x, int y);
+void setup_snake_field();
+void game_setup();
+
+GsDrawEnv game_drawenv;
+GsDispEnv game_dispenv;
+
+GsImage game_image;
+GsSprite game_sprite;
+GsRectangle game_rect;
+
+unsigned short game_clut[16];
+
+char string_buf[256];
+
+int cross_pressed = 0;
+int circle_pressed = 0;
+
+void game_init()
+{
+// Initialize the PSXSDK library
+ PSX_Init();
+
+// Initialize graphics
+ GsInit();
+
+// Clear video memory
+ GsClearMem();
+
+// Set up drawing environment
+ game_drawenv.dither = 0;
+ game_drawenv.draw_on_display = 0;
+ game_drawenv.x = 0;
+ game_drawenv.y = 0;
+ game_drawenv.w = 320;
+ game_drawenv.h = 240;
+ game_drawenv.ignore_mask = 0;
+ game_drawenv.set_mask = 0;
+
+ GsSetDrawEnv(&game_drawenv);
+
+// Set up display environment
+ game_dispenv.x = 0;
+ game_dispenv.y = 256;
+
+ GsSetDispEnv(&game_dispenv);
+
+// Set drawing list
+ GsSetList(game_draw_list);
+
+// Initialize sound
+ SsInit();
+
+
+}
+
+void game_vblank_handler()
+{
+ speed_counter++;
+ seed_counter++;
+ screen_old = 1;
+}
+
+int pal_or_ntsc_selection()
+{
+ unsigned short padbuf;
+ int x;
+
+ game_drawenv.draw_on_display = 1;
+ x = game_drawenv.y;
+ game_drawenv.y = game_dispenv.y;
+ GsSetDrawEnv(&game_drawenv);
+
+ game_rect.x = 0;
+ game_rect.y = 0;
+ game_rect.w = 320;
+ game_rect.h = 240;
+ game_rect.r = 0;
+ game_rect.g = 0;
+ game_rect.b = 0;
+ game_rect.attribute = 0;
+
+ GsSortRectangle(&game_rect);
+
+ game_print("PAL/NTSC SELECTION", 128, 64);
+ game_print("X - PAL", 128, 80);
+ game_print("O - NTSC", 128, 88);
+
+ GsDrawList();
+
+ while(GsIsDrawing());
+
+ game_drawenv.draw_on_display = 0;
+ game_drawenv.y = x;
+ GsSetDrawEnv(&game_drawenv);
+
+ while(1)
+ {
+ PSX_ReadPad(&padbuf, NULL);
+
+ if((padbuf & PAD_CROSS) && !cross_pressed)
+ return VMODE_PAL; // PAL
+
+ if((padbuf & PAD_CIRCLE) && !circle_pressed)
+ {
+ //printf("circle_pressed = %d\n", circle_pressed);
+ return VMODE_NTSC; // NTSC
+ }
+
+
+ if(!(padbuf & PAD_CROSS))
+ cross_pressed = 0;
+
+ if(!(padbuf & PAD_CIRCLE))
+ circle_pressed = 0;
+ }
+}
+
+void new_apple()
+{
+ int a, b;
+
+ do
+ {
+ while((a = rand()%40) < 1);
+ srand(seed_counter);
+ while((b = rand()%29) < 2);
+ srand(seed_counter);
+ }while(snake_array[b][a]);
+
+ snake_array[b][a] = 0x80;
+}
+
+int main()
+{
+ int c;
+
+// Initialize
+ game_init();
+
+ printf("PSXsnake\n");
+ printf("(c) 2009 Giuseppe Gatta\n");
+ printf("Made with PSXSDK\n\n");
+
+ load_file_into_buffer("cdrom:FONT.TIM;1");
+ GsImageFromTim(&game_image, file_buffer);
+
+ GsUploadImage(&game_image);
+
+ game_clut[0] = 0x0;
+ game_clut[1] = 0x7fff;
+
+ LoadImage(game_clut, 640, 24, 16, 1);
+
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+
+ vmode = pal_or_ntsc_selection();
+
+ //printf("vmode = %d\n", vmode);
+
+ GsSetVideoMode(320, 240, vmode);
+
+
+ load_file_into_buffer("cdrom:BACKGRND.TIM;1");
+ GsImageFromTim(&game_image, file_buffer);
+
+ GsUploadImage(&game_image);
+
+ sample_pos[0] = SPU_DATA_BASE_ADDR;
+ c = load_file_into_buffer("cdrom:MUSIC.RAW;1");
+ SsUpload(file_buffer, c, sample_pos[0]);
+
+ if(c&0x7)
+ {
+ c|=0x7;
+ c++;
+ }
+
+ sample_pos[1] = c + sample_pos[0];
+ c = load_file_into_buffer("cdrom:BOMB.RAW;1");
+ SsUpload(file_buffer, c, sample_pos[1]);
+
+ /* ... */
+ if(c&0x7)
+ {
+ c|=0x7;
+ c++;
+ }
+
+ sample_pos[2] = c + sample_pos[1];
+ c = load_file_into_buffer("cdrom:APPLE.RAW;1");
+ SsUpload(file_buffer, c, sample_pos[2]);
+
+ SsVoiceStartAddr(0, sample_pos[0]);
+ SsVoiceStartAddr(1, sample_pos[1]);
+ SsVoiceStartAddr(2, sample_pos[2]);
+
+ SsVoiceVol(0, 0x3fff, 0x3fff);
+ SsVoiceVol(1, 0x3fff, 0x3fff);
+ SsVoiceVol(2, 0x3fff, 0x3fff);
+
+ SsVoicePitch(0, 0x1000 / (44100 / 11025));
+ SsVoicePitch(1, 0x1000 / (44100 / 11025));
+ SsVoicePitch(2, 0x1000);
+
+ game_setup();
+
+ SetVBlankHandler(game_vblank_handler);
+
+
+ while(1)
+ game_run();
+
+ return 0;
+}
+
+int check_snake_collision(int x, int y)
+{
+ if(snake_array[y][x] == 0x80)
+ return 2; // Snake ate an apple
+ else if(snake_array[y][x] == 0)
+ return 1; // Collided with nothing
+
+ return 0; // Die, because snake collided with itself
+}
+
+void game_run()
+{
+ int x, y, a, b, c;
+
+ unsigned short padbuf;
+
+ while(speed_counter > 0)
+ {
+ scc++;
+
+ if(vibration_cntdown > 0)
+ {
+ printf("vibration = %d\n", vibration_cntdown);
+ pad_enable_vibration(0);
+ pad_set_vibration(0, 0xFF, 0x80);
+ vibration_cntdown--;
+
+ if(vibration_cntdown == 0)
+ pad_set_vibration(0, 0, 0);
+ }
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if(scc == 5 && !game_over)
+ {
+ if(snake_dir <= SNAKE_DIR_RIGHT)
+ {
+ if(padbuf & PAD_UP)
+ snake_dir = SNAKE_DIR_UP;
+
+ if(padbuf & PAD_DOWN)
+ snake_dir = SNAKE_DIR_DOWN;
+ }
+ else
+ {
+ if(padbuf & PAD_LEFT)
+ snake_dir = SNAKE_DIR_LEFT;
+
+ if(padbuf & PAD_RIGHT)
+ snake_dir = SNAKE_DIR_RIGHT;
+ }
+
+ for(y = 0; y < 29; y++)
+ for(x = 0; x < 40; x++)
+ {
+ if(snake_array[y][x] == snake_size)
+ {
+ switch(snake_dir)
+ {
+ case SNAKE_DIR_LEFT:
+ b = y;
+ a = x-1;
+ break;
+ case SNAKE_DIR_RIGHT:
+ b = y;
+ a = x+1;
+ break;
+ case SNAKE_DIR_UP:
+ b = y-1;
+ a = x;
+ break;
+ case SNAKE_DIR_DOWN:
+ b = y+1;
+ a = x;
+ break;
+ }
+
+ c = check_snake_collision(a,b);
+
+ if(c)
+ {
+ snake_array[b][a] = snake_size+1;
+
+ if(c==2)
+ {
+ snake_size++;
+ score+=100;
+ //printf("%d\n", score);
+ SsKeyOn(2);
+ new_apple();
+ }
+ }
+ else
+ {
+ vibration_cntdown = 10;
+ game_over = 1;
+ SsKeyOff(0);
+ SsKeyOn(1);
+ scc = 0;
+ }
+
+ if(snake_array[y][x] == 1 && c!=2)
+ snake_array[y][x] = 0;
+
+ goto out_of_collision_checking;
+ }
+ }
+out_of_collision_checking:
+ for(y = 0; y < 29; y++)
+ for(x = 0; x < 40; x++)
+ if(snake_array[y][x]&&snake_array[y][x]<0x80&&c!=2)
+ snake_array[y][x]--;
+
+ scc = 0;
+ }
+ else if(game_over)
+ {
+ scc++;
+
+ if(scc >= 510)
+ {
+ if((padbuf & PAD_CROSS) && !cross_pressed)
+ {
+ game_setup();
+ cross_pressed = 1;
+ }
+ else if((padbuf & PAD_CIRCLE) && !circle_pressed)
+ {
+ circle_pressed = 1;
+ GsSetVideoMode(320, 240, pal_or_ntsc_selection());
+ game_setup();
+ }
+
+ if(!(padbuf & PAD_CROSS))
+ cross_pressed = 0;
+
+ if(!(padbuf & PAD_CIRCLE))
+ circle_pressed = 0;
+ }
+ }
+
+ speed_counter--;
+ }
+
+
+ if(screen_old)
+ {
+ game_rect.x = 0;
+ game_rect.y = 0;
+ game_rect.w = 320;
+ game_rect.h = 240;
+ game_rect.r = 0;
+ game_rect.g = 0;
+ game_rect.b = 0;
+ game_rect.attribute = 0;
+
+ GsSortRectangle(&game_rect);
+
+ game_sprite.x = 0;
+ game_sprite.y = 0;
+ game_sprite.w = 256;
+ game_sprite.h = 240;
+ game_sprite.u = 0;
+ game_sprite.v = 0;
+ game_sprite.r = NORMAL_LUMINOSITY;
+ game_sprite.g = NORMAL_LUMINOSITY;
+ game_sprite.b = NORMAL_LUMINOSITY;
+ game_sprite.tpage = 5;
+ game_sprite.attribute = COLORMODE(COLORMODE_16BPP);
+
+ GsSortSimpleSprite(&game_sprite);
+
+ game_sprite.x += 256;
+ game_sprite.w = 64;
+ game_sprite.tpage = 9;
+
+ GsSortSimpleSprite(&game_sprite);
+
+ game_rect.w = 8;
+ game_rect.h = 8;
+ game_rect.attribute = ENABLE_TRANS | TRANS_MODE(0);
+
+ for(y = 0; y < 29; y++)
+ {
+ for(x = 0; x < 40; x++)
+ {
+ game_rect.x = x * 8;
+ game_rect.y = y * 8;
+
+ if(snake_array[y][x] >= 1 && snake_array[y][x] <= 0x7F)
+ {
+ game_rect.r = 0;
+ game_rect.g = 255;
+ game_rect.b = 0;
+ GsSortRectangle(&game_rect);
+ }
+ else if(snake_array[y][x] == 0x80)
+ {
+ game_rect.r = 255;
+ game_rect.g = 0;
+ game_rect.b = 255;
+ GsSortRectangle(&game_rect);
+ }
+ else if(snake_array[y][x] == 0x81)
+ {
+ game_rect.r = 0;
+ game_rect.g = 0;
+ game_rect.b = 128;
+ GsSortRectangle(&game_rect);
+ }
+ }
+ }
+
+ sprintf(string_buf, "SCORE: %d", score);
+ game_print(string_buf, 0, 232);
+
+ if(game_over)
+ {
+
+ game_rect.w = 320;
+ game_rect.h = 240;
+
+ game_rect.x = 0;
+ game_rect.y = 0;
+
+ if(scc<=255)x=scc;else x=255;
+
+ game_rect.r = x;
+ game_rect.g = x;
+ game_rect.b = x;
+ game_rect.attribute = ENABLE_TRANS|TRANS_MODE(2);
+
+ GsSortRectangle(&game_rect);
+
+ if(scc>=300)
+ {
+ game_center_print("GAME OVER!", 160, 120);
+ }
+
+ if(scc>=420)
+ game_center_print("WHAT DO YOU WANT TO DO NOW?", 160, 136);
+
+ if(scc>=450)
+ game_center_print("PRESS X TO RESTART THE GAME.",160, 152);
+
+ if(scc>=480)
+ game_center_print("PRESS O FOR PAL/NTSC SELECTION SCREEN.",160,168);
+
+ if(scc>=510)
+ game_center_print("MADE WITH PSXSDK BY GIUSEPPE GATTA, 2010", 160, 200);
+ }
+
+ GsDrawList();
+
+// While the graphic synthesizer (video card) is drawing
+// just sleep.
+ while(GsIsDrawing());
+
+// Swap drawing and display Y position, and swap list array
+// to use. In this way we achieve a double buffer.
+
+ if(game_dispenv.y == 0)
+ {
+ game_dispenv.y = 256;
+ game_drawenv.y = 0;
+ }
+ else
+ {
+ game_dispenv.y = 0;
+ game_drawenv.y = 256;
+ }
+
+ GsSetDispEnv(&game_dispenv);
+ GsSetDrawEnv(&game_drawenv);
+
+ screen_old = 0;
+ }
+}
+
+void game_run_gameover()
+{
+ printf("GAME OVER!\n");
+ while(1);
+}
+
+int load_file_into_buffer(char *fname)
+{
+ FILE *f;
+ int sz;
+
+ /*int fd;
+
+ fd = open(fname, O_RDONLY);
+
+ printf("%s (%d)\n", fname, get_file_size(fname));
+
+ read(fd, file_buffer, get_file_size(fname));
+
+ close(fd);*/
+ f = fopen(fname, "rb");
+
+ //f->pos = 0;
+ fseek(f, 0, SEEK_END);
+
+ sz = ftell(f);
+
+ fseek(f, 0, SEEK_SET);
+
+ printf("%s (%d)\n", fname, sz);
+
+ fread(file_buffer, sizeof(char), sz, f);
+
+ fclose(f);
+
+ return sz;
+}
+
+void game_print(char *string, int x, int y)
+{
+ GsSprite print_char;
+ char q;
+
+ print_char.x = x;
+ print_char.y = y;
+ print_char.w = 8;
+ print_char.h = 8;
+ print_char.r = NORMAL_LUMINOSITY;
+ print_char.g = NORMAL_LUMINOSITY;
+ print_char.b = NORMAL_LUMINOSITY;
+ print_char.cx = 640;
+ print_char.cy = 24;
+ print_char.tpage = 10;
+ print_char.attribute = COLORMODE(COLORMODE_4BPP);
+
+ while(*string)
+ {
+ if(*string >= 0x20 && *string <= 0x7F)
+ {
+ q = *string;
+ q -= 0x20;
+
+ print_char.u = (q&0x1f)<<3;
+ print_char.v = (q/0x20)<<3;
+ GsSortSimpleSprite(&print_char);
+ }
+ print_char.x+=8;
+ string++;
+ }
+}
+
+void game_center_print(char *string, int x, int y)
+{
+ int l = strlen(string);
+ l<<=2;
+
+ game_print(string, x - l, y);
+}
+
+
+
+
+
+void setup_snake_field()
+{
+ int x, y;
+
+ for(y=0;y<29;y++)
+ for(x=0;x<40;x++)
+ snake_array[y][x] = 0;
+
+ for(y=0;y<29;y++)
+ {
+ snake_array[y][0] = 0x81;
+ snake_array[y][39] = 0x81;
+ }
+
+ for(x=0;x<40;x++)
+ {
+ snake_array[0][x] = 0x81;
+ snake_array[28][x] = 0x81;
+ }
+
+ new_apple();
+
+ for(x=1;x<=snake_size;x++)
+ snake_array[1][x]=x;
+
+ snake_dir = SNAKE_DIR_RIGHT;
+}
+
+void game_setup()
+{
+ game_over = 0;
+ scc = 0;
+ snake_size = 3;
+ speed_counter = 0;
+ score = 0;
+ setup_snake_field();
+ SsKeyOn(0);
+}
+
diff --git a/examples/puzzle/Makefile b/examples/puzzle/Makefile
new file mode 100644
index 0000000..ee00787
--- /dev/null
+++ b/examples/puzzle/Makefile
@@ -0,0 +1,9 @@
+PROJNAME = puzzle
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+ mkdir -p cd_root
+ bmp2tim puzzle.bmp cd_root/puzzle.tim 16 -org=320,0
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/puzzle/puzzle.bmp b/examples/puzzle/puzzle.bmp
new file mode 100644
index 0000000..ed689c8
--- /dev/null
+++ b/examples/puzzle/puzzle.bmp
Binary files differ
diff --git a/examples/puzzle/puzzle.c b/examples/puzzle/puzzle.c
new file mode 100644
index 0000000..8f2786f
--- /dev/null
+++ b/examples/puzzle/puzzle.c
@@ -0,0 +1,216 @@
+#include <psx.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+unsigned char puzzle_pieces[7][7];
+unsigned char piece_taken[7 * 7];
+
+int puzzle_x = 0, puzzle_y = 0;
+
+volatile int display_is_old = 1;
+
+void prog_vblank_handler()
+{
+ display_is_old=1;
+}
+
+GsImage puzzle_image;
+unsigned int prim_list[0x4000];
+unsigned char data_buffer[0x40000]; // 256 kilobytes
+
+int main()
+{
+ int x, y, ex, ey;
+ int wasleft=0;
+ int wasright=0;
+ int wasup=0;
+ int wasdown=0;
+ int wasexh=0;
+ int wasexv=0;
+ int dbuf=0;
+ unsigned char b;
+ unsigned short padbuf;
+ FILE *f;
+ GsSprite tile_sprite;
+ GsRectangle tile_rectangle;
+
+ PSX_Init();
+ GsInit();
+ GsClearMem();
+ GsSetList(prim_list);
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+
+ f = fopen("cdrom:\\PUZZLE.TIM;1", "rb");
+ fseek(f, 0, SEEK_END);
+ x = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ fread(data_buffer, sizeof(char), x, f);
+ fclose(f);
+
+ GsImageFromTim(&puzzle_image, data_buffer);
+
+ GsUploadImage(&puzzle_image);
+ while(GsIsDrawing());
+
+ GsLoadFont(768, 0, 768, 256);
+ while(GsIsDrawing());
+
+ tile_sprite.tpage = 5;
+ tile_sprite.w = 32;
+ tile_sprite.h = 32;
+ tile_sprite.attribute = COLORMODE(COLORMODE_16BPP);
+ tile_sprite.r = tile_sprite.g = tile_sprite.b = NORMAL_LUMINOSITY;
+
+ SetVBlankHandler(prog_vblank_handler);
+
+ for(x=0;x<sizeof(piece_taken);x++)
+ piece_taken[x] = 0;
+
+ for(y = 0; y < 7; y++)
+ {
+ for(x = 0; x < 7; x++)
+ {
+ do
+ {
+ puzzle_pieces[y][x] = (rand() % 49) + 1;
+ }while(piece_taken[puzzle_pieces[y][x]] == 1);
+
+ piece_taken[puzzle_pieces[y][x]] = 1;
+ }
+ }
+
+ while(1)
+ {
+ if(display_is_old)
+ {
+ GsSetDispEnvSimple(0, dbuf?256:0);
+ GsSetDrawEnvSimple(0, dbuf?0:256, 320, 240);
+ dbuf=!dbuf;
+
+ PSX_ReadPad(&padbuf, NULL);
+
+ if((padbuf & PAD_LEFT) && !wasleft)
+ {
+ if(puzzle_x>0)
+ puzzle_x--;
+
+ wasleft=1;
+ }
+
+ if((padbuf & PAD_RIGHT) && !wasright)
+ {
+ if(puzzle_x<6)
+ puzzle_x++;
+
+ wasright=1;
+ }
+
+ if((padbuf & PAD_UP) && !wasup)
+ {
+ if(puzzle_y>0)
+ puzzle_y--;
+
+ wasup=1;
+ }
+
+ if((padbuf & PAD_DOWN) && !wasdown)
+ {
+ if(puzzle_y<6)
+ puzzle_y++;
+
+ wasdown=1;
+ }
+
+ if(!(padbuf & PAD_LEFT))
+ wasleft=0;
+
+ if(!(padbuf & PAD_RIGHT))
+ wasright=0;
+
+ if(!(padbuf & PAD_UP))
+ wasup=0;
+
+ if(!(padbuf & PAD_DOWN))
+ wasdown=0;
+
+ if((padbuf & PAD_CROSS) && !wasexh) // x <--> y
+ {
+ ey = puzzle_y;
+ if(puzzle_x < 6)
+ ex = puzzle_x+1;
+ else
+ ex = puzzle_x-1;
+
+ b = puzzle_pieces[puzzle_y][puzzle_x];
+ puzzle_pieces[puzzle_y][puzzle_x] =
+ puzzle_pieces[ey][ex];
+ puzzle_pieces[ey][ex] = b;
+
+ wasexh=1;
+ }
+
+ if((padbuf & PAD_CIRCLE) && !wasexv)
+ {
+ ex = puzzle_x;
+ if(puzzle_y < 6)
+ ey = puzzle_y+1;
+ else
+ ey = puzzle_y-1;
+
+ b = puzzle_pieces[puzzle_y][puzzle_x];
+ puzzle_pieces[puzzle_y][puzzle_x] =
+ puzzle_pieces[ey][ex];
+ puzzle_pieces[ey][ex] = b;
+
+ wasexv=1;
+ }
+
+ if(!(padbuf & PAD_CROSS))
+ wasexh=0;
+
+ if(!(padbuf & PAD_CIRCLE))
+ wasexv=0;
+
+ GsSortCls(0, 0, 255);
+
+ for(y = 0; y < 7; y++)
+ {
+ for(x = 0; x < 7; x++)
+ {
+ tile_sprite.x = x * 32;
+ tile_sprite.y = y * 32;
+ tile_sprite.u = ((puzzle_pieces[y][x]-1) % 7) * 32;
+ tile_sprite.v = ((puzzle_pieces[y][x]-1) / 7) * 32;
+ GsSortSimpleSprite(&tile_sprite);
+
+ if(x == puzzle_x && y == puzzle_y)
+ {
+ tile_rectangle.x = x * 32;
+ tile_rectangle.y = y * 32;
+ tile_rectangle.r = 255;
+ tile_rectangle.g = 0;
+ tile_rectangle.b = 255;
+ tile_rectangle.w = 32;
+ tile_rectangle.h = 32;
+ tile_rectangle.attribute = ENABLE_TRANS;
+ GsSortRectangle(&tile_rectangle);
+ }
+ }
+ }
+
+ GsPrintFont(232, 16, "Resolve\nPuzzle\n\n"
+ "Exchange:\n"
+ "\nX\nHorizontal\n"
+ "\nO\nVertical");
+
+ GsDrawList();
+ while(GsIsDrawing());
+
+ display_is_old = 0;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/rottest/Makefile b/examples/rottest/Makefile
new file mode 100644
index 0000000..be7c0c0
--- /dev/null
+++ b/examples/rottest/Makefile
@@ -0,0 +1,9 @@
+PROJNAME = rottest
+
+include ../project.mk
+
+$(PROJNAME)_extra:
+ mkdir -p cd_root
+ bmp2tim image.bmp cd_root/image.tim 16 -org=320,0
+
+$(PROJNAME)_clean_extra:
diff --git a/examples/rottest/image.bmp b/examples/rottest/image.bmp
new file mode 100644
index 0000000..e08b3af
--- /dev/null
+++ b/examples/rottest/image.bmp
Binary files differ
diff --git a/examples/rottest/rottest.c b/examples/rottest/rottest.c
new file mode 100644
index 0000000..4d4f341
--- /dev/null
+++ b/examples/rottest/rottest.c
@@ -0,0 +1,104 @@
+#include <psx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+unsigned int prim_list[0x4000];
+unsigned char filebuf[0x40000];
+
+volatile int display_is_old = 0;
+
+void prog_vblank_handler()
+{
+ display_is_old = 1;
+}
+
+int main()
+{
+ FILE *f;
+ GsSprite my_sprite;
+ GsImage my_image;
+ int y = 0;
+ int ro = 0;
+ int sc_x = SCALE_ONE;
+ int sc_y = SCALE_ONE;
+ unsigned short padbuf;
+
+ PSX_Init();
+
+ GsInit();
+ GsSetList(prim_list);
+ GsSetVideoMode(320, 240, EXAMPLES_VMODE);
+
+ GsClearMem();
+ GsSetDrawEnvSimple(0, 256, 320, 240);
+ GsSetDispEnvSimple(0, 0);
+
+ f = fopen("cdrom:\\IMAGE.TIM;1", "rb");
+ fseek(f, 0, SEEK_END);
+ y = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ fread(filebuf, sizeof(char), y, f);
+ fclose(f);
+
+ GsImageFromTim(&my_image, filebuf);
+ GsSpriteFromImage(&my_sprite, &my_image, 1);
+
+ SetVBlankHandler(prog_vblank_handler);
+
+ GsLoadFont(768, 0, 768, 128);
+ while(GsIsWorking());
+
+ while(1)
+ {
+ if(display_is_old)
+ {
+ PSX_ReadPad(&padbuf, NULL);
+ if(padbuf & PAD_LEFT)
+ {
+ ro--;
+ if(ro < 0) ro = 359;
+ }
+
+ if(padbuf & PAD_RIGHT)
+ {
+ ro++;
+ if(ro>=360) ro = 0;
+ }
+
+ if(padbuf & PAD_UP)
+ sc_x+=128;
+
+ if(padbuf & PAD_DOWN)
+ sc_x-=128;
+
+ if(padbuf & PAD_CROSS)
+ sc_y-=128;
+
+ if(padbuf & PAD_CIRCLE)
+ sc_y+=128;
+
+ GsSortCls(0, 0, 0);
+
+ my_sprite.x = 100;
+ my_sprite.y = 100;
+ my_sprite.r = my_sprite.g = my_sprite.b = NORMAL_LUMINOSITY;
+ my_sprite.rotate = ROTATE_ONE*ro;
+ my_sprite.scalex = sc_x;
+ my_sprite.scaley = sc_y;
+ my_sprite.mx = (my_sprite.w/2) * (my_sprite.scalex / 4096);
+ my_sprite.my = (my_sprite.h/2) * (my_sprite.scaley / 4096);
+ GsSortSprite(&my_sprite);
+
+ GsPrintFont(0, 0, "ro=%d\nsc_x=%d\nsc_y=%d", ro, sc_x, sc_y);
+
+ GsDrawList();
+ while(GsIsWorking());
+
+ y=!y;
+ GsSetDrawEnvSimple(0, y?0:256, 320, 240);
+ GsSetDispEnvSimple(0, y?256:0);
+ display_is_old = 0;
+ }
+ }
+}
diff --git a/libadpcm/Makefile b/libadpcm/Makefile
new file mode 100644
index 0000000..65453a6
--- /dev/null
+++ b/libadpcm/Makefile
@@ -0,0 +1,26 @@
+# Makefile for libadpcm
+
+include ../Makefile.cfg
+
+AR = mipsel-unknown-elf-ar
+RANLIB = mipsel-unknown-elf-ranlib
+CFLAGS += -O3 -I../libm
+
+all: libadpcm.a
+
+adpcm.o: adpcm.c
+ $(CC) $(CFLAGS) -c adpcm.c
+
+libadpcm.a: adpcm.o
+ rm -f libadpcm.a
+ $(AR) r libadpcm.a adpcm.o
+ $(RANLIB) libadpcm.a
+
+install: all
+ cp libadpcm.a $(TOOLCHAIN_PREFIX)/lib
+ cp adpcm.h $(TOOLCHAIN_PREFIX)/include
+
+clean:
+ rm -f *.o *.a
+
+distclean: clean
diff --git a/libadpcm/adpcm.c b/libadpcm/adpcm.c
new file mode 100644
index 0000000..5269316
--- /dev/null
+++ b/libadpcm/adpcm.c
@@ -0,0 +1,251 @@
+/*
+ * PCM -> ADPCM routines
+ *
+ * based on work by Bitmaster and extended
+ */
+
+// The version here was converted by double to ints, and so
+// it loses much precision... but if that wasn't done it would have
+// a very bad performance on the PlayStation hardware
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <math.h>
+#include <psx.h>
+#include "adpcm.h"
+
+#define PCM_BUFFER_SIZE 128*28
+
+short pcm_buffer[PCM_BUFFER_SIZE];
+
+void SsAdpcm_find_predict( short *samples, int *d_samples, int *predict_nr, int *shift_factor);
+void SsAdpcm_pack( int *d_samples, short *four_bit, int predict_nr, int shift_factor);
+
+int SsAdpcmPack(void *pcm_data, void *adpcm_data, int sample_len,
+ int sample_fmt, int adpcm_len, int enable_looping)
+{
+ short *ptr;
+ unsigned char *pcm_data_c = pcm_data;
+ short *pcm_data_s = pcm_data;
+ unsigned char *adpcm_data_c = adpcm_data;
+ int d_samples[28];
+ short four_bit[28];
+ int predict_nr;
+ int shift_factor;
+ int flags;
+ int size;
+ int i, j, k;
+ unsigned char d;
+ int ap = 0;
+
+/*printf("pcm_data = %x, adpcm_data = %x, len = %x, fmt = %x, alen = %x,"
+ "loop = %x\n", pcm_data, adpcm_data, sample_len, sample_fmt,
+ adpcm_len, enable_looping);
+ for(i=0;i<8;i++)
+ printf("I[%d] = %x\n", i, pcm_data_c[i]);*/
+
+ if(enable_looping)
+ flags = 6;
+ else
+ flags = 0;
+
+ //sample_len -= sample_len % 28;
+
+while( sample_len > 0 ) {
+ size = ( sample_len >= PCM_BUFFER_SIZE ) ? PCM_BUFFER_SIZE : sample_len;
+
+ if(sample_fmt == FMT_U8)
+ {
+ for(i = 0; i < size; i++)
+ {
+ //c = fgetc(fp);
+ pcm_buffer[i] = *(pcm_data_c++);
+ pcm_buffer[i] ^= 0x80;
+ pcm_buffer[i] <<= 8;
+ }
+ }
+ else if(sample_fmt == FMT_S16)
+ {
+ //fread( wave, sizeof( short ), size, fp );
+ memcpy(pcm_buffer, pcm_data_s, size * sizeof(short));
+ pcm_data_s += size;
+ }
+ else
+ {
+ printf("%s, line %d: Unknown source sample format!, id=%d\n",__FUNCTION__,__LINE__,sample_fmt);
+ return 0;
+ }
+
+ i = size / 28;
+ if ( size % 28 ) {
+ for ( j = size % 28; j < 28; j++ )
+ pcm_buffer[28*i+j] = 0;
+ i++;
+ }
+
+ for ( j = 0; j < i; j++ ) { // pack 28 samples
+ ptr = pcm_buffer + j * 28;
+ SsAdpcm_find_predict( ptr, d_samples, &predict_nr, &shift_factor );
+ SsAdpcm_pack( d_samples, four_bit, predict_nr, shift_factor );
+ d = ( predict_nr << 4 ) | shift_factor;
+ // fputc( d, vag );
+ adpcm_data_c[ap++] = d;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ // fputc( flags, vag );
+ adpcm_data_c[ap++] = flags;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ for ( k = 0; k < 28; k += 2 ) {
+ d = ( ( four_bit[k+1] >> 8 ) & 0xf0 ) | ( ( four_bit[k] >> 12 ) & 0xf );
+ // fputc( d, vag );
+ adpcm_data_c[ap++] = d;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ }
+ sample_len -= 28;
+ if ( sample_len < 28 && enable_looping == 0)
+ flags = 1;
+
+ if(enable_looping)
+ flags = 2;
+ }
+ }
+
+ // fputc( ( predict_nr << 4 ) | shift_factor, vag );
+ adpcm_data_c[ap++] = ( predict_nr << 4 ) | shift_factor;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ if(enable_looping == 1)
+ // fputc(3, vag);
+ adpcm_data_c[ap++] = 3;
+ else if(enable_looping == 2)
+ adpcm_data_c[ap++] = 0;
+ else if(enable_looping == 3)
+ adpcm_data_c[ap++] = 2;
+ else
+// fputc( 7, vag ); // end flag
+ adpcm_data_c[ap++] = 7;
+
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ if(enable_looping != 2)
+ {
+ for ( i = 0; i < 14; i++ )
+ // fputc( 0, vag );
+ adpcm_data_c[ap++] = 0;
+ }
+
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ return ap;
+
+adpcm_too_big:
+ printf("%s: Resulting ADPCM data would have been larger than the output array length! Exiting %s.\n", __FUNCTION__, __FUNCTION__);
+ return 0;
+}
+
+
+static const int f[5][2] = { { 0, 0 },
+ { 60, 0 },
+ { 115, -52},
+ { 98, -55},
+ { 122, -60} };
+
+void SsAdpcm_find_predict( short *samples, int *d_samples, int *predict_nr, int *shift_factor )
+{
+ int i, j;
+ int buffer[28][5];
+ int min = 0x7fffffff;
+ int max[5];
+ int ds;
+ int min2;
+ int shift_mask;
+ static int _s_1 = 0; // s[t-1]
+ static int _s_2 = 0; // s[t-2]
+ int s_0, s_1, s_2;
+
+
+ for ( i = 0; i < 5; i++ ) {
+ max[i] = 0.0;
+ s_1 = _s_1;
+ s_2 = _s_2;
+ for ( j = 0; j < 28; j ++ ) {
+ s_0 = (int) samples[j]; // s[t-0]
+ if ( s_0 > 32767 )
+ s_0 = 32767;
+ if ( s_0 < - 32768 )
+ s_0 = -32768;
+ ds = s_0 + s_1 * f[i][0] + s_2 * f[i][1];
+ buffer[j][i] = ds;
+ if ( ds > max[i] )
+ max[i] = ds;
+// printf( "%+5.2f\n", s2 );
+ s_2 = s_1; // new s[t-2]
+ s_1 = s_0; // new s[t-1]
+ }
+
+ if ( max[i] <= min ) {
+ // printf("min = %d, max[i] = %d", min, max[i]);
+ min = max[i];
+ *predict_nr = i;
+ }
+ if ( min <= 7 ) {
+ *predict_nr = 0;
+ break;
+ }
+
+ }
+
+// store s[t-2] and s[t-1] in a static variable
+// these than used in the next function call
+
+ _s_1 = s_1;
+ _s_2 = s_2;
+
+ for ( i = 0; i < 28; i++ )
+ d_samples[i] = buffer[i][*predict_nr];
+
+// if ( min > 32767.0 )
+// min = 32767.0;
+
+ min2 = ( int ) min;
+ shift_mask = 0x4000;
+ *shift_factor = 0;
+
+ while( *shift_factor < 12 ) {
+ if ( shift_mask & ( min2 + ( shift_mask >> 3 ) ) )
+ break;
+ (*shift_factor)++;
+ shift_mask = shift_mask >> 1;
+ }
+
+}
+
+void SsAdpcm_pack( int *d_samples, short *four_bit, int predict_nr, int shift_factor )
+{
+ int ds;
+ int di;
+ int s_0;
+ static int s_1 = 0;
+ static int s_2 = 0;
+ int i;
+
+ for ( i = 0; i < 28; i++ ) {
+ s_0 = d_samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1];
+ ds = s_0 * (int) ( 1 << shift_factor );
+
+ di = ( (int) ds + 0x800 ) & 0xfffff000;
+
+ if ( di > 32767 )
+ di = 32767;
+ if ( di < -32768 )
+ di = -32768;
+
+ four_bit[i] = (short) di;
+
+ di = di >> shift_factor;
+ s_2 = s_1;
+ s_1 = (int) di - s_0;
+
+ }
+}
diff --git a/libadpcm/adpcm.h b/libadpcm/adpcm.h
new file mode 100644
index 0000000..8070512
--- /dev/null
+++ b/libadpcm/adpcm.h
@@ -0,0 +1,13 @@
+#ifndef _PSX_ADPCM_H
+#define _PSX_ADPCM_H
+
+enum
+{
+ FMT_U8, // unsigned 8-bit
+ FMT_S16, // signed 16-bit
+};
+
+int SsAdpcmPack(void *pcm_data, void *adpcm_data, int sample_len,
+ int sample_fmt, int adpcm_len, int enable_looping);
+
+#endif \ No newline at end of file
diff --git a/libf3m/Makefile b/libf3m/Makefile
new file mode 100644
index 0000000..4ecd4e7
--- /dev/null
+++ b/libf3m/Makefile
@@ -0,0 +1,20 @@
+# Makefile for libf3m
+
+include ../Makefile.cfg
+
+all: libf3m.a
+
+f3m.o: f3m.c
+ $(CC) $(CFLAGS) -c f3m.c
+
+libf3m.a: f3m.o
+ rm -f libf3m.a
+ $(AR) r libf3m.a f3m.o
+ $(RANLIB) libf3m.a
+
+install: all
+ cp libf3m.a $(TOOLCHAIN_PREFIX)/lib
+ cp f3m.h $(TOOLCHAIN_PREFIX)/include
+
+clean:
+ rm -f *.o *.a \ No newline at end of file
diff --git a/libf3m/f3m.c b/libf3m/f3m.c
new file mode 100755
index 0000000..a6bcab5
--- /dev/null
+++ b/libf3m/f3m.c
@@ -0,0 +1,1068 @@
+// made in 2015 by GreaseMonkey - Public Domain
+// modified in 2016 by nextvolume for inclusion in PSXSDK
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <psx.h>
+#include "f3m.h"
+
+typedef struct ins
+{
+ uint8_t typ;
+ uint8_t fname[12];
+ uint8_t dat_para_h;
+ uint16_t dat_para;
+ uint32_t len, lpbeg, lpend;
+ uint8_t vol, rsv1, pack, flags;
+ uint32_t c4freq;
+ uint8_t rsv2[12];
+ uint8_t name[28];
+ uint8_t magic[4];
+} __attribute__((__packed__)) ins_s;
+
+extern mod_s fsys_s3m_test[];
+
+const uint32_t period_amiclk = 8363*1712-400;
+const uint16_t period_table[12] = {1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907};
+
+// from ITTECH.TXT
+static const int8_t f3m_sintab[64] = {
+ 0, 6, 12, 19, 24, 30, 36, 41,
+ 45, 49, 53, 56, 59, 61, 63, 64,
+ 64, 64, 63, 61, 59, 56, 53, 49,
+ 45, 41, 36, 30, 24, 19, 12, 6,
+};
+
+mod_s *f3m_mod_load(uint32_t *d)
+{
+ return (mod_s*)d;
+}
+
+mod_s *f3m_mod_load_filename(const char *fname)
+{
+ FILE *fp;
+ int filesize;
+ char *buf;
+ mod_s *m;
+
+ fp = fopen(fname, "rb");
+
+ if(!fp)
+ return NULL;
+
+ fseek(fp, 0, SEEK_END);
+ filesize = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ buf = malloc(filesize);
+ fread(buf, sizeof(char), filesize, fp);
+
+ fclose(fp);
+
+ m = f3m_mod_load((uint32_t*)buf);
+
+ if(!m)
+ free(buf);
+
+ return m;
+}
+
+void f3m_mod_free(mod_s *mod)
+{
+ free(mod);
+}
+
+static uint16_t f3m_get_para(const uint16_t *p)
+{
+ const uint8_t *p2 = (const uint8_t *)p;
+ uint16_t v0 = p2[0];
+ uint16_t v1 = p2[1];
+
+ return (v1<<8)|v0;
+}
+
+static int32_t f3m_calc_tempo_samples(int32_t tempo)
+{
+ return (F3M_FREQ*10)/(tempo*4);
+}
+
+static int32_t f3m_calc_freq(int32_t freq)
+{
+#if F3M_FREQ == 32768
+ freq <<= 1;
+#else
+#if F3M_FREQ == 16384
+ freq <<= 2;
+#else
+ freq = (freq << 10) / (F3M_FREQ >> 6);
+#endif
+#endif
+ return freq;
+
+}
+
+static int32_t f3m_calc_period_freq(int32_t period)
+{
+ int32_t freq = period_amiclk / period;
+ return f3m_calc_freq(freq);
+}
+
+int f3m_set_mono_mode(player_s *player, int onoff)
+{
+ int old = player->monomode;
+
+ player->monomode = onoff;
+
+ return old;
+}
+
+uint16_t f3m_set_max_volume(player_s *player, uint16_t maxvolume)
+{
+ uint16_t old = player->maxvolume;
+
+ if(maxvolume > SPU_MAXVOL)
+ player->maxvolume = SPU_MAXVOL;
+ else
+ player->maxvolume = maxvolume;
+
+ return old;
+}
+
+unsigned int f3m_player_init(player_s *player, mod_s *mod)
+{
+ return f3m_player_init_ex(player, mod, 0, SPU_DATA_BASE_ADDR);
+}
+
+unsigned int f3m_player_init_ex(player_s *player, mod_s *mod, int basevoice, unsigned int baseaddr)
+{
+ int i;
+
+ // Optional callback
+ //update_music_status(0, mod->ins_num);
+
+ player->mod = mod;
+ player->modbase = (const void *)mod;
+ player->ord_list = (const uint8_t *)(((const char *)(mod+1)));
+ player->ins_para = (const uint16_t *)(((const char *)(mod+1)) + mod->ord_num);
+ player->pat_para = (const uint16_t *)(((const char *)(mod+1)) + mod->ord_num + mod->ins_num*2);
+
+ player->speed = mod->ispeed;
+ player->tempo = mod->itempo;
+ player->gvol = mod->gvol;
+ player->ctick = player->speed;
+ player->tempo_samples = f3m_calc_tempo_samples(player->tempo);
+ player->tempo_wait = 0;
+
+ player->cord = 0-1;
+ player->cpat = 0;
+ player->crow = 64;
+ player->patptr = NULL;
+ player->patptr_next = NULL;
+ player->sfxoffs = 0;
+ player->ccount = 16;
+ player->repeat_row = 0;
+ player->repeat_count = 0;
+
+ player->baseaddr = baseaddr;
+ player->basevoice = basevoice;
+ player->monomode = 0;
+ player->maxvolume = SPU_MAXVOL;
+
+ for(i = 0; i < F3M_VCHNS; i++)
+ {
+ vchn_s *vchn = &(player->vchn[i]);
+
+ vchn->spu_data = 0;
+
+ vchn->len = 0;
+ vchn->len_loop = 0;
+
+ vchn->freq = 0;
+ vchn->offs = 0;
+ vchn->suboffs = 0;
+ vchn->priority = (i < player->ccount ? F3M_PRIO_MUSIC_OFF : 0);
+
+ vchn->gxx_period = 0;
+ vchn->period = 0;
+ vchn->insvol = 0;
+ vchn->midvol = 0;
+ vchn->outvol = 0;
+ vchn->pan = ((mod->mvol&0x80)==0)
+ ? 0x8
+ : (mod->defpanFC == 0xFC
+ ? ((const uint8_t *)(player->pat_para + mod->pat_num))[i] & 0xF
+ : ((i&1)?0xC:0x3));
+
+ vchn->vib_offs = 0;
+ vchn->tre_offs = 0;
+ vchn->rtg_count = 0;
+
+ vchn->eft = 0;
+ vchn->efp = 0;
+ vchn->lefp = 0;
+ vchn->last_note = 0;
+ vchn->lins = 0;
+
+ vchn->mem_gxx = 0;
+ vchn->mem_hxx = 0;
+ vchn->mem_oxx = 0;
+ }
+
+ int j, k;
+
+ // load samples
+ for(i = 0; i < 99; i++)
+ {
+ player->psx_spu_offset[i] = 0;
+ player->psx_spu_offset_lpbeg[i] = 0;
+ }
+
+ uint16_t spu_offs = baseaddr >> 3;
+
+ static uint16_t smp_data_buf[8];
+
+ static int smp_src_buf[28];
+ int smp_data_last = 0;
+
+ for(i = 0; i < 99 && i < mod->ins_num; i++)
+ {
+ //update_music_status(i, mod->ins_num);
+ // TODO: subtly adjust samples so loops work properly
+
+ // Get instrument + check if valid
+ const ins_s *ins = ((void *)mod) + (((uint32_t)(f3m_get_para(&player->ins_para[i])))*16);
+ uint32_t para = (((uint32_t)(ins->dat_para_h))<<16)|((uint32_t)(ins->dat_para));
+ if(ins->len == 0 || para == 0)
+ continue;
+
+ int lpbeg = (((ins->flags & 0x01) != 0) ? ins->lpbeg : ins->len + 64);
+ int lpend = (((ins->flags & 0x01) != 0) ? ins->lpend+1 : ins->len + 64);
+ // Ensure the loop actually fires
+ // Not sure if the assurance is really that good here!
+ if((ins->flags & 0x01) != 0 && lpend > ((int)ins->len)-14)
+ lpend = ins->len-14;
+
+ const uint8_t *data = ((void *)mod) + (para*16);
+ player->psx_spu_offset[i] = spu_offs;
+ player->psx_spu_offset_lpbeg[i] = spu_offs;
+ for(j = 0; j < 64000 && j < (int)ins->len; j += 28, data += 28, spu_offs += (0x10>>3))
+ {
+ // Load data
+ int src_min = smp_data_last;
+ int src_max = smp_data_last;
+
+ for(k = 0; k < 28; k++)
+ {
+ int v = (j+k >= (int)ins->len ? 0 : (((int)(data[k]))-0x80)<<8);
+ if(v < src_min) src_min = v;
+ if(v > src_max) src_max = v;
+ smp_src_buf[k] = v;
+ }
+
+ // Calculate shift
+ int src_range = src_max - src_min;
+ int shift = 0;
+ while(src_range >= 16 && shift < 12)
+ {
+ shift++;
+ src_range >>= 1;
+ }
+
+ // Clear old buffer
+ for(k = 0; k < 8; k++)
+ smp_data_buf[k] = 0;
+
+ // Set header
+ // applying filter 1 so we get a delta + soft LPF
+ smp_data_buf[0] = (12-shift) | (1<<4) | ((0x00)<<8);
+ if(j+14 >= lpbeg && j-14 < lpbeg)
+ {
+ smp_data_buf[0] |= 0x0400;
+ player->psx_spu_offset_lpbeg[i] = spu_offs;
+ }
+ if(j+14 >= lpend && j-14 < lpend)
+ smp_data_buf[0] |= 0x0300;
+
+ // Add data
+ for(k = 0; k < 28; k++)
+ {
+ int v = smp_src_buf[k];
+ v -= smp_data_last;
+ v = (v + (1<<(shift-1)))>>shift;
+ if(v < -8) v = -8;
+ if(v > 7) v = 7;
+
+ smp_data_buf[1+(k>>2)] |= ((v&15)<<((k&3)<<2));
+ smp_data_last += (v<<shift);
+ }
+
+ // Upload data
+ SsUpload(smp_data_buf, 16, spu_offs << 3);
+ }
+
+ // Upload silence
+ smp_data_buf[0] = 0x0500;
+
+ for(k = 1; k < 8; k++)
+ smp_data_buf[k] = 0x0000;
+
+ SsUpload(smp_data_buf, 16, spu_offs << 3);
+
+ spu_offs += 0x10>>3;
+ }
+
+ return spu_offs << 3;
+}
+
+static void f3m_update_outvol(player_s *player, vchn_s *vchn)
+{
+ vchn->outvol = (vchn->midvol * player->gvol) >> 6;
+}
+
+static void f3m_player_eff_slide_vol(player_s *player, vchn_s *vchn, int isfirst)
+{
+ (void)player; // "player" is only there to check the fast slide flag (TODO!)
+
+ uint8_t lefp = vchn->lefp;
+ int samt = 0;
+
+ if((lefp & 0xF0) == 0x00)
+ {
+ if((!isfirst) || lefp == 0x0F) samt = -(lefp & 0x0F);
+ } else if((lefp & 0x0F) == 0x00) {
+ if((!isfirst) || lefp == 0xF0) samt = lefp >> 4;
+ } else if((lefp & 0x0F) == 0x0F) {
+ if(isfirst) samt = lefp >> 4;
+ } else if((lefp & 0xF0) == 0xF0) {
+ if(isfirst) samt = -(lefp & 0x0F);
+ } else {
+ // default: slide down on nonzero ticks
+ // SATELL.s3m relies on this
+ if(!isfirst) samt = -(lefp & 0x0F);
+ }
+
+ if(samt > 0)
+ {
+ vchn->midvol += samt;
+ if(vchn->midvol > 63) vchn->midvol = 63;
+ } else if(samt < 0) {
+ if(vchn->midvol < (uint8_t)-samt) vchn->midvol = 0;
+ else vchn->midvol += samt;
+ }
+
+ f3m_update_outvol(player, vchn);
+}
+
+static void f3m_player_eff_slide_period(vchn_s *vchn, int amt)
+{
+ vchn->period += amt;
+ vchn->freq = f3m_calc_period_freq(vchn->period);
+}
+
+static void f3m_player_eff_vibrato(vchn_s *vchn, int lefp, int shift)
+{
+ vchn->freq = f3m_calc_period_freq(vchn->period);
+
+ int vspeed = (lefp>>4);
+ int vdepth = (lefp&15)<<shift;
+
+ // TODO: support other waveforms
+
+ // TODO: find rounding + direction
+ int vval = f3m_sintab[vchn->vib_offs&31];
+ if(vchn->vib_offs & 32) vval = -vval;
+ vval *= vdepth;
+ vval += (1<<(5-1));
+ vval >>= 5;
+
+ vchn->freq = f3m_calc_period_freq(vchn->period + vval);
+ vchn->vib_offs += vspeed;
+}
+
+static void f3m_note_retrig(player_s *player, vchn_s *vchn)
+{
+ int iidx = vchn->lins;
+ const ins_s *ins = player->modbase + (((uint32_t)(f3m_get_para(&player->ins_para[iidx-1])))*16);
+
+ int note = vchn->last_note;
+ vchn->gxx_period = ((8363 * 16 * period_table[note&15]) / ins->c4freq)
+ >> (note>>4);
+
+ vchn->spu_data = player->psx_spu_offset[iidx-1];
+ vchn->spu_data_lpbeg = player->psx_spu_offset_lpbeg[iidx-1];
+
+ vchn->priority = F3M_PRIO_MUSIC;
+ vchn->len = (((ins->flags & 0x01) != 0) && ins->lpend < ins->len
+ ? ins->lpend
+ : ins->len);
+ vchn->len_loop = (((ins->flags & 0x01) != 0) && ins->lpbeg < ins->len
+ ? vchn->len - ins->lpbeg
+ : 0);
+
+ // TODO: verify if this is the case wrt note-end
+ if(vchn->spu_data == 0 || (vchn->eft != ('G'-'A'+1) && vchn->eft != ('L'-'A'+1)))
+ {
+ vchn->period = vchn->gxx_period;
+ vchn->freq = f3m_calc_period_freq(vchn->period);
+ vchn->offs = 0;
+ if(vchn->eft == ('O'-'A'+1))
+ {
+ vchn->eft = 0;
+ int lefp = (vchn->efp != 0 ? vchn->efp : vchn->mem_oxx);
+ vchn->mem_oxx = lefp;
+ lefp <<= 8;
+ if(lefp < vchn->len)
+ vchn->offs = lefp;
+ }
+ vchn->vib_offs = 0; // TODO: find correct retrig point
+ vchn->tre_offs = 0; // TODO: find correct retrig point
+ }
+}
+
+static void f3m_jump_to_row(player_s *player, int nrow)
+{
+ int i;
+
+ // Ensure in range
+ // TODO: work out correct behaviour of out of range values
+ if(nrow < 0 || nrow >= 64)
+ {
+ return;
+ }
+
+ // Get patptr
+ const uint8_t *p = player->modbase + (((uint32_t)(f3m_get_para(&player->pat_para[player->cpat])))*16);
+ p += 2;
+
+ // Walk some number of rows
+ for(i = 0; i < nrow; i++)
+ {
+ for(;;)
+ {
+ uint8_t v = *(p++);
+ if(v == 0) break;
+ if((v & 0x80) != 0) p += 2;
+ if((v & 0x40) != 0) p += 1;
+ if((v & 0x20) != 0) p += 2;
+ }
+ }
+
+ // Update next patptr + values
+ player->patptr_next = p;
+ player->crow = nrow-1;
+}
+
+void f3m_effect_nop(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+}
+
+void f3m_effect_Axx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0 && pefp >= 1)
+ player->speed = pefp;
+}
+
+void f3m_effect_Bxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ // TODO: handle Bxx/Cxx combined
+ player->cord = pefp-1;
+ player->crow = 64;
+ }
+}
+
+void f3m_effect_Cxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ if(player->patptr_next == NULL)
+ {
+ // TODO: actually look up the jump value
+ player->crow = 64;
+ }
+ }
+}
+
+void f3m_effect_Dxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ f3m_player_eff_slide_vol(player, vchn, tick == 0);
+}
+
+void f3m_effect_Exx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ if(lefp >= 0xF0)
+ {
+ f3m_player_eff_slide_period(vchn, ((lefp & 0x0F)<<2));
+ } else if(lefp >= 0xE0) {
+ f3m_player_eff_slide_period(vchn, (lefp & 0x0F));
+ }
+ } else {
+ if(lefp < 0xE0)
+ {
+ f3m_player_eff_slide_period(vchn, (lefp<<2));
+ }
+ }
+}
+
+void f3m_effect_Fxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ if(lefp >= 0xF0)
+ {
+ f3m_player_eff_slide_period(vchn, -((lefp & 0x0F)<<2));
+ } else if(lefp >= 0xE0) {
+ f3m_player_eff_slide_period(vchn, -(lefp & 0x0F));
+ }
+ } else {
+ if(lefp < 0xE0)
+ {
+ f3m_player_eff_slide_period(vchn, -(lefp<<2));
+ }
+ }
+}
+
+void f3m_effect_Gxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ lefp = (pefp != 0 ? pefp : vchn->mem_gxx);
+ vchn->mem_gxx = lefp;
+ } else {
+ lefp = vchn->mem_gxx;
+
+ if(vchn->period < vchn->gxx_period)
+ {
+ vchn->period += lefp<<2;
+ if(vchn->period > vchn->gxx_period)
+ vchn->period = vchn->gxx_period;
+ vchn->freq = f3m_calc_period_freq(vchn->period);
+
+ } else if(vchn->period > vchn->gxx_period) {
+ vchn->period -= lefp<<2;
+ if(vchn->period < vchn->gxx_period)
+ vchn->period = vchn->gxx_period;
+ vchn->freq = f3m_calc_period_freq(vchn->period);
+ }
+ }
+}
+
+void f3m_effect_Hxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ lefp = pefp;
+ if((lefp&0x0F) == 0) lefp |= vchn->mem_hxx&0x0F;
+ if((lefp&0xF0) == 0) lefp |= vchn->mem_hxx&0xF0;
+ vchn->mem_hxx = lefp;
+ } else {
+ lefp = vchn->mem_hxx;
+
+ f3m_player_eff_vibrato(vchn, lefp, 2);
+ }
+}
+
+void f3m_effect_Kxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick != 0)
+ {
+ f3m_effect_Hxx(player, vchn, tick, 0, 0);
+ f3m_effect_Dxx(player, vchn, tick, pefp, lefp);
+ }
+}
+
+void f3m_effect_Lxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick != 0)
+ {
+ f3m_effect_Gxx(player, vchn, tick, 0, 0);
+ f3m_effect_Dxx(player, vchn, tick, pefp, lefp);
+ }
+}
+
+void f3m_effect_Qxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ // Notes:
+ // 1. When effect is not Qxy, rtg_count is reset.
+ // 2. Current y (from lefp, not special mem) is used as a threshold.
+ // 3. When y is exceeded, change volume according to current x.
+
+ int voldrop = (lefp>>4);
+ int rtick = (lefp&15);
+
+ if(rtick != 0 && vchn->rtg_count >= rtick)
+ {
+ // Retrigger
+ // TODO: work out what happens when we've already done a period or volume slide
+ // TODO:
+ f3m_note_retrig(player, vchn);
+
+ if(voldrop < 8)
+ {
+ if(voldrop < 6)
+ {
+ vchn->midvol -= (1<<voldrop);
+ if(vchn->midvol < 0) vchn->midvol = 0;
+ } else if(voldrop == 6) {
+ // *2/3, which according to FC is exactly the same as 5/8
+ vchn->midvol = (vchn->midvol*5)>>3;
+ } else {
+ // *1/2
+ vchn->midvol = vchn->midvol>>1;
+ }
+
+ } else {
+ voldrop -= 8;
+ if(voldrop < 6)
+ {
+ vchn->midvol += (1<<voldrop);
+ } else if(voldrop == 6) {
+ // *3/2
+ vchn->midvol = (vchn->midvol*3)>>1;
+ } else {
+ // *2
+ vchn->midvol = vchn->midvol<<1;
+ }
+
+ // XXX: do we deal with the case where volume > 63 before doubling?
+ if(vchn->midvol > 63) vchn->midvol = 63;
+ }
+
+ vchn->rtg_count = 0;
+ f3m_update_outvol(player, vchn);
+ }
+
+ vchn->rtg_count++;
+}
+
+void f3m_effect_Rxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ // TODO: actual tremolo
+
+ if(tick != 0 && vchn->insvol != 0)
+ {
+ int vspeed = (lefp>>4);
+ int vdepth = (lefp&15);
+
+ // TODO: support other waveforms
+ // TODO: find rounding + direction
+ int vval = f3m_sintab[vchn->tre_offs&31];
+ if(vchn->tre_offs & 32) vval = -vval;
+ vval *= vdepth;
+ vval += (1<<(5-1));
+ vval >>= 5;
+
+ // TODO: get clamp range
+ vchn->midvol = vchn->insvol + vval;
+ if(vchn->midvol < 0) vchn->midvol = 0;
+ if(vchn->midvol > 63) vchn->midvol = 63;
+ f3m_update_outvol(player, vchn);
+
+ vchn->tre_offs += vspeed;
+ }
+}
+
+void f3m_effect_Sxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ switch(lefp>>4)
+ {
+ case 0x8:
+ if(tick == 0)
+ if((player->mod->mvol&0x80)!=0)
+ {
+ vchn->pan = lefp & 0x0F;
+ }
+ break;
+
+ case 0xB:
+ // TODO confirm SBx behaviour
+ if(tick == 0)
+ {
+ if((lefp & 0x0F) == 0)
+ {
+ player->repeat_row = player->crow;
+ } else {
+ if(player->repeat_count == 0)
+ {
+ player->repeat_count = lefp & 0x0F;
+ } else {
+ player->repeat_count--;
+ }
+
+ if(player->repeat_count != 0)
+ {
+ f3m_jump_to_row(player, player->repeat_row);
+ } else {
+ player->repeat_row = player->crow + 1;
+ }
+ }
+ }
+ break;
+
+ case 0xC:
+ // SC0 is ignored
+ // TODO: Make this work:
+ // "Playback is temporarily frozen and may be resumed by EFGHJKLU"
+ if(tick != 0 && (lefp&0x0F) == tick)
+ {
+ vchn->spu_data = 0;
+ vchn->priority = F3M_PRIO_MUSIC_OFF;
+ vchn->midvol = 0;
+ f3m_update_outvol(player, vchn);
+ }
+ break;
+
+ case 0xD:
+ // TODO confirm SD0 behaviour
+ if(tick != 0 && (lefp&0x0F) == tick)
+ {
+ f3m_note_retrig(player, vchn);
+ }
+ break;
+ }
+}
+
+void f3m_effect_Txx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(pefp >= 33)
+ {
+ player->tempo = pefp;
+ player->tempo_samples = f3m_calc_tempo_samples(player->tempo);
+ }
+
+}
+
+void f3m_effect_Uxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick == 0)
+ {
+ lefp = pefp;
+ if((lefp&0x0F) == 0) lefp |= vchn->mem_hxx&0x0F;
+ if((lefp&0xF0) == 0) lefp |= vchn->mem_hxx&0xF0;
+ vchn->mem_hxx = lefp;
+ } else {
+ lefp = vchn->mem_hxx;
+
+ f3m_player_eff_vibrato(vchn, lefp, 0);
+ }
+}
+
+void f3m_effect_Vxx(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp)
+{
+ (void)player; (void)vchn; (void)tick; (void)pefp; (void)lefp;
+
+ if(tick != 0)
+ {
+ if(pefp >= 0x00 && pefp <= 0x40)
+ {
+ player->gvol = lefp;
+ }
+ }
+}
+
+
+void (*(f3m_effect_tab[32]))(player_s *player, vchn_s *vchn, int tick, int pefp, int lefp) = {
+ f3m_effect_nop, f3m_effect_Axx, f3m_effect_Bxx, f3m_effect_Cxx,
+ f3m_effect_Dxx, f3m_effect_Exx, f3m_effect_Fxx, f3m_effect_Gxx,
+ f3m_effect_Hxx, f3m_effect_nop, f3m_effect_nop, f3m_effect_Kxx,
+ f3m_effect_Lxx, f3m_effect_nop, f3m_effect_nop, f3m_effect_nop,
+
+ f3m_effect_nop, f3m_effect_Qxx, f3m_effect_Rxx, f3m_effect_Sxx,
+ f3m_effect_Txx, f3m_effect_Uxx, f3m_effect_Vxx, f3m_effect_nop,
+ f3m_effect_nop, f3m_effect_nop, f3m_effect_nop, f3m_effect_nop,
+ f3m_effect_nop, f3m_effect_nop, f3m_effect_nop, f3m_effect_nop,
+};
+
+static void f3m_player_play_newnote(player_s *player)
+{
+ int i;
+
+ // Advance row
+ player->crow++;
+ if(player->crow >= 64)
+ {
+ player->crow = 0;
+
+ // Advance order
+ player->cord++;
+ while(player->cord < player->mod->ord_num && player->ord_list[player->cord] == 0xFE)
+ player->cord++;
+ if(player->cord >= player->mod->ord_num || player->ord_list[player->cord] == 0xFF)
+ player->cord = 0;
+ while(player->cord < player->mod->ord_num && player->ord_list[player->cord] == 0xFE)
+ player->cord++;
+
+ player->cpat = player->ord_list[player->cord];
+ // assert(player->cpat < 200);
+ // assert(player->cpat < player->mod->pat_num);
+
+ // Get new pattern pointer
+ player->patptr = player->modbase + (((uint32_t)(f3m_get_para(&player->pat_para[player->cpat])))*16);
+ player->patptr += 2;
+ }
+
+ // Clear vchn pattern data
+ for(i = 0; i < F3M_VCHNS; i++)
+ {
+ vchn_s *vchn = &(player->vchn[i]);
+ vchn->eft = 0x00;
+ vchn->efp = 0x00;
+ }
+
+ // Read pattern data
+ if(player->patptr_next != NULL)
+ {
+ player->patptr = player->patptr_next;
+ player->patptr_next = NULL;
+ }
+
+ if(player->patptr == NULL)
+ return;
+
+ const uint8_t *p = player->patptr;
+
+ for(;;)
+ {
+ uint8_t cv = *(p++);
+ if(cv == 0) break;
+ vchn_s *vchn = &(player->vchn[cv&15]); // TODO proper channel map check?
+
+ uint8_t pnote = 0xFF;
+ uint8_t pins = 0x00;
+ uint8_t pvol = 0xFF;
+ uint8_t peft = 0x00;
+ uint8_t pefp = 0x00;
+
+ if((cv & 0x20) != 0)
+ {
+ pnote = *(p++);
+ pins = *(p++);
+ }
+
+ if((cv & 0x40) != 0)
+ {
+ pvol = *(p++);
+ }
+
+ if((cv & 0x80) != 0)
+ {
+ peft = *(p++);
+ pefp = *(p++);
+ peft &= 0x1F;
+ }
+
+ vchn->eft = peft;
+ vchn->efp = pefp;
+ if(pefp != 0) vchn->lefp = pefp;
+ uint8_t lefp = vchn->lefp;
+
+ // TODO: DO THIS PROPERLY
+ if(pnote == 0xFE)
+ {
+ vchn->spu_data = 0;
+ vchn->priority = F3M_PRIO_MUSIC_OFF;
+
+ } else if((pnote < 0x80 && (pins != 0 || vchn->lins != 0))
+ || (pnote == 0xFF && pins != 0)) {
+ int iidx = (pins == 0 ? vchn->lins : pins);
+ vchn->lins = iidx;
+ const ins_s *ins = player->modbase + (((uint32_t)(f3m_get_para(&player->ins_para[iidx-1])))*16);
+
+ // TODO: work out correct rounding
+ if(pvol != 0xFF || pins != 0)
+ {
+ vchn->insvol = (pvol != 0xFF ? pvol
+ : pins != 0 ? ins->vol
+ : vchn->insvol);
+ if(vchn->insvol > 63) vchn->insvol = 63; // lesser-known quirk
+ vchn->midvol = vchn->insvol;
+ }
+
+ // TODO: work out what happens on note end when ins but no note
+
+ if(vchn->spu_data == 0 || pnote < 0x80)
+ {
+ int note = (pnote < 0x80 ? pnote : vchn->last_note);
+ vchn->last_note = note;
+
+ if(peft != ('S'-'A'+1) || (lefp&0xF0) != 0xD0)
+ f3m_note_retrig(player, vchn);
+ }
+
+ f3m_update_outvol(player, vchn);
+ }
+
+ if((peft == ('S'-'A'+1) && (lefp&0xF0) == 0xD0) && pnote >= 0x80)
+ {
+ // Cancel effect if no note to trigger (e.g. CLICK.S3M)
+ // TODO: Check if volume column has any effect
+ vchn->eft = 0;
+ }
+
+ if(pvol < 0x80)
+ {
+ vchn->insvol = pvol;
+ if(vchn->insvol > 63) vchn->insvol = 63;
+ vchn->midvol = vchn->insvol;
+ f3m_update_outvol(player, vchn);
+ }
+
+ if(peft != ('Q'-'A'+1))
+ {
+ vchn->rtg_count = 0;
+ }
+
+ f3m_effect_tab[peft](player, vchn, 0, pefp, lefp);
+ }
+
+ player->patptr = p;
+}
+
+void f3m_player_play_newtick(player_s *player)
+{
+ int i;
+
+ player->ctick++;
+ if(player->ctick >= player->speed)
+ {
+ player->ctick = 0;
+ f3m_player_play_newnote(player);
+ } else {
+ for(i = 0; i < F3M_VCHNS; i++)
+ {
+ vchn_s *vchn = &(player->vchn[i]);
+
+ uint8_t peft = vchn->eft;
+ uint8_t pefp = vchn->efp;
+ uint8_t lefp = vchn->lefp;
+
+ f3m_effect_tab[peft&31](player, vchn, player->ctick, pefp, lefp);
+ }
+
+ }
+}
+
+void f3m_player_play(player_s *player)
+{
+ int i;
+ const int blen = F3M_BUFLEN;
+
+ // Check if we have a new tick
+ while(player->tempo_wait < 0)
+ {
+ f3m_player_play_newtick(player);
+ player->tempo_wait += player->tempo_samples;
+ }
+
+ player->tempo_wait -= blen;
+
+ // TARGET_PSX.
+ // We need to use hardware channels for this.
+ uint32_t kon_mask = 0;
+
+ for(i = 0; i < F3M_VCHNS; i++)
+ {
+ vchn_s *vchn = &(player->vchn[i]);
+
+ // Channel enabled?
+ // TODO: handle note offs properly
+ if(vchn->spu_data == 0)
+ {
+ if((vchn->offs & 1) != 0)
+ {
+ vchn->offs &= ~1;
+ SsKeyOff(i+player->basevoice);
+ }
+
+ continue;
+ }
+
+ // Output sample
+ uint16_t spu_offs = vchn->spu_data;
+ uint16_t spu_offs_lpbeg = vchn->spu_data_lpbeg;
+ int32_t offs = vchn->offs;
+ int32_t lvol = vchn->outvol<<7;
+ int32_t rvol = vchn->outvol<<7;
+ if(vchn->pan < 0x8)
+ {
+ lvol = (lvol*(vchn->pan*2+1))/15;
+ } else {
+ rvol = (rvol*((15-vchn->pan)*2+1))/15;
+ }
+ const int32_t freq = vchn->freq;
+
+ if((vchn->offs & 1) == 0)
+ {
+ SsVoiceStartAddr(i+player->basevoice, (spu_offs + (((offs+14)/28)<<1)) << 3);
+ SsVoiceRepeatAddr(i+player->basevoice, spu_offs_lpbeg << 3);
+ SsVoiceADSRRaw(i+player->basevoice, 0x83FF, 0x9FC0);
+
+ kon_mask |= (1<<(i+player->basevoice));
+ vchn->offs |= 1;
+ }
+
+ if(player->maxvolume != SPU_MAXVOL)
+ {
+ lvol = (lvol * player->maxvolume) / SPU_MAXVOL;
+ rvol = (rvol * player->maxvolume) / SPU_MAXVOL;
+ }
+
+ if(player->monomode)
+ {
+ if(lvol > rvol)
+ rvol = lvol;
+ else
+ lvol = rvol;
+ }
+
+ SsVoiceVol(i+player->basevoice, lvol, rvol);
+ SsVoicePitch(i+player->basevoice, freq>>4);
+ }
+
+ SsKeyOnMask(kon_mask);
+}
+
+void f3m_player_stop(player_s *player)
+{
+ int i;
+
+ for(i = 0; i < F3M_VCHNS; i++)
+ {
+ SsVoiceVol(i+player->basevoice, 0, 0);
+ SsVoiceADSRRaw(i+player->basevoice, 0, 0);
+ }
+}
diff --git a/libf3m/f3m.h b/libf3m/f3m.h
new file mode 100644
index 0000000..4ae4e35
--- /dev/null
+++ b/libf3m/f3m.h
@@ -0,0 +1,172 @@
+#ifndef _F3M_H
+#define _F3M_H
+
+#define F3M_FREQ 44100
+#define F3M_BUFLEN 882
+#define F3M_CHNS 2
+
+#define F3M_VCHNS 20
+#define F3M_PRIO_NORMAL 50
+#define F3M_PRIO_MUSIC_OFF 100
+#define F3M_PRIO_MUSIC 0x7FFF
+
+typedef struct
+{
+ uint8_t name[28];
+ uint8_t magic[4];
+ uint16_t ord_num, ins_num, pat_num;
+ uint16_t flags, ver, smptyp;
+ uint8_t magic_scrm[4];
+ uint8_t gvol, ispeed, itempo, mvol;
+ uint8_t uclick, defpanFC;
+ uint8_t unused1[8];
+ uint16_t special;
+ uint8_t cset[32];
+ uint8_t extra[];
+}__attribute__((__packed__)) mod_s;
+
+typedef struct
+{
+ uint16_t spu_data;
+ uint16_t spu_data_lpbeg;
+
+ int32_t len;
+ int32_t len_loop;
+
+ int32_t period;
+ int32_t gxx_period;
+
+ int32_t freq;
+ int32_t offs;
+ uint16_t suboffs;
+ int16_t priority;
+
+ int8_t insvol; // assigned on note start
+ int8_t midvol; // changed on slides
+ int8_t outvol; // actual output
+ uint8_t pan;
+
+ uint8_t vib_offs;
+ uint8_t tre_offs;
+ uint8_t rtg_count;
+
+ uint8_t eft, efp, lefp, last_note;
+ uint8_t lins;
+ uint8_t mem_gxx, mem_hxx, mem_oxx;
+} vchn_s;
+
+typedef struct
+{
+ const mod_s *mod;
+ const void *modbase;
+ const uint16_t *ins_para;
+ const uint16_t *pat_para;
+ const uint8_t *ord_list;
+
+ int32_t speed, tempo;
+ int32_t gvol;
+ int32_t ctick, tempo_samples, tempo_wait;
+ int32_t cord, cpat, crow;
+ const uint8_t *patptr;
+ const uint8_t *patptr_next;
+ int32_t repeat_row, repeat_count;
+
+ int sfxoffs;
+ int ccount;
+
+ uint16_t psx_spu_offset[99];
+ uint16_t psx_spu_offset_lpbeg[99];
+
+ uint32_t baseaddr;
+ int basevoice;
+ int monomode;
+ uint16_t maxvolume;
+
+ vchn_s vchn[F3M_VCHNS];
+} player_s;
+
+/**
+ * Create a module file structure from a data buffer.
+ * The data buffer must contain a valid S3M music module file.
+ * @param d Pointer to buffer memory
+ * @return Module file structure (NULL on error)
+ */
+
+mod_s *f3m_mod_load(uint32_t *d);
+
+/**
+ * Create a module file structure from a file with the given filename,
+ * The file must be a valid S3M music module file.
+ * @param fname Module file filename
+ * @return Module file structure (NULL on error)
+ */
+
+mod_s *f3m_mod_load_filename(const char *fname);
+
+/**
+ * Free the memory associated to a module file structure
+ * @param mod Pointer to module file structure
+ */
+
+void f3m_mod_free(mod_s *mod);
+
+/**
+ * Initialize a music player from a module file structure.
+ * This is just like calling f3m_player_init_ex(player, mod, 0, SPU_DATA_BASE_ADDR)
+ * @param player Pointer to memory of music player structure
+ * @param mod Pointer to module file structure
+ * @return Address in SPU memory after uploaded samples
+ */
+
+unsigned int f3m_player_init(player_s *player, mod_s *mod);
+
+/**
+ * Initialize a music player from a module file structure.
+ * @param player Pointer to memory of music player structure
+ * @param mod Pointer to module file structure
+ * @param basevoice Base voice to use to reproduce samples. Valid range is from 0 to (24 - F3M_VCHNS)
+ * @param baseaddr Base address in SPU memory for uploading samples.
+ * @return Address in SPU memory after uploaded samples
+ */
+
+unsigned int f3m_player_init_ex(player_s *player, mod_s *mod, int basevoice, unsigned int baseaddr);
+
+
+/**
+ * Make a music player play.
+ * This should be called roughly every 1/50th of a second on PAL systems,
+ * or every 1/60th of a second on NTSC systems; you can set a flag in a VBlank
+ * interrupt handler (see SetVBlankHandler()) to do this.
+ * This function is probably not re-entrant, so it is not recommended to call it
+ * directly from the VBlank handler.
+ * @param player Pointer to music player structure
+ */
+
+void f3m_player_play(player_s *player);
+
+/**
+ * Stop a music player.
+ * @param player Pointer to music player structure
+ */
+
+void f3m_player_stop(player_s *player);
+
+/**
+ * Set a music player to mono mode. Music players are by default in stereo mode.
+ * @param player Pointer to music player structure
+ * @param onoff Non-zero for mono mode, zero for stereo mode
+ * @return Previous status of mono mode flag.
+ */
+
+int f3m_set_mono_mode(player_s *player, int onoff);
+
+/**
+ * Set maximum volume for a music player.
+ * Default volume for a music player is the maximum allowed by the SPU.
+ * @param player Pointer to music player structure
+ * @return Previous maximum volume.
+ */
+
+uint16_t f3m_set_max_volume(player_s *player, uint16_t maxvolume);
+
+#endif
diff --git a/libfixmath/Makefile b/libfixmath/Makefile
new file mode 100755
index 0000000..e490e92
--- /dev/null
+++ b/libfixmath/Makefile
@@ -0,0 +1,50 @@
+include ../Makefile.cfg
+
+#Project settings
+PROJECT = libfixmath
+LIB =
+SRC = .
+INC =
+
+#Compiler settings
+AR = mipsel-unknown-elf-ar
+CPP_FLAGS = $(CFLAGS) -O2 $(INC) -c
+CC_FLAGS = $(CFLAGS) -O2 $(INC) -c
+AS_FLAGS = $(CC_FLAGS) -D_ASSEMBLER_
+LD_FLAGS = -Wall
+
+# Find all source files
+SRC_CPP = $(foreach dir, $(SRC), $(wildcard $(dir)/*.cpp))
+SRC_C = $(foreach dir, $(SRC), $(wildcard $(dir)/*.c))
+SRC_S = $(foreach dir, $(SRC), $(wildcard $(dir)/*.S))
+OBJ_CPP = $(patsubst %.cpp, %.o, $(SRC_CPP))
+OBJ_C = $(patsubst %.c, %.o, $(SRC_C))
+OBJ_S = $(patsubst %.S, %.o, $(SRC_S))
+OBJ = $(OBJ_CPP) $(OBJ_C) $(OBJ_S)
+
+# Compile rules.
+.PHONY : all
+all: $(PROJECT).a
+
+$(PROJECT).a: $(OBJ)
+ $(AR) rcs $(PROJECT).a $(OBJ)
+
+$(OBJ_CPP) : %.o : %.cpp
+ $(CPP) $(CPP_FLAGS) -o $@ $<
+
+$(OBJ_C) : %.o : %.c
+ $(CC) $(CC_FLAGS) -Ifixmath -o $@ $<
+
+$(OBJ_S) : %.o : %.S
+ $(AS) $(AS_FLAGS) -o $@ $<
+
+install:
+ cp libfixmath.a $(TOOLCHAIN_PREFIX)/lib
+ mkdir -p $(TOOLCHAIN_PREFIX)/include/fixmath
+ cp fixmath/*.h $(TOOLCHAIN_PREFIX)/include/fixmath
+ cp fixmath.h $(TOOLCHAIN_PREFIX)/include
+
+# Clean rules
+.PHONY : clean
+clean:
+ rm -f $(PROJECT).a $(OBJ)
diff --git a/libfixmath/fix16.c b/libfixmath/fix16.c
new file mode 100755
index 0000000..72e1b4a
--- /dev/null
+++ b/libfixmath/fix16.c
@@ -0,0 +1,484 @@
+#include "fix16.h"
+#include "int64.h"
+
+
+/* Subtraction and addition with overflow detection.
+ * The versions without overflow detection are inlined in the header.
+ */
+#ifndef FIXMATH_NO_OVERFLOW
+fix16_t fix16_add(fix16_t a, fix16_t b)
+{
+ // Use unsigned integers because overflow with signed integers is
+ // an undefined operation (http://www.airs.com/blog/archives/120).
+ uint32_t _a = a, _b = b;
+ uint32_t sum = _a + _b;
+
+ // Overflow can only happen if sign of a == sign of b, and then
+ // it causes sign of sum != sign of a.
+ if (!((_a ^ _b) & 0x80000000) && ((_a ^ sum) & 0x80000000))
+ return fix16_overflow;
+
+ return sum;
+}
+
+fix16_t fix16_sub(fix16_t a, fix16_t b)
+{
+ uint32_t _a = a, _b = b;
+ uint32_t diff = _a - _b;
+
+ // Overflow can only happen if sign of a != sign of b, and then
+ // it causes sign of diff != sign of a.
+ if (((_a ^ _b) & 0x80000000) && ((_a ^ diff) & 0x80000000))
+ return fix16_overflow;
+
+ return diff;
+}
+
+/* Saturating arithmetic */
+fix16_t fix16_sadd(fix16_t a, fix16_t b)
+{
+ fix16_t result = fix16_add(a, b);
+
+ if (result == fix16_overflow)
+ return (a > 0) ? fix16_max : fix16_min;
+
+ return result;
+}
+
+fix16_t fix16_ssub(fix16_t a, fix16_t b)
+{
+ fix16_t result = fix16_sub(a, b);
+
+ if (result == fix16_overflow)
+ return (a > 0) ? fix16_max : fix16_min;
+
+ return result;
+}
+#endif
+
+
+
+/* 64-bit implementation for fix16_mul. Fastest version for e.g. ARM Cortex M3.
+ * Performs a 32*32 -> 64bit multiplication. The middle 32 bits are the result,
+ * bottom 16 bits are used for rounding, and upper 16 bits are used for overflow
+ * detection.
+ */
+
+#if !defined(FIXMATH_NO_64BIT) && !defined(FIXMATH_OPTIMIZE_8BIT)
+fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1)
+{
+ int64_t product = (int64_t)inArg0 * inArg1;
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ // The upper 17 bits should all be the same (the sign).
+ uint32_t upper = (product >> 47);
+ #endif
+
+ if (product < 0)
+ {
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (~upper)
+ return fix16_overflow;
+ #endif
+
+ #ifndef FIXMATH_NO_ROUNDING
+ // This adjustment is required in order to round -1/2 correctly
+ product--;
+ #endif
+ }
+ else
+ {
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (upper)
+ return fix16_overflow;
+ #endif
+ }
+
+ #ifdef FIXMATH_NO_ROUNDING
+ return product >> 16;
+ #else
+ fix16_t result = product >> 16;
+ result += (product & 0x8000) >> 15;
+
+ return result;
+ #endif
+}
+#endif
+
+/* 32-bit implementation of fix16_mul. Potentially fast on 16-bit processors,
+ * and this is a relatively good compromise for compilers that do not support
+ * uint64_t. Uses 16*16->32bit multiplications.
+ */
+#if defined(FIXMATH_NO_64BIT) && !defined(FIXMATH_OPTIMIZE_8BIT)
+fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1)
+{
+ // Each argument is divided to 16-bit parts.
+ // AB
+ // * CD
+ // -----------
+ // BD 16 * 16 -> 32 bit products
+ // CB
+ // AD
+ // AC
+ // |----| 64 bit product
+ int32_t A = (inArg0 >> 16), C = (inArg1 >> 16);
+ uint32_t B = (inArg0 & 0xFFFF), D = (inArg1 & 0xFFFF);
+
+ int32_t AC = A*C;
+ int32_t AD_CB = A*D + C*B;
+ uint32_t BD = B*D;
+
+ int32_t product_hi = AC + (AD_CB >> 16);
+
+ // Handle carry from lower 32 bits to upper part of result.
+ uint32_t ad_cb_temp = AD_CB << 16;
+ uint32_t product_lo = BD + ad_cb_temp;
+ if (product_lo < BD)
+ product_hi++;
+
+#ifndef FIXMATH_NO_OVERFLOW
+ // The upper 17 bits should all be the same (the sign).
+ if (product_hi >> 31 != product_hi >> 15)
+ return fix16_overflow;
+#endif
+
+#ifdef FIXMATH_NO_ROUNDING
+ return (product_hi << 16) | (product_lo >> 16);
+#else
+ // Subtracting 0x8000 (= 0.5) and then using signed right shift
+ // achieves proper rounding to result-1, except in the corner
+ // case of negative numbers and lowest word = 0x8000.
+ // To handle that, we also have to subtract 1 for negative numbers.
+ uint32_t product_lo_tmp = product_lo;
+ product_lo -= 0x8000;
+ product_lo -= (uint32_t)product_hi >> 31;
+ if (product_lo > product_lo_tmp)
+ product_hi--;
+
+ // Discard the lowest 16 bits. Note that this is not exactly the same
+ // as dividing by 0x10000. For example if product = -1, result will
+ // also be -1 and not 0. This is compensated by adding +1 to the result
+ // and compensating this in turn in the rounding above.
+ fix16_t result = (product_hi << 16) | (product_lo >> 16);
+ result += 1;
+ return result;
+#endif
+}
+#endif
+
+/* 8-bit implementation of fix16_mul. Fastest on e.g. Atmel AVR.
+ * Uses 8*8->16bit multiplications, and also skips any bytes that
+ * are zero.
+ */
+#if defined(FIXMATH_OPTIMIZE_8BIT)
+fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1)
+{
+ uint32_t _a = (inArg0 >= 0) ? inArg0 : (-inArg0);
+ uint32_t _b = (inArg1 >= 0) ? inArg1 : (-inArg1);
+
+ uint8_t va[4] = {_a, (_a >> 8), (_a >> 16), (_a >> 24)};
+ uint8_t vb[4] = {_b, (_b >> 8), (_b >> 16), (_b >> 24)};
+
+ uint32_t low = 0;
+ uint32_t mid = 0;
+
+ // Result column i depends on va[0..i] and vb[i..0]
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ // i = 6
+ if (va[3] && vb[3]) return fix16_overflow;
+ #endif
+
+ // i = 5
+ if (va[2] && vb[3]) mid += (uint16_t)va[2] * vb[3];
+ if (va[3] && vb[2]) mid += (uint16_t)va[3] * vb[2];
+ mid <<= 8;
+
+ // i = 4
+ if (va[1] && vb[3]) mid += (uint16_t)va[1] * vb[3];
+ if (va[2] && vb[2]) mid += (uint16_t)va[2] * vb[2];
+ if (va[3] && vb[1]) mid += (uint16_t)va[3] * vb[1];
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (mid & 0xFF000000) return fix16_overflow;
+ #endif
+ mid <<= 8;
+
+ // i = 3
+ if (va[0] && vb[3]) mid += (uint16_t)va[0] * vb[3];
+ if (va[1] && vb[2]) mid += (uint16_t)va[1] * vb[2];
+ if (va[2] && vb[1]) mid += (uint16_t)va[2] * vb[1];
+ if (va[3] && vb[0]) mid += (uint16_t)va[3] * vb[0];
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (mid & 0xFF000000) return fix16_overflow;
+ #endif
+ mid <<= 8;
+
+ // i = 2
+ if (va[0] && vb[2]) mid += (uint16_t)va[0] * vb[2];
+ if (va[1] && vb[1]) mid += (uint16_t)va[1] * vb[1];
+ if (va[2] && vb[0]) mid += (uint16_t)va[2] * vb[0];
+
+ // i = 1
+ if (va[0] && vb[1]) low += (uint16_t)va[0] * vb[1];
+ if (va[1] && vb[0]) low += (uint16_t)va[1] * vb[0];
+ low <<= 8;
+
+ // i = 0
+ if (va[0] && vb[0]) low += (uint16_t)va[0] * vb[0];
+
+ #ifndef FIXMATH_NO_ROUNDING
+ low += 0x8000;
+ #endif
+ mid += (low >> 16);
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (mid & 0x80000000)
+ return fix16_overflow;
+ #endif
+
+ fix16_t result = mid;
+
+ /* Figure out the sign of result */
+ if ((inArg0 >= 0) != (inArg1 >= 0))
+ {
+ result = -result;
+ }
+
+ return result;
+}
+#endif
+
+#ifndef FIXMATH_NO_OVERFLOW
+/* Wrapper around fix16_mul to add saturating arithmetic. */
+fix16_t fix16_smul(fix16_t inArg0, fix16_t inArg1) {
+ fix16_t result = fix16_mul(inArg0, inArg1);
+
+ if (result == fix16_overflow)
+ {
+ if ((inArg0 >= 0) == (inArg1 >= 0))
+ return fix16_max;
+ else
+ return fix16_min;
+ }
+
+ return result;
+}
+#endif
+
+/* 32-bit implementation of fix16_div. Fastest version for e.g. ARM Cortex M3.
+ * Performs 32-bit divisions repeatedly to reduce the remainder. For this to
+ * be efficient, the processor has to have 32-bit hardware division.
+ */
+#if !defined(FIXMATH_OPTIMIZE_8BIT)
+#ifdef __GNUC__
+// Count leading zeros, using processor-specific instruction if available.
+#define clz(x) __builtin_clzl(x)
+#else
+static uint8_t clz(uint32_t x)
+{
+ uint8_t result = 0;
+ if (x == 0) return 32;
+ while (!(x & 0xF0000000)) { result += 4; x <<= 4; }
+ while (!(x & 0x80000000)) { result += 1; x <<= 1; }
+ return result;
+}
+#endif
+
+fix16_t fix16_div(fix16_t a, fix16_t b)
+{
+ // This uses a hardware 32/32 bit division multiple times, until we have
+ // computed all the bits in (a<<17)/b. Usually this takes 1-3 iterations.
+
+ if (b == 0)
+ return fix16_min;
+
+ uint32_t remainder = (a >= 0) ? a : (-a);
+ uint32_t divider = (b >= 0) ? b : (-b);
+ uint32_t quotient = 0;
+ int bit_pos = 17;
+
+ // Kick-start the division a bit.
+ // This improves speed in the worst-case scenarios where N and D are large
+ // It gets a lower estimate for the result by N/(D >> 17 + 1).
+ if (divider & 0xFFF00000)
+ {
+ uint32_t shifted_div = ((divider >> 17) + 1);
+ quotient = remainder / shifted_div;
+ remainder -= ((uint64_t)quotient * divider) >> 17;
+ }
+
+ // If the divider is divisible by 2^n, take advantage of it.
+ while (!(divider & 0xF) && bit_pos >= 4)
+ {
+ divider >>= 4;
+ bit_pos -= 4;
+ }
+
+ while (remainder && bit_pos >= 0)
+ {
+ // Shift remainder as much as we can without overflowing
+ int shift = clz(remainder);
+ if (shift > bit_pos) shift = bit_pos;
+ remainder <<= shift;
+ bit_pos -= shift;
+
+ uint32_t div = remainder / divider;
+ remainder = remainder % divider;
+ quotient += div << bit_pos;
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (div & ~(0xFFFFFFFF >> bit_pos))
+ return fix16_overflow;
+ #endif
+
+ remainder <<= 1;
+ bit_pos--;
+ }
+
+ #ifndef FIXMATH_NO_ROUNDING
+ // Quotient is always positive so rounding is easy
+ quotient++;
+ #endif
+
+ fix16_t result = quotient >> 1;
+
+ // Figure out the sign of the result
+ if ((a ^ b) & 0x80000000)
+ {
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (result == fix16_min)
+ return fix16_overflow;
+ #endif
+
+ result = -result;
+ }
+
+ return result;
+}
+#endif
+
+/* Alternative 32-bit implementation of fix16_div. Fastest on e.g. Atmel AVR.
+ * This does the division manually, and is therefore good for processors that
+ * do not have hardware division.
+ */
+#if defined(FIXMATH_OPTIMIZE_8BIT)
+fix16_t fix16_div(fix16_t a, fix16_t b)
+{
+ // This uses the basic binary restoring division algorithm.
+ // It appears to be faster to do the whole division manually than
+ // trying to compose a 64-bit divide out of 32-bit divisions on
+ // platforms without hardware divide.
+
+ if (b == 0)
+ return fix16_min;
+
+ uint32_t remainder = (a >= 0) ? a : (-a);
+ uint32_t divider = (b >= 0) ? b : (-b);
+
+ uint32_t quotient = 0;
+ uint32_t bit = 0x10000;
+
+ /* The algorithm requires D >= R */
+ while (divider < remainder)
+ {
+ divider <<= 1;
+ bit <<= 1;
+ }
+
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (!bit)
+ return fix16_overflow;
+ #endif
+
+ if (divider & 0x80000000)
+ {
+ // Perform one step manually to avoid overflows later.
+ // We know that divider's bottom bit is 0 here.
+ if (remainder >= divider)
+ {
+ quotient |= bit;
+ remainder -= divider;
+ }
+ divider >>= 1;
+ bit >>= 1;
+ }
+
+ /* Main division loop */
+ while (bit && remainder)
+ {
+ if (remainder >= divider)
+ {
+ quotient |= bit;
+ remainder -= divider;
+ }
+
+ remainder <<= 1;
+ bit >>= 1;
+ }
+
+ #ifndef FIXMATH_NO_ROUNDING
+ if (remainder >= divider)
+ {
+ quotient++;
+ }
+ #endif
+
+ fix16_t result = quotient;
+
+ /* Figure out the sign of result */
+ if ((a ^ b) & 0x80000000)
+ {
+ #ifndef FIXMATH_NO_OVERFLOW
+ if (result == fix16_min)
+ return fix16_overflow;
+ #endif
+
+ result = -result;
+ }
+
+ return result;
+}
+#endif
+
+#ifndef FIXMATH_NO_OVERFLOW
+/* Wrapper around fix16_div to add saturating arithmetic. */
+fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) {
+ fix16_t result = fix16_div(inArg0, inArg1);
+
+ if (result == fix16_overflow)
+ {
+ if ((inArg0 >= 0) == (inArg1 >= 0))
+ return fix16_max;
+ else
+ return fix16_min;
+ }
+
+ return result;
+}
+#endif
+
+fix16_t fix16_lerp8(fix16_t inArg0, fix16_t inArg1, uint8_t inFract) {
+ int64_t tempOut = int64_mul_i32_i32(inArg0, ((1 << 8) - inFract));
+ tempOut = int64_add(tempOut, int64_mul_i32_i32(inArg1, inFract));
+ tempOut = int64_shift(tempOut, -8);
+ return (fix16_t)int64_lo(tempOut);
+}
+
+fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract) {
+ int64_t tempOut = int64_mul_i32_i32(inArg0, ((1 << 16) - inFract));
+ tempOut = int64_add(tempOut, int64_mul_i32_i32(inArg1, inFract));
+ tempOut = int64_shift(tempOut, -16);
+ return (fix16_t)int64_lo(tempOut);
+}
+
+#ifndef FIXMATH_NO_64BIT
+fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract) {
+ int64_t tempOut;
+ tempOut = ((int64_t)inArg0 * (0 - inFract));
+ tempOut += ((int64_t)inArg1 * inFract);
+ tempOut >>= 32;
+ return (fix16_t)tempOut;
+}
+#endif
diff --git a/libfixmath/fix16_exp.c b/libfixmath/fix16_exp.c
new file mode 100755
index 0000000..e7e92e4
--- /dev/null
+++ b/libfixmath/fix16_exp.c
@@ -0,0 +1,48 @@
+#include "fix16.h"
+#include "int64.h"
+
+
+
+#ifndef FIXMATH_NO_CACHE
+static fix16_t _fix16_exp_cache_index[4096] = { 0 };
+static fix16_t _fix16_exp_cache_value[4096] = { 0 };
+#endif
+
+
+
+fix16_t fix16_exp(fix16_t inValue) {
+ if(inValue == 0)
+ return fix16_one;
+ if(inValue == fix16_one)
+ return fix16_e;
+ if(inValue > 681391)
+ return fix16_max;
+ if(inValue < -726817)
+ return 0;
+
+ #ifndef FIXMATH_NO_CACHE
+ fix16_t tempIndex = (inValue ^ (inValue >> 16));
+ tempIndex = (inValue ^ (inValue >> 4)) & 0x0FFF;
+ if(_fix16_exp_cache_index[tempIndex] == inValue)
+ return _fix16_exp_cache_value[tempIndex];
+ #endif
+
+ int64_t tempOut = int64_add(int64_from_int32(fix16_one), int64_from_int32(inValue));
+ int64_t tempValue = int64_from_int32(inValue);
+ uint32_t i, n;
+ for(i = 3, n = 2; i < 13; n *= i, i++) {
+ tempValue = int64_mul_i64_i32(tempValue, inValue);
+ #ifndef FIXMATH_NO_ROUNDING
+ tempValue = int64_add(tempValue, int64_from_int32(fix16_one >> 1));
+ #endif
+ tempValue = int64_shift(tempValue, -16);
+ tempOut = int64_add(tempOut, int64_div_i64_i32(tempValue, n));
+ }
+
+ #ifndef FIXMATH_NO_CACHE
+ _fix16_exp_cache_index[tempIndex] = inValue;
+ _fix16_exp_cache_value[tempIndex] = int64_lo(tempOut);
+ #endif
+
+ return int64_lo(tempOut);
+}
diff --git a/libfixmath/fix16_sqrt.c b/libfixmath/fix16_sqrt.c
new file mode 100755
index 0000000..13d31a8
--- /dev/null
+++ b/libfixmath/fix16_sqrt.c
@@ -0,0 +1,83 @@
+#include "fix16.h"
+
+/* The square root algorithm is quite directly from
+ * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
+ * An important difference is that it is split to two parts
+ * in order to use only 32-bit operations.
+ *
+ * Note that for negative numbers we return -sqrt(-inValue).
+ * Not sure if someone relies on this behaviour, but not going
+ * to break it for now. It doesn't slow the code much overall.
+ */
+fix16_t fix16_sqrt(fix16_t inValue) {
+ uint8_t neg = (inValue < 0);
+ uint32_t num = (neg ? -inValue : inValue);
+ uint32_t result = 0;
+ uint32_t bit;
+ uint8_t n;
+
+ // Many numbers will be less than 15, so
+ // this gives a good balance between time spent
+ // in if vs. time spent in the while loop
+ // when searching for the starting value.
+ if (num & 0xFFF00000)
+ bit = (uint32_t)1 << 30;
+ else
+ bit = (uint32_t)1 << 18;
+
+ while (bit > num) bit >>= 2;
+
+ // The main part is executed twice, in order to avoid
+ // using 64 bit values in computations.
+ for (n = 0; n < 2; n++)
+ {
+ // First we get the top 24 bits of the answer.
+ while (bit)
+ {
+ if (num >= result + bit)
+ {
+ num -= result + bit;
+ result = (result >> 1) + bit;
+ }
+ else
+ {
+ result = (result >> 1);
+ }
+ bit >>= 2;
+ }
+
+ if (n == 0)
+ {
+ // Then process it again to get the lowest 8 bits.
+ if (num > 65535)
+ {
+ // The remainder 'num' is too large to be shifted left
+ // by 16, so we have to add 1 to result manually and
+ // adjust 'num' accordingly.
+ // num = a - (result + 0.5)^2
+ // = num + result^2 - (result + 0.5)^2
+ // = num - result - 0.5
+ num -= result;
+ num = (num << 16) - 0x8000;
+ result = (result << 16) + 0x8000;
+ }
+ else
+ {
+ num <<= 16;
+ result <<= 16;
+ }
+
+ bit = 1 << 14;
+ }
+ }
+
+#ifndef FIXMATH_NO_ROUNDING
+ // Finally, if next bit would have been 1, round the result upwards.
+ if (num > result)
+ {
+ result++;
+ }
+#endif
+
+ return (neg ? -result : result);
+}
diff --git a/libfixmath/fix16_trig.c b/libfixmath/fix16_trig.c
new file mode 100755
index 0000000..6b53682
--- /dev/null
+++ b/libfixmath/fix16_trig.c
@@ -0,0 +1,171 @@
+#include <limits.h>
+#include "fix16.h"
+
+#if defined(FIXMATH_SIN_LUT)
+#include "fix16_trig_sin_lut.h"
+#elif !defined(FIXMATH_NO_CACHE)
+static fix16_t _fix16_sin_cache_index[4096] = { 0 };
+static fix16_t _fix16_sin_cache_value[4096] = { 0 };
+#endif
+
+#ifndef FIXMATH_NO_CACHE
+static fix16_t _fix16_atan_cache_index[2][4096] = { { 0 }, { 0 } };
+static fix16_t _fix16_atan_cache_value[4096] = { 0 };
+#endif
+
+
+fix16_t fix16_sin_parabola(fix16_t inAngle)
+{
+ fix16_t abs_inAngle, abs_retval, retval;
+ fix16_t mask;
+
+ /* Absolute function */
+ mask = (inAngle >> (sizeof(fix16_t)*CHAR_BIT-1));
+ abs_inAngle = (inAngle + mask) ^ mask;
+
+ /* On 0->PI, sin looks like xÂē that is :
+ - centered on PI/2,
+ - equals 1 on PI/2,
+ - equals 0 on 0 and PI
+ that means : 4/PI * x - 4/PIÂē * xÂē
+ Use abs(x) to handle (-PI) -> 0 zone.
+ */
+ retval = fix16_mul(FOUR_DIV_PI, inAngle) + fix16_mul( fix16_mul(_FOUR_DIV_PI2, inAngle), abs_inAngle );
+ /* At this point, retval equals sin(inAngle) on important points ( -PI, -PI/2, 0, PI/2, PI),
+ but is not very precise between these points
+ */
+ #ifndef FIXMATH_FAST_SIN
+ /* Absolute value of retval */
+ mask = (retval >> (sizeof(fix16_t)*CHAR_BIT-1));
+ abs_retval = (retval + mask) ^ mask;
+ /* So improve its precision by adding some x^4 component to retval */
+ retval += fix16_mul(X4_CORRECTION_COMPONENT, fix16_mul(retval, abs_retval) - retval );
+ #endif
+ return retval;
+}
+
+fix16_t fix16_sin(fix16_t inAngle) {
+ fix16_t tempAngle = inAngle % (fix16_pi << 1);
+
+ #ifdef FIXMATH_SIN_LUT
+ if(tempAngle < 0)
+ tempAngle += (fix16_pi << 1);
+
+ fix16_t tempOut;
+ if(tempAngle >= fix16_pi) {
+ tempAngle -= fix16_pi;
+ if(tempAngle >= (fix16_pi >> 1))
+ tempAngle = fix16_pi - tempAngle;
+ tempOut = -(tempAngle >= _fix16_sin_lut_count ? fix16_one : _fix16_sin_lut[tempAngle]);
+ } else {
+ if(tempAngle >= (fix16_pi >> 1))
+ tempAngle = fix16_pi - tempAngle;
+ tempOut = (tempAngle >= _fix16_sin_lut_count ? fix16_one : _fix16_sin_lut[tempAngle]);
+ }
+ #else
+ if(tempAngle > fix16_pi)
+ tempAngle -= (fix16_pi << 1);
+ else if(tempAngle < -fix16_pi)
+ tempAngle += (fix16_pi << 1);
+
+ #ifndef FIXMATH_NO_CACHE
+ fix16_t tempIndex = ((inAngle >> 5) & 0x00000FFF);
+ if(_fix16_sin_cache_index[tempIndex] == inAngle)
+ return _fix16_sin_cache_value[tempIndex];
+ #endif
+
+ fix16_t tempAngleSq = fix16_mul(tempAngle, tempAngle);
+
+ #ifndef FIXMATH_FAST_SIN // Most accurate version, accurate to ~2.1%
+ fix16_t tempOut = tempAngle;
+ tempAngle = fix16_mul(tempAngle, tempAngleSq);
+ tempOut -= (tempAngle / 6);
+ tempAngle = fix16_mul(tempAngle, tempAngleSq);
+ tempOut += (tempAngle / 120);
+ tempAngle = fix16_mul(tempAngle, tempAngleSq);
+ tempOut -= (tempAngle / 5040);
+ tempAngle = fix16_mul(tempAngle, tempAngleSq);
+ tempOut += (tempAngle / 362880);
+ tempAngle = fix16_mul(tempAngle, tempAngleSq);
+ tempOut -= (tempAngle / 39916800);
+ #else // Fast implementation, runs at 159% the speed of above 'accurate' version with an slightly lower accuracy of ~2.3%
+ fix16_t tempOut;
+ tempOut = fix16_mul(-13, tempAngleSq) + 546;
+ tempOut = fix16_mul(tempOut, tempAngleSq) - 10923;
+ tempOut = fix16_mul(tempOut, tempAngleSq) + 65536;
+ tempOut = fix16_mul(tempOut, tempAngle);
+ #endif
+
+ #ifndef FIXMATH_NO_CACHE
+ _fix16_sin_cache_index[tempIndex] = inAngle;
+ _fix16_sin_cache_value[tempIndex] = tempOut;
+ #endif
+ #endif
+
+ return tempOut;
+}
+
+fix16_t fix16_cos(fix16_t inAngle) {
+ return fix16_sin(inAngle + (fix16_pi >> 1));
+}
+
+fix16_t fix16_tan(fix16_t inAngle) {
+ return fix16_sdiv(fix16_sin(inAngle), fix16_cos(inAngle));
+}
+
+fix16_t fix16_asin(fix16_t inValue) {
+ if((inValue > fix16_one) || (inValue < -fix16_one))
+ return 0;
+ fix16_t tempOut;
+ tempOut = (fix16_one - fix16_mul(inValue, inValue));
+ tempOut = fix16_div(inValue, fix16_sqrt(tempOut));
+ tempOut = fix16_atan(tempOut);
+ return tempOut;
+}
+
+fix16_t fix16_acos(fix16_t inValue) {
+ return ((fix16_pi >> 1) - fix16_asin(inValue));
+}
+
+fix16_t fix16_atan2(fix16_t inY , fix16_t inX) {
+ fix16_t abs_inY, mask, angle, r, r_3;
+
+ #ifndef FIXMATH_NO_CACHE
+ uintptr_t hash = (inX ^ inY);
+ hash ^= hash >> 20;
+ hash &= 0x0FFF;
+ if((_fix16_atan_cache_index[0][hash] == inX) && (_fix16_atan_cache_index[1][hash] == inY))
+ return _fix16_atan_cache_value[hash];
+ #endif
+
+ /* Absolute inY */
+ mask = (inY >> (sizeof(fix16_t)*CHAR_BIT-1));
+ abs_inY = (inY + mask) ^ mask;
+
+ if (inX >= 0)
+ {
+ r = fix16_div( (inX - abs_inY), (inX + abs_inY));
+ r_3 = fix16_mul(fix16_mul(r, r),r);
+ angle = fix16_mul(0x00003240 , r_3) - fix16_mul(0x0000FB50,r) + PI_DIV_4;
+ } else {
+ r = fix16_div( (inX + abs_inY), (abs_inY - inX));
+ r_3 = fix16_mul(fix16_mul(r, r),r);
+ angle = fix16_mul(0x00003240 , r_3) - fix16_mul(0x0000FB50,r) + THREE_PI_DIV_4;
+ }
+ if (inY < 0)
+ {
+ angle = -angle;
+ }
+
+ #ifndef FIXMATH_NO_CACHE
+ _fix16_atan_cache_index[0][hash] = inX;
+ _fix16_atan_cache_index[1][hash] = inY;
+ _fix16_atan_cache_value[hash] = angle;
+ #endif
+
+ return angle;
+}
+
+fix16_t fix16_atan(fix16_t inValue) {
+ return fix16_atan2(inValue, fix16_one);
+}
diff --git a/libfixmath/fixmath.h b/libfixmath/fixmath.h
new file mode 100755
index 0000000..3f3cc74
--- /dev/null
+++ b/libfixmath/fixmath.h
@@ -0,0 +1,23 @@
+#ifndef __libfixmath_fixmath_h__
+#define __libfixmath_fixmath_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*!
+ \file fixmath.h
+ \brief Functions to perform fast accurate fixed-point math operations.
+*/
+
+#include <fixmath/uint32.h>
+#include <fixmath/int64.h>
+#include <fixmath/fract32.h>
+#include <fixmath/fix16.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libfixmath/fixmath/fix16.h b/libfixmath/fixmath/fix16.h
new file mode 100755
index 0000000..a2a49b1
--- /dev/null
+++ b/libfixmath/fixmath/fix16.h
@@ -0,0 +1,167 @@
+#ifndef __libfixmath_fix16_h__
+#define __libfixmath_fix16_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* These options may let the optimizer to remove some calls to the functions.
+ * Refer to http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+ */
+#ifndef FIXMATH_FUNC_ATTRS
+# ifdef __GNUC__
+# define FIXMATH_FUNC_ATTRS __attribute__((leaf, nothrow, pure))
+# else
+# define FIXMATH_FUNC_ATTRS
+# endif
+#endif
+
+#include <stdint.h>
+
+typedef int32_t fix16_t;
+
+static const fix16_t FOUR_DIV_PI = 0x145F3; /*!< Fix16 value of 4/PI */
+static const fix16_t _FOUR_DIV_PI2 = 0xFFFF9840; /*!< Fix16 value of -4/PIÂē */
+static const fix16_t X4_CORRECTION_COMPONENT = 0x399A; /*!< Fix16 value of 0.225 */
+static const fix16_t PI_DIV_4 = 0x0000C90F; /*!< Fix16 value of PI/4 */
+static const fix16_t THREE_PI_DIV_4 = 0x00025B2F; /*!< Fix16 value of 3PI/4 */
+
+static const fix16_t fix16_max = 0x7FFFFFFF; /*!< the maximum value of fix16_t */
+static const fix16_t fix16_min = 0x80000000; /*!< the minimum value of fix16_t */
+static const fix16_t fix16_overflow = 0x80000000; /*!< the value used to indicate overflows when FIXMATH_NO_OVERFLOW is not specified */
+
+static const fix16_t fix16_pi = 205887; /*!< fix16_t value of pi */
+static const fix16_t fix16_e = 178145; /*!< fix16_t value of e */
+static const fix16_t fix16_one = 0x00010000; /*!< fix16_t value of 1 */
+
+/* Conversion functions between fix16_t and float/integer.
+ * These are inlined to allow compiler to optimize away constant numbers
+ */
+static inline fix16_t fix16_from_int(int a) { return a * fix16_one; }
+static inline float fix16_to_float(fix16_t a) { return (float)a / fix16_one; }
+static inline double fix16_to_dbl(fix16_t a) { return (double)a / fix16_one; }
+
+static inline int fix16_to_int(fix16_t a)
+{
+#ifdef FIXMATH_NO_ROUNDING
+ return a >> 16;
+#else
+ if (a >= 0)
+ return (a + fix16_one / 2) / fix16_one;
+ else
+ return (a - fix16_one / 2) / fix16_one;
+#endif
+}
+
+static inline fix16_t fix16_from_float(float a)
+{
+ float temp = a * fix16_one;
+#ifndef FIXMATH_NO_ROUNDING
+ temp += (temp >= 0) ? 0.5f : -0.5f;
+#endif
+ return (fix16_t)temp;
+}
+
+static inline fix16_t fix16_from_dbl(double a)
+{
+ double temp = a * fix16_one;
+#ifndef FIXMATH_NO_ROUNDING
+ temp += (temp >= 0) ? 0.5f : -0.5f;
+#endif
+ return (fix16_t)temp;
+}
+
+/* Subtraction and addition with (optional) overflow detection. */
+#ifdef FIXMATH_NO_OVERFLOW
+
+static inline fix16_t fix16_add(fix16_t inArg0, fix16_t inArg1) { return (inArg0 + inArg1); }
+static inline fix16_t fix16_sub(fix16_t inArg0, fix16_t inArg1) { return (inArg0 - inArg1); }
+
+#else
+
+extern fix16_t fix16_add(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS;
+extern fix16_t fix16_sub(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS;
+
+/* Saturating arithmetic */
+extern fix16_t fix16_sadd(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS;
+extern fix16_t fix16_ssub(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS;
+
+#endif
+
+/*! Multiplies the two given fix16_t's and returns the result.
+*/
+extern fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS;
+
+/*! Divides the first given fix16_t by the second and returns the result.
+*/
+extern fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS;
+
+#ifndef FIXMATH_NO_OVERFLOW
+/*! Performs a saturated multiplication (overflow-protected) of the two given fix16_t's and returns the result.
+*/
+extern fix16_t fix16_smul(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS;
+
+/*! Performs a saturated division (overflow-protected) of the first fix16_t by the second and returns the result.
+*/
+extern fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS;
+#endif
+
+/*! Returns the linear interpolation: (inArg0 * (1 - inFract)) + (inArg1 * inFract)
+*/
+extern fix16_t fix16_lerp8(fix16_t inArg0, fix16_t inArg1, uint8_t inFract) FIXMATH_FUNC_ATTRS;
+extern fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract) FIXMATH_FUNC_ATTRS;
+#ifndef FIXMATH_NO_64BIT
+extern fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract) FIXMATH_FUNC_ATTRS;
+#endif
+
+/*! Returns the sine of the given fix16_t.
+*/
+extern fix16_t fix16_sin_parabola(fix16_t inAngle) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the sine of the given fix16_t.
+*/
+extern fix16_t fix16_sin(fix16_t inAngle) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the cosine of the given fix16_t.
+*/
+extern fix16_t fix16_cos(fix16_t inAngle) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the tangent of the given fix16_t.
+*/
+extern fix16_t fix16_tan(fix16_t inAngle) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the arcsine of the given fix16_t.
+*/
+extern fix16_t fix16_asin(fix16_t inValue) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the arccosine of the given fix16_t.
+*/
+extern fix16_t fix16_acos(fix16_t inValue) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the arctangent of the given fix16_t.
+*/
+extern fix16_t fix16_atan(fix16_t inValue) FIXMATH_FUNC_ATTRS;
+
+/*! Returns the arctangent of inY/inX.
+*/
+extern fix16_t fix16_atan2(fix16_t inY, fix16_t inX) FIXMATH_FUNC_ATTRS;
+
+
+
+/*! Returns the square root of the given fix16_t.
+*/
+extern fix16_t fix16_sqrt(fix16_t inValue) FIXMATH_FUNC_ATTRS;
+
+
+
+/*! Returns the exponent (e^) of the given fix16_t.
+*/
+extern fix16_t fix16_exp(fix16_t inValue) FIXMATH_FUNC_ATTRS;
+
+#ifdef __cplusplus
+}
+#include "fix16.hpp"
+#endif
+
+#endif
diff --git a/libfixmath/fixmath/fract32.h b/libfixmath/fixmath/fract32.h
new file mode 100755
index 0000000..ee1f1c6
--- /dev/null
+++ b/libfixmath/fixmath/fract32.h
@@ -0,0 +1,38 @@
+#ifndef __libfixmath_fract32_h__
+#define __libfixmath_fract32_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+typedef uint32_t fract32_t;
+
+/*! Creates a fraction using unsigned integers.
+ \param inNumerator the unsigned integer numerator
+ \param inDenominator the unsigned integer denominator
+ \return a fraction using the given numerator and denominator
+*/
+extern fract32_t fract32_create(uint32_t inNumerator, uint32_t inDenominator);
+
+/*! Inverts the given fraction, swapping the numerator and the denominator.
+*/
+extern fract32_t fract32_invert(fract32_t inFract);
+
+#ifndef FIXMATH_NO_64BIT
+/*! Performs unsigned saturated (overflow-protected) multiplication with the two given fractions and returns the result as an unsigned integer.
+*/
+extern uint32_t fract32_usmul(uint32_t inVal, fract32_t inFract);
+
+/*! Performs saturated (overflow-protected) multiplication with the two given fractions and returns the result as a signed integer.
+*/
+extern int32_t fract32_smul(int32_t inVal, fract32_t inFract);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libfixmath/fixmath/int64.h b/libfixmath/fixmath/int64.h
new file mode 100755
index 0000000..4d716bf
--- /dev/null
+++ b/libfixmath/fixmath/int64.h
@@ -0,0 +1,162 @@
+#ifndef __libfixmath_int64_h__
+#define __libfixmath_int64_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef FIXMATH_NO_64BIT
+static inline int64_t int64_const(int32_t hi, uint32_t lo) { return (((int64_t)hi << 32) | lo); }
+static inline int64_t int64_from_int32(int32_t x) { return (int64_t)x; }
+static inline int32_t int64_hi(int64_t x) { return (x >> 32); }
+static inline uint32_t int64_lo(int64_t x) { return (x & ((1ULL << 32) - 1)); }
+
+static inline int64_t int64_add(int64_t x, int64_t y) { return (x + y); }
+static inline int64_t int64_neg(int64_t x) { return (-x); }
+static inline int64_t int64_sub(int64_t x, int64_t y) { return (x - y); }
+static inline int64_t int64_shift(int64_t x, int8_t y) { return (y < 0 ? (x >> -y) : (x << y)); }
+
+static inline int64_t int64_mul_i32_i32(int32_t x, int32_t y) { return (x * y); }
+static inline int64_t int64_mul_i64_i32(int64_t x, int32_t y) { return (x * y); }
+
+static inline int64_t int64_div_i64_i32(int64_t x, int32_t y) { return (x / y); }
+
+static inline int int64_cmp_eq(int64_t x, int64_t y) { return (x == y); }
+static inline int int64_cmp_ne(int64_t x, int64_t y) { return (x != y); }
+static inline int int64_cmp_gt(int64_t x, int64_t y) { return (x > y); }
+static inline int int64_cmp_ge(int64_t x, int64_t y) { return (x >= y); }
+static inline int int64_cmp_lt(int64_t x, int64_t y) { return (x < y); }
+static inline int int64_cmp_le(int64_t x, int64_t y) { return (x <= y); }
+#else
+
+typedef struct {
+ int32_t hi;
+ uint32_t lo;
+} __int64_t;
+
+static inline __int64_t int64_const(int32_t hi, uint32_t lo) { return (__int64_t){ hi, lo }; }
+static inline __int64_t int64_from_int32(int32_t x) { return (__int64_t){ (x < 0 ? -1 : 0), x }; }
+static inline int32_t int64_hi(__int64_t x) { return x.hi; }
+static inline uint32_t int64_lo(__int64_t x) { return x.lo; }
+
+static inline int int64_cmp_eq(__int64_t x, __int64_t y) { return ((x.hi == y.hi) && (x.lo == y.lo)); }
+static inline int int64_cmp_ne(__int64_t x, __int64_t y) { return ((x.hi != y.hi) || (x.lo != y.lo)); }
+static inline int int64_cmp_gt(__int64_t x, __int64_t y) { return ((x.hi > y.hi) || ((x.hi == y.hi) && (x.lo > y.lo))); }
+static inline int int64_cmp_ge(__int64_t x, __int64_t y) { return ((x.hi > y.hi) || ((x.hi == y.hi) && (x.lo >= y.lo))); }
+static inline int int64_cmp_lt(__int64_t x, __int64_t y) { return ((x.hi < y.hi) || ((x.hi == y.hi) && (x.lo < y.lo))); }
+static inline int int64_cmp_le(__int64_t x, __int64_t y) { return ((x.hi < y.hi) || ((x.hi == y.hi) && (x.lo <= y.lo))); }
+
+static inline __int64_t int64_add(__int64_t x, __int64_t y) {
+ __int64_t ret;
+ ret.hi = x.hi + y.hi;
+ ret.lo = x.lo + y.lo;
+ if((ret.lo < x.lo) || (ret.hi < y.hi))
+ ret.hi++;
+ return ret;
+}
+
+static inline __int64_t int64_neg(__int64_t x) {
+ __int64_t ret;
+ ret.hi = ~x.hi;
+ ret.lo = ~x.lo + 1;
+ if(ret.lo == 0)
+ ret.hi++;
+ return ret;
+}
+
+static inline __int64_t int64_sub(__int64_t x, __int64_t y) {
+ return int64_add(x, int64_neg(y));
+}
+
+static inline __int64_t int64_shift(__int64_t x, int8_t y) {
+ __int64_t ret;
+ if(y > 0) {
+ if(y >= 32)
+ return (__int64_t){ 0, 0 };
+ ret.hi = (x.hi << y) | (x.lo >> (32 - y));
+ ret.lo = (x.lo << y);
+ } else {
+ y = -y;
+ if(y >= 32)
+ return (__int64_t){ 0, 0 };
+ ret.lo = (x.lo >> y) | (x.hi << (32 - y));
+ ret.hi = (x.hi >> y);
+ }
+ return ret;
+}
+
+static inline __int64_t int64_mul_i32_i32(int32_t x, int32_t y) {
+ int16_t hi[2] = { (x >> 16), (y >> 16) };
+ uint16_t lo[2] = { (x & 0xFFFF), (y & 0xFFFF) };
+
+ int32_t r_hi = hi[0] * hi[1];
+ int32_t r_md = (hi[0] * lo[1]) + (hi[1] * lo[0]);
+ uint32_t r_lo = lo[0] * lo[1];
+
+ r_hi += (r_md >> 16);
+ r_lo += (r_md << 16);
+
+ return (__int64_t){ r_hi, r_lo };
+}
+
+static inline __int64_t int64_mul_i64_i32(__int64_t x, int32_t y) {
+ int neg = ((x.hi ^ y) < 0);
+ if(x.hi < 0)
+ x = int64_neg(x);
+ if(y < 0)
+ y = -y;
+
+ uint32_t _x[4] = { (x.hi >> 16), (x.hi & 0xFFFF), (x.lo >> 16), (x.lo & 0xFFFF) };
+ uint32_t _y[2] = { (y >> 16), (y & 0xFFFF) };
+
+ uint32_t r[4];
+ r[0] = (_x[0] * _y[0]);
+ r[1] = (_x[1] * _y[0]) + (_x[0] * _y[1]);
+ r[2] = (_x[1] * _y[1]) + (_x[2] * _y[0]);
+ r[3] = (_x[2] * _y[0]) + (_x[1] * _y[1]);
+
+ __int64_t ret;
+ ret.lo = r[0] + (r[1] << 16);
+ ret.hi = (r[3] << 16) + r[2] + (r[1] >> 16);
+ return (neg ? int64_neg(ret) : ret);
+}
+
+static inline __int64_t int64_div_i64_i32(__int64_t x, int32_t y) {
+ int neg = ((x.hi ^ y) < 0);
+ if(x.hi < 0)
+ x = int64_neg(x);
+ if(y < 0)
+ y = -y;
+
+ __int64_t ret = { (x.hi / y) , (x.lo / y) };
+ x.hi = x.hi % y;
+ x.lo = x.lo % y;
+
+ __int64_t _y = int64_from_int32(y);
+
+ __int64_t i;
+ for(i = int64_from_int32(1); int64_cmp_lt(_y, x); _y = int64_shift(_y, 1), i = int64_shift(i, 1));
+
+ while(x.hi) {
+ _y = int64_shift(_y, -1);
+ i = int64_shift(i, -1);
+ if(int64_cmp_ge(x, _y)) {
+ x = int64_sub(x, _y);
+ ret = int64_add(ret, i);
+ }
+ }
+
+ ret = int64_add(ret, int64_from_int32(x.lo / y));
+ return (neg ? int64_neg(ret) : ret);
+}
+
+#define int64_t __int64_t
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libfixmath/fixmath/uint32.h b/libfixmath/fixmath/uint32.h
new file mode 100755
index 0000000..1303338
--- /dev/null
+++ b/libfixmath/fixmath/uint32.h
@@ -0,0 +1,19 @@
+#ifndef __libfixmath_uint32_h__
+#define __libfixmath_uint32_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+/*! Performs an unsigned log-base2 on the specified unsigned integer and returns the result.
+*/
+extern uint32_t uint32_log2(uint32_t inVal);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libfixmath/fract32.c b/libfixmath/fract32.c
new file mode 100755
index 0000000..397e000
--- /dev/null
+++ b/libfixmath/fract32.c
@@ -0,0 +1,27 @@
+#include "fract32.h"
+
+
+
+fract32_t fract32_create(uint32_t inNumerator, uint32_t inDenominator) {
+ if(inDenominator <= inNumerator)
+ return 0xFFFFFFFF;
+ uint32_t tempMod = (inNumerator % inDenominator);
+ uint32_t tempDiv = (0xFFFFFFFF / (inDenominator - 1));
+ return (tempMod * tempDiv);
+}
+
+fract32_t fract32_invert(fract32_t inFract) {
+ return (0xFFFFFFFF - inFract);
+}
+
+#ifndef FIXMATH_NO_64BIT
+uint32_t fract32_usmul(uint32_t inVal, fract32_t inFract) {
+ return (uint32_t)(((uint64_t)inVal * (uint64_t)inFract) >> 32);
+}
+
+int32_t fract32_smul(int32_t inVal, fract32_t inFract) {
+ if(inVal < 0)
+ return -fract32_usmul(-inVal, inFract);
+ return fract32_usmul(inVal, inFract);
+}
+#endif
diff --git a/libfixmath/uint32.c b/libfixmath/uint32.c
new file mode 100755
index 0000000..2980ab9
--- /dev/null
+++ b/libfixmath/uint32.c
@@ -0,0 +1,15 @@
+#include "uint32.h"
+
+
+
+uint32_t uint32_log2(uint32_t inVal) {
+ if(inVal == 0)
+ return 0;
+ uint32_t tempOut = 0;
+ if(inVal >= (1 << 16)) { inVal >>= 16; tempOut += 16; }
+ if(inVal >= (1 << 8)) { inVal >>= 8; tempOut += 8; }
+ if(inVal >= (1 << 4)) { inVal >>= 4; tempOut += 4; }
+ if(inVal >= (1 << 2)) { inVal >>= 2; tempOut += 2; }
+ if(inVal >= (1 << 1)) { tempOut += 1; }
+ return tempOut;
+}
diff --git a/libhuff/Makefile b/libhuff/Makefile
new file mode 100644
index 0000000..0016f91
--- /dev/null
+++ b/libhuff/Makefile
@@ -0,0 +1,23 @@
+# Makefile for libhuff
+
+include ../Makefile.cfg
+
+#CC = mipsel-unknown-elf-gcc
+#CFLAGS = -I../libpsx/include/ -G0 -O0 -fno-builtin -mno-gpopt -nostdlib -msoft-float -g -Wall
+
+all: libhuff.a
+
+huff.o: huff.c
+ $(CC) $(CFLAGS) -c huff.c
+
+libhuff.a: huff.o
+ rm -f libhuff.a
+ $(AR) r libhuff.a huff.o
+ $(RANLIB) libhuff.a
+
+install: all
+ cp libhuff.a $(TOOLCHAIN_PREFIX)/lib
+ cp huff.h $(TOOLCHAIN_PREFIX)/include
+
+clean:
+ rm -f *.o *.a \ No newline at end of file
diff --git a/libhuff/huff.c b/libhuff/huff.c
new file mode 100644
index 0000000..0a79603
--- /dev/null
+++ b/libhuff/huff.c
@@ -0,0 +1,119 @@
+// Huffman decompression library for PSXSDK
+
+// Huffman decompression code adapted from huff program
+// by Joe Wingbermuehle
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <psx.h>
+#include "huff.h"
+
+#define BUFFER_SIZE 1024
+
+unsigned char libhuff_inBuffer[BUFFER_SIZE];
+unsigned char libhuff_outBuffer[BUFFER_SIZE];
+
+struct CodeNode {
+ unsigned char value;
+ unsigned long code;
+ unsigned int codeSize;
+};
+
+struct CodeNode libhuff_codes[256];
+unsigned int libhuff_codesUsed;
+
+// Decompress_Mem returns size of uncompressed data if SizeLimit >= UncompressedDataSize,
+// otherwise if UncompressedDataSize > SizeLimit, 0 is returned
+
+// SizeLimit is the maximum space available for decompressed data
+
+unsigned int huff_decompress(void *dst, void *src, int sizeLimit) {
+ int x, y;
+ unsigned int dataSize;
+ unsigned long mask, maskSize;
+ unsigned char ch;
+ int offset;
+// int last;
+
+ int ib, ob;
+ int src_pos = 8;
+ int dst_pos = 0;
+ unsigned char *srcc = (unsigned char*)src;
+ unsigned char *dstc = (unsigned char*)dst;
+
+ libhuff_codesUsed = *((unsigned int*)src);
+ dataSize = *((unsigned int*)src + 1);
+
+ if(dataSize > sizeLimit)
+ return 0;
+
+ for(x = 0; x < libhuff_codesUsed; x++) {
+ libhuff_codes[x].value = srcc[src_pos++];
+ libhuff_codes[x].codeSize = srcc[src_pos++] + 1;
+ }
+
+ offset = 7;
+ ch = 0;
+ for(x = 0; x < libhuff_codesUsed; x++) {
+ libhuff_codes[x].code = 0;
+ for(y = libhuff_codes[x].codeSize - 1; y >= 0; y--) {
+ if(offset == 7) {
+ ch = srcc[src_pos++];
+ }
+ libhuff_codes[x].code |= ((ch >> offset) & 1) << y;
+ offset = (offset - 1) & 7;
+ }
+ }
+
+ maskSize = 0;
+ mask = 0;
+ offset = 7;
+ //last = 0;
+ y = 0;
+ x = 0;
+ ib = BUFFER_SIZE;
+ ob = 0;
+ for(;;) {
+ if(offset == 7) {
+ if(ib >= BUFFER_SIZE) {
+ memcpy(libhuff_inBuffer, &srcc[src_pos], BUFFER_SIZE);
+ src_pos += BUFFER_SIZE;
+
+ ib = 0;
+ }
+ ch = libhuff_inBuffer[ib++];
+ }
+ mask <<= 1;
+ mask |= (ch >> offset) & 1;
+ ++maskSize;
+ offset = (offset - 1) & 7;
+
+ while(libhuff_codes[y].codeSize < maskSize) ++y;
+ while(libhuff_codes[y].codeSize == maskSize) {
+ if(libhuff_codes[y].code == mask) {
+ if(ob >= BUFFER_SIZE) {
+ memcpy(&dstc[dst_pos], libhuff_outBuffer, BUFFER_SIZE);
+ dst_pos += BUFFER_SIZE;
+ ob = 0;
+ }
+ libhuff_outBuffer[ob++] = libhuff_codes[y].value;
+ ++x;
+ if(x >= dataSize) {
+ memcpy(&dstc[dst_pos], libhuff_outBuffer, ob);
+ dst_pos += ob;
+ return dataSize;
+ }
+ mask = 0;
+ maskSize = 0;
+ y = 0;
+ break;
+ }
+ ++y;
+ }
+ }
+
+ return dataSize;
+}
+
diff --git a/libhuff/huff.h b/libhuff/huff.h
new file mode 100644
index 0000000..28aecf1
--- /dev/null
+++ b/libhuff/huff.h
@@ -0,0 +1,19 @@
+/*
+ * huff.h
+ *
+ * Huffman decompression routines
+ *
+ * libhuff
+ */
+
+#ifndef _HUFF_H
+#define _HUFF_H
+
+// Decompress_Mem returns size of uncompressed data if SizeLimit >= UncompressedDataSize,
+// otherwise if UncompressedDataSize > SizeLimit, 0 is returned
+
+// SizeLimit is the maximum space available for decompressed data
+
+unsigned int huff_decompress(void *dst, void *src, int sizeLimit);
+
+#endif
diff --git a/libm/Makefile b/libm/Makefile
new file mode 100644
index 0000000..f405a9a
--- /dev/null
+++ b/libm/Makefile
@@ -0,0 +1,116 @@
+#
+# @(#)Makefile 1.4 95/01/18
+#
+# ====================================================
+# Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+#
+# Developed at SunSoft, a Sun Microsystems, Inc. business.
+# Permission to use, copy, modify, and distribute this
+# software is freely granted, provided that this notice
+# is preserved.
+# ====================================================
+#
+#
+
+#
+# There are two options in making libm at fdlibm compile time:
+# _IEEE_LIBM --- IEEE libm; smaller, and somewhat faster
+# _MULTI_LIBM --- Support multi-standard at runtime by
+# imposing wrapper functions defined in
+# fdlibm.h:
+# _IEEE_MODE -- IEEE
+# _XOPEN_MODE -- X/OPEN
+# _POSIX_MODE -- POSIX/ANSI
+# _SVID3_MODE -- SVID
+#
+# Here is how to set up CFLAGS to create the desired libm at
+# compile time:
+#
+# CFLAGS = -D_IEEE_LIBM ... IEEE libm (recommended)
+# CFLAGS = -D_SVID3_MODE ... Multi-standard supported
+# libm with SVID as the
+# default standard
+# CFLAGS = -D_XOPEN_MODE ... Multi-standard supported
+# libm with XOPEN as the
+# default standard
+# CFLAGS = -D_POSIX_MODE ... Multi-standard supported
+# libm with POSIX as the
+# default standard
+# CFLAGS = ... Multi-standard supported
+# libm with IEEE as the
+# default standard
+#
+# NOTE: if scalb's second arguement is an int, then one must
+# define _SCALB_INT in CFLAGS. The default prototype of scalb
+# is double scalb(double, double)
+#
+
+# Include PSXSDK options
+
+include ../Makefile.cfg
+
+#
+# Default IEEE libm
+#
+CFLAGS += -D_IEEE_LIBM -D_REENTRANT
+
+INCFILES = fdlibm.h
+.INIT: $(INCFILES)
+.KEEP_STATE:
+src = k_standard.c k_rem_pio2.c \
+ k_cos.c k_sin.c k_tan.c \
+ e_acos.c e_acosh.c e_asin.c e_atan2.c \
+ e_atanh.c e_cosh.c e_exp.c e_fmod.c \
+ e_gamma.c e_gamma_r.c e_hypot.c e_j0.c \
+ e_j1.c e_jn.c e_lgamma.c e_lgamma_r.c \
+ e_log.c e_log10.c e_pow.c e_rem_pio2.c e_remainder.c \
+ e_scalb.c e_sinh.c e_sqrt.c \
+ w_acos.c w_acosh.c w_asin.c w_atan2.c \
+ w_atanh.c w_cosh.c w_exp.c w_fmod.c \
+ w_gamma.c w_gamma_r.c w_hypot.c w_j0.c \
+ w_j1.c w_jn.c w_lgamma.c w_lgamma_r.c \
+ w_log.c w_log10.c w_pow.c w_remainder.c \
+ w_scalb.c w_sinh.c w_sqrt.c \
+ s_asinh.c s_atan.c s_cbrt.c s_ceil.c s_copysign.c \
+ s_cos.c s_erf.c s_expm1.c s_fabs.c s_finite.c s_floor.c \
+ s_frexp.c s_ilogb.c s_isnan.c s_ldexp.c s_lib_version.c \
+ s_log1p.c s_logb.c s_matherr.c s_modf.c s_nextafter.c \
+ s_rint.c s_scalbn.c s_signgam.c s_significand.c s_sin.c \
+ s_tan.c s_tanh.c wrappers.c
+
+obj = k_standard.o k_rem_pio2.o \
+ k_cos.o k_sin.o k_tan.o \
+ e_acos.o e_acosh.o e_asin.o e_atan2.o \
+ e_atanh.o e_cosh.o e_exp.o e_fmod.o \
+ e_gamma.o e_gamma_r.o e_hypot.o e_j0.o \
+ e_j1.o e_jn.o e_lgamma.o e_lgamma_r.o \
+ e_log.o e_log10.o e_pow.o e_rem_pio2.o e_remainder.o \
+ e_scalb.o e_sinh.o e_sqrt.o \
+ w_acos.o w_acosh.o w_asin.o w_atan2.o \
+ w_atanh.o w_cosh.o w_exp.o w_fmod.o \
+ w_gamma.o w_gamma_r.o w_hypot.o w_j0.o \
+ w_j1.o w_jn.o w_lgamma.o w_lgamma_r.o \
+ w_log.o w_log10.o w_pow.o w_remainder.o \
+ w_scalb.o w_sinh.o w_sqrt.o \
+ s_asinh.o s_atan.o s_cbrt.o s_ceil.o s_copysign.o \
+ s_cos.o s_erf.o s_expm1.o s_fabs.o s_finite.o s_floor.o \
+ s_frexp.o s_ilogb.o s_isnan.o s_ldexp.o s_lib_version.o \
+ s_log1p.o s_logb.o s_matherr.o s_modf.o s_nextafter.o \
+ s_rint.o s_scalbn.o s_signgam.o s_significand.o s_sin.o \
+ s_tan.o s_tanh.o wrappers.o
+
+all: libm.a
+
+libm.a : $(obj)
+ $(AR) cru libm.a $(obj)
+ $(RANLIB) libm.a
+
+source: $(src) README
+
+clean:
+ rm -f $(obj) libm.a
+
+install: all
+ cp libm.a $(TOOLCHAIN_PREFIX)/lib
+ cp math.h $(TOOLCHAIN_PREFIX)/include
+
diff --git a/libm/README b/libm/README
new file mode 100644
index 0000000..78d1f35
--- /dev/null
+++ b/libm/README
@@ -0,0 +1,261 @@
+
+ *********************************
+ * Announcing FDLIBM Version 5.3 *
+ *********************************
+============================================================
+ FDLIBM
+============================================================
+ developed at Sun Microsystems, Inc.
+
+What's new in FDLIBM 5.3?
+
+CONFIGURE
+ To build FDLIBM, edit the supplied Makefile or create
+ a local Makefile by running "sh configure"
+ using the supplied configure script contributed by Nelson Beebe
+
+BUGS FIXED
+
+ 1. e_pow.c incorrect results when
+ x is very close to -1.0 and y is very large, e.g.
+ pow(-1.0000000000000002e+00,4.5035996273704970e+15) = 0
+ pow(-9.9999999999999978e-01,4.5035996273704970e+15) = 0
+ Correct results are close to -e and -1/e.
+
+ 2. k_tan.c error was > 1 ulp target for FDLIBM
+ 5.2: Worst error at least 1.45 ulp at
+ tan(1.7765241907548024E+269) = 1.7733884462610958E+16
+ 5.3: Worst error 0.96 ulp
+
+NOT FIXED YET
+
+ 3. Compiler failure on non-standard code
+ Statements like
+ *(1+(int*)&t1) = 0;
+ are not standard C and cause some optimizing compilers (e.g. GCC)
+ to generate bad code under optimization. These cases
+ are to be addressed in the next release.
+
+FDLIBM (Freely Distributable LIBM) is a C math library
+for machines that support IEEE 754 floating-point arithmetic.
+In this release, only double precision is supported.
+
+FDLIBM is intended to provide a reasonably portable (see
+assumptions below), reference quality (below one ulp for
+major functions like sin,cos,exp,log) math library
+(libm.a). For a copy of FDLIBM, please see
+ http://www.netlib.org/fdlibm/
+or
+ http://www.validlab.com/software/
+
+--------------
+1. ASSUMPTIONS
+--------------
+FDLIBM (double precision version) assumes:
+ a. IEEE 754 style (if not precise compliance) arithmetic;
+ b. 32 bit 2's complement integer arithmetic;
+ c. Each double precision floating-point number must be in IEEE 754
+ double format, and that each number can be retrieved as two 32-bit
+ integers through the using of pointer bashing as in the example
+ below:
+
+ Example: let y = 2.0
+ double fp number y: 2.0
+ IEEE double format: 0x4000000000000000
+
+ Referencing y as two integers:
+ *(int*)&y,*(1+(int*)&y) = {0x40000000,0x0} (on sparc)
+ {0x0,0x40000000} (on 386)
+
+ Note: Four macros are defined in fdlibm.h to handle this kind of
+ retrieving:
+
+ __HI(x) the high part of a double x
+ (sign,exponent,the first 21 significant bits)
+ __LO(x) the least 32 significant bits of x
+ __HIp(x) same as __HI except that the argument is a pointer
+ to a double
+ __LOp(x) same as __LO except that the argument is a pointer
+ to a double
+
+ To ensure obtaining correct ordering, one must define __LITTLE_ENDIAN
+ during compilation for little endian machine (like 386,486). The
+ default is big endian.
+
+ If the behavior of pointer bashing is undefined, one may hack on the
+ macro in fdlibm.h.
+
+ d. IEEE exceptions may trigger "signals" as is common in Unix
+ implementations.
+
+-------------------
+2. EXCEPTION CASES
+-------------------
+All exception cases in the FDLIBM functions will be mapped
+to one of the following four exceptions:
+
+ +-huge*huge, +-tiny*tiny, +-1.0/0.0, +-0.0/0.0
+ (overflow) (underflow) (divided-by-zero) (invalid)
+
+For example, log(0) is a singularity and is thus mapped to
+ -1.0/0.0 = -infinity.
+That is, FDLIBM's log will compute -one/zero and return the
+computed value. On an IEEE machine, this will trigger the
+divided-by-zero exception and a negative infinity is returned by
+default.
+
+Similarly, exp(-huge) will be mapped to tiny*tiny to generate
+an underflow signal.
+
+
+--------------------------------
+3. STANDARD CONFORMANCE WRAPPER
+--------------------------------
+The default FDLIBM functions (compiled with -D_IEEE_LIBM flag)
+are in "IEEE spirit" (i.e., return the most reasonable result in
+floating-point arithmetic). If one wants FDLIBM to comply with
+standards like SVID, X/OPEN, or POSIX/ANSI, then one can
+create a multi-standard compliant FDLIBM. In this case, each
+function in FDLIBM is actually a standard compliant wrapper
+function.
+
+File organization:
+ 1. For FDLIBM's kernel (internal) function,
+ File name Entry point
+ ---------------------------
+ k_sin.c __kernel_sin
+ k_tan.c __kernel_tan
+ ---------------------------
+ 2. For functions that have no standards conflict
+ File name Entry point
+ ---------------------------
+ s_sin.c sin
+ s_erf.c erf
+ ---------------------------
+ 3. Ieee754 core functions
+ File name Entry point
+ ---------------------------
+ e_exp.c __ieee754_exp
+ e_sinh.c __ieee754_sinh
+ ---------------------------
+ 4. Wrapper functions
+ File name Entry point
+ ---------------------------
+ w_exp.c exp
+ w_sinh.c sinh
+ ---------------------------
+
+Wrapper functions will twist the result of the ieee754
+function to comply to the standard specified by the value
+of _LIB_VERSION
+ if _LIB_VERSION = _IEEE_, return the ieee754 result;
+ if _LIB_VERSION = _SVID_, return SVID result;
+ if _LIB_VERSION = _XOPEN_, return XOPEN result;
+ if _LIB_VERSION = _POSIX_, return POSIX/ANSI result.
+(These are macros, see fdlibm.h for their definition.)
+
+
+--------------------------------
+4. HOW TO CREATE FDLIBM's libm.a
+--------------------------------
+There are two types of libm.a. One is IEEE only, and the other is
+multi-standard compliant (supports IEEE,XOPEN,POSIX/ANSI,SVID).
+
+To create the IEEE only libm.a, use
+ make "CFLAGS = -D_IEEE_LIBM"
+This will create an IEEE libm.a, which is smaller in size, and
+somewhat faster.
+
+To create a multi-standard compliant libm, use
+ make "CFLAGS = -D_IEEE_MODE" --- multi-standard fdlibm: default
+ to IEEE
+ make "CFLAGS = -D_XOPEN_MODE" --- multi-standard fdlibm: default
+ to X/OPEN
+ make "CFLAGS = -D_POSIX_MODE" --- multi-standard fdlibm: default
+ to POSIX/ANSI
+ make "CFLAGS = -D_SVID3_MODE" --- multi-standard fdlibm: default
+ to SVID
+
+
+Here is how one makes a SVID compliant libm.
+ Make the library by
+ make "CFLAGS = -D_SVID3_MODE".
+ The libm.a of FDLIBM will be multi-standard compliant and
+ _LIB_VERSION is initialized to the value _SVID_ .
+
+ example1:
+ ---------
+ main()
+ {
+ double y0();
+ printf("y0(1e300) = %1.20e\n",y0(1e300));
+ exit(0);
+ }
+
+ % cc example1.c libm.a
+ % a.out
+ y0: TLOSS error
+ y0(1e300) = 0.00000000000000000000e+00
+
+
+It is possible to change the default standard in multi-standard
+fdlibm. Here is an example of how to do it:
+ example2:
+ ---------
+ #include "fdlibm.h" /* must include FDLIBM's fdlibm.h */
+ main()
+ {
+ double y0();
+ _LIB_VERSION = _IEEE_;
+ printf("IEEE: y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _XOPEN_;
+ printf("XOPEN y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _POSIX_;
+ printf("POSIX y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _SVID_;
+ printf("SVID y0(1e300) = %1.20e\n",y0(1e300));
+ exit(0);
+ }
+
+ % cc example2.c libm.a
+ % a.out
+ IEEE: y0(1e300) = -1.36813604503424810557e-151
+ XOPEN y0(1e300) = 0.00000000000000000000e+00
+ POSIX y0(1e300) = 0.00000000000000000000e+00
+ y0: TLOSS error
+ SVID y0(1e300) = 0.00000000000000000000e+00
+
+Note: Here _LIB_VERSION is a global variable. If global variables
+ are forbidden, then one should modify fdlibm.h to change
+ _LIB_VERSION to be a global constant. In this case, one
+ may not change the value of _LIB_VERSION as in example2.
+
+---------------------------
+5. NOTES ON PORTING FDLIBM
+---------------------------
+ Care must be taken when installing FDLIBM over existing
+ libm.a.
+ All co-existing function prototypes must agree, otherwise
+ users will encounter mysterious failures.
+
+ So far, the only known likely conflict is the declaration
+ of the IEEE recommended function scalb:
+
+ double scalb(double,double) (1) SVID3 defined
+ double scalb(double,int) (2) IBM,DEC,...
+
+ FDLIBM follows Sun definition and use (1) as default.
+ If one's existing libm.a uses (2), then one may raise
+ the flags _SCALB_INT during the compilation of FDLIBM
+ to get the correct function prototype.
+ (E.g., make "CFLAGS = -D_IEEE_LIBM -D_SCALB_INT".)
+ NOTE that if -D_SCALB_INT is raised, it won't be SVID3
+ conformant.
+
+--------------
+6. PROBLEMS ?
+--------------
+Please send comments and bug reports to the electronic mail address
+suggested by:
+ fdlibm-comments AT sun.com
+
diff --git a/libm/e_acos.c b/libm/e_acos.c
new file mode 100644
index 0000000..4d790a0
--- /dev/null
+++ b/libm/e_acos.c
@@ -0,0 +1,105 @@
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_acos(x)
+ * Method :
+ * acos(x) = pi/2 - asin(x)
+ * acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
+ * For x>0.5
+ * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ * = 2asin(sqrt((1-x)/2))
+ * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
+ * = 2f + (2c + 2s*z*R(z))
+ * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ * for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ * acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+#ifdef __STDC__
+ double __ieee754_acos(double x)
+#else
+ double __ieee754_acos(x)
+ double x;
+#endif
+{
+ double z,p,q,r,w,s,c,df;
+ int hx,ix;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x3ff00000) { /* |x| >= 1 */
+ if(((ix-0x3ff00000)|__LO(x))==0) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+2.0*pio2_lo; /* acos(-1)= pi */
+ }
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3fe00000) { /* |x| < 0.5 */
+ if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = sqrt(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - 2.0*(s+w);
+ } else { /* x > 0.5 */
+ z = (one-x)*0.5;
+ s = sqrt(z);
+ df = s;
+ __LO(df) = 0;
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return 2.0*(df+w);
+ }
+}
diff --git a/libm/e_acosh.c b/libm/e_acosh.c
new file mode 100644
index 0000000..78fda36
--- /dev/null
+++ b/libm/e_acosh.c
@@ -0,0 +1,65 @@
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_acosh(x)
+ * Method :
+ * Based on
+ * acosh(x) = log [ x + sqrt(x*x-1) ]
+ * we have
+ * acosh(x) := log(x)+ln2, if x is large; else
+ * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ * acosh(x) is NaN with signal if x<1.
+ * acosh(NaN) is NaN without signal.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */
+
+#ifdef __STDC__
+ double __ieee754_acosh(double x)
+#else
+ double __ieee754_acosh(x)
+ double x;
+#endif
+{
+ double t;
+ int hx;
+ hx = __HI(x);
+ if(hx<0x3ff00000) { /* x < 1 */
+ return (x-x)/(x-x);
+ } else if(hx >=0x41b00000) { /* x > 2**28 */
+ if(hx >=0x7ff00000) { /* x is inf of NaN */
+ return x+x;
+ } else
+ return __ieee754_log(x)+ln2; /* acosh(huge)=log(2x) */
+ } else if(((hx-0x3ff00000)|__LO(x))==0) {
+ return 0.0; /* acosh(1) = 0 */
+ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */
+ t=x*x;
+ return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+ } else { /* 1<x<2 */
+ t = x-one;
+ return log1p(t+sqrt(2.0*t+t*t));
+ }
+}
diff --git a/libm/e_asin.c b/libm/e_asin.c
new file mode 100644
index 0000000..9dc7663
--- /dev/null
+++ b/libm/e_asin.c
@@ -0,0 +1,115 @@
+
+/* @(#)e_asin.c 1.4 96/03/07 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_asin(x)
+ * Method :
+ * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ * we approximate asin(x) on [0,0.5] by
+ * asin(x) = x + x*x^2*R(x^2)
+ * where
+ * R(x^2) is a rational approximation of (asin(x)-x)/x^3
+ * and its Remes error is bounded by
+ * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ * For x in [0.5,1]
+ * asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ * then for x>0.98
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ * For x<=0.98, let pio4_hi = pio2_hi/2, then
+ * f = hi part of s;
+ * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
+ * and
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+huge = 1.000e+300,
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+ /* coefficient for R(x^2) */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+#ifdef __STDC__
+ double __ieee754_asin(double x)
+#else
+ double __ieee754_asin(x)
+ double x;
+#endif
+{
+ double t,w,p,q,c,r,s;
+ int hx,ix;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>= 0x3ff00000) { /* |x|>= 1 */
+ if(((ix-0x3ff00000)|__LO(x))==0)
+ /* asin(1)=+-pi/2 with inexact */
+ return x*pio2_hi+x*pio2_lo;
+ return (x-x)/(x-x); /* asin(|x|>1) is NaN */
+ } else if (ix<0x3fe00000) { /* |x|<0.5 */
+ if(ix<0x3e400000) { /* if |x| < 2**-27 */
+ if(huge+x>one) return x;/* return x with inexact if x!=0*/
+ } else
+ t = x*x;
+
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ w = p/q;
+ return x+x*w;
+ }
+ /* 1> |x|>= 0.5 */
+ w = one-fabs(x);
+ t = w*0.5;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ s = sqrt(t);
+ if(ix>=0x3FEF3333) { /* if |x| > 0.975 */
+ w = p/q;
+ t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+ } else {
+ w = s;
+ __LO(w) = 0;
+ c = (t-w*w)/(s+w);
+ r = p/q;
+ p = 2.0*s*r-(pio2_lo-2.0*c);
+ q = pio4_hi-2.0*w;
+ t = pio4_hi-(p-q);
+ }
+ if(hx>0) return t; else return -t;
+}
diff --git a/libm/e_atan2.c b/libm/e_atan2.c
new file mode 100644
index 0000000..b55bd5b
--- /dev/null
+++ b/libm/e_atan2.c
@@ -0,0 +1,123 @@
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ * 2. Reduce x to positive by (if x and y are unexceptional):
+ * ARG (x+iy) = arctan(y/x) ... if x > 0,
+ * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
+ *
+ * Special cases:
+ *
+ * ATAN2((anything), NaN ) is NaN;
+ * ATAN2(NAN , (anything) ) is NaN;
+ * ATAN2(+-0, +(anything but NaN)) is +-0 ;
+ * ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ * ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ * ATAN2(+-INF,+INF ) is +-pi/4 ;
+ * ATAN2(+-INF,-INF ) is +-3pi/4;
+ * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+tiny = 1.0e-300,
+zero = 0.0,
+pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+#ifdef __STDC__
+ double __ieee754_atan2(double y, double x)
+#else
+ double __ieee754_atan2(y,x)
+ double y,x;
+#endif
+{
+ double z;
+ int k,m,hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = __HI(x); ix = hx&0x7fffffff;
+ lx = __LO(x);
+ hy = __HI(y); iy = hy&0x7fffffff;
+ ly = __LO(y);
+ if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+ ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */
+ return x+y;
+ if(((hx-0x3ff00000)|lx)==0) return atan(y); /* x=1.0 */
+ m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if((iy|ly)==0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
+ case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* when x is INF */
+ if(ix==0x7ff00000) {
+ if(iy==0x7ff00000) {
+ switch(m) {
+ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
+ case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+ case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+ case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return zero ; /* atan(+...,+INF) */
+ case 1: return -zero ; /* atan(-...,+INF) */
+ case 2: return pi+tiny ; /* atan(+...,-INF) */
+ case 3: return -pi-tiny ; /* atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* compute y/x */
+ k = (iy-ix)>>20;
+ if(k > 60) z=pi_o_2+0.5*pi_lo; /* |y/x| > 2**60 */
+ else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */
+ else z=atan(fabs(y/x)); /* safe to do y/x */
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: __HI(z) ^= 0x80000000;
+ return z ; /* atan(-,+) */
+ case 2: return pi-(z-pi_lo);/* atan(+,-) */
+ default: /* case 3 */
+ return (z-pi_lo)-pi;/* atan(-,-) */
+ }
+}
diff --git a/libm/e_atanh.c b/libm/e_atanh.c
new file mode 100644
index 0000000..78697ec
--- /dev/null
+++ b/libm/e_atanh.c
@@ -0,0 +1,68 @@
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atanh(x)
+ * Method :
+ * 1.Reduced x to positive by atanh(-x) = -atanh(x)
+ * 2.For x>=0.5
+ * 1 2x x
+ * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ * 2 1 - x 1 - x
+ *
+ * For x<0.5
+ * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ * atanh(x) is NaN if |x| > 1 with signal;
+ * atanh(NaN) is that NaN with no signal;
+ * atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, huge = 1e300;
+#else
+static double one = 1.0, huge = 1e300;
+#endif
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_atanh(double x)
+#else
+ double __ieee754_atanh(x)
+ double x;
+#endif
+{
+ double t;
+ int hx,ix;
+ unsigned lx;
+ hx = __HI(x); /* high word */
+ lx = __LO(x); /* low word */
+ ix = hx&0x7fffffff;
+ if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+ return (x-x)/(x-x);
+ if(ix==0x3ff00000)
+ return x/zero;
+ if(ix<0x3e300000&&(huge+x)>zero) return x; /* x<2**-28 */
+ __HI(x) = ix; /* x <- |x| */
+ if(ix<0x3fe00000) { /* x < 0.5 */
+ t = x+x;
+ t = 0.5*log1p(t+t*x/(one-x));
+ } else
+ t = 0.5*log1p((x+x)/(one-x));
+ if(hx>=0) return t; else return -t;
+}
diff --git a/libm/e_cosh.c b/libm/e_cosh.c
new file mode 100644
index 0000000..6b0db5b
--- /dev/null
+++ b/libm/e_cosh.c
@@ -0,0 +1,89 @@
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_cosh(x)
+ * Method :
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ * 1. Replace x by |x| (cosh(x) = cosh(-x)).
+ * 2.
+ * [ exp(x) - 1 ]^2
+ * 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
+ * 2*exp(x)
+ *
+ * exp(x) + 1/exp(x)
+ * ln2/2 <= x <= 22 : cosh(x) := -------------------
+ * 2
+ * 22 <= x <= lnovft : cosh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ * cosh(x) is |x| if x is +INF, -INF, or NaN.
+ * only cosh(0)=1 is exact for finite x.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, half=0.5, huge = 1.0e300;
+#else
+static double one = 1.0, half=0.5, huge = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_cosh(double x)
+#else
+ double __ieee754_cosh(x)
+ double x;
+#endif
+{
+ double t,w;
+ int ix;
+ unsigned lx;
+
+ /* High word of |x|. */
+ ix = __HI(x);
+ ix &= 0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x*x;
+
+ /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+ if(ix<0x3fd62e43) {
+ t = expm1(fabs(x));
+ w = one+t;
+ if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
+ return one+(t*t)/(w+w);
+ }
+
+ /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+ if (ix < 0x40360000) {
+ t = __ieee754_exp(fabs(x));
+ return half*t+half/t;
+ }
+
+ /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+ if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE ||
+ ((ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d))) {
+ w = __ieee754_exp(half*fabs(x));
+ t = half*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, cosh(x) overflow */
+ return huge*huge;
+}
diff --git a/libm/e_exp.c b/libm/e_exp.c
new file mode 100644
index 0000000..82aad97
--- /dev/null
+++ b/libm/e_exp.c
@@ -0,0 +1,156 @@
+
+/* @(#)e_exp.c 1.6 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Remes algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+halF[2] = {0.5,-0.5,},
+huge = 1.0e+300,
+twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
+ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
+ -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
+ -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+#ifdef __STDC__
+ double __ieee754_exp(double x) /* default IEEE double exp */
+#else
+ double __ieee754_exp(x) /* default IEEE double exp */
+ double x;
+#endif
+{
+ double y,hi,lo,c,t;
+ int k,xsb;
+ unsigned hx;
+
+ hx = __HI(x); /* high word of x */
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|__LO(x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ if(x < u_threshold) return twom1000*twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = (int)(invln2*x+halF[xsb]);
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x3e300000) { /* when |x|<2**-28 */
+ if(huge+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-2.0)-x);
+ else y = one-((lo-(x*c)/(2.0-c))-hi);
+ if(k >= -1021) {
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ return y;
+ } else {
+ __HI(y) += ((k+1000)<<20);/* add k to y's exponent */
+ return y*twom1000;
+ }
+}
diff --git a/libm/e_fmod.c b/libm/e_fmod.c
new file mode 100644
index 0000000..d244366
--- /dev/null
+++ b/libm/e_fmod.c
@@ -0,0 +1,140 @@
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+#else
+static double one = 1.0, Zero[] = {0.0, -0.0,};
+#endif
+
+#ifdef __STDC__
+ double __ieee754_fmod(double x, double y)
+#else
+ double __ieee754_fmod(x,y)
+ double x,y ;
+#endif
+{
+ int n,hx,hy,hz,ix,iy,sx,i;
+ unsigned lx,ly,lz;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+ hy = __HI(y); /* high word of y */
+ ly = __LO(y); /* low word of y */
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
+ ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<=hy) {
+ if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
+ if(lx==ly)
+ return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00100000) { /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+ } else {
+ for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+ }
+ } else ix = (hx>>20)-1023;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00100000) { /* subnormal y */
+ if(hy==0) {
+ for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+ } else {
+ for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+ }
+ } else iy = (hy>>20)-1023;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -1022)
+ hx = 0x00100000|(0x000fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -1022-ix;
+ if(n<=31) {
+ hx = (hx<<n)|(lx>>(32-n));
+ lx <<= n;
+ } else {
+ hx = lx<<(n-32);
+ lx = 0;
+ }
+ }
+ if(iy >= -1022)
+ hy = 0x00100000|(0x000fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -1022-iy;
+ if(n<=31) {
+ hy = (hy<<n)|(ly>>(32-n));
+ ly <<= n;
+ } else {
+ hy = ly<<(n-32);
+ ly = 0;
+ }
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ while(n--) {
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+ else {
+ if((hz|lz)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ hx = hz+hz+(lz>>31); lx = lz+lz;
+ }
+ }
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz>=0) {hx=hz;lx=lz;}
+
+ /* convert back to floating value and restore the sign */
+ if((hx|lx)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ while(hx<0x00100000) { /* normalize x */
+ hx = hx+hx+(lx>>31); lx = lx+lx;
+ iy -= 1;
+ }
+ if(iy>= -1022) { /* normalize output */
+ hx = ((hx-0x00100000)|((iy+1023)<<20));
+ __HI(x) = hx|sx;
+ __LO(x) = lx;
+ } else { /* subnormal output */
+ n = -1022 - iy;
+ if(n<=20) {
+ lx = (lx>>n)|((unsigned)hx<<(32-n));
+ hx >>= n;
+ } else if (n<=31) {
+ lx = (hx<<(32-n))|(lx>>n); hx = sx;
+ } else {
+ lx = hx>>(n-32); hx = sx;
+ }
+ __HI(x) = hx|sx;
+ __LO(x) = lx;
+ x *= one; /* create necessary signal */
+ }
+ return x; /* exact output */
+}
diff --git a/libm/e_gamma.c b/libm/e_gamma.c
new file mode 100644
index 0000000..8c559d5
--- /dev/null
+++ b/libm/e_gamma.c
@@ -0,0 +1,33 @@
+
+/* @(#)e_gamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_gamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_gamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double __ieee754_gamma(double x)
+#else
+ double __ieee754_gamma(x)
+ double x;
+#endif
+{
+ return __ieee754_gamma_r(x,&signgam);
+}
diff --git a/libm/e_gamma_r.c b/libm/e_gamma_r.c
new file mode 100644
index 0000000..d1620fc
--- /dev/null
+++ b/libm/e_gamma_r.c
@@ -0,0 +1,32 @@
+
+/* @(#)e_gamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_gamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method: See __ieee754_lgamma_r
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double __ieee754_gamma_r(double x, int *signgamp)
+#else
+ double __ieee754_gamma_r(x,signgamp)
+ double x; int *signgamp;
+#endif
+{
+ return __ieee754_lgamma_r(x,signgamp);
+}
diff --git a/libm/e_hypot.c b/libm/e_hypot.c
new file mode 100644
index 0000000..01b6a5b
--- /dev/null
+++ b/libm/e_hypot.c
@@ -0,0 +1,115 @@
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :
+ * If (assume round-to-nearest) z=x*x+y*y
+ * has error less than sqrt(2)/2 ulp, than
+ * sqrt(z) has error less than 1 ulp (exercise).
+ *
+ * So, compute sqrt(x*x+y*y) with some care as
+ * follows to get the error below 1 ulp:
+ *
+ * Assume x>y>0;
+ * (if possible, set rounding to round-to-nearest)
+ * 1. if x > 2y use
+ * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ * where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ * 2. if x <= 2y use
+ * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
+ * y1= y with lower 32 bits chopped, y2 = y-y1.
+ *
+ * NOTE: scaling may be necessary if some argument is too
+ * large or too tiny
+ *
+ * Special cases:
+ * hypot(x,y) is INF if x or y is +INF or -INF; else
+ * hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ * hypot(x,y) returns sqrt(x^2+y^2) with error less
+ * than 1 ulps (units in the last place)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double __ieee754_hypot(double x, double y)
+#else
+ double __ieee754_hypot(x,y)
+ double x, y;
+#endif
+{
+ double a=x,b=y,t1,t2,y1,y2,w;
+ int j,k,ha,hb;
+
+ ha = __HI(x)&0x7fffffff; /* high word of x */
+ hb = __HI(y)&0x7fffffff; /* high word of y */
+ if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+ __HI(a) = ha; /* a <- |a| */
+ __HI(b) = hb; /* b <- |b| */
+ if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+ k=0;
+ if(ha > 0x5f300000) { /* a>2**500 */
+ if(ha >= 0x7ff00000) { /* Inf or NaN */
+ w = a+b; /* for sNaN */
+ if(((ha&0xfffff)|__LO(a))==0) w = a;
+ if(((hb^0x7ff00000)|__LO(b))==0) w = b;
+ return w;
+ }
+ /* scale a and b by 2**-600 */
+ ha -= 0x25800000; hb -= 0x25800000; k += 600;
+ __HI(a) = ha;
+ __HI(b) = hb;
+ }
+ if(hb < 0x20b00000) { /* b < 2**-500 */
+ if(hb <= 0x000fffff) { /* subnormal b or 0 */
+ if((hb|(__LO(b)))==0) return a;
+ t1=0;
+ __HI(t1) = 0x7fd00000; /* t1=2^1022 */
+ b *= t1;
+ a *= t1;
+ k -= 1022;
+ } else { /* scale a and b by 2^600 */
+ ha += 0x25800000; /* a *= 2^600 */
+ hb += 0x25800000; /* b *= 2^600 */
+ k -= 600;
+ __HI(a) = ha;
+ __HI(b) = hb;
+ }
+ }
+ /* medium size a and b */
+ w = a-b;
+ if (w>b) {
+ t1 = 0;
+ __HI(t1) = ha;
+ t2 = a-t1;
+ w = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+ } else {
+ a = a+a;
+ y1 = 0;
+ __HI(y1) = hb;
+ y2 = b - y1;
+ t1 = 0;
+ __HI(t1) = ha+0x00100000;
+ t2 = a - t1;
+ w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+ }
+ if(k!=0) {
+ t1 = 1.0;
+ __HI(t1) += (k<<20);
+ return t1*w;
+ } else return w;
+}
diff --git a/libm/e_j0.c b/libm/e_j0.c
new file mode 100644
index 0000000..92253b8
--- /dev/null
+++ b/libm/e_j0.c
@@ -0,0 +1,478 @@
+
+/* @(#)e_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ * 2. Reduce x to |x| since j0(x)=j0(-x), and
+ * for x in (0,2)
+ * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x;
+ * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ * for x in (2,inf)
+ * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * as follow:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (cos(x) + sin(x))
+ * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j0(nan)= nan
+ * j0(0) = 1
+ * j0(inf) = 0
+ *
+ * Method -- y0(x):
+ * 1. For x<2.
+ * Since
+ * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ * We use the following function to approximate y0,
+ * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ * where
+ * U(z) = u00 + u01*z + ... + u06*z^6
+ * V(z) = 1 + v01*z + ... + v04*z^4
+ * with absolute approximation error bounded by 2**-72.
+ * Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ * 2. For x>=2.
+ * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * by the method mentioned above.
+ * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static double pzero(double), qzero(double);
+#else
+static double pzero(), qzero();
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0, 2.00] */
+R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_j0(double x)
+#else
+ double __ieee754_j0(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,r,u,v;
+ int hx,ix;
+
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/(x*x);
+ x = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<0x3f200000) { /* |x| < 2**-13 */
+ if(huge+x>one) { /* raise inexact if x != 0 */
+ if(ix<0x3e400000) return one; /* |x|<2**-27 */
+ else return one - 0.25*x*x;
+ }
+ }
+ z = x*x;
+ r = z*(R02+z*(R03+z*(R04+z*R05)));
+ s = one+z*(S01+z*(S02+z*(S03+z*S04)));
+ if(ix < 0x3FF00000) { /* |x| < 1.00 */
+ return one + z*(-0.25+(r/s));
+ } else {
+ u = 0.5*x;
+ return((one+u)*(one-u)+z*(r/s));
+ }
+}
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+#ifdef __STDC__
+ double __ieee754_y0(double x)
+#else
+ double __ieee754_y0(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ * where x0 = x-pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) + cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3e400000) { /* x < 2**-27 */
+ return(u00 + tpi*__ieee754_log(x));
+ }
+ z = x*x;
+ u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+ v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+ return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * pzero(x) = 1 + (R/S)
+ * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ * | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+ */
+#ifdef __STDC__
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+#ifdef __STDC__
+static const double pS8[5] = {
+#else
+static double pS8[5] = {
+#endif
+ 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+ 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+ 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+ 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+ 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+#ifdef __STDC__
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+#ifdef __STDC__
+static const double pS5[5] = {
+#else
+static double pS5[5] = {
+#endif
+ 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+ 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+ 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+ 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+ 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+#ifdef __STDC__
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#else
+static double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+#ifdef __STDC__
+static const double pS3[5] = {
+#else
+static double pS3[5] = {
+#endif
+ 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+ 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+ 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+ 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+ 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+#ifdef __STDC__
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+#ifdef __STDC__
+static const double pS2[5] = {
+#else
+static double pS2[5] = {
+#endif
+ 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+ 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+ 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+ 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+#ifdef __STDC__
+ static double pzero(double x)
+#else
+ static double pzero(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double z,r,s;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = pR8; q= pS8;}
+ else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+ else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+ else if(ix>=0x40000000){p = pR2; q= pS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ * -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * qzero(x) = s*(-1.25 + (R/S))
+ * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
+ */
+#ifdef __STDC__
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+ 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+ 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+ 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+ 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+#ifdef __STDC__
+static const double qS8[6] = {
+#else
+static double qS8[6] = {
+#endif
+ 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+ 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+ 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+ 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+ 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+#ifdef __STDC__
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+ 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+ 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+ 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+ 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+ 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+#ifdef __STDC__
+static const double qS5[6] = {
+#else
+static double qS5[6] = {
+#endif
+ 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+ 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+ 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+ 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+ 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+#ifdef __STDC__
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#else
+static double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+ 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+ 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+ 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+ 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+ 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+#ifdef __STDC__
+static const double qS3[6] = {
+#else
+static double qS3[6] = {
+#endif
+ 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+ 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+ 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+ 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+ 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+#ifdef __STDC__
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+ 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+ 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+ 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+ 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+ 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+#ifdef __STDC__
+static const double qS2[6] = {
+#else
+static double qS2[6] = {
+#endif
+ 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+ 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+ 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+ 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+ 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+#ifdef __STDC__
+ static double qzero(double x)
+#else
+ static double qzero(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double s,r,z;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = qR8; q= qS8;}
+ else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+ else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+ else if(ix>=0x40000000){p = qR2; q= qS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (-.125 + r/s)/x;
+}
diff --git a/libm/e_j1.c b/libm/e_j1.c
new file mode 100644
index 0000000..836d966
--- /dev/null
+++ b/libm/e_j1.c
@@ -0,0 +1,477 @@
+
+/* @(#)e_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ * 2. Reduce x to |x| since j1(x)=-j1(-x), and
+ * for x in (0,2)
+ * j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+ * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ * for x in (2,inf)
+ * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * as follow:
+ * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (sin(x) + cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j1(nan)= nan
+ * j1(0) = 0
+ * j1(inf) = 0
+ *
+ * Method -- y1(x):
+ * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+ * 2. For x<2.
+ * Since
+ * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ * We use the following function to approximate y1,
+ * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ * where for x in [0,2] (abs err less than 2**-65.89)
+ * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5
+ * Note: For tiny x, 1/x dominate y1 and hence
+ * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ * 3. For x>=2.
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * by method mentioned above.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static double pone(double), qone(double);
+#else
+static double pone(), qone();
+#endif
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0,2] */
+r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_j1(double x)
+#else
+ double __ieee754_j1(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,r,u,v,y;
+ int hx,ix;
+
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/x;
+ y = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(y);
+ c = cos(y);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure y+y not overflow */
+ z = cos(y+y);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y);
+ else {
+ u = pone(y); v = qone(y);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(y);
+ }
+ if(hx<0) return -z;
+ else return z;
+ }
+ if(ix<0x3e400000) { /* |x|<2**-27 */
+ if(huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+ }
+ z = x*x;
+ r = z*(r00+z*(r01+z*(r02+z*r03)));
+ s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+ r *= x;
+ return(x*0.5+r/s);
+}
+
+#ifdef __STDC__
+static const double U0[5] = {
+#else
+static double U0[5] = {
+#endif
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+#ifdef __STDC__
+static const double V0[5] = {
+#else
+static double V0[5] = {
+#endif
+ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+ 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+#ifdef __STDC__
+ double __ieee754_y1(double x)
+#else
+ double __ieee754_y1(x)
+ double x;
+#endif
+{
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = cos(x+x);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ * where x0 = x-3pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (cos(x) + sin(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pone(x); v = qone(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3c900000) { /* x < 2**-54 */
+ return(-tpi/x);
+ }
+ z = x*x;
+ u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+ v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+ return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x.
+ * We approximate pone by
+ * pone(x) = 1 + (R/S)
+ * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ * | pone(x)-1-R/S | <= 2 ** ( -60.06)
+ */
+
+#ifdef __STDC__
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+ 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+ 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+#ifdef __STDC__
+static const double ps8[5] = {
+#else
+static double ps8[5] = {
+#endif
+ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+ 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+#ifdef __STDC__
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+ 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+ 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+#ifdef __STDC__
+static const double ps5[5] = {
+#else
+static double ps5[5] = {
+#endif
+ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+ 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+#ifdef __STDC__
+static const double pr3[6] = {
+#else
+static double pr3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+ 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+#ifdef __STDC__
+static const double ps3[5] = {
+#else
+static double ps3[5] = {
+#endif
+ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+ 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+#ifdef __STDC__
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+ 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+ 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+#ifdef __STDC__
+static const double ps2[5] = {
+#else
+static double ps2[5] = {
+#endif
+ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+ 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+#ifdef __STDC__
+ static double pone(double x)
+#else
+ static double pone(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double z,r,s;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = pr8; q= ps8;}
+ else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+ else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+ else if(ix>=0x40000000){p = pr2; q= ps2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ * 3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * qone(x) = s*(0.375 + (R/S))
+ * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13)
+ */
+
+#ifdef __STDC__
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#else
+static double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+#endif
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+#ifdef __STDC__
+static const double qs8[6] = {
+#else
+static double qs8[6] = {
+#endif
+ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+ 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+ 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+#ifdef __STDC__
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#else
+static double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+#endif
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+#ifdef __STDC__
+static const double qs5[6] = {
+#else
+static double qs5[6] = {
+#endif
+ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+ 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+ 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+#ifdef __STDC__
+static const double qr3[6] = {
+#else
+static double qr3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+#endif
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+#ifdef __STDC__
+static const double qs3[6] = {
+#else
+static double qs3[6] = {
+#endif
+ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+ 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+ 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+#ifdef __STDC__
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#else
+static double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+#endif
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+#ifdef __STDC__
+static const double qs2[6] = {
+#else
+static double qs2[6] = {
+#endif
+ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+ 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+#ifdef __STDC__
+ static double qone(double x)
+#else
+ static double qone(x)
+ double x;
+#endif
+{
+#ifdef __STDC__
+ const double *p,*q;
+#else
+ double *p,*q;
+#endif
+ double s,r,z;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = qr8; q= qs8;}
+ else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+ else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+ else if(ix>=0x40000000){p = qr2; q= qs2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (.375 + r/s)/x;
+}
diff --git a/libm/e_jn.c b/libm/e_jn.c
new file mode 100644
index 0000000..6ceb618
--- /dev/null
+++ b/libm/e_jn.c
@@ -0,0 +1,272 @@
+
+/* @(#)e_jn.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static double zero = 0.00000000000000000000e+00;
+
+#ifdef __STDC__
+ double __ieee754_jn(int n, double x)
+#else
+ double __ieee754_jn(n,x)
+ int n; double x;
+#endif
+{
+ int i,hx,ix,lx, sgn;
+ double a, b, temp, di;
+ double z, w;
+
+ /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+ * Thus, J(-n,x) = J(n,-x)
+ */
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* if J(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if(n<0){
+ n = -n;
+ x = -x;
+ hx ^= 0x80000000;
+ }
+ if(n==0) return(__ieee754_j0(x));
+ if(n==1) return(__ieee754_j1(x));
+ sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */
+ x = fabs(x);
+ if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */
+ b = zero;
+ else if((double)n<=x) {
+ /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = cos(x)+sin(x); break;
+ case 1: temp = -cos(x)+sin(x); break;
+ case 2: temp = -cos(x)-sin(x); break;
+ case 3: temp = cos(x)-sin(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_j0(x);
+ b = __ieee754_j1(x);
+ for(i=1;i<n;i++){
+ temp = b;
+ b = b*((double)(i+i)/x) - a; /* avoid underflow */
+ a = temp;
+ }
+ }
+ } else {
+ if(ix<0x3e100000) { /* x < 2**-29 */
+ /* x is tiny, return the first Taylor expansion of J(n,x)
+ * J(n,x) = 1/n!*(x/2)^n - ...
+ */
+ if(n>33) /* underflow */
+ b = zero;
+ else {
+ temp = x*0.5; b = temp;
+ for (a=one,i=2;i<=n;i++) {
+ a *= (double)i; /* a = n! */
+ b *= temp; /* b = (x/2)^n */
+ }
+ b = b/a;
+ }
+ } else {
+ /* use backward recurrence */
+ /* x x^2 x^2
+ * J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ * 2n - 2(n+1) - 2(n+2)
+ *
+ * 1 1 1
+ * (for large x) = ---- ------ ------ .....
+ * 2n 2(n+1) 2(n+2)
+ * -- - ------ - ------ -
+ * x x x
+ *
+ * Let w = 2n/x and h=2/x, then the above quotient
+ * is equal to the continued fraction:
+ * 1
+ * = -----------------------
+ * 1
+ * w - -----------------
+ * 1
+ * w+h - ---------
+ * w+2h - ...
+ *
+ * To determine how many terms needed, let
+ * Q(0) = w, Q(1) = w(w+h) - 1,
+ * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ * When Q(k) > 1e4 good for single
+ * When Q(k) > 1e9 good for double
+ * When Q(k) > 1e17 good for quadruple
+ */
+ /* determine k */
+ double t,v;
+ double q0,q1,h,tmp; int k,m;
+ w = (n+n)/(double)x; h = 2.0/(double)x;
+ q0 = w; z = w+h; q1 = w*z - 1.0; k=1;
+ while(q1<1.0e9) {
+ k += 1; z += h;
+ tmp = z*q1 - q0;
+ q0 = q1;
+ q1 = tmp;
+ }
+ m = n+n;
+ for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+ a = t;
+ b = one;
+ /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+ * Hence, if n*(log(2n/x)) > ...
+ * single 8.8722839355e+01
+ * double 7.09782712893383973096e+02
+ * long double 1.1356523406294143949491931077970765006170e+04
+ * then recurrent value may overflow and the result is
+ * likely underflow to zero
+ */
+ tmp = n;
+ v = two/x;
+ tmp = tmp*__ieee754_log(fabs(v*tmp));
+ if(tmp<7.09782712893383973096e+02) {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ }
+ } else {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ /* scale b to avoid spurious overflow */
+ if(b>1e100) {
+ a /= b;
+ t /= b;
+ b = one;
+ }
+ }
+ }
+ b = (t*__ieee754_j0(x)/b);
+ }
+ }
+ if(sgn==1) return -b; else return b;
+}
+
+#ifdef __STDC__
+ double __ieee754_yn(int n, double x)
+#else
+ double __ieee754_yn(n,x)
+ int n; double x;
+#endif
+{
+ int i,hx,ix,lx;
+ int sign;
+ double a, b, temp;
+
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* if Y(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ sign = 1;
+ if(n<0){
+ n = -n;
+ sign = 1 - ((n&1)<<1);
+ }
+ if(n==0) return(__ieee754_y0(x));
+ if(n==1) return(sign*__ieee754_y1(x));
+ if(ix==0x7ff00000) return zero;
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = sin(x)-cos(x); break;
+ case 1: temp = -sin(x)-cos(x); break;
+ case 2: temp = -sin(x)+cos(x); break;
+ case 3: temp = sin(x)+cos(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_y0(x);
+ b = __ieee754_y1(x);
+ /* quit if b is -inf */
+ for(i=1;i<n&&(__HI(b) != 0xfff00000);i++){
+ temp = b;
+ b = ((double)(i+i)/x)*b - a;
+ a = temp;
+ }
+ }
+ if(sign>0) return b; else return -b;
+}
diff --git a/libm/e_lgamma.c b/libm/e_lgamma.c
new file mode 100644
index 0000000..1701bd6
--- /dev/null
+++ b/libm/e_lgamma.c
@@ -0,0 +1,33 @@
+
+/* @(#)e_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_lgamma(x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double __ieee754_lgamma(double x)
+#else
+ double __ieee754_lgamma(x)
+ double x;
+#endif
+{
+ return __ieee754_lgamma_r(x,&signgam);
+}
diff --git a/libm/e_lgamma_r.c b/libm/e_lgamma_r.c
new file mode 100644
index 0000000..846370c
--- /dev/null
+++ b/libm/e_lgamma_r.c
@@ -0,0 +1,304 @@
+
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * where
+ * poly(z) is a 14 degree polynomial.
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * with accuracy
+ * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ * where
+ * |w - f(z)| < 2**-58.74
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1)=lgamma(2)=0
+ * lgamma(x) ~ -log(x) for tiny x
+ * lgamma(0) = lgamma(inf) = inf
+ * lgamma(-integer) = +-inf
+ *
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static double zero= 0.00000000000000000000e+00;
+
+#ifdef __STDC__
+ static double sin_pi(double x)
+#else
+ static double sin_pi(x)
+ double x;
+#endif
+{
+ double y,z;
+ int n,ix;
+
+ ix = 0x7fffffff&__HI(x);
+
+ if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floor(y);
+ if(z!=y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */
+ n = (int) (y*4.0);
+ } else {
+ if(ix>=0x43400000) {
+ y = zero; n = 0; /* y must be even */
+ } else {
+ if(ix<0x43300000) z = y+two52; /* exact */
+ n = __LO(z)&1; /* lower word of z */
+ y = n;
+ n<<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __kernel_sin(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cos(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sin(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cos(pi*(y-1.5),zero); break;
+ default: y = __kernel_sin(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+
+#ifdef __STDC__
+ double __ieee754_lgamma_r(double x, int *signgamp)
+#else
+ double __ieee754_lgamma_r(x,signgamp)
+ double x; int *signgamp;
+#endif
+{
+ double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int i,hx,lx,ix;
+
+ hx = __HI(x);
+ lx = __LO(x);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ *signgamp = 1;
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x*x;
+ if((ix|lx)==0) return one/zero;
+ if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ if(hx<0) {
+ *signgamp = -1;
+ return -__ieee754_log(-x);
+ } else return -__ieee754_log(x);
+ }
+ if(hx<0) {
+ if(ix>=0x43300000) /* |x|>=2**52, must be -integer */
+ return one/zero;
+ t = sin_pi(x);
+ if(t==zero) return one/zero; /* -integer */
+ nadj = __ieee754_log(pi/fabs(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x40000000) {
+ if(ix<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -__ieee754_log(x);
+ if(ix>=0x3FE76944) {y = one-x; i= 0;}
+ else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = zero;
+ if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+ else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+ else {y=x-one;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-0.5*y); break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p); break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += (-0.5*y + p1/p2);
+ }
+ }
+ else if(ix<0x40200000) { /* x < 8.0 */
+ i = (int)x;
+ t = zero;
+ y = x-(double)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = half*y+p/q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6.0); /* FALLTHRU */
+ case 6: z *= (y+5.0); /* FALLTHRU */
+ case 5: z *= (y+4.0); /* FALLTHRU */
+ case 4: z *= (y+3.0); /* FALLTHRU */
+ case 3: z *= (y+2.0); /* FALLTHRU */
+ r += __ieee754_log(z); break;
+ }
+ /* 8.0 <= x < 2**58 */
+ } else if (ix < 0x43900000) {
+ t = __ieee754_log(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-half)*(t-one)+w;
+ } else
+ /* 2**58 <= x <= inf */
+ r = x*(__ieee754_log(x)-one);
+ if(hx<0) r = nadj - r;
+ return r;
+}
diff --git a/libm/e_log.c b/libm/e_log.c
new file mode 100644
index 0000000..b135771
--- /dev/null
+++ b/libm/e_log.c
@@ -0,0 +1,145 @@
+
+/* @(#)e_log.c 1.4 96/03/07 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * 2. Approximation of log(1+f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Remes algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
+ * (the values of Lg1 to Lg7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lg1*s +...+Lg7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log(1+f) = f - s*(f - R) (if f is not too large)
+ * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+ *
+ * 3. Finally, log(x) = k*ln2 + log(1+f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log(x) is NaN with signal if x < 0 (including -INF) ;
+ * log(+INF) is +INF; log(0) is -INF with signal;
+ * log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_log(double x)
+#else
+ double __ieee754_log(x)
+ double x;
+#endif
+{
+ double hfsq,f,s,z,R,w,t1,t2,dk;
+ int k,hx,i,j;
+ unsigned lx;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ hx = __HI(x); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ hx &= 0x000fffff;
+ i = (hx+0x95f64)&0x100000;
+ __HI(x) = hx|(i^0x3ff00000); /* normalize x or x/2 */
+ k += (i>>20);
+ f = x-1.0;
+ if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */
+
+ if(f==zero)
+ {
+ if(k==0) return zero;
+ else {dk=(double)k;
+ return dk*ln2_hi+dk*ln2_lo;}
+ }
+
+ R = f*f*(0.5-0.33333333333333333*f);
+ if(k==0) return f-R; else {dk=(double)k;
+ return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+ }
+ s = f/(2.0+f);
+ dk = (double)k;
+ z = s*s;
+ i = hx-0x6147a;
+ w = z*z;
+ j = 0x6b851-hx;
+ t1= w*(Lg2+w*(Lg4+w*Lg6));
+ t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+ i |= j;
+ R = t2+t1;
+ if(i>0) {
+ hfsq=0.5*f*f;
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+ } else {
+ if(k==0) return f-s*(f-R); else
+ return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+ }
+}
diff --git a/libm/e_log10.c b/libm/e_log10.c
new file mode 100644
index 0000000..5d7e74b
--- /dev/null
+++ b/libm/e_log10.c
@@ -0,0 +1,91 @@
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log10(x)
+ * Return the base 10 logarithm of x
+ *
+ * Method :
+ * Let log10_2hi = leading 40 bits of log10(2) and
+ * log10_2lo = log10(2) - log10_2hi,
+ * ivln10 = 1/log(10) rounded.
+ * Then
+ * n = ilogb(x),
+ * if(n<0) n = n+1;
+ * x = scalbn(x,-n);
+ * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ * To guarantee log10(10**n)=n, where 10**n is normal, the rounding
+ * mode must set to Round-to-Nearest.
+ * Note 2:
+ * [1/log(10)] rounded to 53 bits has error .198 ulps;
+ * log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ * log10(x) is NaN with signal if x < 0;
+ * log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ * log10(NaN) is that NaN with no signal;
+ * log10(10**N) = N for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double __ieee754_log10(double x)
+#else
+ double __ieee754_log10(x)
+ double x;
+#endif
+{
+ double y,z;
+ int i,k,hx;
+ unsigned lx;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ hx = __HI(x); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ i = ((unsigned)k&0x80000000)>>31;
+ hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+ y = (double)(k+i);
+ __HI(x) = hx;
+ z = y*log10_2lo + ivln10*__ieee754_log(x);
+ return z+y*log10_2hi;
+}
diff --git a/libm/e_pow.c b/libm/e_pow.c
new file mode 100644
index 0000000..3f39c3e
--- /dev/null
+++ b/libm/e_pow.c
@@ -0,0 +1,309 @@
+
+//#ifndef lint
+//static char sccsid[] = "@(#)e_pow.c 1.5 04/04/22 SMI";
+//#endif
+
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ * n
+ * Method: Let x = 2 * (1+f)
+ * 1. Compute and return log2(x) in two pieces:
+ * log2(x) = w1 + w2,
+ * where w1 has 53-24 = 29 bit trailing zeros.
+ * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * arithmetic, where |y'|<=0.5.
+ * 3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ * 1. (anything) ** 0 is 1
+ * 2. (anything) ** 1 is itself
+ * 3. (anything) ** NAN is NAN
+ * 4. NAN ** (anything except 0) is NAN
+ * 5. +-(|x| > 1) ** +INF is +INF
+ * 6. +-(|x| > 1) ** -INF is +0
+ * 7. +-(|x| < 1) ** +INF is +0
+ * 8. +-(|x| < 1) ** -INF is +INF
+ * 9. +-1 ** +-INF is NAN
+ * 10. +0 ** (+anything except 0, NAN) is +0
+ * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
+ * 12. +0 ** (-anything except 0, NAN) is +INF
+ * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
+ * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ * 15. +INF ** (+anything except 0,NAN) is +INF
+ * 16. +INF ** (-anything except 0,NAN) is +0
+ * 17. -INF ** (anything) = -0 ** (-anything)
+ * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ * 19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ * pow(x,y) returns x**y nearly rounded. In particular
+ * pow(integer,integer)
+ * always returns the correct integer provided it is
+ * representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
+huge = 1.0e300,
+tiny = 1.0e-300,
+ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+#ifdef __STDC__
+ double __ieee754_pow(double x, double y)
+#else
+ double __ieee754_pow(x,y)
+ double x, y;
+#endif
+{
+ double z,ax,z_h,z_l,p_h,p_l;
+ double y1,t1,t2,r,s,t,u,v,w;
+ int i,j,k,yisint,n;
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ //i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
+ hx = __HI(x); lx = __LO(x);
+ hy = __HI(y); ly = __LO(y);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if((iy|ly)==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+ iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x43400000) yisint = 2; /* even integer y */
+ else if(iy>=0x3ff00000) {
+ k = (iy>>20)-0x3ff; /* exponent */
+ if(k>20) {
+ j = ly>>(52-k);
+ if((j<<(52-k))==ly) yisint = 2-(j&1);
+ } else if(ly==0) {
+ j = iy>>(20-k);
+ if((j<<(20-k))==iy) yisint = 2-(j&1);
+ }
+ }
+ }
+
+ /* special value of y */
+ if(ly==0) {
+ if (iy==0x7ff00000) { /* y is +-inf */
+ if(((ix-0x3ff00000)|lx)==0)
+ return y - y; /* inf**+-1 is NaN */
+ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3ff00000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3fe00000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return sqrt(x);
+ }
+ }
+
+ ax = fabs(x);
+ /* special value of x */
+ if(lx==0) {
+ if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3ff00000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1)
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+ }
+ return z;
+ }
+ }
+
+ n = (hx>>31)+1;
+
+ /* (x<0)**(non-int) is NaN */
+ if((n|yisint)==0) return (x-x)/(x-x);
+
+ s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+ /* |y| is huge */
+ if(iy>0x41e00000) { /* if |y| > 2**31 */
+ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
+ if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+ if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+ }
+ /* over/underflow if x is not close to one */
+ if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+ if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = ax-one; /* t has 20 trailing zeros */
+ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+ u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ __LO(t1) = 0;
+ t2 = v-(t1-u);
+ } else {
+ double ss,s2,s_h,s_l,t_h,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00100000)
+ {ax *= two53; n -= 53; ix = __HI(ax); }
+ n += ((ix)>>20)-0x3ff;
+ j = ix&0x000fffff;
+ /* determine interval */
+ ix = j|0x3ff00000; /* normalize ix */
+ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00100000;}
+ __HI(ax) = ix;
+
+ /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ ss = u*v;
+ s_h = ss;
+ __LO(s_h) = 0;
+ /* t_h=ax+bp[k] High */
+ t_h = zero;
+ __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = ss*ss;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+ss);
+ s2 = s_h*s_h;
+ t_h = 3.0+s2+r;
+ __LO(t_h) = 0;
+ t_l = r-((t_h-3.0)-s2);
+ /* u+v = ss*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*ss;
+ /* 2/(3log2)*(ss+...) */
+ p_h = u+v;
+ __LO(p_h) = 0;
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (double)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ __LO(t1) = 0;
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ y1 = y;
+ __LO(y1) = 0;
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ j = __HI(z);
+ i = __LO(z);
+ if (j>=0x40900000) { /* z >= 1024 */
+ if(((j-0x40900000)|i)!=0) /* if z > 1024 */
+ return s*huge*huge; /* overflow */
+ else {
+ if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */
+ }
+ } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
+ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
+ return s*tiny*tiny; /* underflow */
+ else {
+ if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
+ }
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>20)-0x3ff;
+ n = 0;
+ if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00100000>>(k+1));
+ k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
+ t = zero;
+ __HI(t) = (n&~(0x000fffff>>k));
+ n = ((n&0x000fffff)|0x00100000)>>(20-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ __LO(t) = 0;
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ j = __HI(z);
+ j += (n<<20);
+ if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+ else __HI(z) += (n<<20);
+ return s*z;
+}
diff --git a/libm/e_rem_pio2.c b/libm/e_rem_pio2.c
new file mode 100644
index 0000000..e8e1fa3
--- /dev/null
+++ b/libm/e_rem_pio2.c
@@ -0,0 +1,175 @@
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2()
+ */
+
+#include "math.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+#ifdef __STDC__
+static const int two_over_pi[] = {
+#else
+static int two_over_pi[] = {
+#endif
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
+};
+
+#ifdef __STDC__
+static const int npio2_hw[] = {
+#else
+static int npio2_hw[] = {
+#endif
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 33 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 33 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+#ifdef __STDC__
+ int __ieee754_rem_pio2(double x, double *y)
+#else
+ int __ieee754_rem_pio2(x,y)
+ double x,y[];
+#endif
+{
+ double z,w,t,r,fn;
+ double tx[3];
+ int e0,i,j,nx,n,ix,hx;
+
+ hx = __HI(x); /* high word of x */
+ ix = hx&0x7fffffff;
+ if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */
+ if(hx>0) {
+ z = x - pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z - pio2_1t;
+ y[1] = (z-y[0])-pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z -= pio2_2;
+ y[0] = z - pio2_2t;
+ y[1] = (z-y[0])-pio2_2t;
+ }
+ return 1;
+ } else { /* negative x */
+ z = x + pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z + pio2_1t;
+ y[1] = (z-y[0])+pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z += pio2_2;
+ y[0] = z + pio2_2t;
+ y[1] = (z-y[0])+pio2_2t;
+ }
+ return -1;
+ }
+ }
+ if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+ t = fabs(x);
+ n = (int) (t*invpio2+half);
+ fn = (double)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 85 bit */
+ if(n<32&&ix!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ j = ix>>20;
+ y[0] = r-w;
+ i = j-(((__HI(y[0]))>>20)&0x7ff);
+ if(i>16) { /* 2nd iteration needed, good to 118 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ i = j-(((__HI(y[0]))>>20)&0x7ff);
+ if(i>49) { /* 3rd iteration need, 151 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(ix>=0x7ff00000) { /* x is inf or NaN */
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-23) */
+ __LO(z) = __LO(x);
+ e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */
+ __HI(z) = ix - (e0<<20);
+ for(i=0;i<2;i++) {
+ tx[i] = (double)((int)(z));
+ z = (z-tx[i])*two24;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
diff --git a/libm/e_remainder.c b/libm/e_remainder.c
new file mode 100644
index 0000000..76288b0
--- /dev/null
+++ b/libm/e_remainder.c
@@ -0,0 +1,77 @@
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_remainder(x,p)
+ * Return :
+ * returns x REM p = x - [x/p]*p as if in infinite
+ * precise arithmetic, where [x/p] is the (infinite bit)
+ * integer nearest x/p (in half way case choose the even one).
+ * Method :
+ * Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double zero = 0.0;
+#else
+static double zero = 0.0;
+#endif
+
+
+#ifdef __STDC__
+ double __ieee754_remainder(double x, double p)
+#else
+ double __ieee754_remainder(x,p)
+ double x,p;
+#endif
+{
+ int hx,hp;
+ unsigned sx,lx,lp;
+ double p_half;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+ hp = __HI(p); /* high word of p */
+ lp = __LO(p); /* low word of p */
+ sx = hx&0x80000000;
+ hp &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ /* purge off exception values */
+ if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */
+ if((hx>=0x7ff00000)|| /* x not finite */
+ ((hp>=0x7ff00000)&& /* p is NaN */
+ (((hp-0x7ff00000)|lp)!=0)))
+ return (x*p)/(x*p);
+
+
+ if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */
+ if (((hx-hp)|(lx-lp))==0) return zero*x;
+ x = fabs(x);
+ p = fabs(p);
+ if (hp<0x00200000) {
+ if(x+x>p) {
+ x-=p;
+ if(x+x>=p) x -= p;
+ }
+ } else {
+ p_half = 0.5*p;
+ if(x>p_half) {
+ x-=p;
+ if(x>=p_half) x -= p;
+ }
+ }
+ __HI(x) ^= sx;
+ return x;
+}
diff --git a/libm/e_scalb.c b/libm/e_scalb.c
new file mode 100644
index 0000000..054ff72
--- /dev/null
+++ b/libm/e_scalb.c
@@ -0,0 +1,51 @@
+
+/* @(#)e_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_scalb(x, fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "math.h"
+
+#ifdef _SCALB_INT
+#ifdef __STDC__
+ double __ieee754_scalb(double x, int fn)
+#else
+ double __ieee754_scalb(x,fn)
+ double x; int fn;
+#endif
+#else
+#ifdef __STDC__
+ double __ieee754_scalb(double x, double fn)
+#else
+ double __ieee754_scalb(x,fn)
+ double x, fn;
+#endif
+#endif
+{
+#ifdef _SCALB_INT
+ return scalbn(x,fn);
+#else
+ if (isnan(x)||isnan(fn)) return x*fn;
+ if (!finite(fn)) {
+ if(fn>0.0) return x*fn;
+ else return x/(-fn);
+ }
+ if (rint(fn)!=fn) return (fn-fn)/(fn-fn);
+ if ( fn > 65000.0) return scalbn(x, 65000);
+ if (-fn > 65000.0) return scalbn(x,-65000);
+ return scalbn(x,(int)fn);
+#endif
+}
diff --git a/libm/e_sinh.c b/libm/e_sinh.c
new file mode 100644
index 0000000..a0650c4
--- /dev/null
+++ b/libm/e_sinh.c
@@ -0,0 +1,82 @@
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sinh(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ * 1. Replace x by |x| (sinh(-x) = -sinh(x)).
+ * 2.
+ * E + E/(E+1)
+ * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
+ * 2
+ *
+ * 22 <= x <= lnovft : sinh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ * sinh(x) is |x| if x is +INF, -INF, or NaN.
+ * only sinh(0)=0 is exact for finite x.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, shuge = 1.0e307;
+#else
+static double one = 1.0, shuge = 1.0e307;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_sinh(double x)
+#else
+ double __ieee754_sinh(x)
+ double x;
+#endif
+{
+ double t,w,h;
+ int ix,jx;
+ unsigned lx;
+
+ /* High word of |x|. */
+ jx = __HI(x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x+x;
+
+ h = 0.5;
+ if (jx<0) h = -h;
+ /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3e300000) /* |x|<2**-28 */
+ if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+ t = expm1(fabs(x));
+ if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+ return h*(t+t/(t+one));
+ }
+
+ /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+ if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d))) {
+ w = __ieee754_exp(0.5*fabs(x));
+ t = h*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, sinh(x) overflow */
+ return x*shuge;
+}
diff --git a/libm/e_sqrt.c b/libm/e_sqrt.c
new file mode 100644
index 0000000..f8e32cc
--- /dev/null
+++ b/libm/e_sqrt.c
@@ -0,0 +1,450 @@
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ * ------------------------------------------
+ * | Use the hardware sqrt if you have one |
+ * ------------------------------------------
+ * Method:
+ * Bit by bit method using integer arithmetic. (Slow, but portable)
+ * 1. Normalization
+ * Scale x to y in [1,4) with even powers of 2:
+ * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
+ * sqrt(x) = 2^k * sqrt(y)
+ * 2. Bit by bit computation
+ * Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+ * i 0
+ * i+1 2
+ * s = 2*q , and y = 2 * ( y - q ). (1)
+ * i i i i
+ *
+ * To compute q from q , one checks whether
+ * i+1 i
+ *
+ * -(i+1) 2
+ * (q + 2 ) <= y. (2)
+ * i
+ * -(i+1)
+ * If (2) is false, then q = q ; otherwise q = q + 2 .
+ * i+1 i i+1 i
+ *
+ * With some algebric manipulation, it is not difficult to see
+ * that (2) is equivalent to
+ * -(i+1)
+ * s + 2 <= y (3)
+ * i i
+ *
+ * The advantage of (3) is that s and y can be computed by
+ * i i
+ * the following recurrence formula:
+ * if (3) is false
+ *
+ * s = s , y = y ; (4)
+ * i+1 i i+1 i
+ *
+ * otherwise,
+ * -i -(i+1)
+ * s = s + 2 , y = y - s - 2 (5)
+ * i+1 i i+1 i i
+ *
+ * One may easily use induction to prove (4) and (5).
+ * Note. Since the left hand side of (3) contain only i+2 bits,
+ * it does not necessary to do a full (53-bit) comparison
+ * in (3).
+ * 3. Final rounding
+ * After generating the 53 bits result, we compute one more bit.
+ * Together with the remainder, we can decide whether the
+ * result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ * (it will never equal to 1/2ulp).
+ * The rounding mode can be detected by checking whether
+ * huge + tiny is equal to huge, and whether huge - tiny is
+ * equal to huge for some floating point number "huge" and "tiny".
+ *
+ * Special cases:
+ * sqrt(+-0) = +-0 ... exact
+ * sqrt(inf) = inf
+ * sqrt(-ve) = NaN ... with invalid signal
+ * sqrt(NaN) = NaN ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0, tiny=1.0e-300;
+#else
+static double one = 1.0, tiny=1.0e-300;
+#endif
+
+#ifdef __STDC__
+ double __ieee754_sqrt(double x)
+#else
+ double __ieee754_sqrt(x)
+ double x;
+#endif
+{
+ double z;
+ int sign = (int)0x80000000;
+ unsigned r,t1,s1,ix1,q1;
+ int ix0,s0,q,m,t,i;
+
+ ix0 = __HI(x); /* high word of x */
+ ix1 = __LO(x); /* low word of x */
+
+ /* take care of Inf and NaN */
+ if((ix0&0x7ff00000)==0x7ff00000) {
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ }
+ /* take care of zero */
+ if(ix0<=0) {
+ if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+ else if(ix0<0)
+ return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+ }
+ /* normalize x */
+ m = (ix0>>20);
+ if(m==0) { /* subnormal x */
+ while(ix0==0) {
+ m -= 21;
+ ix0 |= (ix1>>11); ix1 <<= 21;
+ }
+ for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+ m -= i-1;
+ ix0 |= (ix1>>(32-i));
+ ix1 <<= i;
+ }
+ m -= 1023; /* unbias exponent */
+ ix0 = (ix0&0x000fffff)|0x00100000;
+ if(m&1){ /* odd m, double x to make it even */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ }
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
+ r = 0x00200000; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s0+r;
+ if(t<=ix0) {
+ s0 = t+r;
+ ix0 -= t;
+ q += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ r = sign;
+ while(r!=0) {
+ t1 = s1+r;
+ t = s0;
+ if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
+ s1 = t1+r;
+ if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+ ix0 -= t;
+ if (ix1 < t1) ix0 -= 1;
+ ix1 -= t1;
+ q1 += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if((ix0|ix1)!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}
+ else if (z>one) {
+ if (q1==(unsigned)0xfffffffe) q+=1;
+ q1+=2;
+ } else
+ q1 += (q1&1);
+ }
+ }
+ ix0 = (q>>1)+0x3fe00000;
+ ix1 = q1>>1;
+ if ((q&1)==1) ix1 |= sign;
+ ix0 += (m <<20);
+ __HI(z) = ix0;
+ __LO(z) = ix1;
+ return z;
+}
+
+/*
+Other methods (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan
+and K.C. Ng, written in May, 1986)
+
+ Two algorithms are given here to implement sqrt(x)
+ (IEEE double precision arithmetic) in software.
+ Both supply sqrt(x) correctly rounded. The first algorithm (in
+ Section A) uses newton iterations and involves four divisions.
+ The second one uses reciproot iterations to avoid division, but
+ requires more multiplications. Both algorithms need the ability
+ to chop results of arithmetic operations instead of round them,
+ and the INEXACT flag to indicate when an arithmetic operation
+ is executed exactly with no roundoff error, all part of the
+ standard (IEEE 754-1985). The ability to perform shift, add,
+ subtract and logical AND operations upon 32-bit words is needed
+ too, though not part of the standard.
+
+A. sqrt(x) by Newton Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+
+ 1 11 52 ...widths
+ ------------------------------------------------------
+ x: |s| e | f |
+ ------------------------------------------------------
+ msb lsb msb lsb ...order
+
+
+ ------------------------ ------------------------
+ x0: |s| e | f1 | x1: | f2 |
+ ------------------------ ------------------------
+
+ By performing shifts and subtracts on x0 and x1 (both regarded
+ as integers), we obtain an 8-bit approximation of sqrt(x) as
+ follows.
+
+ k := (x0>>1) + 0x1ff80000;
+ y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits
+ Here k is a 32-bit integer and T1[] is an integer array containing
+ correction terms. Now magically the floating value of y (y's
+ leading 32-bit word is y0, the value of its trailing word is 0)
+ approximates sqrt(x) to almost 8-bit.
+
+ Value of T1:
+ static int T1[32]= {
+ 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592,
+ 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215,
+ 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581,
+ 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,};
+
+ (2) Iterative refinement
+
+ Apply Heron's rule three times to y, we have y approximates
+ sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+ y := (y+x/y)/2 ... almost 17 sig. bits
+ y := (y+x/y)/2 ... almost 35 sig. bits
+ y := y-(y-x/y)/2 ... within 1 ulp
+
+
+ Remark 1.
+ Another way to improve y to within 1 ulp is:
+
+ y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x)
+ y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x)
+
+ 2
+ (x-y )*y
+ y := y + 2* ---------- ...within 1 ulp
+ 2
+ 3y + x
+
+
+ This formula has one division fewer than the one above; however,
+ it requires more multiplications and additions. Also x must be
+ scaled in advance to avoid spurious overflow in evaluating the
+ expression 3y*y+x. Hence it is not recommended uless division
+ is slow. If division is very slow, then one should use the
+ reciproot algorithm given in section B.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ I := FALSE; ... reset INEXACT flag I
+ R := RZ; ... set rounding mode to round-toward-zero
+ z := x/y; ... chopped quotient, possibly inexact
+ If(not I) then { ... if the quotient is exact
+ if(z=y) {
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+ } else {
+ z := z - ulp; ... special rounding
+ }
+ }
+ i := TRUE; ... sqrt(x) is inexact
+ If (r=RN) then z=z+ulp ... rounded-to-nearest
+ If (r=RP) then { ... round-toward-+inf
+ y = y+ulp; z=z+ulp;
+ }
+ y := y+z; ... chopped sum
+ y0:=y0-0x00100000; ... y := y/2 is correctly rounded.
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+
+ (4) Special cases
+
+ Square root of +inf, +-0, or NaN is itself;
+ Square root of a negative number is NaN with invalid signal.
+
+
+B. sqrt(x) by Reciproot Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+ (see section A). By performing shifs and subtracts on x0 and y0,
+ we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+ k := 0x5fe80000 - (x0>>1);
+ y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits
+
+ Here k is a 32-bit integer and T2[] is an integer array
+ containing correction terms. Now magically the floating
+ value of y (y's leading 32-bit word is y0, the value of
+ its trailing word y1 is set to zero) approximates 1/sqrt(x)
+ to almost 7.8-bit.
+
+ Value of T2:
+ static int T2[64]= {
+ 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+ 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+ 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+ 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+ 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+ 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+ 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+ 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+ (2) Iterative refinement
+
+ Apply Reciproot iteration three times to y and multiply the
+ result by x to get an approximation z that matches sqrt(x)
+ to about 1 ulp. To be exact, we will have
+ -1ulp < sqrt(x)-z<1.0625ulp.
+
+ ... set rounding mode to Round-to-nearest
+ y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x)
+ y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+ ... special arrangement for better accuracy
+ z := x*y ... 29 bits to sqrt(x), with z*y<1
+ z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x)
+
+ Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+ (a) the term z*y in the final iteration is always less than 1;
+ (b) the error in the final result is biased upward so that
+ -1 ulp < sqrt(x) - z < 1.0625 ulp
+ instead of |sqrt(x)-z|<1.03125ulp.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ R := RZ; ... set rounding mode to round-toward-zero
+ switch(r) {
+ case RN: ... round-to-nearest
+ if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+ if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+ break;
+ case RZ:case RM: ... round-to-zero or round-to--inf
+ R:=RP; ... reset rounding mod to round-to-+inf
+ if(x<z*z ... rounded up) z = z - ulp; else
+ if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+ break;
+ case RP: ... round-to-+inf
+ if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+ if(x>z*z ...chopped) z = z+ulp;
+ break;
+ }
+
+ Remark 3. The above comparisons can be done in fixed point. For
+ example, to compare x and w=z*z chopped, it suffices to compare
+ x1 and w1 (the trailing parts of x and w), regarding them as
+ two's complement integers.
+
+ ...Is z an exact square root?
+ To determine whether z is an exact square root of x, let z1 be the
+ trailing part of z, and also let x0 and x1 be the leading and
+ trailing parts of x.
+
+ If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+ I := 1; ... Raise Inexact flag: z is not exact
+ else {
+ j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2
+ k := z1 >> 26; ... get z's 25-th and 26-th
+ fraction bits
+ I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+ }
+ R:= r ... restore rounded mode
+ return sqrt(x):=z.
+
+ If multiplication is cheaper then the foregoing red tape, the
+ Inexact flag can be evaluated by
+
+ I := i;
+ I := (z*z!=x) or I.
+
+ Note that z*z can overwrite I; this value must be sensed if it is
+ True.
+
+ Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+ zero.
+
+ --------------------
+ z1: | f2 |
+ --------------------
+ bit 31 bit 0
+
+ Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+ or even of logb(x) have the following relations:
+
+ -------------------------------------------------
+ bit 27,26 of z1 bit 1,0 of x1 logb(x)
+ -------------------------------------------------
+ 00 00 odd and even
+ 01 01 even
+ 10 10 odd
+ 10 00 even
+ 11 01 even
+ -------------------------------------------------
+
+ (4) Special cases (see (4) of Section A).
+
+ */
+
diff --git a/libm/float_wrapper.c b/libm/float_wrapper.c
new file mode 100644
index 0000000..bd078b6
--- /dev/null
+++ b/libm/float_wrapper.c
@@ -0,0 +1,90 @@
+#include <math.h>
+
+float acosf(float x){ return acos(x); }
+float acoshf(float x){ return acosh(x); }
+
+float asinf(float x){ return asin(x); }
+float asinhf(float x){ return asinf(x); }
+
+float atanf(float x){ return atan(x); }
+float atanhf(float x){ return atanh(x); }
+
+float atan2f(float x){ return atan2(x); }
+
+float cbrtf(float x){ return cbrt(x); }
+
+float ceilf(float x){ return ceil(x); }
+
+float copysignf(float x, float y) { return copysign(x, y); }
+
+double copysignl(long double x, long double y){ return copysign(x, y); }
+
+float cosf(float x){ return cos(x); }
+float coshf(float x){ return cosh(x); }
+
+float erff(float x){ return erf(x); }
+float erfcf(float x){ return erfc(x); }
+
+float expf(float x){ return exp(x); }
+float exp2f(float x){ return exp2(x); }
+float expm1f(float x){ return expm1(x); }
+
+float fabsf(float x){ return fabs(x); }
+
+float finitef(float x){ return finite(x); }
+
+float floorf(float x){ return floor(x); }
+
+float fmodf(float x, float y){ return fmod(x, y); }
+
+float hypotf(float x, float y){ return hypot(x, y); }
+
+int ilogbf(float x){ return ilogb(x); }
+int ilogbl(long double x){ return iolgb(x); }
+
+float j0f(float x){ return j0(x); }
+float j1f(float x){ return j1(x); }
+float jnf(int n, float x){ return jn(n,x); }
+
+float y0f(float x){ return y0(x); }
+float y1f(float x){ return y1(x); }
+float ynf(float x){ return yn(x); }
+
+float lgammaf(float x){ return lgamma(x); }
+float gammaf(float x){ return gamma(x); }
+float tgammaf(float x){ return tgamma(x); }
+
+float lgammaf_r(float x, int *sign){ return lgamma_r(x, sign); }
+float gammaf_r(float x, int *sign){ return gamma_r(x, sign); }
+
+float logf(float x){ return log(x); }
+float log10f(float x) { return log10(x); }
+float log1pf(float x) { return log1p(x); }
+float log2f(float x) { return log2(x); }
+
+float nanf(const char *tagp) { return nan(tagp); }
+long double nanl(const char *tagp) { return nan(tagp); }
+
+float nextafterf(float x, float y) { return nextafter(x, y); }
+long double nextafterl(long double x, long double y)
+{ return nextafter(x, y); }
+
+float powf(float x, float y) { return pow(x, y); }
+
+float remainderf(float x, float y) { return remainder(x, y); }
+float remquof(float x, float y, int *quo) { return remquo(x, y, quo); }
+
+float rintf(float x){ return rint(x); }
+
+float scalbnf(float x, int n){ return scalbn(x, n); }
+long double scalbnl(long double x, int n){ return scalbn(x, n); }
+
+float sinf(float x){ return sin(x); }
+float sinhf(float x){ return sinh(x); }
+
+float sqrtf(float x){ return sqrt(x); }
+
+float tanf(float x){ return tan(x); }
+float tanhf(float x){ return tanh(x); }
+
+float truncf(float x){ return trunc(x); }
diff --git a/libm/k_cos.c b/libm/k_cos.c
new file mode 100644
index 0000000..2210221
--- /dev/null
+++ b/libm/k_cos.c
@@ -0,0 +1,92 @@
+
+/* @(#)k_cos.c 1.4 96/03/07 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_cos( x, y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ *
+ * Algorithm
+ * 1. Since cos(-x) = cos(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ * 3. cos(x) is approximated by a polynomial of degree 14 on
+ * [0,pi/4]
+ * 4 14
+ * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ * where the Remes error is
+ *
+ * | 2 4 6 8 10 12 14 | -58
+ * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
+ * | |
+ *
+ * 4 6 8 10 12 14
+ * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
+ * cos(x) = 1 - x*x/2 + r
+ * since cos(x+y) ~ cos(x) - sin(x)*y
+ * ~ cos(x) - x*y,
+ * a correction term is necessary in cos(x) and hence
+ * cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ * For better accuracy when x > 0.3, let qx = |x|/4 with
+ * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ * Then
+ * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ * Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ * magnitude of the latter is at least a quarter of x*x/2,
+ * thus, reducing the rounding error in the subtraction.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+#ifdef __STDC__
+ double __kernel_cos(double x, double y)
+#else
+ double __kernel_cos(x, y)
+ double x,y;
+#endif
+{
+ double a,hz,z,r,qx;
+ int ix;
+ ix = __HI(x)&0x7fffffff; /* ix = |x|'s high word*/
+ if(ix<0x3e400000) { /* if x < 2**27 */
+ if(((int)x)==0) return one; /* generate inexact */
+ }
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ if(ix < 0x3FD33333) /* if |x| < 0.3 */
+ return one - (0.5*z - (z*r - x*y));
+ else {
+ if(ix > 0x3fe90000) { /* x > 0.78125 */
+ qx = 0.28125;
+ } else {
+ __HI(qx) = ix-0x00200000; /* x/4 */
+ __LO(qx) = 0;
+ }
+ hz = 0.5*z-qx;
+ a = one-qx;
+ return a - (hz - (z*r-x*y));
+ }
+}
diff --git a/libm/k_rem_pio2.c b/libm/k_rem_pio2.c
new file mode 100644
index 0000000..8921a7f
--- /dev/null
+++ b/libm/k_rem_pio2.c
@@ -0,0 +1,319 @@
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ *
+ * __kernel_rem_pio2 return the last three digits of N with
+ * y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ * x[] The input value (must be positive) is broken into nx
+ * pieces of 24-bit integers in double precision format.
+ * x[i] will be the i-th 24 bit of x. The scaled exponent
+ * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
+ * match x's up to 24 bits.
+ *
+ * Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ * e0 = ilogb(z)-23
+ * z = scalbn(z,-e0)
+ * for i = 0,1,2
+ * x[i] = floor(z)
+ * z = (z-x[i])*2**24
+ *
+ *
+ * y[] ouput result in an array of double precision numbers.
+ * The dimension of y[] is:
+ * 24-bit precision 1
+ * 53-bit precision 2
+ * 64-bit precision 2
+ * 113-bit precision 3
+ * The actual value is the sum of them. Thus for 113-bit
+ * precison, one may have to do something like:
+ *
+ * long double t,w,r_head, r_tail;
+ * t = (long double)y[2] + (long double)y[1];
+ * w = (long double)y[0];
+ * r_head = t+w;
+ * r_tail = w - (r_head - t);
+ *
+ * e0 The exponent of x[0]
+ *
+ * nx dimension of x[]
+ *
+ * prec an integer indicating the precision:
+ * 0 24 bits (single)
+ * 1 53 bits (double)
+ * 2 64 bits (extended)
+ * 3 113 bits (quad)
+ *
+ * ipio2[]
+ * integer array, contains the (24*i)-th to (24*i+23)-th
+ * bit of 2/pi after binary point. The corresponding
+ * floating value is
+ *
+ * ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ * double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ * jk jk+1 is the initial number of terms of ipio2[] needed
+ * in the computation. The recommended value is 2,3,4,
+ * 6 for single, double, extended,and quad.
+ *
+ * jz local integer variable indicating the number of
+ * terms of ipio2[] used.
+ *
+ * jx nx - 1
+ *
+ * jv index for pointing to the suitable ipio2[] for the
+ * computation. In general, we want
+ * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ * is an integer. Thus
+ * e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ * Hence jv = max(0,(e0-3)/24).
+ *
+ * jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ * q[] double array with integral value, representing the
+ * 24-bits chunk of the product of x and 2/pi.
+ *
+ * q0 the corresponding exponent of q[0]. Note that the
+ * exponent for q[i] would be q0-24*i.
+ *
+ * PIo2[] double precision array, obtained by cutting pi/2
+ * into 24 bits chunks.
+ *
+ * f[] ipio2[] in floating point
+ *
+ * iq[] integer array by breaking up q[] in 24-bits chunk.
+ *
+ * fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ * ih integer. If >0 it indicates q[] is >= 0.5, hence
+ * it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+#else
+static int init_jk[] = {2,3,4,6};
+#endif
+
+#ifdef __STDC__
+static const double PIo2[] = {
+#else
+static double PIo2[] = {
+#endif
+ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+ 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+ 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+ 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+zero = 0.0,
+one = 1.0,
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+#ifdef __STDC__
+ int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2)
+#else
+ int __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ double x[], y[]; int e0,nx,prec; int ipio2[];
+#endif
+{
+ int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ double z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/24; if(jv<0) jv=0;
+ q0 = e0-24*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++)
+ fw += x[j]*f[jx+i-j];
+
+ q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (double)((int)(twon24* z));
+ iq[i] = (int)(z-two24*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbn(z,q0); /* actual value of z */
+ z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
+ n = (int) z;
+ z -= (double)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(24-q0)); n += i;
+ iq[jz-1] -= i<<(24-q0);
+ ih = iq[jz-1]>>(23-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>23;
+ else if(z>=0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x1000000- j;
+ }
+ } else iq[i] = 0xffffff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7fffff; break;
+ case 2:
+ iq[jz-1] &= 0x3fffff; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbn(one,q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (double) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==0.0) {
+ jz -= 1; q0 -= 24;
+ while(iq[jz]==0) { jz--; q0-=24;}
+ } else { /* break z into 24-bit if necessary */
+ z = scalbn(z,-q0);
+ if(z>=two24) {
+ fw = (double)((int)(twon24*z));
+ iq[jz] = (int)(z-two24*fw);
+ jz += 1; q0 += 24;
+ iq[jz] = (int) fw;
+ } else iq[jz] = (int) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbn(one,q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(double)iq[i]; fw*=twon24;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
diff --git a/libm/k_sin.c b/libm/k_sin.c
new file mode 100644
index 0000000..5593941
--- /dev/null
+++ b/libm/k_sin.c
@@ -0,0 +1,74 @@
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
+ *
+ * Algorithm
+ * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ * 3. sin(x) is approximated by a polynomial of degree 13 on
+ * [0,pi/4]
+ * 3 13
+ * sin(x) ~ x + S1*x + ... + S6*x
+ * where
+ *
+ * |sin(x) 2 4 6 8 10 12 | -58
+ * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
+ * | x |
+ *
+ * 4. sin(x+y) = sin(x) + sin'(x')*y
+ * ~ sin(x) + (1-x*x/2)*y
+ * For better accuracy, let
+ * 3 2 2 2 2
+ * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ * then 3 2
+ * sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+#ifdef __STDC__
+ double __kernel_sin(double x, double y, int iy)
+#else
+ double __kernel_sin(x, y, iy)
+ double x,y; int iy; /* iy=0 if y is zero */
+#endif
+{
+ double z,r,v;
+ int ix;
+ ix = __HI(x)&0x7fffffff; /* high word of x */
+ if(ix<0x3e400000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/libm/k_standard.c b/libm/k_standard.c
new file mode 100644
index 0000000..0b544e8
--- /dev/null
+++ b/libm/k_standard.c
@@ -0,0 +1,740 @@
+
+/* @(#)k_standard.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "math.h"
+#include <errno.h>
+
+//#ifndef _USE_WRITE
+//#include <stdio.h> /* fputs(), stderr */
+//#define WRITE2(u,v) fputs(u, stderr)
+//#else /* !defined(_USE_WRITE) */
+//#include <unistd.h> /* write */
+//#define WRITE2(u,v) write(2, u, v)
+//#undef fflush
+//#endif /* !defined(_USE_WRITE) */
+
+//#define WRITE2(u,v) ;
+
+int WRITE2(char *a, int b)
+{
+ return 0;
+}
+
+static double zero = 0.0; /* used as const */
+
+/*
+ * Standard conformance (non-IEEE) on exception cases.
+ * Mapping:
+ * 1 -- acos(|x|>1)
+ * 2 -- asin(|x|>1)
+ * 3 -- atan2(+-0,+-0)
+ * 4 -- hypot overflow
+ * 5 -- cosh overflow
+ * 6 -- exp overflow
+ * 7 -- exp underflow
+ * 8 -- y0(0)
+ * 9 -- y0(-ve)
+ * 10-- y1(0)
+ * 11-- y1(-ve)
+ * 12-- yn(0)
+ * 13-- yn(-ve)
+ * 14-- lgamma(finite) overflow
+ * 15-- lgamma(-integer)
+ * 16-- log(0)
+ * 17-- log(x<0)
+ * 18-- log10(0)
+ * 19-- log10(x<0)
+ * 20-- pow(0.0,0.0)
+ * 21-- pow(x,y) overflow
+ * 22-- pow(x,y) underflow
+ * 23-- pow(0,negative)
+ * 24-- pow(neg,non-integral)
+ * 25-- sinh(finite) overflow
+ * 26-- sqrt(negative)
+ * 27-- fmod(x,0)
+ * 28-- remainder(x,0)
+ * 29-- acosh(x<1)
+ * 30-- atanh(|x|>1)
+ * 31-- atanh(|x|=1)
+ * 32-- scalb overflow
+ * 33-- scalb underflow
+ * 34-- j0(|x|>X_TLOSS)
+ * 35-- y0(x>X_TLOSS)
+ * 36-- j1(|x|>X_TLOSS)
+ * 37-- y1(x>X_TLOSS)
+ * 38-- jn(|x|>X_TLOSS, n)
+ * 39-- yn(x>X_TLOSS, n)
+ * 40-- gamma(finite) overflow
+ * 41-- gamma(-integer)
+ * 42-- pow(NaN,0.0)
+ */
+
+
+#ifdef __STDC__
+ double __kernel_standard(double x, double y, int type)
+#else
+ double __kernel_standard(x,y,type)
+ double x,y; int type;
+#endif
+{
+ struct exception exc;
+#ifndef HUGE_VAL /* this is the only routine that uses HUGE_VAL */
+#define HUGE_VAL inf
+ double inf = 0.0;
+
+ __HI(inf) = 0x7ff00000; /* set inf to infinite */
+#endif
+
+#ifdef _USE_WRITE
+ (void) fflush(stdout);
+#endif
+ exc.arg1 = x;
+ exc.arg2 = y;
+ switch(type) {
+ case 1:
+ /* acos(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "acos";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("acos: DOMAIN error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 2:
+ /* asin(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "asin";
+ exc.retval = zero;
+ if(_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("asin: DOMAIN error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 3:
+ /* atan2(+-0,+-0) */
+ exc.arg1 = y;
+ exc.arg2 = x;
+ exc.type = DOMAIN;
+ exc.name = "atan2";
+ exc.retval = zero;
+ if(_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if(_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atan2: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 4:
+ /* hypot(finite,finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "hypot";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 5:
+ /* cosh(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "cosh";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 6:
+ /* exp(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "exp";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 7:
+ /* exp(finite) underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "exp";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 8:
+ /* y0(0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "y0";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y0: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 9:
+ /* y0(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "y0";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y0: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 10:
+ /* y1(0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "y1";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y1: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 11:
+ /* y1(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "y1";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("y1: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 12:
+ /* yn(n,0) = -inf */
+ exc.type = DOMAIN; /* should be SING for IEEE */
+ exc.name = "yn";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("yn: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 13:
+ /* yn(x<0) = NaN */
+ exc.type = DOMAIN;
+ exc.name = "yn";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("yn: DOMAIN error\n", 17);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 14:
+ /* lgamma(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "lgamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 15:
+ /* lgamma(-integer) or lgamma(0) */
+ exc.type = SING;
+ exc.name = "lgamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("lgamma: SING error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 16:
+ /* log(0) */
+ exc.type = SING;
+ exc.name = "log";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log: SING error\n", 16);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 17:
+ /* log(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "log";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log: DOMAIN error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 18:
+ /* log10(0) */
+ exc.type = SING;
+ exc.name = "log10";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log10: SING error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 19:
+ /* log10(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "log10";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = -HUGE;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("log10: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 20:
+ /* pow(0.0,0.0) */
+ /* error only if _LIB_VERSION == _SVID_ */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ exc.retval = zero;
+ if (_LIB_VERSION != _SVID_) exc.retval = 1.0;
+ else if (!matherr(&exc)) {
+ (void) WRITE2("pow(0,0): DOMAIN error\n", 23);
+ errno = EDOM;
+ }
+ break;
+ case 21:
+ /* pow(x,y) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_) {
+ exc.retval = HUGE;
+ y *= 0.5;
+ if(x<zero&&rint(y)!=y) exc.retval = -HUGE;
+ } else {
+ exc.retval = HUGE_VAL;
+ y *= 0.5;
+ if(x<zero&&rint(y)!=y) exc.retval = -HUGE_VAL;
+ }
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 22:
+ /* pow(x,y) underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "pow";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 23:
+ /* 0**neg */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("pow(0,neg): DOMAIN error\n", 25);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 24:
+ /* neg**non-integral */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = zero/zero; /* X/Open allow NaN */
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("neg**non-integral: DOMAIN error\n", 32);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 25:
+ /* sinh(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "sinh";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = ( (x>zero) ? HUGE : -HUGE);
+ else
+ exc.retval = ( (x>zero) ? HUGE_VAL : -HUGE_VAL);
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 26:
+ /* sqrt(x<0) */
+ exc.type = DOMAIN;
+ exc.name = "sqrt";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = zero;
+ else
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("sqrt: DOMAIN error\n", 19);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 27:
+ /* fmod(x,0) */
+ exc.type = DOMAIN;
+ exc.name = "fmod";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = x;
+ else
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("fmod: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 28:
+ /* remainder(x,0) */
+ exc.type = DOMAIN;
+ exc.name = "remainder";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("remainder: DOMAIN error\n", 24);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 29:
+ /* acosh(x<1) */
+ exc.type = DOMAIN;
+ exc.name = "acosh";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("acosh: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 30:
+ /* atanh(|x|>1) */
+ exc.type = DOMAIN;
+ exc.name = "atanh";
+ exc.retval = zero/zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atanh: DOMAIN error\n", 20);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 31:
+ /* atanh(|x|=1) */
+ exc.type = SING;
+ exc.name = "atanh";
+ exc.retval = x/zero; /* sign(x)*inf */
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("atanh: SING error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 32:
+ /* scalb overflow; SVID also returns +-HUGE_VAL */
+ exc.type = OVERFLOW;
+ exc.name = "scalb";
+ exc.retval = x > zero ? HUGE_VAL : -HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 33:
+ /* scalb underflow */
+ exc.type = UNDERFLOW;
+ exc.name = "scalb";
+ exc.retval = copysign(zero,x);
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 34:
+ /* j0(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "j0";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 35:
+ /* y0(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "y0";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 36:
+ /* j1(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "j1";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 37:
+ /* y1(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "y1";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 38:
+ /* jn(|x|>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "jn";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 39:
+ /* yn(x>X_TLOSS) */
+ exc.type = TLOSS;
+ exc.name = "yn";
+ exc.retval = zero;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2(exc.name, 2);
+ (void) WRITE2(": TLOSS error\n", 14);
+ }
+ errno = ERANGE;
+ }
+ break;
+ case 40:
+ /* gamma(finite) overflow */
+ exc.type = OVERFLOW;
+ exc.name = "gamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = ERANGE;
+ else if (!matherr(&exc)) {
+ errno = ERANGE;
+ }
+ break;
+ case 41:
+ /* gamma(-integer) or gamma(0) */
+ exc.type = SING;
+ exc.name = "gamma";
+ if (_LIB_VERSION == _SVID_)
+ exc.retval = HUGE;
+ else
+ exc.retval = HUGE_VAL;
+ if (_LIB_VERSION == _POSIX_)
+ errno = EDOM;
+ else if (!matherr(&exc)) {
+ if (_LIB_VERSION == _SVID_) {
+ (void) WRITE2("gamma: SING error\n", 18);
+ }
+ errno = EDOM;
+ }
+ break;
+ case 42:
+ /* pow(NaN,0.0) */
+ /* error only if _LIB_VERSION == _SVID_ & _XOPEN_ */
+ exc.type = DOMAIN;
+ exc.name = "pow";
+ exc.retval = x;
+ if (_LIB_VERSION == _IEEE_ ||
+ _LIB_VERSION == _POSIX_) exc.retval = 1.0;
+ else if (!matherr(&exc)) {
+ errno = EDOM;
+ }
+ break;
+ }
+ return exc.retval;
+}
diff --git a/libm/k_tan.c b/libm/k_tan.c
new file mode 100644
index 0000000..b58f8f9
--- /dev/null
+++ b/libm/k_tan.c
@@ -0,0 +1,148 @@
+//#pragma ident "@(#)k_tan.c 1.5 04/04/22 SMI"
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* INDENT OFF */
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned.
+ *
+ * Algorithm
+ * 1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ * 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ * 3. tan(x) is approximated by a odd polynomial of degree 27 on
+ * [0,0.67434]
+ * 3 27
+ * tan(x) ~ x + T1*x + ... + T13*x
+ * where
+ *
+ * |tan(x) 2 4 26 | -59.2
+ * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
+ * | x |
+ *
+ * Note: tan(x+y) = tan(x) + tan'(x)*y
+ * ~ tan(x) + (1+x*x)*y
+ * Therefore, for better accuracy in computing tan(x+y), let
+ * 3 2 2 2 2
+ * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ * then
+ * 3 2
+ * tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
+ * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include "math.h"
+
+static const double xxx[] = {
+ 3.33333333333334091986e-01, /* 3FD55555, 55555563 */
+ 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */
+ 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */
+ 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */
+ 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */
+ 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */
+ 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */
+ 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */
+ 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */
+ 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */
+ 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */
+ -1.85586374855275456654e-05, /* BEF375CB, DB605373 */
+ 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */
+/* one */ 1.00000000000000000000e+00, /* 3FF00000, 00000000 */
+/* pio4 */ 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */
+/* pio4lo */ 3.06161699786838301793e-17 /* 3C81A626, 33145C07 */
+};
+#define one xxx[13]
+#define pio4 xxx[14]
+#define pio4lo xxx[15]
+#define T xxx
+/* INDENT ON */
+
+double
+__kernel_tan(double x, double y, int iy) {
+ double z, r, v, w, s;
+ int ix, hx;
+
+ hx = __HI(x); /* high word of x */
+ ix = hx & 0x7fffffff; /* high word of |x| */
+ if (ix < 0x3e300000) { /* x < 2**-28 */
+ if ((int) x == 0) { /* generate inexact */
+ if (((ix | __LO(x)) | (iy + 1)) == 0)
+ return one / fabs(x);
+ else {
+ if (iy == 1)
+ return x;
+ else { /* compute -1 / (x+y) carefully */
+ double a, t;
+
+ z = w = x + y;
+ __LO(z) = 0;
+ v = y - (z - x);
+ t = a = -one / w;
+ __LO(t) = 0;
+ s = one + t * z;
+ return t + a * (s + t * v);
+ }
+ }
+ }
+ }
+ if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */
+ if (hx < 0) {
+ x = -x;
+ y = -y;
+ }
+ z = pio4 - x;
+ w = pio4lo - y;
+ x = z + w;
+ y = 0.0;
+ }
+ z = x * x;
+ w = z * z;
+ /*
+ * Break x^5*(T[1]+x^2*T[2]+...) into
+ * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+ * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+ */
+ r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] +
+ w * T[11]))));
+ v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] +
+ w * T[12])))));
+ s = z * x;
+ r = y + z * (s * (r + v) + y);
+ r += T[0] * s;
+ w = x + r;
+ if (ix >= 0x3FE59428) {
+ v = (double) iy;
+ return (double) (1 - ((hx >> 30) & 2)) *
+ (v - 2.0 * (x - (w * w / (w + v) - r)));
+ }
+ if (iy == 1)
+ return w;
+ else {
+ /*
+ * if allow error up to 2 ulp, simply return
+ * -1.0 / (x+r) here
+ */
+ /* compute -1.0 / (x+r) accurately */
+ double a, t;
+ z = w;
+ __LO(z) = 0;
+ v = r - (z - x); /* z+v = r+x */
+ t = a = -1.0 / w; /* a = -1.0/w */
+ __LO(t) = 0;
+ s = 1.0 + t * z;
+ return t + a * (s + t * v);
+ }
+}
diff --git a/libm/math.h b/libm/math.h
new file mode 100644
index 0000000..5513c87
--- /dev/null
+++ b/libm/math.h
@@ -0,0 +1,319 @@
+/*
+ * math.h
+ *
+ * PSXSDK
+ * modified and stripped down from fdlibm
+ */
+
+#ifndef _MATH_H
+#define _MATH_H
+
+/* @(#)math.h 1.5 2010/06/16 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+#define __HIp(x) *(1+(int*)x)
+#define __LOp(x) *(int*)x
+
+#ifdef __STDC__
+#define __P(p) p
+#else
+#define __P(p) ()
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+
+extern int signgam;
+
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+
+enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix};
+
+#define _LIB_VERSION_TYPE enum fdversion
+#define _LIB_VERSION _fdlib_version
+
+/* if global variable _LIB_VERSION is not desirable, one may
+ * change the following to be a constant by:
+ * #define _LIB_VERSION_TYPE const enum version
+ * In that case, after one initializes the value _LIB_VERSION (see
+ * s_lib_version.c) during compile time, it cannot be modified
+ * in the middle of a program
+ */
+extern _LIB_VERSION_TYPE _LIB_VERSION;
+
+#define _IEEE_ fdlibm_ieee
+#define _SVID_ fdlibm_svid
+#define _XOPEN_ fdlibm_xopen
+#define _POSIX_ fdlibm_posix
+
+struct exception {
+ int type;
+ char *name;
+ double arg1;
+ double arg2;
+ double retval;
+};
+
+#define HUGE MAXFLOAT
+
+/*
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS 1.41484755040568800000e+16
+
+#define DOMAIN 1
+#define SING 2
+#define OVERFLOW 3
+#define UNDERFLOW 4
+#define TLOSS 5
+#define PLOSS 6
+
+/*
+ * ANSI/POSIX
+ */
+extern double acos __P((double));
+extern double asin __P((double));
+extern double atan __P((double));
+extern double atan2 __P((double, double));
+extern double cos __P((double));
+extern double sin __P((double));
+extern double tan __P((double));
+
+extern double cosh __P((double));
+extern double sinh __P((double));
+extern double tanh __P((double));
+
+extern double exp __P((double));
+extern double frexp __P((double, int *));
+extern double ldexp __P((double, int));
+extern double log __P((double));
+extern double log10 __P((double));
+extern double modf __P((double, double *));
+
+extern double pow __P((double, double));
+extern double sqrt __P((double));
+
+extern double ceil __P((double));
+extern double fabs __P((double));
+extern double floor __P((double));
+extern double fmod __P((double, double));
+
+extern double erf __P((double));
+extern double erfc __P((double));
+extern double gamma __P((double));
+extern double hypot __P((double, double));
+extern int isnan __P((double));
+extern int finite __P((double));
+extern double j0 __P((double));
+extern double j1 __P((double));
+extern double jn __P((int, double));
+extern double lgamma __P((double));
+extern double y0 __P((double));
+extern double y1 __P((double));
+extern double yn __P((int, double));
+
+extern double acosh __P((double));
+extern double asinh __P((double));
+extern double atanh __P((double));
+extern double cbrt __P((double));
+extern double logb __P((double));
+extern double nextafter __P((double, double));
+extern double remainder __P((double, double));
+#ifdef _SCALB_INT
+extern double scalb __P((double, int));
+#else
+extern double scalb __P((double, double));
+#endif
+
+extern int matherr __P((struct exception *));
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand __P((double));
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double copysign __P((double, double));
+extern int ilogb __P((double));
+extern double rint __P((double));
+extern double scalbn __P((double, int));
+
+/*
+ * BSD math library entry points
+ */
+extern double expm1 __P((double));
+extern double log1p __P((double));
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r __P((double, int *));
+extern double lgamma_r __P((double, int *));
+#endif /* _REENTRANT */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));
+extern double __ieee754_acos __P((double));
+extern double __ieee754_acosh __P((double));
+extern double __ieee754_log __P((double));
+extern double __ieee754_atanh __P((double));
+extern double __ieee754_asin __P((double));
+extern double __ieee754_atan2 __P((double,double));
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_lgamma __P((double));
+extern double __ieee754_gamma __P((double));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern int __ieee754_rem_pio2 __P((double,double*));
+#ifdef _SCALB_INT
+extern double __ieee754_scalb __P((double,int));
+#else
+extern double __ieee754_scalb __P((double,double));
+#endif
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int __kernel_rem_pio2 __P((double*,double*,int,int,int,const int*));
+
+/* the defines below are from NetBSD's math.h - which is based on fdlibm as well */
+
+#define M_E 2.7182818284590452354 /* e */
+#define M_LOG2E 1.4426950408889634074 /* log 2e */
+#define M_LOG10E 0.43429448190325182765 /* log 10e */
+#define M_LN2 0.69314718055994530942 /* log e2 */
+#define M_LN10 2.30258509299404568402 /* log e10 */
+#define M_PI 3.14159265358979323846 /* pi */
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#define M_PI_4 0.78539816339744830962 /* pi/4 */
+#define M_1_PI 0.31830988618379067154 /* 1/pi */
+#define M_2_PI 0.63661977236758134308 /* 2/pi */
+#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+
+// definitions for wrappers
+
+float acosf(float x);; // acos(x); }
+float acoshf(float x); // acosh(x); }
+
+float asinf(float x); // asin(x); }
+float asinhf(float x); // asinf(x); }
+
+float atanf(float x); // atan(x); }
+float atanhf(float x); // atanh(x); }
+
+float atan2f(float x, float y); // atan2(x,y); }
+
+float cbrtf(float x); // cbrt(x); }
+
+float ceilf(float x); // ceil(x); }
+
+float copysignf(float x, float y) ; // copysign(x, y); }
+
+double copysignl(long double x, long double y); // copysign(x, y); }
+
+float cosf(float x); // cos(x); }
+float coshf(float x); // cosh(x); }
+
+float erff(float x); // erf(x); }
+float erfcf(float x); // erfc(x); }
+
+float expf(float x); // exp(x); }
+//float exp2f(float x); // exp2(x); }
+float expm1f(float x); // expm1(x); }
+
+float fabsf(float x); // fabs(x); }
+
+float finitef(float x); // finite(x); }
+
+float floorf(float x); // floor(x); }
+
+float fmodf(float x, float y); // fmod(x, y); }
+
+float hypotf(float x, float y); // hypot(x, y); }
+
+int ilogbf(float x); // ilogb(x); }
+int ilogbl(long double x); // ilogb(x); }
+
+float j0f(float x); // j0(x); }
+float j1f(float x); // j1(x); }
+float jnf(int n, float x); // jn(n,x); }
+
+float y0f(float x); // y0(x); }
+float y1f(float x); // y1(x); }
+float ynf(int n, float x); // yn(n, x); }
+
+float lgammaf(float x); // lgamma(x); }
+float gammaf(float x); // gamma(x); }
+//float tgammaf(float x); // tgamma(x); }
+
+float lgammaf_r(float x, int *sign); // lgamma_r(x, sign); }
+float gammaf_r(float x, int *sign); // gamma_r(x, sign); }
+
+float logf(float x); // log(x); }
+float log10f(float x) ; // log10(x); }
+float log1pf(float x) ; // log1p(x); }
+//float log2f(float x) ; // log2(x); }
+
+//float nanf(const char *tagp) ; // nan(tagp); }
+//long double nanl(const char *tagp) ; // nan(tagp); }
+
+float nextafterf(float x, float y) ; // nextafter(x, y); }
+long double nextafterl(long double x, long double y)
+; // nextafter(x, y); }
+
+float powf(float x, float y) ; // pow(x, y); }
+
+float remainderf(float x, float y) ; // remainder(x, y); }
+//float remquof(float x, float y, int *quo) ; // remquo(x, y, quo); }
+
+float rintf(float x); // rint(x); }
+
+float scalbnf(float x, int n); // scalbn(x, n); }
+long double scalbnl(long double x, int n); // scalbn(x, n); }
+
+float sinf(float x); // sin(x); }
+float sinhf(float x); // sinh(x); }
+
+float sqrtf(float x); // sqrt(x); }
+
+float tanf(float x); // tan(x); }
+float tanhf(float x); // tanh(x); }
+
+//float truncf(float x); // trunc(x); }
+
+
+#endif
diff --git a/libm/s_asinh.c b/libm/s_asinh.c
new file mode 100644
index 0000000..a0bff27
--- /dev/null
+++ b/libm/s_asinh.c
@@ -0,0 +1,61 @@
+
+/* @(#)s_asinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinh(x)
+ * Method :
+ * Based on
+ * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ * we have
+ * asinh(x) := x if 1+x*x=1,
+ * := sign(x)*(log(x)+ln2)) for large |x|, else
+ * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+huge= 1.00000000000000000000e+300;
+
+#ifdef __STDC__
+ double asinh(double x)
+#else
+ double asinh(x)
+ double x;
+#endif
+{
+ double t,w;
+ int hx,ix;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */
+ if(ix< 0x3e300000) { /* |x|<2**-28 */
+ if(huge+x>one) return x; /* return x inexact except 0 */
+ }
+ if(ix>0x41b00000) { /* |x| > 2**28 */
+ w = __ieee754_log(fabs(x))+ln2;
+ } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
+ t = fabs(x);
+ w = __ieee754_log(2.0*t+one/(sqrt(x*x+one)+t));
+ } else { /* 2.0 > |x| > 2**-28 */
+ t = x*x;
+ w =log1p(fabs(x)+t/(one+sqrt(one+t)));
+ }
+ if(hx>0) return w; else return -w;
+}
diff --git a/libm/s_atan.c b/libm/s_atan.c
new file mode 100644
index 0000000..751cf6b
--- /dev/null
+++ b/libm/s_atan.c
@@ -0,0 +1,134 @@
+
+/* @(#)s_atan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atan(x)
+ * Method
+ * 1. Reduce x to positive by atan(x) = -atan(-x).
+ * 2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ * is further reduced to one of the following intervals and the
+ * arctangent of t is evaluated by the corresponding formula:
+ *
+ * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ * [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double atanhi[] = {
+#else
+static double atanhi[] = {
+#endif
+ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+ 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+ 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+#ifdef __STDC__
+static const double atanlo[] = {
+#else
+static double atanlo[] = {
+#endif
+ 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+ 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+ 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+ 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+#ifdef __STDC__
+static const double aT[] = {
+#else
+static double aT[] = {
+#endif
+ 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+ 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+ 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+ 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+ 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+#ifdef __STDC__
+ static const double
+#else
+ static double
+#endif
+one = 1.0,
+huge = 1.0e300;
+
+#ifdef __STDC__
+ double atan(double x)
+#else
+ double atan(x)
+ double x;
+#endif
+{
+ double w,s1,s2,z;
+ int ix,hx,id;
+
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x44100000) { /* if |x| >= 2^66 */
+ if(ix>0x7ff00000||
+ (ix==0x7ff00000&&(__LO(x)!=0)))
+ return x+x; /* NaN */
+ if(hx>0) return atanhi[3]+atanlo[3];
+ else return -atanhi[3]-atanlo[3];
+ } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
+ if (ix < 0x3e200000) { /* |x| < 2^-29 */
+ if(huge+x>one) return x; /* raise inexact */
+ }
+ id = -1;
+ } else {
+ x = fabs(x);
+ if (ix < 0x3ff30000) { /* |x| < 1.1875 */
+ if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */
+ id = 0; x = (2.0*x-one)/(2.0+x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1; x = (x-one)/(x+one);
+ }
+ } else {
+ if (ix < 0x40038000) { /* |x| < 2.4375 */
+ id = 2; x = (x-1.5)/(one+1.5*x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3; x = -1.0/x;
+ }
+ }}
+ /* end of argument reduction */
+ z = x*x;
+ w = z*z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+ s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+ if (id<0) return x - x*(s1+s2);
+ else {
+ z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+ return (hx<0)? -z:z;
+ }
+}
diff --git a/libm/s_cbrt.c b/libm/s_cbrt.c
new file mode 100644
index 0000000..8f6640e
--- /dev/null
+++ b/libm/s_cbrt.c
@@ -0,0 +1,87 @@
+
+/* @(#)s_cbrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "math.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+#ifdef __STDC__
+static const unsigned
+#else
+static unsigned
+#endif
+ B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+ B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
+F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
+G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+#ifdef __STDC__
+ double cbrt(double x)
+#else
+ double cbrt(x)
+ double x;
+#endif
+{
+ int hx;
+ double r,s,t=0.0,w;
+ unsigned sign;
+
+
+ hx = __HI(x); /* high word of x */
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+ if((hx|__LO(x))==0)
+ return(x); /* cbrt(0) is itself */
+
+ __HI(x) = hx; /* x <- |x| */
+ /* rough cbrt to 5 bits */
+ if(hx<0x00100000) /* subnormal number */
+ {__HI(t)=0x43500000; /* set t= 2**54 */
+ t*=x; __HI(t)=__HI(t)/3+B2;
+ }
+ else
+ __HI(t)=hx/3+B1;
+
+
+ /* new cbrt to 23 bits, may be implemented in single precision */
+ r=t*t/x;
+ s=C+r*t;
+ t*=G+F/(s+E+D/s);
+
+ /* chopped to 20 bits and make it larger than cbrt(x) */
+ __LO(t)=0; __HI(t)+=0x00000001;
+
+
+ /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+ s=t*t; /* t*t is exact */
+ r=x/s;
+ w=t+t;
+ r=(r-t)/(w+r); /* r-s is exact */
+ t=t+t*r;
+
+ /* retore the sign bit */
+ __HI(t) |= sign;
+ return(t);
+}
diff --git a/libm/s_ceil.c b/libm/s_ceil.c
new file mode 100644
index 0000000..8a8b79f
--- /dev/null
+++ b/libm/s_ceil.c
@@ -0,0 +1,78 @@
+
+/* @(#)s_ceil.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double huge = 1.0e300;
+#else
+static double huge = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double ceil(double x)
+#else
+ double ceil(x)
+ double x;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i,j;
+ i0 = __HI(x);
+ i1 = __LO(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;i1=0;}
+ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1 + (1<<(52-j0));
+ if(j<i1) i0+=1; /* got a carry */
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ __HI(x) = i0;
+ __LO(x) = i1;
+ return x;
+}
diff --git a/libm/s_copysign.c b/libm/s_copysign.c
new file mode 100644
index 0000000..371ea95
--- /dev/null
+++ b/libm/s_copysign.c
@@ -0,0 +1,31 @@
+
+/* @(#)s_copysign.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double copysign(double x, double y)
+#else
+ double copysign(x,y)
+ double x,y;
+#endif
+{
+ __HI(x) = (__HI(x)&0x7fffffff)|(__HI(y)&0x80000000);
+ return x;
+}
diff --git a/libm/s_cos.c b/libm/s_cos.c
new file mode 100644
index 0000000..29c5bec
--- /dev/null
+++ b/libm/s_cos.c
@@ -0,0 +1,78 @@
+
+/* @(#)s_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cosine function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double cos(double x)
+#else
+ double cos(x)
+ double x;
+#endif
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = __HI(x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+ /* cos(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cos(y[0],y[1]);
+ case 1: return -__kernel_sin(y[0],y[1],1);
+ case 2: return -__kernel_cos(y[0],y[1]);
+ default:
+ return __kernel_sin(y[0],y[1],1);
+ }
+ }
+}
diff --git a/libm/s_erf.c b/libm/s_erf.c
new file mode 100644
index 0000000..3584d1c
--- /dev/null
+++ b/libm/s_erf.c
@@ -0,0 +1,310 @@
+
+/* @(#)s_erf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ * x
+ * 2 |\
+ * erf(x) = --------- | exp(-t*t)dt
+ * sqrt(pi) \|
+ * 0
+ *
+ * erfc(x) = 1-erf(x)
+ * Note that
+ * erf(-x) = -erf(x)
+ * erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ * 1. For |x| in [0, 0.84375]
+ * erf(x) = x + x*R(x^2)
+ * erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+ * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+ * where R = P/Q where P is an odd poly of degree 8 and
+ * Q is an odd poly of degree 10.
+ * -57.90
+ * | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ * Remark. The formula is derived by noting
+ * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ * and that
+ * 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ * is close to one. The interval is chosen because the fix
+ * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ * near 0.6174), and by some experiment, 0.84375 is chosen to
+ * guarantee the error is less than one ulp for erf.
+ *
+ * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ * c = 0.84506291151 rounded to single (24 bits)
+ * erf(x) = sign(x) * (c + P1(s)/Q1(s))
+ * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+ * 1+(c+P1(s)/Q1(s)) if x < 0
+ * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ * Remark: here we use the taylor series expansion at x=1.
+ * erf(1+s) = erf(1) + s*Poly(s)
+ * = 0.845.. + P1(s)/Q1(s)
+ * That is, we use rational approximation to approximate
+ * erf(1+s) - (c = (single)0.84506291151)
+ * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ * where
+ * P1(s) = degree 6 poly in s
+ * Q1(s) = degree 6 poly in s
+ *
+ * 3. For x in [1.25,1/0.35(~2.857143)],
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ * erf(x) = 1 - erfc(x)
+ * where
+ * R1(z) = degree 7 poly in z, (z=1/x^2)
+ * S1(z) = degree 8 poly in z
+ *
+ * 4. For x in [1/0.35,28]
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ * = 2.0 - tiny (if x <= -6)
+ * erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ * erf(x) = sign(x)*(1.0 - tiny)
+ * where
+ * R2(z) = degree 6 poly in z, (z=1/x^2)
+ * S2(z) = degree 7 poly in z
+ *
+ * Note1:
+ * To compute exp(-x*x-0.5625+R/S), let s be a single
+ * precision number and s := x; then
+ * -x*x = -s*s + (s-x)*(s+x)
+ * exp(-x*x-0.5626+R/S) =
+ * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ * Note2:
+ * Here 4 and 5 make use of the asymptotic series
+ * exp(-x*x)
+ * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ * x*sqrt(pi)
+ * We use rational approximation to approximate
+ * g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ * Here is the error bound for R1/S1 and R2/S2
+ * |R1/S1 - f(x)| < 2**(-62.57)
+ * |R2/S2 - f(x)| < 2**(-61.52)
+ *
+ * 5. For inf > x >= 28
+ * erf(x) = sign(x) *(1 - tiny) (raise inexact)
+ * erfc(x) = tiny*tiny (raise underflow) if x > 0
+ * = 2 - tiny if x<0
+ *
+ * 7. Special case:
+ * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+ * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ * erfc/erf(NaN) is NaN
+ */
+
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+tiny = 1e-300,
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+ /* c = (float)0.84506291151 */
+erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to erf in [0.84375,1.25]
+ */
+pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to erfc in [1.25,1/0.35]
+ */
+ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to erfc in [1/.35,28]
+ */
+rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+#ifdef __STDC__
+ double erf(double x)
+#else
+ double erf(x)
+ double x;
+#endif
+{
+ int hx,ix,i;
+ double R,S,P,Q,s,y,z,r;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erf(nan)=nan */
+ i = ((unsigned)hx>>31)<<1;
+ return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3e300000) { /* |x|<2**-28 */
+ if (ix < 0x00800000)
+ return 0.125*(8.0*x+efx8*x); /*avoid underflow */
+ return x + efx*x;
+ }
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ return x + x*y;
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+ }
+ if (ix >= 0x40180000) { /* inf>|x|>=6 */
+ if(hx>=0) return one-tiny; else return tiny-one;
+ }
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/0.35 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ __LO(z) = 0;
+ r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>=0) return one-r/x; else return r/x-one;
+}
+
+#ifdef __STDC__
+ double erfc(double x)
+#else
+ double erfc(x)
+ double x;
+#endif
+{
+ int hx,ix;
+ double R,S,P,Q,s,y,z,r;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erfc(nan)=nan */
+ /* erfc(+-inf)=0,2 */
+ return (double)(((unsigned)hx>>31)<<1)+one/x;
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3c700000) /* |x|<2**-56 */
+ return one-x;
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ if(hx < 0x3fd00000) { /* x<1/4 */
+ return one-(x+x*y);
+ } else {
+ r = x*y;
+ r += (x-half);
+ return half - r ;
+ }
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) {
+ z = one-erx; return z - P/Q;
+ } else {
+ z = erx+P/Q; return one+z;
+ }
+ }
+ if (ix < 0x403c0000) { /* |x|<28 */
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/.35 ~ 2.857143 */
+ if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ __LO(z) = 0;
+ r = __ieee754_exp(-z*z-0.5625)*
+ __ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>0) return r/x; else return two-r/x;
+ } else {
+ if(hx>0) return tiny*tiny; else return two-tiny;
+ }
+}
diff --git a/libm/s_expm1.c b/libm/s_expm1.c
new file mode 100644
index 0000000..373ed80
--- /dev/null
+++ b/libm/s_expm1.c
@@ -0,0 +1,217 @@
+
+/* @(#)s_expm1.c 1.5 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+ *
+ * Here a correction term c will be computed to compensate
+ * the error in r when rounded to a floating-point number.
+ *
+ * 2. Approximating expm1(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Since
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ * we define R1(r*r) by
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ * That is,
+ * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ * We use a special Remes algorithm on [0,0.347] to generate
+ * a polynomial of degree 5 in r*r to approximate R1. The
+ * maximum error of this polynomial approximation is bounded
+ * by 2**-61. In other words,
+ * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ * where Q1 = -1.6666666666666567384E-2,
+ * Q2 = 3.9682539681370365873E-4,
+ * Q3 = -9.9206344733435987357E-6,
+ * Q4 = 2.5051361420808517002E-7,
+ * Q5 = -6.2843505682382617102E-9;
+ * (where z=r*r, and the values of Q1 to Q5 are listed below)
+ * with error bounded by
+ * | 5 | -61
+ * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+ * | |
+ *
+ * expm1(r) = exp(r)-1 is then computed by the following
+ * specific way which minimize the accumulation rounding error:
+ * 2 3
+ * r r [ 3 - (R1 + R1*r/2) ]
+ * expm1(r) = r + --- + --- * [--------------------]
+ * 2 2 [ 6 - r*(3 - R1*r/2) ]
+ *
+ * To compensate the error in the argument reduction, we use
+ * expm1(r+c) = expm1(r) + c + expm1(r)*c
+ * ~ expm1(r) + c + r*c
+ * Thus c+r*c will be added in as the correction terms for
+ * expm1(r+c). Now rearrange the term to avoid optimization
+ * screw up:
+ * ( 2 2 )
+ * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+ * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+ * ( )
+ *
+ * = r - E
+ * 3. Scale back to obtain expm1(x):
+ * From step 1, we have
+ * expm1(x) = either 2^k*[expm1(r)+1] - 1
+ * = or 2^k*[expm1(r) + (1-2^-k)]
+ * 4. Implementation notes:
+ * (A). To save one multiplication, we scale the coefficient Qi
+ * to Qi*2^i, and replace z by (x^2)/2.
+ * (B). To achieve maximum accuracy, we compute expm1(x) by
+ * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ * (ii) if k=0, return r-E
+ * (iii) if k=-1, return 0.5*(r-E)-0.5
+ * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ * else return 1.0+2.0*(r-E);
+ * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ * (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ * expm1(INF) is INF, expm1(NaN) is NaN;
+ * expm1(-INF) is -1, and
+ * for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+one = 1.0,
+huge = 1.0e+300,
+tiny = 1.0e-300,
+o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+ /* scaled coefficients related to expm1 */
+Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+#ifdef __STDC__
+ double expm1(double x)
+#else
+ double expm1(x)
+ double x;
+#endif
+{
+ double y,hi,lo,c,t,e,hxs,hfx,r1;
+ int k,xsb;
+ unsigned hx;
+
+ hx = __HI(x); /* high word of x */
+ xsb = hx&0x80000000; /* sign bit of x */
+ if(xsb==0) y=x; else y= -x; /* y = |x| */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out huge and non-finite argument */
+ if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|__LO(x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+ }
+ if(x > o_threshold) return huge*huge; /* overflow */
+ }
+ if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+ if(x+tiny<0.0) /* raise inexact */
+ return tiny-one; /* return -1 */
+ }
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ if(xsb==0)
+ {hi = x - ln2_hi; lo = ln2_lo; k = 1;}
+ else
+ {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
+ } else {
+ k = invln2*x+((xsb==0)?0.5:-0.5);
+ t = k;
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
+ lo = t*ln2_lo;
+ }
+ x = hi - lo;
+ c = (hi-x)-lo;
+ }
+ else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */
+ t = huge+x; /* return x with inexact flags when x!=0 */
+ return x - (t-(huge+x));
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ hfx = 0.5*x;
+ hxs = x*hfx;
+ r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+ t = 3.0-r1*hfx;
+ e = hxs*((r1-t)/(6.0 - x*t));
+ if(k==0) return x - (x*e-hxs); /* c is 0 */
+ else {
+ e = (x*(e-c)-c);
+ e -= hxs;
+ if(k== -1) return 0.5*(x-e)-0.5;
+ if(k==1)
+ {
+ if(x < -0.25) return -2.0*(e-(x+0.5));
+ else return one+2.0*(x-e);
+ }
+ if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
+ y = one-(e-x);
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ return y-one;
+ }
+ t = one;
+ if(k<20) {
+ __HI(t) = 0x3ff00000 - (0x200000>>k); /* t=1-2^-k */
+ y = t-(e-x);
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ } else {
+ __HI(t) = ((0x3ff-k)<<20); /* 2^-k */
+ y = x-(e+t);
+ y += one;
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ }
+ }
+ return y;
+}
diff --git a/libm/s_fabs.c b/libm/s_fabs.c
new file mode 100644
index 0000000..695af1c
--- /dev/null
+++ b/libm/s_fabs.c
@@ -0,0 +1,29 @@
+
+/* @(#)s_fabs.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double fabs(double x)
+#else
+ double fabs(x)
+ double x;
+#endif
+{
+ __HI(x) &= 0x7fffffff;
+ return x;
+}
diff --git a/libm/s_finite.c b/libm/s_finite.c
new file mode 100644
index 0000000..6d8f775
--- /dev/null
+++ b/libm/s_finite.c
@@ -0,0 +1,31 @@
+
+/* @(#)s_finite.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * finite(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ int finite(double x)
+#else
+ int finite(x)
+ double x;
+#endif
+{
+ int hx;
+ hx = __HI(x);
+ return (unsigned)((hx&0x7fffffff)-0x7ff00000)>>31;
+}
diff --git a/libm/s_floor.c b/libm/s_floor.c
new file mode 100644
index 0000000..e5e2c8d
--- /dev/null
+++ b/libm/s_floor.c
@@ -0,0 +1,79 @@
+
+/* @(#)s_floor.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floor(x).
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double huge = 1.0e300;
+#else
+static double huge = 1.0e300;
+#endif
+
+#ifdef __STDC__
+ double floor(double x)
+#else
+ double floor(x)
+ double x;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i,j;
+ i0 = __HI(x);
+ i1 = __LO(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=i1=0;}
+ else if(((i0&0x7fffffff)|i1)!=0)
+ { i0=0xbff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1+(1<<(52-j0));
+ if(j<i1) i0 +=1 ; /* got a carry */
+ i1=j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ __HI(x) = i0;
+ __LO(x) = i1;
+ return x;
+}
diff --git a/libm/s_frexp.c b/libm/s_frexp.c
new file mode 100644
index 0000000..1da4905
--- /dev/null
+++ b/libm/s_frexp.c
@@ -0,0 +1,56 @@
+
+/* @(#)s_frexp.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * for non-zero x
+ * x = frexp(arg,&exp);
+ * return a double fp quantity x such that 0.5 <= |x| <1.0
+ * and the corresponding binary exponent "exp". That is
+ * arg = x*2^exp.
+ * If arg is inf, 0.0, or NaN, then frexp(arg,&exp) returns arg
+ * with *exp=0.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
+
+#ifdef __STDC__
+ double frexp(double x, int *eptr)
+#else
+ double frexp(x, eptr)
+ double x; int *eptr;
+#endif
+{
+ int hx, ix, lx;
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ *eptr = 0;
+ if(ix>=0x7ff00000||((ix|lx)==0)) return x; /* 0,inf,nan */
+ if (ix<0x00100000) { /* subnormal */
+ x *= two54;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ *eptr = -54;
+ }
+ *eptr += (ix>>20)-1022;
+ hx = (hx&0x800fffff)|0x3fe00000;
+ __HI(x) = hx;
+ return x;
+}
diff --git a/libm/s_ilogb.c b/libm/s_ilogb.c
new file mode 100644
index 0000000..a785708
--- /dev/null
+++ b/libm/s_ilogb.c
@@ -0,0 +1,46 @@
+
+/* @(#)s_ilogb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = 0x80000001
+ * ilogb(inf/NaN) = 0x7fffffff (no signal is raised)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ int ilogb(double x)
+#else
+ int ilogb(x)
+ double x;
+#endif
+{
+ int hx,lx,ix;
+
+ hx = (__HI(x))&0x7fffffff; /* high word of x */
+ if(hx<0x00100000) {
+ lx = __LO(x);
+ if((hx|lx)==0)
+ return 0x80000001; /* ilogb(0) = 0x80000001 */
+ else /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043; lx>0; lx<<=1) ix -=1;
+ } else {
+ for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+ }
+ return ix;
+ }
+ else if (hx<0x7ff00000) return (hx>>20)-1023;
+ else return 0x7fffffff;
+}
diff --git a/libm/s_isnan.c b/libm/s_isnan.c
new file mode 100644
index 0000000..11b0cfd
--- /dev/null
+++ b/libm/s_isnan.c
@@ -0,0 +1,34 @@
+
+/* @(#)s_isnan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * isnan(x) returns 1 is x is nan, else 0;
+ * no branching!
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ int isnan(double x)
+#else
+ int isnan(x)
+ double x;
+#endif
+{
+ int hx,lx;
+ hx = (__HI(x)&0x7fffffff);
+ lx = __LO(x);
+ hx |= (unsigned)(lx|(-lx))>>31;
+ hx = 0x7ff00000 - hx;
+ return ((unsigned)(hx))>>31;
+}
diff --git a/libm/s_ldexp.c b/libm/s_ldexp.c
new file mode 100644
index 0000000..7698d94
--- /dev/null
+++ b/libm/s_ldexp.c
@@ -0,0 +1,28 @@
+
+/* @(#)s_ldexp.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "math.h"
+#include <errno.h>
+
+#ifdef __STDC__
+ double ldexp(double value, int exp)
+#else
+ double ldexp(value, exp)
+ double value; int exp;
+#endif
+{
+ if(!finite(value)||value==0.0) return value;
+ value = scalbn(value,exp);
+ if(!finite(value)||value==0.0) errno = ERANGE;
+ return value;
+}
diff --git a/libm/s_lib_version.c b/libm/s_lib_version.c
new file mode 100644
index 0000000..45a8202
--- /dev/null
+++ b/libm/s_lib_version.c
@@ -0,0 +1,35 @@
+
+/* @(#)s_lib_version.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * MACRO for standards
+ */
+
+#include "math.h"
+
+/*
+ * define and initialize _LIB_VERSION
+ */
+#ifdef _POSIX_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _POSIX_;
+#else
+#ifdef _XOPEN_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _XOPEN_;
+#else
+#ifdef _SVID3_MODE
+_LIB_VERSION_TYPE _LIB_VERSION = _SVID_;
+#else /* default _IEEE_MODE */
+_LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
+#endif
+#endif
+#endif
diff --git a/libm/s_log1p.c b/libm/s_log1p.c
new file mode 100644
index 0000000..dd657c2
--- /dev/null
+++ b/libm/s_log1p.c
@@ -0,0 +1,169 @@
+
+/* @(#)s_log1p.c 1.4 96/03/07 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double log1p(double x)
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * 1+x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * Note. If k=0, then f=x is exact. However, if k!=0, then f
+ * may not be representable exactly. In that case, a correction
+ * term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ * and add back the correction term c/u.
+ * (Note: when x > 2**53, one can simply return log(x))
+ *
+ * 2. Approximation of log1p(f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Remes algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+ * (the values of Lp1 to Lp7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lp1*s +...+Lp7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ * 3. Finally, log1p(x) = k*ln2 + log1p(f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ * log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ * log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ * algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ * u = 1+x;
+ * if(u==1.0) return x ; else
+ * return log(u)*(x/(u-1.0));
+ *
+ * See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+#ifdef __STDC__
+ double log1p(double x)
+#else
+ double log1p(x)
+ double x;
+#endif
+{
+ double hfsq,f,c,s,z,R,u;
+ int k,hx,hu,ax;
+
+ hx = __HI(x); /* high word of x */
+ ax = hx&0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3FDA827A) { /* x < 0.41422 */
+ if(ax>=0x3ff00000) { /* x <= -1.0 */
+ if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */
+ }
+ if(ax<0x3e200000) { /* |x| < 2**-29 */
+ if(two54+x>zero /* raise inexact */
+ &&ax<0x3c900000) /* |x| < 2**-54 */
+ return x;
+ else
+ return x - x*x*0.5;
+ }
+ if(hx>0||hx<=((int)0xbfd2bec3)) {
+ k=0;f=x;hu=1;} /* -0.2929<x<0.41422 */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ if(k!=0) {
+ if(hx<0x43400000) {
+ u = 1.0+x;
+ hu = __HI(u); /* high word of u */
+ k = (hu>>20)-1023;
+ c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+ c /= u;
+ } else {
+ u = x;
+ hu = __HI(u); /* high word of u */
+ k = (hu>>20)-1023;
+ c = 0;
+ }
+ hu &= 0x000fffff;
+ if(hu<0x6a09e) {
+ __HI(u) = hu|0x3ff00000; /* normalize u */
+ } else {
+ k += 1;
+ __HI(u) = hu|0x3fe00000; /* normalize u/2 */
+ hu = (0x00100000-hu)>>2;
+ }
+ f = u-1.0;
+ }
+ hfsq=0.5*f*f;
+ if(hu==0) { /* |f| < 2**-20 */
+ if(f==zero)
+ {
+ if(k==0) return zero;
+ else {c += k*ln2_lo; return k*ln2_hi+c;}
+ }
+
+ R = hfsq*(1.0-0.66666666666666666*f);
+ if(k==0) return f-R; else
+ return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+ }
+ s = f/(2.0+f);
+ z = s*s;
+ R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/libm/s_logb.c b/libm/s_logb.c
new file mode 100644
index 0000000..857878d
--- /dev/null
+++ b/libm/s_logb.c
@@ -0,0 +1,38 @@
+
+/* @(#)s_logb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double logb(double x)
+#else
+ double logb(x)
+ double x;
+#endif
+{
+ int lx,ix;
+ ix = (__HI(x))&0x7fffffff; /* high |x| */
+ lx = __LO(x); /* low x */
+ if((ix|lx)==0) return -1.0/fabs(x);
+ if(ix>=0x7ff00000) return x*x;
+ if((ix>>=20)==0) /* IEEE 754 logb */
+ return -1022.0;
+ else
+ return (double) (ix-1023);
+}
diff --git a/libm/s_matherr.c b/libm/s_matherr.c
new file mode 100644
index 0000000..bc0e1b4
--- /dev/null
+++ b/libm/s_matherr.c
@@ -0,0 +1,26 @@
+
+/* @(#)s_matherr.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ int matherr(struct exception *x)
+#else
+ int matherr(x)
+ struct exception *x;
+#endif
+{
+ int n=0;
+ if(x->arg1!=x->arg1) return 0;
+ return n;
+}
diff --git a/libm/s_modf.c b/libm/s_modf.c
new file mode 100644
index 0000000..067dfb2
--- /dev/null
+++ b/libm/s_modf.c
@@ -0,0 +1,80 @@
+
+/* @(#)s_modf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ * Bit twiddling.
+ *
+ * Exception:
+ * No exception.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one = 1.0;
+#else
+static double one = 1.0;
+#endif
+
+#ifdef __STDC__
+ double modf(double x, double *iptr)
+#else
+ double modf(x, iptr)
+ double x,*iptr;
+#endif
+{
+ int i0,i1,j0;
+ unsigned i;
+ i0 = __HI(x); /* high x */
+ i1 = __LO(x); /* low x */
+ j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */
+ if(j0<20) { /* integer part in high x */
+ if(j0<0) { /* |x|<1 */
+ __HIp(iptr) = i0&0x80000000;
+ __LOp(iptr) = 0; /* *iptr = +-0 */
+ return x;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) { /* x is integral */
+ *iptr = x;
+ __HI(x) &= 0x80000000;
+ __LO(x) = 0; /* return +-0 */
+ return x;
+ } else {
+ __HIp(iptr) = i0&(~i);
+ __LOp(iptr) = 0;
+ return x - *iptr;
+ }
+ }
+ } else if (j0>51) { /* no fraction part */
+ *iptr = x*one;
+ __HI(x) &= 0x80000000;
+ __LO(x) = 0; /* return +-0 */
+ return x;
+ } else { /* fraction part in low x */
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) { /* x is integral */
+ *iptr = x;
+ __HI(x) &= 0x80000000;
+ __LO(x) = 0; /* return +-0 */
+ return x;
+ } else {
+ __HIp(iptr) = i0;
+ __LOp(iptr) = i1&(~i);
+ return x - *iptr;
+ }
+ }
+}
diff --git a/libm/s_nextafter.c b/libm/s_nextafter.c
new file mode 100644
index 0000000..1a9fc36
--- /dev/null
+++ b/libm/s_nextafter.c
@@ -0,0 +1,78 @@
+
+/* @(#)s_nextafter.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ * nextafter(x,y)
+ * return the next machine floating-point number of x in the
+ * direction toward y.
+ * Special cases:
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double nextafter(double x, double y)
+#else
+ double nextafter(x,y)
+ double x,y;
+#endif
+{
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+ hy = __HI(y); /* high word of y */
+ ly = __LO(y); /* low word of y */
+ ix = hx&0x7fffffff; /* |x| */
+ iy = hy&0x7fffffff; /* |y| */
+
+ if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */
+ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */
+ return x+y;
+ if(x==y) return x; /* x=y, return x */
+ if((ix|lx)==0) { /* x == 0 */
+ __HI(x) = hy&0x80000000; /* return +-minsubnormal */
+ __LO(x) = 1;
+ y = x*x;
+ if(y==x) return y; else return x; /* raise underflow flag */
+ }
+ if(hx>=0) { /* x > 0 */
+ if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x < y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ } else { /* x < 0 */
+ if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x > y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ }
+ hy = hx&0x7ff00000;
+ if(hy>=0x7ff00000) return x+x; /* overflow */
+ if(hy<0x00100000) { /* underflow */
+ y = x*x;
+ if(y!=x) { /* raise underflow flag */
+ __HI(y) = hx; __LO(y) = lx;
+ return y;
+ }
+ }
+ __HI(x) = hx; __LO(x) = lx;
+ return x;
+}
diff --git a/libm/s_rint.c b/libm/s_rint.c
new file mode 100644
index 0000000..3f92689
--- /dev/null
+++ b/libm/s_rint.c
@@ -0,0 +1,84 @@
+
+/* @(#)s_rint.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ * Using floating addition.
+ * Exception:
+ * Inexact flag raised if x not equal to rint(x).
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+TWO52[2]={
+ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+#ifdef __STDC__
+ double rint(double x)
+#else
+ double rint(x)
+ double x;
+#endif
+{
+ int i0,j0,sx;
+ unsigned i,i1;
+ double w,t;
+ i0 = __HI(x);
+ sx = (i0>>31)&1;
+ i1 = __LO(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) {
+ if(((i0&0x7fffffff)|i1)==0) return x;
+ i1 |= (i0&0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1|-i1)>>12)&0x80000;
+ __HI(x)=i0;
+ w = TWO52[sx]+x;
+ t = w-TWO52[sx];
+ i0 = __HI(t);
+ __HI(t) = (i0&0x7fffffff)|(sx<<31);
+ return t;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ i>>=1;
+ if(((i0&i)|i1)!=0) {
+ if(j0==19) i1 = 0x40000000; else
+ i0 = (i0&(~i))|((0x20000)>>j0);
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ i>>=1;
+ if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+ }
+ __HI(x) = i0;
+ __LO(x) = i1;
+ w = TWO52[sx]+x;
+ return w-TWO52[sx];
+}
diff --git a/libm/s_scalbn.c b/libm/s_scalbn.c
new file mode 100644
index 0000000..64e7a23
--- /dev/null
+++ b/libm/s_scalbn.c
@@ -0,0 +1,66 @@
+
+/* @(#)s_scalbn.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n computed by exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge = 1.0e+300,
+tiny = 1.0e-300;
+
+#ifdef __STDC__
+ double scalbn (double x, int n)
+#else
+ double scalbn (x,n)
+ double x; int n;
+#endif
+{
+ int k,hx,lx;
+ hx = __HI(x);
+ lx = __LO(x);
+ k = (hx&0x7ff00000)>>20; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+ x *= two54;
+ hx = __HI(x);
+ k = ((hx&0x7ff00000)>>20) - 54;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7ff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
+ if (k <= -54)
+ {
+ if (n > 50000) /* in case integer overflow in n+k */
+ return huge*copysign(huge,x); /*overflow*/
+ else return tiny*copysign(tiny,x); /*underflow*/
+ }
+
+ k += 54; /* subnormal result */
+ __HI(x) = (hx&0x800fffff)|(k<<20);
+ return x*twom54;
+}
diff --git a/libm/s_signgam.c b/libm/s_signgam.c
new file mode 100644
index 0000000..44ca79b
--- /dev/null
+++ b/libm/s_signgam.c
@@ -0,0 +1,2 @@
+#include "math.h"
+int signgam = 0;
diff --git a/libm/s_significand.c b/libm/s_significand.c
new file mode 100644
index 0000000..f63a43d
--- /dev/null
+++ b/libm/s_significand.c
@@ -0,0 +1,30 @@
+
+/* @(#)s_significand.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * significand(x) computes just
+ * scalb(x, (double) -ilogb(x)),
+ * for exercising the fraction-part(F) IEEE 754-1985 test vector.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double significand(double x)
+#else
+ double significand(x)
+ double x;
+#endif
+{
+ return __ieee754_scalb(x,(double) -ilogb(x));
+}
diff --git a/libm/s_sin.c b/libm/s_sin.c
new file mode 100644
index 0000000..5773936
--- /dev/null
+++ b/libm/s_sin.c
@@ -0,0 +1,78 @@
+
+/* @(#)s_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cose function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double sin(double x)
+#else
+ double sin(x)
+ double x;
+#endif
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = __HI(x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+ /* sin(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sin(y[0],y[1],1);
+ case 1: return __kernel_cos(y[0],y[1]);
+ case 2: return -__kernel_sin(y[0],y[1],1);
+ default:
+ return -__kernel_cos(y[0],y[1]);
+ }
+ }
+}
diff --git a/libm/s_tan.c b/libm/s_tan.c
new file mode 100644
index 0000000..dd57422
--- /dev/null
+++ b/libm/s_tan.c
@@ -0,0 +1,72 @@
+
+/* @(#)s_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ * __kernel_tan ... tangent function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double tan(double x)
+#else
+ double tan(x)
+ double x;
+#endif
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = __HI(x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+ /* tan(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x; /* NaN */
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
+ -1 -- n odd */
+ }
+}
diff --git a/libm/s_tanh.c b/libm/s_tanh.c
new file mode 100644
index 0000000..a0a6001
--- /dev/null
+++ b/libm/s_tanh.c
@@ -0,0 +1,82 @@
+
+/* @(#)s_tanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ * x -x
+ * e - e
+ * 0. tanh(x) is defined to be -----------
+ * x -x
+ * e + e
+ * 1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ * 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+x)
+ * -t
+ * 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x)
+ * t + 2
+ * 2
+ * 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t=expm1(2x)
+ * t + 2
+ * 22.0 < x <= INF : tanh(x) := 1.
+ *
+ * Special cases:
+ * tanh(NaN) is NaN;
+ * only tanh(0)=0 is exact for finite argument.
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+#else
+static double one=1.0, two=2.0, tiny = 1.0e-300;
+#endif
+
+#ifdef __STDC__
+ double tanh(double x)
+#else
+ double tanh(x)
+ double x;
+#endif
+{
+ double t,z;
+ int jx,ix;
+
+ /* High word of |x|. */
+ jx = __HI(x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) {
+ if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
+ else return one/x-one; /* tanh(NaN) = NaN */
+ }
+
+ /* |x| < 22 */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3c800000) /* |x|<2**-55 */
+ return x*(one+x); /* tanh(small) = small */
+ if (ix>=0x3ff00000) { /* |x|>=1 */
+ t = expm1(two*fabs(x));
+ z = one - two/(t+two);
+ } else {
+ t = expm1(-two*fabs(x));
+ z= -t/(t+two);
+ }
+ /* |x| > 22, return +-1 */
+ } else {
+ z = one - tiny; /* raised inexact flag */
+ }
+ return (jx>=0)? z: -z;
+}
diff --git a/libm/w_acos.c b/libm/w_acos.c
new file mode 100644
index 0000000..f6519c5
--- /dev/null
+++ b/libm/w_acos.c
@@ -0,0 +1,39 @@
+
+/* @(#)w_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrap_acos(x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double acos(double x) /* wrapper acos */
+#else
+ double acos(x) /* wrapper acos */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_acos(x);
+#else
+ double z;
+ z = __ieee754_acos(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>1.0) {
+ return __kernel_standard(x,x,1); /* acos(|x|>1) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_acosh.c b/libm/w_acosh.c
new file mode 100644
index 0000000..69d6b0c
--- /dev/null
+++ b/libm/w_acosh.c
@@ -0,0 +1,39 @@
+
+/* @(#)w_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/*
+ * wrapper acosh(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double acosh(double x) /* wrapper acosh */
+#else
+ double acosh(x) /* wrapper acosh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_acosh(x);
+#else
+ double z;
+ z = __ieee754_acosh(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(x<1.0) {
+ return __kernel_standard(x,x,29); /* acosh(x<1) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_asin.c b/libm/w_asin.c
new file mode 100644
index 0000000..06ca3f6
--- /dev/null
+++ b/libm/w_asin.c
@@ -0,0 +1,41 @@
+
+/* @(#)w_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/*
+ * wrapper asin(x)
+ */
+
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double asin(double x) /* wrapper asin */
+#else
+ double asin(x) /* wrapper asin */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_asin(x);
+#else
+ double z;
+ z = __ieee754_asin(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>1.0) {
+ return __kernel_standard(x,x,2); /* asin(|x|>1) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_atan2.c b/libm/w_atan2.c
new file mode 100644
index 0000000..80cfa19
--- /dev/null
+++ b/libm/w_atan2.c
@@ -0,0 +1,40 @@
+
+/* @(#)w_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/*
+ * wrapper atan2(y,x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double atan2(double y, double x) /* wrapper atan2 */
+#else
+ double atan2(y,x) /* wrapper atan2 */
+ double y,x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_atan2(y,x);
+#else
+ double z;
+ z = __ieee754_atan2(y,x);
+ if(_LIB_VERSION == _IEEE_||isnan(x)||isnan(y)) return z;
+ if(x==0.0&&y==0.0) {
+ return __kernel_standard(y,x,3); /* atan2(+-0,+-0) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_atanh.c b/libm/w_atanh.c
new file mode 100644
index 0000000..9d7f52e
--- /dev/null
+++ b/libm/w_atanh.c
@@ -0,0 +1,42 @@
+
+/* @(#)w_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+/*
+ * wrapper atanh(x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double atanh(double x) /* wrapper atanh */
+#else
+ double atanh(x) /* wrapper atanh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_atanh(x);
+#else
+ double z,y;
+ z = __ieee754_atanh(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ y = fabs(x);
+ if(y>=1.0) {
+ if(y>1.0)
+ return __kernel_standard(x,x,30); /* atanh(|x|>1) */
+ else
+ return __kernel_standard(x,x,31); /* atanh(|x|==1) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_cosh.c b/libm/w_cosh.c
new file mode 100644
index 0000000..ce52fec
--- /dev/null
+++ b/libm/w_cosh.c
@@ -0,0 +1,38 @@
+
+/* @(#)w_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper cosh(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double cosh(double x) /* wrapper cosh */
+#else
+ double cosh(x) /* wrapper cosh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_cosh(x);
+#else
+ double z;
+ z = __ieee754_cosh(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>7.10475860073943863426e+02) {
+ return __kernel_standard(x,x,5); /* cosh overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_exp.c b/libm/w_exp.c
new file mode 100644
index 0000000..de32c02
--- /dev/null
+++ b/libm/w_exp.c
@@ -0,0 +1,52 @@
+
+/* @(#)w_exp.c 1.4 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper exp(x)
+ */
+
+#include "math.h"
+
+#ifndef _IEEE_LIBM
+
+#ifdef __STDC__
+static const double
+#else
+static double
+#endif
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02; /* 0xc0874910, 0xD52D3051 */
+
+#endif
+
+#ifdef __STDC__
+ double exp(double x) /* wrapper exp */
+#else
+ double exp(x) /* wrapper exp */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_exp(x);
+#else
+ double z;
+ z = __ieee754_exp(x);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(finite(x)) {
+ if(x>o_threshold)
+ return __kernel_standard(x,x,6); /* exp overflow */
+ else if(x<u_threshold)
+ return __kernel_standard(x,x,7); /* exp underflow */
+ }
+ return z;
+#endif
+}
diff --git a/libm/w_fmod.c b/libm/w_fmod.c
new file mode 100644
index 0000000..2d54dee
--- /dev/null
+++ b/libm/w_fmod.c
@@ -0,0 +1,39 @@
+
+/* @(#)w_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper fmod(x,y)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double fmod(double x, double y) /* wrapper fmod */
+#else
+ double fmod(x,y) /* wrapper fmod */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_fmod(x,y);
+#else
+ double z;
+ z = __ieee754_fmod(x,y);
+ if(_LIB_VERSION == _IEEE_ ||isnan(y)||isnan(x)) return z;
+ if(y==0.0) {
+ return __kernel_standard(x,y,27); /* fmod(x,0) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_gamma.c b/libm/w_gamma.c
new file mode 100644
index 0000000..2f710c3
--- /dev/null
+++ b/libm/w_gamma.c
@@ -0,0 +1,46 @@
+
+/* @(#)w_gamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* double gamma(double x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call gamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double gamma(double x)
+#else
+ double gamma(x)
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_gamma_r(x,&signgam);
+#else
+ double y;
+ y = __ieee754_gamma_r(x,&signgam);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,41); /* gamma pole */
+ else
+ return __kernel_standard(x,x,40); /* gamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/libm/w_gamma_r.c b/libm/w_gamma_r.c
new file mode 100644
index 0000000..c396ec4
--- /dev/null
+++ b/libm/w_gamma_r.c
@@ -0,0 +1,42 @@
+
+/* @(#)w_gamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper double gamma_r(double x, int *signgamp)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double gamma_r(double x, int *signgamp) /* wrapper lgamma_r */
+#else
+ double gamma_r(x,signgamp) /* wrapper lgamma_r */
+ double x; int *signgamp;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_gamma_r(x,signgamp);
+#else
+ double y;
+ y = __ieee754_gamma_r(x,signgamp);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,41); /* gamma pole */
+ else
+ return __kernel_standard(x,x,40); /* gamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/libm/w_hypot.c b/libm/w_hypot.c
new file mode 100644
index 0000000..af44577
--- /dev/null
+++ b/libm/w_hypot.c
@@ -0,0 +1,39 @@
+
+/* @(#)w_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper hypot(x,y)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double hypot(double x, double y)/* wrapper hypot */
+#else
+ double hypot(x,y) /* wrapper hypot */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_hypot(x,y);
+#else
+ double z;
+ z = __ieee754_hypot(x,y);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if((!finite(z))&&finite(x)&&finite(y))
+ return __kernel_standard(x,y,4); /* hypot overflow */
+ else
+ return z;
+#endif
+}
diff --git a/libm/w_j0.c b/libm/w_j0.c
new file mode 100644
index 0000000..d5ac70e
--- /dev/null
+++ b/libm/w_j0.c
@@ -0,0 +1,65 @@
+
+/* @(#)w_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper j0(double x), y0(double x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double j0(double x) /* wrapper j0 */
+#else
+ double j0(x) /* wrapper j0 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_j0(x);
+#else
+ double z = __ieee754_j0(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(fabs(x)>X_TLOSS) {
+ return __kernel_standard(x,x,34); /* j0(|x|>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double y0(double x) /* wrapper y0 */
+#else
+ double y0(x) /* wrapper y0 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_y0(x);
+#else
+ double z;
+ z = __ieee754_y0(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard(x,x,8);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard(x,x,9);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard(x,x,35); /* y0(x>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_j1.c b/libm/w_j1.c
new file mode 100644
index 0000000..7f6873e
--- /dev/null
+++ b/libm/w_j1.c
@@ -0,0 +1,66 @@
+
+/* @(#)w_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper of j1,y1
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double j1(double x) /* wrapper j1 */
+#else
+ double j1(x) /* wrapper j1 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_j1(x);
+#else
+ double z;
+ z = __ieee754_j1(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(fabs(x)>X_TLOSS) {
+ return __kernel_standard(x,x,36); /* j1(|x|>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double y1(double x) /* wrapper y1 */
+#else
+ double y1(x) /* wrapper y1 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_y1(x);
+#else
+ double z;
+ z = __ieee754_y1(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard(x,x,10);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard(x,x,11);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard(x,x,37); /* y1(x>X_TLOSS) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_jn.c b/libm/w_jn.c
new file mode 100644
index 0000000..06a35f4
--- /dev/null
+++ b/libm/w_jn.c
@@ -0,0 +1,88 @@
+
+/* @(#)w_jn.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper jn(int n, double x), yn(int n, double x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double jn(int n, double x) /* wrapper jn */
+#else
+ double jn(n,x) /* wrapper jn */
+ double x; int n;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_jn(n,x);
+#else
+ double z;
+ z = __ieee754_jn(n,x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(fabs(x)>X_TLOSS) {
+ return __kernel_standard((double)n,x,38); /* jn(|x|>X_TLOSS,n) */
+ } else
+ return z;
+#endif
+}
+
+#ifdef __STDC__
+ double yn(int n, double x) /* wrapper yn */
+#else
+ double yn(n,x) /* wrapper yn */
+ double x; int n;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_yn(n,x);
+#else
+ double z;
+ z = __ieee754_yn(n,x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) ) return z;
+ if(x <= 0.0){
+ if(x==0.0)
+ /* d= -one/(x-x); */
+ return __kernel_standard((double)n,x,12);
+ else
+ /* d = zero/(x-x); */
+ return __kernel_standard((double)n,x,13);
+ }
+ if(x>X_TLOSS) {
+ return __kernel_standard((double)n,x,39); /* yn(x>X_TLOSS,n) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_lgamma.c b/libm/w_lgamma.c
new file mode 100644
index 0000000..650daef
--- /dev/null
+++ b/libm/w_lgamma.c
@@ -0,0 +1,46 @@
+
+/* @(#)w_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* double lgamma(double x)
+ * Return the logarithm of the Gamma function of x.
+ *
+ * Method: call __ieee754_lgamma_r
+ */
+
+#include "math.h"
+
+extern int signgam;
+
+#ifdef __STDC__
+ double lgamma(double x)
+#else
+ double lgamma(x)
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_lgamma_r(x,&signgam);
+#else
+ double y;
+ y = __ieee754_lgamma_r(x,&signgam);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,15); /* lgamma pole */
+ else
+ return __kernel_standard(x,x,14); /* lgamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/libm/w_lgamma_r.c b/libm/w_lgamma_r.c
new file mode 100644
index 0000000..42fb1b8
--- /dev/null
+++ b/libm/w_lgamma_r.c
@@ -0,0 +1,42 @@
+
+/* @(#)w_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper double lgamma_r(double x, int *signgamp)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double lgamma_r(double x, int *signgamp) /* wrapper lgamma_r */
+#else
+ double lgamma_r(x,signgamp) /* wrapper lgamma_r */
+ double x; int *signgamp;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_lgamma_r(x,signgamp);
+#else
+ double y;
+ y = __ieee754_lgamma_r(x,signgamp);
+ if(_LIB_VERSION == _IEEE_) return y;
+ if(!finite(y)&&finite(x)) {
+ if(floor(x)==x&&x<=0.0)
+ return __kernel_standard(x,x,15); /* lgamma pole */
+ else
+ return __kernel_standard(x,x,14); /* lgamma overflow */
+ } else
+ return y;
+#endif
+}
diff --git a/libm/w_log.c b/libm/w_log.c
new file mode 100644
index 0000000..8adb5d4
--- /dev/null
+++ b/libm/w_log.c
@@ -0,0 +1,39 @@
+
+/* @(#)w_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper log(x)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double log(double x) /* wrapper log */
+#else
+ double log(x) /* wrapper log */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_log(x);
+#else
+ double z;
+ z = __ieee754_log(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x) || x > 0.0) return z;
+ if(x==0.0)
+ return __kernel_standard(x,x,16); /* log(0) */
+ else
+ return __kernel_standard(x,x,17); /* log(x<0) */
+#endif
+}
diff --git a/libm/w_log10.c b/libm/w_log10.c
new file mode 100644
index 0000000..afd3fb4
--- /dev/null
+++ b/libm/w_log10.c
@@ -0,0 +1,42 @@
+
+/* @(#)w_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper log10(X)
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double log10(double x) /* wrapper log10 */
+#else
+ double log10(x) /* wrapper log10 */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_log10(x);
+#else
+ double z;
+ z = __ieee754_log10(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(x<=0.0) {
+ if(x==0.0)
+ return __kernel_standard(x,x,18); /* log10(0) */
+ else
+ return __kernel_standard(x,x,19); /* log10(x<0) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_pow.c b/libm/w_pow.c
new file mode 100644
index 0000000..5e89859
--- /dev/null
+++ b/libm/w_pow.c
@@ -0,0 +1,60 @@
+
+
+/* @(#)w_pow.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper pow(x,y) return x**y
+ */
+
+#include "math.h"
+
+
+#ifdef __STDC__
+ double pow(double x, double y) /* wrapper pow */
+#else
+ double pow(x,y) /* wrapper pow */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_pow(x,y);
+#else
+ double z;
+ z=__ieee754_pow(x,y);
+ if(_LIB_VERSION == _IEEE_|| isnan(y)) return z;
+ if(isnan(x)) {
+ if(y==0.0)
+ return __kernel_standard(x,y,42); /* pow(NaN,0.0) */
+ else
+ return z;
+ }
+ if(x==0.0){
+ if(y==0.0)
+ return __kernel_standard(x,y,20); /* pow(0.0,0.0) */
+ if(finite(y)&&y<0.0)
+ return __kernel_standard(x,y,23); /* pow(0.0,negative) */
+ return z;
+ }
+ if(!finite(z)) {
+ if(finite(x)&&finite(y)) {
+ if(isnan(z))
+ return __kernel_standard(x,y,24); /* pow neg**non-int */
+ else
+ return __kernel_standard(x,y,21); /* pow overflow */
+ }
+ }
+ if(z==0.0&&finite(x)&&finite(y))
+ return __kernel_standard(x,y,22); /* pow underflow */
+ return z;
+#endif
+}
diff --git a/libm/w_remainder.c b/libm/w_remainder.c
new file mode 100644
index 0000000..622ea97
--- /dev/null
+++ b/libm/w_remainder.c
@@ -0,0 +1,38 @@
+
+/* @(#)w_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper remainder(x,p)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double remainder(double x, double y) /* wrapper remainder */
+#else
+ double remainder(x,y) /* wrapper remainder */
+ double x,y;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_remainder(x,y);
+#else
+ double z;
+ z = __ieee754_remainder(x,y);
+ if(_LIB_VERSION == _IEEE_ || isnan(y)) return z;
+ if(y==0.0)
+ return __kernel_standard(x,y,28); /* remainder(x,0) */
+ else
+ return z;
+#endif
+}
diff --git a/libm/w_scalb.c b/libm/w_scalb.c
new file mode 100644
index 0000000..3e941ba
--- /dev/null
+++ b/libm/w_scalb.c
@@ -0,0 +1,56 @@
+
+/* @(#)w_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper scalb(double x, double fn) is provide for
+ * passing various standard test suite. One
+ * should use scalbn() instead.
+ */
+
+#include "math.h"
+
+#include <errno.h>
+
+#ifdef __STDC__
+#ifdef _SCALB_INT
+ double scalb(double x, int fn) /* wrapper scalb */
+#else
+ double scalb(double x, double fn) /* wrapper scalb */
+#endif
+#else
+ double scalb(x,fn) /* wrapper scalb */
+#ifdef _SCALB_INT
+ double x; int fn;
+#else
+ double x,fn;
+#endif
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_scalb(x,fn);
+#else
+ double z;
+ z = __ieee754_scalb(x,fn);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(!(finite(z)||isnan(z))&&finite(x)) {
+ return __kernel_standard(x,(double)fn,32); /* scalb overflow */
+ }
+ if(z==0.0&&z!=x) {
+ return __kernel_standard(x,(double)fn,33); /* scalb underflow */
+ }
+#ifndef _SCALB_INT
+ if(!finite(fn)) errno = ERANGE;
+#endif
+ return z;
+#endif
+}
diff --git a/libm/w_sinh.c b/libm/w_sinh.c
new file mode 100644
index 0000000..35abbc0
--- /dev/null
+++ b/libm/w_sinh.c
@@ -0,0 +1,38 @@
+
+/* @(#)w_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper sinh(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double sinh(double x) /* wrapper sinh */
+#else
+ double sinh(x) /* wrapper sinh */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_sinh(x);
+#else
+ double z;
+ z = __ieee754_sinh(x);
+ if(_LIB_VERSION == _IEEE_) return z;
+ if(!finite(z)&&finite(x)) {
+ return __kernel_standard(x,x,25); /* sinh overflow */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/w_sqrt.c b/libm/w_sqrt.c
new file mode 100644
index 0000000..eced997
--- /dev/null
+++ b/libm/w_sqrt.c
@@ -0,0 +1,38 @@
+
+/* @(#)w_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * wrapper sqrt(x)
+ */
+
+#include "math.h"
+
+#ifdef __STDC__
+ double sqrt(double x) /* wrapper sqrt */
+#else
+ double sqrt(x) /* wrapper sqrt */
+ double x;
+#endif
+{
+#ifdef _IEEE_LIBM
+ return __ieee754_sqrt(x);
+#else
+ double z;
+ z = __ieee754_sqrt(x);
+ if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
+ if(x<0.0) {
+ return __kernel_standard(x,x,26); /* sqrt(negative) */
+ } else
+ return z;
+#endif
+}
diff --git a/libm/wrappers.c b/libm/wrappers.c
new file mode 100644
index 0000000..a137a63
--- /dev/null
+++ b/libm/wrappers.c
@@ -0,0 +1,90 @@
+#include "math.h"
+
+float acosf(float x){ return acos(x); }
+float acoshf(float x){ return acosh(x); }
+
+float asinf(float x){ return asin(x); }
+float asinhf(float x){ return asinf(x); }
+
+float atanf(float x){ return atan(x); }
+float atanhf(float x){ return atanh(x); }
+
+float atan2f(float x, float y){ return atan2(x,y); }
+
+float cbrtf(float x){ return cbrt(x); }
+
+float ceilf(float x){ return ceil(x); }
+
+float copysignf(float x, float y) { return copysign(x, y); }
+
+double copysignl(long double x, long double y){ return copysign(x, y); }
+
+float cosf(float x){ return cos(x); }
+float coshf(float x){ return cosh(x); }
+
+float erff(float x){ return erf(x); }
+float erfcf(float x){ return erfc(x); }
+
+float expf(float x){ return exp(x); }
+//float exp2f(float x){ return exp2(x); }
+float expm1f(float x){ return expm1(x); }
+
+float fabsf(float x){ return fabs(x); }
+
+float finitef(float x){ return finite(x); }
+
+float floorf(float x){ return floor(x); }
+
+float fmodf(float x, float y){ return fmod(x, y); }
+
+float hypotf(float x, float y){ return hypot(x, y); }
+
+int ilogbf(float x){ return ilogb(x); }
+int ilogbl(long double x){ return ilogb(x); }
+
+float j0f(float x){ return j0(x); }
+float j1f(float x){ return j1(x); }
+float jnf(int n, float x){ return jn(n,x); }
+
+float y0f(float x){ return y0(x); }
+float y1f(float x){ return y1(x); }
+float ynf(int n, float x){ return yn(n, x); }
+
+float lgammaf(float x){ return lgamma(x); }
+float gammaf(float x){ return gamma(x); }
+//float tgammaf(float x){ return tgamma(x); }
+
+float lgammaf_r(float x, int *sign){ return lgamma_r(x, sign); }
+float gammaf_r(float x, int *sign){ return gamma_r(x, sign); }
+
+float logf(float x){ return log(x); }
+float log10f(float x) { return log10(x); }
+float log1pf(float x) { return log1p(x); }
+//float log2f(float x) { return log2(x); }
+
+//float nanf(const char *tagp) { return nan(tagp); }
+//long double nanl(const char *tagp) { return nan(tagp); }
+
+float nextafterf(float x, float y) { return nextafter(x, y); }
+long double nextafterl(long double x, long double y)
+{ return nextafter(x, y); }
+
+float powf(float x, float y) { return pow(x, y); }
+
+float remainderf(float x, float y) { return remainder(x, y); }
+//float remquof(float x, float y, int *quo) { return remquo(x, y, quo); }
+
+float rintf(float x){ return rint(x); }
+
+float scalbnf(float x, int n){ return scalbn(x, n); }
+long double scalbnl(long double x, int n){ return scalbn(x, n); }
+
+float sinf(float x){ return sin(x); }
+float sinhf(float x){ return sinh(x); }
+
+float sqrtf(float x){ return sqrt(x); }
+
+float tanf(float x){ return tan(x); }
+float tanhf(float x){ return tanh(x); }
+
+//float truncf(float x){ return trunc(x); }
diff --git a/libmeidogte/Makefile b/libmeidogte/Makefile
new file mode 100644
index 0000000..938f3c2
--- /dev/null
+++ b/libmeidogte/Makefile
@@ -0,0 +1,26 @@
+include ../Makefile.cfg
+
+CFILES = $(notdir $(wildcard ./*.c))
+AFILES = $(notdir $(wildcard ./*.s))
+OFILES = $(CFILES:.c=.o) $(AFILES:.s=.o)
+
+TARGET = libmeidogte.a
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -I./ -c $< -o $@
+
+%.o: %.s
+ $(AS) $(AFLAGS) -I ./ $< -o $@
+
+clean:
+ rm -Rf $(TARGET) $(OFILES)
+
+install: all
+ cp $(TARGET) $(TOOLCHAIN_PREFIX)/lib
+ cp meidogte.h meidogte_inline.h $(TOOLCHAIN_PREFIX)/include
diff --git a/libmeidogte/applymatrixlv.s b/libmeidogte/applymatrixlv.s
new file mode 100644
index 0000000..332a2f8
--- /dev/null
+++ b/libmeidogte/applymatrixlv.s
@@ -0,0 +1,40 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global ApplyMatrixLV
+.type ApplyMatrixLV, @function
+ApplyMatrixLV:
+
+ # Load matrix to GTE
+ lw $t0, 0($a0)
+ lw $t1, 4($a0)
+ ctc2 $t0, $0
+ ctc2 $t1, $1
+ lw $t0, 8($a0)
+ lw $t1, 12($a0)
+ lhu $t2, 16($a0)
+ ctc2 $t0, $2
+ ctc2 $t1, $3
+ ctc2 $t2, $4
+
+ lw $t0, 0($a1)
+ lw $t1, 4($a1)
+ mtc2 $t0, C2_IR1
+ lw $t0, 8($a1)
+ mtc2 $t1, C2_IR2
+ mtc2 $t0, C2_IR3
+
+ nMVMVA(1, 0, 3, 3, 0)
+
+ swc2 C2_IR1, 0($a2)
+ swc2 C2_IR2, 4($a2)
+ swc2 C2_IR3, 8($a2)
+
+ jr $ra
+ move $v0, $a2
+ \ No newline at end of file
diff --git a/libmeidogte/compmatrixlv.s b/libmeidogte/compmatrixlv.s
new file mode 100644
index 0000000..f613385
--- /dev/null
+++ b/libmeidogte/compmatrixlv.s
@@ -0,0 +1,100 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.set MATRIX_r11r12, 0
+.set MATRIX_r13r21, 4
+.set MATRIX_r22r23, 8
+.set MATRIX_r31r32, 12
+.set MATRIX_r33, 16
+.set MATRIX_trx, 20
+.set MATRIX_try, 24
+.set MATRIX_trz, 28
+
+
+.global CompMatrixLV
+.type CompMatrixLV, @function
+CompMatrixLV:
+
+ # Load matrix v0 to GTE
+ lw $t0, MATRIX_r11r12($a0)
+ lw $t1, MATRIX_r13r21($a0)
+ ctc2 $t0, C2_R11R12
+ ctc2 $t1, C2_R13R21
+ lw $t0, MATRIX_r22r23($a0)
+ lw $t1, MATRIX_r31r32($a0)
+ lhu $t2, MATRIX_r33($a0)
+ ctc2 $t0, C2_R22R23
+ lw $t0, MATRIX_trx($a0)
+ ctc2 $t1, C2_R31R32
+ lw $t1, MATRIX_try($a0)
+ ctc2 $t2, C2_R33
+ lw $t2, MATRIX_trz($a0)
+ ctc2 $t0, C2_TRX
+ ctc2 $t1, C2_TRY
+ ctc2 $t2, C2_TRZ
+
+ lw $t0, MATRIX_trx($a1)
+ lw $t1, MATRIX_try($a1)
+ mtc2 $t0, C2_IR1
+ lw $t0, MATRIX_trz($a1)
+ mtc2 $t1, C2_IR2
+ mtc2 $t0, C2_IR3
+
+ nMVMVA(1, 0, 3, 0, 0)
+
+ swc2 C2_IR1, MATRIX_trx($a2)
+ swc2 C2_IR2, MATRIX_try($a2)
+ swc2 C2_IR3, MATRIX_trz($a2)
+
+ lhu $t1, 2*(0+(3*1))($a1) # Load values for first
+ lhu $t0, 2*(0+(3*0))($a1) # R11 R21 R31
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(0+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ lhu $t1, 2*(1+(3*1))($a1) # Load values for second
+ lhu $t0, 2*(1+(3*0))($a1) # R12 R22 R32
+ MVMVA(1, 0, 0, 3, 0) # First multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(1+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of first
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(0+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(0+(3*1))($a2)
+ sh $t0, 2*(0+(3*2))($a2)
+
+ lhu $t1, 2*(2+(3*1))($a1) # Load values for third
+ lhu $t0, 2*(2+(3*0))($a1) # R13 R23 R33
+ MVMVA(1, 0, 0, 3, 0) # Second multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(2+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of second
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(1+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(1+(3*1))($a2)
+ sh $t0, 2*(1+(3*2))($a2)
+ MVMVA(1, 0, 0, 3, 0) # Third multiply
+
+ mfc2 $t0, C2_IR1 # Store results of third
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(2+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(2+(3*1))($a2)
+ sh $t0, 2*(2+(3*2))($a2)
+
+ jr $ra
+ move $v0, $a2
diff --git a/libmeidogte/gtereg.h b/libmeidogte/gtereg.h
new file mode 100644
index 0000000..5d3391b
--- /dev/null
+++ b/libmeidogte/gtereg.h
@@ -0,0 +1,80 @@
+# GTE register definitions for GNU assembler (as).
+#
+# 2019 Meido-Tek Productions
+
+#
+# GTE data registers (use mfc2, mtc2, lwc2, swc2)
+#
+.set C2_VXY0, $0
+.set C2_VZ0, $1
+.set C2_VXY1, $2
+.set C2_VZ1, $3
+.set C2_VXY2, $4
+.set C2_VZ2, $5
+.set C2_RGB, $6
+.set C2_OTZ, $7
+
+.set C2_IR0, $8
+.set C2_IR1, $9
+.set C2_IR2, $10
+.set C2_IR3, $11
+.set C2_SXY0, $12
+.set C2_SXY1, $13
+.set C2_SXY2, $14
+.set C2_SXYP, $15
+
+.set C2_SZ0, $16
+.set C2_SZ1, $17
+.set C2_SZ2, $18
+.set C2_SZ3, $19
+.set C2_RGB0, $20
+.set C2_RGB1, $21
+.set C2_RGB2, $22
+
+.set C2_MAC0, $24
+.set C2_MAC1, $25
+.set C2_MAC2, $26
+.set C2_MAC3, $27
+.set C2_IRGB, $28
+.set C2_ORGB, $29
+.set C2_LZCS, $30
+.set C2_LZCR, $31
+
+#
+# GTE control registers (use cfc2/ctc2)
+#
+.set C2_R11R12, $0
+.set C2_R13R21, $1
+.set C2_R22R23, $2
+.set C2_R31R32, $3
+.set C2_R33, $4
+.set C2_TRX, $5
+.set C2_TRY, $6
+.set C2_TRZ, $7
+
+.set C2_L11L12, $8
+.set C2_L13L21, $9
+.set C2_L22L23, $10
+.set C2_L31L32, $11
+.set C2_L33, $12
+.set C2_RBK, $13
+.set C2_GBK, $14
+.set C2_BBK, $15
+
+.set C2_LR1LR2, $16
+.set C2_LR3LG1, $17
+.set C2_LG2LG3, $18
+.set C2_LB1LB2, $19
+.set C2_LB3, $20
+.set C2_RFC, $21
+.set C2_GFC, $22
+.set C2_BFC, $23
+
+.set C2_OFX, $24
+.set C2_OFY, $25
+.set C2_H, $26
+.set C2_DQA, $27
+.set C2_DQB, $28
+.set C2_ZSF3, $29
+.set C2_ZSF4, $30
+.set C2_FLAG, $31
diff --git a/libmeidogte/hirotmatrix.c b/libmeidogte/hirotmatrix.c
new file mode 100644
index 0000000..5a252ff
--- /dev/null
+++ b/libmeidogte/hirotmatrix.c
@@ -0,0 +1,35 @@
+#include <meidogte.h>
+
+MATRIX *HiRotMatrix(VECTOR *r, MATRIX *m) {
+
+ short s[3],c[3];
+ MATRIX tm[3];
+
+ s[0] = hisin(r->vx); s[1] = hisin(r->vy); s[2] = hisin(r->vz);
+ c[0] = hicos(r->vx); c[1] = hicos(r->vy); c[2] = hicos(r->vz);
+
+ // mX
+ m->m[0][0] = ONE; m->m[0][1] = 0; m->m[0][2] = 0;
+ m->m[1][0] = 0; m->m[1][1] = c[0]; m->m[1][2] = -s[0];
+ m->m[2][0] = 0; m->m[2][1] = s[0]; m->m[2][2] = c[0];
+
+ // mY
+ tm[0].m[0][0] = c[1]; tm[0].m[0][1] = 0; tm[0].m[0][2] = s[1];
+ tm[0].m[1][0] = 0; tm[0].m[1][1] = ONE; tm[0].m[1][2] = 0;
+ tm[0].m[2][0] = -s[1]; tm[0].m[2][1] = 0; tm[0].m[2][2] = c[1];
+
+ // mZ
+ tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0;
+ tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0;
+ tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE;
+
+ PushMatrix();
+
+ MulMatrix0( m, &tm[0], &tm[2] );
+ MulMatrix0( &tm[2], &tm[1], m );
+
+ PopMatrix();
+
+ return m;
+
+}
diff --git a/libmeidogte/hisin.c b/libmeidogte/hisin.c
new file mode 100644
index 0000000..df03194
--- /dev/null
+++ b/libmeidogte/hisin.c
@@ -0,0 +1,33 @@
+/* Based on isin_S4 implementation from coranac:
+ * http://www.coranac.com/2009/07/sines/
+ *
+ */
+
+#define qN 15
+#define qA 12
+#define B 19900
+#define C 3516
+
+int hisin(int x) {
+
+ int c, y;
+
+ c= x<<(30-qN); // Semi-circle info into carry.
+ x -= 1<<qN; // sine -> cosine calc
+
+ x= x<<(31-qN); // Mask with PI
+ x= x>>(31-qN); // Note: SIGNED shift! (to qN)
+ x= x*x>>(2*qN-14); // x=x^2 To Q14
+
+ y= B - (x*C>>14); // B - x^2*C
+ y= (1<<qA)-(x*y>>16); // A - x^2*(B-x^2*C)
+
+ return c>=0 ? y : -y;
+
+}
+
+int hicos(int x) {
+
+ return hisin( x+32768 );
+
+}
diff --git a/libmeidogte/initgeom.s b/libmeidogte/initgeom.s
new file mode 100644
index 0000000..14ca293
--- /dev/null
+++ b/libmeidogte/initgeom.s
@@ -0,0 +1,45 @@
+.set noreorder
+
+.include "gtereg.h"
+
+.section .text
+
+
+.global InitGeom
+.type InitGeom, @function
+InitGeom:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ jal EnterCriticalSection
+ nop
+
+ mfc0 $v0, $12 # Get SR
+ lui $v1, 0x4000 # Set bit to enable cop2
+ or $v0, $v1
+ mtc0 $v0, $12 # Set new SR
+
+ jal ExitCriticalSection
+ nop
+
+ ctc2 $0 , $24 # Reset GTE offset
+ ctc2 $0 , $25
+
+ li $v0, 320 # Set default projection plane
+ ctc2 $v0, $26
+
+ li $v0, 0x155 # Set ZSF3 and ZSF4 defaults
+ ctc2 $v0, $29
+ li $v0, 0x100
+ ctc2 $v0, $30
+
+ li $v0, 0xef9e # DQA and DQB defaults
+ lui $v1, 0x0140
+ ctc2 $v0, C2_DQA
+ ctc2 $v1, C2_DQB
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
diff --git a/libmeidogte/inline_s.h b/libmeidogte/inline_s.h
new file mode 100644
index 0000000..08e5c38
--- /dev/null
+++ b/libmeidogte/inline_s.h
@@ -0,0 +1,227 @@
+# Inline GTE macros for GNU assembler (as).
+#
+# 2019 Meido-Tek Productions
+#
+
+.macro nRTPS
+ nop
+ nop
+ cop2 0x0180001
+.endm
+
+.macro nRTPT
+ nop
+ nop
+ cop2 0x0280030
+.endm
+
+.macro nNCLIP
+ nop
+ nop
+ cop2 0x1400006
+.endm
+
+.macro nAVSZ3
+ nop
+ nop
+ cop2 0x158002D
+.endm
+
+.macro nAVSZ4
+ nop
+ nop
+ cop2 0x168002E
+.endm
+
+.macro nMVMVA sf mx v cv lm
+ nop
+ nop
+ cop2 0x0400012|(\sf<<19)|(\mx<<17)|(\v<<15)|(\cv<<13)|(\lm<<10)
+.endm
+
+.macro nSQR sf
+ nop
+ nop
+ cop2 0x0A00428|(\sf<<19)
+.endm
+
+.macro nnOP sf lm # extra n to prevent conflict with the nop opcode
+ nop
+ nop
+ cop2 0x170000C|(\sf<<19)|(\lm<<10)
+.endm
+
+.macro nNCS
+ nop
+ nop
+ cop2 0x0C8041E
+.endm
+
+.macro nNCT
+ nop
+ nop
+ cop2 0x0D80420
+.endm
+
+.macro nNCCS
+ nop
+ nop
+ cop2 0x108041B
+.endm
+
+.macro nNCCT
+ nop
+ nop
+ cop2 0x118043F
+.endm
+
+.macro nNCDS
+ nop
+ nop
+ cop2 0x0E80413
+.endm
+
+.macro nNCDT
+ nop
+ nop
+ cop2 0x0F80416
+.endm
+
+.macro nCC
+ nop
+ nop
+ cop2 0x138041C
+.endm
+
+.macro nCDP
+ nop
+ nop
+ cop2 0x1280414
+.endm
+
+.macro nDCPL
+ nop
+ nop
+ cop2 0x0680029
+.endm
+
+.macro nDPCS
+ nop
+ nop
+ cop2 0x0780010
+.endm
+
+.macro nDPCT
+ nop
+ nop
+ cop2 0x0180001
+.endm
+
+.macro nINTPL
+ nop
+ nop
+ cop2 0x0980011
+.endm
+
+.macro nGPF sf
+ nop
+ nop
+ cop2 0x190003D|(\sf<<19)
+.endm
+
+.macro nGPL sf
+ nop
+ nop
+ cop2 0x1A0003E|(\sf<<19)
+.endm
+
+#
+# Macros without leading nops (for optimized usage)
+#
+.macro RTPS
+ cop2 0x0180001
+.endm
+
+.macro RTPT
+ cop2 0x0280030
+.endm
+
+.macro NCLIP
+ cop2 0x1400006
+.endm
+
+.macro AVSZ3
+ cop2 0x158002D
+.endm
+
+.macro AVSZ4
+ cop2 0x168002E
+.endm
+
+.macro MVMVA sf mx v cv lm
+ cop2 0x0400012|(\sf<<19)|(\mx<<17)|(\v<<15)|(\cv<<13)|(\lm<<10)
+.endm
+
+.macro SQR sf
+ cop2 0x0A00428|(\sf<<19)
+.endm
+
+.macro OP sf lm
+ cop2 0x170000C|(\sf<<19)|(\lm<<10)
+.endm
+
+.macro NCS
+ cop2 0x0C8041E
+.endm
+
+.macro NCT
+ cop2 0x0D80420
+.endm
+
+.macro NCCS
+ cop2 0x108041B
+.endm
+
+.macro NCCT
+ cop2 0x118043F
+.endm
+
+.macro NCDS
+ cop2 0x0E80413
+.endm
+
+.macro NCDT
+ cop2 0x0F80416
+.endm
+
+.macro CC
+ cop2 0x138041C
+.endm
+
+.macro CDP
+ cop2 0x1280414
+.endm
+
+.macro DCPL
+ cop2 0x0680029
+.endm
+
+.macro DPCS
+ cop2 0x0780010
+.endm
+
+.macro DPCT
+ cop2 0x0180001
+.endm
+
+.macro INTPL
+ cop2 0x0980011
+.endm
+
+.macro GPF sf
+ cop2 0x190003D|(\sf<<19)
+.endm
+
+.macro GPL sf
+ cop2 0x1A0003E|(\sf<<19)
+.endm
diff --git a/libmeidogte/isin.c b/libmeidogte/isin.c
new file mode 100644
index 0000000..3641efd
--- /dev/null
+++ b/libmeidogte/isin.c
@@ -0,0 +1,34 @@
+/* Based on isin_S4 implementation from coranac:
+ * http://www.coranac.com/2009/07/sines/
+ *
+ */
+
+#define qN 10
+#define qA 12
+#define B 19900
+#define C 3516
+
+int isin(int x) {
+
+ int c, y;
+
+ c= x<<(30-qN); // Semi-circle info into carry.
+ x -= 1<<qN; // sine -> cosine calc
+
+ x= x<<(31-qN); // Mask with PI
+ x= x>>(31-qN); // Note: SIGNED shift! (to qN)
+
+ x= x*x>>(2*qN-14); // x=x^2 To Q14
+
+ y= B - (x*C>>14); // B - x^2*C
+ y= (1<<qA)-(x*y>>16); // A - x^2*(B-x^2*C)
+
+ return c>=0 ? y : -y;
+
+}
+
+int icos(int x) {
+
+ return isin( x+1024 );
+
+}
diff --git a/libmeidogte/matrix.c b/libmeidogte/matrix.c
new file mode 100644
index 0000000..1c226e1
--- /dev/null
+++ b/libmeidogte/matrix.c
@@ -0,0 +1,45 @@
+#include <meidogte.h>
+
+MATRIX *RotMatrix(SVECTOR *r, MATRIX *m) {
+
+ short s[3],c[3];
+ MATRIX tm[3];
+
+ s[0] = isin(r->vx); s[1] = isin(r->vy); s[2] = isin(r->vz);
+ c[0] = icos(r->vx); c[1] = icos(r->vy); c[2] = icos(r->vz);
+
+ // mX
+ m->m[0][0] = ONE; m->m[0][1] = 0; m->m[0][2] = 0;
+ m->m[1][0] = 0; m->m[1][1] = c[0]; m->m[1][2] = -s[0];
+ m->m[2][0] = 0; m->m[2][1] = s[0]; m->m[2][2] = c[0];
+
+ // mY
+ tm[0].m[0][0] = c[1]; tm[0].m[0][1] = 0; tm[0].m[0][2] = s[1];
+ tm[0].m[1][0] = 0; tm[0].m[1][1] = ONE; tm[0].m[1][2] = 0;
+ tm[0].m[2][0] = -s[1]; tm[0].m[2][1] = 0; tm[0].m[2][2] = c[1];
+
+ // mZ
+ tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0;
+ tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0;
+ tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE;
+
+ PushMatrix();
+
+ MulMatrix0( m, &tm[0], &tm[2] );
+ MulMatrix0( &tm[2], &tm[1], m );
+
+ PopMatrix();
+
+ return m;
+
+}
+
+MATRIX *TransMatrix(MATRIX *m, VECTOR *r) {
+
+ m->t[0] = r->vx;
+ m->t[1] = r->vy;
+ m->t[2] = r->vz;
+
+ return m;
+
+}
diff --git a/libmeidogte/meidogte.h b/libmeidogte/meidogte.h
new file mode 100644
index 0000000..3953701
--- /dev/null
+++ b/libmeidogte/meidogte.h
@@ -0,0 +1,170 @@
+#ifndef _MEIDOGTE_H
+#define _MEIDOGTE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <meidogte_inline.h>
+
+/**
+ * One degree = 4096
+ */
+#define ONE 4096
+
+
+typedef struct {
+ short m[3][3];
+ int t[3];
+} MATRIX;
+
+typedef struct {
+ int vx, vy, vz;
+} VECTOR;
+
+typedef struct {
+ short vx, vy, vz, pad;
+} SVECTOR;
+
+typedef struct {
+ unsigned char r, g, b, cd;
+} CVECTOR;
+
+/**
+ * Initialize MeidoGTE library
+ */
+
+void InitGeom();
+
+/**
+ * Integer sine function (4096 = 360 degrees)
+ * @param a Input
+ * @return Sine of input
+ */
+int isin(int a);
+
+/**
+ * Integer cosine function (4096 = 360 degrees)
+ * @param a Input
+ * @return Cosine of input
+ */
+int icos(int a);
+
+/**
+ * Higher precision integer sine function (131072 = 360 degrees)
+ * @param a Input
+ * @return Sine of input
+ */
+int hisin(int a);
+/**
+ * Higher precision integer cosine function (131072 = 360 degrees)
+ * @param a Input
+ * @return Cosine of input
+ */
+int hicos(int a);
+
+/**
+ * Save a constant rotation matrix in stack.
+ */
+void PushMatrix();
+
+/**
+ * Reset a constant rotation matrix from stack.
+ */
+void PopMatrix();
+
+/**
+ * Find rotation matrix from a rotation angle. (4096 = 360 degrees)
+ * @param r Rotation angle (input)
+ * @param m Rotation matrix (output)
+ * @return Pointer to m
+ */
+
+MATRIX *RotMatrix(SVECTOR *r, MATRIX *m);
+
+/**
+ * Find rotation matrix from a rotation angle. (high-precision) (131072 = 360 degrees)
+ * @param r Rotation angle (input)
+ * @param m Rotation matrix (output)
+ * @return Pointer to m
+ */
+MATRIX *HiRotMatrix(VECTOR *r, MATRIX *m);
+
+/**
+ * Give an amount of parallel transfer expressed by v to the matrix m.
+ * @param m Pointer to matrix (output)
+ * @param v Pointer to transfer vector (input)
+ * @return Pointer to m
+ */
+MATRIX *TransMatrix(MATRIX *m, VECTOR *r);
+/**
+ * Scale m by v.
+ * @param m Pointer to matrix (output)
+ * @param v Pointer to scale vector (input)
+ * @return Pointer to m
+ */
+MATRIX *ScaleMatrix(MATRIX *m, VECTOR *s);
+
+/**
+ * Multiply two matrices.
+ * @param m0 First matrix (result is saved here)
+ * @param m1 Second matrix
+ * @return Pointer to m0.
+ */
+MATRIX *MulMatrix(MATRIX *m0, MATRIX *m1);
+/**
+ * Multiply two matrices.
+ * @param m0 First matrix
+ * @param m1 Second matrix
+ * @param m2 Output matrix
+ * @return Pointer to m2
+ */
+MATRIX *MulMatrix0(MATRIX *m0, MATRIX *m1, MATRIX *m2);
+/**
+ * Make a composite coordinate transformation matrix.
+ * @param m0 First matrix
+ * @param m1 Second matrix
+ * @param m2 Output matrix
+ * @return Pointer to m2
+ */
+MATRIX *CompMatrixLV(MATRIX *v0, MATRIX *v1, MATRIX *v2);
+/**
+ * Multiply a vector by a matrix.
+ * @param m Pointer to matrix to be multiplied
+ * @param v0 Pointer to vector (input)
+ * @param v1 Pointer to vector (output)
+ * @return Pointer to v1
+ */
+VECTOR *ApplyMatrixLV(MATRIX *m, VECTOR *v0, VECTOR *v1);
+/**
+ * Normalize a vector.
+ * Warning: if ((v0->vx)^2 + (v1->vx)^2 +(v2->vx)^2) > 0x7FFFFFF,
+ * a processor exception will occur.
+ * @param v0 Pointer to vector (input)
+ * @param v1 Pointer to vector (output)
+ */
+void VectorNormalS(VECTOR *v0, SVECTOR *v1);
+/**
+ * Return a vector, obtained by squaring each term of the vector v0, to v1.
+ * @param v0 Pointer to vector (input)
+ * @param v1 Pointer to vector (output)
+ */
+void Square0(VECTOR *v0, VECTOR *v1);
+/**
+ * Square root
+ * @param a Input value
+ * @return Square root of input value
+ */
+int SquareRoot0(int a);
+/**
+ * Square root
+ * @param a Input value in (0, 20, 12) format
+ * @return Square root of input value in (0, 20, 12) format
+ */
+int SquareRoot12(int a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _MEIDOGTE_H
diff --git a/libmeidogte/meidogte_inline.h b/libmeidogte/meidogte_inline.h
new file mode 100644
index 0000000..ab03702
--- /dev/null
+++ b/libmeidogte/meidogte_inline.h
@@ -0,0 +1,433 @@
+/* Inline GTE macros for the GNU C compiler.
+ *
+ * 2019 Meido-Tek Production
+ *
+ *
+ *
+ * Todo: A couple of GTE operation macros are still missing such as
+ * gte_rtv*() though they appear to be just variants of gte_mvmva more or
+ * less (gte_rtv0() is actually gte_mvmva(1, 0, 0, 3, 0) for example).
+ *
+ */
+
+#ifndef _MEIDOGTE_INLINE_C_H
+#define _MEIDOGTE_INLINE_C_H
+
+/**
+ * GTE load macros
+ */
+
+/**
+ * Load a SVECTOR (passed as a pointer) to GTE V0
+ */
+#define gte_ldv0( r0 ) __asm__ volatile ( \
+ "lwc2 $0 , 0( %0 );" \
+ "lwc2 $1 , 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "$t0" )
+
+/**
+ * Load a SVECTOR (passed as a pointer) to GTE V1
+ */
+#define gte_ldv1( r0 ) __asm__ volatile ( \
+ "lwc2 $2 , 0( %0 );" \
+ "lwc2 $3 , 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "$t0" )
+
+/**
+ * Load a SVECTOR (passed as a pointer) to GTE V2
+ */
+#define gte_ldv2( r0 ) __asm__ volatile ( \
+ "lwc2 $4 , 0( %0 );" \
+ "lwc2 $5 , 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "$t0" )
+
+/**
+ * Load three SVECTORs (passed as a pointer) to the GTE at once
+ */
+#define gte_ldv3( r0, r1, r2 ) __asm__ volatile ( \
+ "lwc2 $0 , 0( %0 );" \
+ "lwc2 $1 , 4( %0 );" \
+ "lwc2 $2 , 0( %1 );" \
+ "lwc2 $3 , 4( %1 );" \
+ "lwc2 $4 , 0( %2 );" \
+ "lwc2 $5 , 4( %2 );" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) )
+
+#define gte_ldrgb( r0 ) __asm__ volatile ( \
+ "lwc2 $6 , 0( %0 );" \
+ : \
+ : "r"( r0 ) )
+
+#define gte_ldopv2( r0 ) __asm__ volatile ( \
+ "lwc2 $11, 8( %0 );" \
+ "lwc2 $9 , 0( %0 );" \
+ "lwc2 $10, 4( %0 );" \
+ : \
+ : "r"( r0 ) )
+
+/**
+ * Sets the GTE offset
+ */
+#define gte_SetGeomOffset( r0, r1 ) __asm__ volatile ( \
+ "sll $t0, %0, 16;" \
+ "sll $t1, %1, 16;" \
+ "ctc2 $t0, $24;" \
+ "ctc2 $t1, $25;" \
+ : \
+ : "r"( r0 ), "r"( r1 ) \
+ : "$t0", "$t1" )
+
+#define gte_SetGeomScreen( r0 ) __asm__ volatile ( \
+ "ctc2 %0, $26;" \
+ : \
+ : "r"( r0 ) )
+
+#define gte_SetTransMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 20( %0 );" \
+ "lw $t1, 24( %0 );" \
+ "ctc2 $t0, $5;" \
+ "lw $t2, 28( %0 );" \
+ "ctc2 $t1, $6;" \
+ "ctc2 $t2, $7;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetRotMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 0( %0 );" \
+ "lw $t1, 4( %0 );" \
+ "ctc2 $t0, $0;" \
+ "ctc2 $t1, $1;" \
+ "lw $t0, 8( %0 );" \
+ "lw $t1, 12( %0 );" \
+ "lhu $t2, 16( %0 );" \
+ "ctc2 $t0, $2;" \
+ "ctc2 $t1, $3;" \
+ "ctc2 $t2, $4;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetLightMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 0( %0 );" \
+ "lw $t1, 4( %0 );" \
+ "ctc2 $t0, $8;" \
+ "ctc2 $t1, $9;" \
+ "lw $t0, 8( %0 );" \
+ "lw $t1, 12( %0 );" \
+ "lhu $t2, 16( %0 );" \
+ "ctc2 $t0, $10;" \
+ "ctc2 $t1, $11;" \
+ "ctc2 $t2, $12;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetColorMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 0( %0 );" \
+ "lw $t1, 4( %0 );" \
+ "ctc2 $t0, $16;" \
+ "ctc2 $t1, $17;" \
+ "lw $t0, 8( %0 );" \
+ "lw $t1, 12( %0 );" \
+ "lhu $t2, 16( %0 );" \
+ "ctc2 $t0, $18;" \
+ "ctc2 $t1, $19;" \
+ "ctc2 $t2, $20;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetBackColor( r0, r1, r2 ) __asm__ volatile ( \
+ "sll $t0, %0, 4;" \
+ "sll $t1, %1, 4;" \
+ "sll $t2, %2, 4;" \
+ "ctc2 $t0, $13;" \
+ "ctc2 $t1, $14;" \
+ "ctc2 $t2, $15;" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) \
+ : "$t0", "$t1", "$t2" )
+
+/**
+ * GTE store macros
+ */
+
+#define gte_otz( r0 ) __asm__ volatile ( \
+ "swc2 $7, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stflg( r0 ) __asm__ volatile ( \
+ "cfc2 $t0, $31;" \
+ "nop;" \
+ "sw $t0, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy( r0 ) __asm__ volatile ( \
+ "swc2 $14, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy0( r0 ) __asm__ volatile ( \
+ "swc2 $12, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy1( r0 ) __asm__ volatile ( \
+ "swc2 $13, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy2( r0 ) __asm__ volatile ( \
+ "swc2 $14, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy3( r0, r1, r2 ) __asm__ volatile ( \
+ "swc2 $12, 0( %0 );" \
+ "swc2 $13, 0( %1 );" \
+ "swc2 $14, 0( %2 );" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) \
+ : "memory" )
+
+#define gte_stotz( r0 ) __asm__ volatile ( \
+ "swc2 $7, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stopz( r0 ) __asm__ volatile ( \
+ "swc2 $24, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_strgb( r0 ) __asm__ volatile ( \
+ "swc2 $22, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_strgb3( r0, r1, r2 ) __asm__ volatile ( \
+ "swc2 $20, 0( %0 );" \
+ "swc2 $21, 0( %1 );" \
+ "swc2 $22, 0( %2 );" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r" ( r2 ) \
+ : "memory" )
+
+#define gte_stsv( r0 ) __asm__ volatile ( \
+ "mfc2 $t0, $9;" \
+ "mfc2 $t1, $10;" \
+ "mfc2 $t2, $11;" \
+ "sh $t0, 0( %0 );" \
+ "sh $t1, 2( %0 );" \
+ "sh $t2, 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stlvnl( r0 ) __asm__ volatile ( \
+ "swc2 $25, 0( %0 );" \
+ "swc2 $26, 4( %0 );" \
+ "swc2 $27, 8( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+
+/**
+ * GTE operation macros
+ */
+
+#define gte_rtps() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0180001;" )
+
+#define gte_rtpt() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0280030;" )
+
+#define gte_nclip() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1400006;" )
+
+#define gte_avsz3() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x158002D;" )
+
+#define gte_avsz4() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x168002E;" )
+
+#define gte_sqr0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0A00428;" )
+
+#define gte_sqr12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0A80428;" )
+
+#define gte_op0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x170000C;" )
+
+#define gte_op12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x178000C;" )
+
+#define gte_ncs() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0C8041E;" )
+
+#define gte_nct() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0D80420;" )
+
+#define gte_nccs() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x108041B;" ) \
+
+#define gte_ncct() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x118043F;" )
+
+#define gte_ncds() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0E80413;" )
+
+#define gte_ncdt() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0F80416;" )
+
+#define gte_cc() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x138041C;" )
+
+#define gte_cdp() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1280414;" )
+
+#define gte_dcpl() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0680029;" )
+
+#define gte_dpcs() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0780010;" )
+
+#define gte_dpct() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0180001;" )
+
+#define gte_intpl() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0980011;" )
+
+#define gte_gpf0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x190003D;" )
+
+#define gte_gpf12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x198003D;" )
+
+#define gte_gpl0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1A0003E;" )
+
+#define gte_gpl12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1A8003E;" )
+
+#define gte_mvmva_core( r0 ) __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 %0" \
+ : \
+ : "g"( r0 ) )
+
+#define gte_mvmva(sf, mx, v, cv, lm) gte_mvmva_core( 0x0400012 | \
+ ((sf)<<19) | ((mx)<<17) | ((v)<<15) | ((cv)<<13) | ((lm)<<10) )
+
+
+/**
+ * GTE operation macros without leading nops
+ *
+ * Checking assembler output when using these is advised.
+ */
+
+#define gte_rtps_b() __asm__ volatile ( "cop2 0x0180001;" )
+#define gte_rtpt_b() __asm__ volatile ( "cop2 0x0280030;" )
+#define gte_nclip_b() __asm__ volatile ( "cop2 0x1400006;" )
+#define gte_avsz3_b() __asm__ volatile ( "cop2 0x158002D;" )
+#define gte_avsz4_b() __asm__ volatile ( "cop2 0x168002E;" )
+#define gte_sqr0_b() __asm__ volatile ( "cop2 0x0A00428;" )
+#define gte_sqr12_b() __asm__ volatile ( "cop2 0x0A80428;" )
+#define gte_op0_b() __asm__ volatile ( "cop2 0x170000C;" )
+#define gte_op12_b() __asm__ volatile ( "cop2 0x178000C;" )
+#define gte_ncs_b() __asm__ volatile ( "cop2 0x0C8041E;" )
+#define gte_nct_b() __asm__ volatile ( "cop2 0x0D80420;" )
+#define gte_nccs_b() __asm__ volatile ( "cop2 0x108041B;" )
+#define gte_ncct_b() __asm__ volatile ( "cop2 0x118043F;" )
+#define gte_ncds_b() __asm__ volatile ( "cop2 0x0E80413;" )
+#define gte_ncdt_b() __asm__ volatile ( "cop2 0x0F80416;" )
+#define gte_cc_b() __asm__ volatile ( "cop2 0x138041C;" )
+#define gte_cdp_b() __asm__ volatile ( "cop2 0x1280414;" )
+#define gte_dcpl_b() __asm__ volatile ( "cop2 0x0680029;" )
+#define gte_dpcs_b() __asm__ volatile ( "cop2 0x0780010;" )
+#define gte_dpct_b() __asm__ volatile ( "cop2 0x0180001;" )
+#define gte_intpl_b() __asm__ volatile ( "cop2 0x0980011;" )
+#define gte_gpf0_b() __asm__ volatile ( "cop2 0x190003D;" )
+#define gte_gpf12_b() __asm__ volatile ( "cop2 0x198003D;" )
+#define gte_gpl0_b() __asm__ volatile ( "cop2 0x1A0003E;" )
+#define gte_gpl12_b() __asm__ volatile ( "cop2 0x1A8003E;" )
+#define gte_mvmva_core_b( r0 ) __asm__ volatile ( \
+ "cop2 %0" \
+ : \
+ : "g"( r0 ) )
+#define gte_mvmva_b(sf, mx, v, cv, lm) gte_mvmva_core_b( 0x0400012 | \
+ ((sf)<<19) | ((mx)<<17) | ((v)<<15) | ((cv)<<13) | ((lm)<<10) )
+
+#endif // _MEIDOGTE_INLINE_C_H \ No newline at end of file
diff --git a/libmeidogte/mulmatrix.s b/libmeidogte/mulmatrix.s
new file mode 100644
index 0000000..19dabe8
--- /dev/null
+++ b/libmeidogte/mulmatrix.s
@@ -0,0 +1,74 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global MulMatrix
+.type MulMatrix, @function
+MulMatrix:
+
+ # Load m1 to GTE
+ lw $t0, 0($a1)
+ lw $t1, 4($a1)
+ ctc2 $t0, $0
+ ctc2 $t1, $1
+ lw $t0, 8($a1)
+ lw $t1, 12($a1)
+ lhu $t2, 16($a1)
+ ctc2 $t0, $2
+ ctc2 $t1, $3
+ ctc2 $t2, $4
+
+ lhu $t1, 2*(0+(3*1))($a0) # Load values for first
+ lhu $t0, 2*(0+(3*0))($a0) # R11 R21 R31
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(0+(3*2))($a0)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ lhu $t1, 2*(1+(3*1))($a0) # Load values for second
+ lhu $t0, 2*(1+(3*0))($a0) # R12 R22 R32
+ MVMVA(1, 0, 0, 3, 0) # First multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(1+(3*2))($a0)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of first
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(0+(3*0))($a0)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(0+(3*1))($a0)
+ sh $t0, 2*(0+(3*2))($a0)
+
+ lhu $t1, 2*(2+(3*1))($a0) # Load values for third
+ lhu $t0, 2*(2+(3*0))($a0) # R13 R23 R33
+ MVMVA(1, 0, 0, 3, 0) # Second multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(2+(3*2))($a0)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of second
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(1+(3*0))($a0)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(1+(3*1))($a0)
+ sh $t0, 2*(1+(3*2))($a0)
+ MVMVA(1, 0, 0, 3, 0) # Third multiply
+
+ mfc2 $t0, C2_IR1 # Store results of third
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(2+(3*0))($a0)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(2+(3*1))($a0)
+ sh $t0, 2*(2+(3*2))($a0)
+
+ jr $ra
+ move $v0, $a0
diff --git a/libmeidogte/mulmatrix0.s b/libmeidogte/mulmatrix0.s
new file mode 100644
index 0000000..874226b
--- /dev/null
+++ b/libmeidogte/mulmatrix0.s
@@ -0,0 +1,74 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global MulMatrix0
+.type MulMatrix0, @function
+MulMatrix0:
+
+ # Load m1 to GTE
+ lw $t0, 0($a0)
+ lw $t1, 4($a0)
+ ctc2 $t0, $0
+ ctc2 $t1, $1
+ lw $t0, 8($a0)
+ lw $t1, 12($a0)
+ lhu $t2, 16($a0)
+ ctc2 $t0, $2
+ ctc2 $t1, $3
+ ctc2 $t2, $4
+
+ lhu $t1, 2*(0+(3*1))($a1) # Load values for first
+ lhu $t0, 2*(0+(3*0))($a1) # R11 R21 R31
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(0+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ lhu $t1, 2*(1+(3*1))($a1) # Load values for second
+ lhu $t0, 2*(1+(3*0))($a1) # R12 R22 R32
+ MVMVA(1, 0, 0, 3, 0) # First multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(1+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of first
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(0+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(0+(3*1))($a2)
+ sh $t0, 2*(0+(3*2))($a2)
+
+ lhu $t1, 2*(2+(3*1))($a1) # Load values for third
+ lhu $t0, 2*(2+(3*0))($a1) # R13 R23 R33
+ MVMVA(1, 0, 0, 3, 0) # Second multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(2+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of second
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(1+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(1+(3*1))($a2)
+ sh $t0, 2*(1+(3*2))($a2)
+ MVMVA(1, 0, 0, 3, 0) # Third multiply
+
+ mfc2 $t0, C2_IR1 # Store results of third
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(2+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(2+(3*1))($a2)
+ sh $t0, 2*(2+(3*2))($a2)
+
+ jr $ra
+ move $v0, $a2
diff --git a/libmeidogte/pushpopmatrix.s b/libmeidogte/pushpopmatrix.s
new file mode 100644
index 0000000..d10687a
--- /dev/null
+++ b/libmeidogte/pushpopmatrix.s
@@ -0,0 +1,68 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global PushMatrix
+.type PushMatrix, @function
+PushMatrix:
+ la $a0, _matrix_stack
+ cfc2 $v0, C2_R11R12
+ cfc2 $v1, C2_R13R21
+ sw $v0, 0($a0)
+ cfc2 $v0, C2_R22R23
+ sw $v1, 4($a0)
+ sw $v0, 8($a0)
+ cfc2 $v0, C2_R31R32
+ cfc2 $v1, C2_R33
+ sw $v0, 12($a0)
+ sw $v1, 16($a0)
+ cfc2 $v0, C2_TRX
+ cfc2 $v1, C2_TRY
+ sw $v0, 20($a0)
+ cfc2 $v0, C2_TRZ
+ sw $v1, 24($a0)
+ jr $ra
+ sw $v0, 28($a0)
+
+.global PopMatrix
+.type PopMatrix, @function
+PopMatrix:
+ la $a0, _matrix_stack
+ lw $v0, 0($a0)
+ lw $v1, 4($a0)
+ ctc2 $v0, C2_R11R12
+ ctc2 $v1, C2_R13R21
+ lw $v0, 8($a0)
+ lw $v1, 12($a0)
+ ctc2 $v0, C2_R22R23
+ lw $v0, 16($a0)
+ ctc2 $v1, C2_R31R32
+ ctc2 $v0, C2_R33
+ lw $v0, 20($a0)
+ lw $v1, 24($a0)
+ ctc2 $v0, C2_TRX
+ lw $v0, 28($a0)
+ ctc2 $v1, C2_TRY
+ ctc2 $v0, C2_TRZ
+ jr $ra
+ nop
+
+
+.section .data
+
+
+.type matrix_stack, @object
+_matrix_stack:
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+
diff --git a/libmeidogte/scalematrix.s b/libmeidogte/scalematrix.s
new file mode 100644
index 0000000..3e83800
--- /dev/null
+++ b/libmeidogte/scalematrix.s
@@ -0,0 +1,68 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global ScaleMatrix
+.type ScaleMatrix, @function
+ScaleMatrix:
+
+ lwc2 C2_IR0, 0($a1) # X
+
+ lh $v0, 2*(0+(3*0))($a0)
+ lh $v1, 2*(0+(3*1))($a0)
+ mtc2 $v0, C2_IR1
+ lh $v0, 2*(0+(3*2))($a0)
+ mtc2 $v1, C2_IR2
+ mtc2 $v0, C2_IR3
+
+ nGPF(1)
+
+ mfc2 $v0, C2_IR1
+ mfc2 $v1, C2_IR2
+ sh $v0, 2*(0+(3*0))($a0)
+ mfc2 $v0, C2_IR3
+ sh $v1, 2*(0+(3*1))($a0)
+ sh $v0, 2*(0+(3*2))($a0)
+
+ lwc2 C2_IR0, 4($a1) # Y
+
+ lh $v0, 2*(1+(3*0))($a0)
+ lh $v1, 2*(1+(3*1))($a0)
+ mtc2 $v0, C2_IR1
+ lh $v0, 2*(1+(3*2))($a0)
+ mtc2 $v1, C2_IR2
+ mtc2 $v0, C2_IR3
+
+ nGPF(1)
+
+ mfc2 $v0, C2_IR1
+ mfc2 $v1, C2_IR2
+ sh $v0, 2*(1+(3*0))($a0)
+ mfc2 $v0, C2_IR3
+ sh $v1, 2*(1+(3*1))($a0)
+ sh $v0, 2*(1+(3*2))($a0)
+
+ lwc2 C2_IR0, 8($a1) # Z
+
+ lh $v0, 2*(2+(3*0))($a0)
+ lh $v1, 2*(2+(3*1))($a0)
+ mtc2 $v0, C2_IR1
+ lh $v0, 2*(2+(3*2))($a0)
+ mtc2 $v1, C2_IR2
+ mtc2 $v0, C2_IR3
+
+ nGPF(1)
+
+ mfc2 $v0, C2_IR1
+ mfc2 $v1, C2_IR2
+ sh $v0, 2*(2+(3*0))($a0)
+ mfc2 $v0, C2_IR3
+ sh $v1, 2*(2+(3*1))($a0)
+ sh $v0, 2*(2+(3*2))($a0)
+
+ jr $ra
+ move $v0, $a0
diff --git a/libmeidogte/square0.s b/libmeidogte/square0.s
new file mode 100644
index 0000000..d037b7e
--- /dev/null
+++ b/libmeidogte/square0.s
@@ -0,0 +1,27 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global Square0
+.type Square0, @function
+Square0:
+
+ # a0 - Pointer to input vector (v0)
+ # a1 - Pointer to output vector (v1)
+
+ lwc2 C2_IR1, 0($a0)
+ lwc2 C2_IR2, 4($a0)
+ lwc2 C2_IR3, 8($a0)
+
+ nSQR(0)
+
+ swc2 C2_IR1, 0($a1)
+ swc2 C2_IR2, 4($a1)
+ swc2 C2_IR3, 8($a1)
+
+ jr $ra
+ nop
diff --git a/libmeidogte/squareroot.s b/libmeidogte/squareroot.s
new file mode 100644
index 0000000..af095a2
--- /dev/null
+++ b/libmeidogte/squareroot.s
@@ -0,0 +1,121 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+.global SquareRoot12
+.type SquareRoot12, @function
+SquareRoot12:
+ mtc2 $a0, C2_LZCS
+ nop
+ nop
+ mfc2 $v0, C2_LZCR
+ beq $v0, 32, $bad_sqr12
+ nop
+ andi $t0, $v0, 0x1
+ addiu $v1, $0 , -2
+ and $t2, $v0, $v1
+ li $t1, 19
+ sub $t1, $t2
+ sra $t1, 1
+ addi $t3, $t2, -24
+ bltz $t3, $value_less12
+ nop
+ sllv $t4, $a0, $t3
+ b $value_greater12
+$value_less12:
+ addiu $t3, $0 , 24
+ sub $t3, $t2
+ srav $t4, $a0, $t3
+$value_greater12:
+ addi $t4, -64
+ sll $t4, 1
+ la $t5, sqrt_table
+ addu $t5, $t4
+ lh $t5, 0($t5)
+ nop
+
+ bltz $t1, $1594c
+ nop
+ jr $ra
+ sllv $v0, $t5, $t1
+
+$1594c:
+
+ sub $t1, $0 , $t1
+ jr $ra
+ srl $v0, $t5, $t1
+
+$bad_sqr12:
+ jr $ra
+ move $v0, $0
+
+
+.global SquareRoot0
+.type SquareRoot0, @function
+SquareRoot0:
+ mtc2 $a0, C2_LZCS
+ nop
+ nop
+ mfc2 $v0, C2_LZCR
+ beq $v0, 32, $bad_sqr
+ nop
+ andi $t0, $v0, 0x1
+ addiu $v1, $0 , -2
+ and $t2, $v0, $v1
+ li $t1, 31
+ sub $t1, $t2
+ sra $t1, 1
+ addi $t3, $t2, -24
+ bltz $t3, $value_less
+ nop
+ sllv $t4, $a0, $t3
+ b $value_greater
+$value_less:
+ addiu $t3, $0 , 24
+ sub $t3, $t2
+ srav $t4, $a0, $t3
+$value_greater:
+ addi $t4, -64
+ sll $t4, 1
+ la $t5, sqrt_table
+ addu $t5, $t4
+ lh $t5, 0($t5)
+ nop
+ sllv $t5, $t5, $t1
+ jr $ra
+ srl $v0, $t5, 12
+$bad_sqr:
+ jr $ra
+ move $v0, $0
+
+
+.section .data
+
+sqrt_table:
+ .hword 0x1000,0x101f,0x103f,0x105e,0x107e,0x109c,0x10bb,0x10da
+ .hword 0x10f8,0x1116,0x1134,0x1152,0x116f,0x118c,0x11a9,0x11c6
+ .hword 0x11e3,0x1200,0x121c,0x1238,0x1254,0x1270,0x128c,0x12a7
+ .hword 0x12c2,0x12de,0x12f9,0x1314,0x132e,0x1349,0x1364,0x137e
+ .hword 0x1398,0x13b2,0x13cc,0x13e6,0x1400,0x1419,0x1432,0x144c
+ .hword 0x1465,0x147e,0x1497,0x14b0,0x14c8,0x14e1,0x14f9,0x1512
+ .hword 0x152a,0x1542,0x155a,0x1572,0x158a,0x15a2,0x15b9,0x15d1
+ .hword 0x15e8,0x1600,0x1617,0x162e,0x1645,0x165c,0x1673,0x1689
+ .hword 0x16a0,0x16b7,0x16cd,0x16e4,0x16fa,0x1710,0x1726,0x173c
+ .hword 0x1752,0x1768,0x177e,0x1794,0x17aa,0x17bf,0x17d5,0x17ea
+ .hword 0x1800,0x1815,0x182a,0x183f,0x1854,0x1869,0x187e,0x1893
+ .hword 0x18a8,0x18bd,0x18d1,0x18e6,0x18fa,0x190f,0x1923,0x1938
+ .hword 0x194c,0x1960,0x1974,0x1988,0x199c,0x19b0,0x19c4,0x19d8
+ .hword 0x19ec,0x1a00,0x1a13,0x1a27,0x1a3a,0x1a4e,0x1a61,0x1a75
+ .hword 0x1a88,0x1a9b,0x1aae,0x1ac2,0xa1d5,0x1ae8,0x1afb,0x1b0e
+ .hword 0x1b21,0x1b33,0x1b46,0x1b59,0x1b6c,0x1b7e,0x1b91,0x1ba3
+ .hword 0x1bb6,0x1bc8,0x1bdb,0x1bed,0x1c00,0x1c12,0x1c24,0x1c36
+ .hword 0x1c48,0x1c5a,0x1c6c,0x1c7e,0x1c90,0x1ca2,0x1cb4,0x1cc6
+ .hword 0x1cd8,0x1ce9,0x1cfb,0x1d0d,0x1d1e,0x1d30,0x1d41,0x1d53
+ .hword 0x1d64,0x1d76,0x1d87,0x1d98,0x1daa,0x1dbb,0x1dcc,0x1ddd
+ .hword 0x1dee,0x1e00,0x1e11,0x1e22,0x1e33,0x1e43,0x1e54,0x1e65
+ .hword 0x1e76,0x1e87,0x1e98,0x1ea8,0x1eb9,0x1eca,0x1eda,0x1eeb
+ .hword 0x1efb,0x1f0c,0x1f1c,0x1f2d,0x1f3d,0x1f4e,0x1f5e,0x1f6e
+ .hword 0x1f7e,0x1f8f,0x1f9f,0x1faf,0x1fbf,0x1fcf,0x1fdf,0x1fef
diff --git a/libmeidogte/vectornormals.s b/libmeidogte/vectornormals.s
new file mode 100644
index 0000000..0dbe1e8
--- /dev/null
+++ b/libmeidogte/vectornormals.s
@@ -0,0 +1,107 @@
+.set noreorder
+.set noat
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global VectorNormalS
+.type VectorNormalS, @function
+VectorNormalS:
+ lw $t0, 0($a0)
+ lw $t1, 4($a0)
+ lw $t2, 8($a0)
+
+ mtc2 $t0, C2_IR1
+ mtc2 $t1, C2_IR2
+ mtc2 $t2, C2_IR3
+
+ nSQR(0)
+
+ mfc2 $t3, C2_MAC1
+ mfc2 $t4, C2_MAC2
+ mfc2 $t5, C2_MAC3
+
+ add $t3, $t4
+ add $v0, $t3, $t5
+ mtc2 $v0, C2_LZCS
+ nop
+ nop
+ mfc2 $v1, C2_LZCR
+
+ addiu $at, $0 , -2
+ and $v1, $at
+
+ addiu $t6, $0 , 0x1f
+ sub $t6, $v1
+ sra $t6, 1
+ addiu $t3, $v1, -24
+
+ bltz $t3, $value_neg
+ nop
+ b $value_pos
+ sllv $t4, $v0, $t3
+$value_neg:
+ addiu $t3, $0 , 24
+ sub $t3, $v1
+ srav $t4, $v0, $t3
+$value_pos:
+ addi $t4, -64
+ sll $t4, 1
+
+ la $t5, _norm_table
+ addu $t5, $t4
+ lh $t5, 0($t5)
+ nop
+
+ mtc2 $t5, C2_IR0
+ mtc2 $t0, C2_IR1
+ mtc2 $t1, C2_IR2
+ mtc2 $t2, C2_IR3
+
+ nGPF(0)
+
+ mfc2 $t0, C2_MAC1
+ mfc2 $t1, C2_MAC2
+ mfc2 $t2, C2_MAC3
+
+ sra $t0, $t6
+ sra $t1, $t6
+ sra $t2, $t6
+
+ sh $t0, 0($a1)
+ sh $t1, 2($a1)
+ jr $ra
+ sh $t2, 4($a1)
+
+
+.section .data
+
+_norm_table:
+ .hword 0x1000, 0x0FE0, 0x0FC1, 0x0FA3, 0x0F85, 0x0F68, 0x0F4C, 0x0F30
+ .hword 0x0F15, 0x0EFB, 0x0EE1, 0x0EC7, 0x0EAE, 0x0E96, 0x0E7E, 0x0E66
+ .hword 0x0E4F, 0x0E38, 0x0E22, 0x0E0C, 0x0DF7, 0x0DE2, 0x0DCD, 0x0DB9
+ .hword 0x0DA5, 0x0D91, 0x0D7E, 0x0D6B, 0x0D58, 0x0D45, 0x0D33, 0x0D21
+ .hword 0x0D10, 0x0CFF, 0x0CEE, 0x0CDD, 0x0CCC, 0x0CBC, 0x0CAC, 0x0C9C
+ .hword 0x0C8D, 0x0C7D, 0x0C6E, 0x0C5F, 0x0C51, 0x0C42, 0x0C34, 0x0C26
+ .hword 0x0C18, 0x0C0A, 0x0BFD, 0x0BEF, 0x0BE2, 0x0BD5, 0x0BC8, 0x0BBB
+ .hword 0x0BAF, 0x0BA2, 0x0B96, 0x0B8A, 0x0B7E, 0x0B72, 0x0B67, 0x0B5B
+ .hword 0x0B50, 0x0B45, 0x0B39, 0x0B2E, 0x0B24, 0x0B19, 0x0B0E, 0x0B04
+ .hword 0x0AF9, 0x0AEF, 0x0AE5, 0x0ADB, 0x0AD1, 0x0AC7, 0x0ABD, 0x0AB4
+ .hword 0x0AAA, 0x0AA1, 0x0A97, 0x0A8E, 0x0A85, 0x0A7C, 0x0A73, 0x0A6A
+ .hword 0x0A61, 0x0A59, 0x0A50, 0x0A47, 0x0A3F, 0x0A37, 0x0A2E, 0x0A26
+ .hword 0x0A1E, 0x0A16, 0x0A0E, 0x0A06, 0x09FE, 0x09F6, 0x09EF, 0x09E7
+ .hword 0x09E0, 0x09D8, 0x09D1, 0x09C9, 0x09C2, 0x09BB, 0x09B4, 0x09AD
+ .hword 0x09A5, 0x099E, 0x0998, 0x0991, 0x098A, 0x0983, 0x097C, 0x0976
+ .hword 0x096F, 0x0969, 0x0962, 0x095C, 0x0955, 0x094F, 0x0949, 0x0943
+ .hword 0x093C, 0x0936, 0x0930, 0x092A, 0x0924, 0x091E, 0x0918, 0x0912
+ .hword 0x090D, 0x0907, 0x0901, 0x08FB, 0x08F6, 0x08F0, 0x08EB, 0x08E5
+ .hword 0x08E0, 0x08DA, 0x08D5, 0x08CF, 0x08CA, 0x08C5, 0x08BF, 0x08BA
+ .hword 0x08B5, 0x08B0, 0x08AB, 0x08A6, 0x08A1, 0x089C, 0x0897, 0x0892
+ .hword 0x088D, 0x0888, 0x0883, 0x087E, 0x087A, 0x0875, 0x0870, 0x086B
+ .hword 0x0867, 0x0862, 0x085E, 0x0859, 0x0855, 0x0850, 0x084C, 0x0847
+ .hword 0x0843, 0x083E, 0x083A, 0x0836, 0x0831, 0x082D, 0x0829, 0x0824
+ .hword 0x0820, 0x081C, 0x0818, 0x0814, 0x0810, 0x080C, 0x0808, 0x0804
+
diff --git a/libmodplay/Makefile b/libmodplay/Makefile
new file mode 100644
index 0000000..af4a8e5
--- /dev/null
+++ b/libmodplay/Makefile
@@ -0,0 +1,38 @@
+# Makefile for libmodplay
+
+include ../Makefile.cfg
+
+CFLAGS += -I../libadpcm
+
+all: libmodplay.a libmodplay_nopsx.a
+
+modplay.o: modplay.c
+ $(CC) $(CFLAGS) -c modplay.c
+
+mod.o: mod.c
+ $(CC) $(CFLAGS) -c mod.c
+
+libmodplay.a: modplay.o mod.o
+ rm -f libmodplay.a
+ $(AR) r libmodplay.a modplay.o mod.o
+ $(RANLIB) libmodplay.a
+
+modplay_nopsx.o: modplay.c
+ $(HOST_CC) $(HOST_CFLAGS) -DNO_PSX_LIB -c modplay.c -o modplay_nopsx.o
+
+mod_nopsx.o: mod.c
+ $(HOST_CC) $(HOST_CFLAGS) -DNO_PSX_LIB -c mod.c -o mod_nopsx.o
+
+libmodplay_nopsx.a: modplay_nopsx.o mod_nopsx.o
+ rm -f libmodplay_nopsx.a
+ $(HOST_AR) r libmodplay_nopsx.a modplay_nopsx.o mod_nopsx.o
+ $(HOST_RANLIB) libmodplay_nopsx.a
+
+install: all
+ cp libmodplay.a $(TOOLCHAIN_PREFIX)/lib
+ cp modplay.h $(TOOLCHAIN_PREFIX)/include
+
+clean:
+ rm -f *.o *.a
+
+distclean: clean
diff --git a/libmodplay/mod.c b/libmodplay/mod.c
new file mode 100644
index 0000000..3b569a6
--- /dev/null
+++ b/libmodplay/mod.c
@@ -0,0 +1,328 @@
+// Ultimate SoundTracker / NoiseTracker / ProTracker module file support for MODPlay
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include "modplay.h"
+#include "modplay_int.h"
+#include "modtbl.h" // Period -> frequency table for ProTracker MODs
+
+ModMusic *MODLoad_MOD(void *d)
+{
+ unsigned char *c = d;
+ ModMusic *m;
+ int x;
+ int mp=0;
+ int y;
+
+// Allocate memory for mod structure
+ m = (ModMusic*)malloc(sizeof(ModMusic));
+
+// Get title
+ memcpy(m->title, &c[0], 20);
+
+// For now let's assume there are 32 samples...
+ mp+=20;
+
+ memcpy(m->id, &c[0x438], 4);
+
+// If there is not a valid ID, this is the start of pattern data,
+// otherwise jump four bytes
+
+ if(strncmp(m->id, "M.K.",4) == 0 || strncmp(m->id, "FLT4", 4) == 0 ||
+ strncmp(m->id, "M!K!",4) == 0 || strncmp(m->id, "4CHN", 4) == 0 ||
+ strncmp(m->id, "6CHN", 4) == 0 || strncmp(m->id, "8CHN", 4) == 0)
+ m->sample_num = 31;
+ else
+ m->sample_num = 15;
+
+// Standard channel number is 4
+
+ if(strncmp(m->id, "6CHN", 4) == 0)
+ m->channel_num = 6;
+ else if(strncmp(m->id, "8CHN", 4) == 0)
+ m->channel_num = 8;
+ else
+ m->channel_num = 4;
+
+// Get sample information
+
+ m->sample = malloc(sizeof(ModSample) * m->sample_num);
+
+ for(x = 0; x < m->sample_num; x++)
+ {
+ // Get sample name
+ memcpy(m->sample[x].name, &c[mp], 22);
+ mp+=22;
+ // Get sample length
+ m->sample[x].length = (c[mp] << 8) | c[mp+1];
+ m->sample[x].length*= 2;
+ mp+=2;
+ // Get finetune value
+ m->sample[x].finetune = c[mp] & 0xf;
+
+ if(m->sample[x].finetune & 0x8)
+ m->sample[x].finetune|=0xf0;
+
+ mp++;
+ // Get sample volume
+ m->sample[x].volume = c[mp];
+ mp++;
+
+ // Get sample repeat offset
+ m->sample[x].repeat_off = (c[mp] << 8) | c[mp+1];
+ m->sample[x].repeat_off *= 2;
+ mp+=2;
+
+ // Get sample repeat length
+ m->sample[x].repeat_len = (c[mp] << 8) | c[mp+1];
+ m->sample[x].repeat_len *= 2;
+ mp+=2;
+
+ // Samples are always 8-bit
+ m->sample[x].bits = 8;
+
+ // Data type is always 0
+ m->sample[x].data_type = 0;
+ }
+
+// Get number of song positons
+ m->song_pos_num = c[mp++];
+
+// Ignore this value...
+ mp++;
+
+// Get pattern table
+ memcpy(m->pattern_tbl, &c[mp], 128);
+ mp+=128;
+
+
+
+// Get ID (it is not assured that this value will be valid)
+ memcpy(m->id, &c[0x438], 4);
+// If there is not a valid ID, this is the start of pattern data,
+// otherwise jump four bytes
+
+ if(strncmp(m->id, "M.K.",4) == 0 || strncmp(m->id, "FLT4", 4) == 0 ||
+ strncmp(m->id, "M!K!",4) == 0 || strncmp(m->id, "4CHN", 4) == 0 ||
+ strncmp(m->id, "6CHN", 4) == 0 || strncmp(m->id, "8CHN", 4) == 0)
+ mp+=4;
+
+// Get number of patterns
+// This is actually done by scanning the pattern table for the highest value
+ y = 0;
+
+ for(x=0;x<128;x++)
+ {
+ //printf("%x, \n", m->pattern_tbl[x]);
+ if(m->pattern_tbl[x] > y)
+ y = m->pattern_tbl[x];
+ }
+
+ //printf("\n");
+
+ m->pattern_num = y+1;
+
+// Pattern row sizes are always 64
+ for(x = 0; x < m->pattern_num; x++)
+ m->pattern_row_num[x] = 64;
+
+// Allocate memory for patterns...
+ m->pattern_data = malloc(m->pattern_num * ((4*m->channel_num)*64));
+
+// Get pattern data
+ memcpy(m->pattern_data,&c[mp], m->pattern_num * ((4*m->channel_num)*64));
+ mp += m->pattern_num * ((4*m->channel_num)*64);
+
+// Allocate & Get sample data
+ for(x = 0; x < m->sample_num; x++)
+ {
+ if(m->sample[x].length < 32 || (modload_flags & MODLOAD_NOSAMPLES))
+ m->sample[x].data = NULL;
+ else
+ {
+ m->sample[x].data = malloc(m->sample[x].length);
+ memcpy(m->sample[x].data, &c[mp], m->sample[x].length);
+
+ // Convert to unsigned 8-bit format
+ // Most sound cards/programs nowadays want data in this format
+ for(y = 0; y < m->sample[x].length; y++)
+ m->sample[x].data[y] ^= 0x80;
+ }
+
+ mp += m->sample[x].length;
+ }
+
+ m->song_pos = 0;
+ m->pat_pos = 0;
+ m->divisions_sec = 7;
+ m->beats_minute = 125;
+ m->ticks_division = 6;
+
+ for(x = 0; x<8;x++)
+ {
+ m->old_samples[x] = 1;
+ m->old_periods[x] = 0;
+ }
+
+ m->cur_tick = 0;
+ m->fmt = MOD_FMT_MOD;
+// MOD has no instruments!
+ m->instrument_num = 0;
+
+ return m;
+}
+
+void MODPlay_MOD(ModMusic *m,int *t)
+{
+ int cur_pat = m->pattern_tbl[m->song_pos];
+ int cur_pat_pos = m->pat_pos;
+ unsigned char b[4];
+ int s, p, e,x,y;
+ int do_not_increase_pat = 0;
+ int v1,f;
+
+ if(*t == 0)
+ return;
+
+
+ m->cur_tick++;
+
+ if(m->cur_tick != (50 / m->divisions_sec))
+ return;
+
+ for(x = 0; x < m->channel_num; x++)
+ {
+ memcpy(b, &m->pattern_data[(cur_pat * ((4*m->channel_num)*64)) + (cur_pat_pos * (4*m->channel_num)) + (x*4)], 4);
+
+ // Get sample
+ s = (b[2] & 0xf0)>>4;
+ s |= b[0] & 0xf0;
+
+ // Get period
+ p = b[1];
+ p|= (b[0] & 0xf)<<8;
+ p&=~(2048|1024);
+
+ // Get effect
+ e = b[3];
+ e|= (b[2] & 0xf)<<8;
+
+ if(s != 0 && p==0)
+ p = m->old_periods[x];
+
+ if(s == 0 && p != 0)
+ s=m->old_samples[x];
+
+ v1 = m->sample[s-1].volume;
+
+ switch(e & 0xf00)
+ {
+ case 0xc00: // Set volume
+ v1 = e & 0xff;
+ break;
+ }
+
+ f = -1;
+
+ for(y = 0; y < sizeof(modplay_pitch_per_tbl) / 4; y++)
+ {
+ if(modplay_pitch_per_tbl[y<<1] == p)
+ {
+ f = modplay_pitch_per_tbl[(y<<1)+1];
+ break;
+ }
+ }
+
+ if(f==-1 && p!=0)
+ {
+ printf("Couldn't find period %d in table. Calculating it.\n", p);
+ f = SsFreqToPitch(7159090/(p*2));
+ }
+
+ f+=m->transpose;
+
+ if(f<0)f=0;
+ else if(f>0x3fff)f=0x3fff;
+
+ v1 <<= 8;
+
+ if(v1 >= 0x4000)
+ v1 = 0x3fff;
+
+
+ if(s && p!=0)
+ {
+ if(x == 0 || x == 3 || x == 4 || x == 7)
+ MODPlay_func(m, x, s-1, f, v1, 0);
+ else
+ MODPlay_func(m, x, s-1, f, 0, v1);
+ }
+
+ switch(e & 0xf00)
+ {
+ case 0xb00: // Position Jump
+ m->song_pos = e & 0xff;
+ m->pat_pos = 0;
+ // printf("Jump to song pos %d\n", m->song_pos);
+
+ // this fixes some mods which jump over the mod itself
+
+ if(m->song_pos >= m->song_pos_num)
+ m->song_pos = 0;
+
+ do_not_increase_pat = 1;
+ break;
+ case 0xd00: // Pattern break
+ m->song_pos++;
+ m->pat_pos = (((e&0xf0)>>4)*10)+(e&0xf);
+ // printf("Pattern break, newpatpos=%d\n", m->pat_pos);
+
+ // this fixes some mods which jump over themselves
+
+ if(m->song_pos >= m->song_pos_num)
+ m->song_pos = 0;
+
+ do_not_increase_pat = 1;
+ break;
+ case 0xf00: // Tempo
+ /*v1 = (e & 0xf0) >> 4;
+ v2 = e & 0xf;
+ v3 = (v1*16)+v2;*/
+
+ if((e & 0xff) <= 32)
+ {
+ if((e&0xff) == 0)e++;
+ m->ticks_division = e & 0xff;
+ }
+ else
+ m->beats_minute = e & 0xff;
+
+ m->divisions_sec = 24 * m->beats_minute;
+ m->divisions_sec /= m->ticks_division;
+ m->divisions_sec /= 60;
+ break;
+ }
+
+ if(s) m->old_samples[x] = s;
+ if(p) m->old_periods[x] = p;
+
+ m->cur_tick = 0;
+ }
+
+ if(!do_not_increase_pat)m->pat_pos++;
+
+ if(m->pat_pos == 64)
+ {
+ m->song_pos++;
+ if(m->song_pos >= m->song_pos_num)
+ {
+ *t-=1;
+
+ MODRewind(m);
+ }
+
+ m->pat_pos = 0;
+ }
+}
diff --git a/libmodplay/modplay.c b/libmodplay/modplay.c
new file mode 100644
index 0000000..9f5f33d
--- /dev/null
+++ b/libmodplay/modplay.c
@@ -0,0 +1,290 @@
+// MODplay for the PS1
+// Music Module Player
+// Supports ProTracker (.mod) module format
+
+// Requires libADPCM!
+
+// If NO_PSX_LIB is defined, no parts using PSXSDK functions are compiled
+// This is useful if you want to use the library to handle module files in tools
+
+#ifndef NO_PSX_LIB
+#include <psx.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#ifndef NO_PSX_LIB
+#include <adpcm.h>
+#endif
+
+#include "modplay.h"
+#include "modplay_int.h"
+
+// Configuration defines
+
+// Size of ADPCM buffer used by MODUploadSamples when
+// converting 8-bit unsigned PCM samples to PS1 ADPCM format
+// By default it is set to 0x4000, 16 kilobytes
+
+#define ADPCM_BUFFER_SIZE 0x4000
+
+
+
+int modplay_base_voice = 0;
+int modplay_max_vol = 0x3fff;
+int modplay_chan_vols[8];
+int modplay_int_cnt = 0;
+int modplay_samples_off[32];
+int modplay_chan_mask = 0;
+int modplay_is_mono = 0;
+unsigned char modplay_adpcm_buffer[ADPCM_BUFFER_SIZE];
+
+unsigned int modload_flags = 0;
+
+ModMusic *MODLoad(void *d)
+{
+ return MODLoadEx(d, 0);
+}
+
+ModMusic *MODLoadEx(void *d, unsigned int flags)
+{
+ modload_flags = flags;
+
+ // If the module file was in no other format, assume the module file is
+ // in ProTracker format. There's no real way to detect a ProTracker module
+ // file 100% correctly so this will do.
+
+ return MODLoad_MOD(d);
+}
+
+void MODUnload(ModMusic *m)
+{
+ int x;
+
+ MODStop(m);
+
+ switch(m->fmt)
+ {
+ case MOD_FMT_MOD:
+ free(m->pattern_data);
+
+ for(x = 0; x < m->sample_num; x++)
+ {
+ if(m->sample[x].data != NULL)
+ free(m->sample[x].data);
+ }
+
+ free(m->sample);
+
+ free(m);
+ break;
+ }
+
+}
+
+#ifdef NO_PSX_LIB
+void MODPlay_func(ModMusic *m, int c, int s, int p, int vl, int vr)
+{
+ // Just a stub
+}
+#else
+void MODPlay_func(ModMusic *m, int c, int s, int p, int vl, int vr)
+{
+ int v = c + modplay_base_voice;
+// static int mask = 0;
+
+// if(s != -1)
+// {
+ // SsKeyOff(v);
+ if(p != -1)
+ SsVoicePitch(v, p);
+// }
+
+ if(modplay_max_vol != 0x3fff)
+ {
+ vl = (modplay_max_vol * vl) / 0x4000;
+ vr = (modplay_max_vol * vr) / 0x4000;
+ vl&=0x3fff;
+ vr&=0x3fff;
+ }
+
+ if(modplay_is_mono)
+ {
+ if(vl>vr)
+ vr=vl;
+ else
+ vl=vr;
+ }
+
+ SsVoiceVol(v, vl, vr);
+
+ if(s != -1)
+ {
+ if(modplay_samples_off[s] != -1)
+ {
+ SsVoiceStartAddr(v, modplay_samples_off[s]);
+ modplay_chan_mask|=(1<<v);
+ }
+ }
+}
+#endif
+
+void MODPlay(ModMusic *m, int *t)
+{
+ modplay_chan_mask = 0;
+
+ switch(m->fmt)
+ {
+ case MOD_FMT_MOD:
+ MODPlay_MOD(m, t);
+ break;
+ }
+
+ //printf("modplay_chan_mask = %d\n", modplay_chan_mask);
+#ifndef NO_PSX_LIB
+ SsKeyOnMask(modplay_chan_mask);
+#endif
+}
+
+void MODStop(ModMusic *m)
+{
+#ifndef NO_PSX_LIB
+ int mask = 0;
+ int x;
+
+ for(x = 0; x<m->channel_num; x++)
+ mask|=1<<(modplay_base_voice+x);
+
+ SsKeyOffMask(mask);
+#endif
+}
+
+#ifndef NO_PSX_LIB
+int MODUploadSamples(ModMusic *m, int base_addr)
+{
+ int x, b;
+
+ if(base_addr == -1)
+ base_addr = SPU_DATA_BASE_ADDR;
+
+ modplay_samples_off[0] = base_addr;
+
+ for(x = 0; x < m->sample_num; x++)
+ {
+ b = SsAdpcmPack(m->sample[x].data, modplay_adpcm_buffer,
+ m->sample[x].length, FMT_U8, sizeof(modplay_adpcm_buffer), 0);
+ SsUpload(modplay_adpcm_buffer, b, modplay_samples_off[x]);
+
+ if(x!=30)
+ modplay_samples_off[x+1] = modplay_samples_off[x]+b;
+ }
+
+ return modplay_samples_off[x];
+}
+
+int MOD4PSX_Upload(void *d, int base_addr)
+{
+ unsigned char *c = d;
+ int x;
+ int o;
+ int sz;
+ int n;
+ int smpOff;
+
+// Check magic string
+
+ if(strncmp((char*)c, "_mod4psx", 8) != 0)
+ return -1;
+
+ o = 12;
+ n = *((int*)(c+8));
+
+ if(base_addr == -1)
+ smpOff = SPU_DATA_BASE_ADDR;
+ else
+ smpOff = base_addr;
+
+ //smpOff = modplay_samples_off[0];
+
+ printf("Number of samples: %d\n", n);
+
+ for(x = 0; x < n; x++)
+ {
+// Get size
+ sz = *((int*)(c+o));
+ printf("Size: %d\n", sz);
+// Ignore eight reserved bytes (for future expension)
+ o+=12;
+
+ if(sz > 0)
+ {
+ modplay_samples_off[x] = smpOff;
+
+ SsUpload(c+o, sz, modplay_samples_off[x]);
+
+ smpOff+=sz;
+ }
+ else
+ modplay_samples_off[x] = -1;
+
+ o += sz;
+ }
+
+ return modplay_samples_off[x];
+}
+
+#endif
+
+void MODSetBaseVoice(int base_voice)
+{
+ modplay_base_voice = base_voice;
+}
+
+void MODSetMaxVolume(unsigned short max_volume)
+{
+ // Default is 0x3fff.
+ // Valid values 0 (MUTE) - 0x3FFF (MAX)
+
+ modplay_max_vol = max_volume & 0x3fff;
+}
+
+void MODRewind(ModMusic *m)
+{
+ MODStop(m);
+ m->song_pos = 0;
+ m->pat_pos = 0;
+
+ if(m->fmt == MOD_FMT_MOD)
+ {
+ m->divisions_sec = 7;
+ m->beats_minute = 125;
+ m->ticks_division = 6;
+ }
+}
+
+void MODSetTranspose(ModMusic *m, short transpose)
+{
+ m->transpose = transpose;
+}
+
+void MODSetMono(int value)
+{
+ /* Sets mono audio mode
+ left volume = right volume */
+
+ modplay_is_mono = value;
+}
+
+#ifdef NO_PSX_LIB
+
+// Some code might use this, so use a stub.
+
+unsigned short SsFreqToPitch(int hz)
+{
+ return 0;
+}
+
+#endif
diff --git a/libmodplay/modplay.h b/libmodplay/modplay.h
new file mode 100644
index 0000000..0370bc6
--- /dev/null
+++ b/libmodplay/modplay.h
@@ -0,0 +1,222 @@
+#ifndef _MODPLAY_H
+#define _MODPLAY_H
+
+#ifndef NO_PSX_LIB
+ #include <psx.h>
+#endif
+
+/** Format identification IDs. */
+
+enum modplay_formats
+{
+ MOD_FMT_MOD, /** Ultimate SoundTracker / NoiseTracker / ProTracker */
+};
+
+typedef struct
+{
+ char name[32];
+ unsigned int length; // Length in bytes
+ char finetune;
+ unsigned char volume;
+ unsigned int repeat_off;
+ unsigned int repeat_len;
+ unsigned char bits;
+ unsigned char data_type;
+ unsigned char *data;
+}ModSample;
+
+/** Instrument. */
+
+typedef struct
+{
+ char name[64];
+ int sample_num;
+ unsigned char sample_ids[8];
+}ModInstrument;
+
+/** Music */
+
+typedef struct
+{
+ /** Music title. */
+ char title[32];
+ /** Number of samples in the music */
+ int sample_num;
+ /** Number of channels used by the music */
+ int channel_num;
+ /** Number of instruments used by the music */
+ int instrument_num;
+ /** Pointer to an array of ModSample structures. */
+ ModSample *sample;
+ /** Pointer to an array of ModInstrument structures. */
+ ModInstrument *instrument;
+ /** Number of song positions. */
+ unsigned char song_pos_num;
+ /** Pattern table. */
+ unsigned char pattern_tbl[256];
+ /** Number of rows for each pattern. */
+ unsigned char pattern_row_num[256];
+ /** ID, such as "M!K!","M.K.","FLT4", etc. */
+ char id[4];
+ /** Number of patterns. */
+ int pattern_num;
+ /** Pointer to pattern data */
+ unsigned char *pattern_data;
+ /** Format of music. */
+ int fmt;
+
+ /** [Runtime] Current song position */
+ unsigned char song_pos;
+ /** [Runtime] Position inside the pattern currently being played */
+ unsigned char pat_pos;
+ /** [Runtime] Divisions per second */
+ int divisions_sec;
+ /** [Runtime] Beats per minute */
+ unsigned char beats_minute;
+ /** [Runtime] Ticks per division */
+ unsigned char ticks_division;
+ /** [Runtime] Current tick count */
+ unsigned char cur_tick;
+ /** [Runtime] Old periods for each channel. */
+ unsigned short old_periods[8];
+ /** [Runtime] Old sample numbers for each channel. */
+ unsigned char old_samples[8];
+ /** [Runtime] In PlayStation pitch, this is added to the original sample pitch
+ and can be used to change the pitch of the music for special effects */
+ short transpose;
+}ModMusic;
+
+/** Flags for MODLoad */
+enum modload_flags
+{
+ /** Do not load the samples in memory */
+ MODLOAD_NOSAMPLES = 1,
+};
+
+/**
+ * Allocate a ModMusic structure and copy data to it from
+ * data in memory containing a music module file
+ *
+ * Almost all data from the music module file is copied into another location
+ * in memory for the ModMusic structure.
+ *
+ * This means your free memory should be roughly the double of
+ * the size of the MOD you're loading.
+ *
+ * You can avoid loading the samples in the module file's native format,
+ * thus saving useful memory, by passing the MODLOAD_NOSAMPLES
+ * flag. This is especially the case when you use MOD4PSX_Upload().
+ *
+ * @param d Pointer to a buffer containing a music module file
+ * @param flags Flag bitmask.
+ * @return Pointer to newly allocated ModMusic structure.
+ */
+
+ModMusic *MODLoadEx(void *d, unsigned int flags);
+
+/**
+ * Just like MODLoadEx() but with the flags parameters set to zero, i.e.
+ * default behaviour.
+ *
+ * @param d Pointer to a buffer containing a music module file
+ * @return Pointer to newly allocated ModMusic structure.
+ */
+
+ModMusic *MODLoad(void *d);
+
+/**
+ * Play a tick of a music.
+ *
+ * This has to be called 60 / 50 times per second.
+ *
+ * MODPlay decreases the value referenced by t every time
+ * the music finishes.
+ *
+ * Set the variable pointed by t when you want to set the number of times again!
+ *
+ * @param m Pointer to ModMusic structure
+ * @param t Pointer to an int which contains how many times the music module has to be played.
+ * i.e. if *t == 1, play once, if *t == 2, play twice, ..., if *t == -1, loop endlessly
+ *
+ */
+
+void MODPlay(ModMusic *m,int *t);
+
+/**
+ * Stop a music.
+ * @param m Pointer to ModMusic structure for the music.
+ */
+void MODStop(ModMusic *m);
+
+/**
+ * Rewind music, that is, make it restart from the beginning.
+ * @param m Pointer to ModMusic structure for the music.
+ */
+void MODRewind(ModMusic *m);
+
+/**
+ * Upload the samples of the module music to Sound RAM
+ * @param m Pointer to ModMusic structure for the music.
+ * @param base_addr Sound RAM address to start from when uploading to Sound RAM
+ * If -1 it is interpreted to be the same as the start of the section for sound data in Sound RAM
+ * (SPU_DATA_BASE_ADDR). base_addr must be a multiply of 8.
+ * @return The sound address after all the uploaded samples
+ */
+
+int MODUploadSamples(ModMusic *m, int base_addr);
+
+/**
+ * Sets the SPU voice to use as the first channel when playing music.
+ *
+ * The voice for the second channel will then be this (value+1), and so on...
+ *
+ * Usually the base voice is 0; a MOD file can have up to eight channels, so take care of that.
+ *
+ * @param base_voice Desired base voice (0-23)
+ */
+
+void MODSetBaseVoice(int base_voice);
+
+/**
+ * Sets transpose for music
+ *
+ * Changing the transpose value for a music shifts the frequency
+ * its samples are played at, but the music's tempo is unchanged.
+ * @param m Pointer to ModMusic structure
+ * @param transpose Transpose value
+ */
+
+void MODSetTranspose(ModMusic *m, short transpose);
+
+/**
+ * Upload preconverted ADPCM samples, as generated by the mod4psx tool.
+ *
+ * @param d Pointer to buffer containing the ADPCM samples archive
+ * @param base_addr Base address at which the samples will start to be uploaded.
+ * @return The sound address after all the uploaded samples
+ */
+
+int MOD4PSX_Upload(void *d, int base_addr);
+
+/**
+ * Free memory allocated for music module
+ * @param m Pointer to ModMusic structure
+ */
+
+void MODUnload(ModMusic *m);
+
+/**
+ * Set maximum volume for MODPlay
+ * @param max_volume Maximum volume desired (0-0x3FFF)
+ */
+
+void MODSetMaxVolume(unsigned short max_volume);
+
+/**
+ * Set mono mode
+ * @param value If 0 set stereo mode, if 1 set mono mode
+ */
+
+void MODSetMono(int value);
+
+#endif
diff --git a/libmodplay/modplay_int.h b/libmodplay/modplay_int.h
new file mode 100644
index 0000000..9a8a124
--- /dev/null
+++ b/libmodplay/modplay_int.h
@@ -0,0 +1,20 @@
+/**
+ * MODPlay: internal prototypes
+ */
+
+#ifndef _MODPLAY_INT_H
+#define _MODPLAY_INT_H
+
+void MODPlay_func(ModMusic *m, int c, int s, int p, int vl, int vr);
+extern int modplay_int_cnt;
+extern unsigned int modload_flags;
+extern const unsigned short modplay_pitch_per_tbl[120];
+
+ModMusic *MODLoad_MOD(void *d);
+void MODPlay_MOD(ModMusic *m, int *t);
+
+#ifdef NO_PSX_LIB
+unsigned short SsFreqToPitch(int hz);
+#endif
+
+#endif \ No newline at end of file
diff --git a/libmodplay/modtbl.h b/libmodplay/modtbl.h
new file mode 100644
index 0000000..96bd407
--- /dev/null
+++ b/libmodplay/modtbl.h
@@ -0,0 +1,62 @@
+const unsigned short modplay_pitch_per_tbl[120] = {
+1712, 194,
+1616, 205,
+1525, 217,
+1440, 230,
+1357, 244,
+1281, 259,
+1209, 274,
+1141, 291,
+1077, 308,
+1017, 326,
+961, 345,
+907, 366,
+856, 388,
+808, 411,
+762, 436,
+720, 461,
+678, 490,
+640, 519,
+604, 550,
+570, 583,
+538, 617,
+508, 654,
+480, 692,
+453, 733,
+428, 776,
+404, 822,
+381, 872,
+360, 923,
+339, 980,
+320, 1038,
+302, 1100,
+285, 1166,
+269, 1235,
+254, 1308,
+240, 1385,
+226, 1471,
+214, 1553,
+202, 1645,
+190, 1749,
+180, 1847,
+170, 1955,
+160, 2077,
+151, 2201,
+143, 2324,
+135, 2462,
+127, 2617,
+120, 2770,
+113, 2942,
+107, 3107,
+101, 3291,
+95, 3499,
+90, 3694,
+85, 3911,
+80, 4155,
+76, 4374,
+71, 4682,
+67, 4962,
+64, 5194,
+60, 5541,
+57, 5832,
+};
diff --git a/libpsx/Makefile b/libpsx/Makefile
new file mode 100644
index 0000000..d905cb8
--- /dev/null
+++ b/libpsx/Makefile
@@ -0,0 +1,49 @@
+# Makefile for PSX SDK library
+
+include ../Makefile.cfg
+
+CFLAGS += -O0
+
+# Never remove the line below!
+CFLAGS += -D__IN_LIBPSX
+
+OBJS = $(patsubst src/%.c, out/%.o, $(wildcard src/*.c)) \
+ $(patsubst src/libc/%.c, out/libc/%.o, $(wildcard src/libc/*.c)) \
+ $(patsubst src/runexe/%.c, out/runexe/%.o, $(wildcard src/runexe/*.c)) \
+ $(patsubst src/%.s, out/%.o, $(wildcard src/*.s)) \
+ $(patsubst src/runexe/%.s, out/runexe/%.o, $(wildcard src/runexe/*.s))
+
+all: libpsx.a start.o
+
+libpsx.a: $(OBJS)
+ $(AR) r libpsx.a $(OBJS)
+
+out/%.o: src/%.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+out/libc/%.o: src/libc/%.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+out/runexe/%.o: src/runexe/%.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+out/%.o: src/%.s
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+out/runexe/%.o: src/runexe/%.s
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+start.o: src/start/start.s
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+install: libpsx.a start.o
+ cp libpsx.a $(TOOLCHAIN_PREFIX)/lib
+ cp start.o $(TOOLCHAIN_PREFIX)/lib
+ cp -r include/* $(TOOLCHAIN_PREFIX)/include
+
+clean:
+ rm -f $(OBJS)
+ rm -f libpsx.a
+ rm -f start.o
+
+distclean: clean
diff --git a/libpsx/include/bitstring.h b/libpsx/include/bitstring.h
new file mode 100644
index 0000000..a9b4c32
--- /dev/null
+++ b/libpsx/include/bitstring.h
@@ -0,0 +1,78 @@
+/**
+ * PSXSDK
+ *
+ * bitstring.h
+ *
+ * Implementation of bitstring.h, a family of macros found in *BSD
+ * to manipulate bit strings
+ */
+
+#ifndef _BITSTRING_H
+#define _BITSTRING_H
+
+#include <stdlib.h>
+
+typedef unsigned char bitstr_t;
+
+#define bitstr_size(nbits) \
+ ( (nbits + 7) >> 3 )
+
+#define bit_alloc(nbits) \
+ calloc( bitstr_size(nbits) , 1)
+
+#define bit_decl(name, nbits) \
+ name[ bitstr_size(nbits) ]
+
+#define bit_clear(name, bit) \
+ name[ bit >> 3 ] &= ~(1 << (bit & 7) )
+
+#define bit_set(name, bit) \
+ name[ bit >> 3] |= 1 << (bit & 7)
+
+#define bit_nclear(name, start, stop) \
+ do{ \
+ int _b__;\
+ for(_b__ = start; _b__ <= stop; _b__++) \
+ bit_clear(name, _b__);\
+ }while(0)
+
+#define bit_nset(name, start, stop) \
+ do{ \
+ int _b__;\
+ for(_b__ = start; _b__ <= stop; _b__++) \
+ bit_set(name, _b__); \
+ }while(0)
+
+#define bit_test(name, bit) \
+ ( name[bit >> 3] & (1 << (bit & 7) ) )
+
+#define bit_ffs(name, nbits, value) \
+ do{\
+ int _b__;\
+ for(_b__ = 0; _b__ < nbits; _b__++) \
+ {\
+ printf("bb = %d\n", _b__);\
+ if( bit_test(name, _b__) ) \
+ {\
+ *(value) = _b__; \
+ break; \
+ }\
+ }\
+ if( _b__ == nbits ) *(value) = -1;\
+ }while(0)
+
+#define bit_ffc(name, nbits, value) \
+ do{\
+ int _b__;\
+ for(_b__ = 0; _b__ < nbits; _b__++) \
+ {\
+ if( !bit_test(name, _b__) ) \
+ {\
+ *(value) = _b__; \
+ break; \
+ }\
+ }\
+ if( _b__ == nbits ) *(value) = -1;\
+ }while(0)
+
+#endif
diff --git a/libpsx/include/ctype.h b/libpsx/include/ctype.h
new file mode 100644
index 0000000..209e175
--- /dev/null
+++ b/libpsx/include/ctype.h
@@ -0,0 +1,25 @@
+/*
+ * ctype.h
+ *
+ * PSXSDK
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+int isupper(int c);
+int islower(int c);
+int isdigit(int c);
+int isxdigit(int c);
+int isalpha(int c);
+int isalnum(int c);
+int isspace(int c);
+int isprint(int c);
+int isgraph(int c);
+int iscntrl(int c);
+int isblank(int c);
+int toupper(int c);
+int tolower(int c);
+
+#endif
+
diff --git a/libpsx/include/errno.h b/libpsx/include/errno.h
new file mode 100644
index 0000000..cfaa8fd
--- /dev/null
+++ b/libpsx/include/errno.h
@@ -0,0 +1,167 @@
+/*
+ * errno.h
+ *
+ * PSXSDK
+ */
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+// There is no real support for errno, this include exists
+// mostly to make things compile
+
+/*
+ * Declarations from NetBSD's /usr/include/sys/errno.h
+ * BSD license
+ */
+
+#ifndef __IN_LIBPSX
+extern int errno;
+#endif
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* Input/output error */
+#define ENXIO 6 /* Device not configured */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file descriptor */
+#define ECHILD 10 /* No child processes */
+#define EDEADLK 11 /* Resource deadlock avoided */
+ /* 11 was EAGAIN */
+#define ENOMEM 12 /* Cannot allocate memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* Operation not supported by device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* Too many open files in system */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Inappropriate ioctl for device */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+
+/* math software */
+#define EDOM 33 /* Numerical argument out of domain */
+#define ERANGE 34 /* Result too large or too small */
+
+/* non-blocking and interrupt i/o */
+#define EAGAIN 35 /* Resource temporarily unavailable */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EINPROGRESS 36 /* Operation now in progress */
+#define EALREADY 37 /* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define ENOTSOCK 38 /* Socket operation on non-socket */
+#define EDESTADDRREQ 39 /* Destination address required */
+#define EMSGSIZE 40 /* Message too long */
+#define EPROTOTYPE 41 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 42 /* Protocol option not available */
+#define EPROTONOSUPPORT 43 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
+#define EOPNOTSUPP 45 /* Operation not supported */
+#define EPFNOSUPPORT 46 /* Protocol family not supported */
+#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
+#define EADDRINUSE 48 /* Address already in use */
+#define EADDRNOTAVAIL 49 /* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define ENETDOWN 50 /* Network is down */
+#define ENETUNREACH 51 /* Network is unreachable */
+#define ENETRESET 52 /* Network dropped connection on reset */
+#define ECONNABORTED 53 /* Software caused connection abort */
+#define ECONNRESET 54 /* Connection reset by peer */
+#define ENOBUFS 55 /* No buffer space available */
+#define EISCONN 56 /* Socket is already connected */
+#define ENOTCONN 57 /* Socket is not connected */
+#define ESHUTDOWN 58 /* Can't send after socket shutdown */
+#define ETOOMANYREFS 59 /* Too many references: can't splice */
+#define ETIMEDOUT 60 /* Operation timed out */
+#define ECONNREFUSED 61 /* Connection refused */
+
+#define ELOOP 62 /* Too many levels of symbolic links */
+#define ENAMETOOLONG 63 /* File name too long */
+
+/* should be rearranged */
+#define EHOSTDOWN 64 /* Host is down */
+#define EHOSTUNREACH 65 /* No route to host */
+#define ENOTEMPTY 66 /* Directory not empty */
+
+/* quotas & mush */
+#define EPROCLIM 67 /* Too many processes */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Disc quota exceeded */
+
+/* Network File System */
+#define ESTALE 70 /* Stale NFS file handle */
+#define EREMOTE 71 /* Too many levels of remote in path */
+#define EBADRPC 72 /* RPC struct is bad */
+#define ERPCMISMATCH 73 /* RPC version wrong */
+#define EPROGUNAVAIL 74 /* RPC prog. not avail */
+#define EPROGMISMATCH 75 /* Program version wrong */
+#define EPROCUNAVAIL 76 /* Bad procedure for program */
+
+#define ENOLCK 77 /* No locks available */
+#define ENOSYS 78 /* Function not implemented */
+
+#define EFTYPE 79 /* Inappropriate file type or format */
+#define EAUTH 80 /* Authentication error */
+#define ENEEDAUTH 81 /* Need authenticator */
+
+/* SystemV IPC */
+#define EIDRM 82 /* Identifier removed */
+#define ENOMSG 83 /* No message of desired type */
+#define EOVERFLOW 84 /* Value too large to be stored in data type */
+
+/* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */
+#define EILSEQ 85 /* Illegal byte sequence */
+
+/* From IEEE Std 1003.1-2001 */
+/* Base, Realtime, Threads or Thread Priority Scheduling option errors */
+#define ENOTSUP 86 /* Not supported */
+
+/* Realtime option errors */
+#define ECANCELED 87 /* Operation canceled */
+
+/* Realtime, XSI STREAMS option errors */
+#define EBADMSG 88 /* Bad or Corrupt message */
+
+/* XSI STREAMS option errors */
+#define ENODATA 89 /* No message available */
+#define ENOSR 90 /* No STREAM resources */
+#define ENOSTR 91 /* Not a STREAM */
+#define ETIME 92 /* STREAM ioctl timeout */
+
+/* File system extended attribute errors */
+#define ENOATTR 93 /* Attribute not found */
+
+/* Realtime, XSI STREAMS option errors */
+#define EMULTIHOP 94 /* Multihop attempted */
+#define ENOLINK 95 /* Link has been severed */
+#define EPROTO 96 /* Protocol error */
+
+#define ELAST 96 /* Must equal largest errno */
+
+#ifdef _KERNEL
+/* pseudo-errors returned inside kernel to modify return to process */
+#define EJUSTRETURN -2 /* don't modify regs, just return */
+#define ERESTART -3 /* restart syscall */
+#define EPASSTHROUGH -4 /* ioctl not handled by this layer */
+#define EDUPFD -5 /* Dup given fd */
+#define EMOVEFD -6 /* Move given fd */
+#endif
+
+#endif
+
diff --git a/libpsx/include/fcntl.h b/libpsx/include/fcntl.h
new file mode 100644
index 0000000..d51faa1
--- /dev/null
+++ b/libpsx/include/fcntl.h
@@ -0,0 +1,72 @@
+/*
+ * fcntl.h
+ *
+ * File control
+ *
+ * PSXSDK
+ */
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#define O_RDONLY 1
+#define O_WRONLY 2
+#define O_NONBLOCK 4
+/** Read locked, not shared. */
+#define O_RDLOCK 16
+/** Write locked, not shared. */
+#define O_WRLOCK 32
+#define O_RDWR (O_RDONLY | O_WRONLY)
+#define O_APPEND 256
+#define O_CREAT 512
+#define O_TRUNC 1024
+/** Obviously, O_EXCL has no effect in the PSXSDK. */
+#define O_EXCL 0
+
+/** The following are PlayStation BIOS extensions. */
+
+/** Set to scanning type. Real purpose unknown. */
+#define O_SCAN 4096
+/** Setup for remote command entry. Real purpose unknown. */
+#define O_RCOM 8192
+/** No buffering and console interrupt */
+#define O_NOBUF 16384
+/** Asynchronous I/O mode */
+#define O_NOWAIT 32768
+/** Asynchronous I/O mode, alias */
+#define O_ASYNC O_NOWAIT
+
+/**
+ * These are standard C library file I/O functions provided by the PSX BIOS.
+ * Filenames have to be specified in this way:
+ * [device]:[filename]
+ *
+ * Where device specifies the device the file is on:
+ * "tty:" Console
+ * "cdrom:" CD-ROM
+ * "buXX:" Memory cards
+ *
+ * When using cdrom: as device, append file version (;1) to filename
+ * Example: cdrom:README.TXT;1
+ *
+ * Subdirectory paths have to be specified with backslashes (\),
+ * like MS-DOS. Read and write operations can be carried only in blocks.
+ * Blocks are 2048 bytes for the CD-ROM device, and 128 bytes for memory cards.
+ */
+
+// The third argument (file mode) makes no sense in PSXSDK,
+// and will be ignored.
+
+#define open(filename, flags, ...) \
+ open(filename, flags)
+
+/** In previous versions, the second argument for open()
+ was named `mode'. That was incorrect; now it is correctly named `flags'.
+*/
+
+int open(const char *filename, int flags);
+int read(int d, void *buf, int nbytes);
+int close(int d);
+int lseek(int fildes, int offset, int whence);
+
+#endif
diff --git a/libpsx/include/inttypes.h b/libpsx/include/inttypes.h
new file mode 100644
index 0000000..831c6ed
--- /dev/null
+++ b/libpsx/include/inttypes.h
@@ -0,0 +1,68 @@
+/* inttypes.h */
+
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <stdint.h>
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef unsigned char uint_least8_t;
+typedef unsigned short uint_least16_t;
+typedef unsigned int uint_least32_t;
+typedef unsigned long long uint_least64_t;
+
+typedef unsigned char uint_fast8_t;
+typedef unsigned short uint_fast16_t;
+typedef unsigned int uint_fast32_t;
+typedef unsigned long long uint_fast64_t;
+
+typedef unsigned long long uintmax_t;
+typedef unsigned int uintptr_t;
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef signed char int_least8_t;
+typedef short int_least16_t;
+typedef int int_least32_t;
+typedef long long int_least64_t;
+
+typedef char int_fast8_t;
+typedef short int_fast16_t;
+typedef int int_fast32_t;
+typedef long long int_fast64_t;
+
+typedef long long intmax_t;
+
+typedef long intptr_t;
+
+#define PRIu8 "hhu"
+#define PRIu16 "hu"
+#define PRIu32 "u"
+#define PRIu64 "llu"
+
+#define PRIs8 "hhd"
+#define PRIs16 "hd"
+#define PRIs32 "d"
+#define PRIs64 "lld"
+
+#define PRIuLEAST8 "hhu"
+#define PRIuLEAST16 "hu"
+#define PRIuLEAST32 "u"
+#define PRIuLEAST64 "llu"
+
+#define PRIuFAST8 "hhu"
+#define PRIuFAST16 "hu"
+#define PRIuFAST32 "u"
+#define PRIuFAST64 "llu"
+
+#define PRIuMAX "llu"
+#define PRIuPTR "lu"
+
+#endif
diff --git a/libpsx/include/memcard.h b/libpsx/include/memcard.h
new file mode 100644
index 0000000..11b443f
--- /dev/null
+++ b/libpsx/include/memcard.h
@@ -0,0 +1,74 @@
+#ifndef _PSXSDK_MEMCARD_H
+#define _PSXSDK_MEMCARD_H
+
+/*Card connection related*/
+enum memcard_status
+{
+ /** Memory card is connected */
+ MEMCARD_CONNECTED = 1,
+ /** Memory card is formatted */
+ MEMCARD_FORMATTED = 2
+};
+
+/**
+ * Results of memory card operations
+ */
+
+enum memcard_operation_result
+{
+ /** Operation was successful - good result */
+ MEMCARD_RW_GOOD = 0x47,
+ /** Bad checksum - bad result */
+ MEMCARD_RW_BADCHECK = 0x4E,
+ /** Bad sector - bad result */
+ MEMCARD_RW_BADSECTOR = 0xFF
+};
+
+/*Card block type*/
+/*#define BLOCK_FORMATTED 0x000000A0
+#define BLOCK_INITIAL 0x00000051
+#define BLOCK_MIDLINK 0x00000052
+#define BLOCK_ENDLINK 0x00000053
+#define BLOCK_DEL_INITIAL 0x000000A1
+#define BLOCK_DEL_MIDLINK 0x000000A2
+#define BLOCK_DEL_ENDLINK 0x000000A3*/
+
+/*128 byte card directory*/
+/*typedef struct{
+ long BlockType;
+ long FileSize;
+ short NextBlock;
+ char FileName[20];
+ char Reserved[97];
+ char XorChecksum;
+}CARDDIR;*/
+
+/**
+ * Reads a 128-byte sector from a memory card.
+ * @param card_slot Memory card slot (0 = first slot, 1 = second slot)
+ * @param sector Sector number (0-511)
+ * @param buffer Pointer to data buffer in which data will be stored
+ * @return Result of operation (possible values in memcard_operation_result enum)
+ */
+
+unsigned char McReadSector(int card_slot, int sector, unsigned char *buffer);
+
+/**
+ * Writes a 128-byte sector to a memory card.
+ * @param card_slot Memory card slot (0 = first slot, 1 = second slot)
+ * @param sector Sector number (0-511)
+ * @param buffer Pointer to data buffer containing data to write
+ * @return Result of operation (possible values in memcard_operation_result enum)
+ */
+
+unsigned char McWriteSector(int card_slot, int sector, unsigned char *buffer);
+
+/**
+ * Get memory card status
+ * @param card_slot Memory card slot (0 = first slot, 1 = second slot)
+ * @return Bitmask for current memory card status (flags in memcard_status enum)
+ */
+
+unsigned int McGetStatus(int card_slot);
+
+#endif
diff --git a/libpsx/include/psx.h b/libpsx/include/psx.h
new file mode 100644
index 0000000..881291b
--- /dev/null
+++ b/libpsx/include/psx.h
@@ -0,0 +1,406 @@
+/*
+ * PSXSDK Library include
+ */
+
+#ifndef _PSX_H
+#define _PSX_H
+
+#include <stdarg.h>
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define IPENDING *((volatile unsigned int*)0x1f801070)
+#define IMASK *((volatile unsigned int*)0x1f801074)
+#define RCNT_COUNT(x) *((volatile unsigned int*)(0x1f801100 + (x<<4)))
+#define RCNT_MODE(x) *((volatile unsigned int*)(0x1f801104 + (x<<4)))
+#define RCNT_TARGET(x) *((volatile unsigned int*)(0x1f801108 + (x<<4)))
+
+/**
+ * PSXSDK version information in hexadecimal format.
+ *
+ * An explanation of version numbers and how they relate to
+ * releases:
+ * + PSXSDK_VERSION undefined
+ * - PSXSDK 0.1
+ * + 0.1.99 (0x0199)
+ * - From PSXSDK releases 2012-03-03 up to 2013-01-14.
+ * + 0.2.99 (0x0299)
+ * - PSXSDK 2013-05-14
+ * + 0.3.99 (0x0399)
+ * - PSXSDK 2013-11-09
+ * + 0.4.99 (0x0499)
+ * - PSXSDK 2014-04-22
+ * + 0.5.99 (0x0599)
+ * - PSXSDK 2015-07-29
+ * + 0.6.00 (0x0600)
+ * - PSXSDK 2016-06-03
+ * + 0.6.1 (0x0601)
+ * - PSXSDK 2018-01-10
+ * + 0.6.2 (0x0602)
+ * - PSXSDK 2019-04-10
+ */
+
+#define PSXSDK_VERSION 0x0602
+
+/**
+ * PSXSDK version information in string format
+ */
+
+#define PSXSDK_VERSION_STRING "0.6.2"
+
+/**
+ * PSXSDK version date (BCD YYYY-MM-DD)
+ */
+
+#define PSXSDK_VERSION_DATE 0x20190410
+
+
+/*
+ * Include some GCC builtin includes
+ */
+
+#ifndef _PSXSDK_WRAPPER
+
+#include <psxbios.h>
+
+#endif
+
+#include <psxgpu.h>
+#include <memcard.h>
+
+#include <psxpad.h>
+#include <psxspu.h>
+#include <psxcdrom.h>
+#include <psxsio.h>
+//#include <adpcm.h>
+#include <psxgte.h>
+
+/**
+ * Scratch pad - unused data cache, that can be used as "fast RAM"
+ */
+
+extern unsigned char __scratchpad[1024];
+
+/**
+ * Coprocessor 0 register numbers
+ */
+
+enum cop0_register_numbers
+{
+ /** Contains the last invalid program address which caused a trap.
+
+ It is set by address errors of all kinds. */
+ COP0_BADVADDR = 8,
+ /** CPU mode flags (status register) */
+ COP0_SR = 12,
+ /** Describes the most recently recognized exception. */
+ COP0_CAUSE = 13,
+ /** Return address from trap */
+ COP0_EPC = 14,
+ /** COP0 type and revision level */
+ COP0_PRID = 15,
+};
+
+/**
+ * Root counter specifications
+ */
+
+enum psx_rcnt_specs
+{
+ /** Pixel clock*/
+ RCntCNT0 = 0xf2000000,
+ /** Horizontal sync*/
+ RCntCNT1 = 0xf2000001,
+ /** System clock / 8 */
+ RCntCNT2 = 0xf2000002,
+ /** VSync (VBlank) */
+ RCntCNT3 = 0xf2000003,
+};
+
+/**
+ * Root counter modes
+ */
+
+enum psx_rcnt_modes
+{
+ /** Interrupt mode */
+ RCntIntr = 0x1000,
+ /** Ignore target and count to 65535 (hex: 0xFFFF) */
+ RCntNotar = 0x0100,
+ /** Timer stop mode */
+ RCntStop = 0x0010,
+ /** System Clock mode */
+ RCntSC = 0x0001,
+};
+
+struct psx_info
+{
+ struct kernel
+ {
+ const char *version; // Kernel version
+ int year; // Kernel year
+ int month; // Kernel month
+ int day; // Kernel day
+ }kernel;
+
+ struct system
+ {
+ int memory; // RAM memory size
+ }system;
+};
+
+/**
+ * Initialize library
+ */
+
+void PSX_Init(void);
+
+/**
+ * Flags for PSX_Init.
+ */
+
+enum psx_init_flags
+{
+ /** PSX_INIT_CD - Initialize CDROM filesystem */
+ PSX_INIT_CD = 1,
+ /** PSX_INIT_SAVESTATE - Save BIOS state before initializing the library */
+ PSX_INIT_SAVESTATE = 2,
+ /** PSX_INIT_NOBIOS - Remove control from the BIOS and let PSXSDK be in complete control */
+ PSX_INIT_NOBIOS = 4,
+};
+
+/**
+ * Deinitialize library
+ */
+
+void PSX_DeInit(void);
+
+/**
+ * Initialize library (extended version)
+ *
+ * flags contains a bitmask specifying which flags are enabled
+ *
+ * PSX_Init() is the same as PSX_InitEx(PSX_INIT_CD)
+ * @param flags Flag bitmask (flags are to be OR'd)
+ */
+
+void PSX_InitEx(unsigned int flags);
+
+/**
+ * Reads the status of the buttons of the two joypads.
+ *
+ * Takes two pointers for 16-bit bitmasks, one for the first player's joypad,
+ * and one for the second one. Their bits are updated to show which buttons were pressed.
+ *
+ * This function only supplies basic functionality, adequate for a normal digital pad.
+ *
+ * If more advanced functionality is desired, use PSX_PollPad() instead of this function.
+ * @attention Note that some joypads, like the official ones from Sony, do not like to be polled more than
+ * once every 1/60th of a second and if this limitation is not considered the data
+ * they return is undefined. Other joypads do not have this limitation but in any case err on the safe side.
+ * @param padbuf Pointer to 16-bit variable where bitmask for pad #1 will be stored.
+ * If NULL is passed, this argument is ignored.
+ * @param padbuf2 Pointer to 16-bit variable where bitmask for pad #2 will be stored
+ * If NULL is passed, this argument is ignored.
+ */
+void PSX_ReadPad(unsigned short *padbuf, unsigned short *padbuf2);
+
+/**
+ * Polls a joypad for information.
+ * @attention Note that some joypads, like the official ones from Sony, do not like to be polled more than
+ * once every 1/60th of a second and if this limitation is not considered the data
+ * they return is undefined. Other joypads do not have this limitation but in any case err on the safe side.
+ * @param pad_num Number of the pad to poll (0 = pad #1, 1 = pad #2, etc.)
+ * @param pad_state Pointer to a psx_pad_state structure in which to store information for the pad.
+ */
+
+void PSX_PollPad(int pad_num, psx_pad_state *pad_state);
+
+/**
+ * Takes a pointer to a struct psx_info structure, and fills it
+ * with information about the PlayStation on which the program is running.
+ * PS-OS kernel build date and version are reported among other things.
+ * @param info Pointer to struct psx_info structure which will be filled.
+ */
+void PSX_GetSysInfo(struct psx_info *info);
+
+/**
+ * Gets Coprocessor 0 status register
+ * @return Value of Coprocessor 0 status register
+ */
+
+unsigned int get_cop0_status(void);
+
+/**
+ * Sets Coprocessor 0 status register
+ * @param sreg New value of Coprocessor 0 status register
+ * @return [[ check: maybe this is a void function ]]
+ */
+
+unsigned int set_cop0_status(unsigned int sreg);
+
+/**
+ * Gets the contents of the program counter when the
+ * last exception happened.
+ * @return Value of the program counter at the time of the last exception
+ */
+
+unsigned int get_cop0_epc(void);
+
+/**
+ * Get value of specified Coprocessor 0 register
+ * @param register_num Number of Coprocessor 0 register whose value must be retrieved
+ * @return Value of specified Coprocessor 0 register
+ */
+
+unsigned int get_cop0_register(unsigned char register_num);
+
+/**
+ * Set value of specified Coprocessor 0 register
+ * @param register_num Number of Coprocessor 0 register whose value must be set
+ * @param value New value of specified Coprocessor 0 register
+ */
+
+void set_cop0_register(unsigned char register_num, unsigned int value);
+
+/**
+ * Get value of the specified (data) register of a specified coprocessor
+ * @param cop_num Coprocessor number
+ * @param register_num Number of coprocessor register whose value must be retrieved
+ * @return Value of specified coprocessor register
+ */
+
+unsigned int get_cop_register(unsigned char cop_num,
+ unsigned char register_num);
+
+
+/**
+ * Get value of the specified control register of a specified coprocessor
+ * @param cop_num Coprocessor number
+ * @param register_num Number of coprocessor register whose value must be retrieved
+ * @return Value of specified coprocessor register
+ */
+
+unsigned int get_cop_ctrl_register(unsigned char cop_num,
+ unsigned char register_num);
+
+/**
+ * Set value of the specified (data) register of a specified coprocessor
+ * @param cop_num Coprocessor number
+ * @param register_num Number of Coprocessor 0 register whose value must be set
+ * @param value New value of specified Coprocessor 0 register
+ */
+
+ void set_cop_register(unsigned char cop_num,
+ unsigned char register_num, unsigned int value);
+
+/**
+ * Set value of the specified control register of a specified coprocessor
+ * @param cop_num Coprocessor number
+ * @param register_num Number of Coprocessor 0 register whose value must be set
+ * @param value New value of specified Coprocessor 0 register
+ */
+
+ void set_cop_ctrl_register(unsigned char cop_num,
+ unsigned char register_num, unsigned int value);
+
+/**
+ * Make the specified coprocessor run the specified instruction
+ * @param operation Operation number for the instruction
+ */
+
+void run_cop_instruction(unsigned char cop_num,
+ unsigned int operation);
+
+// Root counter functions
+
+/**
+ * Set root counter (documentation TO DO)
+ * @param spec Spec
+ * @param target Target
+ * @param mode mode
+ */
+
+int SetRCnt(int spec, unsigned short target, unsigned int mode);
+
+/**
+ * Get root counter (documentation TO DO)
+ * @param spec Spec
+ * @return TO DO
+ */
+
+int GetRCnt(int spec);
+
+/**
+ * Start root counter (documentation TO DO)
+ * @param spec Spec
+ * @return TO DO
+ */
+
+int StartRCnt(int spec);
+
+/**
+ * Stop root counter (documentation TO DO)
+ * @param spec Spec
+ * @return TO DO
+ */
+
+int StopRCnt(int spec);
+
+/**
+ * Restores BIOS state to the one prior the initialization of the library.
+ * This function can only be used if PSX_InitEx() was called with the
+ * PSX_INIT_SAVESTATE flag.
+ * It is usually called by PSX_DeInit() automatically, so unless
+ * you know what you are doing, you do not need to call it yourself.
+ * @return 1 on success, 0 on failure, such as the fact that PSX_InitEx() wasn't called
+ * with the PSX_INIT_SAVESTATE flag.
+ */
+
+int PSX_RestoreBiosState(void);
+
+/**
+ * Gets the bitmask for the flags passed to PSX_InitEx()
+ * @return Flag bitmask
+ */
+
+unsigned int PSX_GetInitFlags(void);
+
+/**
+ * Sets an handler function for the VBlank interrupt.
+ * Used for simple, inaccurate timing - the handler function gets called 60 times a second
+ * in NTSC video mode and 50 times a second in PAL video mode.
+ *
+ * While most games use the VBlank interrupt for timing as they don't require high precision and
+ * have mechanisms to keep up with the different speed in PAL or NTSC video mode, for precise
+ * timing VBlank is inadequate. It is better to look at root counters if you desire precision.
+ *
+ * If there is already a VBlank handler set, this function replaces the current handler with the specified one.
+ * @param h Pointer to (new) VBlank handler function
+ */
+
+void SetVBlankHandler(void (*h)());
+
+/**
+ * Removes a previously set VBlank handler.
+ *
+ * If SetVBlankHandler() was not called before, calling this function has no effect.
+ */
+
+void RemoveVBlankHandler(void);
+
+#endif
diff --git a/libpsx/include/psxbios.h b/libpsx/include/psxbios.h
new file mode 100644
index 0000000..9275393
--- /dev/null
+++ b/libpsx/include/psxbios.h
@@ -0,0 +1,215 @@
+/*
+ * PSXSDK: Bios functions
+ */
+
+#ifndef _PSXBIOS_H
+#define _PSXBIOS_H
+
+/* Joypad functions */
+
+extern void PAD_init(unsigned long mode, unsigned long *pad_buf);
+extern int PAD_dr(void);
+
+/* ROM information functions */
+
+/**
+ * Returns PSX kernel date.
+ * @return Kernel date n 0xYYYYMMDD BCD format.
+ */
+
+unsigned long GetKernelDate(void);
+
+/**
+ * Returns a pointer to a zero-terminated
+ * string which contains the kernel ROM version.
+ * @return Pointer to a zero-terminated string which contains the kernel ROM version.
+ */
+
+const char *GetKernelRomVersion(void);
+
+/**
+ * Returns a pointer to a zero-terminated
+ * string which contains the system ROM version.
+ * @return Zero-terminated string which contains the system ROM version.
+ */
+
+const char *GetSystemRomVersion(void);
+
+/**
+ * GetRamSize() should return size of RAM in bytes.
+ * It doesn't seem to work most times. On SCPH1001, it returns 0.
+ * On SCPH1000, it returns 2 (which is the number of megabytes of RAM
+ * the PSX has.)
+ * @return Size of RAM in bytes.
+ */
+
+unsigned int GetRamSize(void);
+
+/* Interrupt/Exception functions */
+
+/*void Exception();*/
+
+/**
+ * Enters a critical section.
+ */
+
+void EnterCriticalSection(void);
+
+/**
+ * Exits a critical section.
+ */
+
+void ExitCriticalSection(void);
+
+void SysEnqIntRP(int index, unsigned int *buf);
+void SysDeqIntRP(int index, unsigned int *buf);
+
+void ResetEntryInt(void);
+
+
+/**
+ * Directory entry
+ */
+struct DIRENTRY
+{
+ /** Filename */
+ char name[20];
+ /** Attributes */
+ unsigned int attr;
+ /** File size in bytes */
+ int size;
+ /** Pointer to next file entry */
+ struct DIRENTRY *next;
+ /** System reserved */
+ unsigned char system[8];
+};
+
+/**
+ * Gets information about the first file which
+ * matches the pattern. ? and * wildcards can be used.
+ * Characters after * are ignored.
+ * @param name File name string
+ * @param dirent Pointer to a struct DIRENTRY object.
+ * @return dirent on success, NULL on failure.
+ */
+
+struct DIRENTRY *firstfile(const char *name, struct DIRENTRY *dirent);
+
+/**
+ * Finds a file with the same conditions as the previous call to firstfile().
+ * If a corresponding file is found, file information is stored
+ * to the structure pointed to by dir.
+ *
+ * @param dir Pointer to a struct DIRENTRY object.
+ * @return dir on success, NULL on failure.
+ */
+
+struct DIRENTRY *nextfile(struct DIRENTRY *dir);
+
+/**
+ * Gets the file size of the file named "name".
+ * It is actually just a wrapper around firstfile.
+ * It rounds the file size to the block size (2048).
+ * @param name FIle name string
+ * @return File size in bytes, rounded.
+ */
+
+int get_file_size(const char *name);
+
+/**
+ * This function is like get_file_size() but doesn't round
+ * the file size to the block size.
+ * @param name File name string
+ * @return File size in bytes, unrounded.
+ */
+
+int get_real_file_size(const char *name);
+
+void InitHeap(void *block , int size);
+void FlushCache(void);
+
+void SetRCntHandler(void (*callback)(), int spec, unsigned short target);
+void RemoveRCntHandler(int spec);
+
+/**
+ * Opens an event, and returns its identifier
+ * Must be executed in a critical section
+ * @param desc Numerical cause descriptor
+ * @param spec Numerical event type
+ * @param mode Numerical mode
+ * @param func Function pointer to callback function
+ * @return Numerical identifier for the event opened
+ */
+
+int OpenEvent(
+ int desc, // Cause descriptor
+ int spec, // Event type
+ int mode, // Mode
+ int *(*func)(void) // Pointer to callback function
+);
+
+/**
+ * Enables an event by its identifier returned by OpenEvent()
+ * @param event Numerical event identifier
+ * @return ???
+ */
+
+int EnableEvent(unsigned int event);
+
+/**
+ * Closes an event by its identifier
+ * @param event Numerical event identifier
+ * @return ???
+ */
+
+int CloseEvent(unsigned int event);
+
+/**
+ * Disables an event by its identifier
+ * @param event Numerical event identifier
+ * @return ???
+ */
+
+int DisableEvent(unsigned int event);
+
+/**
+ * Generates an event. This must be executed in a critical section.
+ * If the event to deliver is set to generate an interrupt, the handler function is called.
+ * @param ev1 Numerical cause descriptor
+ * @param ev2 Numerical event class
+ * @return ???
+ */
+
+int DeliverEvent(unsigned int ev1, // Cause descriptor
+ int ev2); // Event class
+
+/**
+ * Checks if the event specified by its identifier has occured
+ * @param event Numerical event identifier
+ * @return 1 if the event has occured, 0 if it has not
+ */
+
+int TestEvent(unsigned int event);
+
+/**
+ * Waits until the event specified by identifier occurs.
+ * @param event Numerical event identifier
+ * @return 1 on success, 0 on failure.
+ */
+
+int WaitEvent(unsigned int event);
+
+/**
+ * Replaces the executable image in memory with the one
+ * contained in another executable file in PSX-EXE format.
+ * WARNING: Does not work right now.
+ *
+ * Most likely you want PSX_RunExe()
+ * @param name Path name of PSX-EXE executable
+ * @param argc Number of arguments
+ * @param argv Pointer to an array of string pointers for each argument
+ */
+
+void LoadExec(char *name, int argc, char **argv);
+
+#endif
diff --git a/libpsx/include/psxcdrom.h b/libpsx/include/psxcdrom.h
new file mode 100644
index 0000000..2f18e68
--- /dev/null
+++ b/libpsx/include/psxcdrom.h
@@ -0,0 +1,82 @@
+#ifndef _PSXCDROM_H
+#define _PSXCDROM_H
+
+#define CDSTATUS_PLAY 0x80
+#define CDSTATUS_SEEK 0x40
+#define CDSTATUS_SHELLOPEN 0x10
+
+// Command names
+
+enum
+{
+ CdlSync = 0,
+ CdlNop = 1, CdlGetstat = 1,
+ CdlSetloc = 2,
+ CdlPlay = 3,
+ CdlForward = 4,
+ CdlBackward = 5,
+ CdlReadN = 6,
+ CdlStandby = 7,
+ CdlStop = 8,
+ CdlPause = 9,
+ CdlInit = 10,
+ CdlMute = 11,
+ CdlDemute = 12,
+ CdlSetfilter = 13,
+ CdlSetmode = 14,
+ CdlSetparam = 15,
+ CdlGetlocL = 16,
+ CdlGetlocP = 17,
+ CdlCmd18 = 18,
+ CdlGetTN = 19,
+ CdlGetTD = 20,
+ CdlSeekL = 21,
+ CdlSeekP = 22,
+ CdlCmd23 = 23,
+ CdlCmd24 = 24,
+ CdlTest = 25,
+ CdlID = 26,
+ CdlReadS = 27,
+ CdlReset = 28,
+ CdlCmd29 = 29,
+ CdlReadTOC = 30
+};
+
+/*
+ * Send a low-level CDROM command
+ * cmd = command number
+ * num = number of arguments
+ * ... = arguments
+ */
+
+void CdSendCommand(int cmd, int num, ...);
+
+/**
+ * Reads the results of a low-level CDROM command
+ *
+ * @param out Pointer to array of chars where the output will be stored
+ * @param max Maximum number of bytes to store
+ *
+ * Return value: number of results.
+ */
+
+int CdReadResults(unsigned char *out, int max);
+
+/**
+ * Gets CDROM drive status
+ * @return CDROM drive status bitmask
+ */
+
+int CdGetStatus(void);
+
+/**
+ * Play an Audio CD track
+ * @return 1 on success, 0 on failure
+ */
+
+int CdPlayTrack(unsigned int track);
+
+unsigned char CdRamRead(unsigned short addr);
+
+
+#endif
diff --git a/libpsx/include/psxgpu.h b/libpsx/include/psxgpu.h
new file mode 100644
index 0000000..373b2d6
--- /dev/null
+++ b/libpsx/include/psxgpu.h
@@ -0,0 +1,1142 @@
+#ifndef _PSXGPU_H
+#define _PSXGPU_H
+
+#define GPU_DATA_PORT_ADDR 0x1f801810
+#define GPU_CONTROL_PORT_ADDR 0x1f801814
+#define GPU_DATA_PORT *((volatile unsigned int*)GPU_DATA_PORT_ADDR)
+#define GPU_CONTROL_PORT *((volatile unsigned int*)GPU_CONTROL_PORT_ADDR)
+
+#define DPCR *((volatile unsigned int*)0x1f8010f0)
+#define D2_MADR *((volatile unsigned int*)0x1f8010a0)
+#define D2_BCR *((volatile unsigned int*)0x1f8010a4)
+#define D2_CHCR *((volatile unsigned int*)0x1f8010a8)
+
+#define get_clutid(cx, cy) (((cx&0x3ff)>>4)|((cy&0x1ff)<<6))
+
+/**
+ * Initializes the GPU. Same as GsInitEx(0)
+ *
+ * The display is left disabled.
+ * You can enable it with GsEnableDisplay() or more preferably with GsSetVideoMode()
+ */
+
+void GsInit(void);
+
+/**
+ * Initializes the GPU.
+ *
+ * The display is left disabled.
+ * You can enable it with GsEnableDisplay() or more preferably with GsSetVideoMode()
+ * @param flags Flag bitmask
+ */
+
+void GsInitEx(unsigned int flags);
+
+/**
+ * Resets the GPU
+ */
+
+void GsReset(void);
+
+/**
+ * Enables the display (i.e. generation of video output).
+ *
+ * Unless you are doing low-level GPU programming, you don't need to call this function;
+ * the display is enabled automatically by GsSetVideoMode().
+ * @param enable If TRUE (>=1) the display will be enabled, if FALSE (== 0) it will be disabled
+ */
+
+void GsEnableDisplay(int enable);
+
+/**
+ * Sets a video mode and enables the display. It does so in a quicker way
+ * than GsSetVideoModeEx(), which wants more arguments but offers greater control
+ * @param width Width
+ + 640, 384, 320 and 256 are supported by the PlayStation hardware.
+ * @param height Height
+ + 480 and 240 are supported by the PlayStation hardware.
+ * You probably want to use GsSetVideoModeEx() if you set
+ * 480 here, because this function doesn't enable interlacing.
+ * @param video_mode Video mode
+ + VMODE_NTSC for NTSC, VMODE_PAL for PAL
+ * @return 1 on success, 0 on failure (such as unavailable video mode)
+ */
+
+int GsSetVideoMode(int width, int height, int video_mode);
+
+/**
+ * Works like GsSetVideoMode() but offers more control.
+ * Interlaced, 24-bit RGB, and "reverse" flags can be specified.
+ * @param width Width
+ + 640, 384, 320 and 256 are supported by the PlayStation hardware.
+ * @param height Height
+ + 480 and 240 are supported by the PlayStation hardware.
+ * @param video_mode Video mode
+ + VMODE_NTSC for NTSC, VMODE_PAL for PAL
+ * @param rgb24 24-bit RGB mode
+ + If TRUE (!=0) enables the very rarely used 24-bit color mode. Unless you're very creative, don't enable this.
+ * @param inter Interlacing
+ + If TRUE (!=0) enables interlacing. If you set the height paramater to 480, and you want to display your program on
+ a real television screen, you must enable this.
+ * @param reverse Reverse??
+ + The function of this is not really known. Stay safe and set this to FALSE (0).
+ * @return 1 on success, 0 on failure (such as unavailable video mode)
+ */
+
+int GsSetVideoModeEx(int width, int height, int video_mode, int rgb24, int inter, int reverse);
+
+/**
+ * Assigns the internal pointer to the primitive list to the desired one,
+ * and resets the linked list position counter.
+ * The memory address specified by your pointer has to have enough space free to contain all
+ * the packets which you want to send.
+ * @param listptr Pointer to primitive list
+ */
+
+void GsSetList(unsigned int *listptr);
+
+/**
+ * Assigns the internal pointer to the primitive list to the desired one,
+ * an sets the linked list position counter to the specified value.
+ * The memory address specified by your pointer has to have enough space free to contain all
+ * the packets which you want to send, and you must ensure that the specified position
+ * is not out of bounds.
+ * @param listptr Pointer to primitive list
+ * @param listpos List position
+ */
+
+void GsSetListEx(unsigned int *listptr, unsigned int listpos);
+
+/**
+ * Draws the primitive list.
+ *
+ * This also has the effect of resetting the current drawing list position.
+ */
+
+void GsDrawList(void);
+
+/**
+ * Draws the primitive list using port I/O access.
+ *
+ * GsDrawList() uses DMA to transfer the primitive data in the linked list to the GPU.
+ *
+ * This function which is of main interest to low-level programmers, uses GPU port I/O access instead,
+ * and it is slower (as reads and writes must be done by the main CPU), but works in all situations,
+ * even when you can't get DMA working.
+ *
+ * This function due to its nature is blocking, and always waits for completion.
+ */
+
+void GsDrawListPIO(void);
+
+/**
+ * Makes non-blocking gpu functions like GsDrawList()
+ * wait for completion. Removes the need to use GsIsDrawing()/GsIsWorking()
+ */
+
+void GsSetAutoWait(void);
+
+/** Monochrome 3 point polygon */
+
+typedef struct
+{
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** X Coordinates for vertexes */
+ short x[3];
+ /** Y Coordinates for vertexes */
+ short y[3];
+ /** Attribute bitmask */
+ unsigned int attribute;
+}GsPoly3;
+
+/** Monochrome 4 point polygon */
+
+typedef struct
+{
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** X Coordinates for vertexes */
+ short x[4];
+ /** Y Coordinates for vertexes */
+ short y[4];
+ /** Attribute */
+ unsigned int attribute;
+}GsPoly4;
+
+/** Textured 3 point polygon */
+
+typedef struct
+{
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** X Coordinates for vertexes */
+ short x[3];
+ /** Y Coordinates for vertexes */
+ short y[3];
+ /** X Texture offsets for vertexes */
+ unsigned char u[3];
+ /** Y Texture offset for vertexes */
+ unsigned char v[3];
+ /** CLUT X coordinate */
+ short cx;
+ /** CLUT Y coordinate */
+ short cy;
+ /** Attribute */
+ unsigned int attribute;
+ /** Texture page */
+ unsigned char tpage;
+}GsTPoly3;
+
+/** Textured 4 point polygon */
+
+typedef struct
+{
+ /** X Coordinates for vertexes */
+ short x[4];
+ /** Y Coordinates for vertexes */
+ short y[4];
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** CLUT X coordinate */
+ short cx;
+ /** CLUT Y coordinate */
+ short cy;
+ /** Texture page */
+ unsigned char tpage;
+ /** Horizontal texture offset */
+ unsigned char u[4];
+ /** Vertical texture offset */
+ unsigned char v[4];
+ /** Attribute */
+ unsigned int attribute;
+}GsTPoly4;
+
+/** Graduated 3 point polygon */
+
+typedef struct
+{
+ /** Red color components (0-255) */
+ unsigned char r[3];
+ /** Green color components (0-255) */
+ unsigned char g[3];
+ /** Blue color components (0-255) */
+ unsigned char b[3];
+ /** X Coordinates for vertexes */
+ short x[3];
+ /** Y Coordinates for vertexes */
+ short y[3];
+ /** Attribute */
+ unsigned int attribute;
+}GsGPoly3;
+
+/** Graduated 4 point polygon */
+
+typedef struct
+{
+ /** Red color components (0-255) */
+ unsigned char r[4];
+ /** Green color components (0-255) */
+ unsigned char g[4];
+ /** Blue color components (0-255) */
+ unsigned char b[4];
+ /** X Coordinates for vertexes */
+ short x[4];
+ /** Y Coordinates for vertexes */
+ short y[4];
+ /** Attribute */
+ unsigned int attribute;
+}GsGPoly4;
+
+/** Graduated textured 3 point polygon */
+
+typedef struct
+{
+ /** Red color components (0-255) */
+ unsigned char r[3];
+ /** Green color components (0-255) */
+ unsigned char g[3];
+ /** Blue color components (0-255) */
+ unsigned char b[3];
+ /** X Coordinates for vertexes */
+ short x[3];
+ /** Y Coordinates for vertexes */
+ short y[3];
+ /** CLUT X coordinate */
+ short cx;
+ /** CLUT Y coordinate */
+ short cy;
+ /** Texture page */
+ unsigned char tpage;
+ /** Horizontal texture offset */
+ unsigned char u[3];
+ /** Vertical texture offset */
+ unsigned char v[3];
+ /** Attribute */
+ unsigned int attribute;
+}GsGTPoly3;
+
+/** Graduated textured 4 point polygon */
+
+typedef struct
+{
+ /** Red color components (0-255) */
+ unsigned char r[4];
+ /** Green color components (0-255) */
+ unsigned char g[4];
+ /** Blue color components (0-255) */
+ unsigned char b[4];
+ /** X Coordinates for vertexes */
+ short x[4];
+ /** Y Coordinates for vertexes */
+ short y[4];
+ /** CLUT X coordinate */
+ short cx;
+ /** CLUT Y coordinate */
+ short cy;
+ /** Texture page */
+ unsigned char tpage;
+ /** Horizontal texture offset */
+ unsigned char u[4];
+ /** Vertical texture offset */
+ unsigned char v[4];
+ /** Attribute */
+ unsigned int attribute;
+}GsGTPoly4;
+
+/** Monochrome line */
+
+typedef struct
+{
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** X Coordinates for points */
+ short x[2];
+ /** Y Coordinates for points */
+ short y[2];
+ /** Attribute */
+ unsigned int attribute;
+}GsLine;
+
+/** Dot (pixel) */
+
+typedef struct
+{
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** X coordinate */
+ short x;
+ /** Y coordinate */
+ short y;
+ /** Attribute */
+ unsigned int attribute;
+}GsDot;
+
+/** Graduated line */
+
+typedef struct
+{
+ /** Red color components (0-255) */
+ unsigned char r[2];
+ /** Green color components (0-255) */
+ unsigned char g[2];
+ /** Blue color components (0-255) */
+ unsigned char b[2];
+ /** X coordinates for points */
+ short x[2];
+ /** Y coordinates for points */
+ short y[2];
+ /** Attribute */
+ unsigned int attribute;
+}GsGLine;
+
+/** Sprite */
+
+typedef struct
+{
+ short x, y; /* X, Y positions */
+ unsigned char u, v; /* Offset into texture page of sprite image data */
+ short w, h; /* Width and height of sprite */
+ short cx, cy; /* Color look up table (palette) X, Y positions */
+ unsigned char r, g, b; /* Luminosity of color components - 128 is normal luminosity */
+ unsigned char tpage; /* Texture page */
+ unsigned int attribute; /* Attribute */
+
+ /* Scaling? These are only candidates...
+
+ scalex:
+ Denotes horizontal scaling
+
+ 0 = true size (unmodified)
+ 1 = true size (*1)
+ 2 = double size (*2)
+ 3 = triple size (*3)
+ ...
+
+ -1 = true size (/1)
+ -2 = half size (/2)
+ -3 = one-third size (/3)
+ ...
+
+ scaley:
+ Denotes vertical scaling
+
+ *** The behaviour below was introduced in PSXSDK 0.5
+
+ If scalex > 8,
+ resulting width will be (original_width * scalex) / 4096
+ scalex = 4096 (SCALE_ONE) (original width), scalex = 2048 (half width), etc.
+ If scaley > 8,
+ resulting height will be (original_height * scaley) / 4096
+ works like scalex but affects height
+ */
+ int scalex, scaley;
+
+ int rotate; // Rotation angle - Fixed point notation, 4096 = 1 degree
+ int mx, my; // Coordinates of rotation center - relative to coordinates of sprite
+}GsSprite;
+
+/** Rectangle */
+
+typedef struct
+{
+
+ short x, y;
+ short w, h;
+ unsigned char r, g, b;
+ unsigned int attribute; /* Attribute */
+}GsRectangle;
+
+typedef struct
+{
+ /** Number of points */
+ unsigned int npoints;
+ /** Red color component (0-255) */
+ unsigned char r;
+ /** Green color component (0-255) */
+ unsigned char g;
+ /** Blue color component (0-255) */
+ unsigned char b;
+ /** X Coordinates for points */
+ short *x;
+ /** Y Coordinates for points */
+ short *y;
+ /** Attribute */
+ unsigned int attribute;
+}GsPolyLine;
+
+typedef struct
+{
+ /** Number of points */
+ unsigned int npoints;
+ /** Red color components (0-255) */
+ unsigned char *r;
+ /** Green color components (0-255) */
+ unsigned char *g;
+ /** Blue color components (0-255) */
+ unsigned char *b;
+ /** X Coordinates for points */
+ short *x;
+ /** Y Coordinates for points */
+ short *y;
+ /** Attribute */
+ unsigned int attribute;
+}GsGPolyLine;
+
+/** Map */
+
+//typedef struct
+//{
+// short x, y; /* X, Y positions */
+// unsigned char u, v; /* Offset into texture page of sprite image data */
+// short w, h; /* Width and height of tilemap */
+// short l; /* Length of tilemap line */
+// short cx, cy; /* Color look up table (palette) X, Y positions */
+// unsigned char r, g, b; /* Luminosity of color components - 128 is normal luminosity */
+// unsigned char tpage; /* Texture page */
+// unsigned int attribute; /* Attribute */
+//
+// unsigned short tmw, tmh; /* Map texture width and height */
+// unsigned char tw, th; /* Map tile width and height */
+//
+// unsigned char tsize; /* Size of tile in map (1 = 8-bit, 2 = 16-bit, 4 = 32-bit) */
+//
+// unsigned int tmask; /* Inverted mask for tile number */
+//
+// void *data; /* Pointer to beginning of map data */
+//}GsMap;
+
+/** Texture color modes. */
+
+enum psx_gpu_texmodes
+{
+ /** 4-bit color mode */
+ COLORMODE_4BPP,
+ /** 8-bit color mode */
+ COLORMODE_8BPP,
+ /** 16-bit color mode */
+ COLORMODE_16BPP,
+ /** 24-bit color mode */
+ COLORMODE_24BPP
+};
+
+/**
+ * This is the luminance factor with which images
+ * are drawn as they are stored. (i.e. without applying lighting)
+ *
+ * NORMAL_LUMINOSITY (sic) is kept for backward compatibility,
+ * but "luminosity" is an incorrect term here.
+ */
+
+#define NORMAL_LUMINANCE 128
+#define NORMAL_LUMINOSITY NORMAL_LUMINANCE
+
+/**
+ * Macro to specify texture color mode, takes a value from psx_gpu_texmodes
+ */
+#define COLORMODE(x) x&3
+/**
+ * Macro to specify translucency/semitransparency mode, where x can be a value from 0 to 3.
+ *
+ * If a pixel in image data to be drawn has the STP bit set, semitransparency
+ * processing is enabled for that pixel.
+ *
+ * When the color is black (RGB=0,0,0) STP is processed differently from when it is not
+ * black.
+ *
+ * The table below shows the differences:
+ *
+ * Color | STP bit | Processing off | Processing on
+ * ----- | ---- | ----- | ----
+ * Black | 0 | Transparent | Transparent
+ * Black | 1 | Non-transparent |Non-Transparent
+ * Not black | 0 | Non-Transparent |Non-Transparent
+ * Not black | 1 | Non-Transparent |Transparent
+ *
+ * If the image pixel is semi-transparent (STP bit set) and not black, the formulas for the
+ * final pixel color are the following:
+ *
+ * Mode | From framebuffer pixel| From image pixel
+ * ---- | --- | -----
+ * 0 | +50% | +50%
+ * 1 | +100% | +100%
+ * 2 | +100% | -100%
+ * 3 | +100% | +25%
+ *
+ * The final color component values do not underflow or overflow, they simply saturate at 0 or 255.
+ */
+#define TRANS_MODE(x) ((x&3)<<2)
+/**
+ * Enable semi-transparency processing for the primitive.
+ */
+#define ENABLE_TRANS (1<<4)
+/**
+ * Enable horizontal flipping for the primitive.
+ */
+#define H_FLIP (1<<5)
+/**
+ * Enable vertical flipping for the primitive.
+ */
+#define V_FLIP (1<<6)
+
+/**
+ * Drawing environment.
+ */
+
+typedef struct
+{
+ /**
+ * Dithering enabled flag.
+ */
+ unsigned char dither;
+ /**
+ * Enable drawing on display area flag.
+ *
+ * If this flag is enabled, drawing on display area is allowed.
+ *
+ * Usually you enable this flag when you do not want to use double buffering.
+ */
+ unsigned char draw_on_display;
+
+ /**
+ * Drawing area X start coordinate in framebuffer
+ */
+ short x;
+ /**
+ * Drawing area Y start coordinate in framebuffer
+ */
+ short y;
+ /**
+ * Drawing area width.
+ */
+ short w;
+ /**
+ * Drawing area height.
+ */
+ short h;
+
+ /*
+ * Drawing offset
+ */
+ //short off_x, off_y;
+
+ /**
+ * Masking settings (can also be set with GsSetMasking())
+ */
+
+ /**
+ * Do not draw over pixels which have their mask bit set
+ */
+ unsigned char ignore_mask;
+ /**
+ * If this is set, every pixel drawn will have the mask bit set
+ */
+ unsigned char set_mask;
+}GsDrawEnv;
+
+/**
+ * Display environment.
+ *
+ * The width and height of the display area are those of the currently set video mode.
+ */
+
+typedef struct
+{
+ /** Display area X start coordinate in framebuffer. */
+ short x;
+ /** Display area Y start coordinate in framebuffer. */
+ short y;
+}GsDispEnv;
+
+/**
+ * Image
+ * @brief This structure describes a TIM image
+ */
+
+typedef struct
+{
+
+
+ /** Pixel (color) mode. 0 = 4bpp, 1 = 8bpp, 2 = 16bpp, 3 = 24bpp */
+ int pmode;
+ /** Reports whether this image has a Color Look Up Table. 1 if there's a CLUT, 0 otherwise. */
+ int has_clut;
+ /** X coordinate of CLUT in framebuffer */
+ int clut_x;
+ /** Y coordinate of CLUT in framebuffer */
+ int clut_y;
+ /** Width of CLUT in framebuffer */
+ int clut_w;
+ /** Height of CLUT in framebuffer */
+ int clut_h;
+ /** X coordinate of image in framebuffer */
+ int x;
+ /** Y coordinate of image in framebuffer */
+ int y;
+ /** Width of image in framebuffer */
+ int w;
+ /** Height of image in framebuffer */
+ int h;
+ /** Pointer to CLUT data */
+ void *clut_data;
+ /** Pointer to image data */
+ void *data;
+}GsImage;
+
+/**
+ * Adds a monochrome 3 point polygon to the packet list
+ * @param poly3 Pointer to structure for monochrome 3 point polygon
+ */
+
+void GsSortPoly3(GsPoly3 *poly3);
+
+/**
+ * Adds a monochrome 4 point polygon to the packet list
+ * @param poly4 Pointer to structure for monochrome 4 point polygon
+ */
+
+void GsSortPoly4(GsPoly4 *poly4);
+
+/**
+ * Adds a textured 3 point polygon to the packet list
+ * @param tpoly3 Pointer to structure for textured 3 point polygon
+ */
+
+void GsSortTPoly3(GsTPoly3 *tpoly3);
+
+/**
+ * Adds a textured 4 point polygon to the packet list
+ * @param tpoly4 Pointer to structure for textured 4 point polygon
+ */
+
+void GsSortTPoly4(GsTPoly4 *tpoly4);
+
+/**
+ * Adds a gradated 3 point polygon to the packet list
+ * @param poly3 Pointer to structure for gradated 3 point polygon
+ */
+
+void GsSortGPoly3(GsGPoly3 *poly3);
+
+/**
+ * Adds a gradated 4 point polygon to the packet list
+ * @param poly4 Pointer to structure for gradated 4 point polygon
+ */
+
+void GsSortGPoly4(GsGPoly4 *poly4);
+
+/**
+ * Adds a gradated textured 3 point polygon to the packet list
+ * @param tpoly3 Pointer to structure for textured 3 point polygon
+ */
+
+void GsSortGTPoly3(GsGTPoly3 *tpoly3);
+
+/**
+ * Adds a gradated 4 point polygon to the packet list
+ * @param tpoly4 Pointer to structure for textured 4 point polygon
+ */
+
+void GsSortGTPoly4(GsGTPoly4 *tpoly4);
+
+/**
+ * Adds a monochrome line to the packet list
+ * @param line Pointer to structure for monochrome line
+ */
+
+void GsSortLine(GsLine *line);
+
+/**
+ * Adds a gradated line to the packet list
+ * @param line Pointer to structure for gradated line
+ */
+
+void GsSortGLine(GsGLine *line);
+
+/**
+ * Adds a dot (pixel) to the packet list
+ * @param dot Pointer to structure for dot
+ */
+
+void GsSortDot(GsDot *dot);
+
+/**
+ * Adds a sprite to the packet list
+ * @param sprite Pointer to structure for sprite
+ */
+
+void GsSortSprite(GsSprite *sprite);
+
+/**
+ * Always adds a REAL sprite to the packet list
+ *
+ * + GsSortSprite() on the other hand checks for scaling and flipping, which
+ * are not supported by the "sprite" primitive on the PlayStation, but instead
+ * are done by using a textured 4-point polygon accordingly.
+ * GsSortSprite() only uses the sprite primitive when all the attributes
+ * can be done with a "sprite" primitive as well.
+ *
+ * @param sprite Pointer to structure for sprite
+ */
+
+void GsSortSimpleSprite(GsSprite *sprite);
+
+/**
+ * Adds a rectangle to the packet list
+ * @param rectangle Pointer to structure for rectangle
+ */
+
+void GsSortRectangle(GsRectangle *rectangle);
+
+/**
+ * Moves image data from a part of the framebuffer to another.
+ * Actually it does a copy.
+ * @param src_x Top-left X coordinate of source area
+ * @param src_y Top-left Y coordinate of source area
+ * @param dst_x Top-left X coordinate of destination area
+ * @param dst_y Top-left Y coordinate of destination area
+ * @param w Width of area
+ * @param h Height of area
+ */
+
+void MoveImage(int src_x, int src_y, int dst_x, int dst_y, int w, int h);
+
+/**
+ * Loads image data into framebuffer memory.
+ * @param img Pointer to raw image data
+ * @param x Top-left X coordinate of destination area
+ * @param y Top-left Y coordinate of destination area
+ * @param w Width of image data
+ * @param h Height of image data
+ */
+
+void LoadImage(void *img, int x, int y, int w, int h);
+
+/**
+ * Draws a rectangle in the framebuffer, without considering drawing
+ * and display environments (i.e. it does so in an absolute way)
+ * @param x Top-left X coordinate of area
+ * @param y Top-left Y coordinate of area
+ * @param w Area width
+ * @param h Area height
+ * @param r Red (0 - 255)
+ * @param g Green (0 - 255)
+ * @param b Blue (0 - 255)
+ */
+
+void DrawFBRect(int x, int y, int w, int h, int r, int g, int b);
+
+/**
+ * Set drawing environment
+ * @param drawenv Pointer to drawing environment structure
+ */
+
+void GsSetDrawEnv(GsDrawEnv *drawenv);
+
+/**
+ * Set display environment
+ * @param dispenv Pointer to display environment structure
+ */
+
+void GsSetDispEnv(GsDispEnv *dispenv);
+
+
+
+/* If this flag is set, pixels drawn have MSB set */
+#define MASK_SET 1
+/* If this flag is set, pixels aren't drawn over pixels with MSB set */
+#define MASK_IGNORE 2
+
+ /**
+ * Sets masking settings
+ * @param flag Bitwise flags
+ */
+
+void GsSetMasking(unsigned char flag);
+
+/**
+ * Return pointer position in linked list
+ * @return Pointer position in linked list
+ */
+
+unsigned int GsListPos(void);
+
+/**
+ * Three functions which send data to the control port and to the data port
+ */
+
+void gpu_ctrl(unsigned int command, unsigned int param);
+void gpu_data(unsigned int data);
+void gpu_data_ctrl(unsigned int command, unsigned int param);
+
+/**
+ * Puts information about a TIM image passed in a buffer in a GsImage structure.
+ */
+
+int GsImageFromTim(GsImage *image, void *timdata);
+
+/**
+ * Uploads an image described by a GsImage structure to video memory.
+ */
+
+void GsUploadImage(GsImage *image);
+
+/**
+ * Fills a GsSprite structure with information from an image described
+ * by a GsImage structure, then optionally uploads data to video memory.
+ * Sprite coordinates are set to 0.
+ */
+
+int GsSpriteFromImage(GsSprite *sprite, GsImage *image, int do_upload);
+
+/**
+ * Checks if the GPU is drawing
+ * @return 1 if GPU is drawing, 0 otherwise
+ */
+
+int GsIsDrawing(void);
+
+/**
+ * Checks if the GPU is working. Alias of GsIsDrawing()
+ * @return 1 if GPU is working, 0 otherwise.
+ */
+
+int GsIsWorking(void); // Alias of GsIsDrawing()
+
+/**
+ * Clear Video RAM
+ */
+
+void GsClearMem(void);
+
+/**
+ * Loads the built-in 8x8 font in Video RAM at the specified coordinates
+ *
+ *
+ * Specifying cx and cy as -1 will not load the black&white CLUT to
+ * video memory. Use GsSetFont() to specify clut x and clut y in that case.
+ *
+ * The font occupies a space of 16x128 pixels in 16-bit mode,
+ * and 64x128 in 4-bit mode.
+* @param fb_x X coordinate in framebuffer
+ * @param fb_y Y coordinate in framebuffer
+ * @param cx X coordinate of black/white CLUT in framebuffer
+ * @param cy Y coordinate of black/white CLUT in framebuffer
+ */
+
+void GsLoadFont(int fb_x, int fb_y, int cx, int cy);
+
+/**
+ * Prints string using 8x8 font at screen coordinates x, y
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param fmt format (like *printf())
+ * @return Position identifier.
+ */
+
+unsigned int GsPrintFont(int x, int y, const char *fmt, ...);
+
+/**
+ * Prints string using 8x8 font at screen coordinates x, y
+ * Apart from using a variable argument list, this function
+ * is identical to GsPrintFont()
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param fmt format (like *printf())
+ * @param ap Variable argument list
+ * @return Position identifier.
+ */
+
+unsigned int GsVPrintFont(int x, int y, const char *fmt, va_list ap);
+
+/**
+ * Change font coordinates without reloading it
+ */
+
+void GsSetFont(int fb_x, int fb_y, int cx, int cy);
+
+/**
+ * This is a function that sets an internal variable
+ * flags should be specified as an OR mask
+ *
+ * to set the wrap and scale attributes, with X scaling factor 2 and Y scaling
+ * factor 3, for example:
+ * GsSetFontAttrib(PRFONT_WRAP | PRFONT_SCALE
+ * | PRFONT_SCALEX(2) | PRFONT_SCALEY(3));
+ *
+ * to remove all attributes (normal printing):
+ *
+ * GsSetFontAttrib(0);
+ *
+ * PRFONT_WRAP can't coexist with PRFONT_CENTER or PRFONT_RIGHT
+ * PRFONT_CENTER and PRFONT_RIGHT are justifying attributes and as such
+ * they are mutually exclusive - they cannot coexist with each other.
+ * Specifying both will give priority to PRFONT_CENTER.
+ *
+ * Attribute list:
+ *
+ * PRFONT_WRAP - Wrap to next row when the text would fall off the screen
+ * Ideal for debug
+ * PRFONT_SCALE - Enable font scaling
+ * PRFONT_SCALEX(i) - Specifies the factor "i" as the X scaling factor
+ * This has the same meaning as a sprite's scaling factor
+ * PRFONT_SCALEY(i) - Specify the factor "i" as the Y scaling factor
+ * This has the same meaning as a sprite's scaling factor
+ * PRFONT_RIGHT - Justifies text to the right
+ * PRFONT_CENTER - Justifies text at the center
+ * PRFONT_RL(f) - Luminance factor for the red component
+ * PRFONT_GL(f) - Luminance factor for the green component
+ * PRFONT_BL(f) - Luminance factor for the blue component
+*/
+
+void GsSetFontAttrib(unsigned int flags);
+
+/**
+ * Sets drawing environment
+ * Enables drawing on the display area, disables dithering and disables all masking flags by default
+ * @param x Top-left X coordinate of framebuffer area to use for drawing
+ * @param y Top-left Y coordinate of framebuffer area to use for drawing
+ * @param w Width of area
+ * @param h Height of area
+ */
+
+void GsSetDrawEnvSimple(int x, int y, int w, int h);
+
+/**
+ * Sets display environment
+ * @param x Top-left X coordinate of framebuffer area to display
+ * @param y Top-left Y coordinate of framebuffer area to display
+ */
+
+void GsSetDispEnvSimple(int x, int y);
+
+/**
+ Television video modes.
+*/
+enum psx_gpu_vmodes
+{
+ /** NTSC video mode, 60Hz */
+ VMODE_NTSC,
+ /** PAL video mode, 50Hz */
+ VMODE_PAL
+};
+
+/** One scaling unit. */
+
+#define SCALE_ONE 4096
+
+/** One rotation unit. */
+
+#define ROTATE_ONE 4096
+
+// GsSetFontAttrib() Attribute Flags
+
+#define PRFONT_WRAP 1
+#define PRFONT_CENTER 2
+#define PRFONT_RIGHT 4
+#define PRFONT_SCALE 8
+#define PRFONT_UNIXLF 16
+#define PRFONT_COLOR 32
+
+// These below are not really attributes... but use them as if they were.
+
+unsigned int PRFONT_SCALEX(int i);
+unsigned int PRFONT_SCALEY(int i);
+unsigned int PRFONT_RL(unsigned char f);
+unsigned int PRFONT_GL(unsigned char f);
+unsigned int PRFONT_BL(unsigned char f);
+
+// Use this to get the final X and Y positions from the return value
+// of GsPrintFont(). Especially useful after wrapping.
+
+#define prfont_get_fx(i) ((short)(i & 0xffff))
+#define prfont_get_fy(i) ((short)((i >> 16) & 0xffff))
+
+// Width and height of the screen in the current video mode
+
+/** This global variable reports the current screen width, as set by GsSetVideoMode(). Do not modify. */
+extern unsigned short GsScreenW;
+/** This global variable reports the current screen height, as set by GsSetVideoMode(). Do not modify. */
+extern unsigned short GsScreenH;
+/** This global variable reports the current screen color mode (PAL or NTSC), as set by GsSetVideoMode().
+ You can use the values in the psx_gpu_vmodes enum to evaluate this. Do not modify. */
+extern unsigned char GsScreenM; // Current video mode
+
+/** This global variable reports the width of the current drawing environment. */
+extern unsigned short GsCurDrawEnvW;
+/** This global variable reports the height of the current drawing environment. */
+extern unsigned short GsCurDrawEnvH;
+
+/**
+ * Clear the entire drawing area with specified color
+ * @param r Red (0 - 255)
+ * @param g Green (0 - 255)
+ * @param b Blue (0 - 255)
+ */
+
+void GsSortCls(int r, int g, int b);
+
+/**
+ @attention Macros by their definition do not like being passed invalid values.
+*/
+
+/**
+ * Macro to get a texture page number from a coordinate in VRAM
+ * @param x X coordinate (0-1023)
+ * @param y Y coordinate (0-511)
+ */
+
+#define gs_get_tpage_num(x,y) ((x/64)+((y/256)*16))
+
+/**
+ * Macro to get an horizontal texture offset from a X coordinate in VRAM
+ * @param x X coordinate (0-1023)
+ */
+
+#define gs_get_tpage_u(x) (x&0x3f)
+
+/**
+ * Macro to get a vertical texture offset from a Y coordinate in VRAM
+ * @param y Y coordinate (0-511)
+ */
+
+#define gs_get_tpage_v(y) (y&0xff)
+
+/**
+ * This macro converts a RGB 888 color to PlayStation color format.
+ * @param r Red component (0-255)
+ * @param g Green component (0-255)
+ * @param b Blue component (0-255)
+ */
+
+#define gs_rgb_to_psx(r, g, b) ((r>>3)|((g>>3)<<5)|((b>>3)<<10))
+
+/**
+ * This macro converts a RGB 888 color (a color whose color components have an intensity between 0 and 255)
+ * to PlayStation color format, considering an alpha bit. If the alpha bit is non-zero, the STP bit in the color
+ * is set and will be considered for PlayStation translucency effects.
+ * @param r Red component (0-255)
+ * @param g Green component (0-255)
+ * @param b Blue component (0-255)
+ * @param a Alpha bit (STP/semitransparency bit)
+ */
+
+#define gs_rgba_to_psx(r, g, b, a) ((r>>3)|((g>>3)<<5)|((b>>3)<<10)|(a==0?0:1))
+
+/**
+ * This function can rotate a vector about the X, Y and Z axes
+ * If you don't want to rotate a vector about an axis, pass 0 as angle to that axis
+ *
+ * It is correct to pass the same argument to v and n, as calculations are first done in an internal buffer
+ * and then stored in the output array
+ *
+ * @param x_a Number of degrees (0-359) to which the vector should be rotated about the X axis
+ * @param y_a Number of degrees (0-359) to which the vector should be rotated about the Y axis
+ * @param z_a Number of degrees (0-359) to which the vector should be rotated about the Z axis
+ * @param v Pointer to an array of coordinates for the source vector
+ * @param n Pointer to destination array for the coordinates of the rotated vector
+ */
+
+void GsRotateVector(int x_a, int y_a, int z_a, double *v, double *n);
+
+/**
+ * Adds a monochrome polyline to the packet list
+ * @param line Pointer to structure for monochrome polyline
+ */
+
+void GsSortPolyLine(GsPolyLine *line);
+
+/**
+ * Adds a gradated polyline to the packet list
+ * @param line Pointer to structure for monochrome line
+ */
+
+void GsSortGPolyLine(GsGPolyLine *line);
+
+//void GsSortSimpleMap(GsMap *map);
+
+#endif
diff --git a/libpsx/include/psxgte.h b/libpsx/include/psxgte.h
new file mode 100644
index 0000000..24574b9
--- /dev/null
+++ b/libpsx/include/psxgte.h
@@ -0,0 +1,196 @@
+#ifndef _PSXGTE_H
+#define _PSXGTE_H
+
+/** GTE operations */
+
+enum gte_operations
+{
+ /** Perspective transformation */
+ GTE_OP_RTPS = 0x0180001,
+ /** Perspective Transformation on 3 points */
+ GTE_OP_RTPT = 0x0280030,
+ /** Multiply vector by matrix and vector addition */
+ GTE_OP_MVMVA = 0x0400012,
+ /** Depth Cue Color light */
+ GTE_OP_DCPL = 0x0680029,
+ /** Depth Cueing */
+ GTE_OP_DPCS = 0x0780010,
+ /** Interpolation of a vector and far color vector */
+ GTE_OP_INTPL = 0x0980011,
+ /** Square vector */
+ GTE_OP_SQR = 0x0A00428,
+ /** Normal color single vector */
+ GTE_OP_NCS = 0x0C8041E,
+ /** Normal color three vectors */
+ GTE_OP_NCT = 0x0D80420,
+ /** Normal color depth cue single vector */
+ GTE_OP_NCDS = 0x0E80413,
+ /** Normal color depth cue three vectors */
+ GTE_OP_NCDT = 0x0F80416,
+ /** Depth Cueing */
+ GTE_OP_DPCT = 0x0F8002A,
+ /** Normal Color Color single vector */
+ GTE_OP_NCCS = 0x108041B,
+ /** Normal Color Color three vectors */
+ GTE_OP_NCCT = 0x118043F,
+ /** Color Depth Cue */
+ GTE_OP_CDP = 0x1280414,
+ /** Color Color */
+ GTE_OP_CC = 0x138041C,
+ /** Normal clipping */
+ GTE_OP_NCLIP = 0x1400006,
+ /** Average of three Z values */
+ GTE_OP_AVSZ3 = 0x158002D,
+ /** Average of four Z values */
+ GTE_OP_AVSZ4 = 0x168002E,
+ /** Outer product of 2 vectors */
+ GTE_OP_OP = 0x170000C,
+ /** General purpose interpolation */
+ GTE_OP_GPF = 0x190003D,
+ /** General purpose interpolation */
+ GTE_OP_GPL = 0x1A0003E
+};
+
+/** GTE error flags, grab from cop2 register 63 */
+
+enum gte_error_flags
+{
+ GTE_FLAG_MAC1_OVF_POS = 0x40000000,
+ GTE_FLAG_MAC2_OVF_POS = 0x20000000,
+ GTE_FLAG_MAC3_OVF_POS = 0x10000000,
+
+ GTE_FLAG_MAC1_OVF_NEG = 0x08000000,
+ GTE_FLAG_MAC2_OVF_NEG = 0x04000000,
+ GTE_FLAG_MAC3_OVF_NEG = 0x02000000,
+
+ GTE_FLAG_IR1_SATURATED = 0x01000000,
+ GTE_FLAG_IR2_SATURATED = 0x00800000,
+ GTE_FLAG_IR3_SATURATED = 0x00400000,
+
+ GTE_FLAG_COL_FIFO_R_SATURATED = 0x00200000,
+ GTE_FLAG_COL_FIFO_G_SATURATED = 0x00100000,
+ GTE_FLAG_COL_FIFO_B_SATURATED = 0x00080000,
+
+ GTE_FLAG_SZ3_OTZ_SATURATED = 0x00040000,
+
+ GTE_FLAG_DIV_OVF_SATURATED = 0x00020000,
+
+ GTE_FLAG_MAC0_OVF_POS = 0x00010000,
+ GTE_FLAG_MAC0_OVF_NEG = 0x00008000,
+
+ GTE_FLAG_SX2_SATURATED = 0x00004000,
+ GTE_FLAG_SY2_SATURATED = 0x00002000,
+
+ GTE_FLAG_IR0_SATURATED = 0x00001000
+};
+
+/** GTE data registers */
+
+enum gte_data_registers
+{
+ /** Vector 0 X and Y */
+ GTE_R_VXY0 = 0,
+ /** Vector 0 Z */
+ GTE_R_VZ0 = 1,
+ /** Vector 1 X and Y */
+ GTE_R_VXY1 = 2,
+ /** Vector 1 Z */
+ GTE_R_VZ1 = 3,
+ /** Vector 2 X and Y */
+ GTE_R_VXY2 = 4,
+ /** Vector 2 Z */
+ GTE_R_VZ2 = 5,
+ /** RGB value */
+ GTE_R_RGB = 6,
+ /** Z Average value */
+ GTE_R_OTZ = 7,
+ /** Intermediate value 0 */
+ GTE_R_IR0 = 8,
+ /** Intermediate value 1 */
+ GTE_R_IR1 = 9,
+ /** Intermediate value 2 */
+ GTE_R_IR2 = 10,
+ /** Intermediate value 3 */
+ GTE_R_IR3 = 11,
+ /** Screen XY coordinates 0 FIFO */
+ GTE_R_SXY0 = 12,
+ /** Screen XY coordinates 1 FIFO */
+ GTE_R_SXY1 = 13,
+ /** Screen XY coordinates 2 FIFO */
+ GTE_R_SXY2 = 14,
+ /** Screen XY coordinates P FIFO */
+ GTE_R_SXYP = 15,
+ /** Screen Z 0 FIFO */
+ GTE_R_SZ0 = 16,
+ /** Screen Z 1 FIFO */
+ GTE_R_SZ1 = 17,
+ /** Screen Z 2 FIFO */
+ GTE_R_SZ2 = 18,
+ /** Screen Z 3 FIFO */
+ GTE_R_SZ3 = 19,
+ /** Characteristic color 0 FIFO */
+ GTE_R_RGB0 = 20,
+ /** Characteristic color 1 FIFO */
+ GTE_R_RGB1 = 21,
+ /** Characteristic color 2 FIFO */
+ GTE_R_RGB2 = 22,
+ /** Sum of products value 0 */
+ GTE_R_MAC0 = 24,
+ /** Sum of products value 1 */
+ GTE_R_MAC1 = 25,
+ /** Sum of products value 2 */
+ GTE_R_MAC2 = 26,
+ /** Sum of products value 3 */
+ GTE_R_MAC3 = 27,
+ /** IRGB ?? */
+ GTE_R_IRGB = 28,
+ /** ORGB ?? */
+ GTE_R_ORGB = 29,
+ /** Leading zero count source data. */
+ GTE_R_LZCS = 30,
+ /** Leading zero count result */
+ GTE_R_LZCR = 31
+};
+
+/** GTE control registers */
+
+enum gte_control_registers
+{
+ GTE_R_R11R12 = 0,
+ GTE_R_R13R21 = 1,
+ GTE_R_R22R23 = 2,
+ GTE_R_R31R32 = 3,
+ GTE_R_R33 = 4,
+ GTE_R_TRX = 5,
+ GTE_R_TRY = 6,
+ GTE_R_TRZ = 7,
+
+ GTE_R_L11L12 = 8,
+ GTE_R_L13L21 = 9,
+ GTE_R_L22L23 = 10,
+ GTE_R_L31L32 = 11,
+ GTE_R_L33 = 12,
+ GTE_R_RBK = 13,
+ GTE_R_GBK = 14,
+ GTE_R_BBK = 15,
+
+ GTE_R_LR1LR2 = 16,
+ GTE_R_LR3LG1 = 17,
+ GTE_R_LG2LG3 = 18,
+ GTE_R_LB1LB2 = 19,
+ GTE_R_LB3 = 20,
+ GTE_R_RFC = 21,
+ GTE_R_GFC = 22,
+ GTE_R_BFC = 23,
+
+ GTE_R_OFX = 24,
+ GTE_R_OFY = 25,
+ GTE_R_H = 26,
+ GTE_R_DQA = 27,
+ GTE_R_DQB = 28,
+ GTE_R_ZSF3 = 29,
+ GTE_R_ZSF4 = 30,
+ GTE_R_FLAG = 31
+};
+
+#endif
diff --git a/libpsx/include/psxpad.h b/libpsx/include/psxpad.h
new file mode 100644
index 0000000..3f96861
--- /dev/null
+++ b/libpsx/include/psxpad.h
@@ -0,0 +1,178 @@
+#ifndef _PSXPAD_H
+#define _PSXPAD_H
+
+/* Pad bits defines. */
+
+#define PAD_LEFT (1<<15)
+#define PAD_RIGHT (1<<13)
+#define PAD_UP (1<<12)
+#define PAD_DOWN (1<<14)
+#define PAD_L2 1
+#define PAD_R2 (1<<1)
+#define PAD_L1 (1<<2)
+#define PAD_R1 (1<<3)
+#define PAD_TRIANGLE (1<<4)
+#define PAD_CIRCLE (1<<5)
+#define PAD_CROSS (1<<6)
+#define PAD_SQUARE (1<<7)
+#define PAD_SELECT (1<<8)
+#define PAD_LANALOGB (1<<9)
+#define PAD_RANALOGB (1<<10)
+#define PAD_START (1<<11)
+
+#define PAD_READ_RAW_SIZE 21
+
+/**
+ * These values below are to be used for evalauting the type field of the
+ * psx_pad_state structure
+ */
+
+enum psx_pad_types
+{
+ /** No pad connected. */
+ PADTYPE_NONE,
+ /** Normal pad. */
+ PADTYPE_NORMALPAD,
+ /** Analog joystick, the early ones with analog. */
+ PADTYPE_ANALOGJOY,
+ /** Analog pad, the Dual Shock controller. */
+ PADTYPE_ANALOGPAD,
+ /** Namco NeGcon. Many steering wheels implement this protocol as well. */
+ PADTYPE_NEGCON, // Namco NeGcon
+ /** Konami Justifier gun controller. Many third party gun controllers implement this protocol. */
+ PADTYPE_KONAMIGUN,
+ /** Unknown pad type. */
+ PADTYPE_UNKNOWN
+};
+
+/**
+ * This structure contains the state of the pad (game controller) after
+ * polling it with PSX_PollPad()
+ */
+
+typedef struct
+{
+ /** Status. 0 on success, 255 on failure. */
+ unsigned char status;
+ /** Id. Bits 7-4 indicate the type. Bits 3-0 indicate the number of words
+ in the raw packet returned by the controller. */
+ unsigned char id;
+ /** Type of pad. To be evaluated with the types in the psx_pad_types enum */
+ unsigned char type;
+ /** Button bitmask. To be checked by AND'ing with the defines in
+ psxpad.h for buttons. If a bit is set for a button, it is pressed.
+ Checking the pad type to use this bitmask is not necessary at all,
+ and if button emulations are set up, this may not represent the
+ buttons actually pressed. Also reliable when type is PADTYPE_UNKNOWN */
+ unsigned short buttons;
+
+ /** Extra data for non-normal controllers.
+ You should check the value of the type field before accessing any of this data
+ */
+
+ union extra
+ {
+ /** Data for analog joysticks.
+ * @attention Due to the poor calibration of the analog sticks, it is recommended
+ * that you do not assume "left" for X values lower than zero and
+ * "right" for X values higher than zero.
+ *
+ * @attention It is recommended to pick a value, for instance 64, and assume
+ * "left" for values lower than -64, "right" for values higher than 64,
+ * and no movement for values between -64 and 64.
+ *
+ * @attention The same is valid for Y values, "up" and "down".
+ **/
+
+ struct analogJoy
+ {
+ /** X coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally left: -128, totally right: 127
+ */
+ signed char x[2];
+ /** Y coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally up: -128, totally down: 127
+ */
+ signed char y[2];
+ }analogJoy;
+
+ /** Data for analog joypads (controller).
+ * @attention Due to the poor calibration of the analog sticks, it is recommended
+ * that you do not assume "left" for X values lower than zero and
+ * "right" for X values higher than zero.
+ *
+ * @attention It is recommended to pick a value, for instance 64, and assume
+ * "left" for values lower than -64, "right" for values higher than 64,
+ * and no movement for values between -64 and 64.
+ *
+ * @attention The same is valid for Y values, "up" and "down".
+ **/
+
+ struct analogPad
+ {
+ /** X coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally left: -128, totally right: 127
+ */
+ signed char x[2];
+ /** Y coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally up: -128, totally down: 127
+ */
+ signed char y[2];
+ }analogPad;
+
+ /** Data for Namco NeGcon and steering wheels using its protocol.
+ * Many steering wheels use this protocol or can switch to it if desired.
+ */
+
+ struct negCon
+ {
+ /**
+ * Steering wheel position.
+ *
+ * Unlike analog sticks, the steering is accurate and this value is reliable.
+ *
+ * @par Value
+ * When steering left it is lower than zero, when steering right it is higher than zero
+ * and when not steering at all it is zero.
+ */
+
+ signed char steering;
+
+ /**
+ * Pressure for button I (1).
+ * @par Value
+ * 0 = not pressed, 255 = maximum pressure
+ */
+
+ unsigned char one;
+
+ /**
+ * Pressure for button II (2).
+ * @par Value
+ * 0 = not pressed, 255 = maximum pressure
+ */
+
+ unsigned char two;
+
+ /**
+ * Pressure for "L" shoulder button.
+ * @par Value
+ * 0 = not pressed, 255 = maximum pressure
+ */
+
+ unsigned char shoulder;
+ }negCon;
+ }extra;
+}psx_pad_state;
+
+void QueryPAD(int pad_n, unsigned char *in, unsigned char *out, int len);
+void pad_read_raw(int pad_n, unsigned char *arr);
+void pad_escape_mode(int pad_n, int enable);
+void pad_enable_vibration(int pad_n);
+void pad_set_vibration(int pad_n, unsigned char small, unsigned char big);
+
+#endif
diff --git a/libpsx/include/psxsio.h b/libpsx/include/psxsio.h
new file mode 100644
index 0000000..9756f1d
--- /dev/null
+++ b/libpsx/include/psxsio.h
@@ -0,0 +1,121 @@
+#ifndef _PSXSIO_H
+#define _PSXSIO_H
+
+/** Bitrate reload factors */
+
+enum sio_reload_factors
+{
+ /** STOP */
+ SIO_REL_STOP = 0,
+ /** MUL1 */
+ SIO_REL_MUL1 = 1,
+ /** MUL16 */
+ SIO_REL_MUL16 = 2,
+ /** MUL64 */
+ SIO_REL_MUL64 = 3
+};
+
+/** Character (data) length settings */
+
+enum sio_data_len
+{
+ /** Data Length = 5 bits */
+ SIO_DATA_LEN_5 = 0,
+ /** Data Length = 6 bits */
+ SIO_DATA_LEN_6 = 1,
+ /** Data Length = 7 bits */
+ SIO_DATA_LEN_7 = 2,
+ /** Data Length = 8 bits */
+ SIO_DATA_LEN_8 = 3
+};
+
+/** Stop bit length settings */
+
+enum sio_stop_bit
+{
+ /** Length = 1 bit */
+ SIO_STOP_BIT_1 = 1,
+ /** Length = 1.5 bits */
+ SIO_STOP_BIT_1_5 = 2,
+ /** Length = 2 bits */
+ SIO_STOP_BIT_2 = 3
+};
+
+/** Parity settings */
+
+enum sio_parity
+{
+ /** No parity */
+ SIO_PARITY_NONE = 0,
+ /** Odd parity */
+ SIO_PARITY_ODD = 1,
+ /** Even parity */
+ SIO_PARITY_EVEN = 3
+};
+
+/** SIO FIFO Buffer (TX/RX) Register [Read/Write] */
+#define SIO_TX_RX *((volatile unsigned char*)0x1F801050)
+/** SIO Status Register [Read Only] */
+#define SIO_STAT *((volatile unsigned short*)0x1F801054)
+/** SIO Mode Register [Read/Write] */
+#define SIO_MODE *((volatile unsigned short*)0x1F801058)
+/** SIO Control Register [Read/Write] */
+#define SIO_CTRL *((volatile unsigned short*)0x1F80105A)
+/** SIO Baud Rate Register [Read/Write] */
+#define SIO_BPSV *((volatile unsigned short*)0x1F80105E)
+
+
+/**
+ * Initialize SIO communication at the specified bitrate (baud rate).
+ * Mode is 8N1. (Data Length = 8 bit, No parity, Stop bit Length = 1 bit)
+ * @param bitrate Bitrate (baud rate)
+ */
+void SIOStart(int bitrate);
+
+/**
+ * Same as SIOStart() but with more control.
+ * IMPORTANT: Must use defined macros.
+ * For example setting datalength to 5 should be done with "SIO_DATA_LEN_5"
+ * and not by simply passing 5 as an argument.
+ *
+ * @param bitrate Bit rate (baud rate)
+ * @param datalength Character (data) length
+ * @param parity Parity
+ * @param stopbit Stop bit length
+ */
+void SIOStartEx(int bitrate, int datalength, int parity, int stopbit);
+
+/**
+ * Shuts down SIO communication.
+ */
+void SIOStop(void);
+
+/**
+ * Read a single byte from the input buffer.
+ * @return Data byte from input buffer
+ */
+unsigned char SIOReadByte(void);
+
+/**
+ * Send a single byte to the output buffer.
+ * @param data Byte to send
+ */
+void SIOSendByte(unsigned char data);
+
+/**
+ * Check if any data is waiting in the input buffer.
+ * Must be used when fetching data otherwise incorrect data could be read (usually 0x00).
+ * @return Non-zero if there is data waiting in the input buffer, zero otherwise.
+ */
+int SIOCheckInBuffer(void);
+
+/**
+ * Check if port is ready to send data (previous operation finished).
+ * Must be used when sending data as the output buffer is only 2 bytes long.
+ * @return Non-zero if port is ready to send data, zero otherwise.
+ */
+int SIOCheckOutBuffer(void);
+
+
+
+#endif
diff --git a/libpsx/include/psxspu.h b/libpsx/include/psxspu.h
new file mode 100644
index 0000000..0de3656
--- /dev/null
+++ b/libpsx/include/psxspu.h
@@ -0,0 +1,225 @@
+#ifndef _SPU_H
+#define _SPU_H
+
+#define SPU_ADDR *((volatile unsigned short*)0x1f801da6)
+#define SPU_DATA *((volatile unsigned short*)0x1f801da8)
+#define SPU_CONTROL *((volatile unsigned short*)0x1f801daa)
+#define SPU_STATUS *((volatile unsigned short*)0x1f801dac)
+#define SPU_STATUS2 *((volatile unsigned short*)0x1f801dae)
+#define SPU_MVOL_L *((volatile unsigned short*)0x1f801d80)
+#define SPU_MVOL_R *((volatile unsigned short*)0x1f801d82)
+#define SPU_REVERB_L *((volatile unsigned short*)0x1f801d84)
+#define SPU_REVERB_R *((volatile unsigned short*)0x1f801d86)
+#define SPU_KEY_ON1 *((volatile unsigned short*)0x1f801d88)
+#define SPU_KEY_ON2 *((volatile unsigned short*)0x1f801d8a)
+#define SPU_KEY_OFF1 *((volatile unsigned short*)0x1f801d8c)
+#define SPU_KEY_OFF2 *((volatile unsigned short*)0x1f801d8e)
+#define SPU_KEY_FM_MODE1 *((volatile unsigned short*)0x1f801d90)
+#define SPU_KEY_FM_MODE2 *((volatile unsigned short*)0x1f801d92)
+#define SPU_KEY_NOISE_MODE1 *((volatile unsigned short*)0x1f801d94)
+#define SPU_KEY_NOISE_MODE2 *((volatile unsigned short*)0x1f801d96)
+#define SPU_KEY_REVERB_MODE1 *((volatile unsigned short*)0x1f801d98)
+#define SPU_KEY_REVERB_MODE2 *((volatile unsigned short*)0x1f801d9a)
+#define SPU_CD_MVOL_L *((volatile unsigned short*)0x1f801db0)
+#define SPU_CD_MVOL_R *((volatile unsigned short*)0x1f801db2)
+#define SPU_EXT_VOL_L *((volatile unsigned short*)0x1f801db4)
+#define SPU_EXT_VOL_R *((volatile unsigned short*)0x1f801db6)
+#define SPU_REVERB_WORK_ADDR *((volatile unsigned short*)0x1f801da2)
+#define SPU_VOICE_BASE_ADDR(x) (0x1f801c00 + (x<<4))
+
+/** Start address of sound data in Sound RAM */
+#define SPU_DATA_BASE_ADDR 0x1010
+/** Maximum volume. */
+#define SPU_MAXVOL 0x3FFF
+
+/** VAG file */
+
+typedef struct
+{
+ /** Version. */
+ unsigned int version;
+ /** Data size. */
+ unsigned int data_size;
+ /** Sample rate. */
+ unsigned int sample_rate;
+ /** Name */
+ unsigned char name[16];
+ /** Pointer to sound data */
+ void *data;
+ /** Address in Sound RAM where the sound data was uploaded */
+ unsigned int spu_addr;
+ /** [Runtime] Voice this VAG is currently being played on */
+ char cur_voice;
+}SsVag;
+
+/**
+ * Set voice volume.
+ * @param voice Voice number (0-23)
+ * @param left Left channel volume
+ * @param right Right channel volume
+ */
+
+void SsVoiceVol(int voice, unsigned short left, unsigned short right);
+
+/**
+ * Set voice pitch.
+ * @param voice Voice
+ * @param pitch Pitch.
+ */
+
+void SsVoicePitch(int voice, unsigned short pitch);
+
+
+/**
+ * Set start Sound RAM address for voice.
+ * @param voice Voice
+ * @param addr Start address in Sound RAM (multiplier of 8)
+ */
+
+void SsVoiceStartAddr(int voice, unsigned int addr);
+
+/**
+ * Set ADSR level for voice
+ * @param voice Voice
+ * @param level ADSR level
+ * @param rate ADSR rate
+ */
+
+void SsVoiceADSRRaw(int voice, unsigned short level, unsigned short rate);
+
+/**
+ * Set repeat address for voice
+ * @param voice Voice
+ * @param addr Address in Sound RAM (multiplier of 8)
+ */
+
+void SsVoiceRepeatAddr(int voice, unsigned int addr);
+
+/**
+ * Set a voice to 'on'. This has the effect of playing the sound specified for the voice.
+ * @param voice Voice
+ */
+
+void SsKeyOn(int voice);
+
+/**
+ * Set a voice to 'off'. This stops the sound specified for the voice.
+ * @param voice Voice
+ */
+
+void SsKeyOff(int voice);
+
+/**
+ * Set the voices specified by the bitmask to 'on'. Like SsKeyOn()
+ * @param mask Bitmask
+ */
+
+void SsKeyOnMask(int mask);
+
+/**
+ * Set the voices specified by the bitmask to 'off'. Like SsKeyOff()
+ * @param mask Bitmask
+ */
+
+void SsKeyOffMask(int mask);
+
+/**
+ * Wait for the SPU to be ready.
+ */
+
+void SsWait(void);
+
+/**
+ * Intialize the SPU.
+ */
+
+void SsInit(void);
+
+/**
+ * Uploads sound data in PSX ADPCM format to Sound RAM.
+ * @param addr Pointer to PSX ADPCM sound data in main RAM
+ * @param size Sound data size
+ * @param spu_addr Destination address in Sound RAM (multiplier of 8).
+ */
+
+void SsUpload(void *addr, int size, int spu_addr);
+
+/**
+ * Converts a sampling rate in hertz to PlayStation pitch rate used by the SPU.
+ * @param hz Sampling rate in hertz.
+ * @return PlayStation pitch rate
+ */
+
+unsigned short SsFreqToPitch(int hz);
+
+/**
+ * Reads information from a buffer containg a VAG file and stores it inside a SsVag structure.
+ * @param vag Pointer to structure in which to store information.
+ * @param data Pointer to VAG file data
+ */
+
+int SsReadVag(SsVag *vag, void *data);
+
+/**
+ * Uploads the sound data specified by a SsVag structure to the specified address in Sound RAM.
+ * The SsVag structure can then be used for playing with SsPlayVag()
+ * @param vag Pointer to SsVag structure
+ * @param spu_addr Destination address in Sound RAM (multiplier of 8)
+ */
+
+void SsUploadVagEx(SsVag *vag, int spu_addr);
+
+
+/**
+ * Uploads the sound data specified by a SsVag structure to Sound RAM, beginning from the
+ * base of usable Sound RAM and continuing from there, in an automatic fashion.
+ * @param vag Pointer to SsVag structure
+ */
+
+void SsUploadVag(SsVag *vag);
+
+/**
+ * Plays the sound specified by the SsVag structure at specified voice and volume.
+ * @param vag Pointer to SsVag structure
+ * @param voice Voice
+ * @param vl Left channel volume
+ * @param vr Right channel volume
+ */
+
+void SsPlayVag(SsVag *vag, unsigned char voice, unsigned short vl,
+ unsigned short vr);
+
+/**
+ * Stops the sound specified by the SsVag structure
+ * @param vag Pointer to SsVag structure
+ */
+
+void SsStopVag(SsVag *vag);
+
+/**
+ * Tell SsUploadVag() to start uploading from the base of usable Sound RAM again.
+ */
+
+void SsResetVagAddr(void);
+
+/**
+ * Enable CD Audio.
+ */
+
+void SsEnableCd(void);
+
+/**
+ * Enable External audio. (???)
+ */
+
+void SsEnableExt(void);
+
+/**
+ * Set CD Audio volume.
+ * @param left Left channel volume
+ * @param right Right channel volume
+ */
+
+void SsCdVol(unsigned short left, unsigned short right);
+
+#endif
diff --git a/libpsx/include/psxutil.h b/libpsx/include/psxutil.h
new file mode 100644
index 0000000..0dba29e
--- /dev/null
+++ b/libpsx/include/psxutil.h
@@ -0,0 +1,20 @@
+// psxutil.h
+
+#ifndef _PSXUTIL_H
+#define _PSXUTIL_H
+
+/**
+ * Given a button bitmask, returns the name for the buttons
+ * that the bitmask reports activated.
+ * If more than one button is found in the bitmask, it is specified by the symbol &
+ * followed by the other button name and so on...
+ *
+ * @param button Button bitmask as returned by PSX_ReadPad()
+ * @param out Pointer to a string, to which the button names will be output
+ * @param out_len The maximum length of the string
+ * @return The pointer to passed as the "out" parameter
+ */
+
+char *PSX_GetButtonName(unsigned short button, char *out, unsigned int out_len);
+
+#endif
diff --git a/libpsx/include/runexe.h b/libpsx/include/runexe.h
new file mode 100644
index 0000000..c42c9ee
--- /dev/null
+++ b/libpsx/include/runexe.h
@@ -0,0 +1,17 @@
+#ifndef _PSXSDK_RUNEXE_H
+#define _PSXSDK_RUNEXE_H
+
+/**
+ * Replaces running executable code with code from another executable
+ * stored in a memory buffer and starts executing at the starting point for the new code.
+ * The executable must be in PSX-EXE format (such as generated by elf2exe).
+ * Moreover, PSX_InitEx() must have been initialized by specifying the PSX_INIT_SAVESTATE flag.
+ * @param exeBuffer Pointer to memory buffer where executable is stored
+ * @return On success this function has the effect of making the PlayStation
+ * run another executable, so obviously this function will never return in that case.
+ * This function will only return on failure, where it will return 0.
+ */
+
+int PSX_RunExe(void *exeBuffer);
+
+#endif
diff --git a/libpsx/include/search.h b/libpsx/include/search.h
new file mode 100644
index 0000000..7f8574e
--- /dev/null
+++ b/libpsx/include/search.h
@@ -0,0 +1,14 @@
+/*
+ * search.h
+ *
+ * PSXSDK
+ */
+
+#ifndef _SEARCH_H
+#define _SEARCH_H
+
+void *lsearch(void *key , void *base , int belp , int width , int (*cmp)(void * , void *));
+void *bsearch(void *key , void *base , int nel , int size , int (*cmp)(void * , void *));
+
+#endif
+
diff --git a/libpsx/include/stdint.h b/libpsx/include/stdint.h
new file mode 100644
index 0000000..e6bb9d2
--- /dev/null
+++ b/libpsx/include/stdint.h
@@ -0,0 +1,14 @@
+/* stdint.h */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+#include <inttypes.h>
+
+// Added ifndef or otherwise GCC 4.8 would complain
+
+#ifndef __PTRDIFF_TYPE__
+typedef unsigned int ptrdiff_t;
+#endif
+
+#endif
diff --git a/libpsx/include/stdio.h b/libpsx/include/stdio.h
new file mode 100644
index 0000000..1bf7a99
--- /dev/null
+++ b/libpsx/include/stdio.h
@@ -0,0 +1,170 @@
+/*
+ * stdio.h implementation for PSXSDK
+ */
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#ifdef _PSXSDK_WRAPPER
+
+/*
+ * Dirty hack...
+ */
+
+#include "/usr/include/stdio.h"
+
+#else
+
+#include <types.h>
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#define EOF -1
+
+/* NULL */
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+enum stdio_directions
+{
+ STDIO_DIRECTION_BIOS,
+ STDIO_DIRECTION_SIO
+};
+
+enum file_devices
+{
+ FDEV_UNKNOWN,
+ FDEV_CDROM,
+ FDEV_MEMCARD,
+ FDEV_CONSOLE
+};
+
+extern int __stdio_direction;
+
+/**
+ * File stream
+ */
+
+typedef struct
+{
+ /** File descriptor, as returned by open() */
+ int fildes;
+ /** Current file position */
+ unsigned int pos;
+ /** File access mode */
+ unsigned int mode;
+ /** Device ID */
+ unsigned int dev;
+ /** Size in bytes */
+ unsigned int size;
+ /** Used internally by fopen(), 0 if free, 1 if occupied */
+ unsigned int used;
+ /** End-of-File marker */
+ unsigned int eof;
+ /** Error marker */
+ unsigned int error;
+}FILE;
+
+/* Console functions */
+
+int putchar(int c);
+int puts(const char *str);
+
+/**
+ * BIOS printf() implementation. Does not support floating point.
+ * NOTE: when redirect_stdio_to_sio() is used, PSXSDK's internal implementation is used instead.
+ */
+
+extern int printf(const char *format, ...);
+
+
+#ifdef __IN_LIBPSX
+
+// Only for code in libpsx
+
+// If PSXSDK_DEBUG is defined, dprintf() calls are turned into printf() calls
+// otherwise they are left out
+
+#ifdef PSXSDK_DEBUG
+ #define dprintf printf
+#else
+ #define dprintf(fmt, ...)
+#endif
+
+#endif
+
+int vsnprintf(char *string, size_t size, const char *fmt, va_list ap);
+int vsprintf(char *string, const char *fmt, va_list ap);
+int sprintf(char *string, const char *fmt, ...);
+int snprintf(char *string, size_t size, const char *fmt, ...);
+int vprintf(char *fmt, va_list ap);
+
+FILE *fdopen(int fildes, const char *mode);
+FILE *fopen(const char *path, const char *mode);
+int fclose(FILE *stream);
+int fread(void *ptr, int size, int nmemb, FILE *f);
+int fwrite(void *ptr, int size, int nmemb, FILE *f);
+
+int fgetc(FILE *f);
+int ftell(FILE *f);
+int fseek(FILE *f, int offset, int whence);
+
+int fputs(const char *str, FILE *stream);
+void clearerr(FILE *stream);
+int feof(FILE *stream);
+int ferror(FILE *stream);
+int fileno(FILE *stream);
+
+#define getc(f) fgetc(f)
+
+int rename(const char *oldname, const char *newname);
+int remove(const char *filename);
+
+#ifndef __cplusplus
+// Define delete(x) to be remove(x) only when compiling plain C.
+#define delete(x) remove(x)
+#endif
+
+/**
+ * Redirects STDIO to SIO (serial port)
+ */
+
+void redirect_stdio_to_sio(void);
+
+/**
+ * Sets whether a carriage return must be written before a line feed.
+ * In simpler words, whether '\n' must be translated to a '\r\n' sequence.
+ * If you come from the Unix world, you most likely want to set this.
+ *
+ * @param setting New status of the setting (0 = disabled, 1 = enabled)
+ */
+
+void sio_stdio_mapcr(unsigned int setting);
+
+/**
+ * scanf and friends
+ */
+
+int vsscanf(const char *str, const char *fmt, va_list ap);
+int sscanf(const char *str, const char *fmt, ...);
+
+
+/**
+ * STDIO for SIO
+ */
+
+int sio_putchar(int c);
+int sio_puts(const char *str);
+int sio_printf(const char *fmt, ...);
+int sio_vprintf(const char *fmt, va_list ap);
+
+#endif
+
+#endif
+
diff --git a/libpsx/include/stdlib.h b/libpsx/include/stdlib.h
new file mode 100644
index 0000000..0242213
--- /dev/null
+++ b/libpsx/include/stdlib.h
@@ -0,0 +1,66 @@
+/*
+ * stdlib.h
+ *
+ * Standard library functions
+ *
+ * PSXSDK
+ */
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+typedef unsigned int size_t;
+typedef signed int ssize_t;
+
+/* Conversion functions */
+
+int atoi(const char *s);
+long atol(const char *s);
+char *itoa(int value, char *str, int base);
+char *ltoa(long value, char *str, int base);
+char *lltoa(long long value, char *str, int base);
+char *utoa(unsigned int value, char *str, int base);
+char *ultoa(unsigned long value, char *str, int base);
+char *ulltoa(unsigned long long value, char *str, int base);
+//extern char atob(char *s); // Is this right?
+
+
+// Random number functions
+
+#define RAND_MAX 0x7fffffff
+
+int rand(void);
+void srand(unsigned int seed);
+
+// Quick sort
+
+void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
+
+// Memory allocation functions
+
+//#warning "malloc() family of functions NEEDS MORE TESTING"
+
+void *malloc(size_t size);
+void free(void *buf);
+void *calloc(size_t number, size_t size);
+void *realloc(void *buf , size_t n);
+
+int abs(int x);
+long long strtoll(const char *nptr, char **endptr, int base);
+long strtol(const char *nptr, char **endptr, int base);
+double strtod(const char *nptr, char **endptr);
+long double strtold(const char *nptr, char **endptr);
+float strtof(const char *nptr, char **endptr);
+
+// Misc
+void abort(void);
+void exit(int status);
+void call_atexit_callbacks(void);
+
+// Program return codes
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+#endif
+
diff --git a/libpsx/include/string.h b/libpsx/include/string.h
new file mode 100644
index 0000000..5956b0d
--- /dev/null
+++ b/libpsx/include/string.h
@@ -0,0 +1,64 @@
+/*
+ * string.h
+ *
+ * Prototypes for string functions of the C library
+ *
+ * PSXSDK
+ */
+
+// NOTE: The BIOS was found to be unreliable for many functions,
+// so it is not used anymore for the libc.
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <strings.h> // for backwards compatibility
+#include <types.h>
+
+char *strcat(char *s , const char *append);
+char *strncat(char *s , const char *append, size_t n);
+int strcmp(const char *dst , const char *src);
+int strncmp(const char *dst , const char *src , size_t len);
+int stricmp(const char *s1, const char *s2); // alias of strcasecmp
+int strnicmp(const char *s1, const char *s2, size_t len); // alias of strncasecmp
+char *strcpy(char *dst , const char *src);
+char *strncpy(char *dst , const char *src , size_t n);
+int strlen(const char *s);
+int strnlen(const char *s, size_t maxlen);
+char *strchr(const char *s , int c);
+char *strrchr(const char *s , int c);
+char *strpbrk(const char *dst , const char *src);
+int strspn(const char *s , const char *charset);
+int strcspn(const char *s , const char *charset);
+char *strsep(char **stringp, const char *delim);
+char *strtok(char *str, const char *sep);
+char *strstr(const char *big , const char *little);
+char *strcasestr(const char *big, const char *little);
+char *strlwr(char *string);
+char *strupr(char *string);
+char *strdup(const char *str);
+char *strndup(const char *str, size_t len);
+int strlcpy(char *dst, const char *src, size_t size);
+int strlcat(char *dst, const char *src, size_t size);
+int strcoll(const char *dst , const char *src);
+
+char *strerror(int errnum);
+int strerror_r(int errnum, char *strerrbuf, size_t buflen);
+
+void *memset(void *dst , char c , size_t n);
+void *memmove(void *dst , const void *src , size_t n);
+int memcmp(const void *b1 , const void *b2 , size_t n);
+void *memchr(void *s , int c , size_t n);
+void *memrchr(void *b, int c, size_t len);
+void *memcpy(void *dst , const void *src , size_t len);
+void *memccpy(void *dst, const void *src, int c, size_t len);
+void *memmem(const void *big, size_t big_len, const void *little, size_t little_len);
+
+// ffsl() and ffsll() are glibc extensions, and are in string.h
+// instead of strings.h (like ffs()) for some reason..
+
+int ffsl(long value);
+int ffsll(long long value);
+
+#endif
+
diff --git a/libpsx/include/strings.h b/libpsx/include/strings.h
new file mode 100644
index 0000000..7e9082f
--- /dev/null
+++ b/libpsx/include/strings.h
@@ -0,0 +1,37 @@
+/*
+ * strings.h
+ *
+ * PSXSDK
+ */
+
+#ifndef _STRINGS_H
+#define _STRINGS_H
+
+#include <string.h>
+#include <types.h>
+
+#define bcopy(src,dst,len) memmove(dst,src,len)
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcmp(b1,b2,len) memcmp(b1,b2,len)
+#define index(s, c) strchr(s, c)
+#define rindex(s, c) strrchr(s, c)
+
+int ffs(int value);
+char *index(const char *s, int c);
+char *rindex(const char *s, int c);
+
+/**
+ * Returns the number of bits set in the value
+ * @param value Value
+ * @return Number of bits set in value
+ */
+
+unsigned int popcount(unsigned int value);
+unsigned int popcountl(unsigned long value);
+unsigned int popcountll(unsigned long long value);
+unsigned int popcount32(uint32_t value);
+unsigned int popcount64(uint64_t value);
+int strcasecmp(const char *s1, const char *s2);
+int strncasecmp(const char *s1, const char *s2, size_t len);
+
+#endif
diff --git a/libpsx/include/sys/stat.h b/libpsx/include/sys/stat.h
new file mode 100644
index 0000000..5b0d7ca
--- /dev/null
+++ b/libpsx/include/sys/stat.h
@@ -0,0 +1,19 @@
+/**
+ * PSXSDK
+ *
+ * sys/stat.h
+ */
+
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+struct stat
+{
+ unsigned int st_size;
+ unsigned int st_blksize;
+ unsigned int st_blocks;
+};
+
+int stat(const char *path, struct stat *sb);
+
+#endif
diff --git a/libpsx/include/sys/types.h b/libpsx/include/sys/types.h
new file mode 100644
index 0000000..2d6df2a
--- /dev/null
+++ b/libpsx/include/sys/types.h
@@ -0,0 +1,11 @@
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <types.h>
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+#endif
diff --git a/libpsx/include/types.h b/libpsx/include/types.h
new file mode 100644
index 0000000..395dac4
--- /dev/null
+++ b/libpsx/include/types.h
@@ -0,0 +1,10 @@
+#ifndef _TYPES_H
+#define _TYPES_H
+
+typedef unsigned int size_t;
+typedef signed int ssize_t;
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#endif
diff --git a/libpsx/include/unistd.h b/libpsx/include/unistd.h
new file mode 100644
index 0000000..3ae6aa3
--- /dev/null
+++ b/libpsx/include/unistd.h
@@ -0,0 +1,22 @@
+/*
+ * unistd.h
+ *
+ * PSXSDK
+ */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <types.h>
+
+int lseek(int fd, int off, int whence);
+int read(int fd, void *buf, int nbytes);
+int write(int fd, void *buf, int nbytes);
+int close(int fd);
+int cd(char *dirname);
+
+void swab(const void *src, void *dst, ssize_t len);
+
+#define chdir(dirname) cd(dirname)
+
+#endif
diff --git a/libpsx/src/atexit.c b/libpsx/src/atexit.c
new file mode 100644
index 0000000..835aae3
--- /dev/null
+++ b/libpsx/src/atexit.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+
+static void *f_ptr[32];
+static int f_ptr_pos = 0;
+
+int atexit(void (*function)(void))
+{
+ if(f_ptr_pos >= 32)
+ return -1;
+
+ f_ptr[f_ptr_pos++] = function;
+
+ return 0;
+}
+
+void call_atexit_callbacks(void)
+{
+ int i;
+ void (*f)(void);
+
+ for(i = (f_ptr_pos - 1); i >= 0; i--)
+ (f = f_ptr[i])();
+}
diff --git a/libpsx/src/cdrom.c b/libpsx/src/cdrom.c
new file mode 100644
index 0000000..ca14fd4
--- /dev/null
+++ b/libpsx/src/cdrom.c
@@ -0,0 +1,240 @@
+/*
+ * Low-level CDROM library
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <psx.h>
+
+#define CDREG(x) *((unsigned char*)(0x1f801800+x))
+
+void _internal_cdrom_handler();
+void (*cdrom_handler_callback)();
+volatile int cdrom_command_direct = 0;
+volatile int cdrom_command_done = 0;
+volatile int cdrom_direct_cmd;
+volatile int cdrom_command_dpos = 0;
+volatile unsigned char cdrom_last_command;
+volatile unsigned char cdrom_command_stat[2];
+
+unsigned int cdrom_queue_buf[4] = {0x0, /* Will contain next interrupt handler in queue */
+ 0x0, /* func1 */
+ (unsigned int)_internal_cdrom_handler, /* func2 */
+ 0x0, /* pad */
+ };
+
+static const unsigned char cdrom_command_type[0x1F] = // 0 = single int, 1 = double int, 2,3,... = others
+{
+ 0, // Sync 0
+ 0, // GetStat/Nop 1
+ 0, // Setloc 2
+ 0, // Play 3
+ 0, // Forward 4
+ 0, // Backward 5
+ 0, // ReadN 6
+ 0, // Standby 7
+ 0, // Stop 8
+ 1, // Pause 9
+ 1, // Init A
+ 0, // Mute B
+ 0, // Demute C
+ 0, // Setfilter D
+ 0, // Setmode E
+ 0, // Getmode F
+ 0, // GetlocL 10
+ 0, // GetlocP 11
+ 0xFF, // ??? 12
+ 0, // GetTN 13
+ 0, // GetTD 14
+ 1, // SeekL 15
+ 1, // SeekP 16
+ 0xFF, // ??? 17
+ 0xFF, // ??? 18
+ 0, // Test 19
+ 1, // ID 1A
+ 0, // ReadS 1B
+ 0, // Reset 1C
+ 0xFF, // ??? 1D
+ 1, // ReadToc 1E
+};
+
+void CdSendCommand(int cmd, int num, ...)
+{
+ int x;
+ va_list ap;
+ va_start(ap, num);
+
+// Wait for command execution to end
+// while(CDREG(0) & 128);
+
+// Flush old interrupts
+// If this is not done, some events (like the opening of the shell) will hang the CD controller.
+
+ CDREG(0) = 1;
+ CDREG(3) = 7;
+
+// Send parameters
+
+ CDREG(0) = 0;
+
+ while(num)
+ {
+ CDREG(2) = (unsigned char)va_arg(ap, unsigned int);
+ num--;
+ }
+
+// Send command
+
+ CDREG(0) = 0;
+ CDREG(1) = cmd;
+
+// Depending on the number of INTs we expect for a command,
+// we wait for an INT to occur, we store the response data returned,
+// and we flush the INT.
+ for(x = 0; x < (cdrom_command_type[cmd] + 1); x++)
+ {
+ CDREG(0) = 1;
+ while((CDREG(3) & 7) == 0);
+
+ cdrom_command_stat[x] = CDREG(1);
+
+ CDREG(0) = 1;
+ CDREG(3) = 7;
+ }
+
+// Store ID number of last executed command (this)
+ cdrom_last_command = cmd;
+
+ va_end(ap);
+}
+
+int CdReadResults(unsigned char *out, int max)
+{
+ int x;
+ unsigned char *outo = out;
+ unsigned char b;
+
+ for(x = 0; x < (cdrom_command_type[cdrom_last_command] + 1); x++)
+ {
+ if(max > 0)
+ {
+ *(out++) = cdrom_command_stat[x];
+ max--;
+ }
+ }
+
+ CDREG(0) = 1;
+
+ while(CDREG(0) & 0x20)
+ {
+ b = CDREG(1);
+ if(max>0)
+ {
+ *(out++) = b;
+ max--;
+ }
+ }
+
+ return (out-outo);
+}
+
+void _internal_cdromlib_callback()
+{
+ // 0 = ACKNOWLEDGE (0x*2)
+ // 1 = ACKNOWLEDGE (0x*2), COMPLETE (0x*3)
+
+/* int x;
+
+
+
+ unsigned char i;
+
+
+ if(cdrom_command_done)
+ return;
+
+ for(x = 0; x < 100; x++); // Waste time
+
+ CDREG(0) = 1;
+ i=CDREG(3);
+
+ if((i&0xf)==5) // Error
+ cdrom_command_done = 1;
+
+ //printf("i&0xf = %x\n", i&0xf);
+// printf("cdrom_direct_cmd = %x\n", cdrom_direct_cmd);
+
+ switch(kind[cdrom_direct_cmd])
+ {
+ case 0:
+ if(((i&0xf)==3) || ((i&0xf) == 2))
+ cdrom_command_done = 1;
+ break;
+
+ case 1:
+ if((i&0xf)==2)
+ cdrom_command_done = 1;
+ break;
+
+ case 0xFF: // Unknown command!
+ cdrom_command_done = 1;
+ return;
+ break;
+ }
+
+ cdrom_command_stat[0] = i;
+
+ for(x = 0; x < 100; x++); // Waste time
+
+ CDREG(0) = 1;
+ CDREG(3) = 7;
+ i = CDREG(1);
+ cdrom_command_stat[1] = i;
+
+ //printf("cdrom_command_done = %d\n", cdrom_command_done);*/
+}
+
+void _internal_cdromlib_init()
+{
+ printf("Starting CDROMlib...\n");
+
+ EnterCriticalSection(); // Disable IRQs
+
+ SysEnqIntRP(0, cdrom_queue_buf);
+
+ IMASK|=4;
+
+ cdrom_handler_callback = _internal_cdromlib_callback;
+
+ ExitCriticalSection(); // Enable IRQs
+}
+
+int CdGetStatus()
+{
+ unsigned char out;
+
+ CdSendCommand(CdlGetstat, 0);
+ CdReadResults(&out, 1);
+
+ return out;
+}
+
+int CdPlayTrack(unsigned int track)
+{
+ while(CdGetStatus() & CDSTATUS_SEEK);
+ CdSendCommand(CdlSetmode, 1, 0x20);
+ CdSendCommand(CdlPlay, 1, ((track/10)<<4)|(track%10));
+
+ return 1;
+}
+
+unsigned char CdRamRead(unsigned short addr)
+{
+ unsigned char b;
+ addr &= 0x3ff;
+
+ CdSendCommand(0x19, 0x60, addr&0xff, addr >> 8);
+ CdReadResults(&b, 1);
+
+ return b;
+}
diff --git a/libpsx/src/cdromh.s b/libpsx/src/cdromh.s
new file mode 100644
index 0000000..b2968c1
--- /dev/null
+++ b/libpsx/src/cdromh.s
@@ -0,0 +1,109 @@
+.global _internal_cdrom_handler
+.set noat
+
+
+_internal_cdrom_handler:
+ addi $sp, -112
+ sw $at, 0($sp)
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $s0, 60($sp)
+ sw $s1, 64($sp)
+ sw $s2, 68($sp)
+ sw $s3, 72($sp)
+ sw $s4, 76($sp)
+ sw $s5, 80($sp)
+ sw $s6, 84($sp)
+ sw $s7, 88($sp)
+ sw $t8, 92($sp)
+ sw $t9, 96($sp)
+ sw $gp, 100($sp)
+ sw $s8, 104($sp)
+ sw $ra, 108($sp)
+
+# Do not run code if cdrom interrupt is not enabled
+
+ li $t0, 0x1f801074
+ lw $t1, 0($t0)
+ andi $t1, $t1, 4
+ beq $t1, $zero, cdrom_handler_end
+ nop
+
+# Do not run code if cdrom interrupt is not pending
+
+ li $t0, 0x1f801070
+ lw $t1, 0($t0)
+ andi $t1, $t1, 4
+ beq $t1, $zero, cdrom_handler_end
+ nop
+
+# If the CDROM command isn't direct
+# (direct = sent by us and not by the BIOS' ISO9660 routines)
+# exit and let the BIOS do its work.
+
+cdrom_check_direct_cmd:
+ la $t0, cdrom_command_direct
+ lw $t1, 0($t0)
+ beq $t1, $zero, cdrom_handler_end
+ nop
+
+cdrom_fire_user_handler:
+ la $t0, cdrom_handler_callback
+ lw $t1, 0($t0)
+
+ jalr $t1
+ nop
+
+# Remove bit for CDROM interrupt (bit 2) from pending interrupts mask.
+
+cdrom_handler_remove_pending:
+ li $t0, 0x1f801070
+ lw $t1, 0($t0)
+ xori $t1, $t1, 4
+ sw $t1, 0($t0)
+
+cdrom_handler_end:
+
+ lw $at, 0($sp)
+ lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $s0, 60($sp)
+ lw $s1, 64($sp)
+ lw $s2, 68($sp)
+ lw $s3, 72($sp)
+ lw $s4, 76($sp)
+ lw $s5, 80($sp)
+ lw $s6, 84($sp)
+ lw $s7, 88($sp)
+ lw $t8, 92($sp)
+ lw $t9, 96($sp)
+ lw $gp, 100($sp)
+ lw $s8, 104($sp)
+ lw $ra, 108($sp)
+ addi $sp, 112
+ jr $ra
+ nop
diff --git a/libpsx/src/cop.c b/libpsx/src/cop.c
new file mode 100644
index 0000000..04b49f5
--- /dev/null
+++ b/libpsx/src/cop.c
@@ -0,0 +1,111 @@
+#include <psx.h>
+
+unsigned int get_cop_register(unsigned char cop_num,
+ unsigned char register_num)
+{
+// Workaround for MIPS' simplicistic instruction set...
+
+ unsigned int instr[] =
+ {0x40020000, // cfc $v0, 0
+ 0x03E00008, // jr $ra
+ 0x00000000, // nop
+ 0x00000000}; // nop
+
+ int (*rawFunc)() = (void*)instr;
+
+// Write coprocessor register number inside instruction
+ instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );
+
+// Execute modified instruction
+ return rawFunc();
+}
+
+unsigned int get_cop_ctrl_register(unsigned char cop_num,
+ unsigned char register_num)
+{
+// Workaround for MIPS' simplicistic instruction set...
+ unsigned int instr[] =
+ {0x40420000, // mfc $v0, 0
+ 0x03E00008, // jr $ra
+ 0x00000000, // nop
+ 0x00000000}; // nop
+
+ int (*rawFunc)() = (void*)instr;
+
+// Write coprocessor register number inside instruction
+ instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );
+
+// Execute modified instruction
+ return rawFunc();
+}
+
+unsigned int get_cop0_register(unsigned char register_num)
+{
+ return get_cop_register(0, register_num);
+}
+
+void set_cop_register(unsigned char cop_num,
+ unsigned char register_num,
+ unsigned int value)
+{
+// Workaround for MIPS' simplicistic instruction set...
+ unsigned int instr[] =
+ {0x40840000, // mtc $a0, 0
+ 0x03E00008, // jr $ra
+ 0x00000000, // nop
+ 0x00000000}; // nop
+
+ void (*rawFunc)(int value) = (void*)instr;
+
+// Write coprocessor register number inside instruction
+ instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );
+
+// Execute modified instruction
+ rawFunc(value);
+}
+
+void set_cop_ctrl_register(unsigned char cop_num,
+ unsigned char register_num,
+ unsigned int value)
+{
+// Workaround for MIPS' simplicistic instruction set...
+ unsigned int instr[] =
+ {0x40C40000, // ctc $a0, 0
+ 0x03E00008, // jr $ra
+ 0x00000000, // nop
+ 0x00000000}; // nop
+
+ void (*rawFunc)(int value) = (void*)instr;
+
+// Write coprocessor register number inside instruction
+ instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );
+
+// Execute modified instruction
+ rawFunc(value);
+}
+
+void set_cop0_register(unsigned char register_num,
+ unsigned int value)
+{
+ set_cop_register(0, register_num, value);
+}
+
+void run_cop_instruction(unsigned char cop_num,
+ unsigned int operation)
+{
+// Workaround for MIPS' simplicistic instruction set...
+ unsigned int instr[] =
+ {0x42000000, // cop 0
+ 0x03E00008, // jr $ra
+ 0x00000000, // nop
+ 0x00000000}; // nop
+
+ void (*rawFunc)(void) = (void*)instr;
+
+// Write coprocessor register number inside instruction
+ instr[0] |= ( (cop_num & 3) << 26 ) | (operation & 0x1ffffff);
+
+// Execute modified instruction
+ rawFunc();
+}
+
diff --git a/libpsx/src/costbl.h b/libpsx/src/costbl.h
new file mode 100644
index 0000000..2af73a6
--- /dev/null
+++ b/libpsx/src/costbl.h
@@ -0,0 +1,26 @@
+// Cosine / sine table used for rotations, 1 degree precision
+// While not as good, much faster than using libm cos() and sin() and does not require
+// to link libm with libpsx..
+
+const double gs_rot_cos_tbl[]=
+{
+ 1.000000,0.999848,0.999391,0.998630,0.997564,
+ 0.996195,0.994522,0.992546,0.990268,0.987688,
+ 0.984808,0.981627,0.978148,0.974370,0.970296,
+ 0.965926,0.961262,0.956305,0.951057,0.945519,
+ 0.939693,0.933580,0.927184,0.920505,0.913545,
+ 0.906308,0.898794,0.891007,0.882948,0.874620,
+ 0.866025,0.857167,0.848048,0.838671,0.829038,
+ 0.819152,0.809017,0.798636,0.788011,0.777146,
+ 0.766044,0.754710,0.743145,0.731354,0.719340,
+ 0.707107,0.694658,0.681998,0.669131,0.656059,
+ 0.642788,0.629320,0.615661,0.601815,0.587785,
+ 0.573576,0.559193,0.544639,0.529919,0.515038,
+ 0.500000,0.484810,0.469472,0.453990,0.438371,
+ 0.422618,0.406737,0.390731,0.374607,0.358368,
+ 0.342020,0.325568,0.309017,0.292372,0.275637,
+ 0.258819,0.241922,0.224951,0.207912,0.190809,
+ 0.173648,0.156434,0.139173,0.121869,0.104528,
+ 0.087156,0.069756,0.052336,0.034899,0.017452,
+ 0.000000,
+};
diff --git a/libpsx/src/exc1.s b/libpsx/src/exc1.s
new file mode 100644
index 0000000..379ed6d
--- /dev/null
+++ b/libpsx/src/exc1.s
@@ -0,0 +1,96 @@
+
+.text
+.global __psxsdk_exception_manager
+
+__psxsdk_exception_manager:
+
+# Save registers on stack
+
+.set noat
+ addi $sp, -120
+.set noat
+ sw $at, 0($sp)
+ mfhi $at
+ sw $at, 112($sp)
+ mflo $at
+ sw $at, 116($sp)
+.set at
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $s0, 60($sp)
+ sw $s1, 64($sp)
+ sw $s2, 68($sp)
+ sw $s3, 72($sp)
+ sw $s4, 76($sp)
+ sw $s5, 80($sp)
+ sw $s6, 84($sp)
+ sw $s7, 88($sp)
+ sw $t8, 92($sp)
+ sw $t9, 96($sp)
+ sw $gp, 100($sp)
+ sw $fp, 104($sp)
+ sw $ra, 108($sp)
+
+# Execute real exception handler
+ jal __psxsdk_real_exception_handler
+ nop
+
+# Load registers from stack
+
+.set noat
+ lw $at, 112($sp)
+ nop
+ mthi $at
+ lw $at, 116($sp)
+ nop
+ mtlo $at
+ lw $at, 0($sp)
+.set at
+ lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $s0, 60($sp)
+ lw $s1, 64($sp)
+ lw $s2, 68($sp)
+ lw $s3, 72($sp)
+ lw $s4, 76($sp)
+ lw $s5, 80($sp)
+ lw $s6, 84($sp)
+ lw $s7, 88($sp)
+ lw $t8, 92($sp)
+ lw $t9, 96($sp)
+ lw $gp, 100($sp)
+ lw $fp, 104($sp)
+ lw $ra, 108($sp)
+ addiu $sp, 120
+
+# Get exception return address..
+ mfc0 $k0, $14
+# Exit from exception handler
+.set noreorder # Do not let the assembler fill the delay slot!
+ jr $k0
+ rfe
+.set reorder # The assembler can fill the delay slot again.
diff --git a/libpsx/src/exception.c b/libpsx/src/exception.c
new file mode 100644
index 0000000..6ecabb2
--- /dev/null
+++ b/libpsx/src/exception.c
@@ -0,0 +1,178 @@
+/**
+ * exception.c
+ *
+ * Exception handling code (part 2)
+ */
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <psx.h>
+
+#define DICR *((unsigned int*)0x1f8010f4)
+#define IPENDING *((volatile unsigned int*)0x1f801070)
+#define IMASK *((volatile unsigned int*)0x1f801074)
+
+void __psxsdk_exception_manager();
+
+void (*_EXC_vblank_handler)();
+void (*_EXC_cdrom_handler)();
+void (*_EXC_sio_handler)(unsigned char *data);
+void (*_EXC_dma_handler)();
+unsigned int _EXC_vblank_handler_set;
+unsigned int _EXC_cdrom_handler_set;
+unsigned int _EXC_sio_handler_set;
+unsigned int _EXC_dma_handler_set;
+
+volatile int __psxsdk_gpu_dma_finished;
+
+void __psxsdk_real_exception_handler()
+{
+ unsigned int Cause = get_cop0_register(COP0_CAUSE);
+ unsigned int Cause_excCode = (Cause >> 2) & 31;
+ unsigned int Cause_IP = (Cause >> 8) & 255;
+ unsigned int SR = get_cop0_register(COP0_SR);
+ unsigned int SR_IM = (SR >> 8) & 255;
+ int i;
+/* unsigned int oldSR = SR;
+ unsigned int psxIP = IPENDING;
+ unsigned int psxIM = IMASK;
+ unsigned int sio_data;*/
+
+ if(Cause_excCode == 0) // interrupt generated the exception
+ {
+ /*for(i = 0; i < 8; i++)
+ {
+ if((Cause_IP & (1<<i)) && (SR_IM & (1<<i)))
+ {
+ SR ^= 1<<(i+8);
+ set_cop0_register(COP0_SR, SR);
+
+ switch(i)
+ {
+ case 2: // PSX Interrupt controller
+ // program_vblank_handler();
+ break;
+ }
+ }
+ }*/
+
+ if((Cause_IP & (1<<2)) && (SR_IM & (1<<2)))
+ {
+ Cause ^= 1<<10;
+ set_cop0_register(COP0_CAUSE, Cause);
+ //SR ^= 1<<10;
+ //set_cop0_register(COP0_SR, SR);
+
+ //while(IPENDING != 0)
+ {
+ for(i = 0; i < 11; i++)
+ {
+ if(IPENDING & (1<<i))
+ {
+ // printf("IP = %x\n", IPENDING);
+// Very interesting, when reading joypad status the PCSXR emulator sets in IPENDING that IRQ7 is pending even
+// if it is not enabled in IMASK! That is insane, but it can be easily worked around.
+// So we are going to disable pending bits for IRQs in IPENDING in any case, even if the in IRQ at hand was
+// not enabled in IMASK.
+
+ IPENDING ^= 1 << i;
+
+ if(IMASK & (1<<i))
+ {
+ // printf("IM = %x\n", IMASK);
+
+ switch(i)
+ {
+ case 0: // VBLANK
+ // if(!(GPU_CONTROL_PORT & (1<<0x1c)))
+ // GPU_CONTROL_PORT = 0x02000000;
+
+ // Execute the user-supplied VBlank handler.
+ if(_EXC_vblank_handler_set)
+ _EXC_vblank_handler();
+ break;
+ case 2:
+ /* if(_EXC_cdrom_handler_set)
+ _EXC_cdrom_handler();*/
+ break;
+ case 3: // DMA
+ // Execute the user-supplied DMA handler.
+ if(_EXC_dma_handler_set)
+ _EXC_dma_handler();
+ break;
+ case 8:
+ //while(!(SIO_STAT & 2))
+ //sio_data = SIO_RX_DATA;
+
+ //_EXC_sio_handler((unsigned char*)&sio_data);
+
+ // SIO_CTRL |= SIOCTRL_ACK;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void __psxsdk_dma_handler()
+{
+ unsigned int s_dicr = DICR;
+ unsigned char irq = (s_dicr >> 24) & 127;
+
+ if(irq & (1<<2)) // GPU
+ __psxsdk_gpu_dma_finished = 1;
+
+ // Acknowledge
+ DICR = s_dicr;
+
+ // Waste some cycles, so that the acknowledgement is reported
+// int x;
+
+// for(x = 0; x < 1000; x++);
+}
+
+extern void _internal_cdromlib_callback();
+
+ void __PSX_Init_NoBios()
+ {
+ _EXC_vblank_handler = NULL;
+ _EXC_cdrom_handler = _internal_cdromlib_callback;
+ _EXC_dma_handler = __psxsdk_dma_handler;
+ _EXC_sio_handler = NULL;
+
+ _EXC_vblank_handler_set = 0;
+ _EXC_cdrom_handler_set = 0;
+ _EXC_dma_handler_set = 1;
+ _EXC_sio_handler_set = 0;
+
+ IMASK = 0; // Clear Mask
+ IPENDING = 0; // Clear pending interrupts
+
+// Disable interrupts
+
+ set_cop0_register(COP0_SR, 0);
+
+// Change exception vector to point to our exception manager
+
+ *((unsigned int*)0x80000080) = 0x08000000 | ((((unsigned int)__psxsdk_exception_manager)>>2) & 0x3FFFFFF);
+ *((unsigned int*)0x80000084) = 0;
+
+
+// Enable interrupt generation, and interrupt 2 (PlayStation Interrupt Controller)
+ set_cop0_register(COP0_SR, (1<<10) | 1);
+
+// Enable VBlank, CDROM and DMA IRQs (on PlayStation Interrupt Controller)
+ IMASK = 1 | /* CDROM */ /*4 |*/ 8;
+
+// Set DMA channel priority
+ DPCR = 0x07654321;
+
+// Enable DMA IRQ master, and IRQ generation for DMA channel 2 (GPU)
+ DICR = (1<<23) | (1<<(16+2));
+
+// Setup variables
+ __psxsdk_gpu_dma_finished = 1;
+}
diff --git a/libpsx/src/exception.h b/libpsx/src/exception.h
new file mode 100644
index 0000000..1c72798
--- /dev/null
+++ b/libpsx/src/exception.h
@@ -0,0 +1,14 @@
+#ifndef _PSXSDK_EXCEPTION_H
+#define _PSXSDK_EXCEPTION_H
+
+extern void (*_EXC_vblank_handler)();
+extern void (*_EXC_sio_handler)(unsigned char *data);
+extern void (*_EXC_dma_handler)();
+extern unsigned int _EXC_vblank_handler_set;
+extern unsigned int _EXC_sio_handler_set;
+extern unsigned int _EXC_dma_handler_set;
+
+
+void __PSX_Init_NoBios();
+
+#endif
diff --git a/libpsx/src/font.h b/libpsx/src/font.h
new file mode 100644
index 0000000..b1c71cb
--- /dev/null
+++ b/libpsx/src/font.h
@@ -0,0 +1,266 @@
+// 8x8 ASCII font
+// 64x128
+// 4-bit format
+
+// The font was created by John Reeves Hall
+
+unsigned char psxsdk_font_data[] =
+{
+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,
+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,
+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,
+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,
+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,
+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,
+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,
+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,
+0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 16, 0, 0, 16, 16, 0,
+0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 1, 0, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 16, 0, 0, 16, 16, 0,
+0, 16, 17, 1, 0, 17, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 16, 17, 17, 17,
+0, 1, 1, 0, 0, 17, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 16, 0,
+0, 16, 17, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 16, 17, 17, 17,
+0, 0, 1, 1, 0, 16, 16, 1, 16, 0, 16, 1, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 0,
+0, 17, 17, 0, 0, 1, 16, 1, 16, 0, 16, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 16, 0,
+0, 0, 1, 0, 0, 0, 0, 0, 0, 17, 1, 1, 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, 16, 0, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
+0, 0, 1, 0, 0, 0, 1, 0, 16, 0, 1, 16, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 1, 1, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0,
+0, 16, 0, 0, 0, 0, 16, 0, 0, 16, 17, 0, 16, 17, 17, 17,
+0, 0, 0, 0, 16, 17, 17, 17, 0, 0, 0, 0, 0, 0, 1, 0,
+0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 1, 1, 0, 0, 1, 0,
+0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0,
+0, 0, 1, 0, 0, 0, 1, 0, 16, 0, 1, 16, 0, 0, 1, 0,
+0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 1, 0, 0,
+0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
+0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 16, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 16, 17, 0, 0, 0, 1, 0, 0, 16, 17, 0, 0, 16, 17, 0,
+0, 0, 17, 0, 0, 17, 17, 1, 0, 16, 17, 0, 0, 17, 17, 1,
+0, 1, 0, 1, 0, 16, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1,
+0, 16, 16, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1,
+0, 1, 16, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16, 0,
+0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 17, 0,
+0, 17, 17, 1, 0, 17, 17, 0, 0, 17, 17, 0, 0, 0, 1, 0,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1,
+0, 0, 16, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 16, 0, 0,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 16, 0, 0, 0, 1, 0, 1,
+0, 0, 16, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 16, 0, 0,
+0, 16, 17, 0, 0, 16, 17, 0, 0, 17, 17, 1, 0, 16, 17, 0,
+0, 0, 17, 1, 0, 16, 17, 0, 0, 16, 17, 0, 0, 16, 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, 16, 17, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 16, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 16, 17, 0,
+0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0,
+0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0,
+0, 16, 0, 0, 16, 17, 17, 17, 0, 0, 1, 0, 0, 0, 0, 1,
+0, 16, 17, 0, 0, 16, 17, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0,
+0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0,
+0, 16, 0, 0, 16, 17, 17, 17, 0, 0, 1, 0, 0, 0, 1, 0,
+0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0,
+0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0,
+0, 16, 17, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 16, 0,
+0, 0, 16, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 16, 17, 0, 0, 16, 17, 0, 0, 17, 17, 0, 0, 16, 17, 0,
+0, 17, 17, 0, 0, 17, 17, 1, 0, 17, 17, 1, 0, 16, 17, 0,
+0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1,
+0, 1, 17, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
+0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
+0, 1, 1, 1, 0, 17, 17, 1, 0, 17, 17, 0, 0, 1, 0, 0,
+0, 1, 0, 1, 0, 17, 17, 0, 0, 17, 17, 1, 0, 1, 17, 1,
+0, 1, 17, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
+0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1,
+0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1,
+0, 16, 17, 0, 0, 1, 0, 1, 0, 17, 17, 0, 0, 16, 17, 0,
+0, 17, 17, 0, 0, 17, 17, 1, 0, 1, 0, 0, 0, 16, 17, 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, 1, 0, 1, 0, 16, 17, 0, 0, 0, 17, 1, 0, 1, 0, 1,
+0, 16, 0, 0, 16, 0, 0, 16, 0, 1, 0, 1, 0, 16, 17, 0,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 1, 0, 1,
+0, 16, 0, 0, 16, 1, 0, 17, 0, 17, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 1, 16, 0,
+0, 16, 0, 0, 16, 16, 16, 16, 0, 1, 1, 1, 0, 1, 0, 1,
+0, 17, 17, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 17, 1, 0,
+0, 16, 0, 0, 16, 0, 1, 16, 0, 1, 1, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 16, 0,
+0, 16, 0, 0, 16, 0, 0, 16, 0, 1, 16, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 0, 1,
+0, 16, 0, 0, 16, 0, 0, 16, 0, 1, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 16, 17, 0, 0, 16, 1, 0, 0, 1, 0, 1,
+0, 16, 17, 1, 16, 0, 0, 16, 0, 1, 0, 1, 0, 16, 17, 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, 16, 17, 0, 0, 16, 17, 0, 0, 17, 17, 0, 0, 16, 17, 0,
+0, 17, 17, 1, 0, 1, 0, 1, 0, 1, 0, 1, 16, 0, 0, 16,
+0, 16, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 16, 0, 0, 16,
+0, 16, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
+0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 16, 0, 0, 16,
+0, 16, 17, 0, 0, 1, 0, 1, 0, 17, 17, 0, 0, 16, 17, 0,
+0, 0, 1, 0, 0, 1, 0, 1, 0, 16, 16, 0, 0, 1, 1, 1,
+0, 16, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
+0, 0, 1, 0, 0, 1, 0, 1, 0, 16, 16, 0, 0, 1, 1, 1,
+0, 16, 0, 0, 0, 1, 0, 1, 0, 1, 16, 0, 0, 1, 0, 1,
+0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 16, 16, 0,
+0, 16, 0, 0, 0, 16, 17, 0, 0, 1, 0, 1, 0, 16, 17, 0,
+0, 0, 1, 0, 0, 16, 17, 0, 0, 0, 1, 0, 0, 16, 16, 0,
+0, 0, 0, 0, 0, 0, 16, 1, 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, 1, 0, 1, 0, 1, 0, 1, 0, 17, 17, 1, 0, 16, 17, 0,
+16, 0, 0, 0, 0, 16, 17, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 16, 0, 0,
+0, 1, 0, 0, 0, 0, 16, 0, 0, 16, 16, 0, 0, 0, 0, 0,
+0, 16, 16, 0, 0, 16, 16, 0, 0, 0, 16, 0, 0, 16, 0, 0,
+0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 0, 1, 0, 0, 0, 0,
+0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 16, 0, 0,
+0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 16, 16, 0, 0, 0, 1, 0, 0, 16, 0, 0, 0, 16, 0, 0,
+0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0,
+0, 0, 0, 1, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 17, 17, 1, 0, 16, 17, 0,
+0, 0, 0, 16, 0, 16, 17, 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, 16, 17, 17, 17,
+0, 16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
+0, 0, 1, 0, 0, 16, 17, 0, 0, 16, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 1, 0, 0, 0, 0, 0, 16, 0, 1, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 1, 0, 16, 17, 0, 0, 16, 17, 0,
+0, 0, 17, 1, 0, 16, 17, 0, 0, 16, 0, 0, 0, 16, 17, 16,
+0, 0, 0, 0, 0, 16, 17, 1, 0, 16, 0, 1, 0, 1, 0, 0,
+0, 16, 0, 1, 0, 1, 0, 1, 0, 17, 1, 0, 0, 1, 0, 1,
+0, 0, 0, 0, 0, 1, 0, 1, 0, 16, 0, 1, 0, 1, 0, 0,
+0, 16, 0, 1, 0, 17, 17, 1, 0, 16, 0, 0, 0, 1, 0, 1,
+0, 0, 0, 0, 0, 1, 0, 1, 0, 16, 0, 1, 0, 1, 0, 0,
+0, 16, 0, 1, 0, 1, 0, 0, 0, 16, 0, 0, 0, 16, 17, 1,
+0, 0, 0, 0, 0, 16, 17, 16, 0, 1, 17, 0, 0, 16, 17, 0,
+0, 0, 17, 16, 0, 16, 17, 0, 0, 16, 0, 0, 0, 0, 0, 1,
+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, 16, 17, 0,
+0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
+0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 0,
+0, 0, 1, 0, 1, 17, 16, 1, 0, 1, 17, 0, 0, 16, 17, 0,
+0, 17, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+0, 0, 1, 0, 16, 0, 1, 16, 0, 16, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 17, 0, 0,
+0, 0, 1, 0, 16, 0, 1, 16, 0, 16, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+0, 0, 1, 0, 16, 0, 0, 16, 0, 16, 0, 1, 0, 1, 0, 1,
+0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 16, 0,
+0, 0, 1, 0, 16, 0, 0, 16, 0, 16, 0, 1, 0, 16, 17, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 17, 0, 0, 16, 1, 1, 0, 1, 17, 0, 0, 16, 17, 0,
+0, 16, 17, 0, 0, 1, 16, 0, 0, 1, 0, 1, 16, 0, 0, 16,
+0, 16, 0, 1, 0, 1, 16, 0, 0, 17, 0, 0, 0, 1, 0, 0,
+0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 0, 1, 16, 0, 0, 16,
+0, 16, 0, 1, 0, 1, 16, 0, 0, 1, 0, 0, 0, 16, 1, 0,
+0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 0, 1, 16, 0, 1, 16,
+0, 16, 17, 0, 0, 16, 17, 0, 0, 1, 0, 0, 0, 0, 16, 0,
+0, 0, 1, 0, 0, 1, 16, 0, 0, 16, 16, 0, 16, 16, 16, 16,
+0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 17, 1, 0,
+0, 0, 1, 0, 0, 16, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1,
+0, 16, 0, 0, 0, 0, 16, 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, 17, 0,
+0, 0, 1, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0,
+0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 0, 1, 0, 16, 0, 1, 0, 17, 17, 0, 0, 16, 0, 0,
+0, 0, 1, 0, 0, 0, 1, 0, 0, 17, 0, 0, 0, 0, 0, 0,
+0, 16, 16, 0, 0, 16, 0, 1, 0, 0, 16, 0, 0, 1, 0, 0,
+0, 0, 1, 0, 0, 0, 16, 0, 16, 0, 1, 16, 0, 0, 0, 0,
+0, 0, 1, 0, 0, 16, 0, 1, 0, 0, 1, 0, 0, 16, 0, 0,
+0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 16, 1, 0, 0, 0, 0,
+0, 16, 16, 0, 0, 0, 17, 1, 0, 16, 0, 0, 0, 16, 0, 0,
+0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 1, 0, 1, 0, 0, 0, 1, 0, 17, 17, 0, 0, 0, 17, 0,
+0, 0, 1, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 16, 17, 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,
+};
diff --git a/libpsx/src/gpu.c b/libpsx/src/gpu.c
new file mode 100644
index 0000000..7e097c6
--- /dev/null
+++ b/libpsx/src/gpu.c
@@ -0,0 +1,1507 @@
+// PSXSDK Graphics Processing Unit (GPU) / Graphics Synthesizer (GS)
+// Routines
+
+#include <psx.h>
+#include <stdio.h>
+#include <strings.h>
+#include "font.h"
+#include "costbl.h"
+
+extern volatile int __psxsdk_gpu_dma_finished;
+
+static unsigned int *linked_list;
+static unsigned int linked_list_pos;
+
+int fb_font_x, fb_font_y, fb_font_cx, fb_font_cy;
+
+static unsigned int prfont_flags = 0;
+static int prfont_scale_x = 0;
+static int prfont_scale_y = 0;
+static unsigned char prfont_rl = NORMAL_LUMINANCE;
+static unsigned char prfont_gl = NORMAL_LUMINANCE;
+static unsigned char prfont_bl = NORMAL_LUMINANCE;
+
+unsigned short GsScreenW;
+unsigned short GsScreenH;
+unsigned char GsScreenM;
+
+unsigned short GsCurDrawEnvW;
+unsigned short GsCurDrawEnvH;
+
+double gs_vbuf[4][3];
+
+static int __gs_autowait = 0;
+
+unsigned int PRFONT_SCALEX(int i)
+{
+ prfont_scale_x = i;
+ return PRFONT_SCALE;
+}
+
+unsigned int PRFONT_SCALEY(int i)
+{
+ prfont_scale_y = i;
+ return PRFONT_SCALE;
+}
+
+unsigned int PRFONT_RL(unsigned char f)
+{
+ prfont_rl = f;
+ return PRFONT_COLOR;
+}
+
+unsigned int PRFONT_GL(unsigned char f)
+{
+ prfont_gl = f;
+ return PRFONT_COLOR;
+}
+
+unsigned int PRFONT_BL(unsigned char f)
+{
+ prfont_bl = f;
+ return PRFONT_COLOR;
+}
+
+unsigned int draw_mode_packet;
+
+unsigned int setup_attribs(unsigned char tpage, unsigned int attribute, unsigned char *packet);
+static void gs_internal_vector_rotate(int x_a, int y_a, int z_a, double *v, double *n);
+
+static char gpu_stringbuf[512];
+
+int gs_calculate_scaled_size(int size, int scale)
+{
+ if(scale > 8)
+ return (size * scale) / SCALE_ONE;
+ else if(scale == 0)
+ return size;
+ else if(scale > 0)
+ return size * scale;
+ else if(scale > -8)
+ return size / (scale * -1);
+
+ return (size * SCALE_ONE) / -scale;
+}
+
+void GsSetList(unsigned int *listptr)
+{
+ linked_list = listptr;
+ linked_list_pos = 0;
+}
+
+void GsDrawList()
+{
+ if(PSX_GetInitFlags() & PSX_INIT_NOBIOS)
+ {
+// DMA is unreliable right now, use PIO.
+ GsDrawListPIO();
+ return;
+ }
+
+ //int x = 0;
+
+ /* Put a terminator, so the link listed ends. */
+ linked_list[linked_list_pos] = 0x00ffffff;
+
+// do{printf("linked_list[%d] = %08x\n", x, linked_list[x]);}while(linked_list[x++]!=0xffffff);
+
+ //#warning "Let's hope this works well."
+
+ while(!(GPU_CONTROL_PORT & (1<<0x1a))); /* Wait for the GPU to finish
+ * drawing primitives. */
+ while(!(GPU_CONTROL_PORT & (1<<0x1c))); /* Wait for the GPU to be free */
+
+ gpu_ctrl(4, 2); // DMA CPU->GPU mode
+ D2_MADR = (unsigned int)linked_list;
+ D2_BCR = 0;
+ D2_CHCR = (1<<0xa)|1|(1<<0x18);
+
+ linked_list_pos = 0;
+
+ //if(PSX_GetInitFlags() & PSX_INIT_NOBIOS)
+ // __psxsdk_gpu_dma_finished = 0;
+
+ if(__gs_autowait)
+ while(GsIsDrawing());
+}
+
+void GsDrawListPIO()
+{
+ //linked_list[linked_list_pos] = 0x00ffffff;
+ int pos = 0;
+ int sz = 0;
+ int x;
+
+ while(!(GPU_CONTROL_PORT & (1<<0x1c)));
+ // Disable DMA
+ GPU_CONTROL_PORT = 0x04000000;
+
+
+ while(pos < linked_list_pos)
+ {
+ while(!(GPU_CONTROL_PORT & (1<<0x1c)));
+
+ GPU_DATA_PORT = 0x01000000; // Reset data port
+
+ sz = linked_list[pos++] >> 24;
+
+ for(x = 0; x < sz; x++)
+ GPU_DATA_PORT = linked_list[pos++];
+ }
+
+ linked_list_pos = 0;
+// GPU_DATA_PORT = 0xE6000000; // Disable masking stuff
+// gpu_data_ctrl(2, ((b&0xff)<<16)|((g&0xff)<<8)|r);
+// GPU_DATA_PORT = (y<<16)|x;
+// GPU_DATA_PORT = (h<<16)|w;
+ if(__gs_autowait)
+ while(GsIsDrawing());
+}
+
+void GsSortPoly3(GsPoly3 *poly3)
+{
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x20;
+ unsigned int md;
+
+ md = setup_attribs(0, poly3->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x05000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(poly3->b<<16)|(poly3->g<<8)|(poly3->r);
+
+ for(x = 0; x < 3; x++)
+ linked_list[linked_list_pos++] = ((poly3->y[x]&0x7ff)<<16)|(poly3->x[x]&0x7ff);
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortPoly4(GsPoly4 *poly4)
+{
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x28;
+ unsigned int md;
+
+ md = setup_attribs(0, poly4->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x06000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(poly4->b<<16)|(poly4->g<<8)|(poly4->r);
+
+ for(x = 0; x < 4; x++)
+ linked_list[linked_list_pos++] = ((poly4->y[x]&0x7ff)<<16)|(poly4->x[x]&0x7ff);
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortGPoly3(GsGPoly3 *poly3)
+{
+ // PKT 0x30
+
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x30;
+ unsigned int md;
+
+ md = setup_attribs(0, poly3->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x07000000;
+ linked_list[linked_list_pos++] = md;
+
+ for(x = 0; x < 3; x++)
+ {
+ linked_list[linked_list_pos++] = (poly3->b[x]<<16)|(poly3->g[x]<<8)|(poly3->r[x]) | ((x == 0)?(pkt<<24):0);
+ linked_list[linked_list_pos++] = ((poly3->y[x]&0x7ff)<<16)|(poly3->x[x]&0x7ff);
+ }
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortGPoly4(GsGPoly4 *poly4)
+{
+ // PKT 0x38
+
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x38;
+ unsigned int md;
+
+ md = setup_attribs(0, poly4->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x09000000;
+ linked_list[linked_list_pos++] = md;
+
+ for(x = 0; x < 4; x++)
+ {
+ linked_list[linked_list_pos++] = (poly4->b[x]<<16)|(poly4->g[x]<<8)|(poly4->r[x]) | ((x == 0)?(pkt<<24):0);
+ linked_list[linked_list_pos++] = ((poly4->y[x]&0x7ff)<<16)|(poly4->x[x]&0x7ff);
+ }
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortLine(GsLine *line)
+{
+ // PKT 0x40
+
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x40;
+ unsigned int md;
+
+ md = setup_attribs(0, line->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x04000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(line->b<<16)|(line->g<<8)|(line->r);
+
+ for(x = 0; x < 2; x++)
+ linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x]&0x7ff);
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortGLine(GsGLine *line)
+{
+ // PKT 0x50
+
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x50;
+ unsigned int md;
+
+ md = setup_attribs(0, line->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x05000000;
+ linked_list[linked_list_pos++] = md;
+
+ for(x=0;x<2;x++)
+ {
+ linked_list[linked_list_pos++] = (line->b[x]<<16)|(line->g[x]<<8)|(line->r[x])|((x == 0)?(pkt<<24):0);
+ linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x] & 0x7ff);
+ }
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortDot(GsDot *dot)
+{
+ // PKT 0x68
+
+ int orig_pos = linked_list_pos;
+ unsigned char pkt = 0x68;
+ unsigned int md;
+
+ md = setup_attribs(0, dot->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x03000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(dot->b<<16)|(dot->g<<8)|(dot->r);
+ linked_list[linked_list_pos++] = ((dot->y&0x7ff)<<16)|(dot->x&0x7ff);
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortSprite(GsSprite *sprite)
+{
+ GsTPoly4 tpoly4;
+ int x, y;
+ int sx = sprite->x & 0x7ff;
+ int sy = sprite->y & 0x7ff;
+ int mcx, mcy;
+
+ /*if(sprite->w > 256)
+ sprite->w = 256;
+
+ if(sprite->h > 256)
+ sprite->h = 256;*/
+
+ // If "sprite" has no flipping and no scaling use sprite primitive
+ // otherwise manipulate a 4 point textured polygon primitive
+
+ if(sprite->rotate != 0)
+ {
+ tpoly4.u[0] = sprite->u;
+ tpoly4.v[0] = sprite->v;
+
+ tpoly4.u[1] = sprite->u;
+ tpoly4.v[1] = sprite->v + sprite->h;
+
+ tpoly4.u[2] = sprite->u + sprite->w;
+ tpoly4.v[2] = sprite->v;
+
+ tpoly4.u[3] = sprite->u + sprite->w;
+ tpoly4.v[3] = sprite->v + sprite->h;
+
+ gs_vbuf[0][2] = gs_vbuf[1][2] = gs_vbuf[2][2] = gs_vbuf[3][2] = 0;
+
+ mcx = sprite->mx + sprite->x;
+ mcy = sprite->my + sprite->y;
+
+ gs_vbuf[0][0] = -(mcx - sprite->x);
+ gs_vbuf[0][1] = (mcy - sprite->y);
+
+ gs_vbuf[1][0] = -(mcx - sprite->x);
+ gs_vbuf[1][1] = (mcy - (sprite->y + gs_calculate_scaled_size(sprite->h, sprite->scaley)));
+
+ gs_vbuf[2][0] = -(mcx - (sprite->x + gs_calculate_scaled_size(sprite->w, sprite->scalex)));
+ gs_vbuf[2][1] = (mcy - sprite->y);
+
+ gs_vbuf[3][0] = -(mcx - (sprite->x + gs_calculate_scaled_size(sprite->w, sprite->scalex)));
+ gs_vbuf[3][1] = (mcy - (sprite->y + gs_calculate_scaled_size(sprite->h, sprite->scaley)));
+
+ for(x = 0; x < 4; x++)
+ {
+ gs_internal_vector_rotate(0, 0, sprite->rotate, gs_vbuf[x], gs_vbuf[x]);
+ tpoly4.x[x] = mcx + gs_vbuf[x][0];
+ tpoly4.y[x] = mcy + gs_vbuf[x][1];
+ }
+
+ tpoly4.r = sprite->r;
+ tpoly4.g = sprite->g;
+ tpoly4.b = sprite->b;
+ tpoly4.attribute = sprite->attribute;
+ tpoly4.tpage = sprite->tpage;
+ tpoly4.cx = sprite->cx;
+ tpoly4.cy = sprite->cy;
+
+ GsSortTPoly4(&tpoly4);
+ }
+ else if((sprite->attribute & (H_FLIP|V_FLIP)) ||
+ sprite->scalex != 0 || sprite->scaley != 0)
+ {
+ x = sprite->w;
+ if(x>256)x=256;
+
+ y = sprite->h;
+ if(y>256)y=256;
+
+ if(sprite->scalex > 8)
+ {
+ x *= sprite->scalex;
+ x /= 4096;
+ }
+ else
+ {
+ if(sprite->scalex >= 2)
+ x*=sprite->scalex;
+ else if(sprite->scalex <= -2)
+ x/=-sprite->scalex;
+ }
+
+ if(sprite->scaley > 8)
+ {
+ y *= sprite->scaley;
+ y /= 4096;
+ }
+ else
+ {
+ if(sprite->scaley >= 2)
+ y*=sprite->scaley;
+ else if(sprite->scaley <= -2)
+ y/=-sprite->scaley;
+ }
+
+ tpoly4.x[0] = tpoly4.x[1] = sx;
+ tpoly4.x[2] = tpoly4.x[3] = (sx + x);
+ tpoly4.y[0] = tpoly4.y[2] = sy;
+ tpoly4.y[1] = tpoly4.y[3] = (sy + y);
+
+ if(sprite->attribute & H_FLIP)
+ {
+ tpoly4.u[0] = tpoly4.u[1] = (sprite->u + sprite->w) - 1;
+ tpoly4.u[2] = tpoly4.u[3] = sprite->u;
+ }
+ else
+ {
+ tpoly4.u[0] = tpoly4.u[1] = sprite->u;
+ tpoly4.u[2] = tpoly4.u[3] = (sprite->u + sprite->w);
+ }
+
+ if(sprite->attribute & V_FLIP)
+ {
+ tpoly4.v[0] = tpoly4.v[2] = (sprite->v + sprite->h) - 1;
+ tpoly4.v[1] = tpoly4.v[3] = sprite->v;
+ }
+ else
+ {
+ tpoly4.v[0] = tpoly4.v[2] = sprite->v;
+ tpoly4.v[1] = tpoly4.v[3] = (sprite->v + sprite->h);
+ }
+
+ tpoly4.r = sprite->r;
+ tpoly4.g = sprite->g;
+ tpoly4.b = sprite->b;
+ tpoly4.attribute = sprite->attribute;
+ tpoly4.tpage = sprite->tpage;
+ tpoly4.cx = sprite->cx;
+ tpoly4.cy = sprite->cy;
+
+ GsSortTPoly4(&tpoly4);
+ }
+ else
+ {
+ GsSortSimpleSprite(sprite);
+ }
+}
+
+void GsSortSimpleSprite(GsSprite *sprite)
+{
+ unsigned int orig_pos = linked_list_pos;
+ unsigned char pkt = 0x64;
+ unsigned int md;
+
+ md = setup_attribs(sprite->tpage, sprite->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x05000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(sprite->b<<16)|(sprite->g<<8)|sprite->r;
+ linked_list[linked_list_pos++] = ((sprite->y&0x7ff)<<16)|(sprite->x&0x7ff);
+ linked_list[linked_list_pos++] = (get_clutid(sprite->cx,sprite->cy)<<16)|(sprite->v<<8)|sprite->u;
+ linked_list[linked_list_pos++] = (sprite->h<<16)|sprite->w;
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortRectangle(GsRectangle *rectangle)
+{
+ unsigned int orig_pos = linked_list_pos;
+ unsigned char pkt = 0x60;
+ unsigned int md;
+
+ md = setup_attribs(0, rectangle->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x04000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(rectangle->b<<16)|(rectangle->g<<8)|(rectangle->r);
+ linked_list[linked_list_pos++] = ((rectangle->y&0x7ff)<<16)|(rectangle->x&0x7ff);
+ linked_list[linked_list_pos++] = (rectangle->h<<16)|rectangle->w;
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortTPoly4(GsTPoly4 *tpoly4)
+{
+ unsigned int orig_pos = linked_list_pos;
+ unsigned char pkt = 0x2c;
+ unsigned int md;
+
+ /*md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt);*/
+
+ //printf("tpoly4->tpage = %d\n", tpoly4->tpage);
+
+ md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt);
+
+ //printf("pkt = %x\n", pkt);
+
+ linked_list[linked_list_pos++] = 0x09000000;
+ //linked_list[linked_list_pos++] = md;
+ //linked_list[linked_list_pos++] = 0xe0000000;
+ //linked_list[linked_list_pos++] = 0xe1000105;
+
+ //printf("tpoly4 md: %08x\n", md);
+ linked_list[linked_list_pos++] = (pkt<<24)|(tpoly4->b<<16)|(tpoly4->g<<8)|(tpoly4->r);
+ linked_list[linked_list_pos++] = ((tpoly4->y[0]&0x7ff)<<16)|(tpoly4->x[0]&0x7ff);
+ linked_list[linked_list_pos++] = (get_clutid(tpoly4->cx, tpoly4->cy)<<16)|(tpoly4->v[0]<<8)|tpoly4->u[0];
+ linked_list[linked_list_pos++] = ((tpoly4->y[1]&0x7ff)<<16)|(tpoly4->x[1]&0x7ff);
+ linked_list[linked_list_pos++] = (md << 16)|(tpoly4->v[1]<<8)|tpoly4->u[1];
+ linked_list[linked_list_pos++] = ((tpoly4->y[2]&0x7ff)<<16)|(tpoly4->x[2]&0x7ff);
+ linked_list[linked_list_pos++] = (tpoly4->v[2]<<8)|tpoly4->u[2];
+ linked_list[linked_list_pos++] = ((tpoly4->y[3]&0x7ff)<<16)|(tpoly4->x[3]&0x7ff);
+ linked_list[linked_list_pos++] = (tpoly4->v[3]<<8)|tpoly4->u[3];
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortTPoly3(GsTPoly3 *tpoly3)
+{
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x24;
+ unsigned int md;
+
+ md = setup_attribs(tpoly3->tpage, tpoly3->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x07000000;
+ linked_list[linked_list_pos++] =
+ (pkt<<24)|(tpoly3->b<<16)|(tpoly3->g<<8)|(tpoly3->r);
+
+ for(x = 0; x < 3; x++)
+ {
+ linked_list[linked_list_pos++] = ((tpoly3->y[x]&0x7ff)<<16)|(tpoly3->x[x]&0x7ff);
+ linked_list[linked_list_pos] = (tpoly3->u[x]<<8)|tpoly3->v[x];
+
+ switch(x)
+ {
+ case 0:
+ linked_list[linked_list_pos++] |=
+ get_clutid(tpoly3->cx, tpoly3->cy) << 16;
+ break;
+ case 1:
+ linked_list[linked_list_pos++] |=
+ md << 16;
+ break;
+ default:
+ linked_list_pos++;
+ break;
+ }
+ }
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void MoveImage(int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+ /*
+ * This seems more like "CopyImage"...
+ */
+
+ while(!(GPU_CONTROL_PORT & (1<<0x1c)));
+
+ GPU_CONTROL_PORT = 0x04000000;
+ GPU_DATA_PORT = 0x01000000; // Reset command buffer
+ GPU_DATA_PORT = 0xE6000000;
+ GPU_DATA_PORT = 0x80000000;
+ GPU_DATA_PORT = (src_y<<16)|src_x;
+ GPU_DATA_PORT = (dst_y<<16)|dst_x;
+ GPU_DATA_PORT = (h<<16)|w;
+}
+
+/*
+ * Add a method to add arbitrary data to the packet list
+ */
+
+void LoadImage(void *img, int x, int y, int w, int h)
+{
+ unsigned short *image = (unsigned short*)img;
+ int a, l;
+
+ //printf("LoadImage: %d, %d, %d, %d\n", x, y, w, h);
+
+ while(!(GPU_CONTROL_PORT & (1<<0x1c)));
+
+ GPU_CONTROL_PORT = 0x04000000; // Disable DMA
+
+// Reset should be on data port ! otherwise we won't be able
+// to write CLUTs for some time after they've been used!
+// (why??)
+
+ GPU_DATA_PORT = 0x01000000;
+ GPU_DATA_PORT = 0xE6000000; // disable masking stuff !!
+ GPU_DATA_PORT = 0xA0000000;
+ GPU_DATA_PORT = (y<<16)|x;
+ GPU_DATA_PORT = (h<<16)|w;
+
+ l = w*h;
+ if(l&1)l++;
+
+ for(a = 0; a < l; a+=2)
+ GPU_DATA_PORT = image[a]|(image[a+1]<<16);
+
+ GPU_CONTROL_PORT = 0x01000000;
+// while(!(GPU_CONTROL_PORT & (1<<0x1c)));
+}
+
+/*void LoadImage(void *img, int x, int y, int w, int h)
+{
+ GPU_dw(x, y, w, h, img);
+
+ int l;
+
+ printf("LoadImage: %d, %d, %d, %d\n", x, y, w, h);
+
+ l = w*h;
+ if(l&1)l++;
+ l/=2;
+
+ while(!(GPU_CONTROL_PORT & (1<<0x1c))); // Wait for the GPU to be free
+
+ gpu_ctrl(4, 2); // DMA CPU->GPU mode
+ D2_MADR = (unsigned int)img;
+ D2_BCR = (l << 16) | 1;
+ D2_CHCR = 0x01000201;
+
+ // Wait for DMA to finish
+
+ while(D2_CHCR & (1<<0x18));
+//}*/
+
+void GsSetDrawEnv(GsDrawEnv *drawenv)
+{
+ int end_y, end_x;
+ int mf;
+
+ /*
+ * Store the 0xe1 packet - we need it because we have to
+ * modify drawing environment for sprites
+ */
+
+ draw_mode_packet = (0xe1<<24)|(drawenv->draw_on_display>=1)<<10|
+ (drawenv->dither>=1)<<9;
+
+ gpu_data_ctrl(0xe1, draw_mode_packet);
+ gpu_data_ctrl(0xe2, 0);
+ gpu_data_ctrl(0xe3, (drawenv->y<<10)|drawenv->x);
+
+ end_x = (drawenv->x + drawenv->w)-1;
+ end_y = (drawenv->y + drawenv->h)-1;
+
+ gpu_data_ctrl(0xe4, (end_y<<10)|end_x);
+
+ //#warning "Check drawing offset better."
+ gpu_data_ctrl(0xe5, (drawenv->y<<11)|drawenv->x);
+ //gpu_data_ctrl(0xe5, 0);
+
+
+ mf = 0;
+ if(drawenv->set_mask) mf|=MASK_SET;
+ if(drawenv->ignore_mask) mf|=MASK_IGNORE;
+
+ GsSetMasking(mf);
+
+ GsCurDrawEnvW = drawenv->w;
+ GsCurDrawEnvH = drawenv->h;
+}
+
+void GsSetDispEnv(GsDispEnv *dispenv)
+{
+ gpu_ctrl(5, (dispenv->y<<10)|dispenv->x); // Display offset
+}
+
+void gpu_ctrl(unsigned int command, unsigned int param)
+{
+ unsigned int doubleword = (command << 0x18) | param;
+
+ GPU_CONTROL_PORT = 0x01000000;
+ GPU_CONTROL_PORT = doubleword;
+}
+
+void gpu_data(unsigned int data)
+{
+ GPU_DATA_PORT = data;
+}
+
+void gpu_data_ctrl(unsigned int command, unsigned int param)
+{
+ unsigned int doubleword = (command << 0x18) | param;
+
+ GPU_CONTROL_PORT = 0x01000000;
+ GPU_DATA_PORT = doubleword;
+}
+
+unsigned int setup_attribs(unsigned char tpage, unsigned int attribute, unsigned char *packet)
+{
+ unsigned int sprite_mode_packet;
+
+ //printf("tpage = %d, attribute = %x, packet = %x\n", tpage, attribute, packet);
+ //while(1);*/
+
+/*
+ * First, setup draw mode setting.
+ */
+
+ sprite_mode_packet = draw_mode_packet;
+ sprite_mode_packet|= tpage & 0x1f; /* Texture page */
+ sprite_mode_packet|= (attribute & 3) << 7; /* Color mode */
+ sprite_mode_packet|= ((attribute>>2)&3) << 5; /* Translucency mode */
+
+/*
+ * Check for STP bit flag in attribute, and modify packet byte accordingly
+ */
+ if(attribute & 16)
+ *packet|=2;
+
+ //printf("sprite_mode_packet = %08x\n", sprite_mode_packet);
+
+ return sprite_mode_packet;
+}
+
+unsigned int GsListPos()
+{
+ return linked_list_pos;
+}
+
+void GsEnableDisplay(int enable)
+{
+ gpu_ctrl(3, enable ? 0 : 1);
+}
+
+void GsReset()
+{
+ gpu_ctrl(0, 0); // Reset GPU
+}
+
+void GsInitEx(unsigned int flags)
+{
+ //gpu_ctrl(0, 0); // Reset GPU
+ GsReset(); // Reset GPU
+
+ DPCR |= (1<<0xb); // Enable dma channel 2
+ gpu_ctrl(4, 2); // DMA CPU->GPU mode
+
+ //gpu_ctrl(3, 1); // Disable display
+ GsEnableDisplay(0); // Disable display
+
+ GPU_DATA_PORT = 0x01000000; // Reset data port
+
+ /*gpu_ctrl(6, 0xc40240); // Horizontal start end
+ gpu_ctrl(7, 0x049025); // Vertical start end*/
+ //DrawFBRect(0, 0, 1023, 511, 0, 0, 0);
+}
+
+void GsInit()
+{
+ GsInitEx(0);
+}
+
+/*void SetVBlankHandler2(void *(callback)())
+{
+ unsigned int eventid;
+
+ EnterCriticalSection();
+
+ IMASK|=8; // Enable VBLANK interrupt
+ eventid = openevent(0xf0000001, 2, 0x1000, vblank_handler);
+
+ if(eventid == -1)
+ {
+ printf("SetVBlankHandler: Failed to open event!\n");
+ return;
+ }
+ else
+ printf("SetVBlankHandler: Event opened successfully!\n");
+
+ if(enableevent(eventid) == 0)
+ {
+ printf("SetVBlankHandler: Failed to enable event!\n");
+ // Shouldn't we close the event as well?
+ return;
+ }
+ else
+ printf("SetVBlankHandler: Event enabled successfully!\n");
+
+ ExitCriticalSection();
+}*/
+
+int GsSetVideoMode(int width, int height, int video_mode)
+{
+ // Just a quick wrapper for GsSetVideoModeEx
+ return GsSetVideoModeEx(width, height, video_mode, 0, 0, 0);
+}
+
+int GsSetVideoModeEx(int width, int height, int video_mode, int rgb24,
+ int inter, int reverse)
+{
+ unsigned char mode = 0;
+
+ GsEnableDisplay(0);
+
+ if(video_mode == VMODE_NTSC)
+ {
+ gpu_ctrl(6, 0xC4E24E); // Horizontal screen range
+ gpu_ctrl(7, 0x040010); // Vertical screen range
+ }
+ else
+ {
+ gpu_ctrl(6, 0xC62262); // Horizontal screen range
+ gpu_ctrl(7, 0x04B42D); // Vertical screen range
+ }
+
+ switch(height)
+ {
+ case 240:
+ break;
+ case 480:
+ mode|=4;
+ break;
+ default:
+ printf("%s: error, unknown width %d!\n", __FUNCTION__, width);
+ return 0;
+ }
+
+ switch(width)
+ {
+ case 256:
+ break;
+ case 320:
+ mode|=1;
+ break;
+ case 512:
+ mode|=2;
+ break;
+ case 640:
+ mode|=3;
+ break;
+ case 384:
+ mode|=64;
+ break;
+ default:
+ printf("%s: error, unknown height %d!\n", __FUNCTION__, height);
+ return 0;
+ }
+
+ if(video_mode)mode|=8; // Set PAL
+ if(rgb24)mode|=16; // Set unaccellerated 24-bit mode
+ if(inter)mode|=32; // Set interlaced video mode
+ if(reverse)mode|=128; // Set reverse flag (?)
+
+ gpu_ctrl(8, mode);
+ GsEnableDisplay(1);
+
+ GsScreenW = width;
+ GsScreenH = height;
+ GsScreenM = video_mode;
+
+ return 1;
+}
+
+void DrawFBRect(int x, int y, int w, int h, int r, int g, int b)
+{
+ while(!(GPU_CONTROL_PORT & (1<<0x1c)));
+
+ // Disable DMA
+ GPU_CONTROL_PORT = 0x04000000;
+
+ GPU_DATA_PORT = 0x01000000; // Reset data port
+ GPU_DATA_PORT = 0xE6000000; // Disable masking stuff
+ gpu_data_ctrl(2, ((b&0xff)<<16)|((g&0xff)<<8)|r);
+ GPU_DATA_PORT = (y<<16)|x;
+ GPU_DATA_PORT = (h<<16)|w;
+}
+
+void GsClearMem()
+{
+ // "Clears" the entire video memory by using DrawFBRect
+ // and waits that it has finished drawing...
+
+ DrawFBRect(0,0,1023,511,0,0,0);
+ while(GsIsDrawing());
+ DrawFBRect(0,511,1023,1,0,0,0);
+ while(GsIsDrawing());
+ DrawFBRect(1023,511,1,1,0,0,0);
+ while(GsIsDrawing());
+}
+
+int GsImageFromTim(GsImage *image, void *timdata)
+{
+ unsigned int *timdata_i = (unsigned int*)timdata;
+ unsigned short *timdata_s = (unsigned short*)timdata;
+ unsigned int pdata_pos;
+ unsigned int pdata_pos_s;
+
+ //printf("timdata_i[0] = %08x\n", timdata_i[0]);
+
+ if(timdata_i[0] != 0x10)
+ {
+ //printf("timdata_i[0] = %08x\n", timdata_i[0]);
+ return 0; // Unknown version or ID
+ }
+
+ image->pmode = timdata_i[1] & 7;
+
+ //printf("image->pmode = %d\n", image->pmode);
+
+ image->has_clut = (timdata_i[1] & 8) ? 1 : 0;
+
+ if(!image->has_clut)
+ pdata_pos = 8;
+ else
+ {
+ pdata_pos = 8 + timdata_i[2];
+ image->clut_x = timdata_s[6];
+ image->clut_y = timdata_s[7];
+ image->clut_w = timdata_s[8];
+ image->clut_h = timdata_s[9];
+ image->clut_data = &timdata_s[10];
+
+ /*printf("image->clut_y = %d\n", image->clut_y);
+ printf("image->clut_x = %d\n", image->clut_x);
+ printf("image->clut_h = %d\n", image->clut_h);
+ printf("image->clut_w = %d\n", image->clut_w);*/
+ }
+
+ pdata_pos_s = pdata_pos / 2;
+
+ image->x = timdata_s[pdata_pos_s + 2];
+ image->y = timdata_s[pdata_pos_s + 3];
+ image->w = timdata_s[pdata_pos_s + 4];
+ image->h = timdata_s[pdata_pos_s + 5];
+ image->data = &timdata_s[pdata_pos_s + 6];
+
+ /*printf("image->y = %d\n", image->y);
+ printf("image->x = %d\n", image->x);
+ printf("image->h = %d\n", image->h);
+ printf("image->w = %d\n", image->w);*/
+
+ return 1;
+}
+
+void GsUploadImage(GsImage *image)
+{
+ if(image->has_clut)
+ LoadImage(image->clut_data, image->clut_x, image->clut_y,
+ image->clut_w, image->clut_h);
+
+ LoadImage(image->data, image->x, image->y, image->w, image->h);
+}
+
+int GsSpriteFromImage(GsSprite *sprite, GsImage *image, int do_upload)
+{
+ if(do_upload)
+ GsUploadImage(image);
+
+ bzero(sprite, sizeof(GsSprite));
+
+ sprite->tpage = (image->x / 64) + ((image->y/256)*16);
+ sprite->u = image->x & 0x3f;
+ sprite->v = image->y & 0xff;
+
+ sprite->cx = image->clut_x;
+ sprite->cy = image->clut_y;
+
+ if(image->pmode == 0) // 4-bit pixel mode
+ sprite->u*=4;
+ else if(image->pmode == 1) // 8-bit pixel mode
+ sprite->u*=2;
+
+ switch(image->pmode)
+ {
+ case 0:
+ sprite->w = image->w * 4;
+ break;
+ case 1:
+ sprite->w = image->w * 2;
+ break;
+ case 2:
+ sprite->w = image->w;
+ break;
+ case 3:
+ sprite->w = image->w + (image->w / 2);
+ break;
+ }
+
+ sprite->h = image->h;
+ sprite->attribute = COLORMODE(image->pmode);
+ sprite->r = sprite->g = sprite->b = NORMAL_LUMINANCE;
+
+ return 1;
+}
+
+void GsSetMasking(unsigned char flag)
+{
+ gpu_data_ctrl(0xe6, flag);
+}
+
+int GsIsDrawing()
+{
+ /*int x;
+
+ if(PSX_GetInitFlags() & PSX_INIT_NOBIOS)
+ {
+ int r = (!(GPU_CONTROL_PORT & (1<<0x1a))) || (!__psxsdk_gpu_dma_finished);
+
+ for(x = 0; x < 1000; x++);
+
+ return r;
+ }*/
+
+ return !(GPU_CONTROL_PORT & (1<<0x1a)) ;
+}
+
+
+
+// Functions which use default values to use when you do not
+// really need to fiddle with all the fields of the structure
+
+void GsSetDrawEnvSimple(int x, int y, int w, int h)
+{
+ GsDrawEnv env;
+
+ env.dither = 0;
+ env.draw_on_display = 1;
+ env.x = x;
+ env.y = y;
+ env.w = w;
+ env.h = h;
+ env.ignore_mask = 0;
+ env.set_mask = 0;
+
+ GsSetDrawEnv(&env);
+}
+
+void GsSetDispEnvSimple(int x, int y)
+{
+ GsDispEnv env;
+
+ env.x = x;
+ env.y = y;
+
+ GsSetDispEnv(&env);
+}
+
+// Built-in font functions.
+
+void GsLoadFont(int fb_x, int fb_y, int cx, int cy)
+{
+ unsigned short pal[2] = {0x0, 0x7fff};
+
+ LoadImage(psxsdk_font_data, fb_x, fb_y, 16, 128);
+ while(GsIsDrawing());
+
+ if(cx != -1 && cy != -1)
+ {
+ LoadImage(pal, cx, cy, 16, 1);
+
+ fb_font_cx = cx;
+ fb_font_cy = cy;
+
+ while(GsIsDrawing());
+ }
+
+ fb_font_x = fb_x;
+ fb_font_y = fb_y;
+}
+
+unsigned int GsPrintFont_Draw(int x, int y, int scalex, int scaley)
+{
+ //int r;
+ GsSprite spr;
+ char *string;
+ int fw, fh;
+
+ /*va_list ap;
+
+ va_start(ap, fmt);*/
+
+// r = vsnprintf(gpu_stringbuf, 512, fmt, ap);
+
+// va_end(ap);
+ fw = gs_calculate_scaled_size(8, scalex);//(8*scalex)/4096;
+ fh = gs_calculate_scaled_size(8, scaley);//(8*scaley)/4096;
+
+ spr.x = x;
+ spr.y = y;
+ spr.r = prfont_rl;
+ spr.g = prfont_gl;
+ spr.b = prfont_bl;
+ spr.attribute = 0;
+ spr.cx = fb_font_cx;
+ spr.cy = fb_font_cy;
+ spr.tpage = (fb_font_x / 64) + ((fb_font_y / 256)*16);
+ spr.w = 8;
+ spr.h = 8;
+ spr.scalex = scalex;
+ spr.scaley = scaley;
+
+ string = gpu_stringbuf;
+
+ while(*string)
+ {
+ if(prfont_flags & PRFONT_WRAP)
+ {
+ if(spr.x >= GsScreenW)
+ {
+ spr.x = spr.x - GsScreenW;
+ spr.y += fh;
+ }
+ }
+
+ if(*string >= ' ' && *string <= '~')
+ {
+ spr.u = ((fb_font_x & 0x3f)*4)+((*string & 7) << 3);
+ spr.v = (fb_font_y & 0xff)+(*string & 0xf8);
+
+ if((spr.x < GsCurDrawEnvW && (spr.x+fw)>=0) &&
+ (spr.y < GsCurDrawEnvH && (spr.y+fh)>=0))
+ {
+
+ if((scalex == 0 || scalex == 1) && (scaley == 0 || scaley == 1))
+ GsSortSimpleSprite(&spr);
+ else
+ GsSortSprite(&spr);
+ }
+
+ spr.x += fw;
+ }
+
+ if(*string == '\r')
+ spr.x = 0;
+
+ if(*string == '\n')
+ {
+ spr.x = (prfont_flags & PRFONT_UNIXLF)? 0 : x;
+ spr.y += fh;
+ }
+
+ if(*string == '\t')
+ spr.x += fw * 8;
+
+ string++;
+ }
+
+ return (spr.y << 16) | spr.x;
+}
+
+unsigned int GsVPrintFont(int x, int y, const char *fmt, va_list ap)
+{
+ int r;
+ //GsSprite spr;
+ //char *string;
+ int fw = gs_calculate_scaled_size(8, prfont_scale_x);
+
+ r = vsnprintf(gpu_stringbuf, 512, fmt, ap);
+
+ if(prfont_flags & PRFONT_WRAP)
+ r = GsPrintFont_Draw(x, y, prfont_scale_x, prfont_scale_y);
+ else if(prfont_flags & PRFONT_CENTER)
+ r = GsPrintFont_Draw(x - ((r * fw)/2), y, prfont_scale_x, prfont_scale_y);
+ else if(prfont_flags & PRFONT_RIGHT)
+ r = GsPrintFont_Draw(x - (r * fw), y, prfont_scale_x, prfont_scale_y);
+ else
+ r = GsPrintFont_Draw(x, y, prfont_scale_x, prfont_scale_y);
+
+ return r;
+}
+
+unsigned int GsPrintFont(int x, int y, const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = GsVPrintFont(x, y, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
+
+void GsSetFont(int fb_x, int fb_y, int cx, int cy)
+{
+ if(fb_x != -1)
+ fb_font_x = fb_x;
+
+ if(fb_y != -1)
+ fb_font_y = fb_y;
+
+ if(fb_font_cx != -1)
+ fb_font_cx = cx;
+
+ if(fb_font_cy != -1)
+ fb_font_cy = cy;
+}
+
+void GsSetFontAttrib(unsigned int flags)
+{
+ prfont_flags = flags;
+
+ if(prfont_flags == 0)
+ {
+ PRFONT_SCALEX(0);
+ PRFONT_SCALEY(0);
+
+ PRFONT_RL(NORMAL_LUMINANCE);
+ PRFONT_GL(NORMAL_LUMINANCE);
+ PRFONT_BL(NORMAL_LUMINANCE);
+ }
+}
+
+static double gs_internal_cos(int a)
+{
+ int a_a = (a>>12)-(((a>>12)/360)*360);
+
+ if(a_a>=0 && a_a<=90)
+ return gs_rot_cos_tbl[a_a];
+ else if(a_a>90 && a_a<=180)
+ return -gs_rot_cos_tbl[180 - a_a];
+ else if(a_a>180 && a_a<=270)
+ return -gs_rot_cos_tbl[a_a - 180];
+ else if(a_a>270 && a_a<=359)
+ return gs_rot_cos_tbl[360 - a_a];
+
+ return 0;
+}
+
+static double gs_internal_sin(int a)
+{
+ int a_a = (a>>12)-(((a>>12)/360)*360);
+
+ if(a_a>=0 && a_a<=90)
+ return gs_rot_cos_tbl[90-a_a];
+ else if(a_a>90 && a_a<=180)
+ return gs_rot_cos_tbl[a_a-90];
+ else if(a_a>180 && a_a<=270)
+ return -gs_rot_cos_tbl[270-a_a];
+ else if(a_a>270 && a_a<=359)
+ return -gs_rot_cos_tbl[a_a-270];
+
+ return 0;
+}
+
+static void gs_internal_vector_rotate(int x_a, int y_a, int z_a, double *v, double *n)
+{
+ double axis_m[3][3];
+ double b[3];
+ double k[3], s[3];
+ int x;
+
+ k[0] = gs_internal_cos(x_a);
+ k[1] = gs_internal_cos(y_a);
+ k[2] = gs_internal_cos(z_a);
+
+ s[0] = gs_internal_sin(x_a);
+ s[1] = gs_internal_sin(y_a);
+ s[2] = gs_internal_sin(z_a);
+
+ axis_m[0][0] = k[1] * k[2];
+ axis_m[0][1] = (k[0] * s[2]) + (s[0]*s[1]*k[2]);
+ axis_m[0][2] = (s[0]*s[2]) - (k[0]*s[1]*k[2]);
+ axis_m[1][0] = -(k[1] * s[2]);
+ axis_m[1][1] = (k[0]*k[2]) - (s[0]*s[1]*s[2]);
+ axis_m[1][2] = (s[0]*k[2]) + (k[0]*s[1]*s[2]);
+ axis_m[2][0] = s[1];
+ axis_m[2][1] = -(s[0]*k[1]);
+ axis_m[2][2] = k[0]*k[1];
+
+ for(x=0;x<3;x++)
+ b[x] = (axis_m[x][0] * v[0]) + (axis_m[x][1] * v[1]) + (axis_m[x][2] * v[2]);
+
+ b[1]=-b[1];
+
+ for(x=0;x<3;x++)
+ n[x]=b[x];
+}
+
+int GsIsWorking()
+{
+ return GsIsDrawing();
+}
+
+void GsSortCls(int r, int g, int b)
+{
+ GsRectangle rect;
+
+ rect.r = r;
+ rect.g = g;
+ rect.b = b;
+ rect.x = 0;
+ rect.y = 0;
+ rect.attribute = 0;
+ rect.w = GsCurDrawEnvW;
+ rect.h = GsCurDrawEnvH;
+
+ GsSortRectangle(&rect);
+}
+
+void GsSetAutoWait()
+{
+ __gs_autowait = 1;
+}
+
+void GsRotateVector(int x_a, int y_a, int z_a, double *v, double *n)
+{
+ gs_internal_vector_rotate(x_a, y_a, z_a, v, n);
+}
+
+/*void GsSortSimpleMap(GsMap *map)
+{
+ unsigned int orig_pos = linked_list_pos;
+ //unsigned int
+ unsigned char pkt = 0x64;
+ unsigned int md;
+ unsigned char curCount = 0;
+ unsigned int remaining;
+ unsigned int tn;
+ unsigned short tu;
+ unsigned short tv;
+ int x, y;
+
+ md = setup_attribs(map->tpage, map->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x01000000;
+ linked_list[linked_list_pos++] = md;
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+
+ orig_pos = linked_list_pos;
+ linked_list[linked_list_pos++] = 0x00000000;
+
+ remaining = map->w * map->h;
+
+ for(y = 0; y < map->h; y++)
+ {
+ for(x = 0; x < map->w; x++)
+ {
+ switch(map->tsize)
+ {
+ case 1:
+ tn = ((unsigned char*)map->data)[(y * map->l) + x];
+ break;
+ case 2:
+ tn = ((unsigned short*)map->data)[(y * map->l) + x];
+ break;
+ case 4:
+ tn = ((unsigned int*)map->data)[(y * map->l) + x];
+ break;
+ }
+
+ tn &= ~map->tmask;
+
+ tu = (tn * map->tw) % map->tmw;
+ tv = ((tn * map->tw) / map->tmw) * map->th;
+
+ linked_list[linked_list_pos++] = (pkt<<24)|(map->b<<16)|(map->g<<8)|map->r;
+ linked_list[linked_list_pos++] = (((map->y+(y*map->th))&0x7ff)<<16)|((map->x+(x*map->tw))&0x7ff);
+ linked_list[linked_list_pos++] = (get_clutid(map->cx,map->cy)<<16)|((tv+map->v)<<8)|
+ (tu+map->u);
+ linked_list[linked_list_pos++] = (map->th<<16)|map->tw;
+
+ curCount++;
+
+ if(curCount == 252)
+ {
+ linked_list[orig_pos] = (252 << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff);
+ orig_pos = linked_list_pos;
+
+ remaining -= curCount;
+
+ if(remaining > 0)
+ linked_list_pos++;
+
+ curCount = 0;
+ }
+ }
+ }
+
+ if(curCount > 0)
+ linked_list[orig_pos] = (curCount << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff);
+}*/
+
+void GsSetListEx(unsigned int *listptr, unsigned int listpos)
+{
+ linked_list = listptr;
+ linked_list_pos = listpos;
+}
+
+void GsSortPolyLine(GsPolyLine *line)
+{
+ // PKT 0x48
+
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x48;
+ unsigned int md;
+
+ md = setup_attribs(0, line->attribute, &pkt);
+
+ linked_list_pos++; // skip this word, we will replace it later
+ linked_list[linked_list_pos++] = md;
+ linked_list[linked_list_pos++] = (pkt<<24)|(line->b<<16)|(line->g<<8)|(line->r);
+
+ for(x = 0; x < line->npoints; x++)
+ linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x]&0x7ff);
+
+ linked_list[linked_list_pos++] = 0x55555555; // termination code
+
+ linked_list[orig_pos] = ((line->npoints+3) << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff);
+}
+
+void GsSortGPolyLine(GsGPolyLine *line)
+{
+ // PKT 0x58
+
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x58;
+ unsigned int md;
+
+ md = setup_attribs(0, line->attribute, &pkt);
+
+ linked_list_pos++; // skip this word, we will replace it later
+ linked_list[linked_list_pos++] = md;
+
+ for(x=0; x < line->npoints;x++)
+ {
+ linked_list[linked_list_pos++] = (line->b[x]<<16)|(line->g[x]<<8)|(line->r[x])|((x == 0)?(pkt<<24):0);
+ linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x] & 0x7ff);
+ }
+
+ linked_list[linked_list_pos++] = 0x55555555; // termination code
+
+ linked_list[orig_pos] = (((line->npoints*2)+2) << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff);
+}
+
+void GsSortGTPoly4(GsGTPoly4 *tpoly4)
+{
+ unsigned int orig_pos = linked_list_pos;
+ unsigned char pkt = 0x3c;
+ unsigned int md;
+
+ /*md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt);*/
+
+ //printf("tpoly4->tpage = %d\n", tpoly4->tpage);
+
+ md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt);
+
+ //printf("pkt = %x\n", pkt);
+
+ linked_list[linked_list_pos++] = 0x0C000000;
+ //linked_list[linked_list_pos++] = md;
+ //linked_list[linked_list_pos++] = 0xe0000000;
+ //linked_list[linked_list_pos++] = 0xe1000105;
+
+ //printf("tpoly4 md: %08x\n", md);
+ linked_list[linked_list_pos++] = (pkt<<24)|(tpoly4->b[0]<<16)|(tpoly4->g[0]<<8)|(tpoly4->r[0]);
+ linked_list[linked_list_pos++] = ((tpoly4->y[0]&0x7ff)<<16)|(tpoly4->x[0]&0x7ff);
+ linked_list[linked_list_pos++] = (get_clutid(tpoly4->cx, tpoly4->cy)<<16)|(tpoly4->v[0]<<8)|tpoly4->u[0];
+ linked_list[linked_list_pos++] = (tpoly4->b[1]<<16)|(tpoly4->g[1]<<8)|tpoly4->r[1];
+ linked_list[linked_list_pos++] = ((tpoly4->y[1]&0x7ff)<<16)|(tpoly4->x[1]&0x7ff);
+ linked_list[linked_list_pos++] = (md << 16)|(tpoly4->v[1]<<8)|tpoly4->u[1];
+ linked_list[linked_list_pos++] = (tpoly4->b[1]<<16)|(tpoly4->g[1]<<8)|tpoly4->r[1];
+ linked_list[linked_list_pos++] = ((tpoly4->y[2]&0x7ff)<<16)|(tpoly4->x[2]&0x7ff);
+ linked_list[linked_list_pos++] = (tpoly4->v[2]<<8)|tpoly4->u[2];
+ linked_list[linked_list_pos++] = (tpoly4->b[2]<<16)|(tpoly4->g[2]<<8)|tpoly4->r[2];
+ linked_list[linked_list_pos++] = ((tpoly4->y[3]&0x7ff)<<16)|(tpoly4->x[3]&0x7ff);
+ linked_list[linked_list_pos++] = (tpoly4->v[3]<<8)|tpoly4->u[3];
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
+
+void GsSortGTPoly3(GsGTPoly3 *tpoly3)
+{
+ int orig_pos = linked_list_pos;
+ int x;
+ unsigned char pkt = 0x34;
+ unsigned int md;
+
+ md = setup_attribs(tpoly3->tpage, tpoly3->attribute, &pkt);
+
+ linked_list[linked_list_pos++] = 0x09000000;
+
+ for(x = 0; x < 3; x++)
+ {
+ linked_list[linked_list_pos++] =
+ ((x==0)?(pkt<<24):0)|(tpoly3->b[x]<<16)|(tpoly3->g[x]<<8)|(tpoly3->r[x]);
+ linked_list[linked_list_pos++] = ((tpoly3->y[x]&0x7ff)<<16)|(tpoly3->x[x]&0x7ff);
+ linked_list[linked_list_pos] = (tpoly3->u[x]<<8)|tpoly3->v[x];
+
+ switch(x)
+ {
+ case 0:
+ linked_list[linked_list_pos++] |=
+ get_clutid(tpoly3->cx, tpoly3->cy) << 16;
+ break;
+ case 1:
+ linked_list[linked_list_pos++] |=
+ md << 16;
+ break;
+ default:
+ linked_list_pos++;
+ }
+ }
+
+ linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff;
+}
diff --git a/libpsx/src/libc.c b/libpsx/src/libc.c
new file mode 100644
index 0000000..8ad519b
--- /dev/null
+++ b/libpsx/src/libc.c
@@ -0,0 +1,705 @@
+/*
+ * small libc functions for the PSXSDK
+ *
+ * In this file, C functions either not implemented by the BIOS
+ * or very broken in the BIOS are implemented independently
+ *
+ * Some functions, such as printf, have both a BIOS implementation
+ * and an implementation here. The implementation here is prefixed
+ * with libc_ to not make confusion.
+ */
+
+#include <psx.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+char onesec_buf[2048];
+int errno;
+int __stdio_direction = STDIO_DIRECTION_BIOS;
+static unsigned int __sio_cr_mapped = 0;
+
+#define NUM_OF_FILE_STRUCTS 259
+
+FILE file_structs[NUM_OF_FILE_STRUCTS] =
+{
+ [0] = // stdin
+ {
+ .fildes = 0,
+ .pos = 0,
+ .mode = O_RDONLY,
+ .dev = FDEV_CONSOLE,
+ .size = 0,
+ .used = 1,
+ .eof = 0,
+ .error = 0
+ },
+ [1] = // stdout
+ {
+ .fildes = 1,
+ .pos = 0,
+ .mode = O_WRONLY,
+ .dev = FDEV_CONSOLE,
+ .size = 0,
+ .used = 1,
+ .eof = 0,
+ .error = 0
+ },
+ [2] = // stderr
+ {
+ .fildes = 2,
+ .pos = 0,
+ .mode = O_WRONLY,
+ .dev = FDEV_CONSOLE,
+ .size = 0,
+ .used = 1,
+ .eof = 0,
+ .error = 0
+ },
+};
+
+FILE *stdin = &file_structs[0];
+FILE *stdout = &file_structs[1];
+FILE *stderr = &file_structs[2];
+
+#define IS_CONS_IN(f) (f->fildes == 0)
+#define IS_CONS_OUT(f) (f->fildes == 1 || f->fildes == 2)
+
+//unsigned char file_state[NUM_OF_FILE_STRUCTS];
+
+int libc_get_transtbl_fname(const char *tofind, char *outstr, int outl);
+
+unsigned int fmode_to_desmode(const char *fmode)
+{
+ char rmode[16];
+ int x, y;
+
+ y = 0;
+
+ for(x=0;x<15;x++)
+ {
+ if(fmode[x] == 0)
+ break;
+ else
+ {
+ if(fmode[x] != 'b' && fmode[x] != 'f')
+ rmode[y++] = fmode[x];
+ }
+ }
+
+ rmode[y] = 0;
+
+ if(strcmp(rmode, "r") == 0)
+ {
+ dprintf("Open for reading.\n");
+ return O_RDONLY;
+ }
+ else if(strcmp(rmode, "r+") == 0)
+ {
+ dprintf("Open for reading and writing.\n");
+ return O_RDWR;
+ }
+ else if(strcmp(rmode, "w") == 0)
+ {
+ dprintf("Open for writing.\n");
+ return O_WRONLY | O_CREAT | O_TRUNC;
+ }
+ else if(strcmp(rmode, "w+") == 0)
+ {
+ dprintf("Open for writing. Truncate to zero or create file.\n");
+ return O_RDWR | O_CREAT | O_TRUNC;
+ }
+ else if(strcmp(rmode, "a") == 0)
+ {
+ dprintf("Append; open for writing. Create file if it doesn't exist.\n");
+ return O_WRONLY | O_APPEND;
+ }
+ else if(strcmp(rmode, "a+") == 0)
+ {
+ dprintf("Append; open for reading and writing. Create file if it doesn't exist.\n");
+ return O_RDWR | O_APPEND | O_CREAT;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+FILE *fdopen(int fildes, const char *mode)
+{
+// Adjust for malloc
+ int x;
+
+// Find a free file structure
+ for(x = 0; x < NUM_OF_FILE_STRUCTS; x++)
+ {
+ if(file_structs[x].used == 0)
+ {
+ bzero(&file_structs[x], sizeof(FILE));
+ file_structs[x].used = 1;
+ break;
+ }
+ }
+
+// If we found no free file structure, return NULL pointer
+
+ if(x == NUM_OF_FILE_STRUCTS)
+ return NULL;
+
+ file_structs[x].fildes = fildes;
+ file_structs[x].pos = lseek(fildes, 0, SEEK_CUR);
+ file_structs[x].mode = fmode_to_desmode(mode);
+
+ return &file_structs[x];
+}
+
+static FILE *fopen_internal(const char *path, const char *mode, FILE *f)
+{
+ int fd;
+ char *s = NULL;
+
+ if(strncmp(path, "cdromL:", 7) == 0)
+ {
+ s = malloc(1024);
+
+ if(libc_get_transtbl_fname(path+7, s, 1024) == 0)
+ return NULL;
+
+ fd = open(s, fmode_to_desmode(mode));
+ }
+ else
+ fd = open(path, fmode_to_desmode(mode));
+
+ if(fd == -1)
+ {
+ if(s!=NULL)free(s);
+ return NULL;
+ }
+
+ if(f == NULL)
+ f = fdopen(fd, mode);
+ else
+ {
+ f->fildes = fd;
+ f->pos = lseek(fd, 0, SEEK_CUR);
+ f->mode = fmode_to_desmode(mode);
+ }
+
+ if(f == NULL)
+ {
+ if(s!=NULL)free(s);
+ return NULL;
+ }
+
+ f->dev = FDEV_UNKNOWN;
+
+ if(strncmp(path, "cdrom", 5) == 0 || strncmp(path, "cdromL", 6) == 0)
+ f->dev = FDEV_CDROM;
+ else if(strncmp(path, "bu", 2) == 0)
+ f->dev = FDEV_MEMCARD;
+
+// nocash bios freezes at get_real_file_size(), due
+// to problems with firstfile()
+
+ if(s!=NULL)
+ {
+ f->size = get_real_file_size(s);
+ free(s);
+ }
+ else
+ f->size = get_real_file_size(path);
+
+ return f;
+}
+
+FILE *fopen(const char *path, const char *mode)
+{
+ return fopen_internal(path, mode, NULL);
+}
+
+int fclose(FILE *stream)
+{
+ stream->used = 0;
+ close(stream->fildes);
+ return 0;
+}
+
+/*
+ * fread doesn't require reads to be carried in block unit
+ * Notice that however seeks on the CD drive will be very slow - so avoid using non block units
+ *
+ * This is done to make programming and porting easier
+ */
+
+int fread(void *ptr, int size, int nmemb, FILE *f)
+{
+ int rsize = size * nmemb;
+ int csize = rsize;
+ int max;
+ int nsect = (f->pos + rsize) >> 11;
+ nsect -= f->pos >> 11;
+ nsect++;
+
+ //printf("f->dev = %d, f->pos = %d, rsize = %d\n", f->dev, f->pos, rsize);
+
+ if(f->dev == FDEV_CDROM)
+ {
+ // First sector
+ lseek(f->fildes, f->pos & (~0x7ff), SEEK_SET);
+ read(f->fildes, onesec_buf, 2048);
+
+ max = 2048 - (f->pos & 2047);
+
+ //printf("ptr(FIRST) = %d, %x\n", ptr, ptr);
+ printf("rsize = %d\n", rsize);
+
+ memcpy(ptr, onesec_buf + (f->pos & 2047), (rsize > max) ? max : rsize);
+
+ // Middle sector
+ ptr += max;
+
+ //printf("ptr(MIDDLEsex) = %d, %x\n", ptr, ptr);
+ nsect--;
+ csize -= max;
+
+ if(nsect > 1)
+ {
+ //lseek(f->fildes, (f->pos & (~0x7ff)) + 2048, SEEK_SET);
+
+//#warning "Check correctness of this calculation."
+
+ /*if(rsize & 2047)
+ sect_num = (rsize|2047)+1;
+ else
+ sect_num = rsize;
+
+ sect_num -= 4096;*/
+
+ //printf("read_middle=%d, sect_num = %d\n", read(f->fildes, ptr, sect_num), sect_num);
+
+ read(f->fildes, ptr, (nsect - 1) * 2048);
+
+ ptr += (nsect - 1) * 2048;
+ csize -= (nsect - 1) * 2048;
+ nsect = 1;
+ }
+
+ //printf("ptr(LAST) = %d, %x\n", ptr, ptr);
+
+ if(nsect == 1)
+ {
+ // Last sector
+ read(f->fildes, onesec_buf, 2048);
+
+ memcpy(ptr, onesec_buf, csize);
+ }
+ }
+ else if(f->dev == FDEV_CONSOLE)
+ return 0;
+
+
+ if(f->dev != FDEV_CONSOLE)
+ {
+ f->pos+= rsize;
+ f->eof = (f->pos > f->size);
+
+ if(f->eof)
+ f->pos = f->size;
+ }
+
+ return rsize;
+}
+
+int fgetc(FILE *f)
+{
+ unsigned char c;
+
+ if(f->pos >= f->size)
+ return EOF;
+
+ fread(&c, sizeof(char), 1, f);
+
+ return (int)c;
+}
+
+int ftell(FILE *f)
+{
+ return f->pos;
+}
+
+int fseek(FILE *f, int offset, int whence)
+{
+ switch(whence)
+ {
+ case SEEK_SET:
+ f->pos = offset;
+ break;
+ case SEEK_CUR:
+ f->pos+= offset;
+ break;
+ case SEEK_END:
+ f->pos = f->size + offset;
+ break;
+ default:
+ f->pos = whence + offset;
+ break;
+ }
+
+ return 0;
+}
+
+int toupper(int c)
+{
+ if(c >= 'a' && c <= 'z')
+ return (c-'a')+'A';
+
+ return c;
+}
+
+int tolower(int c)
+{
+ if(c >= 'A' && c <= 'Z')
+ return (c-'A')+'a';
+
+ return c;
+}
+
+int libc_get_transtbl_fname(const char *tofind, char *outstr, int outl)
+{
+ FILE *f;
+ int s;
+ int x;
+ int type;
+ int y;
+ int l = strlen(tofind);
+ int filename_found = 0;
+ int exit_loop = 0;
+ int otfp = 0;
+ int tfp = 0;
+ char transtbl[0x4000];
+ char orgname[16];
+ char newname[256];
+ char rootpath[256];
+
+ bzero(transtbl, 0x4000);
+ strcpy(rootpath, "cdrom:\\");
+
+ f = fopen("cdrom:\\TRANS.TBL;1", "rb");
+
+ if(f == NULL)
+ return 0;
+
+ fseek(f, 0, SEEK_END);
+ s = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ fread(transtbl, 1, s, f);
+ fclose(f);
+
+ outstr[0] = 0;
+
+ x = 0;
+
+ exit_loop = 0;
+ filename_found = 0;
+
+ for(tfp = 0; tofind[tfp] == '\\' || tofind[tfp] == '/'; tfp++);
+
+ otfp = tfp;
+
+ for(y = otfp; y < l; y++)
+ {
+ if(tofind[y] == '\0' || tofind[y] == '\\' || tofind[y] == '/')
+ break;
+ }
+
+ tfp = y;
+
+ while((x < s) && !exit_loop)
+ {
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ if(transtbl[x] == 'F')
+ type = 0;
+ else if(transtbl[x] == 'D')
+ type = 1;
+
+ x++;
+
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ y = 0;
+
+ while(!(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r'
+ || transtbl[x] == 0))
+ orgname[y++] = transtbl[x++];
+
+ orgname[y] = 0;
+ //printf("orgname = %s\n", orgname);
+
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ y = 0;
+
+ while(!(transtbl[x] == '\n' || transtbl[x] == '\r' || transtbl[x] == 0))
+ newname[y++] = transtbl[x++];
+
+ newname[y] = 0;
+
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ //printf("newname = %s\n", newname);
+
+ if(strncasecmp(&tofind[otfp], newname, tfp-otfp) == 0)
+ {
+ if(type == 0)
+ {
+ dprintf("Filename found: %s -> %s%s\n", tofind, rootpath, orgname);
+ filename_found = 1;
+ exit_loop = 1;
+
+ strncpy(outstr, rootpath, outl);
+ strncat(outstr, orgname, outl-strlen(rootpath));
+ }
+ else
+ {
+ //printf("Found directory! %s\n", newname);
+
+ //printf("tfp = %d\n", tfp);
+
+ if(tfp == l || tofind[l-1] == '/'
+ || tofind[l-1] == '\\')
+ {
+ dprintf("File not found. A directory was specified.\n");
+ exit_loop = 1;
+ continue;
+ }
+
+ //tfp++;
+ for(; tofind[tfp] == '\\' || tofind[tfp] == '/'; tfp++);
+
+ otfp = tfp;
+
+ for(y = otfp; y < l; y++)
+ {
+ if(tofind[y] == '\0' || tofind[y] == '\\' || tofind[y] == '/')
+ break;
+ }
+
+ tfp = y;
+
+ strcat(rootpath, orgname);
+ strcat(rootpath, "\\");
+
+ y = strlen(rootpath);
+ strcat(rootpath, "TRANS.TBL;1");
+
+ bzero(transtbl, 0x4000);
+
+ f = fopen(rootpath, "rb");
+
+ if(f == NULL)
+ {
+ dprintf("Couldn't find %s\n", rootpath);
+ exit_loop = 1;
+ continue;
+ }
+
+ rootpath[y] = 0;
+
+ fseek(f, 0, SEEK_END);
+ s = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ fread(transtbl, 1, s, f);
+ fclose(f);
+
+ x = 0;
+ }
+ }
+ }
+
+ return filename_found;
+}
+
+int isupper(int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+int islower(int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+int isdigit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+int isxdigit(int c)
+{
+ return ((c >= '0' && c <= '9') || (c >= 'A' && c<='F') || (c >= 'a' && c<='f'));
+}
+
+int isalpha(int c)
+{
+ return ((c>='a' && c<='z') || (c>='A' && c<='Z'));
+}
+
+int isalnum(int c)
+{
+ return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'));
+}
+
+int isspace(int c)
+{
+ return ((c == ' ') || (c == '\f') || (c == '\n') || (c == '\r') || (c == '\t') || (c == '\v'));
+}
+
+int isprint(int c)
+{
+ return (c >= 0x20) && (c <= 0x7E);
+}
+
+int isgraph(int c)
+{
+ return (c > 0x20) && (c <= 0x7E);
+}
+
+int iscntrl(int c)
+{
+ return (c < 0x20);
+}
+
+int isblank(int c)
+{
+ return ((c == ' ') || (c == '\t'));
+}
+
+void redirect_stdio_to_sio(void)
+{
+ __stdio_direction = STDIO_DIRECTION_SIO;
+}
+
+void sio_stdio_mapcr(unsigned int setting)
+{
+ __sio_cr_mapped = setting;
+}
+
+int sio_putchar(int c)
+{
+ if(c == '\n' && __sio_cr_mapped)
+ sio_putchar('\r');
+
+ while(!SIOCheckOutBuffer());
+
+ SIOSendByte(c);
+
+ return c;
+}
+
+int sio_puts(const char *str)
+{
+ while(*str)
+ sio_putchar(*(str++));
+
+ sio_putchar('\n');
+
+ return 1;
+}
+
+extern int bios_putchar(int c);
+extern int bios_puts(const char *str);
+
+int putchar(int c)
+{
+ switch(__stdio_direction)
+ {
+ case STDIO_DIRECTION_BIOS:
+ return bios_putchar(c);
+ break;
+ case STDIO_DIRECTION_SIO:
+ return sio_putchar(c);
+ break;
+ }
+
+ return EOF;
+}
+
+int puts(const char *str)
+{
+ switch(__stdio_direction)
+ {
+ case STDIO_DIRECTION_BIOS:
+ return bios_puts(str);
+ break;
+ case STDIO_DIRECTION_SIO:
+ return sio_puts(str);
+ break;
+ }
+
+ return EOF;
+}
+
+int fwrite(void *ptr, int size, int nmemb, FILE *f)
+{
+ if(IS_CONS_OUT(f)) // stdout or stderr
+ {
+ char *c = ptr;
+ int i;
+
+ for(i = 0; i < size; i++)
+ putchar(c[i]);
+
+ return size;
+ }
+
+ return 0;
+}
+
+int fputs(const char *str, FILE *stream)
+{
+ if(IS_CONS_OUT(stream))
+ return puts(str);
+
+ return EOF;
+}
+
+FILE *freopen(const char *path, const char *mode, FILE *stream)
+{
+ if(stream == NULL)
+ return NULL;
+
+ if(stream->used)
+ fclose(stream);
+
+ return fopen_internal(path, mode, stream);
+}
+
+void clearerr(FILE *stream)
+{
+ stream->eof = 0;
+ stream->error = 0;
+}
+
+int feof(FILE *stream)
+{
+ return stream->eof;
+}
+
+int ferror(FILE *stream)
+{
+ return stream->error;
+}
+
+int fileno(FILE *stream)
+{
+ return stream->fildes;
+}
diff --git a/libpsx/src/libc/error.c b/libpsx/src/libc/error.c
new file mode 100644
index 0000000..6863b2f
--- /dev/null
+++ b/libpsx/src/libc/error.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <string.h>
+
+static char strerror_not_implemented[64];
+
+char *strerror(int errnum)
+{
+ strerror_r(errnum, strerror_not_implemented, 64);
+
+ return strerror_not_implemented;
+}
+
+int strerror_r(int errnum, char *strerrbuf, size_t buflen)
+{
+ snprintf(strerrbuf, buflen,
+ "strerror(%d)", errnum);
+
+ return 0;
+}
diff --git a/libpsx/src/libc/misc.c b/libpsx/src/libc/misc.c
new file mode 100644
index 0000000..f3a1326
--- /dev/null
+++ b/libpsx/src/libc/misc.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+static unsigned int rand_seed = 0;
+static unsigned int rand_next = 0;
+
+int abs(int x)
+{
+ if(x<0)return -x;
+
+ return x;
+}
+
+void srand(unsigned int seed)
+{
+ rand_seed = seed;
+}
+
+int rand()
+{
+ rand_next = (rand_next ^ 0x98765432)*0x1357;
+
+ return rand_next % RAND_MAX;
+}
+
+static char *__ulltoa_internal__(unsigned long long value, char *str, int base, int minus_sign,
+ unsigned long long maxp )
+{
+ unsigned long long p;
+ unsigned long long p3;
+ int c;
+ int a;
+
+ p = 1;
+
+ do
+ {
+ p3 = p;
+ p *= base;
+
+ if(maxp && p > maxp)
+ break;
+ }while((p >= p3) && !(p % p3));
+
+ if(minus_sign)
+ *(str++) = '-';
+
+ for(a = 0;p3 > 0;p3/=base)
+ {
+ c = value / p3;
+ value %= p3;
+
+ if(c)
+ a = 1;
+
+ if(a)
+ {
+ if(c <= 9)
+ c += '0';
+ else
+ c = (c - 10) + 'A';
+
+ *(str++) = c;
+ }
+ }
+
+ *str = '\0';
+
+ return str;
+}
+
+char *ulltoa(unsigned long long value, char *str, int base)
+{
+ return __ulltoa_internal__(value, str, base, 0, 0);
+}
+
+char *ultoa(unsigned long value, char *str, int base)
+{
+ return __ulltoa_internal__(value, str, base, 0, (sizeof(long)==8)?0:0xFFFFFFFF);
+}
+
+char *utoa(unsigned int value, char *str, int base)
+{
+ return __ulltoa_internal__(value, str, base, 0, 0xFFFFFFFF);
+}
+
+char *lltoa(long long value, char *str, int base)
+{
+ return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, 0);
+}
+
+char *ltoa(long value, char *str, int base)
+{
+ return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, (sizeof(long)==8)?0:0xFFFFFFFF);
+}
+
+char *itoa(int value, char *str, int base)
+{
+ return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, 0xFFFFFFFF);
+}
+
+void abort(void)
+{
+ printf("abort(): Abnormal program termination\n");
+ exit(1);
+}
diff --git a/libpsx/src/libc/printf.c b/libpsx/src/libc/printf.c
new file mode 100644
index 0000000..ce8ffcd
--- /dev/null
+++ b/libpsx/src/libc/printf.c
@@ -0,0 +1,899 @@
+/*
+ * printf.c
+ *
+ * Part of the PSXSDK C library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SPRINTF_ALT_FLAG (1<<0)
+#define SPRINTF_ZERO_FLAG (1<<1)
+#define SPRINTF_NEGFIELD_FLAG (1<<2)
+#define SPRINTF_SPACE_FLAG (1<<3)
+#define SPRINTF_SIGN_FLAG (1<<4)
+
+// sprintf() macros to calculate the real padding and to write it
+// these were made to not repeat the code in the function
+// they can only be used in sprintf()
+
+// sprintf macros START
+
+#define calculate_real_padding() \
+ y = 1; \
+ \
+ for(x=0;x<=19;x++) \
+ { \
+ if(x == 0) \
+ pad_quantity--; \
+ else \
+ { \
+ if(arg / y) \
+ pad_quantity--; \
+ } \
+ \
+ y *= 10; \
+ } \
+ \
+ if(pad_quantity < 0) pad_quantity = 0;
+
+/*#define calculate_real_padding_hex() \
+ for (x = 0; x < 8; x++) \
+ { \
+ if(x == 0) \
+ pad_quantity--; \
+ else \
+ { \
+ if((arg >> (x * 4)) & 0xf) \
+ pad_quantity--; \
+ } \
+ }*/
+
+#define calculate_real_padding_hex() \
+ last = 0; \
+ for (x = 0; x < 16; x++) \
+ if((arg >> (x * 4)) & 0xf) \
+ last = x; \
+ \
+ pad_quantity = (pad_quantity - 1) - last; \
+ if(pad_quantity < 0) pad_quantity = 0;
+
+#define write_padding() \
+ if(!(flags & SPRINTF_NEGFIELD_FLAG)) \
+ for(x = 0; x < pad_quantity; x++) \
+ { \
+ if(flags & SPRINTF_ZERO_FLAG) \
+ put_in_string(string, ssz, '0', string_pos++); \
+ else \
+ put_in_string(string, ssz, ' ', string_pos++); \
+ }
+
+#define write_neg_padding() \
+ if(flags & SPRINTF_NEGFIELD_FLAG) \
+ { \
+ for(x = 0; x < pad_quantity; x++) \
+ put_in_string(string, ssz, ' ', string_pos++);\
+ }
+
+// sprintf macros END
+
+enum
+{
+ SPRINTF_SIZE_CHAR,
+ SPRINTF_SIZE_SHORT,
+ SPRINTF_SIZE_INT,
+ SPRINTF_SIZE_LONG,
+ SPRINTF_SIZE_LONG_LONG,
+};
+
+static unsigned int get_arg_in_size(int size, unsigned long long *arg, unsigned int check_sign)
+{
+ int s = 0;
+
+ switch(size)
+ {
+ case SPRINTF_SIZE_CHAR:
+ *arg &= 0xff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<7))
+ {
+ *arg |= 0xffffff00;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+ case SPRINTF_SIZE_SHORT:
+ *arg &= 0xffff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<15))
+ {
+ *arg |= 0xffff0000;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+
+// sizeof(long) == sizeof(int) on 32bit, so this will suffice for the psx
+
+ case SPRINTF_SIZE_INT:
+ case SPRINTF_SIZE_LONG:
+ *arg &= 0xffffffff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<31))
+ {
+ *arg |= (long long)0xffffffff00000000;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+
+ case SPRINTF_SIZE_LONG_LONG:
+ if(check_sign)
+ {
+ if(*arg & ((long long)1<<63))
+ {
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+ }
+
+ return s;
+}
+
+static int libc_ulltoa(unsigned long long i, char *dst, int n, int nopad)
+{
+ int x, y;
+ unsigned long long a, b;
+ int empty_digit = 1;
+ int sp=0;
+ int n2=0;
+
+ if(n<=0)
+ return 0;
+
+ for(x=18;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+ b = (i/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0 || nopad == 1)
+ {
+ i -= b*a;
+
+ //put_in_string(string, ssz, b + '0', string_pos++);
+ if(n2!=(n-1))
+ {
+ //printf("n2=%d\n",n2);
+ dst[sp++] = b + '0';
+ n2++;
+ }
+ }
+ }
+
+ dst[sp] = 0;
+
+ return n2;
+}
+
+/*static void libc_float_to_string(float fl, char *dst, int n)
+{
+ unsigned int *p = (unsigned int*)&fl;
+ unsigned long long i = 0;
+ unsigned long long f = 0;
+ int e, m, s;
+ int x, y;
+ unsigned long long z;
+
+ s = *p >> 31;
+
+ e = (*p >> 23) & 0xff;
+
+ m = *p & 0x7fffff;
+
+ if(e == 255 && m == 0) // Infinity
+ {
+ if(s) strncpy(dst, "-inf", n);
+ else strncpy(dst, "inf", n);
+ }else if(e == 255 && m != 0) // NaN
+ {
+ strncpy(dst, "nan", n);
+ }
+ else
+ {
+ e -= 127;
+ m |= 1<<23;
+
+
+
+ for(x = 23; x >= 0; x--)
+ {
+ if(m & (1<<x))
+ {
+ if(e >= 0)
+ {
+ z = 1;
+ for(y=0;y<e;y++)
+ z*=2;
+
+ i+=z;
+ }
+ else
+ {
+ z = 5000000000000000000;
+ for(y = 1; y < -e; y++)
+ z /= 2;
+
+ f+=z;
+ }
+ }
+ e--;
+ }
+
+ if(s && (n>0))
+ {
+ *(dst++) = '-';
+ n--;
+ }
+
+ x = libc_ulltoa(i, dst, n, 0);
+ n-=x+1;
+ dst+=x;
+
+ if(n>0)
+ {
+ *(dst++) = '.';
+ n--;
+ if(n>0)
+ {
+ x = libc_ulltoa(f, dst, n<6?n:6, 1);
+ n-=x;
+ dst+=x;
+
+ if(n>0)
+ *dst=0;
+ }
+ }
+ }
+}*/
+
+static void libc_double_to_string(double fl, char *dst, int n, int prec)
+{
+ unsigned long long *p = (unsigned long long *)&fl;
+ unsigned long long i = 0;
+ unsigned long long f = 0;
+ unsigned long long m, s;
+ long long e;
+ int x;
+ unsigned long long z;
+
+ s = *p >> 63;
+
+ e = (*p >> 52) & 0x7ff;
+ //printf("%d\n", e);
+
+ m = *p & 0xfffffffffffff;
+
+ for(x=0;x<52;x++)
+ if(m&((unsigned long long)1<<(52-x))) putchar('1'); else putchar('0');
+
+ if(e == 255 && m == 0) // Infinity
+ {
+ if(s) strncpy(dst, "-inf", n);
+ else strncpy(dst, "inf", n);
+ }else if(e == 255 && m != 0) // NaN
+ {
+ strncpy(dst, "nan", n);
+ }
+ else
+ {
+ e -= 1023;
+ m |= (unsigned long long)1<<52;
+
+ for(x = 52; x >= 0; x--)
+ {
+ if(m & ((unsigned long long)1<<x))
+ {
+ if(e >= 0)
+ {
+ z = (long long)1<<e;
+
+ i+=z;
+ }
+ else
+ {
+ z = 5000000000000000000;
+ z >>= -(e + 1);
+
+ f+=z;
+ }
+ }
+ e--;
+ }
+
+ if(s && (n>0))
+ {
+ *(dst++) = '-';
+ n--;
+ }
+
+ x = libc_ulltoa(i, dst, n, 0);
+ n-=x+1;
+ dst+=x;
+
+ dprintf("N = %d\n", n);
+
+ if(n>0)
+ {
+ *(dst++) = '.';
+
+ if(n>0)
+ libc_ulltoa(f, dst, (n<(prec+1))?n:(prec+1), 1);
+ }
+ }
+}
+
+static char libc_sprintf_floatbuf[64];
+
+static int __vsnprintf_internal(char *string, size_t size, const char *fmt, va_list ap, int (put_in_string(char *string, unsigned int sz, char c, int pos)))
+{
+ int string_pos,fmt_pos;
+ int l;
+ unsigned long long arg;
+ char *argcp;
+ char *argcp_tmp;
+ int directive_coming = 0;
+ int flags = 0;
+ int argsize = 2; // int
+ int x, y;
+ unsigned long long a, b;
+ int empty_digit;
+ int ssz = size - 1;
+ int zero_flag_imp = 0;
+ int pad_quantity = 0;
+ int pad_quantity_f = -1;
+ int last;
+
+ if(size == 0)
+ ssz = 0;
+
+ l = strlen(fmt);
+
+ string_pos = 0;
+
+ for(fmt_pos=0;fmt_pos<l;fmt_pos++)
+ {
+ if(directive_coming)
+ {
+ switch(fmt[fmt_pos])
+ {
+ case '%':
+ put_in_string(string, ssz, '%', string_pos++);
+ directive_coming = 0;
+ break;
+ case ' ':
+ flags |= SPRINTF_SPACE_FLAG;
+ break;
+ case '#': // Specify alternate form
+ flags |= SPRINTF_ALT_FLAG;
+ break;
+ case '+': // Specify sign in signed conversions
+ flags |= SPRINTF_SIGN_FLAG;
+ break;
+ case '0': // Padding with zeros...
+ if(zero_flag_imp == 0)
+ {
+ flags |= SPRINTF_ZERO_FLAG;
+ zero_flag_imp = 1;
+ //printf("Zero padding enabled!\n");
+ }
+ else
+ {
+ pad_quantity *= 10;
+ //printf("pad_quantity = %d\n", pad_quantity);
+ }
+ break;
+ case '1' ... '9': // '...' cases are a GNU extension,
+ // but they simplify a lot
+
+ pad_quantity *= 10;
+ pad_quantity += fmt[fmt_pos] - '0';
+ zero_flag_imp = 1;
+
+ //printf("pad_quantity = %d\n", pad_quantity);
+ break;
+ case '-': // Negative field flag
+ if(flags & SPRINTF_ZERO_FLAG)
+ flags &= ~SPRINTF_ZERO_FLAG;
+
+ flags |= SPRINTF_NEGFIELD_FLAG;
+ break;
+ case '.': // Floating point precision
+ pad_quantity_f = pad_quantity;
+ pad_quantity = 0;
+ break;
+ case 'h': // Half argument size
+ if(argsize) argsize--;
+ break;
+ case 'l': // Double argument size
+ if(argsize < 2) argsize = 2;
+ else if(argsize < SPRINTF_SIZE_LONG_LONG) argsize++;
+ break;
+
+// 'j', 't', 'z', 'q' added 2013-10-26 by nextvolume
+
+ case 'j': // Maximum integer size
+ argsize = SPRINTF_SIZE_LONG_LONG;
+ break;
+
+ case 't': // Size of ptrdiff_t (i.e. long on 32-bit, long long on 64-bit)
+ argsize = (sizeof(void*)==8)?
+ SPRINTF_SIZE_LONG_LONG:SPRINTF_SIZE_LONG;
+ break;
+
+ case 'z': // Size of size_t (int)
+ argsize = SPRINTF_SIZE_INT;
+ break;
+
+ case 'q': // Size of quad_t
+ argsize = SPRINTF_SIZE_LONG_LONG;
+ break;
+
+ case 'd': // signed decimal
+ case 'i':
+ empty_digit = 1;
+
+ //printf("argsize = %d\n", argsize);
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ if(flags & SPRINTF_SPACE_FLAG)
+ put_in_string(string, ssz, ' ', string_pos++);
+
+ if(get_arg_in_size(argsize, &arg, 1))
+ {
+ put_in_string(string, ssz, '-', string_pos++);
+ pad_quantity--;
+ }
+ else
+ {
+ if(flags & SPRINTF_SIGN_FLAG)
+ {
+ put_in_string(string, ssz, '+', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ /* Calculate how much padding we have to write */
+
+ /*y = 1;
+
+ for(x=0;x<=9;x++)
+ {
+ if(x == 0)
+ pad_quantity--;
+ else
+ {
+ if(arg / y)
+ pad_quantity--;
+ }
+
+ y *= 10;
+ }
+ if(pad_quantity < 0) pad_quantity = 0;*/
+
+ calculate_real_padding();
+
+ //printf("Actual pad quantity = %d\n", pad_quantity);
+
+
+
+ /*if(!(flags & SPRINTF_NEGFIELD_FLAG))
+ {
+ for(x = 0; x < pad_quantity; x++)
+ {
+ if(flags & SPRINTF_ZERO_FLAG)
+ put_in_string(string, ssz, '0', string_pos++);
+ else
+ put_in_string(string, ssz, ' ', string_pos++);
+ }
+ }*/
+
+ write_padding();
+
+ for(x=19;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+ b = (arg/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ arg -= b*a;
+
+ put_in_string(string, ssz, b + '0', string_pos++);
+ }
+ }
+
+ /*if(flags & SPRINTF_NEGFIELD_FLAG)
+ {
+ for(x = 0; x < pad_quantity; x++)
+ put_in_string(string, ssz, ' ', string_pos++);
+ }*/
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'u': // unsigned decimal
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ get_arg_in_size(argsize, &arg, 0);
+
+ calculate_real_padding();
+ write_padding();
+
+ for(x=19;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+
+
+ b = (arg/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ arg -= b*a;
+
+ put_in_string(string, ssz, b + '0', string_pos++);
+ }
+ }
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'x': // Hexadecimal
+ case 'X': // Hexadecimal with big letters
+ case 'p': // Hexadecimal with small letters with '0x' prefix
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long int);
+
+ get_arg_in_size(argsize, &arg, 0);
+
+ if(fmt_pos == 'p')
+ flags |= SPRINTF_ALT_FLAG;
+
+ if(flags & SPRINTF_ALT_FLAG)
+ {
+ put_in_string(string, ssz, '0', string_pos++);
+
+ if(fmt[fmt_pos] == 'X')
+ put_in_string(string, ssz, 'X', string_pos++);
+ else
+ put_in_string(string, ssz, 'x', string_pos++);
+ }
+
+ calculate_real_padding_hex();
+ write_padding();
+
+ for(x=15;x>=0;x--)
+ {
+ y = arg >> (x << 2);
+ y &= 0xf;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ if(y>=0 && y<=9)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ else if(y>=0xA && y<=0xF)
+ {
+ if(fmt[fmt_pos] == 'X')
+ put_in_string(string, ssz, (y - 0xa) + 'A', string_pos++);
+ else
+ put_in_string(string, ssz, (y - 0xa) + 'a', string_pos++);
+ }
+ }
+ }
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'c': // character
+ arg = va_arg(ap, int);
+
+ put_in_string(string, ssz, arg & 0xff, string_pos++);
+
+ directive_coming = 0;
+ break;
+ case 's': // string
+ argcp = va_arg(ap, char *);
+ argcp_tmp = argcp;
+
+ if(argcp == NULL)
+ {
+ // Non standard extension, but supported by Linux and the BSDs.
+
+ put_in_string(string, ssz, '(', string_pos++);
+ put_in_string(string, ssz, 'n', string_pos++);
+ put_in_string(string, ssz, 'u', string_pos++);
+ put_in_string(string, ssz, 'l', string_pos++);
+ put_in_string(string, ssz, 'l', string_pos++);
+ put_in_string(string, ssz, ')', string_pos++);
+
+ directive_coming = 0;
+ break;
+ }
+
+ while(*argcp_tmp)
+ {
+ if(pad_quantity > 0) pad_quantity--;
+ argcp_tmp++;
+ }
+
+ if(!(flags & SPRINTF_NEGFIELD_FLAG))
+ {
+ while(pad_quantity > 0)
+ {
+ put_in_string(string,ssz, ' ', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ while(*argcp)
+ {
+ put_in_string(string, ssz, *argcp, string_pos++);
+
+ argcp++;
+ }
+
+ if(flags & SPRINTF_NEGFIELD_FLAG)
+ {
+ while(pad_quantity > 0)
+ {
+ put_in_string(string,ssz, ' ', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ directive_coming = 0;
+ break;
+ case 'o': // Octal
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ for(x=21;x>=0;x--)
+ {
+ y = arg >> (x * 3);
+ y &= 0x7;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ }
+
+ directive_coming = 0;
+ break;
+ case '@': // Binary
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ for(x=63;x>=0;x--)
+ {
+ y = (arg >> x);
+ y &= 1;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ }
+
+ directive_coming = 0;
+ break;
+
+ case 'f':
+ if(pad_quantity_f == -1)
+ pad_quantity_f = 6;
+ else
+ {
+ x = pad_quantity_f;
+ pad_quantity_f = pad_quantity;
+ pad_quantity = x;
+ }
+
+ dprintf("PRECISION = %d\n", pad_quantity_f);
+
+ libc_double_to_string(va_arg(ap, double), libc_sprintf_floatbuf, 64, pad_quantity_f);
+
+ // calculate padding
+ pad_quantity -= strlen(libc_sprintf_floatbuf);
+
+ write_padding();
+
+ for(x=0;libc_sprintf_floatbuf[x]!=0;x++)
+ put_in_string(string, ssz, libc_sprintf_floatbuf[x], string_pos++);
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'n': // Number of characters written
+ *(va_arg(ap,unsigned int*)) = string_pos;
+
+ directive_coming = 0;
+ break;
+
+ default:
+ put_in_string(string, ssz, fmt[fmt_pos], string_pos++);
+ directive_coming = 0;
+ }
+ }
+ else
+ {
+ if(fmt[fmt_pos] == '%')
+ {
+ directive_coming = 1;
+ flags = 0;
+ argsize = 2;
+ pad_quantity = 0;
+ pad_quantity_f = -1;
+ zero_flag_imp = 0;
+ }
+ else
+ {
+ put_in_string(string, ssz, fmt[fmt_pos], string_pos++);
+ }
+ }
+ }
+
+ /*if(((size-1) < string_pos) && (size>0))
+ string[size - 1] = 0;
+ else
+ string[string_pos] = 0;*/
+ put_in_string(string, ssz, '\0', string_pos);
+
+ return string_pos;
+}
+
+static int vsnprintf_put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ if(pos>=sz)
+ return 0;
+ else
+ string[pos] = c;
+
+ return 1;
+}
+
+int vsnprintf(char *string, size_t size, const char *fmt, va_list ap)
+{
+ return __vsnprintf_internal(string, size, fmt, ap, vsnprintf_put_in_string);
+}
+
+static int sio_put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ sio_putchar(c);
+
+ return 1;
+}
+
+int sio_vprintf(const char *fmt, va_list ap)
+{
+ return __vsnprintf_internal(NULL, -1, fmt, ap, sio_put_in_string);
+}
+
+static int out_put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ putchar(c);
+
+ return 1;
+}
+
+int vprintf(char *fmt, va_list ap)
+{
+ return __vsnprintf_internal(NULL, -1, fmt, ap, out_put_in_string);
+}
+
+int vsprintf(char *string, const char *fmt, va_list ap)
+{
+ return vsnprintf(string, 0xffffffff, fmt, ap);
+}
+
+int sprintf(char *string, const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = vsprintf(string, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
+
+int snprintf(char *string, size_t size, const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = vsnprintf(string, size, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
+
+int sio_printf(const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = sio_vprintf(fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
diff --git a/libpsx/src/libc/qsort.c b/libpsx/src/libc/qsort.c
new file mode 100644
index 0000000..0cb1d24
--- /dev/null
+++ b/libpsx/src/libc/qsort.c
@@ -0,0 +1,65 @@
+// quickSort
+//
+// This public-domain C implementation by Darel Rex Finley.
+//
+// Modified by Giuseppe Gatta
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+ #define QSORT_MAX_LEVELS 300
+
+
+ int beg[QSORT_MAX_LEVELS], end[QSORT_MAX_LEVELS], i=0, L, R, swap ;
+ char piv[size];
+
+ beg[0]=0; end[0]=nmemb;
+
+ while (i>=0)
+ {
+ L=beg[i]; R=end[i]-1;
+
+ if (L<R)
+ {
+ memcpy(piv, base + (size * L), size);
+
+ while (L<R)
+ {
+ while(compar(base + (R*size), piv) > 0 && L<R) R--;
+
+ if (L<R)
+ {
+ memcpy(base + (size *L), base + (size * R), size);
+ L++;
+ }
+
+ while(compar(base + (L*size), piv) <= 0 && L<R) L++;
+
+ if (L<R)
+ {
+ memcpy(base + (size *R), base + (size * L), size);
+ R--;
+ }
+ }
+
+ memcpy(base + (size*L), piv, size);
+
+ beg[i+1]=L+1;
+ end[i+1]=end[i];
+ end[i++]=L;
+
+ if (end[i]-beg[i]>end[i-1]-beg[i-1])
+ {
+ swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap;
+ swap=end[i]; end[i]=end[i-1]; end[i-1]=swap;
+ }
+ }
+ else
+ {
+ i--;
+ }
+ }
+}
diff --git a/libpsx/src/libc/scanf.c b/libpsx/src/libc/scanf.c
new file mode 100644
index 0000000..d419030
--- /dev/null
+++ b/libpsx/src/libc/scanf.c
@@ -0,0 +1,425 @@
+// vsscanf
+// Programmed by Giuseppe Gatta, 2011
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+char libc_vsscanf_buf[512];
+char libc_vsscanf_allow[256];
+
+enum
+{
+ elem_skip_space = 1,
+};
+
+int libc_vsscanf_get_element(char *dst, const char *src, int flag, int s)
+{
+ int i;
+ const char *osrc = src;
+
+ if(flag & elem_skip_space)
+ {
+ while(*src == ' ')
+ src++;
+ }
+
+ for(i=0;i<s;i++)
+ {
+ if((flag & elem_skip_space) && *src == ' ')
+ break;
+
+ if(*src != 0)
+ *(dst++) = *(src++);
+ else
+ break;
+ }
+
+ *dst = 0;
+
+ return src - osrc;
+}
+
+enum
+{
+ scanf_s_char, scanf_s_short, scanf_s_int,
+ scanf_s_long,
+ scanf_s_long_long
+};
+
+int vsscanf(const char *str, const char *format, va_list ap)
+{
+ int fp = 0;
+ int sp = 0;
+ int conv = 0;
+ int sz = scanf_s_int; // size for numbers defaults to 32-bit
+ int i,x,y,z;// h;
+ int suppress = 0;
+// int neg = 0;
+ int fsz = 512;
+ int def_fsz = 1;
+ int exspace = 0;
+// int alt = 0;
+ int r = 0;
+ int exit_loop=0;
+ char *ep;
+ long long buf;
+ double fbuf;
+
+
+ while(format[fp] && str[sp] && !exit_loop)
+ {
+ if(conv)
+ {
+ switch(format[fp])
+ {
+ case '%': // Percent, assignment does not occur
+ conv = 0;
+ break;
+
+ case 'h': // Halve size
+ sz--;
+ break;
+
+ case 'l': // Double size
+ sz++;
+ break;
+
+ case '*': // Suppress
+ suppress = 1;
+ break;
+
+ case ' ': // Explicit space
+ exspace = 1;
+ break;
+
+ case '#': // Alternate format
+ //alt = 1;
+ break;
+
+ case '0' ... '9': // '0' ... '9' is a GNU C extension!
+ if(def_fsz)
+ {
+ def_fsz = 0;
+ fsz = 0;
+ }
+
+ fsz *= 10;
+ fsz+=format[fp]-'0';
+
+ if(fsz > 512)
+ fsz = 512; // 512 is the maximum.
+ break;
+
+ case '@': // Binary. Non-standard extension
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 2);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'D':
+ sz++;
+ case 'd': // Decimal
+ case 'u':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 10);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 's': // String
+ sp += libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+
+ if(!suppress)
+ {
+ strcpy(va_arg(ap, char*), libc_vsscanf_buf);
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'c':
+ if(def_fsz)
+ fsz = 1;
+
+ sp += (i = libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], (exspace ? elem_skip_space : 0), fsz));
+ if(!suppress)
+ {
+ memcpy(va_arg(ap, char*), libc_vsscanf_buf, (fsz>i)?i:fsz);
+ r++;
+ }
+ break;
+
+ case 'n':
+ if(!suppress)
+ {
+ *(va_arg(ap, int*)) = sp;
+ r++;
+ }
+ break;
+
+ case 'p':
+ case 'x':
+ case 'X':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 16);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf; break;
+ case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break;
+ case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf; break;
+ case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'O':
+ sz++;
+ case 'o': // Octal integer
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 8);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf;break;
+ case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break;
+ case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf;break;
+ case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf;break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'i':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+
+ if(libc_vsscanf_buf[0] == '0')
+ {
+ if(libc_vsscanf_buf[1] == 'x' || libc_vsscanf_buf[1] == 'X')
+ i = 16;
+ else
+ i = 8;
+ }
+ else
+ i = 10;
+
+ buf = strtoll(libc_vsscanf_buf, &ep, i);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf; break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = (long long)buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case '[':
+ i=0;
+ x=0; // Exclusion?
+ //h=0; // Hyphen?
+
+ fp++;
+ i++;
+
+ while(format[fp])
+ {
+ if(format[fp] == '^' && i==1)
+ {
+ memset(libc_vsscanf_allow, 1, 256);
+ x = 1;
+ fp++; i++; continue;
+ }
+
+ if(x)
+ {
+ if(format[fp] == ']' && i>=3)
+ break;
+ }
+ else
+ {
+ if(format[fp] == ']' && i>=2)
+ break;
+ }
+
+ if(format[fp] == '-')
+ {
+ if(format[fp+1] != ']')
+ y = 1;
+ else
+ libc_vsscanf_allow['-'] = x^1;
+ }
+ else
+ {
+ if(y == 1)
+ {
+ if(format[fp] < format[fp-2])
+ libc_vsscanf_allow[(unsigned char)format[fp]] = x^1;
+ else
+ for(z = format[fp-2]; z <= format[fp]; z++)
+ libc_vsscanf_allow[z] = x^1;
+
+ y = 0;
+
+ //printf("%s all chars from %c to %c\n", x?"Excluding":"Including",format[fp-2], format[fp]);
+ }
+ else
+ libc_vsscanf_allow[(unsigned char)format[fp]] = x^1;
+ }
+
+ fp++;
+ i++;
+ }
+
+// Now as we know what our character set is, let's get data from the string
+ /* puts("Character set:");
+
+ for(y=0;y<16;y++)
+ {
+ for(x=0;x<16;x++)
+ if(libc_vsscanf_allow[(y*16) + x])
+ putchar((y*16)+x);
+ else
+ putchar('*');
+
+ putchar('\n');
+ }
+ */
+ i = 0;
+
+ while(libc_vsscanf_allow[(unsigned char)str[sp]] && i<512)
+ libc_vsscanf_buf[i++] = str[sp++];
+
+ libc_vsscanf_buf[i] = 0;
+
+ if(!suppress)
+ {
+ strcpy(va_arg(ap, char*), libc_vsscanf_buf);
+ r++;
+ }
+ break;
+
+ case 'f': // Floating point number
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ fbuf = strtod(libc_vsscanf_buf, &ep);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char:
+ case scanf_s_short:
+ case scanf_s_int:
+ *(va_arg(ap, float*)) = (float)fbuf;
+ break;
+
+ case scanf_s_long:
+ case scanf_s_long_long:
+ *(va_arg(ap, double*)) = fbuf;
+ break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ }
+ }
+ else
+ {
+ if(format[fp] == '%')
+ {
+ // conv = 1;
+ // neg = 0;
+ suppress = 0;
+ sz = scanf_s_int;
+ fsz = 512;
+ def_fsz = 1;
+ exspace = 0;
+ // alt = 0;
+ bzero(libc_vsscanf_allow, 256);
+ //chset = 0;
+ }
+ else if(format[fp] != ' ')
+ {
+ if(format[fp] != str[sp])
+ exit_loop=1;
+
+ sp++;
+ }
+
+ }
+
+ fp++;
+ }
+
+ return r;
+}
+
+int sscanf(const char *str, const char *fmt, ...)
+{
+ int r;
+ va_list ap;
+
+ va_start(ap, fmt);
+ r = vsscanf(str, fmt, ap);
+
+ va_end(ap);
+ return r;
+}
diff --git a/libpsx/src/libc/stat.c b/libpsx/src/libc/stat.c
new file mode 100644
index 0000000..1c43b92
--- /dev/null
+++ b/libpsx/src/libc/stat.c
@@ -0,0 +1,31 @@
+#include <psx.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+int stat(const char *path, struct stat *sb)
+{
+ struct DIRENTRY dir_e;
+
+ if(firstfile((char*)path, &dir_e) == NULL)
+ return -1;
+
+ sb->st_size = dir_e.size;
+
+ if(strncmp(path, "cdrom:", 6) == 0)
+ sb->st_blksize = 2048;
+ else if(strncmp(path, "bu00:", 5) == 0 ||
+ strncmp(path, "bu10:", 5) == 0)
+ sb->st_blksize = 128;
+ else
+// not a real blocksize, will be there just as a placeholder
+ sb->st_blksize = 1024;
+
+ sb->st_blocks =
+ sb->st_size / sb->st_blksize;
+
+ if(sb->st_size % sb->st_blksize)
+ sb->st_blocks++;
+
+ return 0;
+}
diff --git a/libpsx/src/libc/string.c b/libpsx/src/libc/string.c
new file mode 100644
index 0000000..ea59b91
--- /dev/null
+++ b/libpsx/src/libc/string.c
@@ -0,0 +1,706 @@
+/*
+ * string.c
+ *
+ * Part of the PSXSDK C library
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+ void *dst2 = dst;
+
+ while(len--)
+ *(((unsigned char*)dst++)) = *(((unsigned char*)src++));
+
+ return dst2;
+}
+
+void *memccpy(void *dst, const void *src, int c, size_t len)
+{
+ unsigned char c2;
+
+ while(len--)
+ {
+ *(((unsigned char*)dst++)) = ( c2 = *(((unsigned char*)src++)) );
+
+ if(c2 == c)
+ return (void*)src;
+ }
+
+ return NULL;
+}
+
+void *memset(void *dst , char c , size_t n)
+{
+ unsigned char *dstc = (unsigned char*)dst;
+ int x;
+
+ for(x = 0; x < n; x++)
+ dstc[x] = c;
+
+ return dst;
+}
+
+int memcmp(const void *b1, const void *b2, size_t n)
+{
+ int x;
+ unsigned char *bp1 = (unsigned char*)b1;
+ unsigned char *bp2 = (unsigned char*)b2;
+
+ for(x = 0; x < n; x++)
+ if(bp1[x] != bp2[x])
+ return (bp1[x] - bp2[x]);
+
+ return 0;
+}
+
+void *memmove(void *dst, const void *src, size_t len)
+{
+ void *dst2 = dst;
+
+ dst+=len-1;
+ src+=len-1;
+
+ while(len--)
+ *(((unsigned char*)dst--)) = *(((unsigned char*)src--));
+
+ return dst2;
+}
+
+void *memchr(void *s , int c , size_t n)
+{
+ while(n--)
+ {
+ if(*((unsigned char*)s) == (unsigned char)c)
+ return s;
+
+ s++;
+ }
+
+ return NULL;
+}
+
+char *strncpy(char *dst, const char *src, size_t len)
+{
+ char *odst=dst;
+
+ while(*src && len)
+ {
+ *(dst++) = *(src++);
+ len--;
+ }
+
+ if(len)*dst = 0;
+
+ return odst;
+}
+
+char *strcpy(char *dst, const char *src)
+{
+ char *odst = dst;
+
+ while((*(dst++) = *(src++)));
+ return odst;
+}
+
+int strlen(const char *str)
+{
+ int i = 0;
+ while(*(str++))i++;
+ return i;
+}
+
+char *strchr(const char *s, int c)
+{
+ int x;
+ int l = strlen(s);
+
+ for(x = 0; x <= l; x++)
+ if(s[x] == c) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strrchr(const char *s, int c)
+{
+ int x;
+ int l = strlen(s);
+
+ for(x = l; x>=0; x--)
+ if(s[x] == c) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strpbrk(const char *s, const char *charset)
+{
+ int x,y;
+
+ for(x = 0; s[x] != 0; x++)
+ for(y = 0; charset[y] != 0; y++)
+ if(s[x] == charset[y]) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strstr(const char *big, const char *little)
+{
+ int ls = strlen(little);
+ int bs = strlen(big);
+ int x;
+
+ if(ls == 0)
+ return (char*)big;
+
+ if(ls > bs)
+ return NULL;
+
+ for(x = 0; x <= bs-ls; x++)
+ if(memcmp(little, &big[x], ls) == 0)
+ return (char*)&big[x];
+
+ return NULL;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+ while(*s1 && *s2 && (*s1 == *s2))
+ {
+ s1++;
+ s2++;
+ }
+
+ return *s1-*s2;
+}
+
+int strncmp(const char *s1, const char *s2, size_t len)
+{
+ int p = 0;
+
+ while(*s1 && *s2 && (*s1 == *s2) && p<len)
+ {
+ p++;
+
+ if(p<len)
+ {
+ s1++;
+ s2++;
+ }
+ }
+
+ return *s1-*s2;
+}
+
+int strcoll(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2);
+}
+
+char *strdup(const char *str)
+{
+ char *ns = (void*)malloc(strlen(str) + 1);
+
+ if(ns == NULL)
+ return NULL;
+
+ strcpy(ns, str);
+ return ns;
+}
+
+char *strndup(const char *str, size_t len)
+{
+ int n=strlen(str);
+ char *ns = (void*)malloc((n+1)>len?len:(n+1));
+
+ if(ns == NULL)
+ return NULL;
+
+ strncpy(ns, str, (n+1)>len?len:(n+1));
+ return ns;
+}
+
+long long strtoll(const char *nptr, char **endptr, int base)
+{
+ int r = 0;
+ int t = 0;
+ int n = 0;
+
+ while(*nptr && isspace(*nptr))
+ nptr++;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ n = 1;
+ }
+
+ if(base == 0)
+ {
+ if(*nptr == '0')
+ base = 8;
+ else
+ base = 10;
+ }
+
+ if(!(base >= 2 && base <= 36))
+ return 0;
+
+ if(base == 16 && *nptr == '0')
+ {
+ if(*(nptr+1) == 'x' || *(nptr+1) == 'X')
+ nptr+=2;
+ }
+
+ while(*nptr)
+ {
+ switch(*nptr)
+ {
+ case '0'...'9':
+ t = *nptr - '0';
+ break;
+ case 'a' ... 'z':
+ t = (*nptr - 'a') + 10;
+ break;
+ case 'A' ... 'Z':
+ t = (*nptr - 'A') + 10;
+ break;
+ default:
+ t = 1000;
+ break;
+ }
+
+ if(t>=base)
+ break;
+
+ r*=base;
+ r+=t;
+ nptr++;
+ }
+
+ if(endptr)*endptr = (char*)nptr;
+ return n?-r:r;
+}
+
+long strtol(const char *nptr, char **endptr, int base)
+{
+ return (long)strtoll(nptr, endptr, base);
+}
+
+double strtod(const char *nptr, char **endptr)
+{
+ char strbuf[64];
+ int x = 0;
+ int y;
+ double i=0, d=0;
+ int s=1;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ s=-1;
+ }
+
+ while(*nptr >= '0' && *nptr <= '9' && x < 18)
+ strbuf[x++] = *(nptr++);
+
+ strbuf[x] = 0;
+
+ i = (double)strtoll(strbuf, NULL, 10);
+
+ if(*nptr == '.')
+ {
+ nptr++;
+ x = 0;
+
+ while(*nptr >= '0' && *nptr <= '9' && x < 7)
+ strbuf[x++] = *(nptr++);
+
+ strbuf[x] = 0;
+
+ if(endptr != NULL) *endptr = (char*)nptr;
+
+ y=1;
+
+ for(x=0;strbuf[x]!=0;x++)
+ y*=10;
+
+ d = (double)strtoll(strbuf, NULL, 10);
+ d /= y;
+ }
+ else
+ {
+ if(endptr != NULL)
+ *endptr = (char*)nptr;
+ }
+
+ return (i + d)*s;
+}
+
+long double strtold(const char *nptr, char **endptr)
+{
+ return (long double)strtod(nptr, endptr);
+}
+
+float strtof(const char *nptr, char **endptr)
+{
+ return (float)strtod(nptr, endptr);
+}
+
+char *strcat(char *s, const char *append)
+{
+ strcpy(&s[strlen(s)], append);
+
+ return s;
+}
+
+char *strncat(char *s, const char *append, size_t count)
+{
+ strncpy(&s[strlen(s)], append, count);
+
+ return s;
+}
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ while(tolower(*s1) && tolower(*s2) && (tolower(*s1) == tolower(*s2)))
+ {
+ s1++;
+ s2++;
+ }
+
+ return tolower(*s1)-tolower(*s2);
+}
+
+int strncasecmp(const char *s1, const char *s2, size_t len)
+{
+ int p = 0;
+
+ while(tolower(*s1) && tolower(*s2) && (tolower(*s1) == tolower(*s2)) && p<len)
+ {
+ p++;
+
+ if(p<len)
+ {
+ s1++;
+ s2++;
+ }
+ }
+
+ return tolower(*s1)-tolower(*s2);
+}
+
+int stricmp(const char *s1, const char *s2)
+{
+ return strcasecmp(s1,s2);
+}
+
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+ return strncasecmp(s1, s2, len);
+}
+
+//static char *strtok_string;
+
+char *strsep(char **stringp, const char *delim)
+{
+ //int x,y;
+ char *old = *stringp;
+ const char *s;
+ int ok = 0;
+
+ while(**stringp && !ok)
+ {
+ s = delim;
+
+ while(*delim)
+ {
+ if(**stringp == *delim)
+ {
+ **stringp = 0;
+ ok = 1;
+ break;
+ }
+
+ delim++;
+ }
+
+ delim = s;
+
+ *stringp+=1;
+ }
+
+ if(!ok)*stringp = NULL;
+
+ return old;
+}
+
+char *strtok(char *str, const char *sep)
+{
+ int x, y;
+ static char *strtok_string;
+ static int strtok_len;
+ static int strtok_pos;
+ //int strtok_oldpos = 0;
+
+ if(str != NULL)
+ {
+ strtok_string = str;
+ strtok_len = strlen(str);
+
+ for(x = 0; x < strtok_len; x++)
+ {
+ for(y = 0; sep[y] != 0; y++)
+ {
+ if(strtok_string[x] == sep[y])
+ {
+ strtok_string[x] = 0;
+ break;
+ }
+ }
+ }
+
+ strtok_pos = 0;
+
+ while(strtok_pos < strtok_len)
+ {
+ if(strtok_string[strtok_pos])
+ return &strtok_string[strtok_pos];
+
+ strtok_pos++;
+ }
+ }
+
+ while(strtok_pos < strtok_len)
+ {
+ if(!strtok_string[strtok_pos])
+ {
+ strtok_pos++;
+ break;
+ }
+
+ strtok_pos++;
+ }
+
+ while(strtok_pos < strtok_len)
+ {
+
+ if(strtok_string[strtok_pos])
+ return &strtok_string[strtok_pos];
+
+ strtok_pos++;
+ }
+
+ return NULL;
+}
+
+int strspn(const char *s, const char *charset)
+{
+ int x, y;
+ int appears;
+
+ for(x = 0; s[x] != 0; x++)
+ {
+ appears = 0;
+
+ for(y = 0; charset[y] != 0; y++)
+ {
+ if(s[x] == charset[y])
+ {
+ appears = 1;
+ break;
+ }
+ }
+
+ if(!appears)break;
+ }
+
+ return x;
+}
+
+int strcspn(const char *s, const char *charset)
+{
+ int x, y;
+ int appears;
+
+ for(x = 0; s[x] != 0; x++)
+ {
+ appears = 0;
+
+ for(y = 0; charset[y] != 0; y++)
+ {
+ if(s[x] == charset[y])
+ {
+ appears = 1;
+ break;
+ }
+ }
+
+ if(appears)break;
+ }
+
+ return x;
+}
+
+char *strlwr(char *string)
+{
+ char *old = string;
+
+ while(*string)
+ {
+ *string = tolower(*string);
+ string++;
+ }
+
+ return old;
+}
+
+char *strupr(char *string)
+{
+ char *old = string;
+
+ while(*string)
+ {
+ *string = toupper(*string);
+ string++;
+ }
+
+ return old;
+}
+
+int atoi(const char *string)
+{
+ return (int)strtol(string, NULL, 10);
+}
+
+long atol(const char *string)
+{
+ return strtol(string, NULL, 10);
+}
+
+int strnlen(const char *s, size_t maxlen)
+{
+ int l=0;
+
+ while(*(s++) && l<maxlen)
+ l++;
+
+ return l;
+}
+
+void *memrchr(void *b, int c, size_t len)
+{
+ int i = len - 1;
+ unsigned char *p = b;
+
+ for(i = len - 1; p[i] != (unsigned char)c && i >= 0;i--);
+
+ return (i>=0)?&p[i]:NULL;
+}
+
+char *stpcpy(char *dst, const char *src)
+{
+ do
+ {
+ *(dst++) = *src;
+ }while(*(src++));
+
+ return dst-1;
+}
+
+char *stpncpy(char *dst, const char *src, int len)
+{
+ int c = 0;
+
+ do
+ {
+ if(c < len)
+ *(dst++) = *src;
+
+ c++;
+ }while(*(src++) && c < len);
+
+ return dst-1;
+}
+
+char *strcasestr(const char *big, const char *little)
+{
+ while(*big)
+ {
+ const char *pbig = big;
+ const char *plittle = little;
+ int ok = 1;
+
+ while(*pbig)
+ {
+ if(tolower(*pbig) != tolower(*plittle))
+ {
+ ok = 0;
+ break;
+ }
+
+ pbig++;
+ plittle++;
+ }
+
+ if(ok)
+ return (char*)big;
+
+ big++;
+ }
+
+ return NULL;
+}
+
+int strlcpy(char *dst, const char *src, size_t size)
+{
+ char *src_end = memchr((void*)src, '\0', size);
+
+ if(src_end == NULL)
+ return 0;
+
+ memcpy(dst, src, src_end - src);
+
+ return (src_end - src);
+}
+
+int strlcat(char *dst, const char *src, size_t size)
+{
+ int dstl = strlen(dst);
+ char *q = dst + dstl;
+ int real_size = size;
+
+ if(memchr((void*)src, '\0', size))
+ real_size = strlen(src);
+
+ memcpy(q, src, real_size-dstl-1);
+ if(real_size != size) q[real_size-dstl-1] = '\0';
+
+ return size-dstl;
+}
+
+void *memmem(const void *big, size_t big_len, const void *little,
+ size_t little_len)
+{
+ int i, j, l;
+ unsigned char *bigp = (unsigned char*)big;
+ unsigned char *littlep = (unsigned char*)little;
+
+ for(i = 0, l = (int)(big_len - little_len); i <= l; i++, bigp++)
+ {
+ for(j = 0; j < little_len; j++)
+ {
+ if(littlep[j] != bigp[j])
+ break;
+ }
+
+ if(j == little_len)
+ return bigp;
+ }
+
+ return NULL;
+}
diff --git a/libpsx/src/libc/strings.c b/libpsx/src/libc/strings.c
new file mode 100644
index 0000000..76a5f9f
--- /dev/null
+++ b/libpsx/src/libc/strings.c
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+#include <strings.h>
+#include <stdint.h>
+
+#define ffs_func(func_name, type) \
+\
+int func_name(type value) \
+{ \
+ int i; \
+ int nbits = sizeof(type) * 8;\
+ \
+ for(i = 0; i < nbits && !(value & ((type)1 << i) ); i++);\
+ \
+ return (i == nbits) ? 0 : (i + 1);\
+}
+
+ffs_func(ffs, int);
+ffs_func(ffsl, long);
+ffs_func(ffsll, long long);
+
+#define popcount_func(func_name, type) \
+\
+unsigned int func_name(type value) \
+{ \
+ int i, bitcnt; \
+ int nbits = sizeof(type) * 8; \
+ \
+ for(i = 0, bitcnt = 0; i < nbits; i++) \
+ {\
+ if( value & ((type)1 << i) )\
+ bitcnt++;\
+ }\
+ \
+ return bitcnt;\
+}
+
+popcount_func(popcount, unsigned int);
+popcount_func(popcountl, unsigned long);
+popcount_func(popcountll, unsigned long long);
+popcount_func(popcount32, uint32_t);
+popcount_func(popcount64, uint64_t);
diff --git a/libpsx/src/libc/unistd.c b/libpsx/src/libc/unistd.c
new file mode 100644
index 0000000..f64096b
--- /dev/null
+++ b/libpsx/src/libc/unistd.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+void swab(const void *src, void *dst, ssize_t len)
+{
+ ssize_t x;
+ const unsigned char *srcp = src;
+ unsigned char *dstp = dst;
+
+ for(x = 0; x < len; x+=2)
+ {
+ dstp[x] = srcp[x + 1];
+
+ if( (x+1) < len )
+ dstp[x+1] = srcp[x];
+ }
+}
diff --git a/libpsx/src/memcard.c b/libpsx/src/memcard.c
new file mode 100644
index 0000000..16debf9
--- /dev/null
+++ b/libpsx/src/memcard.c
@@ -0,0 +1,87 @@
+/*
+ * PSXSDK Memory Card Helper Functions
+ *
+ * These functions help to manage memory card loading/saving
+ *
+ * Normal file functions can be used to do this, but it will be very tedious...
+ */
+
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+ #include <memcard.h>
+ #include <string.h>
+ #include <psx.h>
+
+static unsigned char card_cmd[140];
+static unsigned char arr[140];
+
+unsigned char McReadSector(int card_slot, int sector, unsigned char *buffer)
+{
+ memset(&card_cmd[0], 0, 140);
+
+ card_cmd[0] = 0x81; /*MC access*/
+ card_cmd[1] = 0x52; /*Read command*/
+
+ /*Copy frame number to command*/
+ card_cmd[4] = sector >> 8; /*Frame MSB*/
+ card_cmd[5] = sector & 0xFF; /*Frame LSB*/
+
+ QueryPAD(card_slot, card_cmd, arr, sizeof(card_cmd));
+
+ /*Copy received frame data*/
+ memcpy(buffer, &arr[10], 128);
+
+ /*Return RW status*/
+ return arr[139];
+}
+
+unsigned char McWriteSector(int card_slot, int sector, unsigned char *buffer)
+{
+ int i;
+
+ memset(&card_cmd[0], 0, 140);
+
+ card_cmd[0] = 0x81; /*MC access*/
+ card_cmd[1] = 0x57; /*Write command*/
+
+ /*Copy frame number to command*/
+ card_cmd[4] = sector >> 8; /*Frame MSB*/
+ card_cmd[5] = sector & 0xFF; /*Frame LSB*/
+
+ memcpy(&card_cmd[6], buffer, 128);
+
+ /* Compute checksum */
+ for(i = 4, card_cmd[134] = 0; i < 134; i++)
+ card_cmd[134] ^= card_cmd[i];
+
+ QueryPAD(card_slot, card_cmd, arr, sizeof(card_cmd));
+
+ /*Return RW status*/
+ return arr[137];
+}
+
+unsigned int McGetStatus(int card_slot)
+{
+ unsigned int status = 0;
+
+ memset(&card_cmd[0], 0, 140);
+
+ card_cmd[0] = 0x81; /*MC access*/
+ card_cmd[1] = 0x52; /*Read command*/
+
+ /*Copy frame number to command*/
+ card_cmd[4] = 0;//sector >> 8; /*Frame MSB*/
+ card_cmd[5] = 0;//sector & 0xFF; /*Frame LSB*/
+
+ QueryPAD(card_slot, card_cmd, arr, sizeof(card_cmd));
+
+ if(arr[2] == 0x5a && arr[3] == 0x5d)
+ status |= MEMCARD_CONNECTED;
+
+ if(arr[6] == 'M' && arr[7] == 'C')
+ status |= MEMCARD_FORMATTED;
+
+ return status;
+}
diff --git a/libpsx/src/memory.c b/libpsx/src/memory.c
new file mode 100644
index 0000000..e6bb806
--- /dev/null
+++ b/libpsx/src/memory.c
@@ -0,0 +1,215 @@
+/*
+ * memory.c
+ *
+ * PSXSDK malloc() family functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern int __bss_start[];
+extern int __bss_end[];
+
+unsigned int first_free_page;
+
+// 1K granularity and "pages", so more allocations which are small can be done
+
+unsigned char busy_pages[2048];
+unsigned int alloc_size[2048];
+
+// RAM memory map on the PSX
+// 0x80000000 - 0x8000FFFF RAM used by the BIOS
+// 0x80010000 - 0x801FFFFF Program memory
+
+void malloc_setup()
+{
+ int x;
+
+ dprintf("malloc setup.\n");
+
+ first_free_page = (unsigned int) __bss_end;
+ first_free_page-= 0x80000000;
+
+ if(first_free_page & 0x3ff)
+ first_free_page = (first_free_page | 0x3ff) + 1;
+
+ first_free_page>>=10;
+
+ //printf("First free page: %d, bss_end: %x\n", first_free_page, __bss_end);
+
+ for(x = 0; x < first_free_page; x++)
+ {
+ busy_pages[x] = 1; // RAM occupied by program, data and BIOS looks always allocated
+ alloc_size[x] = 1; // Fake that 1K was required
+ }
+
+ for(x = first_free_page; x < 2048; x++)
+ {
+ busy_pages[x] = 0;
+ alloc_size[x] = 0;
+ }
+}
+
+void *malloc(size_t size)
+{
+ dprintf("malloc(%d)\n", size);
+
+ int x, y;
+
+// Round size
+
+ if(size & 0x3ff)
+ size = (size | 0x3ff) + 1;
+
+// Divide it by 1024
+ size >>= 10;
+ //printf("Allocating %dKb\n", size);
+
+// Find a free page
+ for(x = 0; x < 2048; x++)
+ {
+ if(busy_pages[x] == 0)
+ {
+ // If we find a free page, check how many free pages follow it.
+ // If it's enough for the memory we want to allocate, then return
+ // the pointer to the free page we found, otherwise keep finding
+
+ // printf("Page found at %dKb\n", x);
+
+ for(y = 0; y < size; y++)
+ if(busy_pages[x+y] == 1) goto malloc_keep_finding;
+
+ // We found the memory we wanted, now make it busy
+
+ for(y = 0; y < size; y++)
+ busy_pages[x+y] = 1;
+
+ // Store allocation size, it is essential for free()
+
+ alloc_size[x] = size;
+ // printf("malloc(): alloc_size[%d] = %d\n", x, size);
+
+ return (void*)((unsigned int)0x80000000 + (x<<10));
+ }
+malloc_keep_finding:
+ ; // Useless statement to make GCC not bail out...
+ }
+
+// We couldn't find anything, return NULL
+ return NULL;
+}
+
+void *calloc(size_t number, size_t size)
+{
+ void *ptr = malloc(number * size);
+ unsigned char *cptr = (unsigned char*)ptr;
+ int x;
+
+ if(ptr == NULL)
+ ptr = NULL;
+
+ for(x = 0; x < (number * size); x++)
+ cptr[x] = 0;
+
+ return ptr;
+}
+
+void free(void *ptr)
+{
+ dprintf("free(%x)\n", (unsigned int)ptr);
+
+ unsigned int ptri = (unsigned int)ptr;
+ ptri -= 0x80000000;
+ int x;
+
+ if((ptri & 0x3ff) || (busy_pages[ptri>>10] == 0) || (alloc_size[ptri>>10] == 0))
+ {
+ // If the pointer address is not a multiplier of 1K, or the page
+ // is free, it means that memory not allocated by malloc() was passed to free.
+ // Print a warning message and return.
+
+ printf("** free() ** : tried to free memory with invalid pointer at %x\n",
+ ptri + 0x80000000);
+
+ return;
+ }
+
+// Divide ptri by 1024, getting initial page
+
+ ptri>>=10;
+
+// printf("Freeing page at %dKb\n", ptri);
+
+// Free pages
+
+// printf("alloc_size[%d] = %d\n", ptri, alloc_size[ptri]);
+
+ for(x = 0; x < alloc_size[ptri]; x++)
+ {
+ dprintf("ptri + x = %d\n", ptri + x);
+ busy_pages[ptri + x] = 0;
+ }
+
+// Set allocation size to 0, finally freeing initial page
+
+ alloc_size[ptri] = 0;
+
+ /*for(x=150;x<170;x++)
+ printf("%d: %d, %d\n", x, busy_pages[x], alloc_size[x]);*/
+}
+
+void *realloc(void *ptr, size_t size)
+{
+ unsigned int ptri = (unsigned int)ptr;
+ int x;
+ void *newptr;
+
+ if(ptr == NULL)
+ return malloc(size);
+
+ ptri -= 0x80000000;
+
+ size |= 0x3ff;
+ size++;
+
+ size>>=10;
+
+ if((ptri & 0x3ff) || (busy_pages[ptri>>10] == 0) || (alloc_size[ptri>>10] == 0))
+ {
+ // If the pointer address is not a multiplier of 1K, or the page
+ // is free, it means that memory not allocated by malloc() was passed to realloc.
+ // Print a warning message and return.
+
+ printf("** realloc() ** : tried to reallocate memory with invalid pointer at %x\n",
+ ptri + 0x80000000);
+
+ return NULL;
+ }
+
+// Get page
+
+ ptri>>=10;
+
+ if(size < alloc_size[ptri]) // New size smaller than old size
+ {
+ for(x = size; x < alloc_size[ptri]; x++)
+ busy_pages[ptri + x] = 0;
+
+ alloc_size[ptri] = size;
+ }
+ else if(size > alloc_size[ptri]) // New size bigger than old size
+ {
+ newptr = malloc(size * 1024);
+
+ if(newptr == NULL)
+ return NULL;
+
+ memcpy(newptr, ptr, alloc_size[ptri]);
+ free(ptr);
+
+ ptr = newptr;
+ }
+
+ return ptr;
+}
diff --git a/libpsx/src/memory.h b/libpsx/src/memory.h
new file mode 100644
index 0000000..39985b2
--- /dev/null
+++ b/libpsx/src/memory.h
@@ -0,0 +1,6 @@
+#ifndef _PSXSDK_MEMORY_H
+#define _PSXSDK_MEMORY_H
+
+void malloc_setup();
+
+#endif \ No newline at end of file
diff --git a/libpsx/src/pad.c b/libpsx/src/pad.c
new file mode 100644
index 0000000..ea3e20e
--- /dev/null
+++ b/libpsx/src/pad.c
@@ -0,0 +1,163 @@
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <psx.h>
+
+/*
+ * Flags taken from PCSX
+ */
+
+// Status Flags
+#define TX_RDY 0x0001
+#define RX_RDY 0x0002
+#define TX_EMPTY 0x0004
+#define PARITY_ERR 0x0008
+#define RX_OVERRUN 0x0010
+#define FRAMING_ERR 0x0020
+#define SYNC_DETECT 0x0040
+#define DSR 0x0080
+#define CTS 0x0100
+#define IRQ 0x0200
+
+// Control Flags
+#define TX_PERM 0x0001
+#define DTR 0x0002
+#define RX_PERM 0x0004
+#define BREAK 0x0008
+#define RESET_ERR 0x0010
+#define RTS 0x0020
+#define PADSIO_RESET 0x0040
+
+/*
+ from BlackBag/Nagra PSX
+
+ 0x1f801040 - unsigned char data;
+ 0x1f801044 - unsigned short status;
+ 0x1f80104a - unsigned short cntl;
+ 0x1f80104e - unsigned short baud;
+*/
+
+#define PADSIO_DATA(x) *((volatile unsigned char*)(0x1f801040 + (x<<4)))
+#define PADSIO_STATUS(x) *((volatile unsigned short*)(0x1f801044 + (x<<4)))
+#define PADSIO_MODE(x) *((volatile unsigned short*)(0x1f801048 + (x<<4)))
+#define PADSIO_CTRL(x) *((volatile unsigned short*)(0x1f80104a + (x<<4)))
+#define PADSIO_BAUD(x) *((volatile unsigned short*)(0x1f80104e + (x<<4)))
+
+unsigned char readpad_vibrations[4][2];
+int querypad_rxrdy = 1;
+
+void QueryPAD(int pad_n, unsigned char *in, unsigned char *out, int len)
+{
+ int x;
+ volatile int y; // specified as volatile to not make busy loops get optimized out
+ int i;
+ unsigned char TempData;
+ int EmuFlag = 0;
+
+ PADSIO_MODE(0) = 0xD;
+ PADSIO_BAUD(0) = 0x88;
+
+ if(pad_n == 1) PADSIO_CTRL(0) = 0x3003; else PADSIO_CTRL(0) = 0x1003;
+
+ /*Get the initial command (usually 0x01 or 0x81)*/
+ TempData = *in;
+
+ for(y=0;y<400;y++); /*Slight delay before first transmission*/
+
+ for(x = 0; x < len; x++)
+ {
+ /*Must use timeouts or else program hangs on emulators*/
+ if(!EmuFlag)
+ {
+ for(y=0;y<1000;y++)
+ {
+ /*Wait for TX ready*/
+ if(PADSIO_STATUS(0) & 4)break;
+ }
+ }
+
+ PADSIO_DATA(0) = *in;
+ in++;
+
+ if(!EmuFlag)
+ {
+ /*Check ACK only for Memory Cards*/
+ if(TempData == 0x81 || x == 0)
+ {
+ for(y=0;y<2000;y++)
+ {
+ /*Check for ACK signal*/
+ if(PADSIO_STATUS(0) & 128)break;
+ }
+ }
+
+ for(i=0;i<100;i++)
+ {
+ /*Read RX status flag, required for Xebra*/
+ if(PADSIO_STATUS(0) & 2)break;
+ }
+ }
+
+ *out = PADSIO_DATA(0);
+
+ /*This is emulator, valid data was received without ACK, ePSXe and PCSX*/
+ if(x == 0 && y > 1900 && *out != 0xFF)EmuFlag = 1;
+
+ out++;
+ }
+
+ PADSIO_CTRL(0) = 0;
+}
+
+void pad_read_raw(int pad_n, unsigned char *arr)
+{
+ // arr must be at least 16 bytes long...
+
+ unsigned char pad_cmd[PAD_READ_RAW_SIZE] = {1,0x42,0,0,0};
+
+ pad_cmd[3] = readpad_vibrations[pad_n][0];
+ pad_cmd[4] = readpad_vibrations[pad_n][1];
+
+ QueryPAD(pad_n, pad_cmd, arr, sizeof(pad_cmd));
+}
+
+void pad_escape_mode(int pad_n, int enable)
+{
+ unsigned char pad_cmd[] = {1,0x43,0,enable?1:0,0};
+
+ QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd));
+}
+
+void pad_enable_vibration(int pad_n)
+{
+ unsigned char pad_cmd[] = {1, 0x4d, 0, 0, 1, 0xff, 0xff, 0xff, 0xff};
+
+ pad_escape_mode(pad_n, 1); // Enter escape / configuration mode
+ QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd));
+ pad_escape_mode(pad_n, 0); // Exit escape / configuration mode
+}
+
+void pad_set_vibration(int pad_n, unsigned char small, unsigned char big)
+{
+ if(pad_n >= 0 && pad_n <= 3)
+ {
+ readpad_vibrations[pad_n][0] = small;
+ readpad_vibrations[pad_n][1] = big;
+ }
+}
+
+/*
+ // Sony pads make this interface unpractical!
+void pad_set_analog(int pad_n, int lock)
+{
+ unsigned char pad_cmd[9] =
+ {1, 0x44, 0, 1, lock?3:0, 0, 0, 0, 0};
+ unsigned char pad_cmd2[9] =
+ {1, 0x4f, 0, 0xff, 0xff, 3, 0, 0, 0};
+
+ pad_escape_mode(pad_n, 1);
+ QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd));
+ QueryPAD(pad_n, pad_cmd2, NULL, sizeof(pad_cmd));
+ pad_escape_mode(pad_n, 0);
+}*/
+
diff --git a/libpsx/src/psxsdk.c b/libpsx/src/psxsdk.c
new file mode 100644
index 0000000..a595bdb
--- /dev/null
+++ b/libpsx/src/psxsdk.c
@@ -0,0 +1,542 @@
+/*
+ * PSXSDK Library
+ *
+ * Free and open source library to develop for the Sony PlayStation
+ */
+
+#include <psx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "exception.h"
+
+static const char *sysromver_unavail = "System ROM Version Unavailable";
+
+void (*vblank_handler_callback)();
+
+extern int *vblank_handler();
+
+void (*rcnt_handler_callback)();
+
+extern int *rcnt_handler();
+
+/*static unsigned int vblank_queue_buf[4] = {0x0, // Will contain next interrupt handler in queue
+ 0x0, // func1
+ (unsigned int)vblank_handler, // func2
+ 0x0, // pad
+ };*/
+
+static int vblank_handler_set = 0;
+static unsigned int vblank_handler_event_id = 0;
+
+static int rcnt_handler_set = 0;
+static unsigned int rcnt_handler_event_id = 0;
+unsigned int rcnt_handler_evfield;
+
+void _internal_cdromlib_init(void);
+
+static unsigned int psxSdkFlags = 0;
+
+static unsigned char *psxBiosState;
+
+extern void _96_remove(void);
+extern void _96_init(void);
+extern void InitCARD(void);
+extern void StartCARD(void);
+extern void StopCARD(void);
+extern void _bu_init(void);
+extern void BIOSWarmReboot(void);
+
+void PSX_InitEx(unsigned int flags)
+{
+ if(flags & PSX_INIT_NOBIOS)
+ {
+ printf("Entering No BIOS mode...\n");
+
+ __PSX_Init_NoBios();
+ goto _initex_end;
+ }
+
+ if(flags & PSX_INIT_SAVESTATE)
+ {
+// Save BIOS state
+// This simply copies the entire section of RAM used by the BIOS
+// in a buffer.
+ EnterCriticalSection();
+ psxBiosState = malloc(0x10000);
+ memcpy(psxBiosState, (void*)0x80000000, 0x10000);
+ ExitCriticalSection();
+ }
+
+ /* Reinitialize ISO 9660 filesystem driver */
+
+ if(flags & PSX_INIT_CD)
+ {
+ EnterCriticalSection();
+ _96_remove();
+ ExitCriticalSection();
+
+ _96_init();
+ }
+
+
+ /*This is needed, otherwise PSX will crash when VBlank handler is set*/
+ /*InitCARD(1);
+ StartCARD();
+ StopCARD();*/
+
+ if(flags & PSX_INIT_CD)
+ _internal_cdromlib_init();
+
+ printf("PSXSDK testing version !!!\n");
+
+ vblank_handler_set = 0;
+_initex_end:
+ psxSdkFlags = flags;
+}
+
+void PSX_Init(void)
+{
+ PSX_InitEx(PSX_INIT_CD);
+}
+
+void PSX_DeInit(void)
+{
+ if(psxSdkFlags & PSX_INIT_CD)
+ {
+ EnterCriticalSection();
+ _96_remove();
+ ExitCriticalSection();
+ }
+
+ RemoveVBlankHandler();
+
+ if(psxSdkFlags & PSX_INIT_SAVESTATE)// This must always be the last to be called!
+ PSX_RestoreBiosState();
+}
+
+void PSX_ReadPad(unsigned short *padbuf, unsigned short *padbuf2)
+{
+ int x;
+ unsigned char arr[PAD_READ_RAW_SIZE];
+ unsigned short *padbuf_a[2];
+
+// Now uses low level pad routines...
+ padbuf_a[0] = padbuf;
+ padbuf_a[1] = padbuf2;
+
+ for(x = 0; x < 2; x++)
+ {
+ pad_read_raw(x, arr);
+
+ if(arr[2] == 0x5a)
+ {
+ *padbuf_a[x] = (arr[3]<<8)|arr[4];
+ *padbuf_a[x] = ~*padbuf_a[x];
+ }
+ else
+ *padbuf_a[x] = 0;
+ }
+}
+
+unsigned char psxsdkPadArr[PAD_READ_RAW_SIZE];
+
+void PSX_PollPad(int pad_num, psx_pad_state *pad_state)
+{
+// int x;
+ /*unsigned short *padbuf_a[2];
+
+// Now uses low level pad routines...
+ padbuf_a[0] = padbuf;
+ padbuf_a[1] = padbuf2;
+
+ for(x = 0; x < 2; x++)
+ {
+ pad_read_raw(x, arr);
+
+ if(arr[2] == 0x5a)
+ {
+ *padbuf_a[x] = (arr[3]<<8)|arr[4];
+ *padbuf_a[x] = ~*padbuf_a[x];
+ }
+ else
+ *padbuf_a[x] = 0;
+ }*/
+
+ unsigned char *arr = psxsdkPadArr;
+
+ pad_read_raw(pad_num, arr);
+
+ pad_state->status = arr[0];
+ pad_state->id = arr[1];
+
+ pad_state->buttons = (arr[3]<<8)|arr[4];
+ pad_state->buttons = ~pad_state->buttons;
+
+ switch(pad_state->id)
+ {
+ case 0xFF:
+ pad_state->type = PADTYPE_NONE;
+ break;
+ case 0x41:
+ pad_state->type = PADTYPE_NORMALPAD;
+ break;
+ case 0x53:
+ pad_state->type = PADTYPE_ANALOGJOY;
+ pad_state->extra.analogJoy.x[0] = arr[5]-128;
+ pad_state->extra.analogJoy.y[0] = arr[6]-128;
+ pad_state->extra.analogJoy.x[1] = arr[7]-128;
+ pad_state->extra.analogJoy.y[1] = arr[8]-128;
+ break;
+ case 0x73:
+ pad_state->type = PADTYPE_ANALOGPAD;
+ pad_state->extra.analogPad.x[0] = arr[5]-128;
+ pad_state->extra.analogPad.y[0] = arr[6]-128;
+ pad_state->extra.analogPad.x[1] = arr[7]-128;
+ pad_state->extra.analogPad.y[1] = arr[8]-128;
+ break;
+ case 0x23:
+ pad_state->type = PADTYPE_NEGCON;
+ pad_state->extra.negCon.steering = arr[5]-128;
+ pad_state->extra.negCon.one = arr[6];
+ pad_state->extra.negCon.two = arr[7];
+ pad_state->extra.negCon.shoulder = arr[8];
+ break;
+ case 0x31:
+ pad_state->type = PADTYPE_KONAMIGUN;
+ break;
+ default:
+ pad_state->type = PADTYPE_UNKNOWN;
+ }
+}
+
+/*int PSX_GetPadType(unsigned int pad_num)
+//{
+ //#warning "Function does not currently work!"
+// unsigned char arr[16];
+
+ pad_read_raw(pad_num, arr);
+
+ switch(arr[1])
+ {
+ case 0xFF:
+ return PADTYPE_NONE;
+ break;
+ case 0x41:
+ return PADTYPE_NORMALPAD;
+ break;
+ case 0x53:
+ return PADTYPE_ANALOGJOY;
+ break;
+ case 0x73:
+ return PADTYPE_ANALOGPAD;
+ break;
+ }
+
+ return PADTYPE_UNKNOWN;
+}*/
+
+
+void PSX_GetSysInfo(struct psx_info *info)
+{
+ unsigned long i,i2;
+
+ info->kernel.version = GetKernelRomVersion();
+
+ i = GetKernelDate();
+
+/*
+ * Convert year from BCD to decimal
+ */
+
+ i2 = i >> 16;
+
+ info->kernel.year = i2 & 0xf;
+ info->kernel.year+= ((i2>>4)&0xf)*10;
+ info->kernel.year+= ((i2>>8)&0xf)*100;
+ info->kernel.year+= ((i2>>12)&0xf)*1000;
+
+/*
+ * Convert month from BCD to decimal
+ */
+ i2 = (i >> 8) & 0xff;
+
+ info->kernel.month = i2 & 0xf;
+ info->kernel.month+= (i2>>4) * 10;
+
+/*
+ * Convert day from BCD to decimal
+ */
+ i2 = i & 0xff;
+
+ info->kernel.day = i2 & 0xf;
+ info->kernel.day+= (i2>>4) * 10;
+
+/*
+ * Unless we receive something in the range >= 1 && <= 16,
+ * RAM size will be reported as 2 Megabytes
+ */
+
+ i = GetRamSize();
+
+ if(i == 0 || i > 16)
+ info->system.memory = 2<<20; /* 2 Megabytes */
+ else
+ info->system.memory <<= 20;
+}
+
+
+
+int get_real_file_size(const char *name)
+{
+ struct DIRENTRY dirent_buf;
+
+ if(firstfile(name, &dirent_buf) == &dirent_buf)
+ return dirent_buf.size;
+ else
+ return 0;
+}
+
+int get_file_size(const char *name)
+{
+ int i = get_real_file_size(name);
+
+ if(strncmp(name, "cdrom:", 6) == 0)
+ {
+ if(i & 0x7ff)
+ {
+ i += 0x800;
+ i &= ~0x7ff;
+ }
+ }else if(strncmp(name, "bu", 2) == 0)
+ {
+ if(i & 0x7f)
+ {
+ i += 0x80;
+ i &= ~0x7f;
+ }
+ }
+
+ return i;
+}
+
+int SetRCnt(int spec, unsigned short target, unsigned int mode)
+{
+ spec &= 0xf;
+
+ if(spec >= 3)
+ return 0;
+
+ RCNT_MODE(spec)=0;
+ RCNT_TARGET(spec)=target;
+ RCNT_MODE(spec)=mode;
+
+ return 1;
+}
+
+int GetRCnt(int spec)
+{
+ spec &= 0xf;
+
+ if(spec >= 4)
+ return -1;
+
+ return (RCNT_COUNT(spec) & 0xffff);
+}
+
+int StartRCnt(int spec)
+{
+ spec &= 0xf;
+
+ if(spec >= 3)
+ return 0;
+
+ IMASK |= 1 << (spec + 4);
+
+ return 1;
+}
+
+int StopRCnt(int spec)
+{
+ spec &= 0xf;
+
+ if(spec >= 3)
+ return 0;
+
+ IMASK ^= 1 << (spec + 4);
+
+ return 1;
+}
+
+void SetVBlankHandler(void (*callback)())
+{
+ if(psxSdkFlags & PSX_INIT_NOBIOS)
+ {
+ _EXC_vblank_handler_set = 0;
+ _EXC_vblank_handler = callback;
+ _EXC_vblank_handler_set = 1;
+ return;
+ }
+
+ if(vblank_handler_set == 1)
+ {
+ EnterCriticalSection();
+
+ vblank_handler_callback = callback;
+
+ ExitCriticalSection();
+
+ return;
+ }
+
+// Enter critical section
+
+ EnterCriticalSection();
+
+ IMASK|=1;
+
+ vblank_handler_event_id = OpenEvent(RCntCNT3, 2, 0x1000, vblank_handler);
+ EnableEvent(vblank_handler_event_id);
+
+ vblank_handler_callback = callback;
+ vblank_handler_set = 1;
+
+// Exit critical section
+
+ ExitCriticalSection();
+}
+
+void RemoveVBlankHandler(void)
+{
+ if(psxSdkFlags & PSX_INIT_NOBIOS)
+ {
+ _EXC_vblank_handler_set = 0;
+ _EXC_vblank_handler = NULL;
+ return;
+ }
+
+ if(vblank_handler_set)
+ {
+ EnterCriticalSection();
+
+ DisableEvent(vblank_handler_event_id);
+ CloseEvent(vblank_handler_event_id);
+
+ //IMASK^=1;
+ // ^ commented because masking out vblank could give problems to other bios functions
+
+ vblank_handler_set = 0;
+
+ ExitCriticalSection();
+ }
+}
+
+void SetRCntHandler(void (*callback)(), int spec, unsigned short target)
+{
+ if(psxSdkFlags & PSX_INIT_NOBIOS)
+ return; // Not yet supported in No-Bios Mode
+
+ if(rcnt_handler_set)
+ {
+ EnterCriticalSection();
+
+ rcnt_handler_callback = callback;
+
+ ExitCriticalSection();
+
+ return;
+ }
+
+// Enter critical section
+
+ SetRCnt(spec, target, RCntIntr | 0x08 | 0x10 | 0x40);
+ StartRCnt(spec);
+
+ EnterCriticalSection();
+ rcnt_handler_event_id = OpenEvent(spec, 2, 0x1000, rcnt_handler);
+ EnableEvent(rcnt_handler_event_id);
+
+ rcnt_handler_callback = callback;
+ rcnt_handler_set = spec;
+
+ switch(spec)
+ {
+ case RCntCNT0: rcnt_handler_evfield = 1 << 4; break;
+ case RCntCNT1: rcnt_handler_evfield = 1 << 5; break;
+ case RCntCNT2: rcnt_handler_evfield = 1 << 6; break;
+ case RCntCNT3: rcnt_handler_evfield = 1; break;
+ }
+
+// Exit critical section
+
+ ExitCriticalSection();
+}
+
+void RemoveRCntHandler(int spec)
+{
+ if(psxSdkFlags & PSX_INIT_NOBIOS)
+ return; // Not yet supported in No-Bios Mode
+
+ if(rcnt_handler_set)
+ {
+ EnterCriticalSection();
+
+ DisableEvent(rcnt_handler_event_id);
+ CloseEvent(rcnt_handler_event_id);
+
+ rcnt_handler_set = 0;
+
+ ExitCriticalSection();
+ }
+}
+
+const char *GetSystemRomVersion(void)
+{
+// Get pointer to zero-terminated string containing System ROM Version which is embedded in
+// most PlayStation BIOSes.
+
+// If getting the pointer is not possible, a pointer to a string saying "System ROM Unavailable" is returned.
+
+ int x;
+
+ for(x = 0x7ffee; x >= 0; x--)
+ if(memcmp("System ROM Version", (void*)(0xbfc00000 + x), 18) == 0)
+ return (char*)(0xbfc00000 + x);
+
+ return sysromver_unavail;
+}
+
+int PSX_RestoreBiosState(void)
+{
+ if(!(psxSdkFlags & PSX_INIT_SAVESTATE))
+ return 0; // can't restore BIOS state if it was not saved previously
+
+ EnterCriticalSection();
+ memcpy((void*)0x80000000, psxBiosState, 0x10000);
+ ExitCriticalSection();
+
+ return 1;
+}
+
+unsigned int PSX_GetInitFlags(void)
+{
+ return psxSdkFlags;
+}
+
+void PSX_WarmReboot(void)
+{
+ if(psxSdkFlags & PSX_INIT_NOBIOS)
+ {
+psx_warmreboot_nobios:
+ PSX_DeInit();
+ __asm__("j _start");
+ __asm__("nop");
+ }
+ else
+ {
+ if(!(psxSdkFlags & PSX_INIT_CD))
+ goto psx_warmreboot_nobios;
+
+ BIOSWarmReboot();
+ }
+}
diff --git a/libpsx/src/runexe/runexe.c b/libpsx/src/runexe/runexe.c
new file mode 100644
index 0000000..5fe22b0
--- /dev/null
+++ b/libpsx/src/runexe/runexe.c
@@ -0,0 +1,76 @@
+/**
+ * PSXSDK
+ *
+ * RunEXE functionality
+ */
+
+#include <psx.h>
+#include <stdio.h>
+#include <string.h>
+#include <runexe.h>
+
+// Include runexe stage2 position independent code
+
+extern void PSX_RunExeStage2();
+extern void PSX_RunExeStage2_END();
+
+static void *runExeBuffer;
+
+int PSX_RunExe(void *exeBuffer)
+{
+ //unsigned char *exe = exeBuffer;
+ unsigned int *exe = exeBuffer;
+// Size of position indipendent code
+ int sz = PSX_RunExeStage2_END -
+ PSX_RunExeStage2;
+
+ if(!(PSX_GetInitFlags() & PSX_INIT_SAVESTATE))
+ {
+ printf("RunExe error: State was not saved!\n");
+ return 0;
+ }
+
+ if(((unsigned int)exeBuffer & 3))
+ {
+ printf("RunExe: Alignment violation.\n");
+ printf("Specified buffer must have an address which is a multiplier of 4.\n");
+ return 0;
+ }
+
+ // Check magic string
+ if(strcmp(exeBuffer, "PS-X EXE") != 0)
+ return 0; // Return failure if magic string couldn't be found
+
+ runExeBuffer = exeBuffer;
+
+ printf("PSXSDK RunExe Debug Information\n");
+ printf("t_addr = %08x\n", exe[6]);
+ printf("t_size = %08x\n", exe[7]);
+ printf("d_addr = %08x\n", exe[8]);
+ printf("d_size = %08x\n", exe[9]);
+ printf("b_addr = %08x\n", exe[10]);
+ printf("b_size = %08x\n", exe[11]);
+ printf("s_addr = %08x\n", exe[12]);
+ printf("s_size = %08x\n", exe[13]);
+
+ printf("OK..! Farewell.\n");
+
+// Deinitialize the PSXSDK library
+ PSX_DeInit();
+
+// Copy the position independent stage2 code in high memory
+ memcpy((void*)0x801fef00, PSX_RunExeStage2, sz);
+
+// Stack is unusable now! Do not do anything else except calling the stage2 code.
+
+// Jump to the stage2 code without using the stack..
+
+ __asm__("la $a0, runExeBuffer");
+ __asm__("nop");
+ __asm__("lw $a0, 0($a0)");
+ __asm__("j 0x801fef00");
+ __asm__("nop");
+
+// This is never reached but keep the compiler happy
+ return 0;
+}
diff --git a/libpsx/src/runexe/stage2.s b/libpsx/src/runexe/stage2.s
new file mode 100644
index 0000000..e60e109
--- /dev/null
+++ b/libpsx/src/runexe/stage2.s
@@ -0,0 +1,40 @@
+.global PSX_RunExeStage2
+.global PSX_RunExeStage2_END
+
+PSX_RunExeStage2:
+# a0 = address of PSX-EXE buffer
+
+# Load initial program counter in t0
+ lw $t0, 0x10($a0)
+# Load text section address in t1
+ lw $t1, 0x18($a0)
+# Load text section size in t2
+ lw $t2, 0x1c($a0)
+
+# Load initial sp register value in sp
+ lw $sp, 0x30($a0)
+
+# t3 = current source address
+ addiu $t3, $a0, 0x800
+
+# t4 = current destination address
+ addu $t4, $t1, $zero
+
+copyExeLoop:
+ beq $t2, $zero, copyExeLoop_End
+ nop
+copyExeLoop_2:
+ lb $t5, 0($t3)
+ nop
+ sb $t5, 0($t4)
+ addiu $t3, $t3, 1
+ addiu $t4, $t4, 1
+ addiu $t2, $t2, -1
+ beq $zero, $zero, copyExeLoop
+
+copyExeLoop_End:
+# Jump to the program we loaded
+ jr $t0
+ nop
+
+PSX_RunExeStage2_END:
diff --git a/libpsx/src/setup.c b/libpsx/src/setup.c
new file mode 100644
index 0000000..d77f062
--- /dev/null
+++ b/libpsx/src/setup.c
@@ -0,0 +1,50 @@
+#include <psx.h>
+#include <stdio.h>
+#include "memory.h"
+
+extern int __bss_start[];
+extern int __bss_end[];
+
+extern void *__ctor_list;
+extern void *__ctor_end;
+
+
+// Function to call static constructors (for C++, etc.)
+static void call_ctors(void)
+{
+ dprintf("Calling static constructors...\n");
+
+ void **p = &__ctor_end - 1;
+
+ for(--p; *p != NULL && (int)*p != -1 && p > &__ctor_list; p--)
+ {
+ dprintf("Constructor address = %x\n", (unsigned int)*p);
+ (*(void (**)())p)();
+ }
+
+ dprintf("Finished calling static constructors\n");
+}
+
+void psxsdk_setup()
+{
+ unsigned int x;
+
+ printf("Initializing PSXSDK... \n");
+
+ dprintf("Clearing BSS space...\n");
+
+// Clear BSS space
+ for(x = (unsigned int)__bss_start; x < (unsigned int)__bss_end; x++)
+ *((unsigned char*)x) = 0;
+
+ dprintf("BSS space cleared.\n");
+
+// Setup memory allocation functions
+ malloc_setup();
+
+ dprintf("Finished setting up memory allocation functions.\n");
+
+// Call static constructors
+ call_ctors();
+
+}
diff --git a/libpsx/src/sio.c b/libpsx/src/sio.c
new file mode 100644
index 0000000..5d399d3
--- /dev/null
+++ b/libpsx/src/sio.c
@@ -0,0 +1,64 @@
+/*
+ * SIO communication library for PSXSDK.
+ * Originally written by Shendo.
+ * Thanks to Martin Korth of the NO$PSX for documentation.
+ *
+ * This library is accessing SIO registers directly, no BIOS routines are used.
+ */
+
+#include <psx.h>
+#include <psxsio.h>
+#include <stdio.h>
+
+void SIOStart(int bitrate)
+{
+ /*Set to 8N1 mode with desired bitrate*/
+ SIOStartEx(bitrate, SIO_DATA_LEN_8, SIO_PARITY_NONE, SIO_STOP_BIT_1);
+}
+
+void SIOStartEx(int bitrate, int datalength, int parity, int stopbit)
+{
+ /*Set SIO_MODE register, bitrate reload factor set to MUL16 by default*/
+ SIO_MODE = SIO_REL_MUL16 | (datalength << 2) | (parity << 4) | (stopbit << 6);
+
+ /*Reset SIO_CTRL register.*/
+ SIO_CTRL = 0;
+
+ /*Set TX and RT to enabled, no handshaking signals.*/
+ SIO_CTRL = 1 | (1 << 2);
+
+ /*Calculate bitrate reload value based on the given bitrate
+ * Reload = SystemClock (33 Mhz) / (Factor (MULI16) * bitrate)*/
+ SIO_BPSV = 0x204CC00 / (16 * bitrate);
+}
+
+void SIOStop()
+{
+ /*Set all SIO related registers to zero*/
+ SIO_MODE = 0;
+ SIO_CTRL = 0;
+ SIO_BPSV = 0;
+}
+
+unsigned char SIOReadByte()
+{
+ return (unsigned char)SIO_TX_RX;
+}
+
+void SIOSendByte(unsigned char data)
+{
+ SIO_TX_RX = data;
+}
+
+int SIOCheckInBuffer()
+{
+ /*Return status of RX FIFO*/
+ return (SIO_STAT & 0x2)>0;
+}
+
+int SIOCheckOutBuffer()
+{
+ /*Return status of TX Ready flag*/
+ return (SIO_STAT & 0x4)>0;
+}
+ \ No newline at end of file
diff --git a/libpsx/src/spu.c b/libpsx/src/spu.c
new file mode 100644
index 0000000..441acb6
--- /dev/null
+++ b/libpsx/src/spu.c
@@ -0,0 +1,269 @@
+/**
+ * PSXSDK
+ *
+ * Sound Processing Unit Functions
+ * Based on code from James Higgs's PSX lib and on code by bitmaster
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <psx.h>
+
+static unsigned int ss_vag_addr;
+
+void SsVoiceVol(int voice, unsigned short left, unsigned short right)
+{
+ unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice);
+
+ a[0] = left;
+ a[1] = right;
+}
+
+void SsVoicePitch(int voice, unsigned short pitch)
+{
+ unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice);
+
+ a[2] = pitch;
+}
+
+void SsVoiceStartAddr(int voice, unsigned int addr)
+{
+// address given is real address, then it is divided by eight when written to the register
+// example: SSVoiceStartAddr(0, 0x1008) , writes 0x201 on the register which means 0x1008
+
+ unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice);
+
+ a[3] = (addr >> 3);
+}
+
+void SsVoiceADSRRaw(int voice, unsigned short level, unsigned short rate)
+{
+ unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice);
+
+ a[4] = level;
+ a[5] = rate;
+}
+
+void SsVoiceRepeatAddr(int voice, unsigned int addr)
+{
+// only valid after KeyOn
+// the explanation for SSVoiceStartAddr() is valid for this function as well
+
+ unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice);
+
+ a[7] = (addr >> 3);
+}
+
+void SsKeyOn(int voice)
+{
+ unsigned int i = 1 << voice;
+
+ SPU_KEY_ON1 = i & 0xffff;
+ SPU_KEY_ON2 = i >> 16;
+
+/* while(SPU_KEY_ON1 != (i & 0xffff));
+ while(SPU_KEY_ON2 != (i >> 16));
+*/
+}
+
+void SsKeyOff(int voice)
+{
+ unsigned int i = 1 << voice;
+
+ SPU_KEY_OFF1 = i & 0xffff;
+ SPU_KEY_OFF2 = i >> 16;
+}
+
+
+
+void SsKeyOnMask(int mask)
+{
+ SPU_KEY_ON1 = mask & 0xffff;
+ SPU_KEY_ON2 = mask >> 16;
+}
+
+void SsKeyOffMask(int mask)
+{
+ SPU_KEY_OFF1 = mask & 0xffff;
+ SPU_KEY_OFF2 = mask >> 16;
+}
+
+void SsWait()
+{
+ while(SPU_STATUS2 & 0x7ff);
+}
+
+void SsInit()
+{
+ int x;
+
+ printf("Initializing SPU (Sound Synthesizer)...\n");
+
+ DPCR |= 0xB0000;
+
+ SPU_MVOL_L = 0x3fff;
+ SPU_MVOL_R = 0x3fff;
+
+ SPU_CONTROL = 0x0;
+ SsWait();
+
+ SPU_STATUS = 0x4; // Must be done, but not totally understood
+
+ while(SPU_STATUS2 & 0x7ff);
+
+ SPU_REVERB_L = 0x0;
+ SPU_REVERB_R = 0x0;
+
+ // All keys off
+
+ SPU_KEY_OFF1 = 0xFFFF;
+ SPU_KEY_OFF2 = 0xFFFF;
+
+ // Switch FM, reverb and noise off
+ SPU_KEY_FM_MODE1 = 0x0;
+ SPU_KEY_FM_MODE2 = 0x0;
+ SPU_KEY_NOISE_MODE1 = 0x0;
+ SPU_KEY_NOISE_MODE2 = 0x0;
+ SPU_KEY_REVERB_MODE1 = 0x0;
+ SPU_KEY_REVERB_MODE2 = 0x0;
+
+ // set CD master volume to 0 (mute it)
+ SPU_CD_MVOL_L = 0x0;
+ SPU_CD_MVOL_R = 0x0;
+
+ // set external input volume to 0 (mute it)
+ SPU_EXT_VOL_L = 0x0;
+ SPU_EXT_VOL_R = 0x0;
+
+ // set volume of all voices to 0 and adsr to 0,0
+
+ for(x = 0; x < 24; x++)
+ {
+ SsVoiceVol(x, 0, 0);
+ SsVoiceADSRRaw(x, 0, 0);
+ }
+
+ SsWait();
+
+ SPU_CONTROL = 0xC000; // SPU is on
+ SPU_REVERB_WORK_ADDR = 0xFFFE; // Reverb work address in SPU memory, 0x1fff * 8 = 0xFFF8
+
+ ss_vag_addr = SPU_DATA_BASE_ADDR;
+
+ printf("SPU/SS Initialized.\n");
+}
+
+// This implementation of SsUpload() was contributed by Shendo
+// It waits either for a period of time or for the status flags to be raised, whichever comes first.
+// This makes it work also on ePSXe, which never raises the status flags.
+
+void SsUpload(void *addr, int size, int spu_addr)
+{
+ unsigned short *ptr = addr;
+ int i;
+
+ while(size > 0)
+ {
+ SPU_STATUS = 4; // Sound RAM Data Transfer Control
+ SPU_CONTROL = SPU_CONTROL & ~0x30; // SPUCNT.transfer_mode = 0 (STOP)
+
+
+ for(i = 0; i < 100; i++)
+ if(((SPU_STATUS2 >> 4) & 3) == 0)break; // wait until SPUSTAT.transfer is 0 (STOP)
+
+ SPU_ADDR = spu_addr >> 3;
+
+ for(i = 0; i < 32; i++)
+ SPU_DATA = ptr[i];
+
+ SPU_CONTROL = (SPU_CONTROL & ~0x30) | 16; // SPUCNT.transfer_mode = 1 (MANUAL)
+
+ for(i = 0; i < 100; i++)
+ if(((SPU_STATUS2 >> 4) & 3) == 1)break; // wait until SPUSTAT.transfer is 1 (MANUAL)
+
+ while(SPU_STATUS2 & 0x400); // wait for transfer busy bit to be cleared
+
+ spu_addr += 64;
+ ptr += 32;
+ size-=64;
+ }
+}
+
+unsigned short SsFreqToPitch(int hz)
+{
+// Converts a normal samples per second frequency value in Hz
+// in a pitch value
+
+// i.e. 44100 -> 0x1000, 22050 -> 0x800
+
+ return (hz << 12) / 44100;
+}
+
+int SsReadVag(SsVag *vag, void *data)
+{
+ unsigned char *i = data;
+
+ if(strncmp(data, "VAGp", 4) != 0)
+ return 0;
+
+ vag->version = (i[4]<<24)|(i[5]<<16)|(i[6]<<8)|i[7];
+ vag->data_size = (i[12]<<24)|(i[13]<<16)|(i[14]<<8)|i[15];
+ vag->sample_rate = (i[16]<<24)|(i[17]<<16)|(i[18]<<8)|i[19];
+ memcpy(vag->name, &i[32], 16);
+ vag->data = &i[48];
+
+ return 1;
+}
+
+void SsUploadVagEx(SsVag *vag, int spu_addr)
+{
+ vag->spu_addr = spu_addr;
+ SsUpload(vag->data, vag->data_size, vag->spu_addr);
+ //spu_addr += vag->data_size;
+}
+
+void SsUploadVag(SsVag *vag)
+{
+ vag->spu_addr = ss_vag_addr;
+ SsUploadVagEx(vag, ss_vag_addr);
+ ss_vag_addr += vag->data_size;
+}
+
+void SsPlayVag(SsVag *vag, unsigned char voice, unsigned short vl,
+ unsigned short vr)
+{
+ SsVoicePitch(voice, SsFreqToPitch(vag->sample_rate));
+ SsVoiceStartAddr(voice, vag->spu_addr);
+ SsVoiceVol(voice, vl, vr);
+ SsKeyOn(voice);
+
+ vag->cur_voice = voice;
+}
+
+void SsStopVag(SsVag *vag)
+{
+ SsKeyOff(vag->cur_voice);
+ vag->cur_voice = -1;
+}
+
+void SsResetVagAddr()
+{
+ ss_vag_addr = SPU_DATA_BASE_ADDR;
+}
+
+void SsEnableCd()
+{
+ SPU_CONTROL |= 1;
+ CdSendCommand(CdlDemute, 0);
+}
+
+void SsEnableExt()
+{
+ SPU_CONTROL |= 2;
+}
+
+void SsCdVol(unsigned short left, unsigned short right)
+{
+ SPU_CD_MVOL_L = left;
+ SPU_CD_MVOL_R = right;
+}
diff --git a/libpsx/src/start/start.s b/libpsx/src/start/start.s
new file mode 100755
index 0000000..5c72f79
--- /dev/null
+++ b/libpsx/src/start/start.s
@@ -0,0 +1,322 @@
+# This is the start code for the PSXSDK.
+# It sets needed things up, and calls the setup and the main function.
+
+# This has to be linked in as the first object when using ld, so that it
+# appears at the start of the .text section.
+# If a ldscript is being used, it is sufficient to specify this as the first
+# startup object.
+
+# nextvolume (2014-03-17):
+# fixed possible stack corruption.
+
+ .align 16
+ .text
+.global _start
+#.global exit
+.extern call_atexit_callbacks
+#.global vblank_handler
+.extern vblank_handler
+.extern vblank_handler_callback
+
+.extern rcnt_handler
+.extern rcnt_handler_evfield
+.extern rcnt_handler_callback
+
+.extern run_bios
+.extern is_load_delay_ok
+.extern exit
+
+.extern get_cop0_status
+.extern set_cop0_status
+.extern get_cop0_epc
+#.global run_bios
+#.global is_load_delay_ok
+
+_start:
+ li $29, 0x801fff00 # Load stack pointer
+ li $k1, 0x1f800000 # set to hardware base
+
+ addiu $sp, $sp, -24
+ jal ResetEntryInt
+ nop
+
+ jal psxsdk_setup
+ nop
+
+ jal main
+ nop
+
+_real_exit:
+ la $a0, progtermfmt
+ move $a1, $v0
+
+ jal printf
+ nop
+
+ jal call_atexit_callbacks
+ nop
+
+inf_loop:
+ j inf_loop
+ nop
+
+# VBlank handler
+
+vblank_handler:
+ addi $sp, -120
+.set noat
+ sw $at, 0($sp)
+ mfhi $at
+ sw $at, 112($sp)
+ mflo $at
+ sw $at, 116($sp)
+.set at
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $s0, 60($sp)
+ sw $s1, 64($sp)
+ sw $s2, 68($sp)
+ sw $s3, 72($sp)
+ sw $s4, 76($sp)
+ sw $s5, 80($sp)
+ sw $s6, 84($sp)
+ sw $s7, 88($sp)
+ sw $t8, 92($sp)
+ sw $t9, 96($sp)
+ sw $gp, 100($sp)
+ sw $s8, 104($sp)
+ sw $ra, 108($sp)
+
+vblank_fire_user_handler:
+
+ la $t0, vblank_handler_callback
+ lw $t1, 0($t0)
+
+ addiu $sp, $sp, -24
+ jalr $t1
+ nop
+ addiu $sp, $sp, 24
+
+vblank_acknowledge_irq:
+ li $t0, 0x1f801070 # IPENDING
+
+ lw $t1, 0($t0)
+ nop
+ nop
+ xori $t1, $t1, 1 # Acknowledge VBlank IRQ
+ sw $t1, 0($t0)
+
+vblank_handler_end:
+.set noat
+ lw $at, 112($sp)
+ nop
+ mthi $at
+ lw $at, 116($sp)
+ nop
+ mtlo $at
+ lw $at, 0($sp)
+.set at
+ lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $s0, 60($sp)
+ lw $s1, 64($sp)
+ lw $s2, 68($sp)
+ lw $s3, 72($sp)
+ lw $s4, 76($sp)
+ lw $s5, 80($sp)
+ lw $s6, 84($sp)
+ lw $s7, 88($sp)
+ lw $t8, 92($sp)
+ lw $t9, 96($sp)
+ lw $gp, 100($sp)
+ lw $s8, 104($sp)
+ lw $ra, 108($sp)
+ addi $sp, 120
+ jr $ra
+ nop
+
+# Root counter handler
+
+rcnt_handler:
+ addi $sp, -120
+.set noat
+ sw $at, 0($sp)
+ mfhi $at
+ sw $at, 112($sp)
+ mflo $at
+ sw $at, 116($sp)
+.set at
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $s0, 60($sp)
+ sw $s1, 64($sp)
+ sw $s2, 68($sp)
+ sw $s3, 72($sp)
+ sw $s4, 76($sp)
+ sw $s5, 80($sp)
+ sw $s6, 84($sp)
+ sw $s7, 88($sp)
+ sw $t8, 92($sp)
+ sw $t9, 96($sp)
+ sw $gp, 100($sp)
+ sw $s8, 104($sp)
+ sw $ra, 108($sp)
+
+rcnt_fire_user_handler:
+ la $t0, rcnt_handler_callback
+ lw $t1, 0($t0)
+
+ addiu $sp, $sp, -24
+ jalr $t1
+ nop
+ addiu $sp, $sp, 24
+
+rcnt_acknowledge_irq:
+ li $t0, 0x1f801070 # IPENDING
+ la $t2, rcnt_handler_evfield
+
+ lw $t1, 0($t0)
+ nop
+ nop
+ xor $t1, $t1, $t2 # Acknowledge Root Counter IRQ
+ sw $t1, 0($t0)
+
+rcnt_handler_end:
+.set noat
+ lw $at, 112($sp)
+ nop
+ mthi $at
+ lw $at, 116($sp)
+ nop
+ mtlo $at
+ lw $at, 0($sp)
+.set at
+ lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $s0, 60($sp)
+ lw $s1, 64($sp)
+ lw $s2, 68($sp)
+ lw $s3, 72($sp)
+ lw $s4, 76($sp)
+ lw $s5, 80($sp)
+ lw $s6, 84($sp)
+ lw $s7, 88($sp)
+ lw $t8, 92($sp)
+ lw $t9, 96($sp)
+ lw $gp, 100($sp)
+ lw $s8, 104($sp)
+ lw $ra, 108($sp)
+ addi $sp, 120
+ jr $ra
+ nop
+
+get_cop0_status:
+ mfc0 $v0, $12
+ jr $ra
+ nop
+
+set_cop0_status:
+ mtc0 $a0, $12
+ jr $ra
+ nop
+
+get_cop0_epc:
+ mfc0 $2, $14
+ jr $ra
+ nop
+
+run_bios:
+ j 0xbfc00000
+ nop
+
+is_load_delay_ok:
+ li $t2, 0
+ li $t0, 0x0adecade
+ la $t1, isldo_data
+ .word 0x8d2a0000 #lw t2,0(t1)
+ beq $t0, $t2, load_delay_not_ok
+ nop
+load_delay_ok:
+ li $v0, 1
+ jr $ra
+ nop
+load_delay_not_ok:
+ li $v0, 0
+ jr $ra
+ nop
+
+exit:
+ move $s0, $a0
+
+ la $a0, called_exit
+ move $a1, $s0
+
+ addiu $sp, $sp, -24
+ jal printf
+ nop
+ addiu $sp, $sp, 24
+
+ move $v0, $s0
+
+ j _real_exit
+ nop
+
+ .align 16
+ .data
+
+called_exit:
+ .string "Called exit(%d)\n"
+
+progtermfmt:
+ .string "Program terminated with return value %d\n"
+
+isldo_data:
+ .word 0x0adecade
diff --git a/libpsx/src/syscalls.s b/libpsx/src/syscalls.s
new file mode 100644
index 0000000..305d03e
--- /dev/null
+++ b/libpsx/src/syscalls.s
@@ -0,0 +1,344 @@
+# PSX SDK System calls file
+
+.text
+
+# Console functions
+
+.global bios_putchar
+.global bios_puts
+.global printf
+.extern __stdio_direction
+.extern sio_printf
+
+bios_putchar:
+ li $9, 0x3c
+ j 0xa0
+ nop
+
+bios_puts:
+ li $9, 0x3e
+ j 0xa0
+ nop
+
+printf:
+ la $9, __stdio_direction
+ lw $10, 0($9)
+ beq $10, $0, use_bios_printf
+ nop
+ j sio_printf
+ nop
+use_bios_printf:
+ li $9, 0x3f
+ j 0xa0
+ nop
+
+# Memory functions
+# These are not used by PSXSDK, and are here just for completeness.
+
+.global InitHeap
+.global FlushCache
+
+InitHeap:
+ li $9, 0x39
+ j 0xa0
+ nop
+
+FlushCache:
+ li $9, 0x44
+ j 0xa0
+ nop
+
+# GPU functions
+.global GPU_dw
+.global mem2vram
+.global SendGPU
+.global GPU_cw
+.global GPU_cwb
+.global SendPrimitive
+.global GetGPUStatus
+
+GPU_dw:
+ li $9, 0x46
+ j 0xa0
+ nop
+
+mem2vram:
+ li $9, 0x47
+ j 0xa0
+ nop
+
+.global ResetEntryInt
+
+ResetEntryInt:
+ li $9, 0x18
+ j 0xb0
+ nop
+
+# ???
+.global GetKernelDate
+.global GetKernelRomVersion
+.global GetRamSize
+
+GetKernelDate:
+ li $9, 0xb4
+ li $4, 0
+ j 0xa0
+ nop
+
+GetKernelRomVersion:
+ li $9, 0xb4
+ li $4, 2
+ j 0xa0
+ nop
+
+GetRamSize:
+ li $9, 0xb4
+ li $4, 5
+ j 0xa0
+ nop
+
+# Event functions
+.global OpenEvent
+.global EnableEvent
+.global CloseEvent
+.global DisableEvent
+.global WaitEvent
+.global TestEvent
+.global DeliverEvent
+
+OpenEvent:
+ li $9, 0x08
+ j 0xb0
+ nop
+
+EnableEvent:
+ li $9, 0x0c
+ j 0xb0
+ nop
+
+CloseEvent:
+ li $9, 0x09
+ j 0xb0
+ nop
+
+DisableEvent:
+ li $9, 0x0d
+ j 0xb0
+ nop
+
+DeliverEvent:
+ li $9, 0x07
+ j 0xb0
+ nop
+
+WaitEvent:
+ li $9, 0x0a
+ j 0xb0
+ nop
+
+TestEvent:
+ li $9, 0x0b
+ j 0xb0
+ nop
+
+# File I/O functions
+.global open
+.global lseek
+.global read
+.global write
+.global close
+.global cd
+.global firstfile
+.global nextfile
+.global rename
+.global remove
+
+open:
+ li $9, 0x32
+ j 0xb0
+ nop
+
+lseek:
+ li $9, 0x33
+ j 0xb0
+ nop
+
+read:
+ li $9, 0x34
+ j 0xb0
+ nop
+
+write:
+ li $9, 0x35
+ j 0xb0
+ nop
+
+close:
+ li $9, 0x36
+ j 0xb0
+ nop
+
+cd:
+ li $9, 0x40
+ j 0xb0
+ nop
+
+firstfile:
+ li $9, 0x42
+ j 0xb0
+ nop
+
+nextfile:
+ li $9, 0x43
+ j 0xb0
+ nop
+
+rename:
+ li $9, 0x44
+ j 0xb0
+ nop
+
+remove:
+ li $9, 0x45
+ j 0xb0
+ nop
+
+# Exception / Interrupt functions
+
+.global EnterCriticalSection
+.global ExitCriticalSection
+.global SysEnqIntRP
+.global SysDeqIntRP
+
+EnterCriticalSection:
+ li $a0, 1
+ syscall
+ nop
+ jr $ra
+ nop
+
+ExitCriticalSection:
+ li $a0, 2
+ syscall
+ nop
+ jr $ra
+ nop
+
+SysEnqIntRP:
+ li $9, 0x02
+ j 0xc0
+ nop
+
+SysDeqIntRP:
+ li $9, 0x03
+ j 0xc0
+ nop
+
+# Filesystem functions
+
+.global _96_init
+.global _96_remove
+.global _bu_init
+
+_96_init:
+ li $9, 0x71
+ j 0xa0
+ nop
+
+_96_remove:
+ li $9, 0x72
+ j 0xa0
+ nop
+
+_bu_init:
+ li $9, 0x70
+ j 0xa0
+ nop
+
+# Executable loading functions
+
+.global LoadExec
+
+LoadExec:
+ li $9, 0x51
+ j 0xa0
+ nop
+
+# Memory card routines
+
+.global InitCARD
+.global StartCARD
+.global StopCARD
+.global _card_info
+.global _card_load
+.global _card_auto
+.global _card_write
+.global _card_read
+.global _card_status
+.global _new_card
+
+InitCARD:
+ li $9, 0x4a
+ j 0xb0
+ nop
+
+StartCARD:
+ li $9, 0x4b
+ j 0xb0
+ nop
+
+StopCARD:
+ li $9, 0x4c
+ j 0xb0
+ nop
+
+_card_info:
+ li $9, 0xab
+ j 0xa0
+ nop
+
+_card_load:
+ li $9, 0xac
+ j 0xa0
+ nop
+
+_card_auto:
+ li $9, 0xad
+ j 0xa0
+ nop
+
+_card_write:
+ li $9, 0x4e
+ j 0xb0
+ nop
+
+_card_read:
+ li $9, 0x4f
+ j 0xb0
+ nop
+
+_new_card:
+ li $9, 0x50
+ j 0xb0
+ nop
+
+_card_status:
+ li $9, 0x5c
+ j 0xb0
+ nop
+
+# Device functions
+
+.global PrintInstalledDevices
+
+PrintInstalledDevices:
+ li $9, 0x49
+ j 0xb0
+ nop
+
+.global BIOSWarmReboot
+
+BIOSWarmReboot:
+ li $9, 0xa0
+ nop
+ j 0xa0
diff --git a/libpsx/src/util.c b/libpsx/src/util.c
new file mode 100644
index 0000000..a9c7921
--- /dev/null
+++ b/libpsx/src/util.c
@@ -0,0 +1,42 @@
+// util.c
+// PSXSDK utility functions
+
+// This is not a core part of the PSXSDK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <psxutil.h>
+
+const char *psxsdk_btn_names[] =
+ { "L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross",
+ "Square", "Select", "Res1", "Res2", "Start",
+ "Up", "Right", "Down", "Left"};
+
+char *PSX_GetButtonName(unsigned short button, char *out, unsigned int out_len)
+{
+ int x;
+
+ if(out_len)out[0] = 0;
+
+ for(x = 0; x < 16; x++)
+ {
+ if(button & (1<<x))
+ {
+ strncat(out, psxsdk_btn_names[x], out_len);
+ out_len -= strlen(out);
+ strncat(out, "&", out_len);
+ out_len--;
+ }
+ }
+
+ if(strlen(out))
+ {
+ if(out[strlen(out) - 1] == '&')
+ out[strlen(out) - 1] = 0;
+ }
+ else
+ strncpy(out, "None", out_len);
+
+ return out;
+}
diff --git a/license.txt b/license.txt
new file mode 100644
index 0000000..6966c65
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,40 @@
+I don't really know how to write legalese, so I will say it in simple words:
+
+You can use this library for any project, commercial and non-commercial,
+open-source and closed-source. But if you modify the library, you must
+redistribute the source for the modifications you did to it.
+Not doing that constitutes an infringement of this license.
+You are not obliged to redistribute the source code of this library if it
+was not modified at all by you or anyone related to you.
+
+There is no advertising clause; you aren't obliged to mention this library
+in any documentation of your work using it; however, it would be a nice gesture
+if you did so.
+
+These terms were written to not make people close this work which was released
+for all to share. In fact, no use is otherwise restricted.
+
+This license also applies to the following tools:
+bin2c, bmp2tim, getpsxiso, systemcnf
+
+Some of the tools have a different license:
+
+for exefixup it is GPL version 2 or newer
+
+Some of the libraries have a different license:
+
+libfixmath is licensed under the MIT license
+libmeidogte is licensed under version 2 of the Mozilla Public License
+
+Some of the examples have a different license:
+
+gtecube is licensed under version 2 of the Mozilla Public License
+
+some of the other tools are derived from public sources with no clear licensing, but it
+is assumed that they were public domain. In all cases, they are attributed
+to their original authors.
+
+The PSXSDK examples are not under this license and released directly into the Public Domain,
+which means you can do everything with them and you do not have to preserve attribution.
+
+-- Giuseppe Gatta
diff --git a/licenses/Makefile b/licenses/Makefile
new file mode 100644
index 0000000..49dc29f
--- /dev/null
+++ b/licenses/Makefile
@@ -0,0 +1,7 @@
+# Makefile which installs the license files
+
+include ../Makefile.cfg
+
+install:
+ mkdir -p $(TOOLCHAIN_PREFIX)/share/licenses
+ cp -rv *.dat $(TOOLCHAIN_PREFIX)/share/licenses
diff --git a/licenses/infoeur.dat b/licenses/infoeur.dat
new file mode 100644
index 0000000..69193bf
--- /dev/null
+++ b/licenses/infoeur.dat
Binary files differ
diff --git a/licenses/infojap.dat b/licenses/infojap.dat
new file mode 100644
index 0000000..43cb406
--- /dev/null
+++ b/licenses/infojap.dat
Binary files differ
diff --git a/licenses/infousa.dat b/licenses/infousa.dat
new file mode 100644
index 0000000..a0ed761
--- /dev/null
+++ b/licenses/infousa.dat
Binary files differ
diff --git a/misc/Makefile b/misc/Makefile
new file mode 100644
index 0000000..295732b
--- /dev/null
+++ b/misc/Makefile
@@ -0,0 +1,16 @@
+include ../Makefile.cfg
+
+all:
+ sh genscripts.sh $(TOOLCHAIN_PREFIX)
+
+clean:
+ rm -f playstation.x psx-gcc psx-g++
+
+distclean: clean
+
+install: all
+ mkdir -p $(TOOLCHAIN_PREFIX)/bin
+ mkdir -p $(TOOLCHAIN_PREFIX)/mipsel-unknown-elf/lib/ldscripts
+ cp -v psx-gcc $(TOOLCHAIN_PREFIX)/bin
+ cp -v psx-g++ $(TOOLCHAIN_PREFIX)/bin
+ cp -v playstation.x $(TOOLCHAIN_PREFIX)/mipsel-unknown-elf/lib/ldscripts
diff --git a/misc/genscripts.sh b/misc/genscripts.sh
new file mode 100755
index 0000000..537c847
--- /dev/null
+++ b/misc/genscripts.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# This shell script will generate the playstation.x linker script, and the psx-gcc and psx-elf2x shell scripts.
+
+# You have to pass the PREFIX of the toolchain as the first argument of this shell script
+
+echo "/*
+ * Linker script to generate an ELF file
+ * that has to be converted to PS-X EXE.
+ */
+
+TARGET(\"elf32-littlemips\")
+OUTPUT_ARCH(\"mips\")
+
+ENTRY(\"_start\")
+
+SEARCH_DIR(\"$1/lib\")
+STARTUP(start.o)
+INPUT(-lpsx -lgcc)
+
+SECTIONS
+{
+ . = 0x80010000;
+
+ .text ALIGN(4) :
+ {
+ *(.text*)
+ }
+
+ .rodata ALIGN(4) :
+ {
+ *(.rodata)
+ }
+
+ .data ALIGN(4) :
+ {
+ *(.data)
+ }
+
+ .ctors ALIGN(4) :
+ {
+ *(.ctors)
+ }
+
+ .dtors ALIGN(4) :
+ {
+ *(.dtors)
+ }
+
+ .bss ALIGN(4) :
+ {
+ *(.bss)
+ }
+
+ __text_start = ADDR(.text);
+ __text_end = ADDR(.text) + SIZEOF(.text);
+
+ __rodata_start = ADDR(.rodata);
+ __rodata_end = ADDR(.rodata) + SIZEOF(.rodata);
+
+ __data_start = ADDR(.data);
+ __data_end = ADDR(.data) + SIZEOF(.data);
+
+ __ctor_list = ADDR(.ctors);
+ __ctor_end = ADDR(.ctors) + SIZEOF(.ctors);
+
+ __dtor_list = ADDR(.dtors);
+ __dtor_end = ADDR(.dtors) + SIZEOF(.dtors);
+
+ __bss_start = ADDR(.bss);
+ __bss_end = ADDR(.bss) + SIZEOF(.bss);
+
+ __scratchpad = 0x1f800000;
+}
+" > playstation.x
+
+echo "#!/bin/sh
+mipsel-unknown-elf-gcc -D__PSXSDK__ -fno-strict-overflow -fsigned-char -msoft-float -mno-gpopt -fno-builtin -G0 -I$1/include -T $1/mipsel-unknown-elf/lib/ldscripts/playstation.x \$*"> psx-gcc
+chmod +x psx-gcc
+echo "#!/bin/sh
+mipsel-unknown-elf-g++ -D__PSXSDK__ -fno-strict-overflow -fsigned-char -msoft-float -mno-gpopt -fno-builtin -G0 -I$1/include -T $1/mipsel-unknown-elf/lib/ldscripts/playstation.x -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-use-cxa-atexit \$*" > psx-g++
+chmod +x psx-g++
diff --git a/modplay.txt b/modplay.txt
new file mode 100644
index 0000000..695a79d
--- /dev/null
+++ b/modplay.txt
@@ -0,0 +1,42 @@
+libmodplay README
+-------------------------
+libmodplay is a library which plays music module files on your PlayStation.
+You can use it to play music in your productions.
+This means you can grab many module files from the internet and use them very easily and (almost) transparently.
+Control is provided over Sound RAM addresses and base voices which allows playing a music and playing your own sound effects without resorting to guesses and ugly hacks.
+
+Little tutorial
+-------------------------
+The music module file you want to use must be loaded in memory. How to do this will not be explained here. You will also need to initialize the SPU of the PlayStation before you use the MODPlay() function.
+
+Pass to MODLoad() as its only argument the pointer to the memory area in which loaded the music module file. MODLoad() will then return a pointer to ModMusic structure (ModMusic *). As all the data from the module file was copied to the structure you can free or otherwise use for another purpose the memory area whose pointer you passed to MODLoad().
+
+At this point you must load the samples of the music module to Sound RAM. There are two ways of doing this:
+1) Using MODUploadSamples(). This uses the samples in PCM data from the music module data, and before
+ being used by the SPU, they need to be converted at runtime (by the PS CPU) to ADPCM. This takes
+ a lot of time and the resulting quality is very poor. (I needed to make it not very dog slow and if anything I'm a beginner at codecs -nextvolume)
+2) Using MOD4PSX_Upload(). This loads the samples from preconverted data. The samples here are
+ directly in ADPCM, and this way is both very fast and high quality. The only shortcoming is that
+ you need to use more RAM, but this problem is non-existent if you program in certain ways,
+ for example by loading data from the CD filesystem into a buffer. You could first load the MOD,
+ and *then* load the ADPCM sample data. An ADPCM sample data pack file is obtained from a music
+ module file by using the mod4psx tool included in the PSXSDK.
+ You pass the pointer to the memory area where this pack file is loaded to MOD4PSX_Upload() as
+ first argument.
+
+ The base_addr argument has the same meaning for both uploading functions; it specifies the
+ Sound RAM address to start uploading to. Then the two functions return the Sound RAM address
+ after the uploaded sample data. base_addr should be a multiple of 8 due to hardware limitations.
+
+After doing this, to play your music you have to call MODPlay(), giving the pointer to the ModMusic structure as its only argument, fifty/sixty times a second. You can do so by setting up a counter which is increased every timeVSync/VBlank happens (this means it is slightly slower on PAL if done in this way, but it's the easiest method). Check the modplayer example for more information.
+
+When you want to stop playing the music module, call MODStop() in the same way as you called MODPlay().
+
+Basically, this is what you have to do. It is not hard at all, just remember that the default base sound voice is 0, and that you don't need to play anything on voices 0-7 yourself, or things will not work well. Eight voices are used because this is a limit of the Protracker MOD format.
+You can change the number of the base sound voice to another value by using the MODSetBaseVoice() function before using MODPlay().
+
+ISSUES
+--------------------
+- With ProTracker MODs, sample looping is not implemented yet when converting samples at runtime and many effects aren't implemented yet
+ so some modules could sound differently to how they should sound.
+ Always use MODs with few effects.
diff --git a/nobios.txt b/nobios.txt
new file mode 100644
index 0000000..b24bd83
--- /dev/null
+++ b/nobios.txt
@@ -0,0 +1,7 @@
+NOBIOS
+-----
+Adapted functions:
+SetVBlankHandler();
+RemoveVBlankHandler();
+GsIsDrawing()/GsIsWorking()
+GsDrawList() \ No newline at end of file
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..8086d8b
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,287 @@
+PSXSDK 0.6.2
+ReadMe and FAQ
+Last updated: April 10th 2019
+-----------------------------
+
+What is PSXSDK?
+
+PSXSDK is an unofficial and homebrewed software development kit for the Sony PlayStation(TM).
+Its programming tools (compiler, assembler, linker, etc.) are based on GNU Binutils and GNU
+Compiler Collection (GCC) while the PlayStation-specific tools, which you need to convert data
+to PSX format, were either written from scratch or adapted from already existing open source programs.
+
+It is expected that you are already familiar with programming.
+If you want to learn how to program, I recommend starting programming for the operating system
+your computer uses and not here.
+
+This readme is structured as a FAQ which also contains information which is not exclusive to the PSXSDK,
+but that is generally informative.
+
+Q: What do I need to run my programs on my PlayStation console?
+
+A: There are several methods to do that, either a modchip, a boot disk, a cheating device
+like Caetla, or the "swap trick".
+
+The "modchip" method involves soldering a chip on the motherboard of your PlayStation to make it
+think it's reading an original licensed disc. The kind of modchip depends on the model of your console,
+and they are quite hard to find nowadays (as of 2010). You might already have one, as it was very
+common to install it in many parts of the world.
+
+I might be actually telling you to ignore your laws (in case you have EUCD and DMCA), and I recommend
+to do it. The constant eroding of our rights as citizens is getting very annoying, and these
+laws need to be fought. Let's not be hypocrites.
+Big money influences law (TM).
+
+The "boot disk" method uses a specially-made CD-ROM which looks like it is an original licensed disc
+to the PlayStation. Once booted they show you a menu where you can boot an unlicensed disc.
+You might be able to still find one for sale.
+
+The "cheating device" method was very used back in the golden days of the PlayStation scene.
+I have never used this method so I cannot describe it here. Search for "caetla" on your favourite
+search engine and something interesting about that should come up.
+
+The "swap trick" consists in first putting an original licensed disc in the PlayStation, so that
+the PlayStation can authenticate, then when the drive is still spinning you replace it with an
+unlicensed disc, and the PlayStation boots the disc as it already authenticated earlier.
+The exact method of the "swap trick" varies between different models of the console.
+It ruins your CD-ROM drive in the long run and spare PSX CD-ROM drives aren't very easy to find
+(maybe harder to find than entire consoles), so I recommend to use something else if you can.
+Search for this on your favourite search engine, something will surely come up.
+
+On SCPH1001 PlayStations (Early American models) there seems to be an easier way to do the swap trick, also called audio menu exploit.
+Make the SCPH1001 PlayStation go into the BIOS menu by not inserting any CD,
+then go to the cd player, let it read an original PS1 disc until it stops spinning,
+swap the disc with a burned CD-R disc, and exit the cd player.
+
+This trick might also work on early Japanese consoles but I'm not sure of that.
+
+Q: How do I get started?
+
+A: In most cases, you will simply need one of the precompiled toolchains tarballs which you can find
+on the PSXSDK website (http://unhaut.fav.cc/psxsdk). Extract them so that the PSXSDK can
+be found at /usr/local/psxsdk and you're ready.
+
+If you want to do it the hard way, there is no precompiled tarball for your operating system or
+you want to help in developing the PSXSDK, read below on how to build it from sources.
+
+Q: How do I compile a program?
+
+A: This is easy. It is done almost as you do it usually, but with an additional step:
+
+psx-gcc -o myprogram myprogram.c
+elf2exe myprogram myprogram.exe
+
+Why the additional step? It is needed because the GNU compiler outputs an ELF executable file,
+which can't be run on the PlayStation. elf2exe converts that ELF file to a PS-X EXE, which
+is the PlayStation's executable format, and which can be booted.
+
+Q: How do I make a CDROM image?
+
+A: I will first describe how to make your executable boot.
+There are two ways to make your executable boot: you either name it "PSX.EXE" and you
+put it in the CDROM filesystem's root directory, or you set a file named "SYSTEM.CNF" up
+which describes a bit of information about your executable.
+
+A SYSTEM.CNF file looks like this:
+
+BOOT = cdrom:PROGRAM.EXE;1
+TCB = 4
+EVENT = 16
+STACK = 801FFFF0
+
+The BOOT field contains the filename of your program (in this case PROGRAM.EXE in the
+root directory of the CDROM filesystem). I would advise you to not touch the other fields.
+Modifying STACK is even useless (as the starting address of the stack is reset by the PSXSDK
+library to 0x801FFFF0)
+
+Now, you can make the ISO9660 filesystem for the CDROM with any program which does that.
+This, for example, is the command you would use to do it with the cdrtools:
+
+mkisofs -o test.iso -V TEST -sysid PLAYSTATION cd_root
+
+Then you will have to use mkpsxiso to convert the ISO image to a format the PlayStation understands
+and to license it. mkpsxiso outputs a .BIN/.CUE pair, which is supported by most CD burning
+applications.
+NOTE: Some Linux distributions (like Debian and Mint) don't provide mkisofs, but genisoimage instead.
+ Replace the command name in the command line and that's it.
+
+mkpsxiso test.iso test.bin /usr/local/psxsdk/misc/infousa.dat
+
+This will create test.bin and test.cue, and the license applied to the image will be American.
+
+Now you can burn the .BIN/.CUE pair with your favourite burning application.
+
+Q: Where can I find the function reference for the PSXSDK?
+
+A: You can find it either in /usr/local/psxsdk/misc/docs or in the docs subdirectory in the source
+code archive.
+
+Q: Are there any examples which show how to use the PSXSDK library?
+
+A: Yes. Download the examples archive from the PSXSDK website and compile the examples in it.
+In this way you can also test that your PSXSDK compiler is working correctly.
+You can build them all by running ``make build_examples''
+
+Q: What does PSXSDK support?
+
+A: It can use the GPU (or GS, Graphic Synthesizer), the SPU, handle the VBlank Interrupt, handle
+the joysticks and read files from the CDROM drive. Which is more than enough to do a 2D game.
+
+Q: What is missing from PSXSDK?
+
+A: Root counter support and a lot more...
+Even if the PlayStation was very common back in its golden days, there is scarce documentation about it.
+Since version 0.6.2 there is preliminary Geometry Transformation Engine (GTE) support provided by libmeidogte
+
+Q: Why does the C library appear incomplete?
+
+A: Many standard C library functions are wrapped around their implementation in the BIOS which keeps
+code size low and eases implementation, but this also means that they have less features than
+most C libraries of today. That isn't a big problem, because for games you don't need a lot of features.
+Anyway, you can modify the PSXSDK to remove the wrapper and use your functions.
+The PSXSDK already does that for BIOS functions which were found not working or too buggy (like memcpy).
+
+Q: Help! My PlayStation crashed / something odd appeared on screen / other hardware bug
+
+A: PSXSDK was primarily tested on a PAL SCPH-102 PSOne, on SCPH-5552, SCPH-7002 and SCPH-9002 PlayStations and on the PCSX emulator.
+There are probably several hardware quirks and oddities I've not accounted for but which happen
+on other models of the console. Please send an email if something like that happens.
+Be sure to read realhw.txt in the documentation directory first, though, as it might be
+an easily fixable error on your part.
+
+Q: What program can I use to convert my images to PlayStation format?
+
+A: You can use bmp2tim which is included in the PSXSDK or any program which converts an image to
+PlayStation TIM format. It is a fairly standard format in the PlayStation field.
+
+Q: What program do I use in case I want to convert sound?
+
+A: You can use the included wav2vag or any other program which converts to that format.
+As it is the case for TIM, VAG is a quite standard format in the PlayStation environment.
+
+VABs are just find compilations of more VAG files.
+
+Q: Can I sell a game I make with my PSXSDK?
+
+A: Yes, as you are not infringing any copyright.
+
+Q: I want to use Caetla to upload and test programs on my PlayStation, but I cannot find a version of CatFlap for an operating system which is not DOS or Windows. Are there?
+
+A: Very recently Fabio Battaglia (hkzlabs) released his CatFlap for Linux. You can use that on Linux, and use its source
+code as a starting point for a port to other operating systems.
+
+Q: When uploading and running programs with CatFlap, they hang after some PSXSDK initialization messages.
+How can I make them not hang? I cannot run anything!
+
+A: Insert a CD into the drive of your PlayStation. It doesn't have to be a PlayStation CD, any CD is good.
+This happens due to the initialization routines of the CDROM subsystem. Hopefully it will be fixed someday.
+
+Q: How can I change the writing and the logo at the "Licensed by Sony" PlayStation bootscreen?
+
+A: That information is contained inside the license file that you use to license the CD-ROM image that you burn.
+Thus, to modify the information you must use the "lictool" program included in the PSXSDK tools.
+lictool modifies various information contained in the license file such as the writing, the logo, etc.
+
+For example, to output a new modified American license file which uses your logo contained in new.tmd:
+
+lictool /usr/local/psxsdk/share/licenses/infousa.dat my_new_license_file.dat -tmd=new.tmd
+
+Remember to use my_new_license_file.dat when you use mkpsxiso, otherwise you will use the standard
+American license file, and your new logo won't appear!
+
+Logos are in TMD format, the format for 3D models in Sony's original development kit.
+
+Q: My music module sounds wrong or weird when I play it with libmodplay
+
+A: Most music module formats have a lot of built-in effects, which are often poorly documented,
+very complex to implement and which are often thought for personal computer hardware which is less
+limited than the PlayStation SPU in some aspects. Luckily most modules don't really use them
+or sound quite right when those effects are not implemented.
+
+Q: I heard that it is possible to make the PlayStation read CD-RW discs (CD-rewritable). Is this true?
+
+A: Yes, it is. But it is only really usable if you want to do hardware programming tests, as the amount
+that the CD drive of your PlayStation may be able to read might be around 128-150 kilobytes. You will
+not be able to read original PlayStation games or CD-Rs, and if you try to do it, your laser pickup might
+get stuck and you may have to unblock it by unscrewing it and sliding it with your hands...
+With a relatively good laser and very good tuning you might be even able to play full fledged games.
+
+To read CD-RWs on later model PlayStation/cd drives you have to tune the potentiometer on the CD drive
+from its original position to 12-13 hours. It actually sort of looks like a clock. Remember the original
+position to not ruin anything. Use a precision screwdriver to tune the potentiometer.
+This will stress the laser in the CD drive more than it is in normal operation, and it will shorten its life.
+
+The trick to tuning the potentiometer correctly is burning an audio track on the CD-RW and playing the audio track
+in the PlayStation CD player. If the audio track plays smoothly enough, it will be able to read CD-RWs.
+
+You may need several tries before you succeed booting a disk, this happens due to the extensive read checks done
+by the PlayStation BIOS when booting a game.
+
+This is my (Giuseppe Gatta's) experience, and it might work much better on your PlayStation/PS cd drive
+or it might work much worse. PlayStation cd drives are very finicky, I myself have PlayStations which read
+like new and some which almost do not read at all. The CD drive is the lowest quality item inside
+a PlayStation.
+
+On the other hand this is the cheapest way to test things on your modded PlayStation.
+
+Q: I don't use double buffering in my program/game. Nothing is shown on the emulator but it displays fine
+ on the real hardware. Where is the issue?
+
+A: You are using a buggy GPU plugin. If you're using version 1.0.16 of the P.E.Op.S SoftX Driver or most other
+P.E.Op.S GPU plugins, update to P.E.Op.S SoftX Driver 1.0.18 and the problem should go away.
+
+Q: What is a .PSF music file?
+
+A: A .PSF music file is in the Portable Sound Format which is used to store video game music data.
+Actually the .PSF just contains a tiny bit of information data in its header and then a compressed executable
+which can be executed by an emulator (or a video game console). A PSF player is just a stripped-down emulator,
+which supports only the SPU and the executable inside the PSF is an executable hacked to play only music.
+Originally it was meant only for the PlayStation but now there are music files in this platform-indipendent format
+from many consoles. You can play a .psf music just by using your console or emulator. Use the psfex tool shipped
+with the PSXSDK, extract the .exe from the PSF and then run the executable.
+More info here: http://www.neillcorlett.com/psf/
+
+Q: Why are filenames limited to the MSDOS-like 8.3 naming convention?
+
+A: Because the ISO-9660 filesystem used on PlayStation CDs has the 8.3 limit for filenames.
+It is plain ISO-9660 without any extension like Joliet or Rock Ridge, which are commonly added on CDs meant
+to be read on computers to overcome the filename limit and to add new features.
+The PSXSDK can make use of TRANS.TBL files in the directories of your CD to emulate long filenames.
+TRANS.TBL is a normal text file which assigns long filenames to normal ISO9660 filenames.
+Its rows look like this:
+F SYSTEM.CNF;1 system.cnf
+
+What this row does is assign to long filename system.cnf the short filename SYSTEM.CNF;1
+'F' denotes that system.cnf is a file, otherwise 'D' denotes directories.
+
+Good ISO image making tools will support the automatic creation of a TRANS.TBL file for each directory at image creation.
+For instance, adding the -T parameter to your mkisofs command line makes mkisofs do just that.
+
+To make fopen() use long filenames you will have to use the cdromL: pseudo device instead of cdrom:
+Spaces are allowed in paths and both the slash and the back slash can be used to separate directories.
+Examples: cdromL:/Path To/My Filename , cdromL:\Path To\This Name
+
+There is a perfomance penalty when using long filenames because doing that requires reading the
+TRANS.TBL for every directory which is encountered.
+
+firstfile() does not support long filenames (yet) and open() does not support them, either.
+
+Q: I'm running <linux distribution> and audio doesn't work in PCSX!
+A: Many new Linux distributions are using PulseAudio. Run 'padsp pcsx' instead of 'pcsx'.
+
+Q: Why is this SDK called PSXSDK? The PSX is a DVR+PS2 hybrid released by Sony in Japan!
+A: Almost nobody knows about the Japanese PSX from 2004, and on top of that, it was a marketing flop.
+ Seriously, PSX ('PlayStation eXperimental') is the name the original PlayStation went by during development and it continued being called like that later. The name stuck and it is here to stay.
+
+Q: Can I use UPX to pack an executable I made with PSXSDK?
+A: Sure, you can. Due to a technicality of elf2exe, you need to specify --force on the UPX command line.
+ It seems to work well, but I did no extensive testing, so it is at your own risk.
+
+Q: Why do programs not work on the ePSXe/pSX/... emulators?
+A: Despite popular belief, ePSXe and pSX are not as accurate as it is thought.
+ It is recommended to use PCSX Reloaded for testing.
+ The rule of thumb is that when something works fine on real hardware, and the
+ emulator freezes or does something unexpected, it's the emulator's fault.
+
+Written by Giuseppe Gatta
+E-mail: tails92@gmail.com
diff --git a/realhw.txt b/realhw.txt
new file mode 100644
index 0000000..a262346
--- /dev/null
+++ b/realhw.txt
@@ -0,0 +1,136 @@
+Notes to make games run on real hardware
+--------------------
+Emulators are often inaccurate or can't emulate some quirk of the real
+hardware easily. This is a list of what you mustn't do and what you
+should do in order to fix the problem.
+
+Some quirks might even be present only on some revisions of the PlayStation
+hardware, but the goal is that something has to run on every revision, and so
+one has to respect all the tips, regardless of model.
+So if you want to add something to the list, also specify the model it happens
+on. Do not forget to include your name or nickname.
+
+ALL MODELS:
+
+The most noticeable quirk is that the GPU in emulators finishes to draw instantly,
+while on the real hardware the GPU has its own speed and so you must wait for
+it to finish drawing. The result of this is that on the emulator your program will
+run just fine, while on the real hardware the graphics will be entirely scrambled
+
+The way to fix this is to add
+
+while(GsIsDrawing());
+
+after calls like GsDrawList(), LoadImage(), MoveImage(), etc.
+This ensures that your program will first check if the GPU has finished drawing
+before doing anything else.
+
+Why doesn't the SDK do this automatically? It is designed more or less to do what
+you want to do. If you want to somewhat exploit this quirk to make something nice,
+you can.
+
+You can also call GsSetAutoWait() after GsInit(), which removes the need
+for checking the result of the GsIsDrawing() function, and which makes GsDrawList()
+wait until completion.
+
+********************************************************************
+
+Controller vibration (pad_enable_vibration() and pad_set_vibration() )
+
+On controllers which are not DualShock vibration will not work. This is taken for granted.
+If you enabled vibration, and set vibration values, you unplug your controller and you plug it again,
+there will be no vibration as vibration data is not kept by the console and then sent to the controller,
+but it is sent by the console and kept by the controller. Thus when the controller is detached it loses
+its memory about vibration.
+
+A way to work around this is enabling vibration before using pad_set_vibration().
+
+Another way to work around this would be detecting when the pad is detached and when it is plugged
+again, and if it's plugged again enable vibration and set it at its past values
+(you can check pad type, 0xFF = no pad, 0x41 = normal pad, etc.)
+The second solution is the best one but the first is much simpler.
+
+For pad_set_vibration() the second argument is the level of vibration for the small motors,
+and the third argument is the level of vibration for the big motors.
+
+The small motors always seem to vibrate with the same strength.
+To enable them, set their vibration level to 0xFF. To disable them, set their level to 0.
+This does not seem to happen on every controller, but on my no-name third party controller,
+the small motors vibrated when their vibration level AND'ed with 1 was 1, thus also when their
+vibration level was not necessarily 0xFF. But stick to 0xFF and 0 to be sure.
+
+The big motors have a regulable strength.
+The minimum vibration level to make the big motors vibrate on most controllers seems to be 0x40,
+although on mine the big motors started to vibrate starting from 0x20.
+Small values will be barely noticeable, so it is better to use a value which is higher than 0xA0
+to make the player feel the vibration.
+
+********************************************************************
+
+SsKeyOn() and SsKeyOff() must not have multiple calls in a very small amount of time or the
+hardware won't register the changes and will start playing or stop the voice it happens to start playing or stop,
+and not all the voices you wanted it to. You have to use SsKeyOnMask() or SsKeyOffMask() instead.
+
+For example, you want to start playing voices #0, #1, #2 and #3 at the same time.
+DO NOT do:
+SsKeyOn(0); SsKeyOn(1); SsKeyOn(2); SsKeyOn(3);
+
+But DO:
+SsKeyOnMask((1<<0) | (1<<1) | (1<<2)|(1<<3));
+
+Likewise, if you want to stop voices #0, #1, #2, and #3 at the same time, DO: SsKeyOffMask((1<<0)|(1<<1)|(1<<2)|(1<<3));
+
+Using SsKeyOn() to start playing a background music, and then to play a sound, for example, a second later, is perfectly fine.
+Just not at the same time or very near.
+
+********************************************************************
+
+GsDrawList() is not blocking, but GsUploadImage() and LoadImage() are blocking.
+In any case after any function which uploads data to the GPU if you want to be sure that
+the uploading process finished do: while(GsIsDrawing());
+
+********************************************************************
+
+Audio streams for the PlayStation SPU are in an ADPCM format. There is no way to play PCM audio streams directly.
+
+********************************************************************
+
+Response of the joystick when asking for pressed buttons (PSX_ReadPad()).
+It is unwise to read the pad too often and it is recommended to read it only 60 or 50 times a second (vblank/vsync period), because some joysticks will not be able to keep up, will report that no buttons are pressed and they will cause strange behavior in your program/game.
+An example of joystick that shows this problem is the Sony SCPH-1200, if probed too often some times it will report that no buttons are pressed even if some of its buttons are pressed. This does not seem to happen with some clone controllers which apparently can be probed more often.
+
+********************************************************************
+On textures, and parameters to specify their location (tpage, u and v):
+
+You musn't go outside the 256x256 area which starts at the origin of the texture page you are
+taking the texture from, otherwise drawing will not be correct.
+If using texture page 5 at 16-bit depth for instance, you can reference only data from texture pages
+5, 6, 7 and 8. At 8-bit depth only data from pages 5 and 6, and in 4-bit depth only data from page 5.
+
+********************************************************************
+Mirroring of the 2 megabytes of RAM on consumer PlayStations (not Net Yaroze or Debugging Stations):
+the 2 megabytes of RAM are normally accessible in the address range 0x8000000-0x801FFFFF, but this range
+is also mirrored (contains the same contents) in the range 0x80200000-0x803FFFFF, 0x80400000-0x805FFFFF and
+0x80600000-0x807FFFFF. Obviously the same is valid for 0x0.... (by removing the most significant bit), which is the same
+but accessing without using the cache. At least PCSX 1.5 emulates this behavior correctly.
+
+********************************************************************
+Not strictly a hardware problem, but Sony's implementation of firstfile() in the BIOS seems to have a serious bug.
+If you need to use the firstfile() call, then insert in your program the code shown below so that it runs before
+the first call to firstfile().
+
+--- CUT HERE ---
+
+// Open any existing file before calling firstfile() for the first time.
+// If before calling firstfile() for the first time, you have never called open() on an existing file before,
+// every subsequent read will fail but it will report that files are opened ok!
+// This bug happens at least with the SCPH1001 BIOS version.
+// We try to open PSX.EXE and SYSTEM.CNF, as one of them must exist in order to boot from CDROM.
+
+ f = fopen("cdrom:PSX.EXE;1", "rb");
+ fclose(f);
+
+ f = fopen("cdrom:SYSTEM.CNF;1", "rb");
+ fclose(f);
+
+--- CUT HERE ---
diff --git a/repair.txt b/repair.txt
new file mode 100644
index 0000000..5b96e6a
--- /dev/null
+++ b/repair.txt
@@ -0,0 +1,26 @@
+Useful repair information for some PlayStation models
+
+Not really a part of PSXSDK or related to it, but useful nonetheless. (TM)
+
+SCPH-102 (PSOne):
+When using a wrong polarity and/or wrong voltage power adapter, you will smell something burn. This happens because the black component near the writing D004 on the PCB will literally burn and some fuses will break. As this happened, your PSOne will appear to be dead. To fix this, consider that the power jack on the bottom face of the motherboard has these contacts:
+
+x(gnd) x(gnd)
+ o(7.5v)
+
+The middle pin is voltage. Solder a wire from o(7.5v) to the first leg of the IC labelled 78M05 (the 7.5v->5v voltage regulator).
+
+Now not far from the voltage regulator there are some fuses laid out in this way:
+
++-----+
+| a | +--+ +--+ +-----+
++-----+ | c| | d | | e|
++-----+ | | | | +-----+
+| b | +--+ +--+
++-----+
+
+I'm using lettering because names will vary between motherboards. Bridge b (general fuse), and bridge d (cd-rom controller fuse). Now your PSOne will start working again.
+If d is not bridged the PSOne will hang after the "Sony Computer Entertainment" screen because the BIOS is trying to communicate with the CD controller and the CD controller is not receiving any voltage.
+
+When not using the original Sony adapter, use only a regulated 7.5v DC power supply with voltage at the center and ground on the barrel.
+Anything else is bad for your PSOne. \ No newline at end of file
diff --git a/toolchain.txt b/toolchain.txt
new file mode 100644
index 0000000..826279e
--- /dev/null
+++ b/toolchain.txt
@@ -0,0 +1,64 @@
+How to build a toolchain for the PSXSDK
+----------------------
+
+If you do not have the patience for this, do not do this. Unless you have
+some less used operating system and/or using a non-x86 processor on your development computer there are precompiled toolchains on the main PSXSDK site for some of the most common operating systems.
+
+These instructions are for Unix-like operating systems, although they will
+probably work also on Cygwin.
+
+To build a toolchain for the PSXSDK, you need to download GNU Binutils
+(http://www.gnu.org/software/binutils/) and GNU GCC (http://gcc.gnu.org)
+
+It is assumed that you want to install the toolchain you are going to build in
+/usr/local/psxsdk. If you don't want to do that simply replace it in the
+commands with something else.
+
+If you are using a *BSD system, replace `make' with `gmake'.
+
+First of all, open a terminal.
+Then the following is a guide for what you will do:
+# export BASEDIR=<directory-where-you-downloaded-binutils-and-gcc-source-archives>
+# cd $BASEDIR
+# mkdir source build
+# tar xjf binutils*bz2 -C source
+# tar xjf gcc*bz2 -C source
+# cd build
+# mkdir psxsdk-binutils
+# mkdir psxsdk-gcc
+# cd psxsdk-binutils
+# $BASEDIR/source/binutils*/configure --disable-nls --prefix=/usr/local/psxsdk --target=mipsel-unknown-elf --with-float=soft
+# make
+# make install
+# cd ..
+# cd psxsdk-gcc
+# $BASEDIR/source/gcc*/configure --disable-nls --disable-libada --disable-libssp --disable-libquadmath --disable-libstdc++-v3 \
+--target=mipsel-unknown-elf --prefix=/usr/local/psxsdk --with-float=soft --enable-languages=c,c++
+# make
+# make install
+
+Replace <directory-where-you-downloaded-binutils-and-gcc-source-archives> with the directory where you
+put the binutils and gcc source archives you downloaded.
+
+If you don't need C++ support, replace "--enable-languages=c,c++" with "--enable-languages=c" and remember
+to set CXX_SUPPORT in Makefile.cfg to `no'; that will avoid C++ support in PSXSDK from being compiled.
+
+Note that on some systems (like NetBSD) for some reason GCC might not build if you run its configure script using a relative path
+(like ..). This happens for a strange reason. In doubt, run the configure script using an absolute path (the complete name of the directory).
+
+Now you just need to build the PSXSDK. Notice that the PSXSDK installs itself
+after building automatically and you will not need to execute a command to install it after building it.
+
+Before building the PSXSDK, edit Makefile.cfg. TOOLCHAIN_PREFIX is very important,
+it specifies the directory where the PSXSDK toolchain is installed in. In our example it is /usr/local/psxsdk (the default)
+
+There should be explanations for the other variables.
+To build the PSXSDK go into its directory, change your path variable to include the PSXSDK toolchain binaries:
+
+export PATH=$PATH:/usr/local/psxsdk/bin
+
+and execute "make".
+
+If everything went well, execute "make install".
+
+PSXSDK should be ready to go! \ No newline at end of file
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 0000000..15294ff
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,77 @@
+# Makefile for the PSXSDK tools
+
+include ../Makefile.cfg
+
+TOOL_LIST = bmp2tim$(EXE_SUFFIX) \
+ cdcat$(EXE_SUFFIX) \
+ elf2exe$(EXE_SUFFIX) \
+ getpsxiso$(EXE_SUFFIX) \
+ mkpsxiso$(EXE_SUFFIX) \
+ vag2wav$(EXE_SUFFIX) \
+ wav2vag$(EXE_SUFFIX) \
+ exefixup$(EXE_SUFFIX) \
+ systemcnf$(EXE_SUFFIX) \
+ bin2c$(EXE_SUFFIX) \
+ huff$(EXE_SUFFIX) \
+ mod4psx$(EXE_SUFFIX) \
+ tim2bmp$(EXE_SUFFIX) \
+ lictool$(EXE_SUFFIX) \
+ psfex$(EXE_SUFFIX)
+
+all: $(TOOL_LIST)
+ $(MAKE_COMMAND) -C spasm
+
+bmp2tim$(EXE_SUFFIX): bmp2tim.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ bmp2tim.c $(HOST_LDFLAGS)
+
+cdcat$(EXE_SUFFIX): cdcat.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ cdcat.c $(HOST_LDFLAGS)
+
+elf2exe$(EXE_SUFFIX): elf2exe.c
+ $(HOST_CC) $(HOST_CFLAGS) -DOBJCOPY_PATH=\"$(OBJCOPY)\" -o $@ elf2exe.c $(HOST_LDFLAGS)
+
+getpsxiso$(EXE_SUFFIX): getpsxiso.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ getpsxiso.c $(HOST_LDFLAGS)
+
+mkpsxiso$(EXE_SUFFIX): mkpsxiso.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ mkpsxiso.c $(HOST_LDFLAGS)
+
+vag2wav$(EXE_SUFFIX): vag2wav.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ vag2wav.c $(HOST_LDFLAGS)
+
+wav2vag$(EXE_SUFFIX): wav2vag.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ wav2vag.c $(HOST_LDFLAGS)
+
+exefixup$(EXE_SUFFIX): exefixup.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ exefixup.c $(HOST_LDFLAGS)
+
+systemcnf$(EXE_SUFFIX): systemcnf.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ systemcnf.c $(HOST_LDFLAGS)
+
+bin2c$(EXE_SUFFIX): bin2c.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ bin2c.c $(HOST_LDFLAGS)
+
+huff$(EXE_SUFFIX): huff.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ huff.c $(HOST_LDFLAGS)
+
+mod4psx$(EXE_SUFFIX): mod4psx.c adpcm.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ mod4psx.c adpcm.c ../libmodplay/libmodplay_nopsx.a -lm -DNO_PSX_LIB
+
+tim2bmp$(EXE_SUFFIX): tim2bmp.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ tim2bmp.c -lz $(HOST_LDFLAGS)
+
+lictool$(EXE_SUFFIX): lictool.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ lictool.c $(HOST_LDFLAGS)
+
+psfex$(EXE_SUFFIX): psfex.c
+ $(HOST_CC) $(HOST_CFLAGS) -o $@ psfex.c -lz $(HOST_LDFLAGS)
+
+clean:
+ rm -f $(TOOL_LIST)
+ $(MAKE_COMMAND) -C spasm clean
+
+distclean: clean
+
+install:
+ cp -rv $(TOOL_LIST) $(TOOLCHAIN_PREFIX)/bin
+ $(MAKE_COMMAND) -C spasm install
diff --git a/tools/adpcm.c b/tools/adpcm.c
new file mode 100644
index 0000000..1ace061
--- /dev/null
+++ b/tools/adpcm.c
@@ -0,0 +1,259 @@
+/*
+ * PCM -> ADPCM routines
+ *
+ * based on work by Bitmaster and extended
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <math.h>
+#include "adpcm.h"
+
+#define PCM_BUFFER_SIZE 128*28
+
+short pcm_buffer[PCM_BUFFER_SIZE];
+
+void SsAdpcm_find_predict( short *samples, double *d_samples, int *predict_nr, int *shift_factor);
+void SsAdpcm_pack( double *d_samples, short *four_bit, int predict_nr, int shift_factor);
+
+int SsAdpcmPack(void *pcm_data, void *adpcm_data, int sample_len,
+ int sample_fmt, int adpcm_len, int enable_looping,
+ int loop_start)
+{
+ short *ptr;
+ unsigned char *pcm_data_c = pcm_data;
+ short *pcm_data_s = pcm_data;
+ unsigned char *adpcm_data_c = adpcm_data;
+ // short *adpcm_data_s = adpcm_data;
+ double d_samples[28];
+ short four_bit[28];
+ int predict_nr;
+ int shift_factor;
+ int flags;
+ int size;
+ int i, j, k;
+ unsigned char d;
+ // char s[4];
+ // int chunk_data;
+ // short e;
+ // short sample_size;
+ //unsigned char c;
+ int ap = 0;
+ int sp = 0;
+
+/*printf("pcm_data = %x, adpcm_data = %x, len = %x, fmt = %x, alen = %x,"
+ "loop = %x\n", pcm_data, adpcm_data, sample_len, sample_fmt,
+ adpcm_len, enable_looping);
+ for(i=0;i<8;i++)
+ printf("I[%d] = %x\n", i, pcm_data_c[i]);*/
+
+ //if(enable_looping)
+// flags = 6;
+// else
+ flags = 0;
+
+while( sample_len > 0 ) {
+ size = ( sample_len >= PCM_BUFFER_SIZE ) ? PCM_BUFFER_SIZE : sample_len;
+
+ if(sample_fmt == FMT_U8)
+ {
+ for(i = 0; i < size; i++)
+ {
+ //c = fgetc(fp);
+ pcm_buffer[i] = *(pcm_data_c++);
+ pcm_buffer[i] ^= 0x80;
+ pcm_buffer[i] <<= 8;
+ }
+ }
+ else if(sample_fmt == FMT_S16)
+ {
+ //fread( wave, sizeof( short ), size, fp );
+ memcpy(pcm_buffer, pcm_data_s, size * sizeof(short));
+ pcm_data_s += size;
+ }
+ else
+ {
+ printf("%s, line %d: Unknown source sample format!, id=%d\n",__FUNCTION__,__LINE__,sample_fmt);
+ return 0;
+ }
+
+ i = size / 28;
+ if ( size % 28 ) {
+ for ( j = size % 28; j < 28; j++ )
+ pcm_buffer[28*i+j] = 0;
+ i++;
+ }
+
+ for ( j = 0; j < i; j++ ) { // pack 28 samples
+ if ( sample_len < 28 && enable_looping == 0)
+ flags = 1;
+
+ if(enable_looping)
+ {
+ if(((loop_start/28)*28) == sp)
+ flags = 6;
+ else
+ flags = 2;
+ }
+
+
+ ptr = pcm_buffer + j * 28;
+ SsAdpcm_find_predict( ptr, d_samples, &predict_nr, &shift_factor );
+ SsAdpcm_pack( d_samples, four_bit, predict_nr, shift_factor );
+ d = ( predict_nr << 4 ) | shift_factor;
+ // fputc( d, vag );
+ adpcm_data_c[ap++] = d;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ // fputc( flags, vag );
+ adpcm_data_c[ap++] = flags;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ for ( k = 0; k < 28; k += 2 ) {
+ d = ( ( four_bit[k+1] >> 8 ) & 0xf0 ) | ( ( four_bit[k] >> 12 ) & 0xf );
+ // fputc( d, vag );
+ adpcm_data_c[ap++] = d;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ }
+ sample_len -= 28;
+ sp += 28;
+ }
+ }
+
+ // fputc( ( predict_nr << 4 ) | shift_factor, vag );
+ adpcm_data_c[ap++] = ( predict_nr << 4 ) | shift_factor;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ if(enable_looping)
+ // fputc(3, vag);
+ adpcm_data_c[ap++] = 3;
+ else
+// fputc( 7, vag ); // end flag
+ adpcm_data_c[ap++] = 7;
+
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ for ( i = 0; i < 14; i++ )
+ // fputc( 0, vag );
+ adpcm_data_c[ap++] = 0;
+
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ return ap;
+
+adpcm_too_big:
+ printf("%s: Resulting ADPCM data would have been larger than the output array length! Exiting %s.\n", __FUNCTION__, __FUNCTION__);
+ return 0;
+}
+
+
+
+
+
+
+void SsAdpcm_find_predict( short *samples, double *d_samples, int *predict_nr, int *shift_factor )
+{
+ int i, j;
+ double buffer[28][5];
+ double min = 1e10;
+ double max[5];
+ double ds;
+ int min2;
+ int shift_mask;
+ static double _s_1 = 0.0; // s[t-1]
+ static double _s_2 = 0.0; // s[t-2]
+ double s_0, s_1, s_2;
+ double f[5][2] = { { 0.0, 0.0 },
+ { -60.0 / 64.0, 0.0 },
+ { -115.0 / 64.0, 52.0 / 64.0 },
+ { -98.0 / 64.0, 55.0 / 64.0 },
+ { -122.0 / 64.0, 60.0 / 64.0 } };
+
+ for ( i = 0; i < 5; i++ ) {
+ max[i] = 0.0;
+ s_1 = _s_1;
+ s_2 = _s_2;
+ for ( j = 0; j < 28; j ++ ) {
+ s_0 = (double) samples[j]; // s[t-0]
+ if ( s_0 > 30719.0 )
+ s_0 = 30719.0;
+ if ( s_0 < - 30720.0 )
+ s_0 = -30720.0;
+ ds = s_0 + s_1 * f[i][0] + s_2 * f[i][1];
+ buffer[j][i] = ds;
+ if ( fabs( ds ) > max[i] )
+ max[i] = fabs( ds );
+// printf( "%+5.2f\n", s2 );
+ s_2 = s_1; // new s[t-2]
+ s_1 = s_0; // new s[t-1]
+ }
+
+ if ( max[i] < min ) {
+ min = max[i];
+ *predict_nr = i;
+ }
+ if ( min <= 7 ) {
+ *predict_nr = 0;
+ break;
+ }
+
+ }
+
+// store s[t-2] and s[t-1] in a static variable
+// these than used in the next function call
+
+ _s_1 = s_1;
+ _s_2 = s_2;
+
+ for ( i = 0; i < 28; i++ )
+ d_samples[i] = buffer[i][*predict_nr];
+
+// if ( min > 32767.0 )
+// min = 32767.0;
+
+ min2 = ( int ) min;
+ shift_mask = 0x4000;
+ *shift_factor = 0;
+
+ while( *shift_factor < 12 ) {
+ if ( shift_mask & ( min2 + ( shift_mask >> 3 ) ) )
+ break;
+ (*shift_factor)++;
+ shift_mask = shift_mask >> 1;
+ }
+
+}
+
+void SsAdpcm_pack( double *d_samples, short *four_bit, int predict_nr, int shift_factor )
+{
+ static double f[5][2] = { { 0.0, 0.0 },
+ { -60.0 / 64.0, 0.0 },
+ { -115.0 / 64.0, 52.0 / 64.0 },
+ { -98.0 / 64.0, 55.0 / 64.0 },
+ { -122.0 / 64.0, 60.0 / 64.0 } };
+ double ds;
+ int di;
+ double s_0;
+ static double s_1 = 0.0;
+ static double s_2 = 0.0;
+ int i;
+
+ for ( i = 0; i < 28; i++ ) {
+ s_0 = d_samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1];
+ ds = s_0 * (double) ( 1 << shift_factor );
+
+ di = ( (int) ds + 0x800 ) & 0xfffff000;
+
+ if ( di > 32767 )
+ di = 32767;
+ if ( di < -32768 )
+ di = -32768;
+
+ four_bit[i] = (short) di;
+
+ di = di >> shift_factor;
+ s_2 = s_1;
+ s_1 = (double) di - s_0;
+
+ }
+}
diff --git a/tools/adpcm.h b/tools/adpcm.h
new file mode 100644
index 0000000..7dcee2e
--- /dev/null
+++ b/tools/adpcm.h
@@ -0,0 +1,14 @@
+#ifndef _PSX_ADPCM_H
+#define _PSX_ADPCM_H
+
+enum
+{
+ FMT_U8, // unsigned 8-bit
+ FMT_S16, // signed 16-bit
+};
+
+int SsAdpcmPack(void *pcm_data, void *adpcm_data, int sample_len,
+ int sample_fmt, int adpcm_len, int enable_looping,
+ int loop_start);
+
+#endif
diff --git a/tools/bin2c.c b/tools/bin2c.c
new file mode 100644
index 0000000..a40e431
--- /dev/null
+++ b/tools/bin2c.c
@@ -0,0 +1,30 @@
+/*
+ * bin2c: converts a file to a C array of bytes
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ char *name = "data";
+ int n = 0;
+ int c;
+
+ if(argc >= 2)
+ name = argv[1];
+
+ printf("unsigned char %s_array[] =\n{\n", name);
+
+ while((c=getchar()) != EOF)
+ {
+ printf("%d, ", c);
+ n++;
+
+ if(!(n & 15))
+ printf("\n");
+ }
+
+ printf("};\n");
+
+ return 0;
+}
diff --git a/tools/bmp2tim.c b/tools/bmp2tim.c
new file mode 100755
index 0000000..12558b7
--- /dev/null
+++ b/tools/bmp2tim.c
@@ -0,0 +1,895 @@
+/*
+ * bmp2tim
+ *
+ * Converts a bitmap to a TIM image
+ *
+ * TEST output in various color depths... and check for issues on big-endian machines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BMP2TIM_VERSION "0.5"
+
+enum
+{
+ BITMAPINFOHEADER,
+ BITMAPV2INFOHEADER,
+ BITMAPV3INFOHEADER,
+ BITMAPV4HEADER,
+ BITMAPV5HEADER,
+};
+
+typedef struct
+{
+ unsigned char r, g, b;
+}PS_RGB;
+
+typedef struct
+{
+ int w, h;
+ int depth;
+ // 0 = r, 1 = g, 2 = b, 3 = alpha
+ unsigned int mask[4];
+ unsigned int shift[4];
+ unsigned int bits[4];
+ unsigned char hdr_type;
+ void *data;
+}PS_BITMAP;
+
+int do_clut = 0;
+unsigned int clut_x, clut_y;
+
+unsigned int org_x = 0;
+unsigned int org_y = 0;
+
+int tim_depth;
+
+unsigned int tim_flag;
+
+int set_stp_bit = 0;
+
+int transparent_black = 0;
+int magic_pink = 0;
+int raw_flag = 0;
+
+PS_RGB *ps_default_palette;
+
+unsigned short read_le_word(FILE *f)
+{
+ unsigned char c;
+ unsigned short i;
+
+ fread(&c, sizeof(char), 1, f);
+ i = c;
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<8);
+
+ return i;
+}
+
+unsigned int read_le_dword(FILE *f)
+{
+ unsigned char c;
+ unsigned int i;
+
+ fread(&c, sizeof(char), 1, f);
+ i = c;
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<8);
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<16);
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<24);
+
+ return i;
+}
+
+
+void write_le_word(FILE *f, unsigned short leword)
+{
+ unsigned char c;
+
+ c = leword & 0xff;
+ fwrite(&c, sizeof(char), 1, f);
+ c = leword >> 8;
+ fwrite(&c, sizeof(char), 1, f);
+}
+
+void write_le_dword(FILE *f, unsigned int ledword)
+{
+ unsigned char c;
+ int x;
+
+ for(x = 0; x < 4; x++)
+ {
+ c = (ledword >> (x<<3)) & 0xff;
+ fwrite(&c, sizeof(char), 1, f);
+ }
+}
+
+PS_BITMAP *ps_create_bitmap(int w, int h, int depth)
+{
+ PS_BITMAP *bm;
+
+ bm = malloc(sizeof(PS_BITMAP));
+
+ bm->w = w;
+ bm->h = h;
+ bm->depth = depth;
+
+ switch(depth)
+ {
+ case 1:
+ bm->data = malloc((w*h)/8);
+ break;
+ case 4:
+ bm->data = malloc((w*h)/2);
+ break;
+ case 8:
+ bm->data = malloc(w*h);
+ break;
+ case 15:
+ case 16:
+ bm->data = malloc((w*h)*2);
+ break;
+ case 24:
+ bm->data = malloc((w*h)*3);
+ break;
+ case 32:
+ bm->data = malloc((w*h)*4);
+ break;
+ }
+
+ return bm;
+}
+
+void ps_destroy_bitmap(PS_BITMAP *bm)
+{
+ free(bm->data);
+ free(bm);
+}
+
+
+PS_BITMAP *ps_load_bitmap(char *filename, PS_RGB *palette)
+{
+ FILE *bf;
+ //unsigned int bsize;
+ unsigned int bisize;
+ unsigned int bwidth, bheight, bbpp, boff, blw;
+// unsigned int bcompr;
+ unsigned char *bdata;
+ PS_BITMAP *bm;
+ int x, y, z, i, l;
+
+ bf = fopen(filename, "rb");
+
+ if(bf == NULL)
+ return NULL;
+
+ if(read_le_word(bf) != 19778) // 'BM'
+ {
+ fclose(bf);
+ return NULL;
+ }
+
+ /* bsize = */ read_le_dword(bf);
+
+// Read bitmap data offset
+ fseek(bf, 10, SEEK_SET);
+ boff = read_le_dword(bf);
+
+// printf("BOFF = %d\n", boff);
+
+// Read information header size, width and height
+
+ bisize = read_le_dword(bf);
+
+
+
+ bwidth = read_le_dword(bf);
+ bheight = read_le_dword(bf);
+
+// printf("bwidth = %d, bheight = %d\n", bwidth, bheight);
+
+// Read BPP
+
+ fseek(bf, 28, SEEK_SET);
+
+ bbpp = read_le_word(bf);
+
+// Check if there is compression, if there is, abort
+
+ /* bcompr = */ read_le_dword(bf);
+// printf("BCOMPR = %d\n", bcompr);
+
+ bm = ps_create_bitmap(bwidth, bheight, bbpp);
+
+ if(palette != NULL && bm->depth <= 8)
+ {
+ fseek(bf, 14 + bisize, SEEK_SET);
+
+ if(bm->depth == 4) l = 16;
+ else if(bm->depth == 8) l = 256;
+ else if(bm->depth == 1) l = 2;
+
+ for(x=0;x<l;x++)
+ {
+ palette[x].b = fgetc(bf);
+ palette[x].g = fgetc(bf);
+ palette[x].r = fgetc(bf);
+ fgetc(bf);
+ }
+ }
+
+// nextvolume FIX 2011-07-08: Now blw (line width with padding) and bwidth
+// (line width without padding) are calculated in a much cleaner and correct manner.
+
+// printf("BPP = %d\n", bbpp);
+
+ bwidth = (bwidth * bbpp) >> 3;
+ blw = bwidth;
+ if(blw & 3) blw = (blw & ~3) + 4;
+
+ bdata = (unsigned char*)bm->data;
+
+// Bit mask and colour stuff... Added 2011-07-09
+
+ switch(bisize)
+ {
+ case 40: bm->hdr_type = BITMAPINFOHEADER; break;
+ case 52: bm->hdr_type = BITMAPV2INFOHEADER; break;
+ case 56: bm->hdr_type = BITMAPV3INFOHEADER; break;
+ case 108: bm->hdr_type = BITMAPV4HEADER; break;
+ case 124: bm->hdr_type = BITMAPV5HEADER; break;
+ }
+
+// For now clear Alpha, it will be filled only if it will be found
+
+ bm->mask[3] = 0;
+ bm->shift[3] = 0;
+ bm->bits[3] = 0;
+
+ if(bm->hdr_type == BITMAPINFOHEADER && bbpp == 16)
+ {
+ // Old header type and no bitmasks specified - force defaults
+ // X1 R5 G5 B5
+ bm->mask[2] = 0x1f;
+ bm->mask[1] = 0x1f << 5;
+ bm->mask[0] = 0x1f << 10;
+ bm->shift[2] = 0;
+ bm->shift[1] = 5;
+ bm->shift[0] = 10;
+ bm->bits[2] = 5;
+ bm->bits[1] = 5;
+ bm->bits[0] = 5;
+ }
+ else if(bm->hdr_type >= BITMAPV2INFOHEADER)
+ {
+ fseek(bf, 54, SEEK_SET);
+
+// Calculate rshift and rbits
+
+ if(bm->hdr_type >= BITMAPV3INFOHEADER)
+ l = 4;
+ else
+ l = 3;
+
+ for(i = 0; i < l; i++)
+ {
+ bm->mask[i] = read_le_dword(bf);
+
+ y = 0; // rshift
+ z = 0; // rbits
+
+ for(x = 31; x >= 0; x--)
+ {
+ if(bm->mask[i] & (1<<x))
+ {
+ y = x;
+ z++;
+ }
+ }
+
+ bm->shift[i] = y;
+ bm->bits[i] = z;
+
+ //printf("shift[%d] = %d, bits[%d] = %d\n", i, bm->shift[i],
+ // i, bm->bits[i]);
+ }
+ }
+
+// Copy data in allocated memory
+
+ for(y = 0; y < bm->h; y++)
+ {
+ fseek(bf, boff + (blw * (bm->h - (1+y))), SEEK_SET);
+
+ for(x = 0; x < bwidth; x++)
+ fread(&bdata[(y*bwidth)+x], sizeof(char), 1, bf);
+ }
+
+ fclose(bf);
+
+ return bm;
+}
+
+unsigned int ps_makecol(int r, int g, int b, int a)
+{
+ return (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+unsigned int ps_getr(int c)
+{
+ return (c>>16)&0xff;
+}
+
+unsigned int ps_getg(int c)
+{
+ return (c>>8)&0xff;
+}
+
+unsigned int ps_getb(int c)
+{
+ return c&0xff;
+}
+
+unsigned int ps_geta(int c)
+{
+ return (c>>24)&0xff;
+}
+
+unsigned int ps_getpixel(PS_BITMAP *bm, int x, int y)
+{
+ unsigned short shortbuf;
+ unsigned int intbuf;
+ unsigned char r, g, b, a;
+ unsigned char *dataptrb = (unsigned char*)bm->data;
+ int off;
+
+ if(bm->depth == 16)
+ {
+ off = ((y*bm->w)+x)*2;
+
+ // Little endian, guys...
+
+ shortbuf = dataptrb[off];
+ shortbuf|= dataptrb[off+1]<<8;
+
+ b = ((shortbuf & bm->mask[2]) >> bm->shift[2]) << (8-bm->bits[2]);
+ g = ((shortbuf & bm->mask[1]) >> bm->shift[1]) << (8-bm->bits[1]);
+ r = ((shortbuf & bm->mask[0]) >> bm->shift[0]) << (8-bm->bits[0]);
+ a = ((shortbuf & bm->mask[3]) >> bm->shift[3]) << (8-bm->bits[3]);
+
+ return ps_makecol(r, g, b, a);
+ }
+ else if(bm->depth == 24)
+ {
+ // 24-bit bitmaps never have bitmasks.
+
+ off = ((y*bm->w)+x)*3;
+ r = dataptrb[off+2];
+ g = dataptrb[off+1];
+ b = dataptrb[off];
+ a = 255;
+
+ return ps_makecol(r, g, b, 255);
+ }
+ else if(bm->depth == 32)
+ {
+ off = ((y*bm->w)+x)*4;
+ /* r = dataptrb[off+3];
+ g = dataptrb[off+2];
+ b = dataptrb[off+1];*/
+ intbuf = dataptrb[off];
+ intbuf|= dataptrb[off+1]<<8;
+ intbuf|= dataptrb[off+2]<<16;
+ intbuf|= dataptrb[off+3]<<24;
+
+ r = ((intbuf & bm->mask[0]) >> bm->shift[0]) << (8-bm->bits[0]);
+ g = ((intbuf & bm->mask[1]) >> bm->shift[1]) << (8-bm->bits[1]);
+ b = ((intbuf & bm->mask[2]) >> bm->shift[2]) << (8-bm->bits[2]);
+ a = ((intbuf & bm->mask[3]) >> bm->shift[3]) << (8-bm->bits[3]);
+
+ return ps_makecol(r, g, b, a);
+ }
+ else if(bm->depth == 8)
+ {
+ r = dataptrb[(y*bm->w)+x];
+
+ return ps_makecol(ps_default_palette[r].r,
+ ps_default_palette[r].g, ps_default_palette[r].b, 255);
+ }
+ else if(bm->depth == 4)
+ {
+ off = (y*bm->w)+x;
+ off/= 2;
+
+ if(x & 1)
+ r = dataptrb[off] & 0xf;
+ else
+ r = dataptrb[off] >> 4;
+
+ return ps_makecol(ps_default_palette[r].r,
+ ps_default_palette[r].g, ps_default_palette[r].b, 255);
+ }
+ else if(bm->depth == 1)
+ {
+ off = (y*bm->w)+x;
+ off/= 8;
+
+ r = (dataptrb[off] & (1<<(7-(x&7)))) ? 1 : 0;
+
+ return ps_makecol(ps_default_palette[r].r,
+ ps_default_palette[r].g, ps_default_palette[r].b, 255);
+ }
+
+ return 0;
+}
+
+unsigned int ps_getpixel_pal(PS_BITMAP *bm, int x, int y)
+{
+ unsigned char *dataptrb = (unsigned char*)bm->data;
+ int off;
+
+ if(bm->depth == 8)
+ {
+ return dataptrb[(y*bm->w)+x];
+ }
+ else if(bm->depth == 4)
+ {
+ off = (y*bm->w)+x;
+ off/= 2;
+
+ if(x & 1)
+ return dataptrb[off] & 0xf;
+ else
+ return dataptrb[off] >> 4;
+ }
+ else if(bm->depth == 1)
+ {
+ off = (y*bm->w)+x;
+ off/= 8;
+
+ return (dataptrb[off] & (1<<(7-(x&7)))) ? 1 : 0;
+ }
+
+ return 0;
+}
+
+void parse_options(int argc, char *argv[])
+{
+ int x;
+
+ for(x=4;x<argc;x++)
+ {
+ if(strncmp("-clut=", argv[x], 6) == 0)
+ {
+ sscanf(argv[x], "-clut=%d,%d", &clut_x, &clut_y);
+ do_clut = 1;
+ }else if(strncmp("-org=", argv[x], 5) == 0)
+ sscanf(argv[x], "-org=%d,%d", &org_x, &org_y);
+ else if(strcmp("-stp", argv[x]) == 0)
+ set_stp_bit = 1;
+ else if(strcmp("-noblack", argv[x]) == 0)
+ transparent_black = 1;
+ else if(strcmp("-mpink", argv[x]) == 0)
+ magic_pink = 1;
+ else if(strcmp("-raw", argv[x]) == 0)
+ raw_flag = 1;
+ }
+}
+
+unsigned short rgb24_to_rgbpsx(unsigned char r, unsigned char g, unsigned char b)
+{
+ unsigned short c;
+
+ c = r>>3;
+ c|= (g>>3)<<5;
+ c|= (b>>3)<<10;
+
+ /*if(set_stp_bit) c|=0x8000;*/
+// this code is a bit messy, tidy it up.
+
+ if(c == 0 && !transparent_black)
+ c|=0x8000;
+
+ if(c == ((31)|(31<<10)) && magic_pink)
+ c=0;
+
+ if(set_stp_bit)
+ {
+ if(transparent_black && c == 0)
+ return c;
+
+ if(magic_pink && c == ((31)|(31<<10)))
+ return c;
+
+ c|=0x8000;
+ }
+
+ return c;
+}
+
+int main(int argc, char *argv[])
+{
+ PS_BITMAP *in_bitmap;
+ FILE *out_tim;
+ PS_RGB in_palette[256];
+ int x, y, z, c, c2;
+ unsigned short shortbuf;
+ int cx_out = 0;
+
+ ps_default_palette = in_palette;
+
+ for(x=1;x<argc;x++)
+ {
+ if(strcmp("-version", argv[x]) == 0)
+ {
+ printf("bmp2tim version "BMP2TIM_VERSION"\n");
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if(argc < 4)
+ {
+ printf("bmp2tim "BMP2TIM_VERSION" - converts a bitmap to a TIM image\n");
+ printf("usage: bmp2tim <inbmp> <outtim> <depth> [options]\n\n");
+ printf("Options:\n");
+ printf(" -clut=x,y - Generate a Color Look Up Table (default: OFF)\n");
+ printf(" -org=x,y - Set image origin in framebuffer (default: 0, 0)\n");
+ printf(" -stp - Set semi transparency bit (default: BLACK ONLY)\n");
+ printf(" -noblack - Make black transparent (default: OFF)\n");
+ printf(" -mpink - Magic pink, 255,0,255 transparent (default: OFF)\n");
+ printf(" -raw - Do not save header and CLUT (default: OFF)\n");
+ printf(" -version - Print program version on screen\n\n");
+ printf("Valid TIM depths are 4 (16-color), 8 (256-color), 16 (RGB555) and 24 (RGB888)\n");
+ return EXIT_SUCCESS;
+ }
+
+ tim_depth = atoi(argv[3]);
+
+ parse_options(argc, argv);
+
+ if(do_clut && tim_depth >= 16)
+ {
+ printf("Images with depths higher than 8-bit can't have a color look up table.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(clut_x & 0xf)
+ {
+ printf("The X position of the CLUT in the framebuffer must be a multiplier of 16.\n");
+ return EXIT_FAILURE;
+ }
+
+ switch(tim_depth)
+ {
+ case 4:
+ if(clut_x > (1024-16))
+ cx_out = 1;
+ break;
+ case 8:
+ if(clut_x > (1024-256))
+ cx_out = 1;
+ break;
+ }
+
+ if(cx_out)
+ {
+ printf("X position specified for CLUT out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(clut_y >= 512)
+ {
+ printf("Y position specified for CLUT out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(do_clut)
+ printf("Generating a Color Look Up Table (CLUT)\n");
+
+ if(tim_depth != 4 && tim_depth != 8 && tim_depth != 16 && tim_depth != 24)
+ {
+ printf("Invalid color depth specified!\n");
+ return EXIT_FAILURE;
+ }
+
+ in_bitmap = ps_load_bitmap(argv[1], in_palette);
+
+ if(in_bitmap == NULL)
+ {
+ printf("Unable to load bitmap. Unsupported format or file is unreadable or does not exist.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(tim_depth == 4 && in_bitmap->depth > 4)
+ {
+ printf("Error: Only a 4-bit bitmap or a bitmap of lower depth can be used to obtain a 4-bit TIM!\n");
+ return EXIT_FAILURE;
+ }
+
+ if(tim_depth == 8 && in_bitmap->depth > 8)
+ {
+ printf("Error: Only a 8-bit or a bitmap of lower depth can be used to obtain a 8-bit TIM!\n");
+ return EXIT_FAILURE;
+ }
+
+/* allegro_init();
+ set_color_depth(32);
+ install_keyboard();
+ set_gfx_mode(GFX_AUTODETECT_WINDOWED, in_bitmap->w, in_bitmap->h, 0, 0);
+
+ for(y=0;y<in_bitmap->h;y++)
+ {
+ for(x=0;x<in_bitmap->w;x++)
+ {
+ c = ps_getpixel_pal(in_bitmap, x, y);
+
+ //putpixel(screen, x, y, makecol(ps_getr(c), ps_getg(c), ps_getb(c)));
+ putpixel(screen, x, y, makecol(in_palette[c].r, in_palette[c].g,
+ in_palette[c].b));
+ }
+ }
+
+ while(!key[KEY_ESC]);*/
+
+ if(in_bitmap == NULL)
+ {
+ printf("Could not open bitmap. Aborting.\n");
+ return EXIT_FAILURE;
+ }
+
+ switch(tim_depth)
+ {
+ case 4:
+ if(in_bitmap->w & 3)
+ {
+ printf("Error: A 4-bit bitmap must have a width divisible by four.\n");
+ return EXIT_FAILURE;
+ }
+
+ z = in_bitmap->w/4;
+ break;
+ case 8:
+ if(in_bitmap->w & 1)
+ {
+ printf("Error: A 8-bit bitmap must have a width divisible by two.\n");
+ return EXIT_FAILURE;
+ }
+
+ z = in_bitmap->w/2;
+ break;
+ case 16:
+ z = in_bitmap->w;
+ break;
+ }
+
+ if((org_x+z) > 1024)
+ {
+ printf("X position specified for image data out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ switch(tim_depth)
+ {
+ case 4:
+ z = in_bitmap->h/4;
+ break;
+ case 8:
+ z = in_bitmap->h/2;
+ break;
+ case 16:
+ z = in_bitmap->h;
+ break;
+ }
+
+ if((org_y+z) > 512)
+ {
+ printf("Y position specified for image data out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ out_tim = fopen(argv[2], "wb");
+
+ if(out_tim == NULL)
+ {
+ printf("Couldn't open file at path %s for writing. Aborting.\n", argv[2]);
+ return EXIT_FAILURE;
+ }
+
+ if(!raw_flag)
+ {
+
+ write_le_dword(out_tim, 0x10); /* ID = 0x10, Version = 0x00 */
+
+ /*
+ * Now let's fill the TIM flag double word
+ */
+
+ /*
+ * Pixel mode (PMODE)
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ tim_flag = 0;
+ break;
+ case 8:
+ tim_flag = 1;
+ break;
+ case 16:
+ tim_flag = 2;
+ break;
+ case 24:
+ tim_flag = 3;
+ break;
+ }
+
+ /*
+ * Clut flag (CF)
+ */
+ //tim_flag|=8;
+ if(do_clut)tim_flag|=8;
+
+ write_le_dword(out_tim, tim_flag);
+
+ /*
+ * If we have to write a CLUT now, we have to write its data block
+ */
+
+ if(do_clut)
+ {
+ /*
+ * Let's write the information for the block - we already know
+ * everything about it.
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ write_le_dword(out_tim, 44); // Number of bytes contained by the block
+ write_le_dword(out_tim, (clut_y<<16)|clut_x); // X, Y position
+ write_le_dword(out_tim, (1<<16)|16); // Width = 16, Height = 1
+ break;
+ case 8:
+ write_le_dword(out_tim, 524);
+ write_le_dword(out_tim, (clut_y<<16)|clut_x);
+ write_le_dword(out_tim, (1<<16)|256); // Width = 256, Height = 1
+ break;
+ }
+
+ /*
+ * Let's write the CLUT data
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ for(x = 0; x < 16; x++)
+ {
+ shortbuf = rgb24_to_rgbpsx(in_palette[x].r, in_palette[x].g,
+ in_palette[x].b);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ break;
+ case 8:
+ for(x = 0; x < 256; x++)
+ {
+ shortbuf = rgb24_to_rgbpsx(in_palette[x].r, in_palette[x].g,
+ in_palette[x].b);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ break;
+ }
+ }
+
+ /*
+ * Write image data block
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ x = 12 + ((in_bitmap->w * in_bitmap->h) / 2);
+ break;
+ case 8:
+ x = 12 + (in_bitmap->w * in_bitmap->h);
+ break;
+ case 16:
+ x = 12 + ((in_bitmap->w * in_bitmap->h) * 2);
+ break;
+ case 24:
+ x = 12 + ((in_bitmap->w * in_bitmap->h) * 3);
+ break;
+ }
+
+ write_le_dword(out_tim, x);
+ write_le_dword(out_tim, (org_y<<16)|org_x);
+
+ switch(tim_depth)
+ {
+ case 4:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|(in_bitmap->w/4));
+ break;
+ case 8:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|(in_bitmap->w/2));
+ break;
+ case 16:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|in_bitmap->w);
+ break;
+ case 24:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|(in_bitmap->w+
+ (in_bitmap->w/2)));
+ break;
+ }
+
+ }
+
+// Write image pixel data...
+
+ switch(tim_depth)
+ {
+ case 24:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x+=2)
+ {
+ c = ps_getpixel(in_bitmap, x, y);
+ c2 = ps_getpixel(in_bitmap, x+1, y);
+
+ write_le_word(out_tim, (ps_getg(c)<<8)|ps_getr(c));
+ write_le_word(out_tim, (ps_getr(c2)<<8)|ps_getb(c));
+ write_le_word(out_tim, (ps_getb(c2)<<8)|ps_getg(c2));
+ }
+ }
+ break;
+ case 16:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x++)
+ {
+ c = ps_getpixel(in_bitmap, x, y);
+ shortbuf = rgb24_to_rgbpsx(ps_getr(c), ps_getg(c), ps_getb(c));
+ write_le_word(out_tim, shortbuf);
+ }
+ }
+ break;
+ case 4:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x+=4)
+ {
+ shortbuf = 0;
+ for(c = 0; c < 4; c++)
+ shortbuf |= (ps_getpixel_pal(in_bitmap, x+c, y)&0xf) << (c<<2);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ }
+ break;
+ case 8:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x+=2)
+ {
+ shortbuf = 0;
+ for(c = 0; c < 2; c++)
+ shortbuf |= (ps_getpixel_pal(in_bitmap, x+c, y)&0xff) << (c<<3);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ }
+ break;
+ }
+
+ fclose(out_tim);
+ //printf("Bitmap converted to TIM file successfully!\n");
+ return EXIT_SUCCESS;
+}
diff --git a/tools/cdcat.c b/tools/cdcat.c
new file mode 100644
index 0000000..329fd17
--- /dev/null
+++ b/tools/cdcat.c
@@ -0,0 +1,373 @@
+/*
+ * cdcat: get and replace files inside an ISO-9660 CDROM image
+ * Based on cdcat by Robert Nordier
+ *
+ * Copyright (c) 2011 Giuseppe Gatta
+ *
+ * Copyright (c) 2007 Robert Nordier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted subject to the following conditions:
+ *
+ *1. Existing copyright notices in source and other files must be
+ * retained.
+ *
+ *2. Redistributions in whatever form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define CDCAT_VERSION "0.5"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+enum
+{
+ cdrom_mode_1,
+ cdrom_mode_1_raw,
+ cdrom_mode_2,
+};
+
+enum
+{
+ cdcat_oper_read,
+ cdcat_oper_write,
+ cdcat_oper_showoffset
+};
+
+int cdcat_cdrom_mode = cdrom_mode_1;
+int cdcat_oper = cdcat_oper_read;
+
+#define SECSIZ 2048
+#define NAMLEN 255
+
+#define sw(x,y) ((x)<<8|(y))
+#define cv4(x) ((*(unsigned char*)(x)) | ((*(unsigned char*)(x+1))<<8) | \
+ ((*(unsigned char*)(x+2))<<16) | ((*(unsigned char*)(x+3))<<24))
+
+/* ISO 9660 Primary Volume Descriptor */
+static char cdmagic[] = {1, 'C', 'D', '0', '0', '1', 1, 0};
+
+struct cddir {
+ unsigned char len_dr; /* length of directory record */
+ unsigned char len_ear; /* extended attribute record length */
+ unsigned char ext[8]; /* location of extent */
+ unsigned char size[8]; /* data length */
+ unsigned char time[7]; /* recording date and time */
+ unsigned char flags; /* file flags */
+ unsigned char fus; /* file unit size */
+ unsigned char gap; /* interleave gap size */
+ unsigned char vsn[4]; /* volume sequence number */
+ unsigned char len_fi; /* length of file identifier */
+ unsigned char fi[1]; /* file identifier ... */
+};
+
+struct dir {
+ unsigned int ext; /* starting block number */
+ unsigned int size; /* file size */
+ int type; /* file type ('d' or '-') */
+ char name[NAMLEN + 1]; /* file name */
+};
+
+static char *fn; /* special file name */
+static int fd; /* special file descriptor */
+
+int cdcat(char *);
+void loaddir(struct cddir *, struct dir *);
+void susp(unsigned char *, int, struct dir *);
+int readblk(void *, unsigned int);
+void writeblk(void *, unsigned int);
+void error(char *);
+
+void cdcat_print_usage()
+{
+ fprintf(stderr, "usage: cdcat <options> iso-image [path]\n");
+ fprintf(stderr, "\n"
+ "cdcat can be used to explore an ISO9660 filesystem image\n"
+ "If path is not specified the root directory is listed, if it's a directory "
+ "the directory is listed or if it's a file the file is printed to standard output\n"
+ "The Rock Ridge extensions to the ISO9660 filesystem standard are supported\n"
+ "Original program (c) 2007 Robert Nordier.\n"
+ "\n"
+ "Options:\n"
+ "-help - This screen\n"
+ "-mode1 - The image is raw and has Mode 1 sectors\n"
+ "-mode2 - The image is raw and has Mode 2 sectors (like PlayStation dumps)\n"
+ "-replace - If [path] is specified, the data of the file is\n"
+ " replaced with input from standard input\n"
+ "-showoffset - Show file offset in image\n"
+ "-version - Display version\n\n");
+}
+
+int main(int argc, char **argv)
+{
+ char *path;
+ int e;
+ int nargc;
+ int x;
+
+ for(x = 1; x < argc; x++)
+ {
+ if(strcmp(argv[x], "--") == 0 || argv[x][0] != '-')
+ break;
+
+ if(strcmp(argv[x], "-mode2") == 0 || strcmp(argv[x], "--mode2") == 0)
+ cdcat_cdrom_mode = cdrom_mode_2;
+ else if(strcmp(argv[x], "-mode1") == 0 || strcmp(argv[x], "--mode1") == 0)
+ cdcat_cdrom_mode = cdrom_mode_1_raw;
+ else if(strcmp(argv[x], "--help") == 0 || strcmp(argv[x], "-help") == 0)
+ {
+ cdcat_print_usage();
+ return 0;
+ }
+ else if(strcmp(argv[x], "--version") == 0 || strcmp(argv[x], "-version") == 0)
+ {
+ printf("cdcat version "CDCAT_VERSION"\n");
+ return 0;
+ }
+ else if(strcmp(argv[x], "--replace") == 0 || strcmp(argv[x], "-replace") == 0)
+ cdcat_oper = cdcat_oper_write;
+ else if(strcmp(argv[x], "--showoffset") == 0 || strcmp(argv[x], "-showoffset") == 0)
+ cdcat_oper = cdcat_oper_showoffset;
+ else
+ {
+ printf("Invalid option %s! Aborting.\n", argv[x]);
+ return -1;
+ }
+ }
+
+ nargc = argc-(x-1);
+
+ if (nargc != 2 && nargc != 3) {
+ cdcat_print_usage();
+ exit(2);
+ }
+
+ fn = argv[x];
+
+ if ((fd = open(argv[x], cdcat_oper==cdcat_oper_read?O_RDONLY:O_RDWR)) == -1)
+ error("cannot open");
+ path = argv[x+1] ? argv[x+1] : "";
+
+ if ((e = cdcat(path)) != 0)
+ fprintf(stderr, "cdcat: %s: Not found\n", path);
+ return e;
+}
+
+int cdcat(char *path)
+{
+ unsigned char buf[SECSIZ];
+ char name[NAMLEN + 1];
+ struct cddir *dp, *tp;
+ struct dir xd;
+ char *p, *q;
+ unsigned ext, size, bx, bn, x, i;
+ int type, n;
+
+ /*
+ * find primary volume descriptor
+ * and thence root directory
+ */
+ bx = 64;
+ for (bn = 16; bn < bx; bn++) {
+ readblk(buf, bn);
+ if (strcmp((char *)buf, cdmagic) == 0)
+ break;
+ }
+ if (bn == bx)
+ error("Invalid argument");
+ dp = (struct cddir *)&buf[156];
+ loaddir(dp, &xd);
+
+ /*
+ * lookup, list, print ...
+ */
+ for (p = path; dp; p = q) {
+ while (*p == '/')
+ p++;
+ for (q = p; *q && *q != '/'; q++);
+ if ((n = q - p)) {
+ if (n > NAMLEN)
+ n = NAMLEN;
+ memcpy(name, p, n);
+ name[n] = 0;
+ }
+ ext = xd.ext;
+ size = xd.size;
+ type = xd.type;
+ dp = NULL;
+ bx = ext + (size + (SECSIZ - 1)) / SECSIZ;
+ for (bn = ext; !dp && bn < bx; bn++) {
+ if (type == 'd')
+ {
+ readblk(buf, bn);
+
+ for (i = 0; !dp && buf[i]; i += buf[i]) {
+ tp = (struct cddir *)(buf + i);
+ loaddir(tp, &xd);
+ if (n == 0)
+ printf("%10u %c %s\n",
+ xd.size, xd.type, xd.name);
+ else if (strcmp(name, xd.name) == 0)
+ dp = tp;
+ }
+ }
+ else {
+ if(cdcat_oper == cdcat_oper_read)
+ {
+ readblk(buf, bn);
+ x = size < SECSIZ ? size : SECSIZ;
+ for (i = 0; i < x; i++)
+ putchar(buf[i]);
+ size -= x;
+ }else if(cdcat_oper == cdcat_oper_write)
+ {
+ x = size < SECSIZ ? size : SECSIZ;
+ for (i = 0; i < x; i++)
+ buf[i] = getchar();
+
+ writeblk(buf, bn);
+
+ size -= x;
+ }else if(cdcat_oper == cdcat_oper_showoffset)
+ {
+ printf("%d\n", readblk(buf, bn));
+ goto cdcat_end;
+ }
+ }
+ }
+ }
+cdcat_end:
+ return n != 0;
+}
+
+/*
+ * Gather together the directory information that interests us.
+ * Any and all of this may be altered by a suitable SUSP field.
+ */
+void loaddir(struct cddir *dp, struct dir *xp)
+{
+ int c;
+
+ xp->ext = cv4(dp->ext);
+ xp->size = cv4(dp->size);
+ xp->type = dp->flags & 2 ? 'd' : '-';
+ xp->name[0] = 0;
+ if (dp->fi[0] != 0) {
+ c = dp->len_fi | 1;
+ susp(dp->fi + c, dp->len_dr - 33 - c, xp);
+ }
+ if (xp->name[0] == 0)
+ {
+ if (dp->fi[0] == 0 || dp->fi[0] == 1)
+ strcpy(xp->name, dp->fi[0] == 0 ? "." : "..");
+ else
+ {
+ memcpy(xp->name, dp->fi, dp->len_fi);
+ xp->name[dp->len_fi] = 0;
+ }
+ }
+}
+
+/*
+ * SUSP/RRIP support: allowing UNIX-style file names and directories
+ * nested more than eight deep (among other things).
+ */
+void susp(unsigned char *sp, int n, struct dir *xp)
+{
+ unsigned char buf[SECSIZ];
+ unsigned char *p;
+ int i, j;
+
+ for (p = sp; p < sp + n && *p;) {
+ if (p[3] != 1)
+ return;
+ switch (sw(p[0], p[1])) {
+ /* continuation area */
+ case sw('C', 'E'):
+ readblk(buf, cv4(&p[4]));
+ sp = buf + cv4(&p[12]);
+ n = cv4(&p[20]);
+ p = sp;
+ continue;
+ /* child link */
+ case sw('C', 'L'):
+ xp->ext = cv4(&p[4]);
+ xp->size = SECSIZ;
+ xp->type = 'd';
+ break;
+ /* alternate name */
+ case sw('N', 'M'):
+ for (j = 0; xp->name[j]; j++);
+ for (i = 5; i < p[2]; i++)
+ xp->name[j++] = p[i];
+ xp->name[j] = 0;
+ break;
+ }
+ p += p[2];
+ }
+}
+
+int readblk(void *buf, unsigned int blkno)
+{
+ int r;
+
+ switch(cdcat_cdrom_mode)
+ {
+ case cdrom_mode_1:
+ r = lseek(fd, blkno * SECSIZ, 0);
+ break;
+ case cdrom_mode_1_raw:
+ r = lseek(fd, (blkno * 2352) + 16, 0);
+ break;
+ case cdrom_mode_2:
+ r = lseek(fd, (blkno * 2352) + 24, 0);
+ break;
+ }
+
+ if (read(fd, buf, SECSIZ) != SECSIZ)
+ error("read error");
+
+ return r;
+}
+
+void writeblk(void *buf, unsigned int blkno)
+{
+ switch(cdcat_cdrom_mode)
+ {
+ case cdrom_mode_1:
+ lseek(fd, blkno * SECSIZ, 0);
+ break;
+ case cdrom_mode_1_raw:
+ lseek(fd, (blkno * 2352) + 16, 0);
+ break;
+ case cdrom_mode_2:
+ lseek(fd, (blkno * 2352) + 24, 0);
+ break;
+ }
+
+ if (write(fd, buf, SECSIZ) != SECSIZ)
+ error("write error");
+}
+
+void error(char *msg)
+{
+ fprintf(stderr, "cdcat: %s: %s\n", fn, msg);
+ exit(2);
+}
diff --git a/tools/elf2exe.c b/tools/elf2exe.c
new file mode 100755
index 0000000..89e2c6d
--- /dev/null
+++ b/tools/elf2exe.c
@@ -0,0 +1,231 @@
+/*
+ * elf2exe
+ *
+ * Converts an ELF executable to PS-EXE, using objcopy
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const unsigned char psexe_magic[8] = {'P','S','-','X',' ','E','X','E'};
+const char *psexe_marker_usa = "Sony Computer Entertainment Inc. for North America area";
+const char *psexe_marker_jpn = "Sony Computer Entertainment Inc. for Japan area";
+const char *psexe_marker_eur = "Sony Computer Entertainment Inc. for Europe area";
+char *psexe_marker;
+
+//#define OBJCOPY_PATH "mipsel-unknown-elf-objcopy"
+
+int main(int argc, char *argv[])
+{
+ FILE *objcopy_out, *psexe;
+ char stringbuf[2048];
+ unsigned char charbuf;
+ int x;
+ unsigned int sz;
+ unsigned int gp = 0;
+
+ if(argc < 3)
+ {
+ printf("elf2exe - Converts an ELF executable to PS-EXE\n");
+ printf("usage: elf2exe [elf] [ps-x exe] <options>\n");
+ printf("\n");
+ printf("Options:\n");
+ printf("-mark_jpn - Use Japanese ascii marker (default: USA)\n");
+ printf("-mark_eur - Use European ascii marker (default: USA)\n");
+ printf("-mark=<mark> - Use custom ascii marker <mark>\n");
+ return -1;
+ }
+
+ psexe_marker = (char*)psexe_marker_usa;
+
+ for(x = 3; x < argc; x++)
+ {
+ if(strcmp(argv[x], "-mark_jpn") == 0)
+ psexe_marker = (char*)psexe_marker_jpn;
+
+ if(strcmp(argv[x], "-mark_eur") == 0)
+ psexe_marker = (char*)psexe_marker_eur;
+
+ if(strncmp(argv[x], "-mark=", 6) == 0)
+ {
+ if(strlen(argv[x]) >= 7)
+ psexe_marker = argv[x] + 6;
+ }
+
+ if(strncmp(argv[x], "-gp=", 4) == 0)
+ {
+ if(strlen(argv[x]) >= 5)
+ sscanf(argv[x] + 4, "%x", &gp);
+ }
+ }
+
+/*
+ * Now open the output file
+ */
+
+ psexe = fopen(argv[2], "wb");
+
+ if(psexe == NULL)
+ {
+ printf("Couldn't open %s for writing. Aborting!\n", argv[2]);
+ return -1;
+ }
+
+/*
+ * Write PSEXE magic string
+ */
+ fwrite(psexe_magic, sizeof(char), 8, psexe);
+
+/*
+ * Seek output file to 0x10, Initial Program Counter
+ */
+ fseek(psexe, 0x10, SEEK_SET);
+
+/*
+ * Write initial program counter = 0x80010000
+ */
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x01;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Global Pointer
+ */
+ charbuf = gp & 0xff;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff00) >> 8;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff0000) >> 16;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff000000) >> 24;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Seek output file to 0x18, Text section start address
+ */
+ fseek(psexe, 0x18, SEEK_SET);
+
+/*
+ * Write text section start address = 0
+ */
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x01;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Seek output file to 0x30, Initial Stack Pointer
+ */
+ fseek(psexe, 0x30, SEEK_SET);
+
+/*
+ * Write Initial Stack Pointer = 0x801FFFF0
+ */
+ charbuf = 0xF0;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0xFF;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x1F;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+
+/*
+ * Seek output to 0x4C, ASCII marker
+ */
+ fseek(psexe, 0x4C, SEEK_SET);
+
+ x = 0;
+
+/*
+ * Write ASCII marker string
+ */
+ while(psexe_marker[x])
+ fwrite(&psexe_marker[x++], sizeof(char), 1, psexe);
+
+/*
+ * Run objcopy now
+ */
+ sprintf(stringbuf, OBJCOPY_PATH" -O binary %s %s.bin", argv[1], argv[1]);
+ system(stringbuf);
+
+ sprintf(stringbuf, "%s.bin", argv[1]);
+
+/*
+ * Open objcopy output
+ */
+
+ objcopy_out = fopen(stringbuf, "rb");
+ if(objcopy_out == NULL)
+ {
+ printf("Could not open objcopy output at %s. Check your permissions. Aborting.\n",
+ stringbuf);
+ return -1;
+ }
+
+/*
+ * Seek to 0x800, Program Start
+ * and write the output of objcopy into the PS-X EXE
+ */
+ fseek(psexe, 0x800, SEEK_SET);
+
+ while(!feof(objcopy_out))
+ {
+ x = fgetc(objcopy_out);
+ fputc(x, psexe);
+ }
+
+
+ fclose(objcopy_out);
+
+/*
+ * Get the file size of the PS-X EXE
+ */
+ fseek(psexe, 0, SEEK_END);
+ sz = ftell(psexe);
+ fseek(psexe, 0, SEEK_SET);
+
+ if(sz % 2048 != 0)
+ {
+ fseek(psexe, (((sz / 2048) + 1)*2048) - 1, SEEK_SET);
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ sz = ftell(psexe);
+ }
+
+/*
+ * Write the address of the text section in the header of the PS-X EXE
+ */
+
+ sz -= 0x800;
+
+ fseek(psexe, 0x1C, SEEK_SET);
+
+ charbuf = sz & 0xff;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff00) >> 8;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff0000) >> 16;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff000000) >> 24;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+ fclose(psexe);
+
+/*
+ * Remove objcopy output
+ */
+ sprintf(stringbuf, "%s.bin", argv[1]);
+ remove(stringbuf);
+
+ return 0;
+}
diff --git a/tools/endian.c b/tools/endian.c
new file mode 100644
index 0000000..333390f
--- /dev/null
+++ b/tools/endian.c
@@ -0,0 +1,52 @@
+unsigned short read_le_word(FILE *f)
+{
+ unsigned char c;
+ unsigned short i;
+
+ fread(&c, sizeof(char), 1, f);
+ i = c;
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<8);
+
+ return i;
+}
+
+unsigned int read_le_dword(FILE *f)
+{
+ unsigned char c;
+ unsigned int i;
+
+ fread(&c, sizeof(char), 1, f);
+ i = c;
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<8);
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<16);
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<24);
+
+ return i;
+}
+
+
+void write_le_word(FILE *f, unsigned short leword)
+{
+ unsigned char c;
+
+ c = leword & 0xff;
+ fwrite(&c, sizeof(char), 1, f);
+ c = leword >> 8;
+ fwrite(&c, sizeof(char), 1, f);
+}
+
+void write_le_dword(FILE *f, unsigned int ledword)
+{
+ unsigned char c;
+ int x;
+
+ for(x = 0; x < 4; x++)
+ {
+ c = (ledword >> (x<<3)) & 0xff;
+ fwrite(&c, sizeof(char), 1, f);
+ }
+}
diff --git a/tools/exefixup.c b/tools/exefixup.c
new file mode 100644
index 0000000..7f555dc
--- /dev/null
+++ b/tools/exefixup.c
@@ -0,0 +1,204 @@
+/*
+ * exefixup.c v0.02.1 Andrew Kieschnick <andrewk@mail.utexas.edu>
+ * (v0.02.1): Giuseppe Gatta <tails92@gmail.com>
+ *
+ * v0.02.1 changes: removed warnings
+ *
+ * displays PS-X EXE header information
+ * offers to fix incorrect t_size
+ * offers to pad to 2048-byte boundary for cd-rom use
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+unsigned int char2int(unsigned char *foo)
+{
+ return foo[3]*16777216 + foo[2]*65536 + foo[1]*256 + foo[0];
+}
+
+void int2char(unsigned int foo, unsigned char *bar)
+{
+ bar[3]=foo>>24;
+ bar[2]=foo>>16;
+ bar[1]=foo>>8;
+ bar[0]=foo;
+}
+
+void usage(void)
+{
+ printf("Usage: exefixup <filename>\n\n");
+ printf("\t<filename>\ta PS-X EXE file\n\n");
+ printf("\tdisplays EXE header\n");
+ printf("\toffers to correct a wrong t_size\n");
+ printf("\toffers to pad to 2048-byte boundary\n\n");
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *exe;
+ FILE *out;
+ unsigned char data[8];
+ char filename[256];
+ int i;
+ unsigned int header_data[12];
+ unsigned int size;
+ unsigned int padsize;
+ signed char yesno='Z';
+
+ printf("exefixup v0.02.1 Andrew Kieschnick <andrewk@mail.utexas.edu>\n\n");
+
+ if (argc!=2)
+ usage();
+
+ strncpy(filename,argv[1],256);
+
+ exe=fopen(filename, "r");
+
+ strcat(filename, "-fixed"); /* output filename is same as input filename, but with -fix appended */
+
+ if (!exe)
+ {
+ printf("ERROR: Can't open %s\n",filename);
+ exit(-1);
+ }
+
+ for(i=0;i<8;i++)
+ fscanf(exe, "%c", &data[i]);
+ data[8]=0;
+
+ if (strncmp((char*)data, "PS-X EXE", 8))
+ {
+ printf("ERROR: Not a PS-X EXE file\n");
+ exit(-1);
+ }
+
+ for(i=0;i<12;i++)
+ {
+ fscanf(exe, "%c", &data[0]);
+ fscanf(exe, "%c", &data[1]);
+ fscanf(exe, "%c", &data[2]);
+ fscanf(exe, "%c", &data[3]);
+ header_data[i]=char2int(data);
+ }
+
+ printf("id\tPS-X EXE\n");
+ printf("text\t0x%.8x\n", header_data[0]);
+ printf("data\t0x%.8x\n", header_data[1]);
+ printf("pc0\t0x%.8x\n", header_data[2]);
+ printf("gp0\t0x%.8x\n", header_data[3]);
+ printf("t_addr\t0x%.8x\n", header_data[4]);
+ printf("t_size\t0x%.8x\n", header_data[5]);
+ printf("d_addr\t0x%.8x\n", header_data[6]);
+ printf("d_size\t0x%.8x\n", header_data[7]);
+ printf("b_addr\t0x%.8x\n", header_data[8]);
+ printf("b_size\t0x%.8x\n", header_data[9]);
+ printf("s_addr\t0x%.8x\n", header_data[10]);
+ printf("s_size\t0x%.8x\n\n", header_data[11]);
+
+ fseek(exe, 0, SEEK_END);
+
+ size=ftell(exe)-2048;
+
+ padsize=2048-(size%2048);
+
+ if (padsize!=2048)
+ {
+ printf("WARNING: EXE size is not a multiple of 2048!\n");
+ while ((yesno!='Y')&&(yesno!='N'))
+ {
+ printf("Write a padded EXE (to %s) ? ",filename);
+ scanf("%c%*c", &yesno);
+ yesno=toupper(yesno);
+ }
+ if (yesno=='Y')
+ {
+ out = fopen(filename, "w");
+
+ header_data[5]=size+padsize;
+
+ fprintf(out, "PS-X EXE");
+ for(i=0;i<12;i++)
+ {
+ int2char(header_data[i], data);
+ fprintf(out, "%c%c%c%c", data[0], data[1], data[2], data[3]);
+ }
+
+ fseek(exe, 56, SEEK_SET);
+
+ for(i=0;i<size+1992;i++)
+ {
+ fscanf(exe, "%c", &data[0]);
+ fprintf(out, "%c", data[0]);
+ }
+ for(i=0;i<padsize;i++)
+ fprintf(out, "%c", 0);
+
+ size=header_data[5];
+ fclose(out);
+ }
+ }
+
+ yesno='Z';
+
+ if (size!=header_data[5])
+ {
+ printf("WARNING: EXE header t_size does not match filesize-2048\n");
+ printf("EXE header:\t 0x%.8x bytes\n", header_data[5]);
+ printf("filesize-2048:\t 0x%.8x bytes\n", size);
+ while ((yesno!='Y')&&(yesno!='N'))
+ {
+ printf("Write a corrected EXE (to %s) ? ",filename);
+ scanf("%c%*c", &yesno);
+ yesno=toupper(yesno);
+ }
+ if (yesno=='Y')
+ {
+ out = fopen(filename, "w");
+
+ fprintf(out, "PS-X EXE");
+ for(i=0;i<5;i++)
+ {
+ int2char(header_data[i], data);
+ fprintf(out, "%c%c%c%c", data[0], data[1], data[2], data[3]);
+ }
+ int2char(size, data);
+ fprintf(out, "%c%c%c%c", data[0], data[1], data[2], data[3]);
+ for(i=6;i<12;i++)
+ {
+ int2char(header_data[i], data);
+ fprintf(out, "%c%c%c%c", data[0], data[1], data[2], data[3]);
+ }
+
+ fseek(exe, 56, SEEK_SET);
+
+ for(i=0;i<size+1992;i++)
+ {
+ fscanf(exe, "%c", &data[0]);
+ fprintf(out, "%c", data[0]);
+ }
+ fclose(out);
+ }
+ }
+ fclose(exe);
+ return 0;
+}
diff --git a/tools/getpsxiso.c b/tools/getpsxiso.c
new file mode 100644
index 0000000..76cfc72
--- /dev/null
+++ b/tools/getpsxiso.c
@@ -0,0 +1,55 @@
+// Converts a bin suitable for burning for the PlayStation
+// to an ISO by getting only the 2048 data bytes of each sector
+// The reverse of mkpsxiso
+
+// Written by Giuseppe Gatta, 2010
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ FILE *i, *o;
+ int x, s;
+ char buf[2352];
+
+ if (argc < 3)
+ {
+ printf("getpsxiso <input> <output>\n");
+ return -1;
+ }
+
+ i = fopen(argv[1], "rb");
+
+ if(i == NULL)
+ {
+ printf("Could not open specified input file.\n");
+ return -1;
+ }
+
+ fseek(i, 0, SEEK_END);
+ s = ftell(i) / 2352;
+ fseek(i, 0, SEEK_SET);
+
+ if(s % 2352 == 0)
+ {
+ printf("Input file size not a multiplier of 2352.\n");
+ printf("Aborting.\n");
+ return -1;
+ }
+
+ o = fopen(argv[2], "wb");
+
+ for(x = 0; x < s; x++)
+ {
+ fread(buf, sizeof(char), 2352, i);
+ fwrite(buf + 24, sizeof(char), 2048, o);
+ printf("Sector %d/%d written\r", x+1, s);
+ }
+
+ printf("\n");
+
+ fclose(i);
+ fclose(o);
+
+ return 0;
+}
diff --git a/tools/huff.c b/tools/huff.c
new file mode 100644
index 0000000..0e28fc5
--- /dev/null
+++ b/tools/huff.c
@@ -0,0 +1,555 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define BUFFER_SIZE 1024
+
+struct TreeNode {
+ unsigned char value;
+ unsigned long freq;
+ struct TreeNode *left;
+ struct TreeNode *right;
+};
+
+struct CodeNode {
+ unsigned char value;
+ unsigned long code;
+ unsigned int codeSize;
+};
+
+unsigned long table[256];
+unsigned char value[256];
+unsigned long freq[256];
+int tableSize;
+
+struct CodeNode codes[256];
+unsigned int codesUsed;
+
+FILE *inFile;
+unsigned long inputSize;
+
+FILE *outFile;
+
+struct TreeNode *root;
+
+char inBuffer[BUFFER_SIZE];
+char outBuffer[BUFFER_SIZE];
+
+void CreateTable();
+void SiftHeap(struct TreeNode**, unsigned int, unsigned int);
+void SortTrees(struct TreeNode**, unsigned int);
+void DestroyTree(struct TreeNode *);
+void CreateTree();
+void GenerateCodes(struct TreeNode*, unsigned long, unsigned long);
+void SortCodes();
+void Compress();
+void Decompress();
+void DisplayHelp();
+int main(int, char**);
+
+//////////////////////////////////////////////////////////////////////////
+// Create the character frequency table for the file
+//////////////////////////////////////////////////////////////////////////
+void CreateTable() {
+ int x, y;
+ unsigned long maxCount;
+ unsigned char maxIndex;
+ unsigned char ch;
+
+ for(x = 0; x < 256; x++) {
+ value[x] = 0;
+ freq[x] = 0;
+ }
+
+ rewind(inFile);
+ tableSize = 0;
+ for(;;) {
+ ch = fgetc(inFile);
+ if(feof(inFile)) {
+ break;
+ }
+ ++inputSize;
+ if(table[ch] == 0) {
+ ++tableSize;
+ }
+ ++table[ch];
+ }
+
+ y = tableSize;
+ do {
+ --y;
+ maxIndex = 0;
+ maxCount = 0;
+ for(x = 0; x < 256 ; x++) {
+ if(table[x] > maxCount) {
+ maxIndex = x;
+ maxCount = table[(unsigned int)maxIndex];
+ }
+ }
+ freq[y] = maxCount;
+ value[y] = maxIndex;
+ table[(unsigned int)maxIndex] = 0;
+ } while(y > 0);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Max-heapify (for sorting)
+//////////////////////////////////////////////////////////////////////////
+void SiftHeap(struct TreeNode **trees, unsigned int x, unsigned int size) {
+ struct TreeNode *root;
+ int finished;
+ unsigned int y;
+
+ root = trees[x - 1];
+ y = x << 1;
+
+ finished = (y > size);
+ while(!finished) {
+ if(y < size) {
+ if(trees[y + 1 - 1]->freq > trees[y - 1]->freq) {
+ ++y;
+ }
+ }
+ if(trees[y - 1]->freq > root->freq) {
+ trees[x - 1] = trees[y - 1];
+ x = y;
+ y = x << 1;
+ finished = (y > size);
+ } else {
+ finished = 1;
+ }
+ }
+ trees[x - 1] = root;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sort the trees in ascending order by frequency
+//////////////////////////////////////////////////////////////////////////
+void SortTrees(struct TreeNode **trees, unsigned int num) {
+ struct TreeNode *temp;
+ unsigned int x;
+
+ for(x = num >> 1; x > 1; x--) {
+ SiftHeap(trees, x, num);
+ }
+
+ for(x = num; x > 1; x--) {
+ SiftHeap(trees, 1, x);
+ temp = trees[1 - 1];
+ trees[1 - 1] = trees[x - 1];
+ trees[x - 1] = temp;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Release the memory used by the tree
+//////////////////////////////////////////////////////////////////////////
+void DestroyTree(struct TreeNode *ptr) {
+ if(ptr->right) {
+ DestroyTree(ptr->right);
+ }
+ if(ptr->left) {
+ DestroyTree(ptr->left);
+ }
+ free(ptr);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Create the huffman coding tree
+//////////////////////////////////////////////////////////////////////////
+void CreateTree() {
+ struct TreeNode *ptr;
+ struct TreeNode *trees[257];
+ int x, y;
+
+ for(x = 0; x < tableSize; x++) {
+ trees[x] = malloc(sizeof(struct TreeNode));
+ trees[x]->right = 0;
+ trees[x]->left = 0;
+ trees[x]->value = value[x];
+ trees[x]->freq = freq[x];
+ }
+
+ y = tableSize;
+ while(y > 1) {
+ // Combine two smallest nodes into a tree
+ ptr = malloc(sizeof(struct TreeNode));
+ ptr->right = trees[0];
+ ptr->left = trees[1];
+ ptr->freq = trees[0]->freq + trees[1]->freq;
+ ptr->value = 0;
+ trees[0] = ptr;
+ for(x = 1; x < y - 1; x++) {
+ trees[x] = trees[x + 1];
+ }
+ trees[y] = 0;
+ SortTrees(trees, y - 1); // account for the zero
+ --y;
+ }
+
+ root = trees[0];
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Generate code table from the tree
+//////////////////////////////////////////////////////////////////////////
+void GenerateCodes(struct TreeNode *ptr, unsigned long code,
+ unsigned long codeSize) {
+ if(ptr->right) {
+ GenerateCodes(ptr->right, (code << 1), codeSize + 1);
+ GenerateCodes(ptr->left, (code << 1) | 1, codeSize + 1);
+ } else {
+ codes[codesUsed].value = ptr->value;
+ codes[codesUsed].code = code;
+ codes[codesUsed].codeSize = codeSize;
+ ++codesUsed;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Sort the codes in ascending order by size
+// Used for compression
+//////////////////////////////////////////////////////////////////////////
+void SortCodes() {
+ int x, y;
+ struct CodeNode temp;
+
+ for(x = 0; x < codesUsed; x++) {
+ for(y = x; y < codesUsed; y++) {
+ if(codes[x].codeSize > codes[y].codeSize) {
+ temp = codes[x];
+ codes[x] = codes[y];
+ codes[y] = temp;
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Compress the file
+//////////////////////////////////////////////////////////////////////////
+void Compress() {
+ int x, y;
+ unsigned char temp;
+ unsigned char ch;
+ int offset;
+ int ib, ob;
+ int inBufferSize;
+
+ CreateTable();
+ CreateTree();
+ codesUsed = 0;
+ GenerateCodes(root, 0, 0);
+ DestroyTree(root);
+ SortCodes();
+
+// [nextvolume]: Values are now saved as 32-bit little endian instead of ASCII numbers
+
+ fputc(codesUsed & 0xff, outFile);
+ fputc((codesUsed >> 8) & 0xff, outFile);
+ fputc((codesUsed >> 16) & 0xff, outFile);
+ fputc((codesUsed >> 24) & 0xff, outFile);
+
+ fputc(inputSize & 0xff, outFile);
+ fputc((inputSize >> 8) & 0xff, outFile);
+ fputc((inputSize >> 16) & 0xff, outFile);
+ fputc((inputSize >> 24) & 0xff, outFile);
+
+ for(x = 0; x < codesUsed; x++) {
+ fputc(codes[x].value, outFile);
+ fputc(codes[x].codeSize - 1, outFile);
+ }
+
+ offset = 7;
+ temp = 0;
+ for(x = 0; x < codesUsed; x++) {
+ for(y = codes[x].codeSize - 1; y >= 0; y--) {
+ temp |= ((codes[x].code >> y) & 1) << offset;
+ --offset;
+ if(offset < 0) {
+ fputc(temp, outFile);
+ offset = 7;
+ temp = 0;
+ }
+ }
+ }
+ if(offset != 7) {
+ fputc(temp, outFile);
+ }
+
+ offset = 7;
+ temp = 0;
+ rewind(inFile);
+ ib = BUFFER_SIZE;
+ ob = 0;
+ inBufferSize = 0;
+ for(;;) {
+ if(ib >= BUFFER_SIZE) {
+ inBufferSize = fread(inBuffer, sizeof(char),
+ BUFFER_SIZE, inFile);
+ ib = 0;
+ }
+ if(ib >= inBufferSize) {
+ break;
+ }
+ ch = inBuffer[ib++];
+ for(x = 0; x < codesUsed; x++) {
+ if(ch == codes[x].value) {
+ break;
+ }
+ }
+ for(y = codes[x].codeSize - 1; y >= 0; y--) {
+ temp |= ((codes[x].code >> y) & 1) << offset;
+ --offset;
+ if(offset < 0) {
+ outBuffer[ob++] = temp;
+ if(ob >= BUFFER_SIZE) {
+ fwrite(outBuffer, sizeof(char),
+ BUFFER_SIZE, outFile);
+ ob = 0;
+ }
+ temp = 0;
+ offset = 7;
+ }
+ }
+ }
+ if(offset != 7) {
+ outBuffer[ob++] = temp;
+ }
+ if(ob) {
+ fwrite(outBuffer, sizeof(char), ob, outFile);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Decompress the file
+//////////////////////////////////////////////////////////////////////////
+void Decompress() {
+ int x, y;
+ unsigned int dataSize;
+ unsigned long mask, maskSize;
+ unsigned char ch;
+ int offset;
+// int last;
+
+ int ib, ob;
+
+ ib = fgetc(inFile);
+ codesUsed = ib;
+ ib = fgetc(inFile);
+ codesUsed |= ib << 8;
+ ib = fgetc(inFile);
+ codesUsed |= ib << 16;
+ ib = fgetc(inFile);
+ codesUsed |= ib << 24;
+
+ ib = fgetc(inFile);
+ dataSize = ib;
+ ib = fgetc(inFile);
+ dataSize |= ib << 8;
+ ib = fgetc(inFile);
+ dataSize |= ib << 16;
+ ib = fgetc(inFile);
+ dataSize |= ib << 24;
+
+ for(x = 0; x < codesUsed; x++) {
+ codes[x].value = fgetc(inFile);
+ codes[x].codeSize = fgetc(inFile) + 1;
+ }
+
+ offset = 7;
+ ch = 0;
+ for(x = 0; x < codesUsed; x++) {
+ codes[x].code = 0;
+ for(y = codes[x].codeSize - 1; y >= 0; y--) {
+ if(offset == 7) {
+ ch = fgetc(inFile);
+ }
+ codes[x].code |= ((ch >> offset) & 1) << y;
+ offset = (offset - 1) & 7;
+ }
+ }
+
+ maskSize = 0;
+ mask = 0;
+ offset = 7;
+// last = 0;
+ y = 0;
+ x = 0;
+ ib = BUFFER_SIZE;
+ ob = 0;
+ for(;;) {
+ if(offset == 7) {
+ if(ib >= BUFFER_SIZE) {
+ fread(inBuffer, sizeof(char), BUFFER_SIZE,
+ inFile);
+ ib = 0;
+ }
+ ch = inBuffer[ib++];
+ }
+ mask <<= 1;
+ mask |= (ch >> offset) & 1;
+ ++maskSize;
+ offset = (offset - 1) & 7;
+
+ while(codes[y].codeSize < maskSize) ++y;
+ while(codes[y].codeSize == maskSize) {
+ if(codes[y].code == mask) {
+ if(ob >= BUFFER_SIZE) {
+ fwrite(outBuffer, sizeof(char),
+ BUFFER_SIZE, outFile);
+ ob = 0;
+ }
+ outBuffer[ob++] = codes[y].value;
+ ++x;
+ if(x >= dataSize) {
+ fwrite(outBuffer, sizeof(char),
+ ob, outFile);
+ return;
+ }
+ mask = 0;
+ maskSize = 0;
+ y = 0;
+ break;
+ }
+ ++y;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Display usage
+//////////////////////////////////////////////////////////////////////////
+void DisplayHelp() {
+ printf("Huffman compressor for PSXSDK\n");
+ printf("Original version by Joe Wingbermuehle\n");
+ printf("usage: huff [options] file\n");
+ printf("options:\n");
+ printf("\t-\t\tUse stdin for input\n");
+ printf("\t-c\t\tCompress/Uncompress to stdout\n");
+ printf("\t-k\t\tKeep old file\n");
+ printf("\t-u\t\tUncompress\n");
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Main
+//////////////////////////////////////////////////////////////////////////
+int main(int argc, char **argv) {
+ char *inName;
+ char *outName;
+ int x, y;
+ int error;
+ char uncompress;
+ char keep;
+ double savings;
+
+ if(argc < 2) {
+ DisplayHelp();
+ exit(1);
+ }
+
+ uncompress = 0;
+ keep = 0;
+ inName = 0;
+ outName = 0;
+ outFile = 0;
+ inFile = 0;
+ for(x = 1; x < argc; x++) {
+ if(argv[x][0] == '-') {
+ switch(argv[x][1]) {
+ case 'u':
+ uncompress = 1;
+ break;
+ case 'c':
+ outFile = stdout;
+ keep = 1;
+ break;
+ case 'k':
+ keep = 1;
+ break;
+ case 0:
+ inFile = stdout;
+ break;
+ default:
+ DisplayHelp();
+ exit(1);
+ }
+ } else if(!inName && !inFile) {
+ inName = malloc(strlen(argv[x]) + 1);
+ strcpy(inName, argv[x]);
+ } else {
+ printf("unrecognized option: %s\n", argv[x]);
+ DisplayHelp();
+ exit(1);
+ }
+ }
+
+ if(!inFile) {
+ inFile = fopen(inName, "rb");
+ if(!inFile) {
+ printf("error: could not open input\n");
+ exit(1);
+ }
+ }
+
+ if(!uncompress) {
+ outName = malloc(strlen(inName) + 4);
+ strcpy(outName, inName);
+ strcat(outName, ".jh");
+ } else {
+ error = 0;
+ if(strlen(inName) < 5) {
+ error = 1;
+ } else {
+ y = strlen(inName) - 3;
+ for(x = 0; x < 4; x++) {
+ if(inName[x + y] != ".jh"[x]) {
+ error = 1;
+ break;
+ }
+ }
+ }
+ if(error) {
+ printf("bad file extension\n");
+ DisplayHelp();
+ exit(1);
+ }
+ outName = malloc(strlen(inName) + 1);
+ strcpy(outName, inName);
+ if(strlen(outName) > 4) {
+ outName[strlen(outName) - 3] = 0;
+ }
+ }
+
+ if(!outFile) {
+ outFile = fopen(outName, "wb");
+ if(!outFile) {
+ printf("error: could not open output\n");
+ exit(1);
+ }
+ }
+
+ if(uncompress) {
+ Decompress();
+ } else {
+ Compress();
+ savings = (double)inputSize - (double)ftell(outFile);
+ savings /= (double)inputSize;
+ savings *= 100.00;
+ printf("savings: %.2f%%\n", savings);
+ }
+
+ if(inFile != stdin) {
+ fclose(inFile);
+ if(!keep) {
+ remove(inName);
+ }
+ }
+ if(outFile != stdout) {
+ fclose(outFile);
+ }
+ exit(0);
+}
+
+
diff --git a/tools/lictool.c b/tools/lictool.c
new file mode 100644
index 0000000..4fcf493
--- /dev/null
+++ b/tools/lictool.c
@@ -0,0 +1,100 @@
+/*
+ * lictool
+ *
+ * Tool for manipulating PS1 license files
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+unsigned char lic_buffer[37632]; // 16 CD sectors..
+
+//0x2E08
+
+void display_usage();
+
+void display_usage()
+{
+ printf(""
+ "lictool - PS1 license file manipulation tool\n"
+ "usage: lictool <input> <output> <options>\n"
+ "\n"
+ "Options:\n"
+ " -tmd=<file> TMD file for boot logo\n"
+ " -removelogo Remove logo from license file\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int x,y,z,sz;
+ FILE *f;
+
+ if(argc < 3)
+ {
+ display_usage();
+ return 0;
+ }
+
+ f = fopen(argv[1], "rb");
+
+ if(f == NULL)
+ {
+ printf("Could not open input license file! Aborting.\n");
+ return -1;
+ }
+
+ fread(lic_buffer, sizeof(char), 37632, f);
+ fclose(f);
+
+ for(x = 3; x < argc; x++)
+ {
+ if(strncmp(argv[x], "-tmd=", 5) == 0)
+ {
+ f = fopen(argv[x] + 5, "rb");
+
+ if(f == NULL)
+ printf("Could not open TMD file %s. Ignoring option.\n", argv[x] + 5);
+ else
+ {
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ z = 0x2E08;
+
+ for(y = 0; y < sz; y++)
+ {
+ if((z - ((z / 2352)*2352)) == 2072)
+ z+=304;
+
+ fread(&lic_buffer[z], sizeof(char), 1, f);
+
+ z++;
+ }
+
+ fclose(f);
+ }
+ }
+ else if(strncmp(argv[x], "-removelogo", 11) == 0)
+ {
+ z = 0x2E08;
+
+ for(y = 0; y < 12; y++)
+ lic_buffer[z+y] = 0;
+
+ lic_buffer[z] = 0x41;
+ }
+ }
+
+ f = fopen(argv[2], "wb");
+
+ if(f == NULL)
+ {
+ printf("Could not open output file path for writing! Aborting.\n");
+ return -1;
+ }
+
+ fwrite(lic_buffer, sizeof(char), 37632, f);
+ fclose(f);
+
+ return 0;
+}
diff --git a/tools/mkpsxiso.c b/tools/mkpsxiso.c
new file mode 100644
index 0000000..5fd9da5
--- /dev/null
+++ b/tools/mkpsxiso.c
@@ -0,0 +1,250 @@
+/*
+ * mkpsxiso
+ *
+ * Converts an ISO to a .bin/.cue of a Playstation disk
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+char iso2raw_sec[16];
+char iso2raw_sub[8];
+char iso2raw_buf[2048];
+char iso2raw_edc[4];
+char iso2raw_ecc[276];
+
+void Iso2Raw_init()
+{
+ int x;
+
+ for(x = 0; x < 16; x++)
+ iso2raw_sec[x] = 0xFF;
+
+ iso2raw_sec[0] = 0;
+ iso2raw_sec[11] = 0;
+ iso2raw_sec[12] = 0;
+ iso2raw_sec[13] = 2;
+ iso2raw_sec[14] = 0;
+ iso2raw_sec[15] = 2;
+
+ for(x = 0; x < 8; x++)
+ iso2raw_sub[x] = 0;
+
+ for(x = 0; x < 4; x++)
+ iso2raw_edc[x] = 1;
+
+ for(x = 0; x < 276; x++)
+ iso2raw_ecc[x] = 2;
+}
+
+int Iso2Raw_licenseFile(char *licFile, char *binFile) {
+ FILE *lic, *bin;
+ char buffer[37632];
+ int sz;
+ int ret;
+
+ lic = fopen(licFile, "rb"); //lic = new RandomAccessFile(licFile, "r");
+
+ if(lic == NULL)
+ {
+ printf("Error! Could not open license file!\n");
+ ret = 0;
+ goto Iso2Raw_licenseFile_end;
+ }
+
+ bin = fopen(binFile, "rb+"); //bin = new RandomAccessFile(binFile, "rw");
+
+ if(bin == NULL)
+ {
+ printf("Error! Could not open BIN file!\n");
+ fclose(lic);
+ ret = 0;
+ goto Iso2Raw_licenseFile_end;
+ }
+
+ fseek(lic, 0, SEEK_END);
+ sz = ftell(lic);
+ fseek(lic, 0, SEEK_SET);
+
+
+ if (sz != 37632)
+ {
+ printf("Error! License file size mismatch. Image not licensed!\n");
+ fclose(lic);
+ fclose(bin);
+ ret = 0;
+ goto Iso2Raw_licenseFile_end;
+ }
+
+ fseek(bin, 0, SEEK_END);
+ sz = ftell(bin);
+ fseek(bin, 0, SEEK_SET);
+
+ if ((sz % 2352) != 0)
+ {
+ printf("Error! RAW image file size is not a multiple of 2352. Image not licensed!\n");
+ fclose(lic);
+ fclose(bin);
+ ret = 0;
+ goto Iso2Raw_licenseFile_end;
+ }
+
+ fread(buffer, sizeof(char), 37632, lic);
+ fwrite(buffer, sizeof(char), 37632, bin);
+
+ fclose(lic);
+ fclose(bin);
+ ret = 1;
+
+Iso2Raw_licenseFile_end:
+ if(ret == 0)
+ printf("Error licensing file! You must NOT burn the RAW image!\n");
+
+ return ret;
+}
+
+void Iso2Raw_generateCue(char *binFileName)
+{
+ int x, y;
+ char binBaseName[256];
+ char cueFileName[256];
+ FILE *cue_file;
+
+ for(x = (strlen(binFileName) - 1); x >= 0; x--)
+ {
+ if(binFileName[x] == '/' || binFileName[x] == '\\' || binFileName[x] == ':')
+ break;
+ }
+
+ x++;
+ y = 0;
+
+ for(; x < strlen(binFileName); x++)
+ binBaseName[y++] = binFileName[x];
+
+ binBaseName[y] = 0;
+
+ y = 0;
+
+ for(x = 0; x < strlen(binFileName); x++)
+ {
+ if(binFileName[x] == '.')
+ break;
+ else
+ cueFileName[y++] = binFileName[x];
+ }
+
+ cueFileName[y] = 0;
+
+ strcat(cueFileName, ".cue");
+
+ cue_file = fopen(cueFileName, "wb");
+
+ fprintf(cue_file, "FILE \"%s\" BINARY\n", binBaseName);
+ fprintf(cue_file, "TRACK 01 MODE2/2352\n");
+ fprintf(cue_file, " INDEX 01 00:00:00\n");
+
+ fclose(cue_file);
+}
+
+int Iso2Raw_convert(char *isofile, char *rawfile, char *licfile)
+{
+ FILE *infile, *outfile;
+ int c;
+ int thesec = 0;
+ int filesize, totalsectors, sector;
+
+ infile = fopen(isofile, "rb");
+
+ if(infile == NULL)
+ {
+ printf("An error has occured while trying to open file %s\n", isofile);
+ return 0;
+ }
+
+ fseek(infile, 0, SEEK_END);
+ filesize = ftell(infile);
+ fseek(infile, 0, SEEK_SET);
+
+ if ((filesize % 2048) != 0)
+ {
+ printf("Error! ISO file size is not a multiple of 2048. Operation aborted!\n");
+ fclose(infile);
+ return 0;
+ }
+
+ outfile = fopen(rawfile, "wb+");
+ fseek(outfile, 0, SEEK_SET);
+
+ if(outfile == NULL)
+ {
+ printf("An error has occured while trying to create file %s\n", rawfile);
+ fclose(infile);
+ return 0;
+ }
+
+ sector = 1;
+ totalsectors = filesize / 2048;
+ for(;;)
+ {
+ c = fread(iso2raw_buf, sizeof(char), 2048, infile);
+ if(c!=2048)break;
+
+ fwrite(iso2raw_sec, sizeof(char), 16, outfile);
+ fwrite(iso2raw_sub, sizeof(char), 8, outfile);
+ fwrite(iso2raw_buf, sizeof(char), 2048, outfile);
+ fwrite(iso2raw_edc, sizeof(char), 4, outfile);
+ fwrite(iso2raw_ecc, sizeof(char), 276, outfile);
+
+ thesec++;
+
+ if (thesec > 74)
+ {
+ thesec = 0;
+ iso2raw_sec[13]++;
+ }
+
+ iso2raw_sec[14] = ((thesec/10)<<4)|(thesec - ((thesec/10)*10));
+
+ printf("\r%d%% completed...", sector * 100 / totalsectors);
+ sector++;
+ }
+
+ printf("\r100%% completed! \n");
+
+ fclose(infile);
+ fclose(outfile);
+
+ Iso2Raw_generateCue(rawfile);
+
+ if(!Iso2Raw_licenseFile(licfile, rawfile))
+ return 0;
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ puts("mkpsxiso (C Edition) v0.1b - Converts a standard ISO image to .bin/.cue (PSX)");
+ puts("This software is based on Bruno Freitas' mkpsxiso in Java - bootsector@ig.com.br");
+ puts("That version is in turn based on Conyers' mkpsxiso - http://www.conyers.demon.co.uk");
+ puts("Author: Giuseppe Gatta (aka nextvolume) - 01/07/2009 - tails92@gmail.com\n");
+
+ if(argc != 4)
+ {
+ printf("Usage: mkpsxiso <iso file> <bin file> <PSX license file>\n");
+ return 1;
+ }
+
+ Iso2Raw_init();
+
+ if (!Iso2Raw_convert(argv[1], argv[2], argv[3]))
+ {
+ puts("ISO file conversion failed.");
+ return 1;
+ }
+
+ puts("ISO file conversion terminated successfully!!");
+
+ return 0;
+}
diff --git a/tools/mod4psx.c b/tools/mod4psx.c
new file mode 100644
index 0000000..1fc68ef
--- /dev/null
+++ b/tools/mod4psx.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "../libmodplay/modplay.h"
+#include "adpcm.h"
+
+unsigned char *mod_data;
+ModMusic *mod;
+
+// Container format
+
+// Header
+
+// 8 bytes - "_mod4psx"
+// 4 bytes - Number of samples contained
+
+// Sample format
+// 4 bytes - Length of ADPCM sample
+// 8 bytes - Reserved
+// ... Data ...
+
+// All multi word numerical values are in little endian format
+// which is used by the processor of the PlayStation.
+// All data is aligned to 4 bytes.
+
+unsigned char adpcm_buffer[0x10000];
+
+int main(int argc, char *argv[])
+{
+ FILE *f;
+ int sz, x,y;
+
+ if(argc < 3)
+ {
+ printf("mod4psx <mod_music> <adpcm_dat>\n");
+ printf(
+"\nMOD4PSX gets the sound samples from a music module supported by libmodplay, "
+"and then converts them to PS1 ADPCM format and puts them all in a datafile, which will be able to be loaded "
+"by libmodplay. In this way the CPU time needed by the PlayStation processor to convert at runtime from PCM to ADPCM is saved.\n"
+);
+ return -1;
+ }
+
+ f = fopen(argv[1], "rb");
+
+ if(f == NULL)
+ {
+ printf("Could not open %s for reading. Aborting.\n", argv[1]);
+ return -1;
+ }
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ mod_data = malloc(sz);
+
+ if(mod_data == NULL)
+ {
+ printf("Could not allocate %d bytes of memory. Aborting.\n", sz);
+ return -1;
+ }
+
+ fread(mod_data, sizeof(char), sz, f);
+
+ fclose(f);
+
+ mod = MODLoad(mod_data);
+
+ printf("Title: %s\n", mod->title);
+
+
+
+ f = fopen(argv[2], "wb");
+
+// Write header
+
+// Magic string
+ fprintf(f, "_mod4psx");
+// Write number of samples
+ fputc(mod->sample_num & 0xff, f);
+ fputc((mod->sample_num >> 8) & 0xff, f);
+ fputc(0, f);
+ fputc(0, f);
+
+ for(x = 0; x < mod->sample_num; x++)
+ {
+ //printf("%d: %s\n", x, mod->sample[x].name);
+ printf("sample[%d].bits = %d, sample[%d].data_type = %d\n", x, mod->sample[x].bits, x, mod->sample[x].data_type);
+
+
+ if(mod->sample[x].length >= 32)
+ {
+ if((mod->sample[x].data_type & 1) && mod->sample[x].bits == 8)
+ {
+ for(y = 0; y < mod->sample[x].length; y++)
+ mod->sample[x].data[y]^=0x80;
+ }
+
+ if(//mod->fmt == MOD_FMT_MOD &&
+ mod->sample[x].repeat_len > 2)
+ {
+
+ sz = SsAdpcmPack(mod->sample[x].data, adpcm_buffer, // FIX THIS!!!
+ mod->sample[x].length / (mod->sample[x].bits / 8), (mod->sample[x].bits==16)?FMT_S16:FMT_U8,
+ sizeof(adpcm_buffer),
+ 1, mod->sample[x].repeat_off);
+
+ }
+ else
+ {
+
+
+ sz = SsAdpcmPack(mod->sample[x].data, adpcm_buffer,
+ mod->sample[x].length / (mod->sample[x].bits / 8), (mod->sample[x].bits==16)?FMT_S16:FMT_U8,
+ sizeof(adpcm_buffer), 0, 0);
+
+ }
+
+ printf("%d) %s, %d -> %d, %d, %d, FIN=%d\n", x, mod->sample[x].name,
+ mod->sample[x].length, sz,
+ mod->sample[x].repeat_off,
+ mod->sample[x].repeat_len, mod->sample[x].finetune);
+ }
+ else
+ {
+ printf("%d) %s, Not written\n", x, mod->sample[x].name);
+ sz = 0;
+ }
+
+// Write length of ADPCM sample
+
+ fputc(sz & 0xff, f);
+ fputc((sz>>8)&0xff, f);
+ fputc((sz>>16)&0xff, f);
+ fputc((sz>>24)&0xff, f);
+
+// Skip 8 reserved bytes - for future expansion...
+
+ fseek(f, 8, SEEK_CUR);
+
+// Write ADPCM sample data
+
+// Manipulate the samples to do looping for Protracker MOD samples
+// The PCM to ADPCM conversion routines haven't been modified to do this yet.
+
+ /*if(mod->sample[x].repeat_len > 2 &&
+ mod->fmt == MOD_FMT_MOD)
+ {
+
+ for(y = 0; y < ((sz / 16)-1); y++)
+ {
+ if((mod->sample[x].repeat_off / 28) == y)
+ adpcm_buffer[(y<<4) + 1] = 6;
+ else
+ adpcm_buffer[(y<<4) + 1] = 2;
+ }
+
+ adpcm_buffer[(y<<4) + 1] = 3;
+ }*/
+
+ fwrite(adpcm_buffer, sizeof(char), sz, f);
+ }
+
+ return 0;
+}
diff --git a/tools/psfex.c b/tools/psfex.c
new file mode 100644
index 0000000..3de4bc8
--- /dev/null
+++ b/tools/psfex.c
@@ -0,0 +1,113 @@
+/*
+ * psfex - Extracts an EXE from a PSF file
+ *
+ * Programmed by Giuseppe Gatta - released in the public domain
+ * It can be used for any platform which the PSF format supports, not only PS1.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+// 0-2: PSF
+// 3: Version byte (0x01 for PlayStation)
+// 4: Size of reserved area (LE unsigned 32-bit)
+// 8: Compressed program length (LE unsigned 32-bit)
+// 12: Compressed program CRC32 (LE unsigned 32-bit)
+// xxx: Reserved area
+// xxx: Compressed program
+
+int main(int argc, char *argv[])
+{
+ FILE *f;
+ unsigned char *fm;
+ unsigned int res_size;
+ unsigned int cprg_size;
+ unsigned int cprg_crc32;
+ unsigned char *om;
+ unsigned long dest_len;
+ int sz;
+
+ if(argc < 3)
+ {
+ printf("psfex - Extracts an executable from a PSF file\n");
+ printf("psfex [.psf] [output]\n");
+ return -1;
+ }
+
+ f = fopen(argv[1], "rb");
+
+ if (f == NULL)
+ {
+ printf("Could not open file.\n");
+ return -1;
+ }
+
+/*
+ * Get PSF size and load it in memory
+ */
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ fm = malloc(sz);
+ fread(fm, sizeof(char), sz, f);
+
+ fclose(f);
+
+/*
+ * Get header information
+*/
+ if(fm[0] == 'P' && fm[1] == 'S' && fm[2] == 'F')
+ {
+ printf("PSF file.\n");
+ }
+ else
+ {
+ printf("Not a PSF file. Aborting.\n");
+ return -1;
+ }
+
+ res_size = fm[4] | (fm[5] << 8) | (fm[6]<<16) | (fm[7]<<24);
+ cprg_size = fm[8] | (fm[9] << 8) | (fm[10]<<16)|(fm[11]<<24);
+ cprg_crc32 = fm[12] | (fm[13]<<8)|(fm[14]<<16)|(fm[15]<<24);
+
+ printf("Reserved area size: %d bytes\n", res_size);
+ printf("Compressed program size: %d bytes\n", cprg_size);
+ printf("Compressed program CRC32: 0x%08x\n", cprg_crc32);
+
+/*
+ * Decompress the program
+ * The PSF format is inherently flawed and so we have to allocate 2 megabytes
+ * of memory (size of PS1 RAM) and then get the real destination size at the end
+ */
+ om = malloc(0x200000);
+ dest_len = 0x200000;
+ uncompress(om, &dest_len, &fm[16 + res_size], cprg_size);
+
+ printf("Real destination length: %ld\n", dest_len);
+
+/*
+ * Now let's write the decompressed program to the output file
+ */
+ f = fopen(argv[2], "wb");
+
+ if(f == NULL)
+ {
+ printf("Could not open %s for writing. Aborting.\n", argv[2]);
+ return -1;
+ }
+
+ fwrite(om, sizeof(char), dest_len, f);
+ fclose(f);
+
+/*
+ * Free memory, at the exit it is done anyway but this helps adaptions
+ */
+
+ free(om);
+ free(fm);
+
+ return 0;
+}
diff --git a/tools/spasm/Makefile b/tools/spasm/Makefile
new file mode 100644
index 0000000..093b9b5
--- /dev/null
+++ b/tools/spasm/Makefile
@@ -0,0 +1,17 @@
+include ../../Makefile.cfg
+
+OUT = spasm$(EXE_SUFFIX)
+
+OBJS = $(patsubst %.c, %.o, $(wildcard *.c))
+
+$(OUT): $(OBJS)
+ $(HOST_CC) $(HOST_CFLAGS) -o $(OUT) $(OBJS)
+
+%.o: %.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -o $@ $<
+
+install:
+ cp -rv $(OUT) $(TOOLCHAIN_PREFIX)/bin
+
+clean:
+ rm -f $(OBJS) $(OUT)
diff --git a/tools/spasm/codegen.c b/tools/spasm/codegen.c
new file mode 100644
index 0000000..fda456d
--- /dev/null
+++ b/tools/spasm/codegen.c
@@ -0,0 +1,144 @@
+#include "spasm.h"
+
+char curIns[128];
+unsigned int curInsArg;
+unsigned int curInsArgT;
+unsigned int insArgv[64];
+unsigned int insArgc;
+unsigned int insArgt[64];
+unsigned int copn;
+int org_found;
+
+void (*INSFUNC)(void);
+
+volatile unsigned int curPc = 0;
+int curPass = 0;
+unsigned int startAddress = 0;
+unsigned int numLabels;
+unsigned int numLabelsAlloc;
+int first_instruction;
+asm_label *labels;
+static int find_label_status = 1;
+
+void codegen_init(void)
+{
+ curPc = startAddress;
+ curPass = 0;
+ numLabels = 0;
+ numLabelsAlloc = 0;
+ labels = NULL;
+}
+
+static asm_label *find_label_internal(char *name)
+{
+ int i;
+
+ for(i = 0; i < numLabels; i++)
+ {
+ if(strcmp(name, labels[i].name) == 0)
+ return &labels[i];
+ }
+
+ return NULL;
+}
+
+static void add_label_internal(char *name, unsigned int pc)
+{
+ // add labels only if current pass >= 1!
+ asm_label *l;
+
+/* if(curPass == )
+ return;
+
+ if(curPass >= 2)
+ return;*/
+
+ //printf("Name = %s\n", name);
+
+ l = find_label_internal(name);
+
+ if(l)
+ {
+ if(l->pc != pc)
+ {
+ //if(l->pass == curPass)
+ // assembler_error("Impossible to redefine label %s", name);
+
+ //printf("Redefining, [%s] = %08X, pass %d\n", l->name, pc, curPass);
+ l->pc = pc;
+ }
+
+ return;
+ }
+
+ if(numLabels == numLabelsAlloc)
+ {
+ numLabelsAlloc += 128;
+ labels = realloc(labels, sizeof(asm_label) * numLabelsAlloc);
+ }
+
+ strncpy(labels[numLabels].name, name, 127);
+ labels[numLabels].pass = curPass;
+
+ labels[numLabels].pc = pc;
+
+ numLabels++;
+
+ //printf("label #%d, [%s] = %08X, pass = %d\n", numLabels, name, pc, curPass);
+
+ /*while(*name)
+ {
+ printf("%x, \'%c\'\n", *name, *name);
+ name++;
+ }*/
+}
+
+
+
+void add_label(char *name, unsigned int pc)
+{
+ if(curPass == -1)
+ return;
+
+ return add_label_internal(name, pc);
+}
+
+void add_label_equ(char *name, unsigned int pc)
+{
+ return add_label_internal(name, pc);
+}
+
+unsigned int find_label(char *name)
+{
+ //printf("find_label(%s)\n", name);
+
+ asm_label *l = find_label_internal(name);
+
+ if(l)
+ {
+ //find_label_status = 1;
+ return l->pc;
+ }
+
+// remember! if pass >= 1, abort if you can't find a label, because that means it was really
+// impossible to find.
+
+// printf(">>DEBUG, PASS = %d << Couldn't find label %s$\n", curPass, name);
+
+ find_label_status = 0;
+
+ if(curPass == 1)
+ instruction_error("Cannot find label %s", name);
+
+ return 0xFFFFFFFF;
+}
+
+void find_label_reset()
+{
+ find_label_status = 1;
+}
+
+int find_label_ok()
+{
+ return find_label_status;
+}
diff --git a/tools/spasm/codegen.h b/tools/spasm/codegen.h
new file mode 100644
index 0000000..e9e0ab7
--- /dev/null
+++ b/tools/spasm/codegen.h
@@ -0,0 +1,33 @@
+#ifndef _SPASM_CODEGEN_H
+#define _SPASM_CODEGEN_H
+
+typedef struct
+{
+ char name[128];
+ unsigned int pc;
+ unsigned int pass;
+}asm_label;
+
+extern asm_label *labels;
+
+extern volatile unsigned int curPc;
+extern int curPass;
+extern unsigned int numLabels;
+extern unsigned int startAddress;
+extern unsigned int copn;
+extern int first_instruction;
+extern int org_found;
+extern void (*INSFUNC)(void);
+
+void codegen_init(void);
+void add_label(char *label, unsigned int pc);
+void add_label_equ(char *label, unsigned int pc);
+unsigned int find_label(char *label);
+void find_label_reset();
+int find_label_ok();
+int label_was_not_found_once(char *name);
+void add_not_found_label(char *name);
+//void resolve_labels();
+
+
+#endif
diff --git a/tools/spasm/error.c b/tools/spasm/error.c
new file mode 100644
index 0000000..019c3da
--- /dev/null
+++ b/tools/spasm/error.c
@@ -0,0 +1,58 @@
+#include "spasm.h"
+
+static void show_line(void)
+{
+ printf("%s\n", curLine);
+ printf("^^^^^^^^^^^^^^\n");
+}
+
+void instruction_error(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ printf("Line %d: Error(%s) - ", line_number, curIns);
+ vprintf(format, ap);
+ printf("\n");
+ show_line();
+
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+void instruction_warning(char *format, ...)
+{
+ if(curPass <= 0)
+ return;
+
+ va_list ap;
+
+ va_start(ap, format);
+
+ printf("Line %d: Warning (%s) - ", line_number, curIns);
+ vprintf(format, ap);
+ printf("\n");
+ show_line();
+
+ va_end(ap);
+}
+
+void assembler_error(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ printf("Line %d, assembler error: ", line_number);
+ vprintf(format, ap);
+ printf("\n");
+ show_line();
+
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+ \ No newline at end of file
diff --git a/tools/spasm/error.h b/tools/spasm/error.h
new file mode 100644
index 0000000..3951ffd
--- /dev/null
+++ b/tools/spasm/error.h
@@ -0,0 +1,10 @@
+#ifndef _SPASM_ERROR_H
+#define _SPASM_ERROR_H
+
+void instruction_error(char *format, ...);
+void instruction_warning(char *format, ...);
+void assembler_error(char *format, ...);
+extern int yylineno;
+
+#endif
+
diff --git a/tools/spasm/eval.c b/tools/spasm/eval.c
new file mode 100644
index 0000000..01f8f66
--- /dev/null
+++ b/tools/spasm/eval.c
@@ -0,0 +1,130 @@
+#include "spasm.h"
+
+/**
+ * Expressions in SPASM are implemented in a totally broken manner.
+ *
+ * The result of an expression is the value of its initial argument
+ * after executing the operation of the last operand with the last argument.
+ *
+ * For example dw $cafeba00+2+4 is not equal to dw $cafeba06
+ * but to dw $cafeba04.
+ * Likewise, dw $2+$cafeba00+4 is not equal to dw $cafeba06
+ * but to dw $6 !
+ */
+
+unsigned int spasm_eval(char *expr)
+{
+ char *cset = "+-><&|*!";
+ char *csetp;
+ char *cp;
+ int ok;
+ int t = T_INTEGER;
+ char sbuf[128];
+
+ if(strcmp(expr, "*") == 0) // Return current return address
+ return curPc;
+
+ if(strcasecmp(curIns, "incbin") == 0)
+ return 0; // If current instruction is incbin, do not evaluate.
+
+ if(*expr == '"' || *expr == '\'')
+ return 0; // I won't even try to evaluate strings!
+
+ int ispan = strcspn(expr, cset);
+
+ csetp = cset;
+
+ ok = 0; // ok will be 0 if we found no operator, 1 if we found it
+
+ char op = '?';
+
+ cp = NULL;
+
+ while(*csetp)
+ {
+ char *tcp = strrchr(expr, *csetp);
+
+ if(tcp) // Found operator
+ {
+ if(tcp > cp)
+ cp = tcp;
+
+ if(*cp == '>')
+ {
+ if(*(cp-1) != '>')
+ instruction_error("Bad operator");
+ }
+
+ if(*cp == '<')
+ {
+ if(*(cp-1) != '<')
+ instruction_error("Bad operator");
+ }
+
+ cp++;
+ ok = 1;
+ op = *csetp;
+ break;
+ }
+
+ csetp++;
+ }
+
+ unsigned int one = 0;
+ unsigned int two = 0;
+
+ memcpy(sbuf, expr, ispan);
+ sbuf[ispan] = '\0';
+
+ if(strlen(sbuf) == 0)
+ strcpy(sbuf, "0");
+ //instruction_error("Bad expression");
+
+ //printf("sbuf = %s\n", sbuf);
+ one = asm_atoi(sbuf);
+
+ t = atoiT[insArgc];
+
+ if(ok)
+ {
+ strcpy(sbuf, cp);
+
+ if(strlen(sbuf) == 0)
+ instruction_error("Bad expression");
+
+ two = asm_atoi(sbuf);
+
+ if(t == T_INTEGER)
+ t = atoiT[insArgc];
+ }
+
+ atoiT[insArgc] = t;
+
+ switch(op)
+ {
+ case '+':
+ return one + two;
+ break;
+ case '-':
+ return one - two;
+ break;
+ case '<':
+ return one << two;
+ break;
+ case '>':
+ return one >> two;
+ break;
+ case '&':
+ return one & two;
+ break;
+ case '|':
+ case '!':
+ return one | two;
+ break;
+ case '*':
+ return one * two;
+ break;
+ }
+
+ return one;
+}
diff --git a/tools/spasm/eval.h b/tools/spasm/eval.h
new file mode 100644
index 0000000..a568f7e
--- /dev/null
+++ b/tools/spasm/eval.h
@@ -0,0 +1,6 @@
+#ifndef _SPASM_EVAL_H
+#define _SPASM_EVAL_H
+
+unsigned int spasm_eval(char *expr);
+
+#endif
diff --git a/tools/spasm/fcaseopen.c b/tools/spasm/fcaseopen.c
new file mode 100755
index 0000000..20efd5b
--- /dev/null
+++ b/tools/spasm/fcaseopen.c
@@ -0,0 +1,137 @@
+/*
+Copyright (c) 2009 Keith Bauer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "fcaseopen.h"
+
+#if !defined(_WIN32)
+#include <stdlib.h>
+#include <string.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+
+// r must have strlen(path) + 2 bytes
+static int casepath(char const *path, char *r)
+{
+ size_t l = strlen(path);
+ char *p = alloca(l + 1);
+ strcpy(p, path);
+ size_t rl = 0;
+
+ DIR *d;
+ if (p[0] == '/')
+ {
+ d = opendir("/");
+ p = p + 1;
+ }
+ else
+ {
+ d = opendir(".");
+ r[0] = '.';
+ r[1] = 0;
+ rl = 1;
+ }
+
+ int last = 0;
+ char *c = strsep(&p, "/");
+ while (c)
+ {
+ if (!d)
+ {
+ return 0;
+ }
+
+ if (last)
+ {
+ closedir(d);
+ return 0;
+ }
+
+ r[rl] = '/';
+ rl += 1;
+ r[rl] = 0;
+
+ struct dirent *e = readdir(d);
+ while (e)
+ {
+ if (strcasecmp(c, e->d_name) == 0)
+ {
+ strcpy(r + rl, e->d_name);
+ rl += strlen(e->d_name);
+
+ closedir(d);
+ d = opendir(r);
+
+ break;
+ }
+
+ e = readdir(d);
+ }
+
+ if (!e)
+ {
+ strcpy(r + rl, c);
+ rl += strlen(c);
+ last = 1;
+ }
+
+ c = strsep(&p, "/");
+ }
+
+ if (d) closedir(d);
+ return 1;
+}
+#endif
+
+FILE *fcaseopen(char const *path, char const *mode)
+{
+ FILE *f = fopen(path, mode);
+#if !defined(_WIN32)
+ if (!f)
+ {
+ char *r = alloca(strlen(path) + 2);
+ if (casepath(path, r))
+ {
+ f = fopen(r, mode);
+ }
+ }
+#endif
+ return f;
+}
+
+void casechdir(char const *path)
+{
+#if !defined(_WIN32)
+ char *r = alloca(strlen(path) + 2);
+ if (casepath(path, r))
+ {
+ chdir(r);
+ }
+ else
+ {
+ errno = ENOENT;
+ }
+#else
+ chdir(path);
+#endif
+}
diff --git a/tools/spasm/fcaseopen.h b/tools/spasm/fcaseopen.h
new file mode 100755
index 0000000..a6d024b
--- /dev/null
+++ b/tools/spasm/fcaseopen.h
@@ -0,0 +1,40 @@
+/*
+Copyright (c) 2009 Keith Bauer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef fcaseopen_h
+#define fcaseopen_h
+
+#include <stdio.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern FILE *fcaseopen(char const *path, char const *mode);
+
+extern void casechdir(char const *path);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/tools/spasm/opcode.c b/tools/spasm/opcode.c
new file mode 100644
index 0000000..a09c119
--- /dev/null
+++ b/tools/spasm/opcode.c
@@ -0,0 +1,2214 @@
+#include "spasm.h"
+
+struct
+{
+ char *name;
+ void (*func)();
+}instruction_table[] =
+{
+ {"add" ,INS_ADD},
+ {"addi" ,INS_ADDI},
+ {"addiu" ,INS_ADDIU},
+ {"addu" ,INS_ADDU},
+ {"and" ,INS_AND},
+ {"andi" ,INS_ANDI},
+ {"beq" ,INS_BEQ},
+ {"bgez" ,INS_BGEZ},
+ {"bgezal" ,INS_BGEZAL},
+ {"bgtz" ,INS_BGTZ},
+ {"blez" ,INS_BLEZ},
+ {"bltz" ,INS_BLTZ},
+ {"bltzal" ,INS_BLTZAL},
+ {"bne" ,INS_BNE},
+ {"break" ,INS_BREAK},
+ {"cfc0" ,INS_CFC },
+ {"cfc1" ,INS_CFC },
+ {"cfc2" ,INS_CFC },
+ {"cfc3" ,INS_CFC },
+ {"cop0" ,INS_COP },
+ {"cop1" ,INS_COP },
+ {"cop2" ,INS_COP },
+ {"cop3" ,INS_COP },
+ {"ctc0" ,INS_CTC },
+ {"ctc1" ,INS_CTC },
+ {"ctc2" ,INS_CTC },
+ {"ctc3" ,INS_CTC },
+ {"div" ,INS_DIV},
+ {"divu" ,INS_DIVU},
+ {"j" ,INS_J},
+ {"jal" ,INS_JAL},
+ {"jalr" ,INS_JALR},
+ {"jr" ,INS_JR},
+ {"lb" ,INS_LB},
+ {"lbu" ,INS_LBU},
+ {"lh" ,INS_LH},
+ {"lhu" ,INS_LHU},
+ {"lui" ,INS_LUI},
+ {"lw" ,INS_LW},
+ {"lwc0" ,INS_LWC },
+ {"lwc1" ,INS_LWC },
+ {"lwc2" ,INS_LWC },
+ {"lwc3" ,INS_LWC },
+ {"lwl" ,INS_LWL},
+ {"lwr" ,INS_LWR},
+ {"mfc0" ,INS_MFC},
+ {"mfc1" ,INS_MFC},
+ {"mfc2" ,INS_MFC},
+ {"mfc3" ,INS_MFC},
+ {"mfhi" ,INS_MFHI},
+ {"mflo" ,INS_MFLO},
+ {"mtc0" ,INS_MTC },
+ {"mtc1" ,INS_MTC },
+ {"mtc2" ,INS_MTC },
+ {"mtc3" ,INS_MTC },
+ {"mthi" ,INS_MTHI},
+ {"mtlo" ,INS_MTLO},
+ {"mult" ,INS_MULT},
+ {"multu" ,INS_MULTU},
+ {"nor" ,INS_NOR},
+ {"or" ,INS_OR},
+ {"ori" ,INS_ORI},
+ {"sb" ,INS_SB},
+ {"sh" ,INS_SH},
+ {"sll" ,INS_SLL},
+ {"sllv" ,INS_SLLV},
+ {"slt" ,INS_SLT},
+ {"slti" ,INS_SLTI},
+ {"sltiu" ,INS_SLTIU},
+ {"sltu" ,INS_SLTU},
+ {"sra" ,INS_SRA},
+ {"srav" ,INS_SRAV},
+ {"srl" ,INS_SRL},
+ {"srlv" ,INS_SRLV},
+ {"sub" ,INS_SUB},
+ {"subu" ,INS_SUBU},
+ {"sw" ,INS_SW},
+ {"swc0" ,INS_SWC},
+ {"swc1" ,INS_SWC},
+ {"swc2" ,INS_SWC},
+ {"swc3" ,INS_SWC},
+ {"swl" ,INS_SWL},
+ {"swr" ,INS_SWR},
+ {"syscall" ,INS_SYSCALL},
+ {"xor" ,INS_XOR},
+ {"xori" ,INS_XORI},
+
+ {"b" ,INS_B},
+ {"la" ,INS_LA},
+ {"li" ,INS_LI},
+ {"nop" ,INS_NOP},
+ {"move" ,INS_MOVE},
+ {"subi" ,INS_SUBI},
+ {"subiu" ,INS_SUBIU},
+ {"beqz" ,INS_BEQZ},
+ {"bnez" ,INS_BNEZ},
+ {"bal" ,INS_BAL},
+ {"org" ,INS_ORG},
+ {"include" ,INS_INCLUDE},
+ {"incbin" ,INS_INCBIN},
+ {"dcb" ,INS_DCB},
+ {"db" ,INS_DB},
+ {"dh" ,INS_DH},
+ {"dw" ,INS_DW},
+ {"align" ,INS_ALIGN},
+
+ {NULL},
+};
+
+#define I_TYPE(op, rs, rt, imm) \
+ ( (((op) & 63) << 26) | (((rs) & 31) << 21) | (((rt) & 31) << 16) | \
+ ((imm) & 0xFFFF) )
+
+#define J_TYPE(op, target) \
+ ( (((op) & 63) << 26) | ((target) & 0x3FFFFFF) )
+
+#define R_TYPE(op, rs, rt, rd, shamt, funct) \
+ ( (((op) & 63) << 26) | (((rs) & 31) << 21) | (((rt) & 31) << 16) | \
+ (((rd) & 31) << 11) | (((shamt) & 31) << 6) | \
+ ((funct) & 63))
+
+// copn = coprocessor number
+// SET_DIS_CHECK()
+
+#define SET_DIS_CHECK() /* Argument type check. Placeholder, contains nothing for now. */
+
+int set_delay_slot = 0;
+
+void OUTSEEK(unsigned int position)
+{
+ fseek(asmOut, position, SEEK_SET);
+}
+
+void OUTBYTE(unsigned char b)
+{
+ if(curPass>0)
+ fputc(b, asmOut);
+
+ curPc++;
+}
+
+void OUTHALF(unsigned short h)
+{
+ if(curPass>0)
+ {
+ fputc(h&0xff, asmOut);
+ fputc(h>>8, asmOut);
+ }
+
+ curPc += 2;
+}
+
+void OUTWORD(unsigned int w)
+{
+ if(curPass>0)
+ {
+ fputc(w&0xff, asmOut);
+ fputc((w>>8)&0xff, asmOut);
+ fputc((w>>16)&0xff, asmOut);
+ fputc(w>>24, asmOut);
+ }
+
+ curPc += 4;
+}
+
+void OUTINS(unsigned int instruction)
+{
+ OUTWORD(instruction);
+
+ if(set_delay_slot)
+ {
+ OUTWORD(0);
+
+ set_delay_slot = 0;
+ }
+}
+
+
+void OUTSTRING(char *string)
+{
+ int stringt;
+ int esc=0;
+
+ if(*string == '"')
+ stringt = 0;
+ else if(*string == '\'')
+ stringt = 1;
+ else
+ instruction_error("OUTSTRING <INTERNAL ERROR>. Not a string!");
+
+ string++;
+
+ while(*string)
+ {
+ if(*string == '"')
+ {
+ if(stringt == 0 && !esc)
+ break;
+
+ OUTBYTE('"');
+ esc = 0;
+ }
+ else if(*string == '\'')
+ {
+ if(stringt == 1 && !esc)
+ break;
+
+ OUTBYTE('\'');
+ esc = 0;
+ }
+ else if(*string == 'n')
+ {
+ if(esc)
+ OUTBYTE('\n');
+ else
+ OUTBYTE('n');
+
+ esc = 0;
+ }
+ else if(*string == 't')
+ {
+ if(esc)
+ OUTBYTE('\t');
+ else
+ OUTBYTE('t');
+
+ esc = 0;
+ }
+ else if(*string == 'r')
+ {
+ if(esc)
+ OUTBYTE('\r');
+ else
+ OUTBYTE('r');
+
+ esc = 0;
+ }
+ else if(*string == '\\')
+ {
+ if(esc)
+ {
+ OUTBYTE('\\');
+ esc = 0;
+ }
+ else
+ esc = 1;
+ }
+ else
+ {
+ if(esc)
+ instruction_error("Invalid escape sequence \\%c in string", *string);
+
+ OUTBYTE(*string);
+ }
+
+ string++;
+ }
+}
+
+unsigned int OUTSIZE(void)
+{
+ int r;
+ int pos = ftell(asmOut);
+ fseek(asmOut, 0, SEEK_END);
+ r = ftell(asmOut);
+ fseek(asmOut, pos, SEEK_SET);
+ return r;
+}
+
+unsigned short compute_branch(unsigned int imm)
+{
+ unsigned int off = imm - (curPc + 4);
+ //off >>= 2;
+
+ if(curPass <= 0)
+ return 0;
+
+ if(off >= 0x20000 && off < -0x20000)
+ instruction_error("Branch out of range. %04x", off);
+
+ return (off>>2) & 0xFFFF;
+}
+
+unsigned int compute_jump(unsigned int imm)
+{
+ if(curPass <= 0)
+ return 0;
+
+ return (imm >> 2);
+}
+
+struct
+{
+ int size;
+ int pos;
+ unsigned int *el;
+}cannotPredict = {0, 0, NULL};
+
+unsigned int compute_real_offset(unsigned int imm, unsigned int base,
+ unsigned int rt)
+{
+ int i, unpredictable=0;
+ unsigned short hipart;
+ unsigned short lopart;
+
+ if(!find_label_ok())
+ {
+ if(cannotPredict.size == cannotPredict.pos)
+ {
+ cannotPredict.size += 128;
+ cannotPredict.el = realloc(cannotPredict.el, cannotPredict.size * sizeof(int));
+ }
+
+ cannotPredict.el[cannotPredict.pos++] = curPc;
+ }
+
+ for(i = 0; i < cannotPredict.pos; i++)
+ {
+ if(curPc == cannotPredict.el[i])
+ {
+ unpredictable = 1;
+ break;
+ }
+ }
+
+ if(!unpredictable && ((imm <= 0xFFFF) || (imm >= 0xFFFF8000 && imm <= 0xFFFFFFFF)))
+ return I_TYPE(0, base, rt, imm);
+
+//compute_real_offset_output_wide:
+ // li at, offset
+ // add at, at, base
+ // lw rt, 0(at)
+ hipart = (imm >> 16);
+ lopart = imm & 0xFFFF;
+ int t=(*curIns == 'l') ? rt : 1;
+
+ // lw at, $CAFEBABE(zero) -> lui at, $CAFE, ori at, at, $BABE, lw at, 0(at)
+ // lw at, $CAFEBABE(v0) -> lui at, $CAFE, ori at, at, $BABE, lw at, 0(v0)
+ // sw at, $CAFEBABE ->
+
+ if(base)
+ {
+ /*OUTINS( I_TYPE(15, 0, t, hipart)); // lui $t, (offset > 16)
+
+ if(lopart || unpredictable)
+ OUTINS( I_TYPE (13, t, t, lopart)); // ori $t, $t, offset & 0xffff
+
+ OUTINS( R_TYPE (0, t, base, t, 0, 33) ); // add $t, $t, base
+ return I_TYPE(0, t, rt, 0);*/
+
+// SPASM is seriously broken regarding this..
+ return I_TYPE(0, base, rt, imm);
+ }
+
+ if(lopart >= 0x8000)
+ hipart++;
+
+ OUTINS( I_TYPE(15, 0, t, hipart)); // lui $t, (offset > 16)
+
+ return I_TYPE(0, t, rt, lopart); // XX rt, lopart(rt)
+}
+
+void INS_ADD(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADD rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ADDI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ADDI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 32) );
+}
+
+void INS_ADDI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADDI rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range.");
+
+ OUTINS( I_TYPE (8, rs, rt, imm) );
+}
+
+void INS_ADDIU(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADDIU rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range.");
+
+ OUTINS( I_TYPE (9, rs, rt, imm) );
+}
+
+void INS_ADDU(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADDU rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ADDIU();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ADDIU();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 33) );
+}
+
+void INS_AND(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // AND rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ANDI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ANDI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 36) );
+}
+
+void INS_ANDI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ANDI rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0xFFFF)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (12, rs, rt, imm) );
+}
+
+void INS_BEQ(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+ imm = insArgv[2];
+
+ OUTINS( I_TYPE(4, rs, rt, compute_branch(imm)) );
+}
+
+void INS_BGEZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 1, compute_branch(imm)) );
+}
+
+void INS_BGEZAL(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 17, compute_branch(imm)) );
+}
+
+void INS_BGTZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(7, rs, 0, compute_branch(imm)) );
+}
+
+void INS_BLEZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(6, rs, 0, compute_branch(imm)) );
+}
+
+void INS_BLTZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 0, compute_branch(imm)) );
+}
+
+void INS_BLTZAL(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 16, compute_branch(imm)) );
+}
+
+void INS_BNE(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+ imm = insArgv[2];
+
+ OUTINS( I_TYPE(5, rs, rt, compute_branch(imm)) );
+}
+
+void INS_BREAK(void)
+{
+ unsigned int imm = 0;
+
+ if(insArgc > 1)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 1)
+ imm = insArgv[0];
+
+ imm &= 0xFFFFF;
+
+ OUTINS( (imm << 6) | 13 );
+}
+
+void INS_CFC(void)
+{
+ unsigned int rt, rd;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rd = insArgv[1];
+
+ OUTINS ( R_TYPE(16 | copn, 2, rt, rd, 0, 0) );
+}
+
+void INS_COP(void)
+{
+ unsigned int cofun;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ cofun = insArgv[0];
+
+ OUTINS( ( (16 | copn) << 26) | (1<<25) | (cofun & 0x1FFFFFF));
+}
+
+void INS_CTC(void)
+{
+ unsigned int rt, rd;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rd = insArgv[1];
+
+ OUTINS ( R_TYPE(16 | copn, 6, rt, rd, 0, 0) );
+}
+
+void INS_DIV(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS ( R_TYPE(0, rs, rt, 0, 0, 26));
+}
+
+void INS_DIVU(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS ( R_TYPE(0, rs, rt, 0, 0, 27));
+}
+
+void INS_J(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS ( J_TYPE(2, compute_jump(insArgv[0])));
+}
+
+void INS_JAL(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS ( J_TYPE(3, compute_jump(insArgv[0])));
+}
+
+void INS_JALR(void)
+{
+ unsigned int rd, rs;
+
+ if(insArgc < 1)
+ instruction_error("Not enough arguments");
+ if(insArgc > 2)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 1)
+ {
+ rd = 31; // register ra
+ rs = insArgv[0];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rs = insArgv[1];
+ }
+
+ OUTINS ( R_TYPE(0, rs, 0, rd, 0, 9));
+}
+
+void INS_JR(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS ( R_TYPE(0, insArgv[0], 0, 0, 0, 8));
+}
+
+void INS_LB(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(32, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LBU(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(36, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LH(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(33, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LHU(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(37, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LUI(void)
+{
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(I_TYPE(15, 0, insArgv[0], insArgv[1]));
+}
+
+void INS_LW(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(35, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LWC(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(48 | copn, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LWL(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(34, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LWR(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(38, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_MFC(void)
+{
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE (16 | copn, 0, insArgv[0], insArgv[1], 0, 0));
+}
+
+void INS_MFHI(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, 0, 0, insArgv[0], 0, 16));
+}
+
+void INS_MFLO(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, 0, 0, insArgv[0], 0, 18));
+}
+
+void INS_MTC(void)
+{
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE (16 | copn, 4, insArgv[0], insArgv[1], 0, 0));
+}
+
+void INS_MTHI(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, insArgv[0], 0, 0, 0, 17));
+}
+
+void INS_MTLO(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, insArgv[0], 0, 0, 0, 19));
+}
+
+void INS_MULT(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS(R_TYPE(0, rs, rt, 0, 0, 24));
+}
+
+void INS_MULTU(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS(R_TYPE(0, rs, rt, 0, 0, 25));
+}
+
+void INS_NOR(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 39) );
+}
+
+void INS_OR(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ORI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ORI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 37) );
+}
+
+void INS_ORI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ANDI rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0xFFFF)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (13, rs, rt, imm) );
+}
+
+void INS_SB(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(40, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SH(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(41, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SLL(void)
+{
+ unsigned int rd, rt, sa;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ sa = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ sa = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(0, 0, rt, rd, sa, 0));
+}
+
+void INS_SLLV(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ rs = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ rs = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 4) );
+}
+
+void INS_SLT(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ if(atoiT[2] == T_INTEGER)
+ return INS_SLTI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 42) );
+}
+
+void INS_SLTI(void)
+{
+ unsigned int imm, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+
+ if(imm > 0x7FFF && imm < 0xFFFF8000)
+ instruction_error("Immediate out of range.");
+
+ OUTINS( I_TYPE (10, rs, rt, imm) );
+}
+
+void INS_SLTIU(void)
+{
+ unsigned int imm, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+
+ if(imm > 0x7FFF && imm < 0xFFFF8000)
+ instruction_error("Immediate out of range.");
+
+ OUTINS( I_TYPE (11, rs, rt, imm) );
+}
+
+void INS_SLTU(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ if(atoiT[2] == T_INTEGER)
+ return INS_SLTIU();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 43) );
+}
+
+void INS_SRA(void)
+{
+ unsigned int rd, rt, sa;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ sa = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ sa = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(0, 0, rt, rd, sa, 3));
+}
+
+void INS_SRAV(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ rs = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ rs = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 7) );
+}
+
+void INS_SRL(void)
+{
+ unsigned int rd, rt, sa;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ sa = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ sa = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(0, 0, rt, rd, sa, 2));
+}
+
+void INS_SRLV(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ rs = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ rs = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 6) );
+}
+
+void INS_SUB(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_SUBI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_SUBI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 34) );
+}
+
+void INS_SUBU(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADD rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_SUBIU();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_SUBIU();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 35) );
+}
+
+void INS_SW(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(43, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SWC(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(56 | copn, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SWL(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(42, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SWR(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(46, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SYSCALL(void)
+{
+ unsigned int imm = 0;
+
+ if(insArgc > 1)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 1)
+ imm = insArgv[0];
+
+ imm &= 0xFFFFF;
+
+ OUTINS( (imm << 6) | 12 );
+}
+
+void INS_XOR(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_XORI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_XORI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 38) );
+}
+
+void INS_XORI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0xFFFF)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (14, rs, rt, imm) );
+}
+
+// ***** PSEUDO INSTRUCTIONS *****
+
+void INS_B(void)
+{
+ unsigned int imm;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ imm = insArgv[0];
+
+ OUTINS( I_TYPE(4, 0, 0, compute_branch(imm)) ); // <- beq zero, zero, imm
+}
+
+/*void INS_LI(void)
+{
+ unsigned int rd, imm;
+ unsigned short lopart, hipart;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ imm = insArgv[1];
+
+ hipart = imm >> 16;
+ lopart = imm & 0xFFFF;
+
+ if(atoiT[1] == T_INTEGER && imm >= 0 && imm <= 0xFFFF)
+ OUTINS(I_TYPE(13, 0, rd, lopart)); // ori $rd, $zero, imm
+ else
+ {
+ if(lopart >= 0x8000)
+ hipart++;
+
+ OUTINS( I_TYPE(15, 0, rd, hipart)); // lui $rd, (imm > 16)
+ OUTINS( I_TYPE (9, rd, rd, lopart)); // addiu $rd, $rd, imm & 0xffff
+ }
+}*/
+
+void INS_LI(void)
+{
+ int i;
+ unsigned int rd, imm;
+ unsigned short lopart, hipart;
+ int unpredictable=0;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ imm = insArgv[1];
+
+ hipart = imm >> 16;
+ lopart = imm & 0xFFFF;
+
+ if(!find_label_ok())
+ {
+ if(cannotPredict.size == cannotPredict.pos)
+ {
+ cannotPredict.size += 128;
+ cannotPredict.el = realloc(cannotPredict.el, cannotPredict.size * sizeof(int));
+ }
+
+ cannotPredict.el[cannotPredict.pos++] = curPc;
+ }
+
+ for(i = 0; i < cannotPredict.pos; i++)
+ {
+ if(curPc == cannotPredict.el[i])
+ {
+ unpredictable = 1;
+ break;
+ }
+ }
+
+ if(/*atoiT[1] == T_INTEGER &&*/ !unpredictable && imm >= 0 && imm <= 0xFFFF)
+ OUTINS(I_TYPE(13, 0, rd, lopart)); // ori $rd, $zero, imm
+ else if(!unpredictable && !lopart)
+ OUTINS(I_TYPE(15, 0, rd, hipart));
+ else
+ {
+ // if(lopart >= 0x8000)
+ // hipart++;
+
+ OUTINS( I_TYPE(15, 0, rd, hipart)); // lui $rd, (imm > 16)
+
+ // OUTINS( I_TYPE(9, rd, rd, lopart)); // addiu $rd, $rd, imm & 0xffff
+ OUTINS( I_TYPE (13, rd, rd, lopart)); // ori $rd, $rd, imm & 0xffff
+ }
+
+}
+
+void INS_LA(void)
+{
+ int i;
+ unsigned int rd, imm;
+ unsigned short lopart, hipart;
+ int unpredictable=0;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ imm = insArgv[1];
+
+ hipart = imm >> 16;
+ lopart = imm & 0xFFFF;
+
+ if(!find_label_ok())
+ {
+ if(cannotPredict.size == cannotPredict.pos)
+ {
+ cannotPredict.size += 128;
+ cannotPredict.el = realloc(cannotPredict.el, cannotPredict.size * sizeof(int));
+ }
+
+ cannotPredict.el[cannotPredict.pos++] = curPc;
+ }
+
+ for(i = 0; i < cannotPredict.pos; i++)
+ {
+ if(curPc == cannotPredict.el[i])
+ {
+ unpredictable = 1;
+ break;
+ }
+ }
+
+ if(/*atoiT[1] == T_INTEGER &&*/ !unpredictable && imm >= 0 && imm <= 0xFFFF)
+ OUTINS(I_TYPE(13, 0, rd, lopart)); // ori $rd, $zero, imm
+ //else if(!unpredictable && !lopart)
+ // OUTINS(I_TYPE(15, 0, rd, hipart));
+ else
+ {
+ if(lopart >= 0x8000)
+ hipart++;
+
+ OUTINS( I_TYPE(15, 0, rd, hipart)); // lui $rd, (imm > 16)
+
+ OUTINS( I_TYPE(9, rd, rd, lopart)); // addiu $rd, $rd, imm & 0xffff
+// OUTINS( I_TYPE (13, rd, rd, lopart)); // ori $rd, $rd, imm & 0xffff
+ }
+
+}
+
+/*void INS_LA(void)
+{
+ INS_LI(); // The LI and LA pseudo-instructions are the same thing in SPASM
+}*/
+
+void INS_NOP(void)
+{
+ OUTINS(0);
+}
+
+void INS_MOVE(void)
+{
+ unsigned int rd, rs;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+
+ OUTINS( R_TYPE (0, rs, 0, rd, 0, 33) ); // addu $rd, $rs, $zero
+}
+
+void INS_SUBI(void)
+{
+// just like ADDI, but switches the sign of the immediate
+
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = -insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = -insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (8, rs, rt, imm) );
+}
+
+void INS_SUBIU(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = -insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = -insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (9, rs, rt, imm) );
+}
+
+void INS_BEQZ(void)
+{
+ unsigned int rt, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(4, rt, 0, compute_branch(imm)) ); // <- beq zero, rt, imm
+// OUTINS( I_TYPE(4, rs, rt, compute_branch(imm)) );
+
+}
+
+void INS_BNEZ(void)
+{
+ unsigned int rt, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(5,rt, 0, compute_branch(imm)) ); // <- bne zero, rt, imm
+}
+
+void INS_BAL(void)
+{
+ unsigned int imm;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ imm = insArgv[0];
+
+ OUTINS( I_TYPE(1, 0, 17, compute_branch(imm)) ); //bgezal $zero, imm
+}
+
+void INS_ORG(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ //if(!first_instruction)
+ // instruction_error("ORG is not the first instruction");
+
+ curPc = insArgv[0];
+ startAddress = insArgv[0];
+ org_found = 1;
+}
+
+void INS_INCBIN(void)
+{
+ FILE *f;
+ char *path, *cp;
+ int sz;
+
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ path = rawArgv[0];
+
+ if(*path == '"')
+ {
+ path++;
+ if((cp = strrchr(path, '"')))
+ *cp = '\0';
+ }
+ else if(*path == '\'')
+ {
+ path++;
+ if((cp = strrchr(path, '\'')))
+ *cp = '\0';
+ }
+
+ //printf("DEBUG(INCBIN): including %s\n", path);
+
+ f = spasm_fopen(path, "rb");
+
+ if(!f)
+ instruction_error("Could not open \"%s\"", path);
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ if(curPass <= 0)
+ curPc += sz;
+ else
+ {
+ for(;sz;sz--)
+ OUTBYTE(fgetc(f));
+ }
+
+ fclose(f);
+}
+
+void INS_DCB(void)
+{
+ unsigned int num, value;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ num = insArgv[0];
+ value = insArgv[1];
+
+ if(num & (1<<31))
+ {
+ instruction_warning("Negative number of values, ignoring instruction");
+
+ return;
+ }
+
+ if(curPass <= 0)
+ curPc += num;
+ else
+ {
+ for(;num;num--)
+ OUTBYTE(value);
+ }
+}
+
+void INS_DB(void)
+{
+ int i;
+
+ for(i = 0; i < insArgc; i++)
+ {
+ if(rawArgv[i][0] == '"' || rawArgv[i][0] == '\'')
+ OUTSTRING(rawArgv[i]);
+ else
+ OUTBYTE(insArgv[i] & 0xFF);
+ }
+}
+
+void INS_DH(void)
+{
+ int i;
+
+ for(i = 0; i < insArgc; i++)
+ {
+ if(rawArgv[i][0] == '"' || rawArgv[i][0] == '\'')
+ OUTSTRING(rawArgv[i]);
+ else
+ OUTHALF(insArgv[i] & 0xFFFF);
+ }
+}
+
+void INS_DW(void)
+{
+ int i;
+
+ for(i = 0; i < insArgc; i++)
+ {
+ if(rawArgv[i][0] == '"' || rawArgv[i][0] == '\'')
+ OUTSTRING(rawArgv[i]);
+ else
+ OUTWORD(insArgv[i]);
+ }
+}
+
+void INS_ALIGN(void)
+{
+ unsigned int unit;
+ unsigned int delta;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ unit = insArgv[0];
+
+ if(unit <= 0)
+ instruction_error("Alignment unit cannot be equal to zero or negative");
+
+ if((curPc % unit))
+ {
+ delta = (unit - (curPc % unit)) % unit;
+
+ if(curPass <= 0)
+ curPc += delta;
+ else
+ {
+ for(;delta;delta--)
+ OUTBYTE(0);
+ }
+ }
+}
+
+void INS_INCLUDE(void)
+{
+ int i, l, o;
+ int sz;
+ int tsz;
+ FILE *f;
+ char *path;
+ char *cp;
+ char *newtext;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ if(curPass <= 0)
+ {
+
+ path = rawArgv[0];
+
+ if(*path == '"')
+ {
+ path++;
+ if((cp = strrchr(path, '"')))
+ *cp = '\0';
+ }
+ else if(*path == '\'')
+ {
+ path++;
+ if((cp = strrchr(path, '\'')))
+ *cp = '\0';
+ }
+
+ f = spasm_fopen(path, "rb");
+
+ if(!f)
+ instruction_error("Could not open %s", path);
+
+ //printf("DEBUG(INCLUDE): Including %s, line %d\n", path, line_number);
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ tsz = strlen(curText);
+
+ newtext = malloc(sz + tsz + 1);
+
+ for(i = 0, l = 1; l < line_number; i++)
+ {
+ if(curText[i] == '\n')
+ l++;
+
+ newtext[i] = curText[i];
+ }
+
+ fread(&newtext[i], sizeof(char), sz, f);
+
+ o = i+sz;
+
+ if(newtext[i+sz-1] != '\n')
+ {
+ instruction_warning("No newline found at end of file %s", path);
+ newtext[o++] = '\n';
+ }
+
+
+ for(; curText[i] != '\n'; i++);
+
+ i++;
+ newtext[o] = '\0';
+
+ strcat(newtext, &curText[i]);
+
+ free(curText);
+ curText = newtext;
+ }
+}
+
+void INS_BLANK(void)
+{
+
+}
+
+void *get_instruction(char *name)
+{
+ int i;
+
+
+ for(i = 0; instruction_table[i].name; i++)
+ {
+ //printf("name = ^%s$, iname = ^%s$\n", name, instruction_table[i].name);
+
+ if(strcasecmp(name, instruction_table[i].name) == 0)
+ {
+ // printf("di sranron\n");
+ return instruction_table[i].func;
+ }
+ }
+
+ return NULL;
+}
diff --git a/tools/spasm/opcode.h b/tools/spasm/opcode.h
new file mode 100644
index 0000000..c2f6857
--- /dev/null
+++ b/tools/spasm/opcode.h
@@ -0,0 +1,108 @@
+#ifndef _SPASM_OPCODE_H
+#define _SPASM_OPCODE_H
+
+// Helper functions
+
+void OUTSEEK(unsigned int position);
+void OUTBYTE(unsigned char b);
+void OUTHALF(unsigned short h);
+void OUTWORD(unsigned int w);
+void OUTINS(unsigned int instruction);
+void OUTSTRING(char *string);
+unsigned int OUTSIZE(void);
+void *get_instruction(char *name);
+
+// Instructions
+
+void INS_ADD(void);
+void INS_ADDI(void);
+void INS_ADDIU(void);
+void INS_ADDU(void);
+void INS_AND(void);
+void INS_ANDI(void);
+void INS_BEQ(void);
+void INS_BGEZ(void);
+void INS_BGEZAL(void);
+void INS_BGTZ(void);
+void INS_BLEZ(void);
+void INS_BLTZ(void);
+void INS_BLTZAL(void);
+void INS_BNE(void);
+void INS_BREAK(void);
+void INS_CFC(void);
+void INS_COP(void);
+void INS_CTC(void);
+void INS_DIV(void);
+void INS_DIVU(void);
+void INS_J(void);
+void INS_JAL(void);
+void INS_JALR(void);
+void INS_JR(void);
+void INS_LB(void);
+void INS_LBU(void);
+void INS_LH(void);
+void INS_LHU(void);
+void INS_LUI(void);
+void INS_LW(void);
+void INS_LWC(void);
+void INS_LWL(void);
+void INS_LWR(void);
+void INS_MFC(void);
+void INS_MFHI(void);
+void INS_MFLO(void);
+void INS_MTC(void);
+void INS_MTHI(void);
+void INS_MTLO(void);
+void INS_MULT(void);
+void INS_MULTU(void);
+void INS_NOR(void);
+void INS_OR(void);
+void INS_ORI(void);
+void INS_SB(void);
+void INS_SH(void);
+void INS_SLL(void);
+void INS_SLLV(void);
+void INS_SLT(void);
+void INS_SLTI(void);
+void INS_SLTIU(void);
+void INS_SLTU(void);
+void INS_SRA(void);
+void INS_SRAV(void);
+void INS_SRL(void);
+void INS_SRLV(void);
+void INS_SUB(void);
+void INS_SUBU(void);
+void INS_SW(void);
+void INS_SWC(void);
+void INS_SWL(void);
+void INS_SWR(void);
+void INS_SYSCALL(void);
+void INS_XOR(void);
+void INS_XORI(void);
+
+// Pseudo instructions
+
+void INS_B(void);
+void INS_LI(void);
+void INS_LA(void);
+void INS_NOP(void);
+void INS_MOVE(void);
+void INS_SUBI(void);
+void INS_SUBIU(void);
+void INS_BEQZ(void);
+void INS_BNEZ(void);
+void INS_BAL(void);
+void INS_ORG(void);
+void INS_INCBIN(void);
+void INS_INCLUDE(void);
+void INS_DCB(void);
+void INS_DB(void);
+void INS_DH(void);
+void INS_DW(void);
+void INS_ALIGN(void);
+
+// Fake instructions
+
+void INS_BLANK(void);
+
+#endif
diff --git a/tools/spasm/parser.c b/tools/spasm/parser.c
new file mode 100644
index 0000000..46fdccb
--- /dev/null
+++ b/tools/spasm/parser.c
@@ -0,0 +1,478 @@
+#include "spasm.h"
+
+int atoiT[64];
+
+static char *reg_names[] =
+{
+ "zero",
+ "at",
+ "v0", "v1",
+ "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9",
+ "k0", "k1",
+ "gp", "sp",
+ "fp",
+ "ra",
+ NULL
+};
+
+static int regtoi(char *arg)
+{
+ int i;
+
+ if(strcmp(arg, "s8") == 0)
+ arg = "fp";
+
+ for(i = 0; reg_names[i]; i++)
+ {
+ if(strcmp(arg, reg_names[i]) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+unsigned int asm_atoi(char *arg)
+{
+ unsigned int i;
+
+
+ if((i = regtoi(arg)) != -1)
+ {
+ atoiT[insArgc] = T_REGISTER;
+ return i;
+ }
+ else if(tolower((int)*arg) == 'r' &&( (strlen(arg) == 2 && isdigit((int)*(arg+1))) ||
+ (strlen(arg) == 3 && isdigit((int)*(arg+1)) && isdigit((int)*(arg+2)))))
+ {
+ sscanf(arg+1, "%d", &i);
+ atoiT[insArgc] = T_REGISTER;
+ return i;
+ }
+ else if(*arg == '-' && *(arg+1) == '$' && isxdigit((unsigned int)*(arg+2)) )
+ {
+ sscanf(arg+2, "%x", &i);
+ atoiT[insArgc] = T_INTEGER;
+ return -i;
+ }
+ else if(*arg == '$' )
+ {
+ sscanf(arg+1, "%x", &i);
+ atoiT[insArgc] = T_INTEGER;
+
+ return i;
+ }
+ else if(strcmp(arg, "*") == 0)
+ {
+ atoiT[insArgc] = T_INTEGER;
+
+ return curPc;
+ }
+ else if(isalpha((unsigned int)*arg) || (*arg) == '_')
+ {
+ atoiT[insArgc] = T_LABEL;
+
+ i = find_label(arg);
+
+ return i;
+ }
+
+ sscanf(arg, "%i", &i);
+ atoiT[insArgc] = T_INTEGER;
+
+ return i;
+}
+
+enum
+{
+ INITIAL, ARG_ENTER, COMMENT
+};
+
+char *spasm_parser(char *text, int pass)
+{
+ int i, j, l, m;
+ char linebuf[1024];
+ char linebuf2[1024];
+ char linebuf3[1024];
+ char argbuf[1024];
+ char *tok[256];
+ int state = INITIAL;
+ int num_of_tok=0;
+ char *t;
+ curText = text;
+ unsigned int v;
+
+theBeginning:
+ i = 0;
+ curPass = pass;
+ org_found = 0;
+ first_instruction = 1;
+ line_number = 0;
+ text = curText;
+
+ while(text[i])
+ {
+ state = INITIAL;
+
+ for(j = 0; text[i] && text[i] != '\n'; i++)
+ {
+ if(j < 1023 && text[i] != '\r')
+ linebuf[j++] = text[i];
+ }
+
+ line_number++;
+ rawArgc = insArgc = 0;
+ INSFUNC = NULL;
+
+ if(text[i] == '\n')
+ i++;
+
+ linebuf[j] = '\0';
+
+//tokenize_line:
+ strcpy(linebuf2, linebuf); // Keep a second copy, we will need it later.
+ strcpy(linebuf3, linebuf);
+ curLine = linebuf3;
+
+ char *a = linebuf;
+ char *s;
+ j = 0;
+
+ num_of_tok = 0;
+
+ for(m = 0; m < 256; m++)
+ tok[m]=NULL;
+
+ while((s = strtok(a, " \t")))
+ {
+ tok[num_of_tok++] = s;
+ a = NULL;
+ }
+
+ tok[num_of_tok] = NULL;
+
+ j = 0;
+
+
+
+ while((s = tok[j]))
+ {
+ //printf("tok[%d] = %s\n", j, tok[j]);
+
+ find_label_reset();
+
+ if(strlen(s) == 0)
+ { // A token with zero length is garbage, skip it
+ j++;
+ continue;
+ }
+
+ //printf("s = ^%s\n", s);
+
+ switch(state)
+ {
+ case INITIAL: // Initial case
+
+ // Is this token a comment?
+
+ if(*s == ';')
+ {
+ state = COMMENT;
+ break;
+ }
+
+ // Is this token an instruction?
+
+ if((INSFUNC = get_instruction(s)))
+ {
+ strncpy(curIns, s, 127);
+ s[127] = '\0';
+ insArgc = 0;
+ state = ARG_ENTER;
+ argbuf[0] = '\0';
+
+ break;
+ }
+
+ // Now we know it's a label
+ // There are two possible cases now
+ // - It's a label with a specified value: i.e. label EQU value
+ // - It's a label which has the current value of the program counter
+
+ // First, we will check for EQU
+
+ if((j + 2) < num_of_tok)
+ { // If there are not enough tokens in the line, don't bother checking for EQU.
+ if(strcasecmp(tok[j+1], "equ") == 0 || strcasecmp(tok[j+1], "=") == 0)
+ { // EQU found! Set label value to the one specified.
+
+ // Set current instruction to EQU
+ strcpy(curIns, "equ");
+
+ // Remove quotes. Yes, in SPASM, values in EQU statements can have quotes
+ // even if they are numerical values!
+
+ if( (t = strchr(tok[j+2], '"')) )
+ {
+ *t = '\0';
+ if( (t = strrchr(tok[j+2], '"')) )
+ *t = '\0';
+ }
+
+ find_label_reset();
+
+ v = spasm_eval(tok[j+2]);
+
+ if(strchr(tok[j+2], ';'))
+ state = COMMENT;
+
+ if(!find_label_ok())
+ assembler_error("Can't resolve expression for EQU statement");
+
+ if(find_label_ok())
+ add_label_equ(tok[j], v);
+ else
+ add_label(tok[j], v);
+
+ j+=2;// As we have processed the EQU, we need to jump two tokens ahead
+ break;
+ }
+ }
+
+ // At this point, it is a label which has the current value of the program counter
+
+ if((t = strrchr(tok[j], ':')))
+ *t='\0'; // Remove trailing colon, if any.
+
+ add_label(tok[j], curPc);
+ break;
+
+ case ARG_ENTER: // Inside instruction
+ if(curPass == -1)
+ break;
+
+ // Is this token a comment?
+ // If so, we do not have arguments anymore.
+
+
+ if(*s == ';')
+ {
+ state = COMMENT;
+ break;
+ }
+
+ strcat(argbuf, s);
+
+ int was_sp = 0;
+ int in_string = 0;
+ int stringt = 0;
+ char *argPlace = &linebuf2[ tok[j] - tok[0] ];
+
+ a = linebuf2;
+
+ l = 0;
+ while(l < j && (argPlace = strtok(a, " \t")))
+ {
+ a = NULL;
+ l++;
+ }
+
+ while(*argPlace)argPlace++;
+ while(!(*argPlace))argPlace++;
+
+ char arg[64];
+ char *argp = arg;
+ int is_ok = 0;
+ int esc = 0;
+
+ rawArgc = 0;
+
+ // Emulate a bug in Hitmen's assembler
+ if(strcasecmp(curIns, "li") == 0)
+ {
+argplace_li_remove_spaces_begin:
+ for(l = 0; argPlace[l]; l++)
+ {
+ if(argPlace[l] == ' ')
+ {
+ l++;
+ for(; argPlace[l]; l++)
+ argPlace[l-1] = argPlace[l];
+
+ argPlace[l-1] = '\0';
+
+ goto argplace_li_remove_spaces_begin;
+ }
+ }
+ }
+
+ for(l = 0; argPlace[l] && rawArgc < 64; l++)
+ {
+ char c = argPlace[l];
+
+ if(in_string)
+ {
+ *(argp++) = c;
+
+ if(!esc)
+ {
+ if(stringt == 0 && c == '"')
+ in_string = 0;
+ else if(stringt == 1 && c == '\'')
+ in_string = 0;
+ else if(c == '\\')
+ esc = 1;
+ }
+ else
+ esc = 0;
+ }
+ else
+ {
+ if(isalnum((unsigned int)c) || c == '_' || c == '$' || c == '.' || c == '*')
+ {
+ is_ok = 0;
+
+ if(was_sp && (isalnum((unsigned int)*(argp-1)) || (*(argp-1) == '_') ||
+ (*(argp-1) == '$') || (*(argp-1) == '"')
+ || (*(argp-1) == '\'') || (*(argp-1) == '.') || (*(argp-1) == '*')))
+ goto noMoreArgs;
+
+ *(argp++) = c;
+ was_sp = 0;
+ }
+ else if(c == '"')
+ {
+ if(was_sp && (isalnum((unsigned int)*(argp-1)) || (*(argp-1) == '_') ||
+ (*(argp-1) == '$') || (*(argp-1) == '"')
+ || (*(argp-1) == '\'') || (*(argp-1) == '.') || (*(argp-1) == '*')))
+ goto noMoreArgs;
+
+ *(argp++) = c;
+ was_sp = 0;
+ in_string = 1;
+ stringt = 0;
+ esc = 0;
+ }
+ else if(c == '\'')
+ {
+ if(was_sp && (isalnum((unsigned int)*(argp-1)) || (*(argp-1) == '_') ||
+ (*(argp-1) == '$') || (*(argp-1) == '"')
+ || (*(argp-1) == '\'') || (*(argp-1) == '.') || (*(argp-1) == '*')))
+ goto noMoreArgs;
+
+ *(argp++) = c;
+ was_sp = 0;
+ in_string = 1;
+ stringt = 1;
+ esc = 0;
+ }
+ else if(c == ' ' || c == '\t')
+ {
+ is_ok = 0;
+ was_sp = 1;
+ }
+ else if(c == '+' || c == '-' || c == '>' || c == '<'
+ || c == '(' || c == ')' || c == '&' || c == '|' || c == '!')
+ {
+ is_ok = 0;
+ *(argp++) = c;
+ }
+ else if(c == ',')
+ {
+ *argp = '\0';
+ insArgt[rawArgc] = 0;
+ strcpy(rawArgv[rawArgc++], arg);
+ argp = arg;
+ was_sp = 0;
+ is_ok = 1;
+ }
+ else if(c == ';' || c == '/')
+ {
+// '/' added in order to emulate a very buggy behavior of SPASM that is needed
+// in order to assemble the imbNES 1.3.2 sources without modifications.
+// yes, imbNES has some UNDENOTATED comments!
+//
+// pearls such as
+//
+// lw v0,$1074(v1) // this line would be at $DFAC where the jump goes from the patch
+//
+// and...
+//
+// lw v0,$DFFC(v0) load the address to jump back to that was set in _patch_card
+//
+// It makes no sense, but hey it works in the original SPASM!
+
+
+ goto noMoreArgs;
+ }
+ else
+ {
+ instruction_error("Invalid character!\n");
+ break;
+ }
+ }
+ }
+
+noMoreArgs:
+ if(!is_ok)
+ {
+ *argp = '\0';
+
+ char *fb = strchr(arg, '(');
+ char *sb = strrchr(arg, ')');
+
+
+ int pa=(*arg != '"' && *arg != '\'' && fb && sb && fb<sb);
+
+ if(pa)
+ {
+ *fb = '\0';
+ *sb = '\0';
+ insArgt[rawArgc+1] = 1;
+ strcpy(rawArgv[rawArgc+1], fb+1);
+ }
+
+ insArgt[rawArgc] = 0;
+ strcpy(rawArgv[rawArgc++], arg);
+
+ if(pa)rawArgc++;
+ }
+
+ insArgc = 0;
+
+ find_label_reset();
+
+ for(l = 0; l < rawArgc; l++, insArgc++)
+ insArgv[l] = spasm_eval(rawArgv[l]);
+
+ if(curPass == 1 && !find_label_ok())
+ instruction_error("Can't resolve expression");
+
+ goto theNextLine;
+ break;
+
+ case COMMENT: // Inside comment
+
+ break;
+ }
+
+ a = NULL;
+ j++;
+ }
+
+theNextLine:
+ if(INSFUNC)
+ {
+ if(curPass>=0)INSFUNC();
+
+ if(strcasecmp(curIns, "include") == 0 && curPass == 0)
+ goto theBeginning;
+
+ first_instruction = 0;
+ }
+ }
+
+ return curText;
+}
diff --git a/tools/spasm/parser.h b/tools/spasm/parser.h
new file mode 100644
index 0000000..72ecb0d
--- /dev/null
+++ b/tools/spasm/parser.h
@@ -0,0 +1,29 @@
+#ifndef _SPASM_PARSER_H
+#define _SPASM_PARSER_H
+
+enum
+{
+ T_INTEGER = 1, T_REGISTER = 2, T_LABEL = 3
+};
+
+extern char *fileBuffer;
+extern unsigned int fileBufferSize;
+
+extern char *curText;
+extern char *curLine;
+
+unsigned int asm_atoi(char *arg);
+char *spasm_parser(char *text, int pass);
+
+extern char curIns[128];
+extern unsigned int curInsArg;
+extern unsigned int curInsArgT;
+extern unsigned int insArgv[64];
+extern unsigned int insArgt[64];
+extern unsigned int insArgc;
+extern int rawArgc;
+extern char rawArgv[64][128];
+extern FILE *asmOut;
+extern int line_number;
+extern int atoiT[64];
+#endif
diff --git a/tools/spasm/readme.txt b/tools/spasm/readme.txt
new file mode 100644
index 0000000..8baa290
--- /dev/null
+++ b/tools/spasm/readme.txt
@@ -0,0 +1,120 @@
+nv-SPASM 0.34.1
+(c) 2014-2015 Giuseppe Gatta, a.k.a. nextvolume <tails92@gmail.com>
+-------------------------
+
+1. What is this?
+2. Features
+3. How to use
+4. License
+
+1. What is this?
+--------------------------
+
+nv-SPASM is a stand-alone MIPS assembler that can output either a little-endian flat binary file
+or Sony PlayStation PS-X EXE executable (the default).
+
+It is simple and lightweight, and it is ideal for people who just want to play around
+with assembly without bothering with too many details which would arise with
+more advanced tools, such as those provided by the GNU project.
+
+nv-SPASM is also meant to be compatible with the Hitmen group's SPASM assembler,
+which was an early tool for PlayStation homebrew programmers who had no access
+to more advanced software development kits, such as Net Yaroze or PsyQ.
+
+While to most a tool like SPASM isn't as useful as it was back in the day, due to the
+availability of freely usable software development kits like the PSXSDK, as already
+mentioned before there are still some use cases for which it's more feasible
+to use nv-SPASM instead of more advanced tools.
+
+And, why not? nv-SPASM is easier to hack and to learn from than more advanced,
+complex designs.
+
+You could use it as the assembler for your virtual machine, or even embed this assembler inside it.
+
+1. What is this not?
+--------------------------
+
+nv-SPASM isn't a complex and full-fledged macro assembler; in fact it does not
+even support macros currently.
+
+You can't easily mix code written in a high-level language with assembly code
+with nv-SPASM, as nv-SPASM is unable to output object files that can be linked
+against other object files.
+
+nv-SPASM does not currently support complex expressions, just very simple ones.
+
+2. Features
+--------------------------
+
+- Complete MIPS R3000 instruction set support, with the following pseudo-instructions
+ implemented:
+
+ - B - unconditional branch
+ - LA, LI - load label/integer inside a register (LA and LI are the same thing in nv-SPASM)
+ - NOP - No operation
+ - MOVE - Copy the contents of a register into another
+ - SUBI - Subtract immediate from register
+ - SUBIU - Subtract immediate unsigned from register
+ - BEQZ - Branch if register is Equal to Zero
+ - BNEZ - Branch if register is Not Equal to Zero
+ - BAL - unconditional branch-and-link
+ - ORG - move start address to the desired address
+ it relocates every instruction, and must be the first instruction.
+ - INCLUDE - include a source file
+ - INCBIN - include a binary file
+ - DCB - declare a block of bytes
+ - DB - declare bytes and/or strings
+ - DH - declare half-words and/or strings
+ - DW - declare words and/or strings
+ - ALIGN - align incoming code to the specified boundary
+
+- Compatibility with the Hitmen group's SPASM assembler and thus the possibility
+ of assembling software developed with it, barring bugs in nv-SPASM or the fact
+ that the original source code may depend on bugs in the Hitmen's SPASM assembler
+ in order to assemble correctly.
+
+- Very simple expression support, single operator, two operands.
+ For laymen, this means that while for instance 3+3 is rendered as 6,
+ 3+3+2 is rendered as 5, as if it were 3+2.
+ This is coherent with the original SPASM assembler.
+ Supported operators are +, -, >>, <<, & and |
+
+- Automatic generation of Sony PlayStation PS-X EXE executables.
+
+- Symbol names (labels) can be treated just like normal numerical values,
+ the numerical value being either the program counter value at the moment
+ the label was met by the assembler, or a value set with an EQU or = statement.
+
+
+3. How to use
+--------------------------
+
+nv-SPASM is really simple to use, and does not need any special explanation.
+Therefore, it will suffice to report its usage banner.
+
+nv-spASM version 0.34.1 (c) 2014-2015 nextvolume
+Assembler for the Sony PlayStation
+
+Usage: ./spasm [options] infile outfile
+
+Options: -b create binary file instead of PS-X EXE
+ -N do not pad executable
+ -S be case sensitive on file paths
+
+4. License
+--------------------------
+
+It is permitted to do (almost) anything with the nv-SPASM code and documentation.
+The only restriction is that all existing copyright notices must remain intact, and
+modifed versions must ship with the corresponding modified source code.
+
+fcaseopen.c is (C) 2009 Keith Bauer. Read fcaseopen.c for the license (BSD-style)
+
+5. Useful information
+--------------------------
+
+Hitmen's official website <http://www.hitmen-console.org>
+- The README file for Hitmen's original SPASM assembler is a good read,
+ as this assembler tries to closely follow it.
+- The GreenTro source code is another good resource, as it was developed with SPASM,
+ and thus it can be considered an example to write nv-SPASM assembly source code.
diff --git a/tools/spasm/spasm.c b/tools/spasm/spasm.c
new file mode 100644
index 0000000..c94f5a7
--- /dev/null
+++ b/tools/spasm/spasm.c
@@ -0,0 +1,167 @@
+#include "spasm.h"
+#include "fcaseopen.h"
+
+int rawArgc = 0;
+char rawArgv[64][128];
+char *curText;
+char *curLine;
+FILE *asmOut;
+int line_number;
+
+char *fileBuffer;
+unsigned int fileBufferSize;
+
+int open_case_sensitive = 0;
+
+static void titlecard(void)
+{
+ printf("nv-spASM version 0.34.1 (c) 2014-2015 nextvolume\n");
+}
+
+static void usage(char *prog_name)
+{
+ titlecard();
+ printf("Assembler for the Sony PlayStation\n");
+ printf("\n");
+ printf("Usage: %s [options] infile outfile\n", prog_name);
+ printf("\n");
+ printf("Options: -b create binary file instead of PS-X EXE\n");
+ printf(" -N do not pad executable\n");
+ printf(" -S be case sensitive on file paths\n");
+ printf("\n");
+}
+
+FILE *spasm_fopen(const char *path, const char *mode)
+{
+ if(open_case_sensitive)
+ return fopen(path, mode);
+
+ return fcaseopen(path, mode);
+}
+
+int main(int argc, char *argv[])
+{
+ int sz;
+ int farg=1;
+ int bfile=0;
+ int no_newline=0;
+ int no_pad=0;
+
+ if(argc < 3)
+ {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ while(argv[farg][0] == '-')
+ {
+ if(strcmp(argv[farg], "-b") == 0)
+ bfile = 1; // Generate binary file
+ else if(strcmp(argv[farg], "-N") == 0)
+ no_pad = 1;
+ else if(strcmp(argv[farg], "-S") == 0)
+ open_case_sensitive = 1;
+ else
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ farg++;
+ }
+
+ FILE *f = spasm_fopen(argv[farg], "rb");
+
+ if(!f)
+ {
+ printf("Could not open file %s for reading! Exiting.\n", argv[farg]);
+ return EXIT_FAILURE;
+ }
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ fileBufferSize = sz + 2; // two newline bytes + two NUL bytes
+ fileBuffer = malloc(fileBufferSize);
+ fread(fileBuffer, sizeof(char), sz, f);
+
+ if(fileBuffer[sz-1] != '\n')
+ no_newline = 1;
+
+ fileBuffer[sz] = '\n';
+ fileBuffer[sz+1] = '\0';
+
+ //fileBuffer = process_includes(fileBuffer);
+
+ fclose(f);
+
+ asmOut = fopen(argv[farg+1], "wb");
+
+ if(!asmOut)
+ {
+ printf("Could not open file %s for writing! Exiting.\n", argv[farg+1]);
+ return EXIT_FAILURE;
+ }
+
+ startAddress = 0x80010000;
+
+ titlecard();
+
+ if(no_newline)
+ printf("Warning: No newline found at end of file.\n");
+
+
+ printf("\nPass 1\n");
+ codegen_init();
+ fileBuffer = spasm_parser(fileBuffer, -1);
+ fileBuffer = spasm_parser(fileBuffer, 0);
+
+ /*if(!org_found)
+ {
+ printf("Warning: no ORG directive found... defaulting to $80010000\n");
+ startAddress = 0x80010000;
+ }*/
+
+ curPc = startAddress;
+
+ printf("Pass 2\n");
+ printf("Writing output file %s ...\n", argv[farg+1]);
+
+ if(!bfile)
+ OUTSEEK(0x800);
+
+ fileBuffer = spasm_parser(fileBuffer, 1);
+
+ if(!bfile)
+ {
+ OUTSEEK(0x0);
+ OUTSTRING("\"PS-X EXE\""); // PSX-EXE magic
+ OUTSEEK(0x10);
+ OUTWORD(startAddress); // Initial program counter
+ OUTSEEK(0x18);
+ OUTWORD(startAddress); // Text section start address
+ OUTSEEK(0x30);
+ OUTWORD(0x801FFFF0); // Initial stack pointer
+
+ sz = OUTSIZE();
+
+
+ if(!no_pad && (sz & 2047)) // Pad executable
+ {
+ sz |= 2047;
+ sz++;
+ OUTSEEK(sz-1);
+ OUTBYTE(0);
+ }
+
+ OUTSEEK(0x1C);
+ OUTWORD(sz - 0x800); // Output size of text section
+ }
+
+ printf("\nAssembly complete\n\n");
+
+ fclose(asmOut);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/spasm/spasm.h b/tools/spasm/spasm.h
new file mode 100644
index 0000000..b1ea821
--- /dev/null
+++ b/tools/spasm/spasm.h
@@ -0,0 +1,20 @@
+#ifndef _SPASM_H
+#define _SPASM_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include "error.h"
+#include "codegen.h"
+#include "parser.h"
+#include "opcode.h"
+#include "spasm.h"
+#include "eval.h"
+
+FILE *spasm_fopen(const char *path, const char *mode);
+
+#endif
diff --git a/tools/systemcnf.c b/tools/systemcnf.c
new file mode 100644
index 0000000..301936d
--- /dev/null
+++ b/tools/systemcnf.c
@@ -0,0 +1,50 @@
+/*
+ * systemcnf
+ *
+ * Small program that outputs a system.cnf file to standard output
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+int tcb = 4;
+int event = 16;
+unsigned int stack = 0x801FFFF0;
+
+int main(int argc, char *argv[])
+{
+ int x;
+
+ if(argc < 2)
+ {
+ printf("systemcnf\n");
+ printf("usage: systemcnf exe_name [tcb] [event] [stack_addr]\n");
+ printf("\n");
+ printf("This programs outputs a system.cnf file to standard output\n");
+ printf("Only the exe_name argument is necessary because if the others\n");
+ printf("are missing, the default values are used.\n");
+ printf("Specify stack_addr in hexadecimal, without prefixes.\n");
+ return 0;
+ }
+
+ if(argc >= 3)
+ tcb = atoi(argv[2]);
+
+ if(argc >= 4)
+ event = atoi(argv[3]);
+
+ if(argc >= 5)
+ sscanf(argv[4],"%x",&stack);
+
+ for(x=0;x<strlen(argv[1]);x++)
+ argv[1][x] = toupper((int)argv[1][x]);
+
+ printf("BOOT = cdrom:%s;1\n", argv[1]);
+ printf("TCB = %d\n", tcb);
+ printf("EVENT = %d\n", event);
+ printf("STACK = %X", stack);
+
+ return 0;
+}
diff --git a/tools/tim2bmp.c b/tools/tim2bmp.c
new file mode 100644
index 0000000..ccb0c99
--- /dev/null
+++ b/tools/tim2bmp.c
@@ -0,0 +1,390 @@
+/*
+ * TIM2BMP
+ * Converts TIM, emulator save state VRAM data and raw PSX data
+ * to Windows bitmap format
+ *
+ * Written by Giuseppe Gatta (a.k.a. nextvolume), part of PSXSDK
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+
+#define PCSX_1_5_SAVESTATE_SUPPORT
+
+z_stream strm;
+unsigned short *tim_clut;
+
+typedef struct
+{
+ unsigned int clut_off;
+ unsigned int data_off;
+ unsigned short w; // Width in 16-bit unit pixels
+ unsigned short real_w; // Real width in pixels
+ unsigned short h;
+ unsigned char bpp;
+ unsigned char compr; // Compression - 0 = normal, 1 = GZIP
+ unsigned char has_clut;
+ unsigned short *clut;
+}tim2bmp_info;
+
+tim2bmp_info tim_info;
+
+#include "endian.c"
+
+int mpink_flag = 0;
+
+void rgbpsx_to_rgb24(unsigned short psx_c, unsigned char *r,
+ unsigned char *g, unsigned char *b)
+{
+ *r = (psx_c & 31) << 3;
+ *g = ((psx_c >> 5)&31) << 3;
+ *b = ((psx_c >> 10) &31) << 3;
+
+ if(mpink_flag && !(psx_c & 0x8000) && *r == 0 && *g == 0 && *b == 0)
+ {
+ *r = 255;
+ *g = 0;
+ *b = 255;
+ }
+}
+
+// Returns number of bytes to round image row with.
+int write_bitmap_headers(FILE *f, int w, int h, int bpp)
+{
+ int x;
+ int r;
+ int ret;
+
+ if(bpp == 16)
+ bpp = 24;
+
+ fputc('B', f);
+ fputc('M', f);
+
+ // Calculate and write size of bitmap
+
+ if(bpp == 24)
+ r = w * 3;
+ else if(bpp == 8)
+ r = w;
+ else if(bpp == 4)
+ r = w / 2;
+
+ ret = r;
+
+ if(r & 3)
+ {
+ r|=3;
+ r++;
+ }
+
+ ret = r-ret;
+
+ x=r*h;
+ x+=54;
+
+ if(bpp == 8)
+ x+= 1024;
+ else if(bpp == 4)
+ x+= 64;
+
+ write_le_dword(f, x);
+
+ // Write bfReserved1 and bfReserved2 as zero
+ write_le_dword(f, 0);
+
+ // Calculate and write data offset in file
+
+ x = 54;
+
+ if(bpp == 8)
+ x+= 1024;
+ else if(bpp == 4)
+ x+= 64;
+
+ write_le_dword(f, x);
+
+ write_le_dword(f, 40);
+ write_le_dword(f, w); // Width
+ write_le_dword(f, h); // Height
+ write_le_word(f, 1);
+ write_le_word(f, bpp); // Bits Per Pixel
+ write_le_dword(f, 0);
+ write_le_dword(f, r * h); // Image data size
+ write_le_dword(f, 0);
+ write_le_dword(f, 0);
+ write_le_dword(f, 0);
+ write_le_dword(f,0);
+
+ return ret;
+}
+
+int tim2bmp_read_tim(char *ip, tim2bmp_info *t)
+{
+ int tim_pmode;
+ //int tim_w, tim_h;
+ int /* tim_x, tim_y, tim_cx, tim_cy, */ tim_cw, tim_ch;
+ //int bl;
+ int x;
+ FILE *i = fopen(ip, "rb");
+
+ fseek(i,0,SEEK_SET);
+
+ if(read_le_dword(i) != 0x10)
+ {
+ fclose(i);
+ return -1;
+ }
+
+ tim_pmode = read_le_dword(i);
+ t->has_clut = (tim_pmode & 8) ? 1 : 0;
+ tim_pmode &= 7;
+
+ if(tim_pmode == 0) t->bpp = 4;
+ else if(tim_pmode == 1) t->bpp = 8;
+ else if(tim_pmode == 2) t->bpp = 16;
+ else if(tim_pmode == 3) t->bpp = 24;
+
+ if(t->has_clut)
+ {
+ t->clut_off = 8;
+ /* bl = */ read_le_dword(i);
+ /* tim_cx = */ read_le_word(i);
+ /* tim_cy = */ read_le_word(i);
+ tim_cw = read_le_word(i);
+ tim_ch = read_le_word(i);
+
+ t->clut = malloc((tim_cw * tim_ch) * sizeof(short));
+
+ for(x = 0; x < (tim_cw * tim_ch); x++)
+ t->clut[x] = read_le_word(i);
+ }
+
+ /* bl = */ read_le_dword(i);
+
+ // Read framebuffer X,Y coordinates
+
+ /* tim_x = */ read_le_word(i);
+ /* tim_y = */ read_le_word(i);
+
+ // Read width and height
+ t->w = read_le_word(i); // Fix this for 4bpp and 8bpp images !
+ t->h = read_le_word(i);
+
+ switch(tim_pmode)
+ {
+ case 0: t->real_w = t->w * 4; break;
+ case 1: t->real_w = t->w * 2; break;
+ case 2:
+ t->real_w = t->w;
+ break;
+ }
+
+ t->data_off = ftell(i);
+ t->compr = 0;
+
+ fclose(i);
+
+ return 1;
+}
+
+int tim2bmp_read_pcsx15(char *ip, tim2bmp_info *t)
+{
+ t->w = 1024;
+ t->real_w = 1024;
+ t->h = 512;
+ t->bpp = 16;
+ t->has_clut = 0;
+ t->clut_off = 0;
+ t->data_off = 0x2996C0;
+ t->compr = 1;
+
+ return 1;
+}
+
+void tim2bmp_convert_image_data(char *ip, char *fp, tim2bmp_info *t)
+{
+ int row_round;
+ int y,x;
+ //int z;
+ int tim_row_off;
+ unsigned short c;
+ unsigned char r, g, b;
+ gzFile gzf;
+ //unsigned char test[17];
+ FILE *i = fopen(ip, "rb");
+ FILE *f = fopen(fp, "wb");
+
+ if(t->compr == 1)
+ gzf = gzopen(ip, "rb");
+
+ write_bitmap_headers(f, t->real_w, t->h, t->bpp);
+
+ if(t->has_clut)
+ {
+ if(t->bpp == 4) // 4bpp
+ {
+ for(x = 0; x < 16; x++)
+ {
+ rgbpsx_to_rgb24(t->clut[x], &r, &g, &b);
+ fputc(b, f);
+ fputc(g, f);
+ fputc(r, f);
+ fputc(0, f);
+ }
+ }
+ else if(t->bpp == 8) // 8 bpp
+ {
+ for(x = 0; x < 256; x++)
+ {
+ rgbpsx_to_rgb24(t->clut[x], &r, &g, &b);
+ fputc(b, f);
+ fputc(g, f);
+ fputc(r, f);
+ fputc(0, f);
+ }
+ }
+ }
+ else
+ {
+ if(t->bpp == 4) fseek(f, 64, SEEK_CUR);
+ else if(t->bpp == 8) fseek(f, 1024, SEEK_CUR);
+ }
+
+ if(t->bpp == 16)
+ y = (t->real_w * 24) / 8;
+ else
+ y = (t->real_w * t->bpp) / 8;
+
+// printf("y = %d\n", y);
+ row_round = y;
+// printf("row_round = %d\n", y);
+
+ if(row_round & 3)
+ {
+ row_round |= 3;
+ row_round++;
+ }
+// printf("row_round = %d\n", y);
+
+ row_round -= y;
+// printf("row_round = %d\n", row_round);
+
+ for(y = 0; y < t->h; y++)
+ {
+ tim_row_off = (t->w * 2) * ((t->h - 1)-y);
+
+ if(t->compr == 1)
+ gzseek(gzf, t->data_off + tim_row_off, SEEK_SET);
+ else
+ fseek(i, t->data_off + tim_row_off, SEEK_SET);
+
+ // printf("ERRNO SHY = %s\n", gzerror(gzf, &x));
+
+
+ for(x = 0; x < t->w; x++)
+ {
+ if(t->compr == 1)
+ {
+ gzread(gzf, &b, 1);
+ c = b;
+ gzread(gzf, &b, 1);
+ c|=b<<8;
+ }
+ else
+ c = read_le_word(i);
+
+ switch(t->bpp)
+ {
+ case 4:
+ fputc(((c >> 4) & 0xf) | ((c & 0xf) << 4), f);
+ fputc(((c >> 12) & 0xf) | (((c>>8)&0xf)<<4), f);
+ break;
+ case 8:
+ write_le_word(f, c);
+ break;
+ case 16:
+ rgbpsx_to_rgb24(c, &r, &g, &b);
+
+ fputc(b, f);
+ fputc(g, f);
+ fputc(r, f);
+ break;
+ }
+ }
+
+ for(x = 0; x < row_round; x++)
+ fputc(0, f);
+ }
+
+ fclose(i);
+ fclose(f);
+ if(t->compr == 1) gzclose(gzf);
+}
+
+int main(int argc, char *argv[])
+{
+ //int x, y;
+ int x;
+ FILE *i;
+ //int bl;
+ /*int tim_w, tim_h, tim_x, tim_y, tim_cx, tim_cy, tim_cw, tim_ch;
+ int row_round;
+ unsigned short c;*/
+ //unsigned char r, g, b;
+ /*int tim_pdata_fpos;
+ int tim_row_off;
+ int tim_pmode;
+ int tim_has_clut;
+ int actual_w;
+ int bmp_bpp;*/
+ int r;
+ tim2bmp_info *t = &tim_info;
+
+ if(argc < 2)
+ {
+ printf("tim2bmp - converts a TIM image to a bitmap\n");
+ printf("usage: tim2bmp <intim> <outbmp> [options]\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" -o=<offset>\n");
+ printf(" -mpink - Convert transparency to magic pink\n");
+ printf("\n");
+ return -1;
+ }
+
+ /*strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ r = deflateInit(&strm, 1);*/
+ //printf("r = %d, Z_OK = %d\n", r, Z_OK);
+
+ for(x = 3; x < argc; x++)
+ {
+ if(strcmp(argv[x], "-mpink") == 0)
+ mpink_flag = 1;
+ }
+
+ i = fopen(argv[1], "rb");
+
+ if(i == NULL)
+ {
+ printf("Couldn't open specified TIM file for reading.\n");
+ return -1;
+ }
+
+ fclose(i);
+
+ r = tim2bmp_read_tim(argv[1], &tim_info);
+
+ if(r != 1)
+ r = tim2bmp_read_pcsx15(argv[1], &tim_info);
+
+ if(argc > 2)
+ tim2bmp_convert_image_data(argv[1], argv[2], t);
+
+ return 0;
+}
diff --git a/tools/vag2wav.c b/tools/vag2wav.c
new file mode 100755
index 0000000..09b474a
--- /dev/null
+++ b/tools/vag2wav.c
@@ -0,0 +1,202 @@
+/*
+ * vag2wav
+ *
+ * Converts a PlayStation VAG sound file to a WAV file
+ *
+ * Based on VAG-Depack 0.1 by bITmASTER
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "endian.c"
+
+double f[5][2] = { { 0.0, 0.0 },
+ { 60.0 / 64.0, 0.0 },
+ { 115.0 / 64.0, -52.0 / 64.0 },
+ { 98.0 / 64.0, -55.0 / 64.0 },
+ { 122.0 / 64.0, -60.0 / 64.0 } };
+
+double samples[28];
+
+int main( int argc, char *argv[] )
+{
+ FILE *vag, *pcm;
+ char vag_name[17];
+ int predict_nr, shift_factor, flags;
+ int i;
+ int d, s;
+ static double s_1 = 0.0;
+ static double s_2 = 0.0;
+ int sz;
+ unsigned int samp_freq;
+ unsigned int data_size;
+
+ if(argc < 3)
+ {
+ printf("vag2wav - Convert a PlayStation VAG sound file to a WAV file\n");
+ printf("usage: vag2wav [vag] [wav file]\n");
+ printf("\n");
+ printf("This utility is based on PSX VAG-Depack by bITmASTER\n");
+ return( -1 );
+ }
+
+ vag = fopen( argv[1], "rb" );
+
+ fread(vag_name, sizeof(char), 4, vag);
+
+ if(vag == NULL)
+ {
+ printf("Can't open %s. Aborting.\n", argv[1]);
+ return -1;
+ }
+
+ if(strncmp(vag_name, "VAGp", 4))
+ {
+ printf("%s is not in VAG format. Aborting.\n", argv[1]);
+ return -1;
+ }
+
+ fseek(vag, 4, SEEK_SET);
+ i = fgetc(vag) << 24;
+ i |= fgetc(vag) << 16;
+ i |= fgetc(vag) << 8;
+ i |= fgetc(vag);
+
+ printf("Version: %x\n", i);
+
+ fseek(vag, 12, SEEK_SET);
+ data_size = fgetc(vag) << 24;
+ data_size |= fgetc(vag) << 16;
+ data_size |= fgetc(vag) << 8;
+ data_size |= fgetc(vag);
+
+ printf("Data size: %d bytes\n", data_size);
+
+ fseek(vag, 32, SEEK_SET);
+ fread(vag_name, sizeof(char), 16, vag);
+ vag_name[16] = 0;
+
+ printf("Name: %s\n", vag_name);
+
+ fseek(vag, 16, SEEK_SET);
+
+ samp_freq = fgetc(vag)<<24;
+ samp_freq|=fgetc(vag)<<16;
+ samp_freq|=fgetc(vag)<<8;
+ samp_freq|=fgetc(vag);
+
+ printf("Sampling frequency: %d\n", samp_freq);
+
+ fseek( vag, 64, SEEK_SET );
+
+ /* strcpy( fname, argv[1] );
+ p = strrchr( fname, '.' );
+ p++;
+ strcpy( p, "PCM" );*/
+ pcm = fopen( argv[2], "wb" );
+
+ if ( pcm == NULL ) {
+ printf( "canīt write output file\n" );
+ return( -8 );
+ }
+
+
+// Write header chunk
+ fprintf(pcm, "RIFF");
+// Skip file size field for now
+ fseek(pcm, 4, SEEK_CUR);
+
+ fprintf(pcm, "WAVE");
+// Write fmt chunk
+ fprintf(pcm, "fmt ");
+// Write chunk 1 size in little endian format
+ fputc(0x10, pcm);
+ fputc(0, pcm);
+ fputc(0, pcm);
+ fputc(0, pcm);
+// Write audio format (1 = PCM)
+ fputc(1, pcm);
+ fputc(0, pcm);
+// Number of channels (1)
+ fputc(1, pcm);
+ fputc(0, pcm);
+// Write sample rate
+ fputc((samp_freq & 0xff), pcm);
+ fputc((samp_freq >> 8) & 0xff, pcm);
+ fputc(0, pcm);
+ fputc(0, pcm);
+// Write byte rate (SampleRate * NumChannels * BitsPerSample/8)
+// That would be 44100*1*(16/8), thus 88200.
+ fputc(((samp_freq*2) & 0xff), pcm);
+ fputc(((samp_freq*2) >> 8) & 0xff, pcm);
+ fputc(((samp_freq*2) >> 16) & 0xff, pcm);
+ fputc(((samp_freq*2) >> 24) & 0xff, pcm);
+// Write block align (NumChannels * BitsPerSample/8), thus 2
+ fputc(2, pcm);
+ fputc(0, pcm);
+// Write BitsPerSample
+ fputc(16, pcm);
+ fputc(0, pcm);
+
+// Write data chunk
+ fprintf(pcm, "data");
+
+// Skip SubChunk2Size, we will return to it later
+ fseek(pcm, 4, SEEK_CUR);
+
+// Now write data...
+
+ while( ftell(vag) < (data_size+48)) {
+ predict_nr = fgetc( vag );
+ shift_factor = predict_nr & 0xf;
+ predict_nr >>= 4;
+ flags = fgetc( vag ); // flags
+ if ( flags == 7 )
+ break;
+ for ( i = 0; i < 28; i += 2 ) {
+ d = fgetc( vag );
+ s = ( d & 0xf ) << 12;
+ if ( s & 0x8000 )
+ s |= 0xffff0000;
+ samples[i] = (double) ( s >> shift_factor );
+ s = ( d & 0xf0 ) << 8;
+ if ( s & 0x8000 )
+ s |= 0xffff0000;
+ samples[i+1] = (double) ( s >> shift_factor );
+ }
+
+ for ( i = 0; i < 28; i++ ) {
+ samples[i] = samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1];
+ s_2 = s_1;
+ s_1 = samples[i];
+ d = (int) ( samples[i] + 0.5 );
+ fputc( d & 0xff, pcm );
+ fputc( d >> 8, pcm );
+ }
+ }
+
+// Get file size
+ sz = ftell(pcm);
+
+// Now write ChunkSize
+ fseek(pcm, 4, SEEK_SET);
+
+ fputc((sz-8) & 0xff, pcm);
+ fputc(((sz-8)>>8)&0xff, pcm);
+ fputc(((sz-8)>>16)&0xff,pcm);
+ fputc(((sz-8)>>24)&0xff,pcm);
+
+// Now write Subchunk2Size
+ fseek(pcm, 40, SEEK_SET);
+
+ fputc((sz-44) & 0xff, pcm);
+ fputc(((sz-44)>>8)&0xff, pcm);
+ fputc(((sz-44)>>16)&0xff,pcm);
+ fputc(((sz-44)>>24)&0xff,pcm);
+
+ fclose( pcm );
+ fclose( vag );
+ return( 0 );
+}
+
diff --git a/tools/wav2vag.c b/tools/wav2vag.c
new file mode 100644
index 0000000..e78b84c
--- /dev/null
+++ b/tools/wav2vag.c
@@ -0,0 +1,431 @@
+/*
+ * wav2vag
+ *
+ * Converts a WAV file to a PlayStation VAG file.
+ * Based on PSX VAG-Packer 0.1 by bITmASTER.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "endian.c"
+
+#define BUFFER_SIZE 128*28
+
+short wave[BUFFER_SIZE];
+
+void find_predict( short *samples, double *d_samples, int *predict_nr, int *shift_factor );
+void pack( double *d_samples, short *four_bit, int predict_nr, int shift_factor );
+void fputi( int d, FILE *fp );
+
+int main( int argc, char *argv[] )
+{
+ FILE *fp, *vag;
+ short *ptr;
+ double d_samples[28];
+ short four_bit[28];
+ int predict_nr;
+ int shift_factor;
+ int flags;
+ int size;
+ int i, j, k;
+ unsigned char d;
+ char s[4];
+ int chunk_data;
+ short e;
+ int sample_freq = 0, sample_len;
+ char internal_name[16];
+ int enable_looping = 0;
+ int raw_output = 0;
+ int sraw = 0;
+ short sample_size;
+ unsigned char c;
+
+ if (argc < 3)
+ {
+ printf("wav2vag - Convert a WAV file to a PlayStation VAG sound file\n");
+ printf("usage: wav2vag [wav] [vag] <options>\n");
+ printf("\n");
+ printf("WAV files must have one channel (mono)\n");
+ printf("WAV data format must be either unsigned 8-bit or signed 16-bit PCM\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" -L - Make a looping sample (when it ends it is played again)\n");
+ printf(" -name=<name> - Set sample name\n");
+ printf(" -raw - Output only data, without VAG header\n");
+ printf(" -sraw8 - Source is RAW data, in 8-bit format\n");
+ printf(" -sraw16 - Source is RAW data, in 16-bit format\n");
+ printf(" -freq=<freq> - Force frequency in output VAG\n");
+ printf("\n");
+ printf("This utility is based on PSX VAG-Packer by bITmASTER\n");
+ return -1;
+ }
+
+ for(i = 0; i < sizeof(internal_name); i++)
+ internal_name[i] = 0;
+
+ strcpy(internal_name, "PSXSDK");
+
+ fp = fopen(argv[1], "rb");
+ if (fp == NULL)
+ {
+ printf("Canīt open %s. Aborting.\n", argv[1]);
+ return -2;
+ }
+
+ for(i = 3; i < argc; i++)
+ {
+ if(strcmp(argv[i], "-L") == 0)
+ enable_looping = 1;
+
+ if(strncmp(argv[i], "-name=",6) == 0)
+ strncpy(internal_name, argv[i]+6, 15);
+
+ if(strcmp(argv[i], "-raw") == 0)
+ raw_output = 1;
+
+ if(strcmp(argv[i], "-sraw8") == 0)
+ {
+ fseek(fp, 0, SEEK_END);
+ sample_len = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ sample_size = 8;
+ sample_freq = 44010;
+ sraw = 1;
+ }
+
+ if(strcmp(argv[i], "-sraw16") == 0)
+ {
+ fseek(fp, 0, SEEK_END);
+ sample_len = ftell(fp) / 2;
+ fseek(fp, 0, SEEK_SET);
+ sample_size = 16;
+ sample_freq = 44010;
+ sraw = 1;
+ }
+
+ if(strncmp(argv[i], "-freq=", 6) == 0)
+ {
+ sscanf(argv[i], "-freq=%d", &sample_freq);
+ }
+ }
+
+
+ if(sraw == 1)
+ goto convert_to_vag;
+
+ fread(s, 1, 4, fp);
+ if (strncmp(s, "RIFF", 4))
+ {
+ printf("%s is not in WAV format\n", argv[1]);
+ return -3;
+ }
+
+ fseek(fp, 8, SEEK_SET);
+ fread(s, 1, 4, fp);
+
+ if (strncmp(s, "WAVE", 4))
+ {
+ printf("%s is not in WAV format\n", argv[1]);
+ return -3;
+ }
+
+ fseek(fp, 8 + 4, SEEK_SET);
+ fread(s, 1, 4, fp);
+
+ if (strncmp(s, "fmt", 3))
+ {
+ printf("%s is not in WAV format\n", argv[1]);
+ return -3;
+ }
+
+ // fread(&chunk_data, sizeof(int), 1, fp);
+ chunk_data = read_le_dword(fp);
+ chunk_data += ftell(fp);
+
+ // fread(&e, 2, 1, fp);
+ e = read_le_word(fp);
+
+ if (e!=1)
+ {
+ printf("No PCM found in %s. Aborting.\n", argv[1]);
+ return -4;
+ }
+
+// fread(&e, 2, 1, fp);
+ e = read_le_word(fp);
+
+ if (e!=1)
+ {
+ //printf( "must be MONO\n" );
+ printf("WAV file must have only one channel. Aborting.\n");
+ return -5;
+ }
+
+ if(sample_freq != 0)
+ fseek(fp, 4, SEEK_CUR);
+ else
+ //fread(&sample_freq, 4, 1, fp);
+ sample_freq = read_le_dword(fp);
+
+ fseek(fp, 4 + 2, SEEK_CUR);
+
+// fread(&sample_size, 2, 1, fp);
+ sample_size = read_le_word(fp);
+
+ /* if (e!=16)
+ {
+ //printf( "only 16 bit samples\n" );
+ printf("The size of the samples of the WAV file must be 16-bit."
+ "Aborting.\n");
+ return -6;
+ }*/
+
+ fseek(fp, chunk_data, SEEK_SET);
+
+ fread(s, 1, 4, fp);
+
+ if (strncmp(s, "data", 4))
+ {
+ printf("No data chunk in %s. Aborting.\n", argv[1]);
+ return -7;
+ }
+
+ // fread(&sample_len, 4, 1, fp);
+ sample_len = read_le_dword(fp);
+
+ if(sample_size == 16)
+ sample_len /= 2;
+
+ /*strcpy( fname, argv[1] );
+ p = strrchr( fname, '.' );
+ p++;
+ strcpy( p, "vag" );*/
+convert_to_vag:
+ vag = fopen(argv[2], "wb");
+
+ if (vag == NULL)
+ {
+ printf("Can't open output file. Aborting.\n");
+ return -8;
+ }
+
+/* strcpy(internal_name, "PSXSDK");
+
+ for(i = 3; i < argc; i++)
+ {
+ if(strcmp(argv[i], "-L") == 0)
+ enable_looping = 1;
+
+ if(strncmp(argv[i], "-name=",6) == 0)
+ strncpy(internal_name, argv[i]+6, 15);
+
+ if(strcmp(argv[i], "-raw") == 0)
+ raw_output = 1;
+ }
+*/
+
+ if(raw_output == 0)
+ {
+ fprintf( vag, "VAGp" ); // ID
+ fputi( 0x20, vag ); // Version
+ fputi( 0x00, vag ); // Reserved
+ size = sample_len / 28;
+ if( sample_len % 28 )
+ size++;
+ fputi( 16 * ( size + 2 ), vag ); // Data size
+ fputi( sample_freq, vag ); // Sampling frequency
+
+ for ( i = 0; i < 12; i++ ) // Reserved
+ fputc( 0, vag );
+
+ fwrite(internal_name, sizeof(char), 16, vag);
+
+ for( i = 0; i < 16; i++ )
+ fputc( 0, vag ); // ???
+ }
+
+ if(enable_looping)
+ flags = 6;
+ else
+ flags = 0;
+
+ while( sample_len > 0 ) {
+ size = ( sample_len >= BUFFER_SIZE ) ? BUFFER_SIZE : sample_len;
+
+ if(sample_size == 8)
+ {
+ for(i = 0; i < size; i++)
+ {
+ c = fgetc(fp);
+ wave[i] = c;
+ wave[i] ^= 0x80;
+ wave[i] <<= 8;
+ }
+ }
+ else
+ {
+ // fread( wave, sizeof( short ), size, fp );
+ for(i = 0; i < size; i++)
+ wave[i] = read_le_word(fp);
+ }
+
+ i = size / 28;
+ if ( size % 28 ) {
+ for ( j = size % 28; j < 28; j++ )
+ wave[28*i+j] = 0;
+ i++;
+ }
+
+ for ( j = 0; j < i; j++ ) { // pack 28 samples
+ ptr = wave + j * 28;
+ find_predict( ptr, d_samples, &predict_nr, &shift_factor );
+ pack( d_samples, four_bit, predict_nr, shift_factor );
+ d = ( predict_nr << 4 ) | shift_factor;
+ fputc( d, vag );
+ fputc( flags, vag );
+ for ( k = 0; k < 28; k += 2 ) {
+ d = ( ( four_bit[k+1] >> 8 ) & 0xf0 ) | ( ( four_bit[k] >> 12 ) & 0xf );
+ fputc( d, vag );
+ }
+ sample_len -= 28;
+ if ( sample_len < 28 && enable_looping == 0)
+ flags = 1;
+
+ if(enable_looping)
+ flags = 2;
+ }
+ }
+
+ fputc( ( predict_nr << 4 ) | shift_factor, vag );
+
+ if(enable_looping)
+ fputc(3, vag);
+ else
+ fputc( 7, vag ); // end flag
+
+ for ( i = 0; i < 14; i++ )
+ fputc( 0, vag );
+
+ fclose( fp );
+ fclose( vag );
+// getch();
+ return( 0 );
+}
+
+
+static double f[5][2] = { { 0.0, 0.0 },
+ { -60.0 / 64.0, 0.0 },
+ { -115.0 / 64.0, 52.0 / 64.0 },
+ { -98.0 / 64.0, 55.0 / 64.0 },
+ { -122.0 / 64.0, 60.0 / 64.0 } };
+
+
+
+void find_predict( short *samples, double *d_samples, int *predict_nr, int *shift_factor )
+{
+ int i, j;
+ double buffer[28][5];
+ double min = 1e10;
+ double max[5];
+ double ds;
+ int min2;
+ int shift_mask;
+ static double _s_1 = 0.0; // s[t-1]
+ static double _s_2 = 0.0; // s[t-2]
+ double s_0, s_1, s_2;
+
+ for ( i = 0; i < 5; i++ ) {
+ max[i] = 0.0;
+ s_1 = _s_1;
+ s_2 = _s_2;
+ for ( j = 0; j < 28; j ++ ) {
+ s_0 = (double) samples[j]; // s[t-0]
+ if ( s_0 > 30719.0 )
+ s_0 = 30719.0;
+ if ( s_0 < - 30720.0 )
+ s_0 = -30720.0;
+ ds = s_0 + s_1 * f[i][0] + s_2 * f[i][1];
+ buffer[j][i] = ds;
+ if ( fabs( ds ) > max[i] )
+ max[i] = fabs( ds );
+// printf( "%+5.2f\n", s2 );
+ s_2 = s_1; // new s[t-2]
+ s_1 = s_0; // new s[t-1]
+ }
+
+ if ( max[i] < min ) {
+ min = max[i];
+ *predict_nr = i;
+ }
+ if ( min <= 7 ) {
+ *predict_nr = 0;
+ break;
+ }
+
+ }
+
+// store s[t-2] and s[t-1] in a static variable
+// these than used in the next function call
+
+ _s_1 = s_1;
+ _s_2 = s_2;
+
+ for ( i = 0; i < 28; i++ )
+ d_samples[i] = buffer[i][*predict_nr];
+
+// if ( min > 32767.0 )
+// min = 32767.0;
+
+ min2 = ( int ) min;
+ shift_mask = 0x4000;
+ *shift_factor = 0;
+
+ while( *shift_factor < 12 ) {
+ if ( shift_mask & ( min2 + ( shift_mask >> 3 ) ) )
+ break;
+ (*shift_factor)++;
+ shift_mask = shift_mask >> 1;
+ }
+
+}
+
+void pack( double *d_samples, short *four_bit, int predict_nr, int shift_factor )
+{
+ double ds;
+ int di;
+ double s_0;
+ static double s_1 = 0.0;
+ static double s_2 = 0.0;
+ int i;
+
+ for ( i = 0; i < 28; i++ ) {
+ s_0 = d_samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1];
+ ds = s_0 * (double) ( 1 << shift_factor );
+
+ di = ( (int) ds + 0x800 ) & 0xfffff000;
+
+ if ( di > 32767 )
+ di = 32767;
+ if ( di < -32768 )
+ di = -32768;
+
+ four_bit[i] = (short) di;
+
+ di = di >> shift_factor;
+ s_2 = s_1;
+ s_1 = (double) di - s_0;
+
+ }
+}
+
+void fputi( int d, FILE *fp )
+{
+ fputc( d >> 24, fp );
+ fputc( d >> 16, fp );
+ fputc( d >> 8, fp );
+ fputc( d, fp );
+}