summaryrefslogtreecommitdiff
path: root/lib/ultralib/src
diff options
context:
space:
mode:
authorAnghelo Carvajal <angheloalf95@gmail.com>2023-03-28 23:42:56 -0300
committerGitHub <noreply@github.com>2023-03-29 03:42:56 +0100
commitd66a21685f45d130f980e8a5ec7b08cfe189e40b (patch)
treef11b3b09dc5772e419fe08d3d0ead4e778def57f /lib/ultralib/src
parent6a5e64cc4c26398cc607bb02cdc12a056ddf42d1 (diff)
Initial repo setup (#1)
* git subrepo clone git@github.com:ethteck/splat.git tools/splat subrepo: subdir: "tools/splat" merged: "4fec014" upstream: origin: "git@github.com:ethteck/splat.git" branch: "master" commit: "4fec014" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * gitignore * decompress_baserom.py * Initial yaml * run flib * more yaml stuff * Builds an uncompressed ROM * setup ido download * git subrepo clone git@github.com:simonlindholm/asm-differ.git tools/asm-differ subrepo: subdir: "tools/asm-differ" merged: "ae40866" upstream: origin: "git@github.com:simonlindholm/asm-differ.git" branch: "main" commit: "ae40866" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * git subrepo clone git@github.com:simonlindholm/asm-processor.git tools/asm-processor subrepo: subdir: "tools/asm-processor" merged: "bbd86ea" upstream: origin: "git@github.com:simonlindholm/asm-processor.git" branch: "main" commit: "bbd86ea" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * git subrepo clone (merge) git@github.com:EllipticEllipsis/fado.git tools/fado subrepo: subdir: "tools/fado" merged: "8d896ee" upstream: origin: "git@github.com:EllipticEllipsis/fado.git" branch: "master" commit: "8d896ee" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * setup ido in makefile * data and rodata * add automatic file splits * bootstrap most symbol_addrs * git subrepo clone --branch=irix git@github.com:hensldm/ultralib.git lib/ultralib subrepo: subdir: "lib/ultralib" merged: "0d1e095" upstream: origin: "git@github.com:hensldm/ultralib.git" branch: "irix" commit: "0d1e095" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * setup ido building * various tooling * git subrepo pull tools/asm-differ subrepo: subdir: "tools/asm-differ" merged: "857b398" upstream: origin: "git@github.com:simonlindholm/asm-differ.git" branch: "main" commit: "857b398" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * Change defines to match IDO * review * newlin * update gitignore * Windows error * D_01000000 * yeet settings.json * yeet * git subrepo clone git@github.com:decompals/ultralib.git lib/ultralib subrepo: subdir: "lib/ultralib" merged: "d03b2a3" upstream: origin: "git@github.com:decompals/ultralib.git" branch: "main" commit: "d03b2a3" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596" * clangformat and clangtidy * Setup a bunch of headers * bootstrap boot and code functions and variables headers * global.h * update format.py includes * -D_MIPS_SZLONG=32 * format.py: --verbose * Update tools/decompress_baserom.py Co-authored-by: Derek Hensley <hensley.derek58@gmail.com> * Add libc to global.h * review * yeet saved_regs * yeet headers * yeet _MSC_VER * more header cleanup * add readme licensing note --------- Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
Diffstat (limited to 'lib/ultralib/src')
-rw-r--r--lib/ultralib/src/audio/Makefile120
-rw-r--r--lib/ultralib/src/audio/auxbus.c65
-rw-r--r--lib/ultralib/src/audio/bnkf.c143
-rw-r--r--lib/ultralib/src/audio/cents2ratio.c33
-rw-r--r--lib/ultralib/src/audio/copy.c35
-rw-r--r--lib/ultralib/src/audio/cseq.c409
-rw-r--r--lib/ultralib/src/audio/cseq.h11
-rw-r--r--lib/ultralib/src/audio/cseqp.h10
-rw-r--r--lib/ultralib/src/audio/cspdelete.c29
-rw-r--r--lib/ultralib/src/audio/cspgetchlvol.c27
-rw-r--r--lib/ultralib/src/audio/cspgetfxmix.c27
-rw-r--r--lib/ultralib/src/audio/cspgetpan.c27
-rw-r--r--lib/ultralib/src/audio/cspgetpriority.c26
-rw-r--r--lib/ultralib/src/audio/cspgetprogram.c42
-rw-r--r--lib/ultralib/src/audio/cspgetseq.c29
-rw-r--r--lib/ultralib/src/audio/cspgetstate.c29
-rw-r--r--lib/ultralib/src/audio/cspgettempo.c31
-rw-r--r--lib/ultralib/src/audio/cspgetvol.c27
-rw-r--r--lib/ultralib/src/audio/csplayer.c886
-rw-r--r--lib/ultralib/src/audio/cspplay.c34
-rw-r--r--lib/ultralib/src/audio/cspsendmidi.c40
-rw-r--r--lib/ultralib/src/audio/cspsetbank.c32
-rw-r--r--lib/ultralib/src/audio/cspsetchlvol.c35
-rw-r--r--lib/ultralib/src/audio/cspsetfxmix.c35
-rw-r--r--lib/ultralib/src/audio/cspsetpan.c35
-rw-r--r--lib/ultralib/src/audio/cspsetpriority.c32
-rw-r--r--lib/ultralib/src/audio/cspsetprogram.c35
-rw-r--r--lib/ultralib/src/audio/cspsetseq.c34
-rw-r--r--lib/ultralib/src/audio/cspsettempo.c36
-rw-r--r--lib/ultralib/src/audio/cspsetvol.c32
-rw-r--r--lib/ultralib/src/audio/cspstop.c32
-rw-r--r--lib/ultralib/src/audio/drvrnew.c306
-rw-r--r--lib/ultralib/src/audio/env.c595
-rw-r--r--lib/ultralib/src/audio/event.c272
-rw-r--r--lib/ultralib/src/audio/filter.c32
-rw-r--r--lib/ultralib/src/audio/heapalloc.c65
-rw-r--r--lib/ultralib/src/audio/heapcheck.c71
-rw-r--r--lib/ultralib/src/audio/heapinit.c37
-rw-r--r--lib/ultralib/src/audio/initfx.h59
-rw-r--r--lib/ultralib/src/audio/load.c471
-rw-r--r--lib/ultralib/src/audio/mainbus.c67
-rw-r--r--lib/ultralib/src/audio/parse_abi.c47
-rw-r--r--lib/ultralib/src/audio/resample.c150
-rw-r--r--lib/ultralib/src/audio/reverb.c457
-rw-r--r--lib/ultralib/src/audio/save.c73
-rw-r--r--lib/ultralib/src/audio/seq.c343
-rw-r--r--lib/ultralib/src/audio/seq.h9
-rw-r--r--lib/ultralib/src/audio/seqp.h37
-rw-r--r--lib/ultralib/src/audio/seqpdelete.c42
-rw-r--r--lib/ultralib/src/audio/seqpgetchlvol.c27
-rw-r--r--lib/ultralib/src/audio/seqpgetfxmix.c27
-rw-r--r--lib/ultralib/src/audio/seqpgetpan.c27
-rw-r--r--lib/ultralib/src/audio/seqpgetpriority.c26
-rw-r--r--lib/ultralib/src/audio/seqpgetprogram.c42
-rw-r--r--lib/ultralib/src/audio/seqpgetseq.c29
-rw-r--r--lib/ultralib/src/audio/seqpgetstate.c29
-rw-r--r--lib/ultralib/src/audio/seqpgettempo.c31
-rw-r--r--lib/ultralib/src/audio/seqpgetvol.c27
-rw-r--r--lib/ultralib/src/audio/seqplayer.c1231
-rw-r--r--lib/ultralib/src/audio/seqploop.c35
-rw-r--r--lib/ultralib/src/audio/seqpplay.c48
-rw-r--r--lib/ultralib/src/audio/seqpsendmidi.c40
-rw-r--r--lib/ultralib/src/audio/seqpsetbank.c32
-rw-r--r--lib/ultralib/src/audio/seqpsetchlvol.c35
-rw-r--r--lib/ultralib/src/audio/seqpsetfxmix.c35
-rw-r--r--lib/ultralib/src/audio/seqpsetpan.c35
-rw-r--r--lib/ultralib/src/audio/seqpsetpriority.c32
-rw-r--r--lib/ultralib/src/audio/seqpsetprogram.c36
-rw-r--r--lib/ultralib/src/audio/seqpsetseq.c34
-rw-r--r--lib/ultralib/src/audio/seqpsettempo.c36
-rw-r--r--lib/ultralib/src/audio/seqpsetvol.c32
-rw-r--r--lib/ultralib/src/audio/seqpstop.c33
-rw-r--r--lib/ultralib/src/audio/sl.c65
-rw-r--r--lib/ultralib/src/audio/sndp.h102
-rw-r--r--lib/ultralib/src/audio/sndpallocate.c43
-rw-r--r--lib/ultralib/src/audio/sndpdeallocate.c35
-rw-r--r--lib/ultralib/src/audio/sndpdelete.c44
-rw-r--r--lib/ultralib/src/audio/sndpgetsound.c27
-rw-r--r--lib/ultralib/src/audio/sndpgetstate.c29
-rw-r--r--lib/ultralib/src/audio/sndplayer.c300
-rw-r--r--lib/ultralib/src/audio/sndpplay.c36
-rw-r--r--lib/ultralib/src/audio/sndpplayat.c32
-rw-r--r--lib/ultralib/src/audio/sndpsetfxmix.c42
-rw-r--r--lib/ultralib/src/audio/sndpsetpan.c42
-rw-r--r--lib/ultralib/src/audio/sndpsetpitch.c48
-rw-r--r--lib/ultralib/src/audio/sndpsetpriority.c38
-rw-r--r--lib/ultralib/src/audio/sndpsetsound.c36
-rw-r--r--lib/ultralib/src/audio/sndpsetvol.c42
-rw-r--r--lib/ultralib/src/audio/sndpstop.c35
-rw-r--r--lib/ultralib/src/audio/synaddplayer.c34
-rw-r--r--lib/ultralib/src/audio/synallocfx.c32
-rw-r--r--lib/ultralib/src/audio/synallocvoice.c132
-rw-r--r--lib/ultralib/src/audio/syndelete.c27
-rw-r--r--lib/ultralib/src/audio/synfreefx.c26
-rw-r--r--lib/ultralib/src/audio/synfreevoice.c54
-rw-r--r--lib/ultralib/src/audio/syngetfxref.c33
-rw-r--r--lib/ultralib/src/audio/syngetpriority.c27
-rw-r--r--lib/ultralib/src/audio/synremoveplayer.c49
-rw-r--r--lib/ultralib/src/audio/synsetfxmix.c51
-rw-r--r--lib/ultralib/src/audio/synsetfxparam.c29
-rw-r--r--lib/ultralib/src/audio/synsetpan.c50
-rw-r--r--lib/ultralib/src/audio/synsetpitch.c50
-rw-r--r--lib/ultralib/src/audio/synsetpriority.c27
-rw-r--r--lib/ultralib/src/audio/synsetvol.c50
-rw-r--r--lib/ultralib/src/audio/synstartvoice.c48
-rw-r--r--lib/ultralib/src/audio/synstartvoiceparam.c64
-rw-r--r--lib/ultralib/src/audio/synstopvoice.c44
-rw-r--r--lib/ultralib/src/audio/synthInternals.h338
-rw-r--r--lib/ultralib/src/audio/synthesizer.c327
-rw-r--r--lib/ultralib/src/debug/osint_debug.h11
-rw-r--r--lib/ultralib/src/debug/threadprofile.c22
-rw-r--r--lib/ultralib/src/debug/threadprofileclear.c11
-rw-r--r--lib/ultralib/src/debug/threadprofileinit.c16
-rw-r--r--lib/ultralib/src/debug/threadprofilereadcount.c31
-rw-r--r--lib/ultralib/src/debug/threadprofilereadtime.c43
-rw-r--r--lib/ultralib/src/debug/threadprofilestart.c20
-rw-r--r--lib/ultralib/src/debug/threadprofilestop.c34
-rw-r--r--lib/ultralib/src/flash/flashallerase.c31
-rw-r--r--lib/ultralib/src/flash/flashallerasethrough.c7
-rw-r--r--lib/ultralib/src/flash/flashchange.c8
-rw-r--r--lib/ultralib/src/flash/flashcheckeraseend.c21
-rw-r--r--lib/ultralib/src/flash/flashclearstatus.c10
-rw-r--r--lib/ultralib/src/flash/flashgetaddr.c7
-rw-r--r--lib/ultralib/src/flash/flashinit.c43
-rw-r--r--lib/ultralib/src/flash/flashreadarray.c49
-rw-r--r--lib/ultralib/src/flash/flashreadid.c27
-rw-r--r--lib/ultralib/src/flash/flashreadstatus.c17
-rw-r--r--lib/ultralib/src/flash/flashreinit.c14
-rw-r--r--lib/ultralib/src/flash/flashsectorerase.c31
-rw-r--r--lib/ultralib/src/flash/flashsectorerasethrough.c7
-rw-r--r--lib/ultralib/src/flash/flashwritearray.c33
-rw-r--r--lib/ultralib/src/flash/flashwritebuffer.c19
-rw-r--r--lib/ultralib/src/gio/giointerrupt.c8
-rw-r--r--lib/ultralib/src/gio/giorawinterrupt.c18
-rw-r--r--lib/ultralib/src/gt/Makefile19
-rw-r--r--lib/ultralib/src/gt/dumpturbo.c255
-rw-r--r--lib/ultralib/src/gt/gt.c155
-rw-r--r--lib/ultralib/src/gt/gtint.h36
-rw-r--r--lib/ultralib/src/gu/Makefile52
-rw-r--r--lib/ultralib/src/gu/align.c75
-rw-r--r--lib/ultralib/src/gu/cosf.c137
-rw-r--r--lib/ultralib/src/gu/coss.c45
-rw-r--r--lib/ultralib/src/gu/dump_gbi.c274
-rw-r--r--lib/ultralib/src/gu/frustum.c42
-rw-r--r--lib/ultralib/src/gu/guint.h42
-rw-r--r--lib/ultralib/src/gu/guloadtile_bug.c235
-rw-r--r--lib/ultralib/src/gu/libm_vals.s5
-rw-r--r--lib/ultralib/src/gu/loadtextureblockmipmap.c716
-rw-r--r--lib/ultralib/src/gu/lookat.c83
-rw-r--r--lib/ultralib/src/gu/lookathil.c185
-rw-r--r--lib/ultralib/src/gu/lookatref.c111
-rw-r--r--lib/ultralib/src/gu/lookatstereo.c111
-rw-r--r--lib/ultralib/src/gu/mtxcatl.c45
-rw-r--r--lib/ultralib/src/gu/mtxutil.c73
-rw-r--r--lib/ultralib/src/gu/ortho.c41
-rw-r--r--lib/ultralib/src/gu/parse_gbi.c131
-rw-r--r--lib/ultralib/src/gu/parse_rdp.c36
-rw-r--r--lib/ultralib/src/gu/parse_string.c35
-rw-r--r--lib/ultralib/src/gu/perspective.c58
-rw-r--r--lib/ultralib/src/gu/position.c73
-rw-r--r--lib/ultralib/src/gu/poslight.c69
-rw-r--r--lib/ultralib/src/gu/poslighthil.c168
-rw-r--r--lib/ultralib/src/gu/random.c33
-rw-r--r--lib/ultralib/src/gu/readme.txt17
-rw-r--r--lib/ultralib/src/gu/rotate.c63
-rw-r--r--lib/ultralib/src/gu/rotaterpy.c58
-rw-r--r--lib/ultralib/src/gu/sinf.c157
-rw-r--r--lib/ultralib/src/gu/sins.c61
-rw-r--r--lib/ultralib/src/gu/sintable.h1031
-rw-r--r--lib/ultralib/src/gu/sqrtf.s25
-rw-r--r--lib/ultralib/src/gu/us2dex.c62
-rw-r--r--lib/ultralib/src/gu/us2dex2_emu.c12
-rw-r--r--lib/ultralib/src/gu/us2dex_emu.c502
-rw-r--r--lib/ultralib/src/gu/usprite.c39
-rw-r--r--lib/ultralib/src/host/host_ptn64.c203
-rw-r--r--lib/ultralib/src/host/readhost.c36
-rw-r--r--lib/ultralib/src/host/writehost.c54
-rwxr-xr-xlib/ultralib/src/io/ai.c15
-rwxr-xr-xlib/ultralib/src/io/aigetlen.c8
-rwxr-xr-xlib/ultralib/src/io/aigetstat.c8
-rwxr-xr-xlib/ultralib/src/io/aisetfreq.c29
-rwxr-xr-xlib/ultralib/src/io/aisetnextbuf.c31
-rw-r--r--lib/ultralib/src/io/cartrominit.c65
-rw-r--r--lib/ultralib/src/io/contchannelreset.c27
-rwxr-xr-xlib/ultralib/src/io/conteeplongread.c15
-rwxr-xr-xlib/ultralib/src/io/conteeplongwrite.c17
-rwxr-xr-xlib/ultralib/src/io/conteepprobe.c32
-rwxr-xr-xlib/ultralib/src/io/conteepread.c100
-rwxr-xr-xlib/ultralib/src/io/conteepwrite.c158
-rwxr-xr-xlib/ultralib/src/io/contpfs.c297
-rwxr-xr-xlib/ultralib/src/io/contquery.c25
-rw-r--r--lib/ultralib/src/io/contramread.c75
-rw-r--r--lib/ultralib/src/io/contramwrite.c77
-rw-r--r--lib/ultralib/src/io/contreaddata.c68
-rw-r--r--lib/ultralib/src/io/contreset.c51
-rw-r--r--lib/ultralib/src/io/controller.c99
-rwxr-xr-xlib/ultralib/src/io/controller.h257
-rw-r--r--lib/ultralib/src/io/controller_gbpak.h8
-rw-r--r--lib/ultralib/src/io/controller_voice.h59
-rw-r--r--lib/ultralib/src/io/contsetch.c19
-rw-r--r--lib/ultralib/src/io/crc.c64
-rw-r--r--lib/ultralib/src/io/devmgr.c110
-rwxr-xr-xlib/ultralib/src/io/dp.c15
-rwxr-xr-xlib/ultralib/src/io/dpctr.c9
-rwxr-xr-xlib/ultralib/src/io/dpgetstat.c9
-rwxr-xr-xlib/ultralib/src/io/dpsetnextbuf.c24
-rwxr-xr-xlib/ultralib/src/io/dpsetstat.c9
-rw-r--r--lib/ultralib/src/io/epidma.c24
-rw-r--r--lib/ultralib/src/io/epigettype.c8
-rw-r--r--lib/ultralib/src/io/epilinkhandle.c12
-rw-r--r--lib/ultralib/src/io/epirawdma.c27
-rw-r--r--lib/ultralib/src/io/epirawread.c14
-rw-r--r--lib/ultralib/src/io/epirawwrite.c14
-rw-r--r--lib/ultralib/src/io/epiread.c13
-rw-r--r--lib/ultralib/src/io/epiwrite.c13
-rw-r--r--lib/ultralib/src/io/gbpakcheckconnector.c131
-rw-r--r--lib/ultralib/src/io/gbpakgetbank.c28
-rw-r--r--lib/ultralib/src/io/gbpakgetstatus.c39
-rw-r--r--lib/ultralib/src/io/gbpakinit.c90
-rw-r--r--lib/ultralib/src/io/gbpakpower.c34
-rw-r--r--lib/ultralib/src/io/gbpakreadid.c84
-rw-r--r--lib/ultralib/src/io/gbpakreadwrite.c69
-rw-r--r--lib/ultralib/src/io/gbpaksetbank.c35
-rw-r--r--lib/ultralib/src/io/motor.c136
-rw-r--r--lib/ultralib/src/io/pfsallocatefile.c148
-rw-r--r--lib/ultralib/src/io/pfschecker.c203
-rw-r--r--lib/ultralib/src/io/pfsdeletefile.c64
-rw-r--r--lib/ultralib/src/io/pfsfilestate.c55
-rw-r--r--lib/ultralib/src/io/pfsfreeblocks.c27
-rw-r--r--lib/ultralib/src/io/pfsgetlabel.c23
-rw-r--r--lib/ultralib/src/io/pfsgetstatus.c78
-rw-r--r--lib/ultralib/src/io/pfsinit.c25
-rw-r--r--lib/ultralib/src/io/pfsinitpak.c101
-rw-r--r--lib/ultralib/src/io/pfsisplug.c96
-rw-r--r--lib/ultralib/src/io/pfsnumfiles.c24
-rw-r--r--lib/ultralib/src/io/pfsreadwritefile.c119
-rw-r--r--lib/ultralib/src/io/pfsreformat.c70
-rw-r--r--lib/ultralib/src/io/pfsrepairid.c18
-rw-r--r--lib/ultralib/src/io/pfssearchfile.c51
-rw-r--r--lib/ultralib/src/io/pfsselectbank.c20
-rw-r--r--lib/ultralib/src/io/pfssetlabel.c31
-rw-r--r--lib/ultralib/src/io/pi.c13
-rw-r--r--lib/ultralib/src/io/piacs.c24
-rw-r--r--lib/ultralib/src/io/pidma.c30
-rw-r--r--lib/ultralib/src/io/pigetcmdq.c10
-rw-r--r--lib/ultralib/src/io/pigetstat.c9
-rw-r--r--lib/ultralib/src/io/pigettype.c8
-rw-r--r--lib/ultralib/src/io/piint.h154
-rw-r--r--lib/ultralib/src/io/pimgr.c53
-rw-r--r--lib/ultralib/src/io/pirawdma.c25
-rw-r--r--lib/ultralib/src/io/pirawread.c13
-rw-r--r--lib/ultralib/src/io/pirawwrite.c13
-rw-r--r--lib/ultralib/src/io/piread.c13
-rw-r--r--lib/ultralib/src/io/piwrite.c13
-rw-r--r--lib/ultralib/src/io/si.c15
-rw-r--r--lib/ultralib/src/io/siacs.c24
-rw-r--r--lib/ultralib/src/io/sigetstat.c9
-rwxr-xr-xlib/ultralib/src/io/siint.h15
-rw-r--r--lib/ultralib/src/io/sirawdma.c29
-rw-r--r--lib/ultralib/src/io/sirawread.c14
-rw-r--r--lib/ultralib/src/io/sirawwrite.c14
-rwxr-xr-xlib/ultralib/src/io/sp.c17
-rwxr-xr-xlib/ultralib/src/io/spgetstat.c9
-rwxr-xr-xlib/ultralib/src/io/sprawdma.c30
-rwxr-xr-xlib/ultralib/src/io/sprawread.c16
-rwxr-xr-xlib/ultralib/src/io/sprawwrite.c15
-rw-r--r--lib/ultralib/src/io/spsetpc.c15
-rwxr-xr-xlib/ultralib/src/io/spsetstat.c9
-rwxr-xr-xlib/ultralib/src/io/sptask.c63
-rwxr-xr-xlib/ultralib/src/io/sptaskyield.c6
-rwxr-xr-xlib/ultralib/src/io/sptaskyielded.c18
-rw-r--r--lib/ultralib/src/io/vi.c39
-rw-r--r--lib/ultralib/src/io/viblack.c17
-rw-r--r--lib/ultralib/src/io/viextendvstart.c6
-rw-r--r--lib/ultralib/src/io/vifade.c18
-rw-r--r--lib/ultralib/src/io/vigetcurrcontext.c9
-rw-r--r--lib/ultralib/src/io/vigetcurrframebuf.c10
-rw-r--r--lib/ultralib/src/io/vigetfield.c6
-rw-r--r--lib/ultralib/src/io/vigetline.c6
-rw-r--r--lib/ultralib/src/io/vigetmode.c10
-rw-r--r--lib/ultralib/src/io/vigetnextcontext.c6
-rw-r--r--lib/ultralib/src/io/vigetnextframebuf.c10
-rw-r--r--lib/ultralib/src/io/vigetstat.c6
-rw-r--r--lib/ultralib/src/io/viint.h70
-rw-r--r--lib/ultralib/src/io/vimgr.c110
-rw-r--r--lib/ultralib/src/io/virepeatline.c17
-rw-r--r--lib/ultralib/src/io/visetevent.c14
-rw-r--r--lib/ultralib/src/io/visetmode.c14
-rw-r--r--lib/ultralib/src/io/visetspecial.c48
-rw-r--r--lib/ultralib/src/io/visetxscale.c16
-rw-r--r--lib/ultralib/src/io/visetyscale.c13
-rw-r--r--lib/ultralib/src/io/viswapbuf.c13
-rw-r--r--lib/ultralib/src/io/viswapcontext.c72
-rw-r--r--lib/ultralib/src/io/vitbl.c1742
-rw-r--r--lib/ultralib/src/libc/bcmp.s92
-rw-r--r--lib/ultralib/src/libc/bcopy.s218
-rw-r--r--lib/ultralib/src/libc/bzero.s58
-rwxr-xr-xlib/ultralib/src/libc/ldiv.c33
-rwxr-xr-xlib/ultralib/src/libc/ll.c46
-rwxr-xr-xlib/ultralib/src/libc/llbit.c50
-rwxr-xr-xlib/ultralib/src/libc/llcvt.c31
-rwxr-xr-xlib/ultralib/src/libc/sprintf.c24
-rwxr-xr-xlib/ultralib/src/libc/string.c34
-rwxr-xr-xlib/ultralib/src/libc/syncprintf.c17
-rw-r--r--lib/ultralib/src/libc/xldtob.c311
-rwxr-xr-xlib/ultralib/src/libc/xlitob.c64
-rwxr-xr-xlib/ultralib/src/libc/xprintf.c241
-rwxr-xr-xlib/ultralib/src/libc/xstdio.h37
-rw-r--r--lib/ultralib/src/mgu/Makefile36
-rw-r--r--lib/ultralib/src/mgu/asm.h49
-rw-r--r--lib/ultralib/src/mgu/mtxcatf.s103
-rw-r--r--lib/ultralib/src/mgu/mtxcatl.c34
-rw-r--r--lib/ultralib/src/mgu/mtxf2l.s80
-rw-r--r--lib/ultralib/src/mgu/mtxident.s60
-rw-r--r--lib/ultralib/src/mgu/mtxidentf.s60
-rw-r--r--lib/ultralib/src/mgu/mtxl2f.s80
-rw-r--r--lib/ultralib/src/mgu/mtxxfmf.c40
-rw-r--r--lib/ultralib/src/mgu/mtxxfml.c41
-rw-r--r--lib/ultralib/src/mgu/normalize.s56
-rw-r--r--lib/ultralib/src/mgu/regdef.h187
-rw-r--r--lib/ultralib/src/mgu/rotate.c64
-rw-r--r--lib/ultralib/src/mgu/scale.s85
-rw-r--r--lib/ultralib/src/mgu/scalef.s57
-rw-r--r--lib/ultralib/src/mgu/translate.s101
-rw-r--r--lib/ultralib/src/mgu/translatef.s58
-rw-r--r--lib/ultralib/src/os/ackramromread.c8
-rw-r--r--lib/ultralib/src/os/ackramromwrite.c8
-rw-r--r--lib/ultralib/src/os/afterprenmi.c5
-rw-r--r--lib/ultralib/src/os/assert.c5
-rw-r--r--lib/ultralib/src/os/atomic.c15
-rw-r--r--lib/ultralib/src/os/createmesgqueue.c11
-rw-r--r--lib/ultralib/src/os/createthread.c27
-rw-r--r--lib/ultralib/src/os/destroythread.c37
-rw-r--r--lib/ultralib/src/os/exceptasm.h23
-rw-r--r--lib/ultralib/src/os/exceptasm.s1019
-rw-r--r--lib/ultralib/src/os/exit.c8
-rw-r--r--lib/ultralib/src/os/getactivequeue.c6
-rw-r--r--lib/ultralib/src/os/getcause.s9
-rw-r--r--lib/ultralib/src/os/getcompare.s9
-rw-r--r--lib/ultralib/src/os/getconfig.s9
-rw-r--r--lib/ultralib/src/os/getcount.s9
-rw-r--r--lib/ultralib/src/os/getcurrfaultthread.c6
-rw-r--r--lib/ultralib/src/os/getfpccsr.s10
-rw-r--r--lib/ultralib/src/os/gethwinterrupt.c13
-rw-r--r--lib/ultralib/src/os/getintmask.s32
-rw-r--r--lib/ultralib/src/os/getmemsize.c35
-rw-r--r--lib/ultralib/src/os/getnextfaultthread.c28
-rw-r--r--lib/ultralib/src/os/getsr.s9
-rw-r--r--lib/ultralib/src/os/getthreadid.c10
-rw-r--r--lib/ultralib/src/os/getthreadpri.c10
-rw-r--r--lib/ultralib/src/os/gettime.c15
-rw-r--r--lib/ultralib/src/os/gettlbasid.s11
-rw-r--r--lib/ultralib/src/os/gettlbhi.s17
-rw-r--r--lib/ultralib/src/os/gettlblo0.s17
-rw-r--r--lib/ultralib/src/os/gettlblo1.s17
-rw-r--r--lib/ultralib/src/os/gettlbpagemask.s17
-rw-r--r--lib/ultralib/src/os/getwatchlo.s9
-rw-r--r--lib/ultralib/src/os/initialize.c105
-rw-r--r--lib/ultralib/src/os/initialize_emu.c28
-rw-r--r--lib/ultralib/src/os/initialize_isv.c176
-rw-r--r--lib/ultralib/src/os/initialize_kmc.c154
-rw-r--r--lib/ultralib/src/os/initialize_msp.c154
-rw-r--r--lib/ultralib/src/os/initrdb.c30
-rw-r--r--lib/ultralib/src/os/interrupt.s41
-rw-r--r--lib/ultralib/src/os/invaldcache.s61
-rw-r--r--lib/ultralib/src/os/invalicache.s42
-rw-r--r--lib/ultralib/src/os/jammesg.c27
-rw-r--r--lib/ultralib/src/os/kdebugserver.c96
-rw-r--r--lib/ultralib/src/os/maptlb.s64
-rw-r--r--lib/ultralib/src/os/maptlbrdb.s30
-rw-r--r--lib/ultralib/src/os/osint.h55
-rw-r--r--lib/ultralib/src/os/parameters.s16
-rw-r--r--lib/ultralib/src/os/physicaltovirtual.c6
-rw-r--r--lib/ultralib/src/os/probetlb.s54
-rw-r--r--lib/ultralib/src/os/rdbsend.c1
-rw-r--r--lib/ultralib/src/os/recvmesg.c31
-rw-r--r--lib/ultralib/src/os/resetglobalintmask.c9
-rw-r--r--lib/ultralib/src/os/sendmesg.c28
-rw-r--r--lib/ultralib/src/os/setcause.s9
-rw-r--r--lib/ultralib/src/os/setcompare.s9
-rw-r--r--lib/ultralib/src/os/setconfig.s9
-rw-r--r--lib/ultralib/src/os/setcount.s9
-rw-r--r--lib/ultralib/src/os/seterrorhandler.c10
-rw-r--r--lib/ultralib/src/os/seteventmesg.c23
-rw-r--r--lib/ultralib/src/os/setfpccsr.s11
-rw-r--r--lib/ultralib/src/os/setglobalintmask.c9
-rw-r--r--lib/ultralib/src/os/sethwinterrupt.c16
-rw-r--r--lib/ultralib/src/os/setintmask.s124
-rw-r--r--lib/ultralib/src/os/setpiinterrupt.c16
-rw-r--r--lib/ultralib/src/os/setsr.s10
-rw-r--r--lib/ultralib/src/os/setthreadpri.c26
-rw-r--r--lib/ultralib/src/os/settime.c6
-rw-r--r--lib/ultralib/src/os/settimer.c41
-rw-r--r--lib/ultralib/src/os/settlbasid.s9
-rw-r--r--lib/ultralib/src/os/setwatchlo.s10
-rw-r--r--lib/ultralib/src/os/startthread.c35
-rw-r--r--lib/ultralib/src/os/stopthread.c25
-rw-r--r--lib/ultralib/src/os/stoptimer.c30
-rw-r--r--lib/ultralib/src/os/syncputchars.c32
-rw-r--r--lib/ultralib/src/os/testhost.c4
-rw-r--r--lib/ultralib/src/os/thread.c25
-rw-r--r--lib/ultralib/src/os/threadasm.h68
-rw-r--r--lib/ultralib/src/os/timerintr.c106
-rw-r--r--lib/ultralib/src/os/unmaptlb.s24
-rw-r--r--lib/ultralib/src/os/unmaptlball.s26
-rw-r--r--lib/ultralib/src/os/virtualtophysical.c13
-rw-r--r--lib/ultralib/src/os/writebackdcache.s35
-rw-r--r--lib/ultralib/src/os/writebackdcacheall.s18
-rw-r--r--lib/ultralib/src/os/yieldthread.c10
-rwxr-xr-xlib/ultralib/src/rg/free.c15
-rwxr-xr-xlib/ultralib/src/rg/getbufcount.c10
-rwxr-xr-xlib/ultralib/src/rg/getsize.c9
-rwxr-xr-xlib/ultralib/src/rg/malloc.c17
-rwxr-xr-xlib/ultralib/src/rg/region.c36
-rw-r--r--lib/ultralib/src/rmon/rmonbrk.c423
-rw-r--r--lib/ultralib/src/rmon/rmoncmds.c49
-rw-r--r--lib/ultralib/src/rmon/rmonint.h169
-rw-r--r--lib/ultralib/src/rmon/rmonmain.c127
-rw-r--r--lib/ultralib/src/rmon/rmonmem.c271
-rw-r--r--lib/ultralib/src/rmon/rmonmisc.c69
-rw-r--r--lib/ultralib/src/rmon/rmonprint.c1
-rw-r--r--lib/ultralib/src/rmon/rmonrcp.s59
-rw-r--r--lib/ultralib/src/rmon/rmonregs.c402
-rw-r--r--lib/ultralib/src/rmon/rmonsio.c77
-rw-r--r--lib/ultralib/src/rmon/rmontask.c332
-rw-r--r--lib/ultralib/src/sched/Makefile19
-rw-r--r--lib/ultralib/src/sched/sched.c623
-rw-r--r--lib/ultralib/src/sched/sched_log.fmt19
-rw-r--r--lib/ultralib/src/sp/Makefile30
-rw-r--r--lib/ultralib/src/sp/clearattribute.c35
-rw-r--r--lib/ultralib/src/sp/color.c39
-rw-r--r--lib/ultralib/src/sp/hide.c35
-rw-r--r--lib/ultralib/src/sp/setattribute.c35
-rw-r--r--lib/ultralib/src/sp/show.c35
-rw-r--r--lib/ultralib/src/sp/sprite.c757
-rw-r--r--lib/ultralib/src/sp/spriteex.c2
-rw-r--r--lib/ultralib/src/sp/spriteex2.c2
-rw-r--r--lib/ultralib/src/sp/spscale.c42
-rw-r--r--lib/ultralib/src/vimodes/vimodefpalhaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpalhan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpalhpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpalhpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpalhpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpalhpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallaf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallan2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodefpallpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempalhaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempalhan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempalhpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempalhpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempalhpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempalhpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallaf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallan2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodempallpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentschaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentschan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentschpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentschpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentschpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentschpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclaf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclan2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodentsclpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepalhaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepalhan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepalhpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepalhpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepalhpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepalhpn2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallaf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallaf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallan1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallan2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallpf1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallpf2.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallpn1.c35
-rw-r--r--lib/ultralib/src/vimodes/vimodepallpn2.c35
-rw-r--r--lib/ultralib/src/voice/voicecheckresult.c23
-rw-r--r--lib/ultralib/src/voice/voicecheckword.c116
-rw-r--r--lib/ultralib/src/voice/voicecleardictionary.c28
-rw-r--r--lib/ultralib/src/voice/voicecontread2.c75
-rw-r--r--lib/ultralib/src/voice/voicecontread36.c73
-rw-r--r--lib/ultralib/src/voice/voicecontrolgain.c22
-rw-r--r--lib/ultralib/src/voice/voicecontwrite20.c77
-rw-r--r--lib/ultralib/src/voice/voicecontwrite4.c75
-rw-r--r--lib/ultralib/src/voice/voicecountsyllables.c59
-rw-r--r--lib/ultralib/src/voice/voicecrc.c40
-rw-r--r--lib/ultralib/src/voice/voicegetreaddata.c94
-rw-r--r--lib/ultralib/src/voice/voicegetstatus.c61
-rw-r--r--lib/ultralib/src/voice/voiceinit.c40
-rw-r--r--lib/ultralib/src/voice/voiceinternal.h10
-rw-r--r--lib/ultralib/src/voice/voicemaskdictionary.c47
-rw-r--r--lib/ultralib/src/voice/voicesetadconverter.c70
-rw-r--r--lib/ultralib/src/voice/voicesetword.c44
-rw-r--r--lib/ultralib/src/voice/voicestartreaddata.c35
-rw-r--r--lib/ultralib/src/voice/voicestopreaddata.c44
513 files changed, 35517 insertions, 0 deletions
diff --git a/lib/ultralib/src/audio/Makefile b/lib/ultralib/src/audio/Makefile
new file mode 100644
index 0000000..d8fdce4
--- /dev/null
+++ b/lib/ultralib/src/audio/Makefile
@@ -0,0 +1,120 @@
+#!smake
+#
+# Makefile for audio library subdirectory
+#
+
+include $(ROOT)/usr/include/make/PRdefs
+
+# LCOPTS = -mips2 -non_shared -fullwarn -G 0
+LCINCS = -I. -I$(ROOT)/usr/include/PR -I$(ROOT)/usr/include
+
+CFILES = \
+ drvrnew.c \
+ load.c \
+ auxbus.c \
+ bnkf.c \
+ env.c \
+ event.c \
+ filter.c \
+ mainbus.c \
+ resample.c \
+ reverb.c \
+ save.c \
+ seq.c \
+ sl.c \
+ heapcheck.c \
+ heapinit.c \
+ heapalloc.c \
+ copy.c \
+ seqpdelete.c \
+ seqpgetfxmix.c \
+ seqpgetpan.c \
+ seqpgetchlvol.c \
+ seqpgetpriority.c \
+ seqpgetprogram.c \
+ seqpgetseq.c \
+ seqpgettempo.c \
+ seqpgetvol.c \
+ seqpgetstate.c \
+ seqploop.c \
+ seqpplay.c \
+ seqpsendmidi.c \
+ seqpsetbank.c \
+ seqpsetfxmix.c \
+ seqpsetpan.c \
+ seqpsetchlvol.c \
+ seqpsetpriority.c \
+ seqpsetprogram.c \
+ seqpsetseq.c \
+ seqpsettempo.c \
+ seqpsetvol.c \
+ seqpstop.c \
+ seqplayer.c \
+ cseq.c \
+ cspdelete.c \
+ cspgetfxmix.c \
+ cspgetpan.c \
+ cspgetchlvol.c \
+ cspgetpriority.c \
+ cspgetprogram.c \
+ cspgetseq.c \
+ cspgettempo.c \
+ cspgetvol.c \
+ cspgetstate.c \
+ cspplay.c \
+ cspsendmidi.c \
+ cspsetbank.c \
+ cspsetfxmix.c \
+ cspsetpan.c \
+ cspsetchlvol.c \
+ cspsetpriority.c \
+ cspsetprogram.c \
+ cspsetseq.c \
+ cspsettempo.c \
+ cspsetvol.c \
+ cspstop.c \
+ csplayer.c \
+ sndplayer.c \
+ sndpdelete.c \
+ sndpallocate.c \
+ sndpdeallocate.c \
+ sndpsetsound.c \
+ sndpplay.c \
+ sndpplayat.c \
+ sndpgetsound.c \
+ sndpstop.c \
+ sndpgetstate.c \
+ sndpsetpitch.c \
+ sndpsetpriority.c \
+ sndpsetvol.c \
+ sndpsetpan.c \
+ sndpsetfxmix.c \
+ synthesizer.c \
+ syndelete.c \
+ synaddplayer.c \
+ synremoveplayer.c \
+ synfreevoice.c \
+ synallocvoice.c \
+ synstopvoice.c \
+ synstartvoice.c \
+ synstartvoiceparam.c \
+ synsetpitch.c \
+ synsetvol.c \
+ synsetfxmix.c \
+ synsetpan.c \
+ syngetpriority.c \
+ synsetpriority.c \
+ synallocfx.c \
+ synfreefx.c \
+ syngetfxref.c \
+ synsetfxparam.c \
+ cents2ratio.c \
+ parse_abi.c
+
+TARGETS = $(CFILES:.c=.o)
+
+default : $(TARGETS)
+
+include $(COMMONRULES)
+
+
diff --git a/lib/ultralib/src/audio/auxbus.c b/lib/ultralib/src/audio/auxbus.c
new file mode 100644
index 0000000..471ba41
--- /dev/null
+++ b/lib/ultralib/src/audio/auxbus.c
@@ -0,0 +1,65 @@
+/*====================================================================
+ * auxbus.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+
+Acmd *alAuxBusPull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset,
+ Acmd *p)
+{
+ Acmd *ptr = p;
+ ALAuxBus *m = (ALAuxBus *)filter;
+ ALFilter **sources = m->sources;
+ s32 i;
+
+ /*
+ * clear the output buffers here
+ */
+ aClearBuffer(ptr++, AL_AUX_L_OUT, outCount<<1);
+ aClearBuffer(ptr++, AL_AUX_R_OUT, outCount<<1);
+
+ for (i = 0; i < m->sourceCount; i++) {
+ ptr = (sources[i]->handler)(sources[i], outp, outCount, sampleOffset,
+ ptr);
+ }
+
+ return ptr;
+}
+
+s32 alAuxBusParam(void *filter, s32 paramID, void *param)
+{
+ ALAuxBus *m = (ALAuxBus *) filter;
+ ALFilter **sources = m->sources;
+
+ switch (paramID) {
+
+ case (AL_FILTER_ADD_SOURCE):
+ sources[m->sourceCount++] = (ALFilter *) param;
+ break;
+
+ default:
+ /* ??? */
+ break;
+ }
+
+ return 0;
+
+}
+
diff --git a/lib/ultralib/src/audio/bnkf.c b/lib/ultralib/src/audio/bnkf.c
new file mode 100644
index 0000000..dfd312f
--- /dev/null
+++ b/lib/ultralib/src/audio/bnkf.c
@@ -0,0 +1,143 @@
+/*====================================================================
+ * bnkf.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+
+/*
+ * ### when the file format settles down a little, I'll remove these
+ * ### for efficiency.
+ */
+static void _bnkfPatchBank(ALBank *bank, s32 offset, s32 table);
+static void _bnkfPatchInst(ALInstrument *i, s32 offset, s32 table);
+static void _bnkfPatchSound(ALSound *s, s32 offset, s32 table);
+static void _bnkfPatchWaveTable(ALWaveTable *w, s32 offset, s32 table);
+
+void alSeqFileNew(ALSeqFile *file, u8 *base)
+{
+ s32 offset = (s32) base;
+ s32 i;
+
+ /*
+ * patch the file so that offsets are pointers
+ */
+ for (i = 0; i < file->seqCount; i++) {
+ file->seqArray[i].offset = (u8 *)((u8 *)file->seqArray[i].offset + offset);
+ }
+}
+
+void alBnkfNew(ALBankFile *file, u8 *table)
+{
+ s32 offset = (s32) file;
+ s32 woffset = (s32) table;
+
+ s32 i;
+
+ /*
+ * check the file format revision in debug libraries
+ */
+ ALFailIf(file->revision != AL_BANK_VERSION, ERR_ALBNKFNEW);
+
+ /*
+ * patch the file so that offsets are pointers
+ */
+ for (i = 0; i < file->bankCount; i++) {
+ file->bankArray[i] = (ALBank *)((u8 *)file->bankArray[i] + offset);
+ if(file->bankArray[i])
+ _bnkfPatchBank(file->bankArray[i], offset, woffset);
+ }
+}
+
+void _bnkfPatchBank(ALBank *bank, s32 offset, s32 table)
+{
+ s32 i;
+
+ if (bank->flags)
+ return;
+
+ bank->flags = 1;
+
+ if (bank->percussion) {
+ bank->percussion = (ALInstrument *)((u8 *)bank->percussion + offset);
+ _bnkfPatchInst(bank->percussion, offset, table);
+ }
+
+ for (i = 0; i < bank->instCount; i++) {
+ bank->instArray[i] = (ALInstrument *)((u8 *)bank->instArray[i] +
+ offset);
+ if(bank->instArray[i])
+ _bnkfPatchInst(bank->instArray[i], offset, table);
+ }
+}
+
+void _bnkfPatchInst(ALInstrument *inst, s32 offset, s32 table)
+{
+ s32 i;
+
+ if (inst->flags)
+ return;
+
+ inst->flags = 1;
+
+ for (i = 0; i < inst->soundCount; i++) {
+ inst->soundArray[i] = (ALSound *)((u8 *)inst->soundArray[i] +
+ offset);
+ _bnkfPatchSound(inst->soundArray[i], offset, table);
+
+ }
+}
+
+void _bnkfPatchSound(ALSound *s, s32 offset, s32 table)
+{
+ if (s->flags)
+ return;
+
+ s->flags = 1;
+
+ s->envelope = (ALEnvelope *)((u8 *)s->envelope + offset);
+ s->keyMap = (ALKeyMap *)((u8 *)s->keyMap + offset);
+
+ s->wavetable = (ALWaveTable *)((u8 *)s->wavetable + offset);
+ _bnkfPatchWaveTable(s->wavetable, offset, table);
+}
+
+void _bnkfPatchWaveTable(ALWaveTable *w, s32 offset, s32 table)
+{
+ if (w->flags)
+ return;
+
+ w->flags = 1;
+
+ w->base += table;
+
+ /* sct 2/14/96 - patch wavetable loop info based on type. */
+ if (w->type == AL_ADPCM_WAVE)
+ {
+ w->waveInfo.adpcmWave.book = (ALADPCMBook *)((u8 *)w->waveInfo.adpcmWave.book + offset);
+ if (w->waveInfo.adpcmWave.loop)
+ w->waveInfo.adpcmWave.loop = (ALADPCMloop *)((u8 *)w->waveInfo.adpcmWave.loop + offset);
+ }
+ else if (w->type == AL_RAW16_WAVE)
+ {
+ if (w->waveInfo.rawWave.loop)
+ w->waveInfo.rawWave.loop = (ALRawLoop *)((u8 *)w->waveInfo.rawWave.loop + offset);
+ }
+}
diff --git a/lib/ultralib/src/audio/cents2ratio.c b/lib/ultralib/src/audio/cents2ratio.c
new file mode 100644
index 0000000..55cd2a3
--- /dev/null
+++ b/lib/ultralib/src/audio/cents2ratio.c
@@ -0,0 +1,33 @@
+/*
+ * alCents2Ratio()
+ *
+ * Calculates the pitch shift ratio from the number of cents according to
+ * ratio = 2^(cents/1200)
+ *
+ * This is accurate to within one cent for ratios up and octave and down
+ * two ocataves.
+ */
+
+#include <libaudio.h>
+
+f32 alCents2Ratio(s32 cents)
+{
+ f32 x;
+ f32 ratio = 1.0f;
+
+ if (cents >= 0) {
+ x = 1.00057779f; /* 2^(1/1200) */
+ } else {
+ x = 0.9994225441f; /* 2^(-1/1200) */
+ cents = -cents;
+ }
+
+ while (cents) {
+ if (cents & 1)
+ ratio *= x;
+ x *= x;
+ cents >>= 1;
+ }
+
+ return ratio;
+}
diff --git a/lib/ultralib/src/audio/copy.c b/lib/ultralib/src/audio/copy.c
new file mode 100644
index 0000000..e80a8df
--- /dev/null
+++ b/lib/ultralib/src/audio/copy.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * copy.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCopy(void *src, void *dest, s32 len)
+{
+ s32 i;
+ u8 *s = (u8 *)src;
+ u8 *d = (u8 *)dest;
+
+ for (i = 0; i < len; i++){
+ *d++ = *s++;
+ }
+}
+
diff --git a/lib/ultralib/src/audio/cseq.c b/lib/ultralib/src/audio/cseq.c
new file mode 100644
index 0000000..9c4b8bd
--- /dev/null
+++ b/lib/ultralib/src/audio/cseq.c
@@ -0,0 +1,409 @@
+/*====================================================================
+ * cseq.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+#include "cseq.h"
+
+
+static u32 __readVarLen(ALCSeq *s,u32 track);
+static u8 __getTrackByte(ALCSeq *s,u32 track);
+static u32 __alCSeqGetTrackEvent(ALCSeq *seq, u32 track, ALEvent *event);
+
+void alCSeqNew(ALCSeq *seq, u8 *ptr)
+{
+ u32 i,tmpOff,flagTmp;
+
+ /* load the seqence pointed to by ptr */
+ seq->base = (ALCMidiHdr*)ptr;
+ seq->validTracks = 0;
+ seq->lastDeltaTicks = 0;
+ seq->lastTicks = 0;
+ seq->deltaFlag = 1;
+
+ for(i = 0; i < 16; i++)
+ {
+ seq->lastStatus[i] = 0;
+ seq->curBUPtr[i] = 0;
+ seq->curBULen[i] = 0;
+ tmpOff = seq->base->trackOffset[i];
+ if(tmpOff) /* if the track is valid */
+ {
+ flagTmp = 1 << i;
+ seq->validTracks |= flagTmp;
+ seq->curLoc[i] = (u8*)((u32)ptr + tmpOff);
+ seq->evtDeltaTicks[i] = __readVarLen(seq,i);
+ /*__alCSeqGetTrackEvent(seq,i); prime the event buffers */
+ }
+ else
+ seq->curLoc[i] = 0;
+ }
+
+ seq->qnpt = 1.0/(f32)seq->base->division;
+}
+
+void alCSeqNextEvent(ALCSeq *seq,ALEvent *evt)
+{
+ u32 i;
+ u32 firstTime = 0xFFFFFFFF;
+ u32 firstTrack;
+ u32 lastTicks = seq->lastDeltaTicks;
+
+#ifdef _DEBUG
+ /* sct 1/17/96 - Warn if we are beyond the end of sequence. */
+ if (!seq->validTracks)
+ __osError(ERR_ALSEQOVERRUN, 0);
+#endif
+
+
+ for(i = 0; i < 16 ; i++)
+ {
+ if((seq->validTracks >> i) & 1)
+ {
+ if(seq->deltaFlag)
+ seq->evtDeltaTicks[i] -= lastTicks;
+ if(seq->evtDeltaTicks[i] < firstTime)
+ {
+ firstTime = seq->evtDeltaTicks[i];
+ firstTrack = i;
+ }
+ }
+ }
+
+ __alCSeqGetTrackEvent(seq,firstTrack,evt);
+
+ evt->msg.midi.ticks = firstTime;
+ seq->lastTicks += firstTime;
+ seq->lastDeltaTicks = firstTime;
+ if(evt->type != AL_TRACK_END)
+ seq->evtDeltaTicks[firstTrack] += __readVarLen(seq,firstTrack);
+ seq->deltaFlag = 1;
+
+}
+
+
+/*
+ Note: If there are no valid tracks (ie. all tracks have
+ reached the end of their data stream), then return FALSE
+ to indicate that there is no next event.
+*/
+char __alCSeqNextDelta(ALCSeq *seq, s32 *pDeltaTicks)
+{
+ u32 i;
+ u32 firstTime = 0xFFFFFFFF;
+ u32 lastTicks = seq->lastDeltaTicks;
+
+ if (!seq->validTracks)
+ return FALSE;
+
+ for(i = 0; i < 16 ; i++)
+ {
+ if((seq->validTracks >> i) & 1)
+ {
+ if(seq->deltaFlag)
+ seq->evtDeltaTicks[i] -= lastTicks;
+
+ if(seq->evtDeltaTicks[i] < firstTime)
+ firstTime = seq->evtDeltaTicks[i];
+ }
+ }
+
+ seq->deltaFlag = 0;
+ *pDeltaTicks = firstTime;
+
+ return TRUE;
+}
+
+/* only call alCSeqGetTrackEvent with a valid track !! */
+static u32 __alCSeqGetTrackEvent(ALCSeq *seq, u32 track, ALEvent *event)
+{
+ u32 offset;
+ u8 status, loopCt, curLpCt, *tmpPtr;
+
+
+ status = __getTrackByte(seq,track); /* read the status byte */
+
+ if (status == AL_MIDI_Meta) /* running status not allowed on meta events!! */
+ {
+ u8 type = __getTrackByte(seq,track);
+
+ if (type == AL_MIDI_META_TEMPO)
+ {
+ event->type = AL_TEMPO_EVT;
+ event->msg.tempo.status = status;
+ event->msg.tempo.type = type;
+ event->msg.tempo.byte1 = __getTrackByte(seq,track);
+ event->msg.tempo.byte2 = __getTrackByte(seq,track);
+ event->msg.tempo.byte3 = __getTrackByte(seq,track);
+ seq->lastStatus[track] = 0; /* lastStatus not supported after meta */
+ }
+ else if (type == AL_MIDI_META_EOT)
+ {
+ u32 flagMask;
+
+ flagMask = 0x01 << track;
+ seq->validTracks = seq->validTracks ^ flagMask;
+
+ if(seq->validTracks) /* there is music left don't end */
+ event->type = AL_TRACK_END;
+ else /* no more music send AL_SEQ_END_EVT msg */
+ event->type = AL_SEQ_END_EVT;
+ }
+ else if (type == AL_CMIDI_LOOPSTART_CODE)
+ {
+ status = __getTrackByte(seq,track); /* get next two bytes, ignore them */
+ status = __getTrackByte(seq,track);
+ seq->lastStatus[track] = 0;
+ event->type = AL_CSP_LOOPSTART;
+ }
+ else if (type == AL_CMIDI_LOOPEND_CODE)
+ {
+ tmpPtr = seq->curLoc[track];
+ loopCt = *tmpPtr++;
+ curLpCt = *tmpPtr;
+ if(curLpCt == 0) /* done looping */
+ {
+ *tmpPtr = loopCt; /* reset current loop count */
+ seq->curLoc[track] = tmpPtr + 5; /* move pointer to end of event */
+ }
+ else
+ {
+ if(curLpCt != 0xFF) /* not a loop forever */
+ *tmpPtr = curLpCt - 1; /* decrement current loop count */
+ tmpPtr++; /* get offset from end of event */
+ offset = (*tmpPtr++) << 24;
+ offset += (*tmpPtr++) << 16;
+ offset += (*tmpPtr++) << 8;
+ offset += *tmpPtr++;
+ seq->curLoc[track] = tmpPtr - offset;
+ }
+ seq->lastStatus[track] = 0;
+ event->type = AL_CSP_LOOPEND;
+ }
+
+#ifdef _DEBUG
+ else
+ __osError(ERR_ALSEQMETA, 1, type);
+#endif
+
+ }
+ else
+ {
+ event->type = AL_SEQ_MIDI_EVT;
+ if (status & 0x80) /* if high bit is set, then new status */
+ {
+ event->msg.midi.status = status;
+ event->msg.midi.byte1 = __getTrackByte(seq,track);
+ seq->lastStatus[track] = status;
+ }
+ else /* running status */
+ {
+#ifdef _DEBUG
+ if(seq->lastStatus[track] == 0)
+ __osError(ERR_ALCSEQZEROSTATUS, 1, track);
+#endif
+ event->msg.midi.status = seq->lastStatus[track];
+ event->msg.midi.byte1 = status;
+ }
+
+ if (((event->msg.midi.status & 0xf0) != AL_MIDI_ProgramChange) &&
+ ((event->msg.midi.status & 0xf0) != AL_MIDI_ChannelPressure))
+ {
+ event->msg.midi.byte2 = __getTrackByte(seq,track);
+ if((event->msg.midi.status & 0xf0) == AL_MIDI_NoteOn)
+ {
+ event->msg.midi.duration = __readVarLen(seq,track);
+#ifdef _DEBUG
+ if(event->msg.midi.byte2 == 0)
+ __osError( ERR_ALCSEQZEROVEL, 1, track);
+#endif
+ }
+ }
+ else
+ event->msg.midi.byte2 = 0;
+ }
+ return TRUE;
+}
+
+f32 alCSeqTicksToSec(ALCSeq *seq, s32 ticks, u32 tempo)
+{
+ return ((f32) (((f32)(ticks) * (f32)(tempo)) /
+ ((f32)(seq->base->division) * 1000000.0)));
+}
+
+u32 alCSeqSecToTicks(ALCSeq *seq, f32 sec, u32 tempo)
+{
+ return (u32)(((sec * 1000000.0) * seq->base->division) / tempo);
+}
+
+
+s32 alCSeqGetTicks(ALCSeq *seq)
+{
+ return seq->lastTicks;
+}
+
+
+void alCSeqNewMarker(ALCSeq *seq, ALCSeqMarker *m, u32 ticks)
+{
+ ALEvent evt;
+ ALCSeq tempSeq;
+ s32 i;
+
+
+ alCSeqNew(&tempSeq, (u8*)seq->base);
+
+ do {
+ m->validTracks = tempSeq.validTracks;
+ m->lastTicks = tempSeq.lastTicks;
+ m->lastDeltaTicks = tempSeq.lastDeltaTicks;
+
+ for(i=0;i<16;i++)
+ {
+ m->curLoc[i] = tempSeq.curLoc[i];
+ m->curBUPtr[i] = tempSeq.curBUPtr[i];
+ m->curBULen[i] = tempSeq.curBULen[i];
+ m->lastStatus[i] = tempSeq.lastStatus[i];
+ m->evtDeltaTicks[i] = tempSeq.evtDeltaTicks[i];
+ }
+
+ alCSeqNextEvent(&tempSeq, &evt);
+
+ if (evt.type == AL_SEQ_END_EVT)
+ break;
+
+ } while (tempSeq.lastTicks < ticks);
+
+}
+
+void alCSeqSetLoc(ALCSeq *seq, ALCSeqMarker *m)
+{
+ s32 i;
+
+ seq->validTracks = m->validTracks;
+ seq->lastTicks = m->lastTicks;
+ seq->lastDeltaTicks = m->lastDeltaTicks;
+
+ for(i=0;i<16;i++)
+ {
+ seq->curLoc[i] = m->curLoc[i];
+ seq->curBUPtr[i] = m->curBUPtr[i];
+ seq->curBULen[i] = m->curBULen[i];
+ seq->lastStatus[i] = m->lastStatus[i];
+ seq->evtDeltaTicks[i] = m->evtDeltaTicks[i];
+ }
+}
+
+void alCSeqGetLoc(ALCSeq *seq, ALCSeqMarker *m)
+{
+ s32 i;
+
+ m->validTracks = seq->validTracks;
+ m->lastTicks = seq->lastTicks;
+ m->lastDeltaTicks = seq->lastDeltaTicks;
+
+ for(i=0;i<16;i++)
+ {
+ m->curLoc[i] = seq->curLoc[i];
+ m->curBUPtr[i] = seq->curBUPtr[i];
+ m->curBULen[i] = seq->curBULen[i];
+ m->lastStatus[i] = seq->lastStatus[i];
+ m->evtDeltaTicks[i] = seq->evtDeltaTicks[i];
+ }
+}
+
+/* non-aligned byte reading routines */
+static u8 __getTrackByte(ALCSeq *seq,u32 track)
+{
+ u8 theByte;
+
+
+ if(seq->curBULen[track])
+ {
+ theByte = *seq->curBUPtr[track];
+ seq->curBUPtr[track]++;
+ seq->curBULen[track]--;
+ }
+ else /* need to handle backup mode */
+ {
+ theByte = *seq->curLoc[track];
+ seq->curLoc[track]++;
+ if(theByte == AL_CMIDI_BLOCK_CODE)
+ {
+ u8 loBackUp,hiBackUp,theLen,nextByte;
+ u32 backup;
+
+ nextByte = *seq->curLoc[track];
+ seq->curLoc[track]++;
+ if(nextByte != AL_CMIDI_BLOCK_CODE)
+ {
+ /* if here, then got a backup section. get the amount of
+ backup, and the len of the section. Subtract the amount of
+ backup from the curLoc ptr, and subtract four more, since
+ curLoc has been advanced by four while reading the codes. */
+ hiBackUp = nextByte;
+ loBackUp = *seq->curLoc[track];
+ seq->curLoc[track]++;
+ theLen = *seq->curLoc[track];
+ seq->curLoc[track]++;
+ backup = (u32)hiBackUp;
+ backup = backup << 8;
+ backup += loBackUp;
+ seq->curBUPtr[track] = seq->curLoc[track] - (backup + 4);
+ seq->curBULen[track] = (u32)theLen;
+
+ /* now get the byte */
+ theByte = *seq->curBUPtr[track];
+ seq->curBUPtr[track]++;
+ seq->curBULen[track]--;
+ }
+ }
+ }
+
+ return theByte;
+}
+
+static u32 __readVarLen(ALCSeq *seq,u32 track)
+{
+ u32 value;
+ u32 c;
+
+ value = (u32)__getTrackByte(seq,track);
+ if ( value & 0x00000080 )
+ {
+ value &= 0x7f;
+ do
+ {
+ c = (u32)__getTrackByte(seq,track);
+ value = (value << 7) + (c & 0x7f);
+ } while (c & 0x80);
+ }
+ return (value);
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ultralib/src/audio/cseq.h b/lib/ultralib/src/audio/cseq.h
new file mode 100644
index 0000000..0342398
--- /dev/null
+++ b/lib/ultralib/src/audio/cseq.h
@@ -0,0 +1,11 @@
+
+
+
+#ifndef __cseq__
+#define __cseq__
+
+
+char __alCSeqNextDelta(ALCSeq *seq, s32 *pDeltaTicks);
+
+
+#endif /* __cseq__ */
diff --git a/lib/ultralib/src/audio/cseqp.h b/lib/ultralib/src/audio/cseqp.h
new file mode 100644
index 0000000..bb72541
--- /dev/null
+++ b/lib/ultralib/src/audio/cseqp.h
@@ -0,0 +1,10 @@
+
+
+#ifndef __cseqp__
+#define __cseqp__
+
+
+void __CSPPostNextSeqEvent(ALCSPlayer *seqp);
+
+
+#endif /* __cseqp__ */
diff --git a/lib/ultralib/src/audio/cspdelete.c b/lib/ultralib/src/audio/cspdelete.c
new file mode 100644
index 0000000..063c543
--- /dev/null
+++ b/lib/ultralib/src/audio/cspdelete.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * cspdelete.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPDelete(ALCSPlayer *seqp)
+{
+ alSynRemovePlayer(seqp->drvr, &seqp->node);
+}
+
diff --git a/lib/ultralib/src/audio/cspgetchlvol.c b/lib/ultralib/src/audio/cspgetchlvol.c
new file mode 100644
index 0000000..23d256e
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetchlvol.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * cspgetchlvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+u8 alCSPGetChlVol(ALCSPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].vol;
+}
+
diff --git a/lib/ultralib/src/audio/cspgetfxmix.c b/lib/ultralib/src/audio/cspgetfxmix.c
new file mode 100644
index 0000000..c67e033
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetfxmix.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * cspgetfxmix.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+u8 alCSPGetChlFXMix(ALCSPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].fxmix;
+}
+
diff --git a/lib/ultralib/src/audio/cspgetpan.c b/lib/ultralib/src/audio/cspgetpan.c
new file mode 100644
index 0000000..5c0e322
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetpan.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * cspgetpan.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+ALPan alCSPGetChlPan(ALCSPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].pan;
+}
+
diff --git a/lib/ultralib/src/audio/cspgetpriority.c b/lib/ultralib/src/audio/cspgetpriority.c
new file mode 100644
index 0000000..ac38cae
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetpriority.c
@@ -0,0 +1,26 @@
+/*====================================================================
+ * cspgetpriority.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+u8 alCSPGetChlPriority(ALCSPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].priority;
+}
diff --git a/lib/ultralib/src/audio/cspgetprogram.c b/lib/ultralib/src/audio/cspgetprogram.c
new file mode 100644
index 0000000..382616f
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetprogram.c
@@ -0,0 +1,42 @@
+/*====================================================================
+ * cspgetprogram.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s32 alCSPGetChlProgram(ALCSPlayer *seqp, u8 chan)
+
+{
+ s32 i;
+ ALBank *b = seqp->bank;
+ ALInstrument *inst;
+ ALChanState s;
+
+ s = seqp->chanState[chan];
+ for (i=0; i<b->instCount; i++){
+ inst = b->instArray[i];
+ if (inst == s.instrument)
+ return i;
+ }
+ return(-1);
+
+}
+
diff --git a/lib/ultralib/src/audio/cspgetseq.c b/lib/ultralib/src/audio/cspgetseq.c
new file mode 100644
index 0000000..85d2545
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetseq.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * cspgetseq.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+ALCSeq *alCSPGetSeq(ALCSPlayer *seqp)
+{
+ return seqp->target;
+}
+
diff --git a/lib/ultralib/src/audio/cspgetstate.c b/lib/ultralib/src/audio/cspgetstate.c
new file mode 100644
index 0000000..9be7937
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetstate.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * cspgetstate.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s32 alCSPGetState(ALCSPlayer *seqp)
+{
+ return seqp->state;
+}
+
diff --git a/lib/ultralib/src/audio/cspgettempo.c b/lib/ultralib/src/audio/cspgettempo.c
new file mode 100644
index 0000000..ed3dfe2
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgettempo.c
@@ -0,0 +1,31 @@
+/*====================================================================
+ * cspgettempo.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s32 alCSPGetTempo(ALCSPlayer *seqp)
+{
+ /* sct 1/8/96 - If no target sequence has been set, just return zero (instead of crashing). */
+ if (seqp->target == NULL)
+ return 0;
+
+ return seqp->uspt/seqp->target->qnpt;
+}
+
diff --git a/lib/ultralib/src/audio/cspgetvol.c b/lib/ultralib/src/audio/cspgetvol.c
new file mode 100644
index 0000000..5353228
--- /dev/null
+++ b/lib/ultralib/src/audio/cspgetvol.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * cspgetvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s16 alCSPGetVol(ALCSPlayer *seqp)
+{
+ return seqp->vol;
+}
+
diff --git a/lib/ultralib/src/audio/csplayer.c b/lib/ultralib/src/audio/csplayer.c
new file mode 100644
index 0000000..621ce02
--- /dev/null
+++ b/lib/ultralib/src/audio/csplayer.c
@@ -0,0 +1,886 @@
+/*====================================================================
+ * csplayer.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+/*
+ * Notes:
+ *
+ * Controller Numbers:
+ * 1 Modulation
+ * 7 Volume
+ * 10 Pan
+ * 11 Expression
+ * 64 Sustain
+ * 121 Reset All Controllers
+ * 123 All Notes Off
+ *
+ * Registered Parameters
+ * 0 Pitch Bend Sensitivity
+ * 1 Fine Tuning
+ * 2 Coarse Tuning
+ */
+
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+#include <assert.h>
+#include "seqp.h"
+#include "cseqp.h"
+#include "cseq.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+
+static ALMicroTime __CSPVoiceHandler(void *node);
+static void __CSPHandleNextSeqEvent(ALCSPlayer *seqp);
+static void __CSPHandleMIDIMsg(ALCSPlayer *seqp, ALEvent *event);
+static void __CSPHandleMetaMsg(ALCSPlayer *seqp, ALEvent *event);
+static void __CSPRepostEvent(ALEventQueue *evtq, ALEventListItem *item);
+static void __setUsptFromTempo(ALCSPlayer *seqp, f32 tempo); /* sct 1/8/96 */
+
+
+/*
+ * Sequence Player public functions
+ */
+void alCSPNew(ALCSPlayer *seqp, ALSeqpConfig *c)
+{
+ s32 i;
+ ALEventListItem *items;
+ ALVoiceState *vs;
+ ALVoiceState *voices;
+
+ ALHeap *hp = c->heap;
+
+ /*
+ * initialize member variables
+ */
+ seqp->bank = 0;
+ seqp->target = NULL;
+ seqp->drvr = &alGlobals->drvr;
+ seqp->chanMask = 0xff;
+ seqp->uspt = 488;
+ seqp->nextDelta = 0;
+ seqp->state = AL_STOPPED;
+ seqp->vol = 0x7FFF; /* full volume */
+ seqp->frameTime = AL_USEC_PER_FRAME; /* should get this from driver */
+ seqp->curTime = 0;
+ seqp->initOsc = c->initOsc;
+ seqp->updateOsc = c->updateOsc;
+ seqp->stopOsc = c->stopOsc;
+
+ seqp->nextEvent.type = AL_SEQP_API_EVT; /* this will start the voice handler "spinning" */
+
+ /*
+ * init the channel state
+ */
+ seqp->maxChannels = c->maxChannels;
+ seqp->chanState = alHeapAlloc(hp, c->maxChannels, sizeof(ALChanState) );
+ __initChanState((ALSeqPlayer*)seqp); /* sct 11/6/95 */
+
+ /*
+ * init the voice state array
+ */
+ voices = alHeapAlloc(hp, c->maxVoices, sizeof(ALVoiceState));
+ seqp->vFreeList = 0;
+ for (i = 0; i < c->maxVoices; i++) {
+ vs = &voices[i];
+ vs->next = seqp->vFreeList;
+ seqp->vFreeList = vs;
+ }
+
+ seqp->vAllocHead = 0;
+ seqp->vAllocTail = 0;
+
+ /*
+ * init the event queue
+ */
+ items = alHeapAlloc(hp, c->maxEvents, sizeof(ALEventListItem));
+ alEvtqNew(&seqp->evtq, items, c->maxEvents);
+
+
+ /*
+ * add ourselves to the driver
+ */
+ seqp->node.next = NULL;
+ seqp->node.handler = __CSPVoiceHandler;
+ seqp->node.clientData = seqp;
+ alSynAddPlayer(&alGlobals->drvr, &seqp->node);
+}
+
+/*************************************************************
+ * private routines or driver callback routines
+ *************************************************************/
+static ALMicroTime __CSPVoiceHandler(void *node)
+{
+ ALCSPlayer *seqp = (ALCSPlayer *) node;
+ ALEvent evt;
+ ALVoice *voice;
+ ALMicroTime delta;
+ ALVoiceState *vs;
+ void *oscState;
+ f32 oscValue;
+ u8 chan;
+
+ do {
+ switch (seqp->nextEvent.type)
+ {
+ case (AL_SEQ_REF_EVT):
+ __CSPHandleNextSeqEvent(seqp);
+ break;
+
+ case (AL_SEQP_API_EVT):
+ evt.type = AL_SEQP_API_EVT;
+ alEvtqPostEvent(&seqp->evtq, (ALEvent *)&evt, seqp->frameTime);
+ break;
+
+ case (AL_NOTE_END_EVT):
+ voice = seqp->nextEvent.msg.note.voice;
+
+ alSynStopVoice(seqp->drvr, voice);
+ alSynFreeVoice(seqp->drvr, voice);
+ vs = (ALVoiceState *)voice->clientPrivate;
+ if(vs->flags)
+ __seqpStopOsc((ALSeqPlayer*)seqp,vs);
+ __unmapVoice((ALSeqPlayer*)seqp, voice);
+ break;
+
+ case (AL_SEQP_ENV_EVT):
+ voice = seqp->nextEvent.msg.vol.voice;
+ vs = (ALVoiceState *)voice->clientPrivate;
+
+ if(vs->envPhase == AL_PHASE_ATTACK)
+ vs->envPhase = AL_PHASE_DECAY;
+
+ delta = seqp->nextEvent.msg.vol.delta;
+ vs->envEndTime = seqp->curTime + delta;
+ vs->envGain = seqp->nextEvent.msg.vol.vol;
+ alSynSetVol(seqp->drvr, voice, __vsVol(vs, (ALSeqPlayer*)seqp), delta);
+ break;
+
+ case (AL_TREM_OSC_EVT):
+ vs = seqp->nextEvent.msg.osc.vs;
+ oscState = seqp->nextEvent.msg.osc.oscState;
+ delta = (*seqp->updateOsc)(oscState,&oscValue);
+ vs->tremelo = (u8)oscValue;
+ alSynSetVol(seqp->drvr, &vs->voice, __vsVol(vs,(ALSeqPlayer*)seqp),
+ __vsDelta(vs,seqp->curTime));
+ evt.type = AL_TREM_OSC_EVT;
+ evt.msg.osc.vs = vs;
+ evt.msg.osc.oscState = oscState;
+ alEvtqPostEvent(&seqp->evtq, &evt, delta);
+ break;
+
+ case (AL_VIB_OSC_EVT):
+ vs = seqp->nextEvent.msg.osc.vs;
+ oscState = seqp->nextEvent.msg.osc.oscState;
+ chan = seqp->nextEvent.msg.osc.chan;
+ delta = (*seqp->updateOsc)(oscState,&oscValue);
+ vs->vibrato = oscValue;
+ alSynSetPitch(seqp->drvr, &vs->voice, vs->pitch * vs->vibrato
+ * seqp->chanState[chan].pitchBend);
+ evt.type = AL_VIB_OSC_EVT;
+ evt.msg.osc.vs = vs;
+ evt.msg.osc.oscState = oscState;
+ evt.msg.osc.chan = chan;
+ alEvtqPostEvent(&seqp->evtq, &evt, delta);
+ break;
+
+ case (AL_SEQP_MIDI_EVT):
+ case (AL_CSP_NOTEOFF_EVT): /* nextEvent is a note off midi message */
+ __CSPHandleMIDIMsg(seqp, &seqp->nextEvent);
+ break;
+
+ case (AL_SEQP_META_EVT):
+ __CSPHandleMetaMsg(seqp, &seqp->nextEvent);
+ break;
+
+ case (AL_SEQP_VOL_EVT):
+ seqp->vol = seqp->nextEvent.msg.spvol.vol;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ alSynSetVol(seqp->drvr, &vs->voice,
+ __vsVol(vs, (ALSeqPlayer*)seqp),
+ __vsDelta(vs, seqp->curTime));
+ }
+ break;
+
+ case (AL_SEQP_PLAY_EVT):
+ if (seqp->state != AL_PLAYING)
+ {
+ seqp->state = AL_PLAYING;
+ __CSPPostNextSeqEvent(seqp); /* seqp must be AL_PLAYING before we call this routine. */
+ }
+ break;
+
+ case (AL_SEQP_STOP_EVT):
+ if ( seqp->state == AL_STOPPING )
+ {
+ for (vs = seqp->vAllocHead; vs != 0; vs = seqp->vAllocHead)
+ {
+#ifdef _DEBUG
+ __osError(ERR_ALCSPVNOTFREE, 2, vs->channel, vs->key);
+#endif
+ alSynStopVoice(seqp->drvr, &vs->voice);
+ alSynFreeVoice(seqp->drvr, &vs->voice);
+ if(vs->flags)
+ __seqpStopOsc((ALSeqPlayer*)seqp,vs);
+ __unmapVoice((ALSeqPlayer*)seqp, &vs->voice);
+ }
+ seqp->state = AL_STOPPED;
+
+ /* alEvtqFlush(&seqp->evtq); - Don't flush event queue
+ anymore. */
+ /* sct 1/3/96 - Don't overwrite nextEvent with
+ AL_SEQP_API_EVT or set nextDelta to
+ AL_USEC_PER_FRAME since we're not stopping event
+ processing. */
+ /* sct 1/3/96 - Don't return here since we keep
+ processing events as usual. */
+ }
+ break;
+
+ case (AL_SEQP_STOPPING_EVT):
+ if (seqp->state == AL_PLAYING)
+ {
+ /* sct 12/29/95 - Remove events associated with the
+ * stopping sequence. For compact sequence player,
+ * also remove all queued note off events since they
+ * are not contained in a compact sequence but are
+ * generated in response to note ons. Note that
+ * flushing AL_SEQP_MIDI_EVTs may flush events that
+ * were posted after the call to alSeqpStop, so the
+ * application must queue these events either when
+ * the player is fully stopped, or when it is
+ * playing. */
+ alEvtqFlushType(&seqp->evtq, AL_SEQ_REF_EVT);
+ alEvtqFlushType(&seqp->evtq, AL_CSP_NOTEOFF_EVT);
+ alEvtqFlushType(&seqp->evtq, AL_SEQP_MIDI_EVT);
+
+ /* sct 1/3/96 - Check to see which voices need to be
+ killed and release them. */
+ /* Unkilled voices should have note end events
+ occurring prior to KILL_TIME. */
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ if (__voiceNeedsNoteKill ((ALSeqPlayer*)seqp, &vs->voice, KILL_TIME))
+ __seqpReleaseVoice((ALSeqPlayer*)seqp, &vs->voice, KILL_TIME);
+ }
+
+ seqp->state = AL_STOPPING;
+ evt.type = AL_SEQP_STOP_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END);
+ }
+ break;
+
+ case (AL_SEQP_PRIORITY_EVT):
+ chan = seqp->nextEvent.msg.sppriority.chan;
+ seqp->chanState[chan].priority = seqp->nextEvent.msg.sppriority.priority;
+ break;
+
+ case (AL_SEQP_SEQ_EVT):
+
+#ifdef _DEBUG
+ assert(seqp->state != AL_PLAYING); /* Must be done playing to change sequences. */
+#endif
+
+ seqp->target = seqp->nextEvent.msg.spseq.seq;
+ __setUsptFromTempo (seqp, 500000.0);
+ if (seqp->bank)
+ __initFromBank((ALSeqPlayer *)seqp, seqp->bank);
+ break;
+
+ case (AL_SEQP_BANK_EVT):
+
+#ifdef _DEBUG
+ assert(seqp->state == AL_STOPPED); /* Must be fully stopped to change banks. */
+#endif
+
+ seqp->bank = seqp->nextEvent.msg.spbank.bank;
+ __initFromBank((ALSeqPlayer *)seqp, seqp->bank);
+ break;
+
+ /* sct 11/6/95 - these events should now be handled by __CSPHandleNextSeqEvent */
+ case (AL_SEQ_END_EVT):
+ case (AL_TEMPO_EVT):
+ case (AL_SEQ_MIDI_EVT):
+
+#ifdef _DEBUG
+ assert(FALSE);
+#endif
+
+ break;
+ }
+ seqp->nextDelta = alEvtqNextEvent(&seqp->evtq, &seqp->nextEvent);
+
+ } while (seqp->nextDelta == 0);
+
+ /*
+ * assume that next callback won't be more than half an
+ * hour away
+ */
+ seqp->curTime += seqp->nextDelta; /* sct 11/7/95 */
+ return seqp->nextDelta;
+}
+
+/*
+ Calculates the delta time in ticks until the next sequence
+ event and posts a sequence reference event with the time in usecs.
+ Loops are handled automatically by the compact sequence.
+
+ Does nothing if the sequence player is not playing or if there
+ is no target sequence.
+
+ sct 11/7/95
+*/
+void __CSPPostNextSeqEvent(ALCSPlayer *seqp)
+{
+ ALEvent evt;
+ s32 deltaTicks;
+
+ if (seqp->state != AL_PLAYING || seqp->target == NULL)
+ return;
+
+ /* Get the next event time in ticks. */
+ /* If false is returned, then there is no next delta (ie. end of sequence reached). */
+ if (!__alCSeqNextDelta(seqp->target, &deltaTicks))
+ return;
+
+ evt.type = AL_SEQ_REF_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTicks * seqp->uspt);
+}
+
+
+/*
+ Call this routine to handle the next event in the sequence.
+ Assumes that the next sequence event is scheduled to be processed
+ immediately since it does not check the event's tick time.
+
+ sct 11/7/95
+*/
+static void
+__CSPHandleNextSeqEvent(ALCSPlayer *seqp)
+{
+ ALEvent evt;
+
+ /* sct 1/5/96 - Do nothing if we don't have a target sequence. */
+ if (seqp->target == NULL)
+ return;
+
+ alCSeqNextEvent(seqp->target, &evt);
+
+ switch (evt.type)
+ {
+ case AL_SEQ_MIDI_EVT:
+ __CSPHandleMIDIMsg(seqp, &evt);
+ __CSPPostNextSeqEvent(seqp);
+ break;
+
+ case AL_TEMPO_EVT:
+ __CSPHandleMetaMsg(seqp, &evt);
+ __CSPPostNextSeqEvent(seqp);
+ break;
+
+ case AL_SEQ_END_EVT:
+ seqp->state = AL_STOPPING;
+ evt.type = AL_SEQP_STOP_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END);
+ break;
+
+ case AL_TRACK_END:
+ case AL_CSP_LOOPSTART:
+ case AL_CSP_LOOPEND:
+ __CSPPostNextSeqEvent(seqp);
+ break;
+
+ default:
+
+#ifdef _DEBUG
+ assert(FALSE); /* Sequence event type not supported. */
+#endif
+
+ break;
+ }
+}
+
+
+static void __CSPHandleMIDIMsg(ALCSPlayer *seqp, ALEvent *event)
+{
+ ALVoice *voice;
+ ALVoiceState *vs;
+ s32 status;
+ u8 chan;
+ u8 key;
+ u8 vel;
+ u8 byte1;
+ u8 byte2;
+ ALMIDIEvent *midi = &event->msg.midi;
+ s16 vol;
+ ALEvent evt;
+ ALMicroTime deltaTime;
+ ALVoiceState *vstate;
+ ALPan pan;
+ ALFxRef fxref;
+
+
+ status = midi->status & AL_MIDI_StatusMask;
+ chan = midi->status & AL_MIDI_ChannelMask;
+ byte1 = key = midi->byte1;
+ byte2 = vel = midi->byte2;
+
+ switch (status)
+ {
+ case (AL_MIDI_NoteOn):
+
+ if (vel != 0) /* a real note on */
+ {
+ ALVoiceConfig config;
+ ALSound *sound;
+ s16 cents;
+ f32 pitch,oscValue;
+ u8 fxmix;
+ void *oscState;
+ ALInstrument *inst;
+
+ /* If we're not playing, don't process note ons. */
+ if (seqp->state != AL_PLAYING)
+ break;
+
+ sound = __lookupSoundQuick((ALSeqPlayer*)seqp, key, vel, chan);
+ ALFlagFailIf(!sound, seqp->debugFlags & NO_SOUND_ERR_MASK,
+ ERR_ALSEQP_NO_SOUND);
+
+ config.priority = seqp->chanState[chan].priority;
+ config.fxBus = 0;
+ config.unityPitch = 0;
+
+ vstate = __mapVoice((ALSeqPlayer*)seqp, key, vel, chan);
+ ALFlagFailIf(!vstate, seqp->debugFlags & NO_VOICE_ERR_MASK,
+ ERR_ALSEQP_NO_VOICE );
+
+ voice = &vstate->voice;
+
+ alSynAllocVoice(seqp->drvr, voice, &config);
+
+ /*
+ * set up the voice state structure
+ */
+ vstate->sound = sound;
+ vstate->envPhase = AL_PHASE_ATTACK;
+ if (seqp->chanState[chan].sustain > AL_SUSTAIN)
+ vstate->phase = AL_PHASE_SUSTAIN;
+ else
+ vstate->phase = AL_PHASE_NOTEON;
+
+ cents = (key - sound->keyMap->keyBase) * 100
+ + sound->keyMap->detune;
+
+ vstate->pitch = alCents2Ratio(cents);
+ vstate->envGain = sound->envelope->attackVolume;
+ vstate->envEndTime = seqp->curTime +
+ sound->envelope->attackTime;
+
+ /*
+ * setup tremelo and vibrato if active
+ */
+ vstate->flags = 0;
+ inst = seqp->chanState[chan].instrument;
+
+ oscValue = (f32)AL_VOL_FULL; /* set this as a default */
+ if(inst->tremType)
+ {
+ if(seqp->initOsc)
+ {
+ deltaTime = (*seqp->initOsc)(&oscState,&oscValue,inst->tremType,
+ inst->tremRate,inst->tremDepth,inst->tremDelay);
+
+ if(deltaTime) /* a deltaTime of zero means don't run osc */
+ {
+ evt.type = AL_TREM_OSC_EVT;
+ evt.msg.osc.vs = vstate;
+ evt.msg.osc.oscState = oscState;
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+ vstate->flags |= 0x01; /* set tremelo flag bit */
+ }
+ }
+ }
+ vstate->tremelo = (u8)oscValue; /* will default if not changed by initOsc */
+
+ oscValue = 1.0f; /* set this as a default */
+ if(inst->vibType)
+ {
+ if(seqp->initOsc)
+ {
+ deltaTime = (*seqp->initOsc)(&oscState,&oscValue,inst->vibType,
+ inst->vibRate,inst->vibDepth,inst->vibDelay);
+
+ if(deltaTime) /* a deltaTime of zero means don't run osc. */
+ {
+ evt.type = AL_VIB_OSC_EVT;
+ evt.msg.osc.vs = vstate;
+ evt.msg.osc.oscState = oscState;
+ evt.msg.osc.chan = chan;
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+ vstate->flags |= 0x02; /* set the vibrato flag bit */
+ }
+ }
+ }
+ vstate->vibrato = oscValue; /* will default if not changed by initOsc */
+
+ /*
+ * calculate the note on parameters
+ */
+ pitch = vstate->pitch * seqp->chanState[chan].pitchBend *
+ vstate->vibrato;
+ fxmix = seqp->chanState[chan].fxmix;
+ pan = __vsPan(vstate, (ALSeqPlayer*)seqp);
+ vol = __vsVol(vstate, (ALSeqPlayer*)seqp);
+ deltaTime = sound->envelope->attackTime;
+
+ alSynStartVoiceParams(seqp->drvr, voice, sound->wavetable,
+ pitch, vol, pan, fxmix, deltaTime);
+ /*
+ * set up callbacks for envelope
+ */
+ evt.type = AL_SEQP_ENV_EVT;
+ evt.msg.vol.voice = voice;
+ evt.msg.vol.vol = sound->envelope->decayVolume;
+ evt.msg.vol.delta = sound->envelope->decayTime;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+
+ if(midi->duration)
+ {
+ /*
+ * set up note off evt. if no duration don't do this
+ */
+ evt.type = AL_CSP_NOTEOFF_EVT;
+ evt.msg.midi.status = chan | AL_MIDI_NoteOff;
+ evt.msg.midi.byte1 = key;
+ evt.msg.midi.byte2 = 0; /* not needed ? */
+ deltaTime = seqp->uspt * midi->duration;
+
+ /* max time would be about one hour ten minutes */
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+ }
+
+ break;
+ }
+
+ /*
+ * NOTE: intentional fall-through for note on with zero
+ * velocity (Should never happen with compact midi sequence,
+ * but could happen with real time midi.)
+ */
+
+ case (AL_MIDI_NoteOff):
+ vstate = __lookupVoice((ALSeqPlayer*)seqp, key, chan);
+ ALFlagFailIf(!vstate, seqp->debugFlags & NOTE_OFF_ERR_MASK,
+ ERR_ALSEQP_OFF_VOICE );
+
+ if (vstate->phase == AL_PHASE_SUSTAIN)
+ vstate->phase = AL_PHASE_SUSTREL;
+ else
+ {
+ vstate->phase = AL_PHASE_RELEASE;
+ __seqpReleaseVoice((ALSeqPlayer*)seqp, &vstate->voice,
+ vstate->sound->envelope->releaseTime);
+ }
+
+ break;
+
+ case (AL_MIDI_PolyKeyPressure):
+ /*
+ * Aftertouch per key (hardwired to volume). Note that
+ * aftertouch affects only notes that are already
+ * sounding.
+ */
+ vstate = __lookupVoice((ALSeqPlayer*)seqp, key, chan);
+ ALFailIf(!vstate, ERR_ALSEQP_POLY_VOICE );
+
+ vstate->velocity = byte2;
+ alSynSetVol(seqp->drvr, &vstate->voice,
+ __vsVol(vstate, (ALSeqPlayer*)seqp),
+ __vsDelta(vstate,seqp->curTime));
+ break;
+
+ case (AL_MIDI_ChannelPressure):
+ /*
+ * Aftertouch per channel (hardwired to volume). Note that
+ * aftertouch affects only notes that are already
+ * sounding.
+ */
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if (vs->channel == chan) {
+ vs->velocity = byte1;
+ alSynSetVol(seqp->drvr, &vs->voice,
+ __vsVol(vs, (ALSeqPlayer*)seqp),
+ __vsDelta(vs,seqp->curTime));
+ }
+ }
+ break;
+
+ case (AL_MIDI_ControlChange):
+ switch (byte1)
+ {
+ case (AL_MIDI_PAN_CTRL):
+ seqp->chanState[chan].pan = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ if (vs->channel == chan)
+ {
+ pan = __vsPan(vs, (ALSeqPlayer*)seqp);
+ alSynSetPan(seqp->drvr, &vs->voice, pan);
+ }
+ }
+ break;
+ case (AL_MIDI_VOLUME_CTRL):
+ seqp->chanState[chan].vol = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ if ((vs->channel == chan) && (vs->envPhase != AL_PHASE_RELEASE))
+ {
+ vol = __vsVol(vs, (ALSeqPlayer*)seqp);
+ alSynSetVol(seqp->drvr, &vs->voice, vol,
+ __vsDelta(vs,seqp->curTime));
+ }
+ }
+ break;
+ case (AL_MIDI_PRIORITY_CTRL):
+ /* leave current voices where they are */
+ seqp->chanState[chan].priority = byte2;
+ break;
+ case (AL_MIDI_SUSTAIN_CTRL):
+ seqp->chanState[chan].sustain = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ if ((vs->channel == chan) && (vs->phase != AL_PHASE_RELEASE))
+ {
+ if ( byte2 > AL_SUSTAIN )
+ {
+ /*
+ * sustain pedal down
+ */
+ if (vs->phase == AL_PHASE_NOTEON)
+ vs->phase = AL_PHASE_SUSTAIN;
+ }
+ else
+ {
+ /*
+ * sustain pedal up
+ */
+ if (vs->phase == AL_PHASE_SUSTAIN)
+ vs->phase = AL_PHASE_NOTEON;
+
+ else if(vs->phase == AL_PHASE_SUSTREL)
+ {
+ vs->phase = AL_PHASE_RELEASE;
+ __seqpReleaseVoice((ALSeqPlayer*)seqp,
+ &vs->voice,
+ vs->sound->envelope->releaseTime);
+ }
+ }
+ }
+ }
+ break;
+ case (AL_MIDI_FX1_CTRL):
+ seqp->chanState[chan].fxmix = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ if (vs->channel == chan)
+ alSynSetFXMix(seqp->drvr, &vs->voice, byte2);
+ }
+ break;
+/* case (AL_MIDI_FX_CTRL_0):
+ case (AL_MIDI_FX_CTRL_1):
+ case (AL_MIDI_FX_CTRL_2):
+ case (AL_MIDI_FX_CTRL_3):
+ case (AL_MIDI_FX_CTRL_4):
+ case (AL_MIDI_FX_CTRL_5):
+ case (AL_MIDI_FX_CTRL_6):
+ case (AL_MIDI_FX_CTRL_7):
+ fxref = alSynGetFXRef(seqp->drvr, 0, 0);
+ if (fxref)
+ alSynSetFXParam(seqp->drvr, fxref, (s16)byte1, (void *)byte2);
+ break;
+ case (AL_MIDI_FX3_CTRL): */
+ default:
+ break;
+ }
+ break;
+ case (AL_MIDI_ProgramChange):
+ /* sct 1/16/96 - We must have a valid bank in order to process the program change. */
+
+#ifdef _DEBUG
+ assert(seqp->bank != NULL);
+#endif
+
+ if (key < seqp->bank->instCount)
+ {
+ ALInstrument *inst = seqp->bank->instArray[key];
+ __setInstChanState((ALSeqPlayer*)seqp, inst, chan); /* sct 11/6/95 */
+ }
+ else
+ {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQPINVALIDPROG, 2, key, seqp->bank->instCount);
+#endif
+ }
+ break;
+ case (AL_MIDI_PitchBendChange):
+ {
+ s32 bendVal;
+ f32 bendRatio;
+ s32 cents;
+
+ /* get 14-bit unsigned midi value */
+ bendVal = ( (byte2 << 7) + byte1) - 8192;
+
+ /* calculate pitch bend in cents */
+ cents = (seqp->chanState[chan].bendRange * bendVal)/8192;
+
+ /* calculate the corresponding ratio */
+ bendRatio = alCents2Ratio(cents);
+ seqp->chanState[chan].pitchBend = bendRatio;
+
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ if (vs->channel == chan)
+ alSynSetPitch(seqp->drvr, &vs->voice,
+ vs->pitch * bendRatio * vs->vibrato);
+
+ }
+ break;
+
+ default:
+#ifdef _DEBUG
+ __osError(ERR_ALSEQPUNKNOWNMIDI, 1, status);
+#endif
+ break;
+ }
+
+}
+
+static void __CSPHandleMetaMsg(ALCSPlayer *seqp, ALEvent *event)
+{
+ ALTempoEvent *tevt = &event->msg.tempo;
+ ALEvent evt;
+ s32 tempo;
+ s32 oldUspt;
+ u32 ticks;
+ ALMicroTime tempDelta,curDelta = 0;
+ ALEventListItem *thisNode,*nextNode,*firstTemp = 0;
+
+
+ if (event->msg.tempo.status == AL_MIDI_Meta)
+ {
+ if (event->msg.tempo.type == AL_MIDI_META_TEMPO)
+ {
+ oldUspt = seqp->uspt;
+ tempo = (tevt->byte1 << 16) | (tevt->byte2 << 8) | (tevt->byte3 << 0);
+ __setUsptFromTempo (seqp, (f32)tempo); /* sct 1/8/96 */
+
+ thisNode = (ALEventListItem*)seqp->evtq.allocList.next;
+ while(thisNode)
+ {
+ curDelta += thisNode->delta;
+ nextNode = (ALEventListItem*)thisNode->node.next;
+ if(thisNode->evt.type == AL_CSP_NOTEOFF_EVT)
+ {
+ alUnlink((ALLink*)thisNode);
+
+ if(firstTemp)
+ alLink((ALLink*)thisNode,(ALLink*)firstTemp);
+ else
+ {
+ thisNode->node.next = 0;
+ thisNode->node.prev = 0;
+ firstTemp = thisNode;
+ }
+ tempDelta = curDelta; /* record the current delta */
+ if(nextNode) /* don't do this if no nextNode */
+ {
+ curDelta -= thisNode->delta; /* subtract out this delta */
+ nextNode->delta += thisNode->delta; /* add it to next event */
+ }
+ thisNode->delta = tempDelta; /* set this event delta from current */
+ }
+ thisNode = nextNode;
+ }
+
+ thisNode = firstTemp;
+ while(thisNode)
+ {
+ nextNode = (ALEventListItem*)thisNode->node.next;
+ ticks = thisNode->delta/oldUspt;
+ thisNode->delta = ticks * seqp->uspt;
+ __CSPRepostEvent(&seqp->evtq,thisNode);
+ thisNode = nextNode;
+ }
+ }
+ }
+}
+
+static void __CSPRepostEvent(ALEventQueue *evtq, ALEventListItem *item)
+{
+ OSIntMask mask;
+ ALLink *node;
+ ALEventListItem *nextItem;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ for (node = &evtq->allocList; node != 0; node = node->next)
+ {
+ if (!node->next) /* end of the list */
+ {
+ alLink((ALLink *)item, node);
+ break;
+ }
+ else
+ {
+ nextItem = (ALEventListItem *)node->next;
+ if (item->delta < nextItem->delta)
+ {
+ nextItem->delta -= item->delta;
+ alLink((ALLink *)item, node);
+ break;
+ }
+ item->delta -= nextItem->delta;
+ }
+ }
+ osSetIntMask(mask);
+}
+
+
+/*
+ This routine safely calculates the sequence player's
+ uspt value based on the given tempo. It does this safely
+ by making sure that the player has a target sequence and
+ therefore a qnpt value which is needed for the calculation.
+
+ Compact sequence player needs its own version of this routine
+ since the ALCSeq's qnpt field is at a different offset.
+*/
+static void __setUsptFromTempo (ALCSPlayer *seqp, f32 tempo)
+{
+ if (seqp->target)
+ seqp->uspt = (s32)((f32)tempo * seqp->target->qnpt);
+ else
+ seqp->uspt = 488; /* This is the initial value set by alSeqpNew. */
+}
+
diff --git a/lib/ultralib/src/audio/cspplay.c b/lib/ultralib/src/audio/cspplay.c
new file mode 100644
index 0000000..e34914c
--- /dev/null
+++ b/lib/ultralib/src/audio/cspplay.c
@@ -0,0 +1,34 @@
+/*====================================================================
+ * cspplay.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "cseqp.h"
+
+void alCSPPlay(ALCSPlayer *seqp)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_PLAY_EVT;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsendmidi.c b/lib/ultralib/src/audio/cspsendmidi.c
new file mode 100644
index 0000000..3d03c9b
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsendmidi.c
@@ -0,0 +1,40 @@
+/*====================================================================
+ * cspsendmidi.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSendMidi(ALCSPlayer *seqp, s32 ticks, u8 status, u8 byte1,
+ u8 byte2)
+{
+ ALEvent evt;
+ ALMicroTime deltaTime;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = status;
+ evt.msg.midi.byte1 = byte1;
+ evt.msg.midi.byte2 = byte2;
+ evt.msg.midi.duration = 0;
+
+ deltaTime = ticks*seqp->uspt;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetbank.c b/lib/ultralib/src/audio/cspsetbank.c
new file mode 100644
index 0000000..63292b4
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetbank.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * cspsetbank.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetBank(ALCSPlayer *seqp, ALBank *b)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_BANK_EVT;
+ evt.msg.spbank.bank = b;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetchlvol.c b/lib/ultralib/src/audio/cspsetchlvol.c
new file mode 100644
index 0000000..28e62bb
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetchlvol.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * cspsetchlvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetChlVol(ALCSPlayer *seqp, u8 chan, u8 vol)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ControlChange | chan;
+ evt.msg.midi.byte1 = AL_MIDI_VOLUME_CTRL;
+ evt.msg.midi.byte2 = vol;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetfxmix.c b/lib/ultralib/src/audio/cspsetfxmix.c
new file mode 100644
index 0000000..f099297
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetfxmix.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * cspsetfxmix.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetChlFXMix(ALCSPlayer *seqp, u8 chan, u8 fxmix)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ControlChange | chan;
+ evt.msg.midi.byte1 = AL_MIDI_FX1_CTRL;
+ evt.msg.midi.byte2 = fxmix;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetpan.c b/lib/ultralib/src/audio/cspsetpan.c
new file mode 100644
index 0000000..c0dab00
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetpan.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * cspsetpan.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetChlPan(ALCSPlayer *seqp, u8 chan, ALPan pan)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ControlChange | chan;
+ evt.msg.midi.byte1 = AL_MIDI_PAN_CTRL;
+ evt.msg.midi.byte2 = pan;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetpriority.c b/lib/ultralib/src/audio/cspsetpriority.c
new file mode 100644
index 0000000..b449b82
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetpriority.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * cspsetpriority.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetChlPriority(ALCSPlayer *seqp, u8 chan, u8 priority)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_PRIORITY_EVT;
+ evt.msg.sppriority.chan = chan;
+ evt.msg.sppriority.priority = priority;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
diff --git a/lib/ultralib/src/audio/cspsetprogram.c b/lib/ultralib/src/audio/cspsetprogram.c
new file mode 100644
index 0000000..2b19e63
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetprogram.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * cspsetprogram.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetChlProgram(ALCSPlayer *seqp, u8 chan, u8 prog)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ProgramChange | chan;
+ evt.msg.midi.byte1 = prog;
+ evt.msg.midi.byte2 = 0;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetseq.c b/lib/ultralib/src/audio/cspsetseq.c
new file mode 100644
index 0000000..4b6718e
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetseq.c
@@ -0,0 +1,34 @@
+/*====================================================================
+ * cspsetseq.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetSeq(ALCSPlayer *seqp, ALCSeq *seq)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_SEQ_EVT;
+ evt.msg.spseq.seq = seq;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsettempo.c b/lib/ultralib/src/audio/cspsettempo.c
new file mode 100644
index 0000000..b085b45
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsettempo.c
@@ -0,0 +1,36 @@
+/*====================================================================
+ * cspsettempo.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetTempo(ALCSPlayer *seqp, s32 tempo)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_META_EVT;
+ evt.msg.tempo.status = AL_MIDI_Meta;
+ evt.msg.tempo.type = AL_MIDI_META_TEMPO;
+ evt.msg.tempo.byte1 = (tempo & 0xff0000)>>16;
+ evt.msg.tempo.byte2 = (tempo & 0xff00)>>8;
+ evt.msg.tempo.byte3 = tempo & 0xff;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspsetvol.c b/lib/ultralib/src/audio/cspsetvol.c
new file mode 100644
index 0000000..6782f33
--- /dev/null
+++ b/lib/ultralib/src/audio/cspsetvol.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * cspsetvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPSetVol(ALCSPlayer *seqp, s16 vol)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_VOL_EVT;
+ evt.msg.spvol.vol = vol;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/cspstop.c b/lib/ultralib/src/audio/cspstop.c
new file mode 100644
index 0000000..9929820
--- /dev/null
+++ b/lib/ultralib/src/audio/cspstop.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * cspstop.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alCSPStop(ALCSPlayer *seqp)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_STOPPING_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/drvrnew.c b/lib/ultralib/src/audio/drvrnew.c
new file mode 100644
index 0000000..ef9e27f
--- /dev/null
+++ b/lib/ultralib/src/audio/drvrnew.c
@@ -0,0 +1,306 @@
+/*====================================================================
+ * drvrNew.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+#include <os.h>
+#include <stdio.h>
+#include "initfx.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.49 $"
+
+/*
+ * WARNING: THE FOLLOWING CONSTANT MUST BE KEPT IN SYNC
+ * WITH SCALING IN MICROCODE!!!
+ */
+#define SCALE 16384
+
+/*
+ * the following arrays contain default parameters for
+ * a few hopefully useful effects.
+ */
+#define ms *(((s32)((f32)44.1))&~0x7)
+
+
+static s32 SMALLROOM_PARAMS[26] = {
+ /* sections length */
+ 3, 100 ms,
+ /* chorus chorus filter
+ input output fbcoef ffcoef gain rate depth coef */
+ 0, 54 ms, 9830, -9830, 0, 0, 0, 0,
+ 19 ms, 38 ms, 3276, -3276, 0x3fff, 0, 0, 0,
+ 0, 60 ms, 5000, 0, 0, 0, 0, 0x5000
+};
+
+static s32 BIGROOM_PARAMS[34] = {
+ /* sections length */
+ 4, 100 ms,
+ /* chorus chorus filter
+ input output fbcoef ffcoef gain rate depth coef */
+ 0, 66 ms, 9830, -9830, 0, 0, 0, 0,
+ 22 ms, 54 ms, 3276, -3276, 0x3fff, 0, 0, 0,
+ 66 ms, 91 ms, 3276, -3276, 0x3fff, 0, 0, 0,
+ 0, 94 ms, 8000, 0, 0, 0, 0, 0x5000
+};
+
+static s32 ECHO_PARAMS[10] = {
+ /* sections length */
+ 1, 200 ms,
+ /* chorus chorus filter
+ input output fbcoef ffcoef gain rate depth coef */
+ 0, 179 ms, 12000, 0, 0x7fff, 0, 0, 0
+};
+
+static s32 CHORUS_PARAMS[10] = {
+ /* sections length */
+ 1, 20 ms,
+ /* chorus chorus filter
+ input output fbcoef ffcoef gain rate depth coef */
+ 0, 5 ms, 0x4000, 0, 0x7fff, 7600, 700, 0
+};
+
+static s32 FLANGE_PARAMS[10] = {
+ /* sections length */
+ 1, 20 ms,
+ /* chorus chorus filter
+ input output fbcoef ffcoef gain rate depth coef */
+ 0, 5 ms, 0, 0x5fff, 0x7fff, 380, 500, 0
+};
+
+static s32 NULL_PARAMS[10] = {
+ 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+void _init_lpfilter(ALLowPass *lp)
+{
+ s32 i, temp;
+ s16 fc;
+ f64 ffc, fcoef;
+
+ temp = lp->fc * SCALE;
+ fc = temp >> 15;
+ lp->fgain = SCALE - fc;
+
+ lp->first = 1;
+ for (i=0; i<8; i++)
+ lp->fcvec.fccoef[i] = 0;
+
+ lp->fcvec.fccoef[i++] = fc;
+ fcoef = ffc = (f64)fc/SCALE;
+
+ for (; i<16; i++){
+ fcoef *= ffc;
+ lp->fcvec.fccoef[i] = (s16)(fcoef * SCALE);
+ }
+}
+
+
+void alFxNew(ALFx *r, ALSynConfig *c, ALHeap *hp)
+{
+ u16 i, j, k;
+ s32 *param = 0;
+ ALFilter *f = (ALFilter *) r;
+ ALDelay *d;
+
+ alFilterNew(f, 0, alFxParam, AL_FX);
+ f->handler = alFxPull;
+ r->paramHdl = (ALSetFXParam)alFxParamHdl;
+
+ switch (c->fxType) {
+ case AL_FX_SMALLROOM: param = SMALLROOM_PARAMS; break;
+ case AL_FX_BIGROOM: param = BIGROOM_PARAMS; break;
+ case AL_FX_ECHO: param = ECHO_PARAMS; break;
+ case AL_FX_CHORUS: param = CHORUS_PARAMS; break;
+ case AL_FX_FLANGE: param = FLANGE_PARAMS; break;
+ case AL_FX_CUSTOM: param = c->params; break;
+ default: param = NULL_PARAMS; break;
+ }
+
+
+ j = 0;
+
+ r->section_count = param[j++];
+ r->length = param[j++];
+
+ r->delay = alHeapAlloc(hp, r->section_count, sizeof(ALDelay));
+ r->base = alHeapAlloc(hp, r->length, sizeof(s16));
+ r->input = r->base;
+
+ for ( k=0; k < r->length; k++)
+ r->base[k] = 0;
+
+ for ( i=0; i<r->section_count; i++ ){
+ d = &r->delay[i];
+ d->input = param[j++];
+ d->output = param[j++];
+ d->fbcoef = param[j++];
+ d->ffcoef = param[j++];
+ d->gain = param[j++];
+
+ if (param[j]) {
+#define RANGE 2.0
+/* d->rsinc = ((f32) param[j++])/0xffffff; */
+ d->rsinc = ((((f32)param[j++])/1000) * RANGE)/c->outputRate;
+
+ /*
+ * the following constant is derived from:
+ *
+ * ratio = 2^(cents/1200)
+ *
+ * and therefore for hundredths of a cent
+ * x
+ * ln(ratio) = ---------------
+ * (120,000)/ln(2)
+ * where
+ * 120,000/ln(2) = 173123.40...
+ */
+#define CONVERT 173123.404906676
+#define LENGTH (d->output - d->input)
+ d->rsgain = (((f32) param[j++])/CONVERT) * LENGTH;
+ d->rsval = 1.0;
+ d->rsdelta = 0.0;
+ d->rs = alHeapAlloc(hp, 1, sizeof(ALResampler));
+ d->rs->state = alHeapAlloc(hp, 1, sizeof(RESAMPLE_STATE));
+ d->rs->delta = 0.0;
+ d->rs->first = 1;
+ } else {
+ d->rs = 0;
+ j++;
+ j++;
+ }
+
+ if (param[j]) {
+ d->lp = alHeapAlloc(hp, 1, sizeof(ALLowPass));
+ d->lp->fstate = alHeapAlloc(hp, 1, sizeof(POLEF_STATE));
+ d->lp->fc = param[j++];
+ _init_lpfilter(d->lp);
+ } else {
+ d->lp = 0;
+ j++;
+ }
+ }
+}
+
+void alEnvmixerNew(ALEnvMixer *e, ALHeap *hp)
+{
+ alFilterNew((ALFilter *) e, alEnvmixerPull, alEnvmixerParam, AL_ENVMIX);
+
+ e->state = alHeapAlloc(hp, 1, sizeof(ENVMIX_STATE));
+
+ e->first = 1;
+ e->motion = AL_STOPPED;
+ e->volume = 1;
+ e->ltgt = 1;
+ e->rtgt = 1;
+ e->cvolL = 1;
+ e->cvolR = 1;
+ e->dryamt = 0;
+ e->wetamt = 0;
+ e->lratm = 1;
+ e->lratl = 0;
+ e->lratm = 1;
+ e->lratl = 0;
+ e->delta = 0;
+ e->segEnd = 0;
+ e->pan = 0;
+ e->ctrlList = 0;
+ e->ctrlTail = 0;
+ e->sources = 0;
+}
+
+void alLoadNew(ALLoadFilter *f, ALDMANew dmaNew, ALHeap *hp)
+{
+ s32
+ i;
+
+ /*
+ * init filter superclass
+ */
+
+ alFilterNew((ALFilter *) f, alAdpcmPull, alLoadParam, AL_ADPCM);
+
+ f->state = alHeapAlloc(hp, 1, sizeof(ADPCM_STATE));
+ f->lstate = alHeapAlloc(hp, 1, sizeof(ADPCM_STATE));
+
+ f->dma = dmaNew(&f->dmaState);
+
+ /*
+ * init the adpcm state
+ */
+ f->lastsam = 0;
+ f->first = 1;
+ f->memin = 0;
+}
+
+void alResampleNew(ALResampler *r, ALHeap *hp)
+{
+ alFilterNew((ALFilter *) r, alResamplePull, alResampleParam, AL_RESAMPLE);
+
+ /*
+ * Init resampler state
+ */
+ r->state = alHeapAlloc(hp, 1, sizeof(RESAMPLE_STATE));
+ r->delta = 0.0;
+ r->first = 1;
+ r->motion = AL_STOPPED;
+ r->ratio = 1.0;
+ r->upitch = 0;
+ r->ctrlList = 0;
+ r->ctrlTail = 0;
+
+ /* state in the ucode is initialized by the A_INIT flag */
+}
+
+void alAuxBusNew(ALAuxBus *m, void *sources, s32 maxSources)
+{
+ alFilterNew((ALFilter *) m, alAuxBusPull, alAuxBusParam, AL_AUXBUS);
+ m->sourceCount = 0;
+ m->maxSources = maxSources;
+ m->sources = (ALFilter **)sources;
+}
+
+void alMainBusNew(ALMainBus *m, void *sources, s32 maxSources)
+{
+ alFilterNew((ALFilter *) m, alMainBusPull, alMainBusParam, AL_MAINBUS);
+ m->sourceCount = 0;
+ m->maxSources = maxSources;
+ m->sources = (ALFilter **)sources;
+}
+
+void alSaveNew(ALSave *f)
+{
+ /*
+ * init filter superclass
+ */
+
+ alFilterNew((ALFilter *) f, alSavePull, alSaveParam, AL_SAVE);
+
+ /*
+ * init the save state, which is a virtual dram address
+ */
+
+ f->dramout = 0;
+ f->first = 1;
+
+}
+
diff --git a/lib/ultralib/src/audio/env.c b/lib/ultralib/src/audio/env.c
new file mode 100644
index 0000000..bc7369a
--- /dev/null
+++ b/lib/ultralib/src/audio/env.c
@@ -0,0 +1,595 @@
+/*====================================================================
+ * envmixer.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+#include <os.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+// TODO: these come from headers
+#ident "$Revision: 1.49 $"
+#ident "$Revision: 1.17 $"
+
+#ifdef AUD_PROFILE
+extern u32 cnt_index, env_num, env_cnt, env_max, env_min, lastCnt[];
+extern u32 rate_num, rate_cnt, rate_max, rate_min;
+extern u32 vol_num, vol_cnt, vol_max, vol_min;
+#endif
+
+#define EQPOWER_LENGTH 128
+static s16 eqpower[ EQPOWER_LENGTH ] = {
+ 32767, 32764, 32757, 32744, 32727, 32704,
+ 32677, 32644, 32607, 32564, 32517, 32464,
+ 32407, 32344, 32277, 32205, 32127, 32045,
+ 31958, 31866, 31770, 31668, 31561, 31450,
+ 31334, 31213, 31087, 30957, 30822, 30682,
+ 30537, 30388, 30234, 30075, 29912, 29744,
+ 29572, 29395, 29214, 29028, 28838, 28643,
+ 28444, 28241, 28033, 27821, 27605, 27385,
+ 27160, 26931, 26698, 26461, 26220, 25975,
+ 25726, 25473, 25216, 24956, 24691, 24423,
+ 24151, 23875, 23596, 23313, 23026, 22736,
+ 22442, 22145, 21845, 21541, 21234, 20924,
+ 20610, 20294, 19974, 19651, 19325, 18997,
+ 18665, 18331, 17993, 17653, 17310, 16965,
+ 16617, 16266, 15913, 15558, 15200, 14840,
+ 14477, 14113, 13746, 13377, 13006, 12633,
+ 12258, 11881, 11503, 11122, 10740, 10357,
+ 9971, 9584, 9196, 8806, 8415, 8023,
+ 7630, 7235, 6839, 6442, 6044, 5646,
+ 5246, 4845, 4444, 4042, 3640, 3237,
+ 2833, 2429, 2025, 1620, 1216, 810,
+ 405, 0
+};
+
+extern f64 __pow(f64, f64);
+
+/*
+ * prototypes for private enveloper functions
+ */
+static Acmd *_pullSubFrame(void *filter, s16 *inp, s16 *outp, s32 outCount,
+ s32 sampleOffset, Acmd *p) ;
+static s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel);
+
+static f32 _getVol(f32 ivol, s32 samples, s16 ratem, u16 ratel);
+
+/***********************************************************************
+ * Enveloper filter public interfaces
+ ***********************************************************************/
+Acmd *alEnvmixerPull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset,
+ Acmd *p)
+{
+ Acmd *ptr = p;
+ ALEnvMixer *e = (ALEnvMixer *)filter;
+ s16 inp;
+ s32 lastOffset;
+ s32 thisOffset = sampleOffset;
+ s32 samples;
+ s16 loutp = 0;
+ s32 fVol;
+ ALParam *thisParam;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ /*
+ * Force the input to be the resampler output
+ */
+ inp = AL_RESAMPLER_OUT;
+
+ while (e->ctrlList != 0) {
+
+ lastOffset = thisOffset;
+ thisOffset = e->ctrlList->delta;
+ samples = thisOffset - lastOffset;
+ if (samples > outCount)
+ break;
+
+#ifdef _DEBUG
+ assert(samples >= 0);
+ assert(samples <= AL_MAX_RSP_SAMPLES);
+#endif
+
+ switch (e->ctrlList->type) {
+ case (AL_FILTER_START_VOICE_ALT):
+ {
+ ALStartParamAlt *param = (ALStartParamAlt *)e->ctrlList;
+ ALFilter *f = (ALFilter *) e;
+ s32 tmp;
+
+ if (param->unity) {
+ (*e->filter.setParam)(&e->filter,
+ AL_FILTER_SET_UNITY_PITCH, 0);
+ }
+
+ (*e->filter.setParam)(&e->filter, AL_FILTER_SET_WAVETABLE,
+ param->wave);
+ (*e->filter.setParam)(&e->filter, AL_FILTER_START, 0);
+
+ e->first = 1;
+
+ e->delta = 0;
+ e->segEnd = param->samples;
+
+ tmp = ((s32)param->volume * (s32)param->volume) >> 15;
+ e->volume = (s16) tmp;
+ e->pan = param->pan;
+ e->dryamt = eqpower[param->fxMix];
+ e->wetamt = eqpower[EQPOWER_LENGTH - param->fxMix - 1];
+
+ if (param->samples) {
+ e->cvolL = 1;
+ e->cvolR = 1;
+ } else {
+ /*
+ * Attack time is zero. Simply set the
+ * volume. We don't want an attack segment.
+ */
+ e->cvolL = (e->volume * eqpower[e->pan]) >> 15;
+ e->cvolR = (e->volume *
+ eqpower[EQPOWER_LENGTH - e->pan - 1]) >> 15;
+ }
+
+ if (f->source) {
+ union {
+ f32 f;
+ s32 i;
+ } data;
+ data.f = param->pitch;
+ (*f->source->setParam)(f->source, AL_FILTER_SET_PITCH,
+ (void *)data.i);
+ }
+
+ }
+
+ break;
+
+ case (AL_FILTER_SET_FXAMT):
+ case (AL_FILTER_SET_PAN):
+ case (AL_FILTER_SET_VOLUME):
+ ptr = _pullSubFrame(e, &inp, &loutp, samples, sampleOffset, ptr);
+
+ if (e->delta >= e->segEnd){
+ /*
+ * We should have reached our target, calculate
+ * target in case e->segEnd was 0
+ */
+ e->ltgt = (e->volume * eqpower[e->pan]) >> 15;
+ e->rtgt = (e->volume *
+ eqpower[EQPOWER_LENGTH - e->pan - 1]) >> 15;
+ e->delta = e->segEnd; /* To prevent overflow */
+ e->cvolL = e->ltgt;
+ e->cvolR = e->rtgt;
+ } else {
+ /*
+ * Estimate the current volume
+ */
+ e->cvolL = _getVol(e->cvolL, e->delta, e->lratm, e->lratl);
+ e->cvolR = _getVol(e->cvolR, e->delta, e->rratm, e->rratl);
+ }
+
+ /*
+ * We can't have volume of zero, because the envelope
+ * would never go anywhere from there
+ */
+ if( e->cvolL == 0 ) e->cvolL = 1;
+ if( e->cvolR == 0 ) e->cvolR = 1;
+
+ if (e->ctrlList->type == AL_FILTER_SET_PAN)
+
+ /*
+ * This should result in a change to the current
+ * segment rate and target
+ */
+ e->pan = (s16) e->ctrlList->data.i;
+
+ if (e->ctrlList->type == AL_FILTER_SET_VOLUME){
+
+ /*
+ * Switching to a new segment
+ */
+ e->delta = 0;
+
+ /*
+ * Map volume non-linearly to give something close to
+ * loudness
+ */
+ fVol = (e->ctrlList->data.i);
+ fVol = (fVol*fVol)>>15;
+ e->volume = (s16) fVol;
+
+ e->segEnd = e->ctrlList->moredata.i;
+
+ }
+
+ if (e->ctrlList->type == AL_FILTER_SET_FXAMT){
+ e->dryamt = eqpower[e->ctrlList->data.i];
+ e->wetamt = eqpower[EQPOWER_LENGTH - e->ctrlList->data.i - 1];
+ }
+
+ /*
+ * Force a volume update
+ */
+ e->first = 1;
+ break;
+
+ case (AL_FILTER_START_VOICE):
+ {
+ ALStartParam *p = (ALStartParam *)e->ctrlList;
+
+ /*
+ * Changing to PLAYING (since the previous state was
+ * persumable STOPPED, we'll just bump the output
+ * pointer rather than pull a subframe of zeros).
+ */
+ if (p->unity) {
+ (*e->filter.setParam)(&e->filter,
+ AL_FILTER_SET_UNITY_PITCH, 0);
+ }
+
+ (*e->filter.setParam)(&e->filter, AL_FILTER_SET_WAVETABLE,
+ p->wave);
+ (*e->filter.setParam)(&e->filter, AL_FILTER_START, 0);
+ }
+ break;
+
+ case (AL_FILTER_STOP_VOICE):
+ {
+ /*
+ * Changing to STOPPED and reset the filter
+ */
+ ptr = _pullSubFrame(e, &inp, &loutp, samples, sampleOffset, ptr);
+ (*e->filter.setParam)(&e->filter, AL_FILTER_RESET, 0);
+ }
+ break;
+
+ case (AL_FILTER_FREE_VOICE):
+ {
+ ALSynth *drvr = &alGlobals->drvr;
+ ALFreeParam *param = (ALFreeParam *)e->ctrlList;
+ param->pvoice->offset = 0;
+ _freePVoice(drvr, (PVoice *)param->pvoice);
+ }
+ break;
+
+ default:
+ /*
+ * Pull the reuired number of samples and then pass the message
+ * on down the chain
+ */
+ ptr = _pullSubFrame(e, &inp, &loutp, samples, sampleOffset, ptr);
+ (*e->filter.setParam)(&e->filter, e->ctrlList->type,
+ (void *) e->ctrlList->data.i);
+ break;
+ }
+ loutp += (samples<<1);
+ outCount -= samples;
+
+ /*
+ * put the param record back on the free list
+ */
+ thisParam = e->ctrlList;
+ e->ctrlList = e->ctrlList->next;
+ if (e->ctrlList == 0)
+ e->ctrlTail = 0;
+
+ __freeParam(thisParam);
+
+ }
+
+ ptr = _pullSubFrame(e, &inp, &loutp, outCount, sampleOffset, ptr);
+
+ /*
+ * Prevent overflow in e->delta
+ */
+ if (e->delta > e->segEnd)
+ e->delta = e->segEnd;
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(env_num, env_cnt, env_max, env_min);
+#endif
+ return ptr;
+}
+
+s32
+alEnvmixerParam(void *filter, s32 paramID, void *param)
+{
+ ALFilter *f = (ALFilter *) filter;
+ ALEnvMixer *e = (ALEnvMixer *) filter;
+
+ switch (paramID) {
+
+ case (AL_FILTER_ADD_UPDATE):
+ if (e->ctrlTail) {
+ e->ctrlTail->next = (ALParam *)param;
+ } else {
+ e->ctrlList = (ALParam *)param;
+ }
+ e->ctrlTail = (ALParam *)param;
+
+ break;
+
+ case (AL_FILTER_RESET):
+ e->first = 1;
+ e->motion = AL_STOPPED;
+ e->volume = 1;
+ if (f->source)
+ (*f->source->setParam)(f->source, AL_FILTER_RESET, param);
+ break;
+
+ case (AL_FILTER_START):
+ e->motion = AL_PLAYING;
+ if (f->source)
+ (*f->source->setParam)(f->source, AL_FILTER_START, param);
+ break;
+
+ case (AL_FILTER_SET_SOURCE):
+ f->source = (ALFilter *) param;
+ break;
+
+ default:
+ if (f->source)
+ (*f->source->setParam)(f->source, paramID, param);
+ }
+ return 0;
+}
+
+static
+Acmd* _pullSubFrame(void *filter, s16 *inp, s16 *outp, s32 outCount,
+ s32 sampleOffset, Acmd *p)
+{
+ Acmd *ptr = p;
+ ALEnvMixer *e = (ALEnvMixer *)filter;
+ ALFilter *source= e->filter.source;
+
+ /* filter must be playing and request non-zero output samples to pull. */
+ if (e->motion != AL_PLAYING || !outCount)
+ return ptr;
+
+ /*
+ * ask all filters upstream from us to build their command
+ * lists.
+ */
+#ifdef _DEBUG
+ assert(source);
+#endif
+
+ ptr = (*source->handler)(source, inp, outCount, sampleOffset, p);
+
+ /*
+ * construct our portion of the command list
+ */
+ aSetBuffer(ptr++, A_MAIN, *inp, AL_MAIN_L_OUT + *outp, outCount<<1);
+ aSetBuffer(ptr++, A_AUX, AL_MAIN_R_OUT + *outp, AL_AUX_L_OUT + *outp,
+ AL_AUX_R_OUT + *outp);
+
+ if (e->first){
+ e->first = 0;
+
+ /*
+ * Calculate derived parameters
+ */
+ e->ltgt = (e->volume * eqpower[e->pan]) >> 15;
+ e->lratm = _getRate((f64)e->cvolL, (f64)e->ltgt,
+ e->segEnd, &(e->lratl));
+ e->rtgt = (e->volume *
+ eqpower[EQPOWER_LENGTH - e->pan - 1]) >> 15;
+ e->rratm = _getRate((f64)e->cvolR, (f64)e->rtgt, e->segEnd,
+ &(e->rratl));
+
+ aSetVolume(ptr++, A_LEFT | A_VOL, e->cvolL, 0, 0);
+ aSetVolume(ptr++, A_RIGHT | A_VOL, e->cvolR, 0, 0);
+ aSetVolume(ptr++, A_LEFT | A_RATE, e->ltgt, e->lratm, e->lratl);
+ aSetVolume(ptr++, A_RIGHT | A_RATE, e->rtgt, e->rratm, e->rratl);
+ aSetVolume(ptr++, A_AUX, e->dryamt, 0, e->wetamt);
+ aEnvMixer (ptr++, A_INIT | A_AUX, osVirtualToPhysical(e->state));
+ }
+ else
+ aEnvMixer(ptr++, A_CONTINUE | A_AUX, osVirtualToPhysical(e->state));
+
+ /*
+ * bump the input buffer pointer
+ */
+
+ *inp += (outCount<<1);
+ e->delta += outCount;
+
+ return ptr;
+}
+
+#define EXP_MASK 0x7f800000
+#define MANT_MASK 0x807fffff
+
+f64
+_frexpf(f64 value, s32 *eptr)
+{
+ f64 absvalue;
+
+ *eptr = 0;
+ if (value == 0.0) /* nothing to do for zero */
+ return (value);
+ absvalue = (value > 0.0) ? value : -value;
+ for ( ; absvalue >= 1.0; absvalue *= 0.5)
+ ++*eptr;
+ for ( ; absvalue < 0.5; absvalue += absvalue)
+ --*eptr;
+ return (value > 0.0 ? absvalue : -absvalue);
+}
+
+f64
+_ldexpf(f64 in, s32 ex)
+{
+ s32 exp;
+
+ if ( ex ) {
+ exp = 1 << ex;
+ in *= (f64)exp;
+ }
+
+ return ( in );
+}
+
+/*
+ _getRate() -- This function determines how to go from the
+ current volume level (vol) to the target
+ volume level (tgt) in some number of steps
+ (count). Two values are returned that are
+ used as multipliers to incrementally scale
+ the volume. Some tricky math is used and
+ is explained below.
+ RWW 28jun95
+*/
+
+static
+s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel)
+{
+ s16 s;
+
+ f64 invn = 1.0/count, eps, a, fs, mant;
+ s32 i_invn, ex, indx;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ if (count == 0){
+ if (tgt >= vol){
+ *ratel = 0xffff;
+ return 0x7fff;
+ }
+ else{
+ *ratel = 0;
+ return 0;
+ }
+ }
+
+ if (tgt < 1.0)
+ tgt = 1.0;
+ if (vol <= 0) vol = 1; /* zero and neg values not allowed */
+
+#define NBITS (3)
+#define NPOS (1<<NBITS)
+#define NFRACBITS (30)
+#define M_LN2 0.69314718055994530942
+ /*
+ * rww's parametric pow()
+ Goal: compute a = (tgt/vol)^(1/count)
+
+ Approach:
+ (tgt/vol)^(1/count) =
+ ((tgt/vol)^(1/2^30))^(2^30*1/count)
+
+ (tgt/vol)^(1/2^30) ~= 1 + eps
+
+ where
+
+ eps ~= ln(tgt/vol)/2^30
+
+ ln(tgt/vol) = ln2(tgt/vol) * ln(2)
+
+ ln2(tgt/vol) = fp_exponent( tgt/vol ) +
+ ln2( fp_mantissa( tgt/vol ) )
+
+ fp_mantissa() and fp_exponent() are
+ calculated via tricky bit manipulations of
+ the floating point number. ln2() is
+ approximated by a look up table.
+
+ Note that this final (1+eps) value needs
+ to be raised to the 2^30/count power. This
+ is done by operating on the binary representaion
+ of this number in the final while loop.
+
+ Enjoy!
+ */
+ {
+ f64 logtab[] = { -0.912537, -0.752072, -0.607683, -0.476438,
+ -0.356144, -0.245112, -0.142019, -0.045804 };
+
+ i_invn = (s32) _ldexpf( invn, NFRACBITS );
+ mant = _frexpf( tgt/vol, &ex );
+ indx = (s32) (_ldexpf( mant, NBITS+1 ) ); /* NPOS <= indx < 2*NPOS */
+ eps = (logtab[indx - NPOS] + ex) * M_LN2;
+ eps /= _ldexpf( 1, NFRACBITS ); /* eps / 2^NFRACBITS */
+ fs = (1.0 + eps);
+ a = 1.0;
+ while( i_invn ) {
+ if( i_invn & 1 )
+ a = a * fs;
+ fs *= fs;
+ i_invn >>= 1;
+ }
+ }
+
+ a *= (a *= (a *= a));
+ s = (s16) a;
+ *ratel = (s16)(0xffff * (a - (f32) s));
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(rate_num, rate_cnt, rate_max, rate_min);
+#endif
+ return (s16)a;
+
+}
+
+static
+f32 _getVol(f32 ivol, s32 samples, s16 ratem, u16 ratel)
+{
+ f32 r, a;
+ s32 i;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ /*
+ * Rate values are actually rate^8
+ */
+ samples >>=3;
+ if (samples == 0){
+ return ivol;
+ }
+ r = ((f32) (ratem<<16) + (f32) ratel)/65536;
+
+ a = 1.0;
+ for (i=0; i<32; i++){
+ if( samples & 1 )
+ a *= r;
+ samples >>= 1;
+ if (samples == 0)
+ break;
+ r *= r;
+ }
+ ivol *= a;
+#ifdef AUD_PROFILE
+ PROFILE_AUD(vol_num, vol_cnt, vol_max, vol_min);
+#endif
+ return ivol;
+}
+
+
+
+
+
+
+
diff --git a/lib/ultralib/src/audio/event.c b/lib/ultralib/src/audio/event.c
new file mode 100644
index 0000000..3112c99
--- /dev/null
+++ b/lib/ultralib/src/audio/event.c
@@ -0,0 +1,272 @@
+/*====================================================================
+ * event.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+
+
+void alEvtqNew(ALEventQueue *evtq, ALEventListItem *items, s32 itemCount)
+{
+ s32 i;
+
+ evtq->eventCount = 0;
+ evtq->allocList.next = 0;
+ evtq->allocList.prev = 0;
+ evtq->freeList.next = 0;
+ evtq->freeList.prev = 0;
+
+ for (i = 0; i < itemCount; i++) {
+ alLink((ALLink *)&items[i], &evtq->freeList);
+ }
+}
+
+ALMicroTime alEvtqNextEvent(ALEventQueue *evtq, ALEvent *evt)
+{
+ ALEventListItem *item;
+ ALMicroTime delta;
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ item = (ALEventListItem *)evtq->allocList.next;
+
+ if (item)
+ {
+ alUnlink((ALLink *)item);
+ alCopy(&item->evt, evt, sizeof(*evt));
+ alLink((ALLink *)item, &evtq->freeList);
+ delta = item->delta;
+ }
+ else
+ {
+ /* sct 11/28/95 - If we get here, most like we overflowed the event queue */
+ /* with non-self-perpetuating events. Eg. if we filled the evtq with volume */
+ /* events, then when the seqp is told to play it will handle all the events */
+ /* at once completely emptying out the queue. At this point this problem */
+ /* must be treated as an out of resource error and the evtq should be increased. */
+ evt->type = -1;
+ delta = 0;
+ }
+
+ osSetIntMask(mask);
+
+ return delta;
+}
+
+void alEvtqPostEvent(ALEventQueue *evtq, ALEvent *evt, ALMicroTime delta)
+{
+ ALEventListItem *item;
+ ALEventListItem *nextItem;
+ ALLink *node;
+ s32 postAtEnd=0;
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ item = (ALEventListItem *)evtq->freeList.next;
+ if (!item) {
+ osSetIntMask(mask);
+#ifdef _DEBUG
+ __osError(ERR_ALEVENTNOFREE, 0);
+#endif
+ return;
+ }
+
+ alUnlink((ALLink *)item);
+ alCopy(evt, &item->evt, sizeof(*evt));
+
+ if (delta == AL_EVTQ_END)
+ postAtEnd = -1;
+
+ for (node = &evtq->allocList; node != 0; node = node->next) {
+ if (!node->next) { /* end of the list */
+ if (postAtEnd)
+ item->delta = 0;
+ else
+ item->delta = delta;
+ alLink((ALLink *)item, node);
+ break;
+ } else {
+ nextItem = (ALEventListItem *)node->next;
+
+ if (delta < nextItem->delta) {
+ item->delta = delta;
+ nextItem->delta -= delta;
+
+ alLink((ALLink *)item, node);
+ break;
+ }
+
+ delta -= nextItem->delta;
+
+ }
+ }
+
+ osSetIntMask(mask);
+
+}
+
+void alEvtqFlush(ALEventQueue *evtq)
+{
+ ALLink *thisNode;
+ ALLink *nextNode;
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ thisNode = evtq->allocList.next;
+ while( thisNode != 0 ) {
+ nextNode = thisNode->next;
+ alUnlink(thisNode);
+ alLink(thisNode, &evtq->freeList);
+ thisNode = nextNode;
+ }
+
+ osSetIntMask(mask);
+}
+
+
+/*
+ This routine flushes events according their type.
+*/
+void alEvtqFlushType(ALEventQueue *evtq, s16 type)
+{
+ ALLink *thisNode;
+ ALLink *nextNode;
+ ALEventListItem *thisItem, *nextItem;
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ thisNode = evtq->allocList.next;
+ while( thisNode != 0 )
+ {
+ nextNode = thisNode->next;
+ thisItem = (ALEventListItem *)thisNode;
+ nextItem = (ALEventListItem *)nextNode;
+ if (thisItem->evt.type == type)
+ {
+ if (nextItem)
+ nextItem->delta += thisItem->delta;
+ alUnlink(thisNode);
+ alLink(thisNode, &evtq->freeList);
+ }
+ thisNode = nextNode;
+ }
+
+ osSetIntMask(mask);
+}
+
+
+#ifdef _DEBUG_INTERNAL
+void alEvtqPrintEvtQueue(ALEventQueue *evtq)
+{
+ s32 count1 = 0;
+ s32 count2 = 0;
+ ALLink *node;
+ ALEventListItem *item;
+
+ /* count free events */
+ for (node = evtq->freeList.next; node != 0; node= node->next) {
+ count1++;
+ }
+
+ PRINTF("----- Allocated Events -----\n");
+ for (node = evtq->allocList.next; node != 0; node= node->next) {
+ item = (ALEventListItem *)node;
+
+ PRINTF("\tdelta: %d\ttype %d\n", item->delta, item->evt.type);
+ count2++;
+ }
+ PRINTF("\n");
+
+ PRINTF("free events\t %d\n", count1);
+ PRINTF("alloc events\t %d\n", count2);
+ PRINTF("total events\t %d\n", count1 + count2);
+}
+
+char *MidiStatus2Str (char status, char *str);
+
+void
+alEvtqPrintAllocEvts(ALEventQueue *evtq)
+{
+ ALLink *node;
+ ALEventListItem *item;
+ ALMicroTime itemTime = 0;
+ char str[32];
+
+ PRINTF("----- Allocated Events -----\n");
+ for (node = evtq->allocList.next; node != 0; node= node->next)
+ {
+ item = (ALEventListItem *)node;
+ itemTime += item->delta;
+
+ PRINTF("\tdelta: %d\tabs: %d\t", item->delta, itemTime);
+
+ switch (item->evt.type)
+ {
+ case AL_NOTE_END_EVT:
+ PRINTF("NOTE_END\tvox: %x\n", item->evt.msg.note.voice);
+ break;
+
+ case AL_SEQP_MIDI_EVT:
+ PRINTF("SEQP_MIDI\t%s\n", MidiStatus2Str(item->evt.msg.midi.status & AL_MIDI_StatusMask, str));
+ break;
+
+ case AL_SEQP_PRIORITY_EVT:
+ PRINTF("SEQP_PRIORITY\n");
+ break;
+
+ default:
+ PRINTF("type: %d\n", item->evt.type);
+ break;
+ }
+
+ }
+ PRINTF("\n");
+
+}
+
+char *
+MidiStatus2Str (char status, char *str)
+{
+ switch (status)
+ {
+ case AL_MIDI_NoteOn:
+ sprintf(str, "note on");
+ break;
+
+ case AL_MIDI_NoteOff:
+ sprintf(str, "note off");
+ break;
+
+ default:
+ sprintf(str, "status:%d", status);
+ break;
+ }
+
+ return str;
+}
+
+#endif /* _DEBUG_INTERNAL */
+
+
+
diff --git a/lib/ultralib/src/audio/filter.c b/lib/ultralib/src/audio/filter.c
new file mode 100644
index 0000000..d88460b
--- /dev/null
+++ b/lib/ultralib/src/audio/filter.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * filter.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+
+void alFilterNew(ALFilter *f, ALCmdHandler h, ALSetParam s, s32 type)
+{
+ f->source = 0;
+ f->handler = h;
+ f->setParam = s;
+ f->inp = 0;
+ f->outp = 0;
+ f->type = type;
+}
diff --git a/lib/ultralib/src/audio/heapalloc.c b/lib/ultralib/src/audio/heapalloc.c
new file mode 100644
index 0000000..8a37808
--- /dev/null
+++ b/lib/ultralib/src/audio/heapalloc.c
@@ -0,0 +1,65 @@
+/*====================================================================
+ * heapalloc.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void *alHeapDBAlloc(u8 *file, s32 line, ALHeap *hp, s32 num, s32 size)
+{
+ s32 bytes;
+ u8 *ptr = 0;
+
+ bytes = (num*size + AL_CACHE_ALIGN) & ~AL_CACHE_ALIGN;
+
+#ifdef _DEBUG
+ hp->count++;
+ bytes += sizeof(HeapInfo);
+#endif
+
+ if ((hp->cur + bytes) <= (hp->base + hp->len)) {
+
+ ptr = hp->cur;
+ hp->cur += bytes;
+
+#ifdef _DEBUG
+ ((HeapInfo *)ptr)->magic = AL_HEAP_MAGIC;
+ ((HeapInfo *)ptr)->size = bytes;
+ ((HeapInfo *)ptr)->count = hp->count;
+ if (file) {
+ ((HeapInfo *)ptr)->file = file;
+ ((HeapInfo *)ptr)->line = line;
+ } else {
+ ((HeapInfo *)ptr)->file = (u8 *) "unknown";
+ ((HeapInfo *)ptr)->line = 0;
+ }
+
+ ptr += sizeof(HeapInfo);
+#endif
+
+ } else {
+#ifdef _DEBUG
+ __osError(ERR_ALHEAPNOFREE, 1, size);
+#endif
+ }
+
+ return ptr;
+}
diff --git a/lib/ultralib/src/audio/heapcheck.c b/lib/ultralib/src/audio/heapcheck.c
new file mode 100644
index 0000000..baae643
--- /dev/null
+++ b/lib/ultralib/src/audio/heapcheck.c
@@ -0,0 +1,71 @@
+/*====================================================================
+ * heapcheck.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+
+#ifdef AUD_PROFILE
+#include <os.h>
+extern u32 cnt_index, heap_num, heap_cnt, heap_max, heap_min, lastCnt[];
+#endif
+
+s32 alHeapCheck(ALHeap *hp)
+{
+ s32 rv = 0;
+ HeapInfo *hi;
+ HeapInfo *last = 0;
+ u8 *ptr;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+#ifdef _DEBUG
+ for (ptr = hp->base; ptr < hp->cur; ptr += hi->size){
+
+ hi = (HeapInfo *)ptr;
+
+ if ( hi->magic != AL_HEAP_MAGIC) {
+ if (last) {
+ __osError(ERR_ALHEAPCORRUPT, 0);
+ } else {
+ __osError(ERR_ALHEAPFIRSTBLOCK, 0);
+ }
+
+ rv = 1;
+#ifdef AUD_PROFILE
+ PROFILE_AUD(heap_num, heap_cnt, heap_max, heap_min);
+#endif
+ return rv;
+ }
+
+ last = hi;
+
+ }
+#endif
+#ifdef AUD_PROFILE
+ PROFILE_AUD(heap_num, heap_cnt, heap_max, heap_min);
+#endif
+ return rv;
+}
+
+
diff --git a/lib/ultralib/src/audio/heapinit.c b/lib/ultralib/src/audio/heapinit.c
new file mode 100644
index 0000000..9053375
--- /dev/null
+++ b/lib/ultralib/src/audio/heapinit.c
@@ -0,0 +1,37 @@
+/*====================================================================
+ * heapinit.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <libaudio.h>
+
+void alHeapInit(ALHeap *hp, u8 *base, s32 len)
+{
+ s32 extraAlign = (AL_CACHE_ALIGN+1) - ((s32) base & AL_CACHE_ALIGN);
+
+ if (extraAlign != AL_CACHE_ALIGN+1)
+ hp->base = base + extraAlign;
+ else
+ hp->base = base;
+
+ hp->len = len;
+ hp->cur = hp->base;
+ hp->count = 0;
+}
+
diff --git a/lib/ultralib/src/audio/initfx.h b/lib/ultralib/src/audio/initfx.h
new file mode 100644
index 0000000..704e1f4
--- /dev/null
+++ b/lib/ultralib/src/audio/initfx.h
@@ -0,0 +1,59 @@
+/*====================================================================
+ * initfx.h
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#ifndef __initfx__
+#define __initfx__
+
+#define MAX_L0 AL_FX_BUFFER_SIZE/4
+#define MAX_L1 AL_FX_BUFFER_SIZE/4
+#define MAX_L2 AL_FX_BUFFER_SIZE/2
+
+#define L0_INC MAX_L0/128
+#define L1_INC MAX_L1/128
+#define L2_INC MAX_L2/128
+
+#define SMALLROOM_SECT_CNT 3
+#define SMALLROOM_SIZE AL_FX_BUFFER_SIZE
+#define SMALLROOM_L0 880 /* 22 ms */
+#define SMALLROOM_C0 9830
+#define SMALLROOM_L1 1400 /* 35 ms */
+#define SMALLROOM_C1 3276
+#define SMALLROOM_L2 2640 /* 66 ms */
+#define SMALLROOM_C2 10000
+#define SMALLROOM_FILT_CNT 1
+#define SMALLROOM_FC0 0x4000 /* .25 */
+
+#define BIGROOM_SECT_CNT 3
+#define BIGROOM_SIZE AL_FX_BUFFER_SIZE
+#define BIGROOM_L0 1408 /* 32 ms */
+#define BIGROOM_C0 9830
+#define BIGROOM_L1 1984 /* 45 ms */
+#define BIGROOM_C1 9830
+#define BIGROOM_L2 3792 /* 86 ms */
+#define BIGROOM_C2 12000
+#define BIGROOM_FILT_CNT 1
+#define BIGROOM_FC0 0x4000 /* .25 */
+
+#define ECHO_SIZE AL_FX_BUFFER_SIZE
+#define ECHO_SECT_CNT 1
+#define ECHO_L0 7936 /* 180 ms */
+#define ECHO_C0 0x6000
+
+#endif
diff --git a/lib/ultralib/src/audio/load.c b/lib/ultralib/src/audio/load.c
new file mode 100644
index 0000000..af07075
--- /dev/null
+++ b/lib/ultralib/src/audio/load.c
@@ -0,0 +1,471 @@
+/*====================================================================
+ * load.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+#include <os.h>
+#include <R4300.h>
+
+#ifndef MIN
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifdef AUD_PROFILE
+extern u32 cnt_index, adpcm_num, adpcm_cnt, adpcm_max, adpcm_min, lastCnt[];
+#endif
+
+#define ADPCMFBYTES 9
+#define LFSAMPLES 4
+
+static
+Acmd *_decodeChunk(Acmd *ptr, ALLoadFilter *f, s32 tsam, s32 nbytes, s16 outp, s16 inp, u32 flags);
+
+Acmd *alAdpcmPull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset, Acmd *p)
+{
+ Acmd *ptr = p;
+ s16 inp;
+ s32 tsam;
+ s32 nframes;
+ s32 nbytes;
+ s32 overFlow;
+ s32 startZero;
+ s32 nOver;
+ s32 nSam;
+ s32 op;
+ s32 nLeft;
+ s32 bEnd;
+ s32 decoded = 0;
+ s32 looped = 0;
+
+ ALLoadFilter *f = (ALLoadFilter *)filter;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ if (outCount == 0)
+ return ptr;
+
+ inp = AL_DECODER_IN;
+ aLoadADPCM(ptr++, f->bookSize,
+ K0_TO_PHYS(f->table->waveInfo.adpcmWave.book->book));
+
+ looped = (outCount + f->sample > f->loop.end) && (f->loop.count != 0);
+ if (looped)
+ nSam = f->loop.end - f->sample;
+ else
+ nSam = outCount;
+
+ if (f->lastsam)
+ nLeft = ADPCMFSIZE - f->lastsam;
+ else
+ nLeft = 0;
+ tsam = nSam - nLeft;
+ if (tsam<0) tsam = 0;
+
+ nframes = (tsam+ADPCMFSIZE-1)>>LFSAMPLES;
+ nbytes = nframes*ADPCMFBYTES;
+
+ if (looped){
+
+ ptr = _decodeChunk(ptr, f, tsam, nbytes, *outp, inp, f->first);
+
+ /*
+ * Fix up output pointer, which will be used as the input pointer
+ * by the following module.
+ */
+ if (f->lastsam)
+ *outp += (f->lastsam<<1);
+ else
+ *outp += (ADPCMFSIZE<<1);
+
+ /*
+ * Now fix up state info to reflect the loop start point
+ */
+ f->lastsam = f->loop.start &0xf;
+ f->memin = (s32) f->table->base + ADPCMFBYTES *
+ ((s32) (f->loop.start>>LFSAMPLES) + 1);
+ f->sample = f->loop.start;
+
+ bEnd = *outp;
+ while (outCount > nSam){
+
+ outCount -= nSam;
+
+ /*
+ * Put next one after the end of the last lot - on the
+ * frame boundary (32 byte) after the end.
+ */
+ op = (bEnd + ((nframes+1)<<(LFSAMPLES+1))) & ~0x1f;
+
+ /*
+ * The actual end of data
+ */
+ bEnd += (nSam<<1);
+
+ /*
+ * -1 is loop forever - the loop count is not exact now
+ * for small loops!
+ */
+ if ((f->loop.count != -1) && (f->loop.count != 0))
+ f->loop.count--;
+
+ /*
+ * What's left to compute.
+ */
+ nSam = MIN(outCount, f->loop.end - f->loop.start);
+ tsam = nSam - ADPCMFSIZE + f->lastsam;
+ if (tsam<0) tsam = 0;
+ nframes = (tsam+ADPCMFSIZE-1)>>LFSAMPLES;
+ nbytes = nframes*ADPCMFBYTES;
+ ptr = _decodeChunk(ptr, f, tsam, nbytes, op, inp, f->first | A_LOOP);
+ /*
+ * Merge the two sections in DMEM.
+ */
+ aDMEMMove(ptr++, op+(f->lastsam<<1), bEnd, nSam<<1);
+
+ }
+
+ f->lastsam = (outCount + f->lastsam) & 0xf;
+ f->sample += outCount;
+ f->memin += ADPCMFBYTES*nframes;
+#ifdef AUD_PROFILE
+ PROFILE_AUD(adpcm_num, adpcm_cnt, adpcm_max, adpcm_min);
+#endif
+ return ptr;
+ }
+
+ /*
+ * The unlooped case, which is executed most of the time
+ */
+
+ nSam = nframes<<LFSAMPLES;
+
+ /*
+ * overFlow is the number of bytes past the end
+ * of the bitstream I try to generate
+ */
+ overFlow = f->memin + nbytes - ((s32) f->table->base + f->table->len);
+ if (overFlow < 0)
+ overFlow = 0;
+ nOver = (overFlow/ADPCMFBYTES)<<LFSAMPLES;
+ if (nOver > nSam + nLeft)
+ nOver = nSam + nLeft;
+
+ nbytes -= overFlow;
+
+ if ((nOver - (nOver & 0xf))< outCount){
+ decoded = 1;
+ ptr = _decodeChunk(ptr, f, nSam - nOver, nbytes, *outp, inp, f->first);
+
+ if (f->lastsam)
+ *outp += (f->lastsam<<1);
+ else
+ *outp += (ADPCMFSIZE<<1);
+
+ f->lastsam = (outCount + f->lastsam) & 0xf;
+ f->sample += outCount;
+ f->memin += ADPCMFBYTES*nframes;
+ } else {
+ f->lastsam = 0;
+ f->memin += ADPCMFBYTES*nframes;
+ }
+
+ /*
+ * Put zeros in if necessary
+ */
+ if (nOver){
+ f->lastsam = 0;
+ if (decoded)
+ startZero = (nLeft + nSam - nOver)<<1;
+ else
+ startZero = 0;
+ aClearBuffer(ptr++, startZero + *outp, nOver<<1);
+ }
+#ifdef AUD_PROFILE
+ PROFILE_AUD(adpcm_num, adpcm_cnt, adpcm_max, adpcm_min);
+#endif
+
+ return ptr;
+}
+
+Acmd *alRaw16Pull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset, Acmd *p)
+{
+ Acmd *ptr = p;
+ s32 nbytes;
+ s32 dramLoc;
+ s32 dramAlign;
+ s32 dmemAlign;
+ s32 overFlow;
+ s32 startZero;
+ s32 nSam;
+ s32 op;
+
+ ALLoadFilter *f = (ALLoadFilter *)filter;
+ ALFilter *a = (ALFilter *) filter;
+
+ if (outCount == 0)
+ return ptr;
+
+ if ((outCount + f->sample > f->loop.end) && (f->loop.count != 0)){
+
+ nSam = f->loop.end - f->sample;
+ nbytes = nSam<<1;
+ if (nSam > 0){
+ dramLoc = (f->dma)(f->memin, nbytes, f->dmaState);
+
+ /*
+ * Make sure enough is loaded into DMEM to take care
+ * of 8 byte alignment
+ */
+ dramAlign = dramLoc & 0x7;
+ nbytes += dramAlign;
+ aSetBuffer(ptr++, 0, *outp, 0, nbytes + 8 - (nbytes & 0x7));
+ aLoadBuffer(ptr++, dramLoc - dramAlign);
+ } else
+ dramAlign = 0;
+
+ /*
+ * Fix up output pointer to allow for dram alignment
+ */
+ *outp += dramAlign;
+
+ f->memin = (s32) f->table->base + (f->loop.start<<1);
+ f->sample = f->loop.start;
+ op = *outp;
+
+ while (outCount > nSam){
+
+ op += (nSam<<1);
+ outCount -= nSam;
+ /*
+ * -1 is loop forever
+ */
+ if ((f->loop.count != -1) && (f->loop.count != 0))
+ f->loop.count--;
+
+ /*
+ * What to compute.
+ */
+ nSam = MIN(outCount, f->loop.end - f->loop.start);
+ nbytes = nSam<<1;
+
+ /*
+ * Do the next section, same as last.
+ */
+ dramLoc = (f->dma)(f->memin, nbytes, f->dmaState);
+
+ /*
+ * Make sure enough is loaded into DMEM to take care
+ * of 8 byte alignment
+ */
+ dramAlign = dramLoc & 0x7;
+ nbytes += dramAlign;
+ if (op & 0x7)
+ dmemAlign = 8 - (op & 0x7);
+ else
+ dmemAlign = 0;
+
+ aSetBuffer(ptr++, 0, op + dmemAlign, 0, nbytes + 8 - (nbytes & 0x7));
+ aLoadBuffer(ptr++, dramLoc - dramAlign);
+
+ /*
+ * Merge the two sections in DMEM.
+ */
+ if (dramAlign || dmemAlign)
+ aDMEMMove(ptr++, op+dramAlign+dmemAlign, op, nSam<<1);
+
+ }
+
+ f->sample += outCount;
+ f->memin += (outCount<<1);
+
+ return ptr;
+ }
+
+ /*
+ * The unlooped case, which is executed most of the time
+ *
+ * overFlow is the number of bytes past the end
+ * of the bitstream I try to generate
+ */
+
+ nbytes = outCount<<1;
+ overFlow = f->memin + nbytes - ((s32) f->table->base + f->table->len);
+ if (overFlow < 0)
+ overFlow = 0;
+ if (overFlow > nbytes)
+ overFlow = nbytes;
+
+ if (overFlow < nbytes){
+ if (outCount > 0){
+ nbytes -= overFlow;
+ dramLoc = (f->dma)(f->memin, nbytes, f->dmaState);
+
+ /*
+ * Make sure enough is loaded into DMEM to take care
+ * of 8 byte alignment
+ */
+ dramAlign = dramLoc & 0x7;
+ nbytes += dramAlign;
+ aSetBuffer(ptr++, 0, *outp, 0, nbytes + 8 - (nbytes & 0x7));
+ aLoadBuffer(ptr++, dramLoc - dramAlign);
+ } else
+ dramAlign = 0;
+ *outp += dramAlign;
+
+ f->sample += outCount;
+ f->memin += outCount<<1;
+ } else {
+ f->memin += outCount<<1;
+ }
+
+ /*
+ * Put zeros in if necessary
+ */
+ if (overFlow){
+ startZero = (outCount<<1) - overFlow;
+ if (startZero < 0)
+ startZero = 0;
+ aClearBuffer(ptr++, startZero + *outp, overFlow);
+ }
+ return ptr;
+}
+
+
+s32
+alLoadParam(void *filter, s32 paramID, void *param)
+{
+ ALLoadFilter *a = (ALLoadFilter *) filter;
+ ALFilter *f = (ALFilter *) filter;
+
+ switch (paramID) {
+ case (AL_FILTER_SET_WAVETABLE):
+ a->table = (ALWaveTable *) param;
+ a->memin = (s32) a->table->base;
+ a->sample = 0;
+ switch (a->table->type){
+ case (AL_ADPCM_WAVE):
+
+ /*
+ * Set up the correct handler
+ */
+ f->handler = alAdpcmPull;
+
+ /*
+ * Make sure the table length is an integer number of
+ * frames
+ */
+ a->table->len = ADPCMFBYTES *
+ ((s32) (a->table->len/ADPCMFBYTES));
+
+ a->bookSize = 2*a->table->waveInfo.adpcmWave.book->order*
+ a->table->waveInfo.adpcmWave.book->npredictors*ADPCMVSIZE;
+ if (a->table->waveInfo.adpcmWave.loop) {
+ a->loop.start = a->table->waveInfo.adpcmWave.loop->start;
+ a->loop.end = a->table->waveInfo.adpcmWave.loop->end;
+ a->loop.count = a->table->waveInfo.adpcmWave.loop->count;
+ alCopy(a->table->waveInfo.adpcmWave.loop->state,
+ a->lstate, sizeof(ADPCM_STATE));
+ } else {
+ a->loop.start = a->loop.end = a->loop.count = 0;
+ }
+ break;
+
+ case (AL_RAW16_WAVE):
+ f->handler = alRaw16Pull;
+ if (a->table->waveInfo.rawWave.loop) {
+ a->loop.start = a->table->waveInfo.rawWave.loop->start;
+ a->loop.end = a->table->waveInfo.rawWave.loop->end;
+ a->loop.count = a->table->waveInfo.rawWave.loop->count;
+ } else {
+ a->loop.start = a->loop.end = a->loop.count = 0;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ break;
+
+ case (AL_FILTER_RESET):
+ a->lastsam = 0;
+ a->first = 1;
+ a->sample = 0;
+
+ /* sct 2/14/96 - Check table since it is initialized to null and */
+ /* Get loop info according to table type. */
+ if (a->table)
+ {
+ a->memin = (s32) a->table->base;
+ if (a->table->type == AL_ADPCM_WAVE)
+ {
+ if (a->table->waveInfo.adpcmWave.loop)
+ a->loop.count = a->table->waveInfo.adpcmWave.loop->count;
+ }
+ else if (a->table->type == AL_RAW16_WAVE)
+ {
+ if (a->table->waveInfo.rawWave.loop)
+ a->loop.count = a->table->waveInfo.rawWave.loop->count;
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+Acmd *_decodeChunk(Acmd *ptr, ALLoadFilter *f, s32 tsam, s32 nbytes, s16 outp, s16 inp, u32 flags)
+
+{
+
+ s32
+ dramAlign,
+ dramLoc;
+
+ if (nbytes > 0){
+ dramLoc = (f->dma)(f->memin, nbytes, f->dmaState);
+ /*
+ * Make sure enough is loaded into DMEM to take care
+ * of 8 byte alignment
+ */
+ dramAlign = dramLoc & 0x7;
+ nbytes += dramAlign;
+ aSetBuffer(ptr++, 0, inp, 0, nbytes + 8 - (nbytes & 0x7));
+ aLoadBuffer(ptr++, dramLoc - dramAlign);
+ } else
+ dramAlign = 0;
+
+ if (flags & A_LOOP){
+ aSetLoop(ptr++, K0_TO_PHYS(f->lstate));
+ }
+
+ aSetBuffer(ptr++, 0, inp + dramAlign, outp, tsam<<1);
+ aADPCMdec(ptr++, flags, K0_TO_PHYS(f->state));
+ f->first = 0;
+
+ return ptr;
+}
+
+
+
diff --git a/lib/ultralib/src/audio/mainbus.c b/lib/ultralib/src/audio/mainbus.c
new file mode 100644
index 0000000..d5c8eca
--- /dev/null
+++ b/lib/ultralib/src/audio/mainbus.c
@@ -0,0 +1,67 @@
+/*====================================================================
+ * mainbus.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+
+Acmd *alMainBusPull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset, Acmd *p)
+{
+ Acmd *ptr = p;
+ ALMainBus *m = (ALMainBus *)filter;
+ ALFilter **sources = m->sources;
+ s32 i;
+
+ /*
+ * clear the output buffers here
+ */
+ aClearBuffer(ptr++, AL_MAIN_L_OUT, outCount<<1);
+ aClearBuffer(ptr++, AL_MAIN_R_OUT, outCount<<1);
+
+ for (i = 0; i < m->sourceCount; i++) {
+ ptr = (sources[i]->handler)(sources[i], outp, outCount, sampleOffset,
+ ptr);
+ aSetBuffer(ptr++, 0, 0, 0, outCount<<1);
+ aMix(ptr++, 0, 0x7fff, AL_AUX_L_OUT, AL_MAIN_L_OUT);
+ aMix(ptr++, 0, 0x7fff, AL_AUX_R_OUT, AL_MAIN_R_OUT);
+ }
+
+ return ptr;
+}
+
+s32 alMainBusParam(void *filter, s32 paramID, void *param)
+{
+ ALMainBus *m = (ALMainBus *) filter;
+ ALFilter **sources = m->sources;
+
+ switch (paramID) {
+
+ case (AL_FILTER_ADD_SOURCE):
+ sources[m->sourceCount++] = (ALFilter *) param;
+ break;
+
+ default:
+ /* ??? */
+ break;
+ }
+
+ return 0;
+
+}
+
diff --git a/lib/ultralib/src/audio/parse_abi.c b/lib/ultralib/src/audio/parse_abi.c
new file mode 100644
index 0000000..f1fd37d
--- /dev/null
+++ b/lib/ultralib/src/audio/parse_abi.c
@@ -0,0 +1,47 @@
+#include <ultra64.h>
+#include <libaudio.h>
+#include <ultrahost.h>
+#include <gu.h>
+
+#ifndef _FINALROM
+void alParseAbiCL(Acmd *cmdList, u32 nbytes)
+{
+ guDLPrintCB cntlBlk;
+
+ cntlBlk.dataSize = nbytes;
+ cntlBlk.flags = 0;
+ cntlBlk.dlType = GU_PARSE_ABI_TYPE;
+ cntlBlk.paddr = osVirtualToPhysical(cmdList);
+
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+ osWriteHost(cmdList,nbytes);
+
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ultralib/src/audio/resample.c b/lib/ultralib/src/audio/resample.c
new file mode 100644
index 0000000..2baf26f
--- /dev/null
+++ b/lib/ultralib/src/audio/resample.c
@@ -0,0 +1,150 @@
+/*====================================================================
+ * resample.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+#include <os.h>
+#include <stdio.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.49 $"
+
+#ifdef AUD_PROFILE
+extern u32 cnt_index, resampler_num, resampler_cnt, resampler_max, resampler_min, lastCnt[];
+#endif
+
+/***********************************************************************
+ * Resampler filter public interfaces
+ ***********************************************************************/
+Acmd *alResamplePull(void *filter, s16 *outp, s32 outCnt, s32 sampleOffset, Acmd *p)
+{
+ ALResampler *f = (ALResampler *)filter;
+ Acmd *ptr = p;
+ s16 inp;
+ s32 inCount;
+ ALFilter *source = f->filter.source;
+ s32 incr;
+ f32 finCount;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ inp = AL_DECODER_OUT;
+
+ if (!outCnt)
+ return ptr;
+
+ /*
+ * check if resampler is required
+ */
+ if (f->upitch) {
+
+ ptr = (*source->handler)(source, &inp, outCnt, sampleOffset, p);
+ aDMEMMove(ptr++, inp, *outp, outCnt<<1);
+
+ } else {
+
+ /*
+ * clip to maximum allowable pitch
+ * FIXME: should we check for some minimum as well?
+ */
+ if (f->ratio > MAX_RATIO) f->ratio = MAX_RATIO;
+
+ /*
+ * quantize the pitch
+ */
+ f->ratio = (s32)(f->ratio * UNITY_PITCH);
+ f->ratio = f->ratio / UNITY_PITCH;
+
+ /*
+ * determine how many samples to generate
+ */
+ finCount = f->delta + (f->ratio * (f32) outCnt);
+ inCount = (s32) finCount;
+ f->delta = finCount - (f32)inCount;
+
+ /*
+ * ask all filters upstream from us to build their command
+ * lists.
+ */
+ ptr = (*source->handler)(source, &inp, inCount, sampleOffset, p);
+
+ /*
+ * construct our portion of the command list
+ */
+ incr = (s32)(f->ratio * UNITY_PITCH);
+ aSetBuffer(ptr++, 0, inp, *outp, outCnt<<1);
+ aResample(ptr++, f->first, incr, osVirtualToPhysical(f->state));
+ f->first = 0;
+ }
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(resampler_num, resampler_cnt, resampler_max, resampler_min);
+#endif
+ return ptr;
+}
+
+s32 alResampleParam(void *filter, s32 paramID, void *param)
+{
+ ALFilter *f = (ALFilter *) filter;
+ ALResampler *r = (ALResampler *) filter;
+ union {
+ f32 f;
+ s32 i;
+ } data;
+
+ switch (paramID) {
+
+ case (AL_FILTER_SET_SOURCE):
+ f->source = (ALFilter *) param;
+ break;
+
+ case (AL_FILTER_RESET):
+ r->delta = 0.0;
+ r->first = 1;
+ r->motion = AL_STOPPED;
+ r->upitch = 0;
+ if (f->source)
+ (*f->source->setParam)(f->source, AL_FILTER_RESET, 0);
+ break;
+
+ case (AL_FILTER_START):
+ r->motion = AL_PLAYING;
+ if (f->source)
+ (*f->source->setParam)(f->source, AL_FILTER_START, 0);
+ break;
+
+ case (AL_FILTER_SET_PITCH):
+ data.i = (s32) param;
+ r->ratio = data.f;
+ break;
+
+ case (AL_FILTER_SET_UNITY_PITCH):
+ r->upitch = 1;
+ break;
+
+ default:
+ if (f->source)
+ (*f->source->setParam)(f->source, paramID, param);
+ break;
+ }
+ return 0;
+}
diff --git a/lib/ultralib/src/audio/reverb.c b/lib/ultralib/src/audio/reverb.c
new file mode 100644
index 0000000..292ed0f
--- /dev/null
+++ b/lib/ultralib/src/audio/reverb.c
@@ -0,0 +1,457 @@
+/*====================================================================
+ * reverb.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include <ultraerror.h>
+#include "synthInternals.h"
+#include <os.h>
+#include <os_internal.h>
+#include <stdio.h>
+#include <assert.h>
+#include "initfx.h"
+
+// TODO: these come from headers
+#ident "$Revision: 1.49 $"
+#ident "$Revision: 1.17 $"
+
+#define RANGE 2.0
+extern ALGlobals *alGlobals;
+
+#ifdef AUD_PROFILE
+extern u32 cnt_index, reverb_num, reverb_cnt, reverb_max, reverb_min, lastCnt[];
+extern u32 load_num, load_cnt, load_max, load_min, save_num, save_cnt, save_max, save_min;
+#endif
+
+/*
+ * macros
+ */
+#define SWAP(in, out) \
+{ \
+ s16 t = out; \
+ out = in; \
+ in = t; \
+}
+
+
+
+Acmd *_loadOutputBuffer(ALFx *r, ALDelay *d, s32 buff, s32 incount, Acmd *p);
+Acmd *_loadBuffer(ALFx *r, s16 *curr_ptr, s32 buff, s32 count, Acmd *p);
+Acmd *_saveBuffer(ALFx *r, s16 *curr_ptr, s32 buff, s32 count, Acmd *p);
+Acmd *_filterBuffer(ALLowPass *lp, s32 buff, s32 count, Acmd *p);
+f32 _doModFunc(ALDelay *d, s32 count);
+
+static s32 L_INC[] = { L0_INC, L1_INC, L2_INC };
+
+/***********************************************************************
+ * Reverb filter public interfaces
+ ***********************************************************************/
+Acmd *alFxPull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset,
+ Acmd *p)
+{
+ Acmd *ptr = p;
+ ALFx *r = (ALFx *)filter;
+ ALFilter *source = r->filter.source;
+ s16 i, buff1, buff2, input, output;
+ s16 *in_ptr, *out_ptr, gain, *prev_out_ptr = 0;
+ ALDelay *d, *pd;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+#ifdef _DEBUG
+ assert(source);
+#endif
+
+ /*
+ * pull channels going into this effect first
+ */
+ ptr = (*source->handler)(source, outp, outCount, sampleOffset, p);
+
+ input = AL_AUX_L_OUT;
+ output = AL_AUX_R_OUT;
+ buff1 = AL_TEMP_0;
+ buff2 = AL_TEMP_1;
+
+ aSetBuffer(ptr++, 0, 0, 0, outCount<<1); /* set the buffer size */
+ aMix(ptr++, 0, 0xda83, AL_AUX_L_OUT, input); /* .707L = L - .293L */
+ aMix(ptr++, 0, 0x5a82, AL_AUX_R_OUT, input); /* mix the AuxL and AuxR into the AuxL */
+ /* and write the mixed value to the delay line at r->input */
+ ptr = _saveBuffer(r, r->input, input, outCount, ptr);
+
+ aClearBuffer(ptr++, output, outCount<<1); /* clear the AL_AUX_R_OUT */
+
+ for (i = 0; i < r->section_count; i++) {
+ d = &r->delay[i]; /* get the ALDelay structure */
+ in_ptr = &r->input[-d->input];
+ out_ptr = &r->input[-d->output];
+
+ if (in_ptr == prev_out_ptr) {
+ SWAP(buff1, buff2);
+ } else { /* load data at in_ptr into buff1 */
+ ptr = _loadBuffer(r, in_ptr, buff1, outCount, ptr);
+ }
+ ptr = _loadOutputBuffer(r, d, buff2, outCount, ptr);
+
+ if (d->ffcoef) {
+ aMix(ptr++, 0, (u16)d->ffcoef, buff1, buff2);
+ if (!d->rs && !d->lp) {
+ ptr = _saveBuffer(r, out_ptr, buff2, outCount, ptr);
+ }
+ }
+
+ if (d->fbcoef) {
+ aMix(ptr++, 0, (u16)d->fbcoef, buff2, buff1);
+ ptr = _saveBuffer(r, in_ptr, buff1, outCount, ptr);
+ }
+
+ if (d->lp)
+ ptr = _filterBuffer(d->lp, buff2, outCount, ptr);
+
+ if (!d->rs)
+ ptr = _saveBuffer(r, out_ptr, buff2, outCount, ptr);
+
+ if (d->gain)
+ aMix(ptr++, 0, (u16)d->gain, buff2, output);
+
+ prev_out_ptr = &r->input[d->output];
+ }
+
+ /*
+ * bump the master delay line input pointer
+ * modulo the length
+ */
+ r->input += outCount;
+ if (r->input > &r->base[r->length])
+ r->input -= r->length;
+
+ /*
+ * output already in AL_AUX_R_OUT
+ * just copy to AL_AUX_L_OUT
+ */
+ aDMEMMove(ptr++, output, AL_AUX_L_OUT, outCount<<1);
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(reverb_num, reverb_cnt, reverb_max, reverb_min);
+#endif
+ return ptr;
+}
+
+s32 alFxParam(void *filter, s32 paramID, void *param)
+{
+ if(paramID == AL_FILTER_SET_SOURCE)
+ {
+ ALFilter *f = (ALFilter *) filter;
+ f->source = (ALFilter*) param;
+ }
+ return 0;
+}
+
+/*
+ * This routine gets called by alSynSetFXParam. No checking takes place to
+ * verify the validity of the paramID or the param value. input and output
+ * values must be 8 byte aligned, so round down any param passed.
+ */
+s32 alFxParamHdl(void *filter, s32 paramID, void *param)
+{
+ ALFx *f = (ALFx *) filter;
+ s32 p = (paramID - 2) % 8;
+ s32 s = (paramID - 2) / 8;
+ s32 val = *(s32*)param;
+
+#define INPUT_PARAM 0
+#define OUTPUT_PARAM 1
+#define FBCOEF_PARAM 2
+#define FFCOEF_PARAM 3
+#define GAIN_PARAM 4
+#define CHORUSRATE_PARAM 5
+#define CHORUSDEPTH_PARAM 6
+#define LPFILT_PARAM 7
+
+ switch(p)
+ {
+ case INPUT_PARAM:
+ f->delay[s].input = (u32)val & 0xFFFFFFF8;
+ break;
+ case OUTPUT_PARAM:
+ f->delay[s].output = (u32)val & 0xFFFFFFF8;
+ break;
+ case FFCOEF_PARAM:
+ f->delay[s].ffcoef = (s16)val;
+ break;
+ case FBCOEF_PARAM:
+ f->delay[s].fbcoef = (s16)val;
+ break;
+ case GAIN_PARAM:
+ f->delay[s].gain = (s16)val;
+ break;
+ case CHORUSRATE_PARAM:
+ /* f->delay[s].rsinc = ((f32)val)/0xffffff; */
+ f->delay[s].rsinc = ((((f32)val)/1000) * RANGE)/alGlobals->drvr.outputRate;
+ break;
+
+/*
+ * the following constant is derived from:
+ *
+ * ratio = 2^(cents/1200)
+ *
+ * and therefore for hundredths of a cent
+ * x
+ * ln(ratio) = ---------------
+ * (120,000)/ln(2)
+ * where
+ * 120,000/ln(2) = 173123.40...
+ */
+#define CONVERT 173123.404906676
+#define LENGTH (f->delay[s].output - f->delay[s].input)
+
+ case CHORUSDEPTH_PARAM:
+ /*f->delay[s].rsgain = (((f32)val) / CONVERT) * LENGTH; */
+ f->delay[s].rsgain = (((f32)val) / CONVERT) * LENGTH;
+ break;
+ case LPFILT_PARAM:
+ if(f->delay[s].lp)
+ {
+ f->delay[s].lp->fc = (s16)val;
+ _init_lpfilter(f->delay[s].lp);
+ }
+ break;
+ }
+ return 0;
+}
+
+Acmd *_loadOutputBuffer(ALFx *r, ALDelay *d, s32 buff, s32 incount, Acmd *p)
+{
+ Acmd *ptr = p;
+ s32 ratio, count, rbuff = AL_TEMP_2;
+ s16 *out_ptr;
+ f32 fincount, fratio, delta;
+ s32 ramalign = 0, length;
+ static f32 val=0.0, lastval=-10.0;
+ static f32 blob=0;
+/*
+ * The following section implements the chorus resampling. Modulate where you pull
+ * the samples from, since you need varying amounts of samples.
+ */
+ if (d->rs) {
+ length = d->output - d->input;
+ delta = _doModFunc(d, incount); /* get the number of samples to modulate by */
+ /*
+ * find ratio of delta to delay length and quantize
+ * to same resolution as resampler
+ */
+ delta /= length; /* convert delta from number of samples to a pitch ratio */
+ delta = (s32)(delta * UNITY_PITCH); /* quantize to value microcode will use */
+ delta = delta / UNITY_PITCH;
+ fratio = 1.0 - delta; /* pitch ratio needs to be centered around 1, not zero */
+
+ /* d->rs->delta is the difference between the fractional and integer value
+ * of the samples needed. fratio * incount + rs->delta gives the number of samples
+ * needed for this frame.
+ */
+ fincount = d->rs->delta + (fratio * (f32)incount);
+ count = (s32) fincount; /* quantize to s32 */
+ d->rs->delta = fincount - (f32)count; /* calculate the round off and store */
+
+ /*
+ * d->rsdelta is amount the out_ptr has deviated from its starting position.
+ * You calc the out_ptr by taking d->output - d->rsdelta, and then using the
+ * negative of that as an index into the delay buffer. loadBuffer that uses this
+ * value then bumps it up if it is below the delay buffer.
+ */
+ out_ptr = &r->input[-(d->output - d->rsdelta)];
+ ramalign = ((s32)out_ptr & 0x7) >> 1; /* calculate the number of samples needed
+ to align the buffer*/
+#ifdef _DEBUG
+#if 0
+ if(length > 0) {
+ if (length - d->rsdelta > (s32)r->length) {
+ __osError(ERR_ALMODDELAYOVERFLOW, 1, length - d->rsdelta - r->length);
+ }
+ }
+ else if(length < 0) {
+ if ((-length) - d->rsdelta > (s32)r->length) {
+ __osError(ERR_ALMODDELAYOVERFLOW, 1, (-length) - d->rsdelta - r->length);
+ }
+ }
+#endif
+#endif
+ /* load the rbuff with samples, note that there will be ramalign worth of
+ * samples at the begining which you don't care about. */
+ ptr = _loadBuffer(r, out_ptr - ramalign, rbuff, count + ramalign, ptr);
+
+ /* convert fratio to 16 bit fraction for microcode use */
+ ratio = (s32)(fratio * UNITY_PITCH);
+ /* set the buffers, and do the resample */
+ aSetBuffer(ptr++, 0, rbuff + (ramalign<<1), buff, incount<<1);
+ aResample(ptr++, d->rs->first, ratio, osVirtualToPhysical(d->rs->state));
+
+ d->rs->first = 0; /* turn off first time flag */
+ d->rsdelta += count - incount; /* add the number of samples to d->rsdelta */
+ } else {
+ out_ptr = &r->input[-d->output];
+ ptr = _loadBuffer(r, out_ptr, buff, incount, ptr);
+ }
+
+ return ptr;
+}
+/*
+ * This routine is for loading data from the delay line buff. If the
+ * address of curr_ptr < r->base, it will force it to be within r->base
+ * space, If the load goes past the end of r->base it will wrap around.
+ * Cause count bytes of data at curr_ptr (within the delay line) to be
+ * loaded into buff. (Buff is a dmem buffer)
+ */
+Acmd *_loadBuffer(ALFx *r, s16 *curr_ptr, s32 buff, s32 count, Acmd *p)
+{
+ Acmd *ptr = p;
+ s32 after_end, before_end;
+ s16 *updated_ptr, *delay_end;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ delay_end = &r->base[r->length];
+
+#ifdef _DEBUG
+ if(curr_ptr > delay_end)
+ __osError(ERR_ALMODDELAYOVERFLOW, 1, delay_end - curr_ptr);
+#endif
+
+ if (curr_ptr < r->base)
+ curr_ptr += r->length;
+ updated_ptr = curr_ptr + count;
+
+ if (updated_ptr > delay_end) {
+ after_end = updated_ptr - delay_end;
+ before_end = delay_end - curr_ptr;
+
+ aSetBuffer(ptr++, 0, buff, 0, before_end<<1);
+ aLoadBuffer(ptr++, osVirtualToPhysical(curr_ptr));
+ aSetBuffer(ptr++, 0, buff+(before_end<<1), 0, after_end<<1);
+ aLoadBuffer(ptr++, osVirtualToPhysical(r->base));
+ } else {
+ aSetBuffer(ptr++, 0, buff, 0, count<<1);
+ aLoadBuffer(ptr++, osVirtualToPhysical(curr_ptr));
+ }
+
+ aSetBuffer(ptr++, 0, 0, 0, count<<1);
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(load_num, load_cnt, load_max, load_min);
+#endif
+ return ptr;
+
+}
+
+/*
+ * This routine is for writing data to the delay line buff. If the
+ * address of curr_ptr < r->base, it will force it to be within r->base
+ * space. If the write goes past the end of r->base, it will wrap around
+ * Cause count bytes of data at buff to be written to delay line, curr_ptr.
+ */
+Acmd *_saveBuffer(ALFx *r, s16 *curr_ptr, s32 buff, s32 count, Acmd *p)
+{
+ Acmd *ptr = p;
+ s32 after_end, before_end;
+ s16 *updated_ptr, *delay_end;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ delay_end = &r->base[r->length];
+ if (curr_ptr < r->base) /* probably just security */
+ curr_ptr += r->length; /* shouldn't occur */
+ updated_ptr = curr_ptr + count;
+
+ if (updated_ptr > delay_end) { /* if the data wraps past end of r->base */
+ after_end = updated_ptr - delay_end;
+ before_end = delay_end - curr_ptr;
+
+ aSetBuffer(ptr++, 0, 0, buff, before_end<<1);
+ aSaveBuffer(ptr++, osVirtualToPhysical(curr_ptr));
+ aSetBuffer(ptr++, 0, 0, buff+(before_end<<1), after_end<<1);
+ aSaveBuffer(ptr++, osVirtualToPhysical(r->base));
+ aSetBuffer(ptr++, 0, 0, 0, count<<1);
+ } else {
+ aSetBuffer(ptr++, 0, 0, buff, count<<1);
+ aSaveBuffer(ptr++, osVirtualToPhysical(curr_ptr));
+ }
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(save_num, save_cnt, save_max, save_min);
+#endif
+ return ptr;
+
+}
+
+Acmd *_filterBuffer(ALLowPass *lp, s32 buff, s32 count, Acmd *p)
+{
+ Acmd *ptr = p;
+
+ aSetBuffer(ptr++, 0, buff, buff, count<<1);
+ aLoadADPCM(ptr++, 32, osVirtualToPhysical(lp->fcvec.fccoef));
+ aPoleFilter(ptr++, lp->first, lp->fgain, osVirtualToPhysical(lp->fstate));
+ lp->first = 0;
+
+ return ptr;
+}
+
+
+
+/*
+ * Generate a triangle wave from -1 to 1, and find the current position
+ * in the wave. (Rate of the wave is controlled by d->rsinc, which is chorus
+ * rate) Multiply the current triangle wave value by d->rsgain, (chorus depth)
+ * which is expressed in number of samples back from output pointer the chorus
+ * should go at it's full chorus. In otherwords, this function returns a number
+ * of samples the output pointer should modulate backwards.
+ */
+f32 _doModFunc(ALDelay *d, s32 count)
+{
+ f32 val;
+
+ /*
+ * generate bipolar sawtooth
+ * from -RANGE to +RANGE
+ */
+ d->rsval += d->rsinc * count;
+ d->rsval = (d->rsval > RANGE) ? d->rsval-(RANGE*2) : d->rsval;
+
+ /*
+ * convert to monopolar triangle
+ * from 0 to RANGE
+ */
+ val = d->rsval;
+ val = (val < 0) ? -val : val;
+
+ /*
+ * convert to bipolar triangle
+ * from -1 to 1
+ */
+ val -= RANGE/2;
+
+ return(d->rsgain * val);
+}
+
+
+
diff --git a/lib/ultralib/src/audio/save.c b/lib/ultralib/src/audio/save.c
new file mode 100644
index 0000000..bc15294
--- /dev/null
+++ b/lib/ultralib/src/audio/save.c
@@ -0,0 +1,73 @@
+/*====================================================================
+ * save.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "synthInternals.h"
+#include <os.h>
+#include <assert.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+Acmd *alSavePull(void *filter, s16 *outp, s32 outCount, s32 sampleOffset,
+ Acmd *p)
+
+{
+ Acmd *ptr = p;
+ ALSave *f = (ALSave *)filter;
+ ALFilter *source = f->filter.source;
+
+#ifdef _DEBUG
+ assert(f->filter.source);
+#endif
+
+ ptr = (*source->handler)(source, outp, outCount, sampleOffset, ptr);
+
+ aSetBuffer (ptr++, 0, 0, 0, outCount<<1);
+ aInterleave(ptr++, AL_MAIN_L_OUT, AL_MAIN_R_OUT);
+ aSetBuffer (ptr++, 0, 0, 0, outCount<<2);
+ aSaveBuffer(ptr++, f->dramout);
+ return ptr;
+}
+
+s32 alSaveParam(void *filter, s32 paramID, void *param)
+{
+ ALSave *a = (ALSave *) filter;
+ ALFilter *f = (ALFilter *) filter;
+ s32 pp = (s32) param;
+
+ switch (paramID) {
+ case (AL_FILTER_SET_SOURCE):
+ f->source = (ALFilter *) param;
+ break;
+
+ case (AL_FILTER_SET_DRAM):
+ a->dramout = pp;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+
+}
+
+
+
diff --git a/lib/ultralib/src/audio/seq.c b/lib/ultralib/src/audio/seq.c
new file mode 100644
index 0000000..5da5b11
--- /dev/null
+++ b/lib/ultralib/src/audio/seq.c
@@ -0,0 +1,343 @@
+/*====================================================================
+ * seq.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+#include "seq.h"
+
+
+#define IFF_FILE_HDR 0x4d546864 /* 'MThd' */
+#define IFF_TRACK_HDR 0x4d54726b /* 'MTrk' */
+
+static s32 readVarLen(ALSeq *s);
+static u8 read8(ALSeq *s);
+static s16 read16(ALSeq *s);
+static s32 read32(ALSeq *s);
+
+
+void alSeqNew(ALSeq *seq, u8 *ptr, s32 len)
+{
+ /*
+ * load the seqence pointed to by ptr
+ */
+ seq->base = ptr;
+ seq->len = len;
+ seq->lastStatus = 0;
+ seq->lastTicks = 0;
+ seq->curPtr = ptr;
+
+ if (read32(seq) != IFF_FILE_HDR) {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQNOTMIDI, 1, ptr);
+#endif
+ return;
+ }
+
+ read32(seq); /* skip the length field */
+
+ if (read16(seq) != 0) {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQNOTMIDI0, 1, ptr);
+#endif
+ return;
+ }
+
+ if (read16(seq) != 1) {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQNUMTRACKS, 1, ptr);
+#endif
+ return;
+ }
+
+ seq->division = read16(seq);
+ if (seq->division & 0x8000) {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQTIME, 1, ptr);
+#endif
+ return;
+ }
+
+ seq->qnpt = 1.0/(f32)seq->division;
+
+ if (read32(seq) != IFF_TRACK_HDR) {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQTRACKHDR, 1, ptr);
+#endif
+ return;
+ }
+
+ read32(seq); /* skip the length field */
+
+ seq->trackStart = seq->curPtr;
+}
+
+
+void alSeqNextEvent(ALSeq *seq, ALEvent *event)
+{
+ u8 status;
+ s16 delta;
+ s32 len;
+ s32 deltaTicks;
+ s32 i;
+
+#ifdef _DEBUG
+ /* sct 1/17/96 - Warn if curPtr is beyond the end of sequence. */
+ if (seq->curPtr >= seq->base + seq->len)
+ __osError(ERR_ALSEQOVERRUN, 0);
+#endif
+
+ deltaTicks = readVarLen(seq); /* read the delta time */
+ seq->lastTicks += deltaTicks;
+ status = read8(seq);
+
+#if _DEBUG
+ /*
+ * System exclusives are not supported, so just skip them and read
+ * the next event
+ */
+ if ((status == 0xf0) || (status == 0xf7)) {
+ __osError(ERR_ALSEQSYSEX, 0);
+ len = readVarLen(seq);
+ for (i = 0; i < len; i++) {
+ read8(seq);
+ }
+ alSeqNextEvent(seq,event);
+ return;
+ }
+#endif
+
+ if (status == AL_MIDI_Meta) {
+ u8 type = read8(seq);
+
+ if (type == AL_MIDI_META_TEMPO) {
+ event->type = AL_TEMPO_EVT;
+ event->msg.tempo.ticks = deltaTicks;
+ event->msg.tempo.status = status;
+ event->msg.tempo.type = type;
+ event->msg.tempo.len = read8(seq);
+ event->msg.tempo.byte1 = read8(seq);
+ event->msg.tempo.byte2 = read8(seq);
+ event->msg.tempo.byte3 = read8(seq);
+ } else if (type == AL_MIDI_META_EOT) {
+ event->type = AL_SEQ_END_EVT;
+ event->msg.end.ticks = deltaTicks;
+ event->msg.end.status = status;
+ event->msg.end.type = type;
+ event->msg.end.len = read8(seq);
+ } else {
+#ifdef _DEBUG
+ __osError(ERR_ALSEQMETA, 1, type);
+ len = readVarLen(seq);
+ for (i = 0; i < len; i++) {
+ read8(seq);
+ }
+ alSeqNextEvent(seq,event);
+ return;
+#endif
+ }
+
+ seq->lastStatus = 0;
+
+ } else {
+ event->type = AL_SEQ_MIDI_EVT;
+ event->msg.midi.ticks = deltaTicks;
+ if (status & 0x80) {
+ event->msg.midi.status = status;
+ event->msg.midi.byte1 = read8(seq);
+ seq->lastStatus = status;
+ } else {
+ /* running status */
+ event->msg.midi.status = seq->lastStatus;
+ event->msg.midi.byte1 = status;
+ }
+
+ if (((event->msg.midi.status & 0xf0) != AL_MIDI_ProgramChange) &&
+ ((event->msg.midi.status & 0xf0) != AL_MIDI_ChannelPressure)) {
+ event->msg.midi.byte2 = read8(seq);
+ } else {
+ event->msg.midi.byte2 = 0;
+ }
+ }
+}
+
+
+/*
+ Returns the delta time in ticks for the next event in the sequence.
+ Assumes that the sequence data pointer is pointing to the delta time.
+
+ If the curPtr is at or beyond the end of the sequence, then return FALSE
+ to indicate no next event.
+
+ sct 11/6/95
+*/
+char __alSeqNextDelta (ALSeq *seq, s32 *pDeltaTicks)
+{
+ u8 * savedPtr;
+
+ /* sct 1/16/96 - Put in safety check here to make sure we don't read past sequence data. */
+ if (seq->curPtr >= seq->base + seq->len)
+ return FALSE;
+
+ savedPtr = seq->curPtr;
+ *pDeltaTicks = readVarLen(seq); /* read the delta time */
+ seq->curPtr = savedPtr;
+
+ return TRUE;
+}
+
+
+f32 alSeqTicksToSec(ALSeq *seq, s32 ticks, u32 tempo)
+{
+ return ((f32) (((f32)(ticks) * (f32)(tempo)) /
+ ((f32)(seq->division) * 1000000.0)));
+}
+
+u32 alSeqSecToTicks(ALSeq *seq, f32 sec, u32 tempo)
+{
+ return (u32)(((sec * 1000000.0) * seq->division) / tempo);
+}
+
+void alSeqNewMarker(ALSeq *seq, ALSeqMarker *m, u32 ticks)
+{
+ ALEvent evt;
+ u8 *savePtr, *lastPtr;
+ s32 saveTicks, lastTicks;
+ s16 saveStatus, lastStatus;
+
+ /* does not check that ticks is within bounds */
+
+ if (ticks == 0) { /* common case */
+ m->curPtr = seq->trackStart;
+ m->lastStatus = 0;
+ m->lastTicks = 0;
+ m->curTicks = 0;
+ return;
+ } else {
+ savePtr = seq->curPtr;
+ saveStatus = seq->lastStatus;
+ saveTicks = seq->lastTicks;
+
+ seq->curPtr = seq->trackStart;
+ seq->lastStatus = 0;
+ seq->lastTicks = 0;
+
+ do {
+ lastPtr = seq->curPtr;
+ lastStatus = seq->lastStatus;
+ lastTicks = seq->lastTicks;
+
+ alSeqNextEvent(seq, &evt);
+
+ if (evt.type == AL_SEQ_END_EVT)
+ {
+ lastPtr = seq->curPtr;
+ lastStatus = seq->lastStatus;
+ lastTicks = seq->lastTicks;
+ break;
+ }
+
+ } while (seq->lastTicks < ticks);
+
+ m->curPtr = lastPtr;
+ m->lastStatus = lastStatus;
+ m->lastTicks = lastTicks;
+ m->curTicks = seq->lastTicks; /* Used by test loop condition. */
+
+ seq->curPtr = savePtr;
+ seq->lastStatus = saveStatus;
+ seq->lastTicks = saveTicks;
+
+ }
+}
+
+s32 alSeqGetTicks(ALSeq *seq)
+{
+ return seq->lastTicks;
+}
+
+void alSeqSetLoc(ALSeq *seq, ALSeqMarker *m)
+{
+ seq->curPtr = m->curPtr;
+ seq->lastStatus = m->lastStatus;
+ seq->lastTicks = m->lastTicks;
+}
+
+void alSeqGetLoc(ALSeq *seq, ALSeqMarker *m)
+{
+ m->curPtr = seq->curPtr;
+ m->lastStatus = seq->lastStatus;
+ m->lastTicks = seq->lastTicks;
+}
+
+/* non-aligned byte reading routines */
+static u8 read8(ALSeq *seq)
+{
+ return *seq->curPtr++;
+}
+
+static s16 read16(ALSeq *seq)
+{
+ s16 tmp;
+
+ tmp = *seq->curPtr++ << 8;
+ tmp |= *seq->curPtr++;
+
+ return tmp;
+}
+
+static s32 read32(ALSeq *seq)
+{
+ s32 tmp;
+
+ tmp = *seq->curPtr++ << 24;
+ tmp |= *seq->curPtr++ << 16;
+ tmp |= *seq->curPtr++ << 8;
+ tmp |= *seq->curPtr++;
+
+ return tmp;
+}
+
+static s32 readVarLen(ALSeq *seq)
+{
+ s32 value;
+ s32 c;
+
+ c = *seq->curPtr++;
+ value = c;
+ if ( c & 0x80 ) {
+ value &= 0x7f;
+ do {
+ c = *seq->curPtr++;
+ value = (value << 7) + (c & 0x7f);
+ } while (c & 0x80);
+ }
+ return (value);
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ultralib/src/audio/seq.h b/lib/ultralib/src/audio/seq.h
new file mode 100644
index 0000000..479b339
--- /dev/null
+++ b/lib/ultralib/src/audio/seq.h
@@ -0,0 +1,9 @@
+
+
+#ifndef __seq__
+#define __seq__
+
+char __alSeqNextDelta (ALSeq *seq, s32 *pDeltaTicks);
+
+
+#endif /* __seq__ */
diff --git a/lib/ultralib/src/audio/seqp.h b/lib/ultralib/src/audio/seqp.h
new file mode 100644
index 0000000..c9ab02b
--- /dev/null
+++ b/lib/ultralib/src/audio/seqp.h
@@ -0,0 +1,37 @@
+
+
+#define KILL_TIME 50000 /* 50 ms */
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+ALVoiceState *__mapVoice(ALSeqPlayer *, u8, u8, u8);
+void __unmapVoice(ALSeqPlayer *seqp, ALVoice *voice);
+char __voiceNeedsNoteKill(ALSeqPlayer *seqp, ALVoice *voice, ALMicroTime killTime); /* sct 1/5/96 */
+
+ALVoiceState *__lookupVoice(ALSeqPlayer *, u8, u8);
+ALSound *__lookupSound(ALSeqPlayer *, u8, u8, u8);
+ALSound *__lookupSoundQuick(ALSeqPlayer *, u8, u8, u8);
+
+s16 __vsVol(ALVoiceState *voice, ALSeqPlayer *seqp);
+ALMicroTime __vsDelta(ALVoiceState *voice, ALMicroTime t);
+ALPan __vsPan(ALVoiceState *voice, ALSeqPlayer *seqp);
+
+void __initFromBank(ALSeqPlayer *seqp, ALBank *b);
+void __initChanState(ALSeqPlayer *seqp);
+void __resetPerfChanState(ALSeqPlayer *seqp, s32 chan);
+void __setInstChanState(ALSeqPlayer *seqp, ALInstrument *inst, s32 chan);
+
+void __seqpPrintVoices(ALSeqPlayer *);
+void __seqpReleaseVoice(ALSeqPlayer *seqp, ALVoice *voice,
+ ALMicroTime deltaTime);
+
+void __seqpStopOsc(ALSeqPlayer *seqp, ALVoiceState *vs);
+
+void __postNextSeqEvent(ALSeqPlayer *seqp); /* sct 11/7/95 */
+
diff --git a/lib/ultralib/src/audio/seqpdelete.c b/lib/ultralib/src/audio/seqpdelete.c
new file mode 100644
index 0000000..b4f11fd
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpdelete.c
@@ -0,0 +1,42 @@
+/*====================================================================
+ * seqpdelete.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include <assert.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+
+void alSeqpDelete(ALSeqPlayer *seqp)
+{
+ /* sct 1/4/96 - If the sequence player isn't stopped, then you may end
+ up with stuck notes. Application should check state before calling
+ this routine to be sure. */
+
+#ifdef _DEBUG
+ assert(seqp->state == AL_STOPPED);
+#endif
+
+ alSynRemovePlayer(seqp->drvr, &seqp->node);
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetchlvol.c b/lib/ultralib/src/audio/seqpgetchlvol.c
new file mode 100644
index 0000000..e205651
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetchlvol.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * seqpgetchlvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+u8 alSeqpGetChlVol(ALSeqPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].vol;
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetfxmix.c b/lib/ultralib/src/audio/seqpgetfxmix.c
new file mode 100644
index 0000000..5d7ee3f
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetfxmix.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * seqpgetfxmix.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+u8 alSeqpGetChlFXMix(ALSeqPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].fxmix;
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetpan.c b/lib/ultralib/src/audio/seqpgetpan.c
new file mode 100644
index 0000000..23f1067
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetpan.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * seqpgetpan.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+ALPan alSeqpGetChlPan(ALSeqPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].pan;
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetpriority.c b/lib/ultralib/src/audio/seqpgetpriority.c
new file mode 100644
index 0000000..e6f77a4
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetpriority.c
@@ -0,0 +1,26 @@
+/*====================================================================
+ * seqpgetpriority.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+u8 alSeqpGetChlPriority(ALSeqPlayer *seqp, u8 chan)
+{
+ return seqp->chanState[chan].priority;
+}
diff --git a/lib/ultralib/src/audio/seqpgetprogram.c b/lib/ultralib/src/audio/seqpgetprogram.c
new file mode 100644
index 0000000..d421cde
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetprogram.c
@@ -0,0 +1,42 @@
+/*====================================================================
+ * seqpgetprogram.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s32 alSeqpGetChlProgram(ALSeqPlayer *seqp, u8 chan)
+
+{
+ s32 i;
+ ALBank *b = seqp->bank;
+ ALInstrument *inst;
+ ALChanState s;
+
+ s = seqp->chanState[chan];
+ for (i=0; i<b->instCount; i++){
+ inst = b->instArray[i];
+ if (inst == s.instrument)
+ return i;
+ }
+ return(-1);
+
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetseq.c b/lib/ultralib/src/audio/seqpgetseq.c
new file mode 100644
index 0000000..d35ea19
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetseq.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * seqpgetseq.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+ALSeq *alSeqpGetSeq(ALSeqPlayer *seqp)
+{
+ return seqp->target;
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetstate.c b/lib/ultralib/src/audio/seqpgetstate.c
new file mode 100644
index 0000000..8d36b49
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetstate.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * seqpgetstate.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s32 alSeqpGetState(ALSeqPlayer *seqp)
+{
+ return seqp->state;
+}
+
diff --git a/lib/ultralib/src/audio/seqpgettempo.c b/lib/ultralib/src/audio/seqpgettempo.c
new file mode 100644
index 0000000..41cd4b4
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgettempo.c
@@ -0,0 +1,31 @@
+/*====================================================================
+ * seqpgettempo.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s32 alSeqpGetTempo(ALSeqPlayer *seqp)
+{
+ /* sct 1/8/96 - If no target sequence has been set, just return zero (instead of crashing). */
+ if (seqp->target == NULL)
+ return 0;
+
+ return seqp->uspt/seqp->target->qnpt;
+}
+
diff --git a/lib/ultralib/src/audio/seqpgetvol.c b/lib/ultralib/src/audio/seqpgetvol.c
new file mode 100644
index 0000000..43a3bb8
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpgetvol.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * seqpgetvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+s16 alSeqpGetVol(ALSeqPlayer *seqp)
+{
+ return seqp->vol;
+}
+
diff --git a/lib/ultralib/src/audio/seqplayer.c b/lib/ultralib/src/audio/seqplayer.c
new file mode 100644
index 0000000..3b83257
--- /dev/null
+++ b/lib/ultralib/src/audio/seqplayer.c
@@ -0,0 +1,1231 @@
+/*====================================================================
+ * seqplayer.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+/*
+ * Notes:
+ *
+ * Controller Numbers:
+ * 1 Modulation
+ * 7 Volume
+ * 10 Pan
+ * 11 Expression
+ * 64 Sustain
+ * 121 Reset All Controllers
+ * 123 All Notes Off
+ *
+ * Registered Parameters
+ * 0 Pitch Bend Sensitivity
+ * 1 Fine Tuning
+ * 2 Coarse Tuning
+ */
+
+#include <libaudio.h>
+#include <os_internal.h>
+#include <ultraerror.h>
+#include <assert.h>
+#include "seqp.h"
+#include "seq.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+
+static ALMicroTime __seqpVoiceHandler(void *node);
+static void __handleMIDIMsg(ALSeqPlayer *seqp, ALEvent *event);
+static void __handleMetaMsg(ALSeqPlayer *seqp, ALEvent *event);
+static void __handleNextSeqEvent(ALSeqPlayer *seqp);
+static void __setUsptFromTempo(ALSeqPlayer *seqp, f32 tempo); /* sct 1/8/96 */
+
+/*
+ * Sequence Player public functions
+ */
+void alSeqpNew(ALSeqPlayer *seqp, ALSeqpConfig *c)
+{
+ s32 i;
+ ALEventListItem *items;
+ ALVoiceState *vs;
+ ALVoiceState *voices;
+ ALHeap *hp = c->heap;
+
+ /*
+ * initialize member variables
+ */
+ seqp->bank = 0;
+ seqp->target = NULL;
+ seqp->drvr = &alGlobals->drvr;
+ seqp->chanMask = 0xff;
+ seqp->uspt = 488;
+ seqp->nextDelta = 0;
+ seqp->state = AL_STOPPED;
+ seqp->vol = 0x7FFF; /* full volume */
+ seqp->debugFlags = c->debugFlags;
+ seqp->frameTime = AL_USEC_PER_FRAME; /* should get this from driver */
+ seqp->curTime = 0;
+ seqp->initOsc = c->initOsc;
+ seqp->updateOsc = c->updateOsc;
+ seqp->stopOsc = c->stopOsc;
+ seqp->loopStart = 0;
+ seqp->loopEnd = 0;
+ seqp->loopCount = 0; /* -1 = loop forever, 0 = no loop */
+
+ seqp->nextEvent.type = AL_SEQP_API_EVT; /* start the voice handler "spinning" */
+
+ /*
+ * init the channel state
+ */
+ seqp->maxChannels = c->maxChannels;
+ seqp->chanState = alHeapAlloc(hp, c->maxChannels, sizeof(ALChanState) );
+ __initChanState(seqp); /* sct 11/6/95 */
+
+ /*
+ * init the voice state array
+ */
+ voices = alHeapAlloc(hp, c->maxVoices, sizeof(ALVoiceState));
+ seqp->vFreeList = 0;
+ for (i = 0; i < c->maxVoices; i++) {
+ vs = &voices[i];
+ vs->next = seqp->vFreeList;
+ seqp->vFreeList = vs;
+ }
+
+ seqp->vAllocHead = 0;
+ seqp->vAllocTail = 0;
+
+ /*
+ * init the event queue
+ */
+ items = alHeapAlloc(hp, c->maxEvents, sizeof(ALEventListItem));
+ alEvtqNew(&seqp->evtq, items, c->maxEvents);
+
+ /*
+ * add ourselves to the driver
+ */
+ seqp->node.next = NULL;
+ seqp->node.handler = __seqpVoiceHandler;
+ seqp->node.clientData = seqp;
+ alSynAddPlayer(&alGlobals->drvr, &seqp->node);
+}
+
+/*************************************************************
+ * private routines or driver callback routines
+ *************************************************************/
+ALMicroTime __seqpVoiceHandler(void *node)
+{
+ ALSeqPlayer *seqp = (ALSeqPlayer *) node;
+ ALEvent evt;
+ ALVoice *voice;
+ ALMicroTime delta;
+ ALVoiceState *vs;
+ void *oscState;
+ f32 oscValue;
+ u8 chan;
+
+ do {
+
+ switch (seqp->nextEvent.type) {
+
+ case (AL_SEQ_REF_EVT):
+ __handleNextSeqEvent(seqp);
+ break;
+
+ case (AL_SEQP_API_EVT):
+ evt.type = AL_SEQP_API_EVT;
+ alEvtqPostEvent(&seqp->evtq, (ALEvent *)&evt, seqp->frameTime);
+ break;
+
+ case (AL_NOTE_END_EVT):
+ voice = seqp->nextEvent.msg.note.voice;
+ alSynStopVoice(seqp->drvr, voice);
+ alSynFreeVoice(seqp->drvr, voice);
+ vs = (ALVoiceState *)voice->clientPrivate;
+ if(vs->flags)
+ __seqpStopOsc((ALSeqPlayer*)seqp,vs);
+ __unmapVoice(seqp, voice);
+ break;
+
+ case (AL_SEQP_ENV_EVT):
+ voice = seqp->nextEvent.msg.vol.voice;
+ vs = (ALVoiceState *)voice->clientPrivate;
+
+ if (vs->envPhase == AL_PHASE_ATTACK)
+ vs->envPhase = AL_PHASE_DECAY;
+
+ delta = seqp->nextEvent.msg.vol.delta;
+ vs->envGain = seqp->nextEvent.msg.vol.vol;
+ vs->envEndTime = seqp->curTime + delta;
+ alSynSetVol(seqp->drvr, voice, __vsVol(vs, seqp), delta);
+ break;
+
+ case (AL_TREM_OSC_EVT):
+ vs = seqp->nextEvent.msg.osc.vs;
+ oscState = seqp->nextEvent.msg.osc.oscState;
+ delta = (*seqp->updateOsc)(oscState,&oscValue);
+ vs->tremelo = (u8)oscValue;
+ alSynSetVol(seqp->drvr, &vs->voice, __vsVol(vs,seqp),
+ __vsDelta(vs,seqp->curTime));
+ evt.type = AL_TREM_OSC_EVT;
+ evt.msg.osc.vs = vs;
+ evt.msg.osc.oscState = oscState;
+ alEvtqPostEvent(&seqp->evtq, &evt, delta);
+ break;
+
+ case (AL_VIB_OSC_EVT):
+ vs = seqp->nextEvent.msg.osc.vs;
+ oscState = seqp->nextEvent.msg.osc.oscState;
+ chan = seqp->nextEvent.msg.osc.chan;
+ delta = (*seqp->updateOsc)(oscState,&oscValue);
+ vs->vibrato = oscValue;
+ alSynSetPitch(seqp->drvr, &vs->voice, vs->pitch * vs->vibrato
+ * seqp->chanState[chan].pitchBend);
+ evt.type = AL_VIB_OSC_EVT;
+ evt.msg.osc.vs = vs;
+ evt.msg.osc.oscState = oscState;
+ evt.msg.osc.chan = chan;
+ alEvtqPostEvent(&seqp->evtq, &evt, delta);
+ break;
+
+ case (AL_SEQP_MIDI_EVT):
+ __handleMIDIMsg(seqp, &seqp->nextEvent);
+ break;
+
+ case (AL_SEQP_META_EVT):
+ __handleMetaMsg(seqp, &seqp->nextEvent);
+ break;
+
+ case (AL_SEQP_PLAY_EVT):
+ if (seqp->state != AL_PLAYING)
+ {
+ seqp->state = AL_PLAYING;
+ __postNextSeqEvent(seqp); /* seqp must be AL_PLAYING before we call this routine. */
+ }
+ break;
+
+ case (AL_SEQP_STOP_EVT):
+ if ( seqp->state == AL_STOPPING )
+ {
+ for (vs = seqp->vAllocHead; vs != 0; vs = seqp->vAllocHead)
+ {
+ alSynStopVoice(seqp->drvr, &vs->voice);
+ alSynFreeVoice(seqp->drvr, &vs->voice);
+ if(vs->flags)
+ __seqpStopOsc((ALSeqPlayer*)seqp,vs);
+ __unmapVoice((ALSeqPlayer*)seqp, &vs->voice);
+ }
+
+ seqp->curTime = 0;
+ seqp->state = AL_STOPPED;
+
+ /* alEvtqFlush(&seqp->evtq); - Don't flush event
+ queue anymore. */
+ /* sct 1/3/96 - Don't overwrite nextEvent with
+ AL_SEQP_API_EVT or set nextDelta to
+ AL_USEC_PER_FRAME since we're not stopping event
+ processing. */
+ /* sct 1/3/96 - Don't return here since we keep
+ processing events as usual. */
+ }
+ break;
+
+ case (AL_SEQP_STOPPING_EVT):
+ if (seqp->state == AL_PLAYING)
+ {
+ /*
+ * sct 12/29/95 - Remove events associated with the
+ * stopping sequence. Note that flushing
+ * AL_SEQP_MIDI_EVTs may flush events that were
+ * posted after the call to alSeqpStop, so the
+ * application must queue these events either when
+ * the player is fully stopped, or when it is
+ * playing.
+ */
+ alEvtqFlushType(&seqp->evtq, AL_SEQ_REF_EVT);
+ alEvtqFlushType(&seqp->evtq, AL_SEQP_MIDI_EVT);
+
+ /*
+ * sct 1/3/96 - Check to see which voices need to be
+ * killed and release them. Unkilled voices should
+ * have note end events occurring prior to
+ * KILL_TIME.
+ */
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next)
+ {
+ if (__voiceNeedsNoteKill (seqp, &vs->voice, KILL_TIME))
+ __seqpReleaseVoice(seqp, &vs->voice, KILL_TIME);
+ }
+
+ seqp->state = AL_STOPPING;
+ evt.type = AL_SEQP_STOP_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END);
+ }
+ break;
+
+ case (AL_SEQP_VOL_EVT):
+ seqp->vol = seqp->nextEvent.msg.spvol.vol;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ alSynSetVol(seqp->drvr, &vs->voice, __vsVol(vs, seqp),
+ __vsDelta(vs, seqp->curTime));
+ }
+ break;
+
+ case (AL_SEQP_LOOP_EVT):
+ seqp->loopStart = seqp->nextEvent.msg.loop.start;
+ seqp->loopEnd = seqp->nextEvent.msg.loop.end;
+ seqp->loopCount = seqp->nextEvent.msg.loop.count;
+ break;
+
+ case (AL_SEQP_PRIORITY_EVT):
+ chan = seqp->nextEvent.msg.sppriority.chan;
+ seqp->chanState[chan].priority = seqp->nextEvent.msg.sppriority.priority;
+ break;
+
+ case (AL_SEQP_SEQ_EVT):
+
+#ifdef _DEBUG
+ assert(seqp->state != AL_PLAYING); /* Must be done playing to change sequences. */
+#endif
+
+ seqp->target = seqp->nextEvent.msg.spseq.seq;
+ __setUsptFromTempo (seqp, 500000.0);
+ if (seqp->bank)
+ __initFromBank(seqp, seqp->bank);
+ break;
+
+ case (AL_SEQP_BANK_EVT):
+
+#ifdef _DEBUG
+ assert(seqp->state == AL_STOPPED); /* Must be fully stopped to change banks. */
+#endif
+
+ seqp->bank = seqp->nextEvent.msg.spbank.bank;
+ __initFromBank(seqp, seqp->bank);
+ break;
+
+ /* sct 11/6/95 - these events should now be handled by __handleNextSeqEvent */
+ case (AL_SEQ_END_EVT):
+ case (AL_TEMPO_EVT):
+ case (AL_SEQ_MIDI_EVT):
+
+#ifdef _DEBUG
+ assert(FALSE);
+#endif
+
+ break;
+ }
+
+ seqp->nextDelta = alEvtqNextEvent (&seqp->evtq, &seqp->nextEvent);
+
+ } while (seqp->nextDelta == 0);
+
+ /*
+ * assume that next callback won't be more than half an hour away
+ */
+ seqp->curTime += seqp->nextDelta; /* Update the player's current time. */
+ return seqp->nextDelta;
+}
+
+
+/*
+ Calculates the delta time in ticks until the next sequence
+ event taking into account loop points, and posts a
+ sequence reference event with the time in usecs.
+
+ Does nothing if the sequence player is not playing or there
+ is no target sequence.
+
+ sct 11/7/95
+*/
+void __postNextSeqEvent(ALSeqPlayer *seqp)
+{
+ ALEvent evt;
+ s32 deltaTicks;
+ ALSeq *seq = seqp->target;
+
+ /* sct 1/5/96 - Do nothing if we're not playing or don't have a target sequence. */
+ if ((seqp->state != AL_PLAYING) || (seq == NULL))
+ return;
+
+ /* Get the next event time in ticks. */
+ /* If false is returned, then there is no next delta (ie. end of sequence reached). */
+ if (!__alSeqNextDelta(seq, &deltaTicks))
+ return;
+
+ /* Handle loops. */
+ if (seqp->loopCount)
+ {
+ /* Assume that the loop end falls on a MIDI event. Delta time
+ will be correct even if we loop */
+ if (alSeqGetTicks(seq) + deltaTicks >= seqp->loopEnd->curTicks)
+ {
+ alSeqSetLoc(seq, seqp->loopStart);
+
+ if (seqp->loopCount != -1)
+ seqp->loopCount--;
+ }
+ }
+
+ evt.type = AL_SEQ_REF_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTicks * seqp->uspt);
+}
+
+
+/*
+ Call this routine to handle the next event in the sequence.
+ Assumes that the next sequence event is scheduled to be processed
+ immediately since it does not check the event's tick time.
+
+ sct 11/7/95
+*/
+static void
+__handleNextSeqEvent(ALSeqPlayer *seqp)
+{
+ ALEvent evt;
+
+ /* sct 1/5/96 - Do nothing if we don't have a target sequence. */
+ if (seqp->target == NULL)
+ return;
+
+ alSeqNextEvent(seqp->target, &evt);
+
+ switch (evt.type)
+ {
+ case AL_SEQ_MIDI_EVT:
+ __handleMIDIMsg(seqp, &evt);
+ __postNextSeqEvent(seqp);
+ break;
+
+ case AL_TEMPO_EVT:
+ __handleMetaMsg(seqp, &evt);
+ __postNextSeqEvent(seqp);
+ break;
+
+ case AL_SEQ_END_EVT:
+ seqp->state = AL_STOPPING;
+ evt.type = AL_SEQP_STOP_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END);
+ break;
+
+ default:
+
+#ifdef _DEBUG
+ assert(FALSE); /* Sequence event type not supported. */
+#endif
+
+ break;
+ }
+}
+
+
+void __handleMIDIMsg(ALSeqPlayer *seqp, ALEvent *event)
+{
+ ALVoice *voice;
+ ALVoiceState *vs;
+ s32 status;
+ u8 chan;
+ u8 key;
+ u8 vel;
+ u8 byte1;
+ u8 byte2;
+ ALMIDIEvent *midi = &event->msg.midi;
+ s16 vol;
+ ALEvent evt;
+ ALMicroTime deltaTime;
+ ALVoiceState *vstate;
+ ALPan pan;
+ ALFxRef fxref;
+
+#ifdef _DEBUG
+ /* sct 12/15/95 - Fixed assert to also allow seqp midi event types. */
+ assert(event->type == AL_SEQ_MIDI_EVT || event->type == AL_SEQP_MIDI_EVT);
+#endif
+
+ status = midi->status & AL_MIDI_StatusMask;
+ chan = midi->status & AL_MIDI_ChannelMask;
+ byte1 = key = midi->byte1;
+ byte2 = vel = midi->byte2;
+
+ switch (status) {
+
+ case (AL_MIDI_NoteOn):
+
+ if (vel != 0) { /* a real note on */
+ ALVoiceConfig config;
+ ALSound *sound;
+ s16 cents;
+ f32 pitch,oscValue;
+ u8 fxmix;
+ void *oscState;
+ ALInstrument *inst;
+
+ /* If we're not playing, don't process note ons. */
+ if (seqp->state != AL_PLAYING)
+ break;
+
+ sound = __lookupSoundQuick(seqp, key, vel, chan);
+ ALFlagFailIf(!sound, seqp->debugFlags & NO_SOUND_ERR_MASK,
+ ERR_ALSEQP_NO_SOUND);
+
+ config.priority = seqp->chanState[chan].priority;
+ config.fxBus = 0;
+ config.unityPitch = 0;
+
+ vstate = __mapVoice(seqp, key, vel, chan);
+ ALFlagFailIf(!vstate, seqp->debugFlags & NO_VOICE_ERR_MASK,
+ ERR_ALSEQP_NO_VOICE );
+
+ voice = &vstate->voice;
+
+ alSynAllocVoice(seqp->drvr, voice, &config);
+
+ /*
+ * set up the voice state structure
+ */
+ vstate->sound = sound;
+ vstate->envPhase = AL_PHASE_ATTACK;
+ if (seqp->chanState[chan].sustain > AL_SUSTAIN)
+ vstate->phase = AL_PHASE_SUSTAIN;
+ else
+ vstate->phase = AL_PHASE_NOTEON;
+
+ cents = (key - sound->keyMap->keyBase) * 100
+ + sound->keyMap->detune;
+
+ vstate->pitch = alCents2Ratio(cents);
+ vstate->envGain = sound->envelope->attackVolume;
+ vstate->envEndTime = seqp->curTime +
+ sound->envelope->attackTime;
+
+ /*
+ * setup tremelo and vibrato if active
+ */
+ vstate->flags = 0;
+ inst = seqp->chanState[chan].instrument;
+
+ oscValue = (f32)AL_VOL_FULL; /* set this as a default */
+
+ if(inst->tremType)
+ {
+ if(seqp->initOsc)
+ {
+ deltaTime = (*seqp->initOsc)(&oscState,&oscValue,
+ inst->tremType,
+ inst->tremRate,
+ inst->tremDepth,
+ inst->tremDelay);
+
+ if(deltaTime) /* if deltaTime = zero, don't run osc */
+ {
+ evt.type = AL_TREM_OSC_EVT;
+ evt.msg.osc.vs = vstate;
+ evt.msg.osc.oscState = oscState;
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+ vstate->flags |= 0x01; /* set tremelo flag bit */
+ }
+ }
+ }
+ /* will default if not changed by initOsc */
+ vstate->tremelo = (u8)oscValue;
+
+ oscValue = 1.0f; /* set this as a default */
+ if(inst->vibType)
+ {
+ if(seqp->initOsc)
+ {
+ deltaTime = (*seqp->initOsc)(&oscState,&oscValue,
+ inst->vibType,
+ inst->vibRate,
+ inst->vibDepth,
+ inst->vibDelay);
+
+ if(deltaTime) /* if deltaTime = zero,don't run osc. */
+ {
+ evt.type = AL_VIB_OSC_EVT;
+ evt.msg.osc.vs = vstate;
+ evt.msg.osc.oscState = oscState;
+ evt.msg.osc.chan = chan;
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+ vstate->flags |= 0x02; /* set the vibrato flag bit */
+ }
+ }
+ }
+ /* will default if not changed by initOsc */
+ vstate->vibrato = oscValue;
+
+ /*
+ * calculate the note on parameters
+ */
+ pitch = vstate->pitch * seqp->chanState[chan].pitchBend *
+ vstate->vibrato;
+ fxmix = seqp->chanState[chan].fxmix;
+ pan = __vsPan(vstate, seqp);
+ vol = __vsVol(vstate, seqp);
+ deltaTime = sound->envelope->attackTime;
+
+ alSynStartVoiceParams(seqp->drvr, voice, sound->wavetable,
+ pitch, vol, pan, fxmix, deltaTime);
+ /*
+ * set up callbacks for envelope
+ */
+ evt.type = AL_SEQP_ENV_EVT;
+ evt.msg.vol.voice = voice;
+ evt.msg.vol.vol = sound->envelope->decayVolume;
+ evt.msg.vol.delta = sound->envelope->decayTime;
+ deltaTime = sound->envelope->attackTime;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+
+ break;
+ }
+
+ /*
+ * NOTE: intentional fall-through for note on with zero
+ * velocity
+ */
+
+ case (AL_MIDI_NoteOff):
+ vstate = __lookupVoice(seqp, key, chan);
+ ALFlagFailIf(!vstate, (seqp->debugFlags & NOTE_OFF_ERR_MASK),
+ ERR_ALSEQP_OFF_VOICE );
+
+ if (vstate->phase == AL_PHASE_SUSTAIN)
+ vstate->phase = AL_PHASE_SUSTREL;
+ else {
+ vstate->phase = AL_PHASE_RELEASE;
+ __seqpReleaseVoice(seqp, &vstate->voice,
+ vstate->sound->envelope->releaseTime);
+ }
+
+ break;
+
+ case (AL_MIDI_PolyKeyPressure):
+ /*
+ * Aftertouch per key (hardwired to volume). Note that
+ * aftertouch affects only notes that are already
+ * sounding.
+ */
+ vstate = __lookupVoice(seqp, key, chan);
+ ALFailIf(!vstate, ERR_ALSEQP_POLY_VOICE );
+
+ vstate->velocity = byte2;
+ alSynSetVol(seqp->drvr, &vstate->voice, __vsVol(vstate, seqp),
+ __vsDelta(vstate, seqp->curTime));
+ break;
+
+ case (AL_MIDI_ChannelPressure):
+ /*
+ * Aftertouch per channel (hardwired to volume). Note that
+ * aftertouch affects only notes that are already
+ * sounding.
+ */
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if (vs->channel == chan) {
+ vs->velocity = byte1;
+ alSynSetVol(seqp->drvr, &vs->voice, __vsVol(vs, seqp),
+ __vsDelta(vs, seqp->curTime));
+ }
+ }
+ break;
+
+ case (AL_MIDI_ControlChange):
+
+ switch (byte1) {
+
+ case (AL_MIDI_PAN_CTRL):
+ seqp->chanState[chan].pan = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if (vs->channel == chan) {
+ pan = __vsPan(vs, seqp);
+ alSynSetPan(seqp->drvr, &vs->voice, pan);
+ }
+ }
+ break;
+
+ case (AL_MIDI_VOLUME_CTRL):
+ seqp->chanState[chan].vol = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if ((vs->channel == chan) &&
+ (vs->envPhase != AL_PHASE_RELEASE))
+ {
+ vol = __vsVol(vs, seqp);
+ alSynSetVol(seqp->drvr, &vs->voice, vol,
+ __vsDelta(vs, seqp->curTime));
+ }
+ }
+ break;
+ case (AL_MIDI_PRIORITY_CTRL):
+ /* leave current voices where they are */
+ seqp->chanState[chan].priority = byte2;
+ break;
+ case (AL_MIDI_SUSTAIN_CTRL):
+ seqp->chanState[chan].sustain = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if ((vs->channel == chan) &&
+ (vs->phase != AL_PHASE_RELEASE)) {
+ if ( byte2 > AL_SUSTAIN ) {
+ /*
+ * sustain pedal down
+ */
+ if (vs->phase == AL_PHASE_NOTEON)
+ vs->phase = AL_PHASE_SUSTAIN;
+ } else {
+ /*
+ * sustain pedal up
+ */
+ if (vs->phase == AL_PHASE_SUSTAIN)
+ vs->phase = AL_PHASE_NOTEON;
+ else if(vs->phase == AL_PHASE_SUSTREL) {
+ vs->phase = AL_PHASE_RELEASE;
+ __seqpReleaseVoice(seqp, &vs->voice,
+ vs->sound->envelope->releaseTime);
+ }
+ }
+ }
+ }
+ break;
+
+ case (AL_MIDI_FX1_CTRL):
+ seqp->chanState[chan].fxmix = byte2;
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if (vs->channel == chan) {
+ alSynSetFXMix(seqp->drvr, &vs->voice, byte2);
+ }
+ }
+ break;
+
+ case (AL_MIDI_FX_CTRL_0):
+ case (AL_MIDI_FX_CTRL_1):
+ case (AL_MIDI_FX_CTRL_2):
+ case (AL_MIDI_FX_CTRL_3):
+ case (AL_MIDI_FX_CTRL_4):
+ case (AL_MIDI_FX_CTRL_5):
+ case (AL_MIDI_FX_CTRL_6):
+ case (AL_MIDI_FX_CTRL_7):
+#if 0 /* fx control not implemented */
+ fxref = alSynGetFXRef(seqp->drvr, 0, 0);
+ if (fxref)
+ alSynSetFXParam(seqp->drvr, fxref, (s16)byte1, (void *)byte2);
+ break;
+#endif
+ case (AL_MIDI_FX3_CTRL):
+ default:
+ break;
+
+ }
+ break;
+
+ case (AL_MIDI_ProgramChange):
+ /* sct 1/16/96 - We must have a valid bank in order to process the program change. */
+
+#ifdef _DEBUG
+ assert(seqp->bank != NULL);
+#endif
+
+ if (key < seqp->bank->instCount) {
+ ALInstrument *inst = seqp->bank->instArray[key];
+ __setInstChanState(seqp, inst, chan); /* sct 11/6/95 */
+ }
+#ifdef _DEBUG
+ else
+ __osError(ERR_ALSEQPINVALIDPROG, 2, key, seqp->bank->instCount);
+#endif
+ break;
+
+ case (AL_MIDI_PitchBendChange):
+ {
+ s32 bendVal;
+ f32 bendRatio;
+ s32 cents;
+
+ /*
+ * get 14-bit unsigned midi value
+ */
+ bendVal = ( (byte2 << 7) + byte1) - 8192;
+
+ /*
+ * calculate pitch bend in cents
+ */
+ cents = (seqp->chanState[chan].bendRange * bendVal)/8192;
+
+ /*
+ * calculate the corresponding ratio
+ */
+ bendRatio = alCents2Ratio(cents);
+ seqp->chanState[chan].pitchBend = bendRatio;
+
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if (vs->channel == chan) {
+ alSynSetPitch(seqp->drvr, &vs->voice,
+ vs->pitch * bendRatio * vs->vibrato);
+ }
+ }
+ }
+ break;
+
+ default:
+#ifdef _DEBUG
+ __osError(ERR_ALSEQPUNKNOWNMIDI, 1, status);
+#endif
+ break;
+ }
+}
+
+void __handleMetaMsg(ALSeqPlayer *seqp, ALEvent *event)
+{
+ ALTempoEvent *tevt = &event->msg.tempo;
+ ALEvent evt;
+ s32 tempo;
+
+ if (event->msg.tempo.status == AL_MIDI_Meta)
+ {
+ if (event->msg.tempo.type == AL_MIDI_META_TEMPO)
+ {
+ tempo =
+ (tevt->byte1 << 16) |
+ (tevt->byte2 << 8) |
+ (tevt->byte3 << 0);
+ __setUsptFromTempo (seqp, (f32)tempo); /* sct 1/8/96 */
+ }
+ }
+}
+
+ALVoiceState *__mapVoice(ALSeqPlayer *seqp, u8 key, u8 vel, u8 channel)
+{
+ ALVoiceState *vs = seqp->vFreeList;
+
+ if (vs) {
+
+ seqp->vFreeList = vs->next;
+
+ vs->next = 0;
+
+ if (!seqp->vAllocHead)
+ seqp->vAllocHead = vs;
+ else
+ seqp->vAllocTail->next = vs;
+
+ seqp->vAllocTail = vs;
+
+ vs->channel = channel;
+ vs->key = key;
+ vs->velocity = vel;
+ vs->voice.clientPrivate = vs;
+ }
+
+ return vs;
+}
+
+void __unmapVoice(ALSeqPlayer *seqp, ALVoice *voice)
+{
+ ALVoiceState *prev = 0;
+ ALVoiceState *vs;
+
+ /*
+ * we could use doubly linked lists here and save some code and
+ * execution time, but time spent here in negligible, so it won't
+ * make much difference.
+ */
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if (&vs->voice == voice) {
+
+ if (prev)
+ prev->next = vs->next;
+ else
+ seqp->vAllocHead = vs->next;
+
+ if (vs == seqp->vAllocTail) {
+ seqp->vAllocTail = prev;
+ }
+
+ vs->next = seqp->vFreeList;
+ seqp->vFreeList = vs;
+ return;
+
+ }
+ prev = vs;
+ }
+#ifdef _DEBUG
+ __osError(ERR_ALSEQPUNMAP, 1, voice);
+#endif
+}
+
+ALVoiceState *__lookupVoice(ALSeqPlayer *seqp, u8 key, u8 channel)
+{
+ ALVoiceState *vs;
+
+ for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) {
+ if ((vs->key == key) && (vs->channel == channel) &&
+ (vs->phase != AL_PHASE_RELEASE) && (vs->phase != AL_PHASE_SUSTREL))
+ return vs;
+ }
+
+ return 0;
+}
+
+#if 0
+ALSound *__lookupSound(ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan)
+{
+ s32 i;
+ ALInstrument *inst = seqp->chanState[chan].instrument;
+ ALSound *snd = 0;
+
+ for (i = 0; i < inst->soundCount; i++) {
+ ALSound *sound = inst->soundArray[i];
+ ALKeyMap *keymap = sound->keyMap;
+
+ if ((key >= keymap->keyMin) && (key <= keymap->keyMax) &&
+ (vel >= keymap->velocityMin) && (vel <= keymap->velocityMax)) {
+ snd = sound;
+ break;
+ }
+ }
+ return snd;
+}
+#endif
+
+ALSound *__lookupSoundQuick(ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan)
+{
+ ALInstrument *inst = seqp->chanState[chan].instrument;
+ s32 l = 1;
+ s32 r = inst->soundCount;
+ s32 i;
+ ALKeyMap *keymap;
+
+#ifdef _DEBUG
+ assert(inst != NULL); /* sct 10/31/95 - If inst is NULL, then the seqp probably wasn't setup correctly. */
+#endif
+
+ while (r >= l) {
+ i = (l+r)/2;
+
+ keymap = inst->soundArray[i-1]->keyMap;
+
+ if ((key >= keymap->keyMin) && (key <= keymap->keyMax) &&
+ (vel >= keymap->velocityMin) && (vel <= keymap->velocityMax)) {
+ return inst->soundArray[i-1];
+ } else if ((key < keymap->keyMin) ||
+ ((vel < keymap->velocityMin) && (key <= keymap->keyMax))) {
+ r = i - 1;
+ } else {
+ l = i + 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * __vsVol calculates the target volume for the voice based on the
+ * note on velocity, envelope, sampleVolume and controller.
+ */
+s16 __vsVol(ALVoiceState *vs, ALSeqPlayer *seqp)
+{
+
+ u32 t1,t2;
+
+ t1 = (vs->tremelo*vs->velocity*vs->envGain) >> 6;
+ t2 = (vs->sound->sampleVolume*seqp->vol*
+ seqp->chanState[vs->channel].vol) >> 14;
+
+ t1 *= t2;
+ t1 >>= 15;
+
+ return( (s16)t1 );
+
+}
+
+ALMicroTime __vsDelta(ALVoiceState *vs, ALMicroTime t)
+{
+ /*
+ * If we are interrupting a previously set envelope segment, we
+ * need to recalculate the segment end time given the current
+ * time. Note: this routine assumes that the voice is currently
+ * playing.
+ */
+
+ s32 delta = vs->envEndTime - t;
+
+ if (delta >= 0) {
+ return delta;
+ } else {
+ return AL_GAIN_CHANGE_TIME;
+ }
+}
+
+
+ALPan __vsPan(ALVoiceState *vs, ALSeqPlayer *seqp)
+{
+ s32 tmp;
+
+ tmp = seqp->chanState[vs->channel].pan - AL_PAN_CENTER +
+ vs->sound->samplePan;
+ tmp = MAX(tmp, AL_PAN_LEFT);
+ tmp = MIN(tmp, AL_PAN_RIGHT);
+
+ return (ALPan) tmp;
+}
+
+#ifdef IMPLEMENTED
+
+s32 seqpGetVoices(SEQP *seqp);
+s32 seqpSetVoices(SEQP *seqp, s32 numvoices);
+
+u16 seqpGetChannelMask(SEQP *seqp);
+s32 seqpSetChannelMask(SEQP *seqp, u16 bitmask);
+
+#endif
+
+void __seqpReleaseVoice(ALSeqPlayer *seqp, ALVoice *voice,
+ ALMicroTime deltaTime)
+{
+ ALEvent evt;
+ ALVoiceState *vs = (ALVoiceState *)voice->clientPrivate;
+
+ /*
+ * if in attack phase, remove all pending volume
+ * events for this voice from the queue
+ */
+
+ if (vs->envPhase == AL_PHASE_ATTACK) {
+ ALLink *thisNode;
+ ALLink *nextNode;
+ ALEventListItem *thisItem, *nextItem;
+
+ thisNode = seqp->evtq.allocList.next;
+ while( thisNode != 0 ) {
+ nextNode = thisNode->next;
+ thisItem = (ALEventListItem *)thisNode;
+ nextItem = (ALEventListItem *)nextNode;
+ if (thisItem->evt.type == AL_SEQP_ENV_EVT) {
+ if(thisItem->evt.msg.vol.voice == voice) {
+ if( nextItem )
+ nextItem->delta += thisItem->delta;
+ alUnlink(thisNode);
+ alLink(thisNode, &seqp->evtq.freeList);
+ }
+ }
+ thisNode = nextNode;
+ }
+ }
+
+ vs->velocity = 0;
+ vs->envPhase = AL_PHASE_RELEASE;
+ vs->envGain = 0;
+ vs->envEndTime = seqp->curTime + deltaTime;
+
+ alSynSetPriority(seqp->drvr, voice, 0); /* make candidate for stealing */
+ alSynSetVol(seqp->drvr, voice, 0, deltaTime);
+ evt.type = AL_NOTE_END_EVT;
+ evt.msg.note.voice = voice;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+}
+
+
+
+/*
+ This special purpose routine is called only when processing
+ a stopping event in order to properly kill all active voices.
+
+ The routine searches through the seqp's event queue for an
+ AL_NOTE_END_EVT for the given voice. If the event's execution
+ time is greater than kill time, it removes the event from the
+ event queue and returns true that it needs to kill the voice.
+ Otherwise, if the event's time is less than the kill time, it
+ returns false that the voice needs to be killed.
+
+ sct 1/3/96
+*/
+
+#define VOICENEEDSNOTEKILL_DEBUG _DEBUG_INTERNAL&&0 /* For debugging voiceNeedsNoteKill routine. */
+
+char __voiceNeedsNoteKill (ALSeqPlayer *seqp, ALVoice *voice, ALMicroTime killTime)
+{
+ ALLink *thisNode;
+ ALLink *nextNode;
+ ALEventListItem *thisItem;
+ ALMicroTime itemTime = 0;
+ char needsNoteKill = TRUE;
+
+#if VOICENEEDSNOTEKILL_DEBUG
+ alEvtqPrintAllocEvts (&seqp->evtq);
+#endif
+
+ thisNode = seqp->evtq.allocList.next;
+ while (thisNode != 0)
+ {
+ nextNode = thisNode->next;
+ thisItem = (ALEventListItem *)thisNode;
+ itemTime += thisItem->delta;
+
+ if (thisItem->evt.type == AL_NOTE_END_EVT)
+ {
+ if (thisItem->evt.msg.note.voice == voice)
+ {
+ if (itemTime > killTime)
+ {
+ if ((ALEventListItem *)nextNode)
+ ((ALEventListItem *)nextNode)->delta += thisItem->delta;
+ alUnlink(thisNode);
+ alLink(thisNode, &seqp->evtq.freeList);
+ }
+ else
+ needsNoteKill = FALSE;
+ break;
+ }
+ }
+ thisNode = nextNode;
+ }
+
+#if VOICENEEDSNOTEKILL_DEBUG
+ if (thisNode)
+ osSyncPrintf("vox 0x%0x: end time %d kill time %d\n\n", voice, itemTime, killTime);
+ else
+ osSyncPrintf("vox 0x%0x: not found\n\n", voice);
+
+ alEvtqPrintAllocEvts (&seqp->evtq);
+#endif
+
+ return needsNoteKill;
+}
+
+
+
+
+void __initFromBank(ALSeqPlayer *seqp, ALBank *b)
+{
+ /*
+ * init the chanState with the default instrument
+ */
+ s32 i;
+ ALInstrument *inst = 0;
+
+ /* set to the first available instrument. */
+ for(i = 0; !inst ; i++)
+ inst = b->instArray[i];
+
+ /* sct 11/6/95 - Setup the channel state for the given instrument. */
+ /* There is some wasted effort here since both calls the same state vars */
+ /* but it's safer. */
+ for (i = 0; i < seqp->maxChannels; i++) {
+ __resetPerfChanState(seqp, i);
+ __setInstChanState(seqp, inst, i);
+ }
+
+ if (b->percussion) {
+ __resetPerfChanState(seqp, i);
+ __setInstChanState(seqp, b->percussion, 9);
+ }
+}
+
+
+/*
+ sct 11/6/95 - Call this whenever a new instrument gets assigned to a channel
+ such as when changing banks or in response to a MIDI program change event.
+ Currently also gets called when changing sequences.
+*/
+void __setInstChanState(ALSeqPlayer *seqp, ALInstrument *inst, s32 chan)
+{
+ seqp->chanState[chan].instrument = inst;
+ seqp->chanState[chan].pan = inst->pan;
+ seqp->chanState[chan].vol = inst->volume;
+ seqp->chanState[chan].priority = inst->priority;
+ seqp->chanState[chan].bendRange = inst->bendRange;
+}
+
+
+/*
+ sct 11/6/95 -- Call this whenever a new sequence is to be played or when
+ initializing a sequence player.
+*/
+void __resetPerfChanState(ALSeqPlayer *seqp, s32 chan)
+{
+ seqp->chanState[chan].fxId = AL_FX_NONE;
+ seqp->chanState[chan].fxmix = AL_DEFAULT_FXMIX;
+ seqp->chanState[chan].pan = AL_PAN_CENTER;
+ seqp->chanState[chan].vol = AL_VOL_FULL;
+ seqp->chanState[chan].priority = AL_DEFAULT_PRIORITY;
+ seqp->chanState[chan].sustain = 0;
+ seqp->chanState[chan].bendRange = 200;
+ seqp->chanState[chan].pitchBend = 1.0f;
+}
+
+
+/*
+ sct 11/6/95 - Called only when creating a new sequence player.
+*/
+void __initChanState(ALSeqPlayer *seqp)
+{
+ int i;
+
+ for (i = 0; i < seqp->maxChannels; i++)
+ {
+ seqp->chanState[i].instrument = 0;
+ __resetPerfChanState (seqp, i);
+ }
+}
+
+
+void __seqpStopOsc(ALSeqPlayer *seqp, ALVoiceState *vs)
+{
+ ALEventListItem *thisNode,*nextNode;
+ s16 evtType;
+
+ thisNode = (ALEventListItem*)seqp->evtq.allocList.next;
+ while(thisNode)
+ {
+ nextNode = (ALEventListItem*)thisNode->node.next;
+ evtType = thisNode->evt.type;
+ if(evtType == AL_TREM_OSC_EVT || evtType == AL_VIB_OSC_EVT)
+ {
+ if(thisNode->evt.msg.osc.vs == vs)
+ {
+ (*seqp->stopOsc)(thisNode->evt.msg.osc.oscState);
+ alUnlink((ALLink*)thisNode);
+ if(nextNode)
+ nextNode->delta += thisNode->delta;
+ alLink((ALLink*)thisNode, &seqp->evtq.freeList);
+ if(evtType == AL_TREM_OSC_EVT)
+ vs->flags = vs->flags & 0xFE;
+ else /* must be a AL_VIB_OSC_EVT */
+ vs->flags = vs->flags & 0xFD;
+ if(!vs->flags)
+ return; /* there should be no more events */
+ }
+ }
+
+ thisNode = nextNode;
+ }
+}
+
+
+
+/*
+ This routine safely calculates the sequence player's
+ uspt value based on the given tempo. It does this safely
+ by making sure that the player has a target sequence and
+ therefore a qnpt value which is needed for the calculation.
+*/
+static void __setUsptFromTempo (ALSeqPlayer *seqp, f32 tempo)
+{
+ if (seqp->target)
+ seqp->uspt = (s32)((f32)tempo * seqp->target->qnpt);
+ else
+ seqp->uspt = 488; /* This is the initial value set by alSeqpNew. */
+}
diff --git a/lib/ultralib/src/audio/seqploop.c b/lib/ultralib/src/audio/seqploop.c
new file mode 100644
index 0000000..9bbaf5f
--- /dev/null
+++ b/lib/ultralib/src/audio/seqploop.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * seqploop.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpLoop(ALSeqPlayer *seqp, ALSeqMarker *start, ALSeqMarker *end,
+ s32 count)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_LOOP_EVT;
+ evt.msg.loop.start = start;
+ evt.msg.loop.end = end;
+ evt.msg.loop.count = count;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpplay.c b/lib/ultralib/src/audio/seqpplay.c
new file mode 100644
index 0000000..8e65504
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpplay.c
@@ -0,0 +1,48 @@
+/*====================================================================
+ * seqpplay.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+#include "seqp.h"
+
+void alSeqpPlay(ALSeqPlayer *seqp)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_PLAY_EVT;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ultralib/src/audio/seqpsendmidi.c b/lib/ultralib/src/audio/seqpsendmidi.c
new file mode 100644
index 0000000..56a9510
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsendmidi.c
@@ -0,0 +1,40 @@
+/*====================================================================
+ * seqpsendmidi.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSendMidi(ALSeqPlayer *seqp, s32 ticks, u8 status, u8 byte1,
+ u8 byte2)
+{
+ ALEvent evt;
+ ALMicroTime deltaTime;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = status;
+ evt.msg.midi.byte1 = byte1;
+ evt.msg.midi.byte2 = byte2;
+ evt.msg.midi.duration = 0;
+
+ deltaTime = ticks*seqp->uspt;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, deltaTime);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetbank.c b/lib/ultralib/src/audio/seqpsetbank.c
new file mode 100644
index 0000000..1c00e8b
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetbank.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * seqpsetbank.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetBank(ALSeqPlayer *seqp, ALBank *b)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_BANK_EVT;
+ evt.msg.spbank.bank = b;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetchlvol.c b/lib/ultralib/src/audio/seqpsetchlvol.c
new file mode 100644
index 0000000..9b48803
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetchlvol.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * seqpsetchlvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetChlVol(ALSeqPlayer *seqp, u8 chan, u8 vol)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ControlChange | chan;
+ evt.msg.midi.byte1 = AL_MIDI_VOLUME_CTRL;
+ evt.msg.midi.byte2 = vol;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetfxmix.c b/lib/ultralib/src/audio/seqpsetfxmix.c
new file mode 100644
index 0000000..9397963
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetfxmix.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * seqpsetfxmix.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetChlFXMix(ALSeqPlayer *seqp, u8 chan, u8 fxmix)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ControlChange | chan;
+ evt.msg.midi.byte1 = AL_MIDI_FX1_CTRL;
+ evt.msg.midi.byte2 = fxmix;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetpan.c b/lib/ultralib/src/audio/seqpsetpan.c
new file mode 100644
index 0000000..85d07d9
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetpan.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * seqpsetpan.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetChlPan(ALSeqPlayer *seqp, u8 chan, ALPan pan)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ControlChange | chan;
+ evt.msg.midi.byte1 = AL_MIDI_PAN_CTRL;
+ evt.msg.midi.byte2 = pan;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetpriority.c b/lib/ultralib/src/audio/seqpsetpriority.c
new file mode 100644
index 0000000..0910726
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetpriority.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * seqpsetpriority.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetChlPriority(ALSeqPlayer *seqp, u8 chan, u8 priority)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_PRIORITY_EVT;
+ evt.msg.sppriority.chan = chan;
+ evt.msg.sppriority.priority = priority;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
diff --git a/lib/ultralib/src/audio/seqpsetprogram.c b/lib/ultralib/src/audio/seqpsetprogram.c
new file mode 100644
index 0000000..dfd6d94
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetprogram.c
@@ -0,0 +1,36 @@
+/*====================================================================
+ * seqpsetprogram.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetChlProgram(ALSeqPlayer *seqp, u8 chan, u8 prog)
+
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_MIDI_EVT;
+ evt.msg.midi.ticks = 0;
+ evt.msg.midi.status = AL_MIDI_ProgramChange | chan;
+ evt.msg.midi.byte1 = prog;
+ evt.msg.midi.byte2 = 0;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetseq.c b/lib/ultralib/src/audio/seqpsetseq.c
new file mode 100644
index 0000000..3fe8175
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetseq.c
@@ -0,0 +1,34 @@
+/*====================================================================
+ * seqpsetseq.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetSeq(ALSeqPlayer *seqp, ALSeq *seq)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_SEQ_EVT;
+ evt.msg.spseq.seq = seq;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsettempo.c b/lib/ultralib/src/audio/seqpsettempo.c
new file mode 100644
index 0000000..592320a
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsettempo.c
@@ -0,0 +1,36 @@
+/*====================================================================
+ * seqpsettempo.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetTempo(ALSeqPlayer *seqp, s32 tempo)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_META_EVT;
+ evt.msg.tempo.status = AL_MIDI_Meta;
+ evt.msg.tempo.type = AL_MIDI_META_TEMPO;
+ evt.msg.tempo.byte1 = (tempo & 0xff0000)>>16;
+ evt.msg.tempo.byte2 = (tempo & 0xff00)>>8;
+ evt.msg.tempo.byte3 = tempo & 0xff;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpsetvol.c b/lib/ultralib/src/audio/seqpsetvol.c
new file mode 100644
index 0000000..b698a40
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpsetvol.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * seqpsetvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpSetVol(ALSeqPlayer *seqp, s16 vol)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_VOL_EVT;
+ evt.msg.spvol.vol = vol;
+
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/seqpstop.c b/lib/ultralib/src/audio/seqpstop.c
new file mode 100644
index 0000000..abec781
--- /dev/null
+++ b/lib/ultralib/src/audio/seqpstop.c
@@ -0,0 +1,33 @@
+/*====================================================================
+ * seqpstop.c
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSeqpStop(ALSeqPlayer *seqp)
+{
+ ALEvent evt;
+
+ evt.type = AL_SEQP_STOPPING_EVT;
+ alEvtqPostEvent(&seqp->evtq, &evt, 0);
+
+}
+
diff --git a/lib/ultralib/src/audio/sl.c b/lib/ultralib/src/audio/sl.c
new file mode 100644
index 0000000..d184972
--- /dev/null
+++ b/lib/ultralib/src/audio/sl.c
@@ -0,0 +1,65 @@
+/*====================================================================
+ * sl.c
+ *
+ * Synopsis:
+ * Sound library global routines
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+ALGlobals *alGlobals=0;
+
+void alInit(ALGlobals *g, ALSynConfig *c)
+{
+ if (!alGlobals) { /* already initialized? */
+ alGlobals = g;
+ alSynNew(&alGlobals->drvr, c);
+ }
+}
+
+void alClose(ALGlobals *glob)
+{
+ if (alGlobals) {
+ alSynDelete(&glob->drvr);
+ alGlobals = 0;
+ }
+}
+
+/* might want to make these macros */
+void alLink(ALLink *ln, ALLink *to)
+{
+ ln->next = to->next;
+ ln->prev = to;
+ if (to->next)
+ to->next->prev = ln;
+ to->next = ln;
+}
+
+void alUnlink(ALLink *ln)
+{
+ if (ln->next)
+ ln->next->prev = ln->prev;
+ if (ln->prev)
+ ln->prev->next = ln->next;
+}
+
+
+
+
+
diff --git a/lib/ultralib/src/audio/sndp.h b/lib/ultralib/src/audio/sndp.h
new file mode 100644
index 0000000..17d7015
--- /dev/null
+++ b/lib/ultralib/src/audio/sndp.h
@@ -0,0 +1,102 @@
+/*====================================================================
+ * sndp.h
+ *
+ * Synopsis:
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+
+#ifndef __SNDP__
+#define __SNDP__
+
+#include <libaudio.h>
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define MIN_RATIO 0.0001
+
+typedef enum {
+ AL_SNDP_PLAY_EVT,
+ AL_SNDP_STOP_EVT,
+ AL_SNDP_PAN_EVT,
+ AL_SNDP_VOL_EVT,
+ AL_SNDP_PITCH_EVT,
+ AL_SNDP_API_EVT,
+ AL_SNDP_DECAY_EVT,
+ AL_SNDP_END_EVT,
+ AL_SNDP_FX_EVT
+} ALSndpMsgType;
+
+typedef struct {
+ ALVoice voice;
+ ALSound *sound; /* sound referenced here */
+ s16 priority;
+ f32 pitch; /* current playback pitch */
+ s32 state; /* play state for this sound */
+ s16 vol; /* volume - combined with volume from bank */
+ ALPan pan; /* pan - 0 = left, 127 = right */
+ u8 fxMix; /* wet/dry mix - 0 = dry, 127 = wet */
+} ALSoundState;
+
+typedef union {
+
+ ALEvent msg;
+
+ struct {
+ s16 type;
+ ALSoundState *state;
+ } common;
+
+ struct {
+ s16 type;
+ ALSoundState *state;
+ s16 vol;
+ } vol;
+
+ struct {
+ s16 type;
+ ALSoundState *state;
+ f32 pitch;
+ } pitch;
+
+ struct {
+ s16 type;
+ ALSoundState *state;
+ ALPan pan;
+ } pan;
+
+ struct {
+ s16 type;
+ ALSoundState *state;
+ u8 mix;
+ } fx;
+
+} ALSndpEvent;
+
+static ALMicroTime _sndpVoiceHandler(void *node);
+static void _handleEvent(ALSndPlayer *sndp, ALSndpEvent *event);
+static void _removeEvents(ALEventQueue *evtq, ALSoundState *state);
+static s32 _DivS32ByF32 (s32 i, f32 f);
+
+#endif
diff --git a/lib/ultralib/src/audio/sndpallocate.c b/lib/ultralib/src/audio/sndpallocate.c
new file mode 100644
index 0000000..0629ac7
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpallocate.c
@@ -0,0 +1,43 @@
+/*====================================================================
+ * sndpallocate.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+
+ALSndId alSndpAllocate(ALSndPlayer *sndp, ALSound *sound)
+{
+ ALSndId i;
+ ALSoundState *sState = sndp->sndState;
+
+ for (i = 0; i < sndp->maxSounds; i++) {
+ if (!sState[i].sound) {
+ sState[i].sound = sound;
+ sState[i].priority = AL_DEFAULT_PRIORITY;
+ sState[i].state = AL_STOPPED;
+ sState[i].pitch = 1.0;
+ sState[i].pan = AL_PAN_CENTER;
+ sState[i].fxMix = AL_DEFAULT_FXMIX;
+ sState[i].vol = 32767*sound->sampleVolume/AL_VOL_FULL;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
diff --git a/lib/ultralib/src/audio/sndpdeallocate.c b/lib/ultralib/src/audio/sndpdeallocate.c
new file mode 100644
index 0000000..7c18b56
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpdeallocate.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * sndpdeallocate.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpDeallocate(ALSndPlayer *sndp, ALSndId id)
+{
+ ALSoundState *sState = sndp->sndState;
+
+ ALFailIf((sState + id)->state != AL_STOPPED, ERR_ALSNDPDEALLOCATE);
+
+ sState[id].sound = 0;
+ if (sndp->target == id) /* if we are deleting the target sound */
+ sndp->target = -1;
+}
+
diff --git a/lib/ultralib/src/audio/sndpdelete.c b/lib/ultralib/src/audio/sndpdelete.c
new file mode 100644
index 0000000..5cfb4f7
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpdelete.c
@@ -0,0 +1,44 @@
+/*====================================================================
+ * sndpdelete.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpDelete(ALSndPlayer *sndp)
+{
+ /*
+ * Remove client from synthesizer. Note application is responsible
+ * for making sure all sounds have been stopped beforehand.
+ */
+#ifdef _DEBUG
+ {
+ int i, notStopped = 0;
+ ALSoundState *sState = sndp->sndState;
+
+ for (i=0; i<sndp->maxSounds; i++)
+ if ((sState + i)->state != AL_STOPPED)
+ notStopped = 1;
+ ALFailIf(notStopped, ERR_ALSNDPDELETE);
+ }
+#endif
+ alSynRemovePlayer(&alGlobals->drvr, &sndp->node);
+}
+
diff --git a/lib/ultralib/src/audio/sndpgetsound.c b/lib/ultralib/src/audio/sndpgetsound.c
new file mode 100644
index 0000000..9088982
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpgetsound.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * sndpgetsound.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+
+ALSndId alSndpGetSound(ALSndPlayer *sndp)
+{
+ return (ALSndId) sndp->target;
+}
+
diff --git a/lib/ultralib/src/audio/sndpgetstate.c b/lib/ultralib/src/audio/sndpgetstate.c
new file mode 100644
index 0000000..882b4a3
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpgetstate.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * sndpgetstate.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+
+s32 alSndpGetState(ALSndPlayer *sndp)
+{
+ ALSoundState *sState = sndp->sndState;
+
+ return (sState + sndp->target)->state;
+}
+
diff --git a/lib/ultralib/src/audio/sndplayer.c b/lib/ultralib/src/audio/sndplayer.c
new file mode 100644
index 0000000..391e6ac
--- /dev/null
+++ b/lib/ultralib/src/audio/sndplayer.c
@@ -0,0 +1,300 @@
+/*====================================================================
+ * Sndplayer.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+#include <assert.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void alSndpNew(ALSndPlayer *sndp, ALSndpConfig *c)
+{
+ u8 *ptr;
+ ALEvent evt;
+ ALSoundState *sState;
+ u32 i;
+
+ /*
+ * Init member variables
+ */
+ sndp->maxSounds = c->maxSounds;
+ sndp->target = -1;
+ sndp->frameTime = AL_USEC_PER_FRAME; /* time between API events */
+ sState = (ALSoundState*)alHeapAlloc(c->heap, 1,
+ c->maxSounds * sizeof(ALSoundState));
+ sndp->sndState = sState;
+
+ for(i = 0; i < c->maxSounds; i++)
+ sState[i].sound = 0;
+
+ /*
+ * init the event queue
+ */
+ ptr = alHeapAlloc(c->heap, 1, c->maxEvents * sizeof(ALEventListItem));
+ alEvtqNew(&sndp->evtq, (ALEventListItem *)ptr, c->maxEvents);
+
+ /*
+ * add ourselves to the driver
+ */
+ sndp->drvr = &alGlobals->drvr;
+ sndp->node.next = NULL;
+ sndp->node.handler = _sndpVoiceHandler;
+ sndp->node.clientData = sndp;
+ alSynAddPlayer(sndp->drvr, &sndp->node);
+
+ /*
+ * Start responding to API events
+ */
+ evt.type = AL_SNDP_API_EVT;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, sndp->frameTime);
+ sndp->nextDelta = alEvtqNextEvent(&sndp->evtq, &sndp->nextEvent);
+
+}
+
+/*************************************************************
+ * Sound Player private routines
+ *************************************************************/
+ALMicroTime _sndpVoiceHandler(void *node)
+{
+ ALSndPlayer *sndp = (ALSndPlayer *) node;
+ ALSndpEvent evt;
+
+ do {
+ switch (sndp->nextEvent.type) {
+ case (AL_SNDP_API_EVT):
+ evt.common.type = AL_SNDP_API_EVT;
+ evt.common.state = (ALSoundState*)-1;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, sndp->frameTime);
+ break;
+
+ default:
+ _handleEvent(sndp, (ALSndpEvent *)&sndp->nextEvent);
+ break;
+ }
+ sndp->nextDelta = alEvtqNextEvent(&sndp->evtq, &sndp->nextEvent);
+
+ } while (sndp->nextDelta == 0);
+ sndp->curTime += sndp->nextDelta;
+ return sndp->nextDelta;
+}
+
+void _handleEvent(ALSndPlayer *sndp, ALSndpEvent *event)
+{
+ ALVoiceConfig vc;
+ ALSound *snd;
+ ALVoice *voice;
+ ALPan pan;
+ f32 pitch;
+ ALSndpEvent evt;
+ ALMicroTime delta;
+
+ s16 vol;
+ s16 tmp;
+ s32 vtmp;
+ ALSoundState *state;
+
+ state = event->common.state;
+ snd = state->sound;
+
+
+ switch (event->msg.type) {
+ case (AL_SNDP_PLAY_EVT):
+ if (state->state != AL_STOPPED || !snd)
+ return;
+
+ vc.fxBus = 0; /* effect buss 0 */
+ vc.priority = state->priority;
+ vc.unityPitch = 0;
+
+ voice = &state->voice;
+ alSynAllocVoice(sndp->drvr, voice, &vc);
+
+ vol = (s16) ((s32) snd->envelope->attackVolume*state->vol/AL_VOL_FULL);
+ tmp = state->pan - AL_PAN_CENTER + snd->samplePan;
+ tmp = MAX(tmp, AL_PAN_LEFT);
+ pan = (ALPan) MIN(tmp, AL_PAN_RIGHT);
+ pitch = state->pitch;
+ delta = snd->envelope->attackTime;
+
+ alSynStartVoice(sndp->drvr, voice, snd->wavetable);
+ state->state = AL_PLAYING;
+
+ alSynSetPan(sndp->drvr, voice, pan);
+ alSynSetVol(sndp->drvr, voice, vol, delta);
+ alSynSetPitch(sndp->drvr, voice, pitch);
+ alSynSetFXMix(sndp->drvr, voice, state->fxMix);
+
+ evt.common.type = AL_SNDP_DECAY_EVT;
+ evt.common.state = state;
+ delta = (ALMicroTime) _DivS32ByF32 (snd->envelope->attackTime, state->pitch);
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, delta);
+ break;
+
+ case (AL_SNDP_STOP_EVT):
+ if (state->state != AL_PLAYING || !snd)
+ return;
+
+ delta = (ALMicroTime) _DivS32ByF32 (snd->envelope->releaseTime, state->pitch);
+ alSynSetVol(sndp->drvr, &state->voice, 0, delta);
+
+ if (delta) {
+ evt.common.type = AL_SNDP_END_EVT;
+ evt.common.state = state;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, delta);
+ state->state = AL_STOPPING;
+ } else {
+ /* note: this code is repeated in AL_SNDP_END_EVT */
+ alSynStopVoice(sndp->drvr, &state->voice);
+ alSynFreeVoice(sndp->drvr, &state->voice);
+ _removeEvents(&sndp->evtq, state);
+ state->state = AL_STOPPED;
+ }
+ break;
+
+ case (AL_SNDP_PAN_EVT):
+ state->pan = event->pan.pan;
+ if (state->state == AL_PLAYING && snd){
+ tmp = state->pan - AL_PAN_CENTER + snd->samplePan;
+ tmp = MAX(tmp, AL_PAN_LEFT);
+ pan = (ALPan) MIN(tmp, AL_PAN_RIGHT);
+ alSynSetPan(sndp->drvr, &state->voice, pan);
+ }
+ break;
+
+ case (AL_SNDP_PITCH_EVT):
+ /* Limit the pitch to a practical value even though we only need */
+ /* to limit it to a non-zero number to avoid divide by zero. */
+ if ((state->pitch = event->pitch.pitch) < MIN_RATIO)
+ state->pitch = MIN_RATIO;
+
+ if (state->state == AL_PLAYING){
+ alSynSetPitch(sndp->drvr, &state->voice, state->pitch);
+ }
+ break;
+
+ case (AL_SNDP_FX_EVT):
+ state->fxMix = event->fx.mix;
+ if (state->state == AL_PLAYING)
+ alSynSetFXMix(sndp->drvr, &state->voice, state->fxMix);
+ break;
+
+ case (AL_SNDP_VOL_EVT):
+ state->vol = event->vol.vol;
+ if (state->state == AL_PLAYING && snd){
+ vtmp = snd->envelope->decayVolume * state->vol/AL_VOL_FULL;
+ alSynSetVol(sndp->drvr, &state->voice, (s16) vtmp, 1000);
+ }
+ break;
+
+ case (AL_SNDP_DECAY_EVT):
+ /*
+ * The voice has theoretically reached its attack velocity,
+ * set up callback for release envelope - except for a looped sound
+ */
+ if (snd->envelope->decayTime != -1){
+ vtmp = snd->envelope->decayVolume * state->vol/AL_VOL_FULL;
+ delta = (ALMicroTime) _DivS32ByF32 (snd->envelope->decayTime, state->pitch);
+ alSynSetVol(sndp->drvr, &state->voice, (s16) vtmp, delta);
+ evt.common.type = AL_SNDP_STOP_EVT;
+ evt.common.state = state;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, delta);
+ }
+ break;
+
+ case (AL_SNDP_END_EVT):
+ /* note: this code is repeated in AL_SNDP_STOP_EVT */
+ alSynStopVoice(sndp->drvr, &state->voice);
+ alSynFreeVoice(sndp->drvr, &state->voice);
+ _removeEvents(&sndp->evtq, state);
+ state->state = AL_STOPPED;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static
+void _removeEvents(ALEventQueue *evtq, ALSoundState *state)
+{
+ ALLink *thisNode;
+ ALLink *nextNode;
+ ALEventListItem *thisItem;
+ ALEventListItem *nextItem;
+ ALSndpEvent *thisEvent;
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ thisNode = evtq->allocList.next;
+ while( thisNode != 0 ) {
+ nextNode = thisNode->next;
+ thisItem = (ALEventListItem *)thisNode;
+ nextItem = (ALEventListItem *)nextNode;
+ thisEvent = (ALSndpEvent *) &thisItem->evt;
+ if (thisEvent->common.state == state){
+ if( nextItem )
+ nextItem->delta += thisItem->delta;
+ alUnlink(thisNode);
+ alLink(thisNode, &evtq->freeList);
+ }
+ thisNode = nextNode;
+ }
+
+ osSetIntMask(mask);
+}
+
+
+/*
+ This routine safely divides a signed 32-bit integer
+ by a floating point value. It avoids overflow by using
+ a double to store the result and then before truncating
+ to an integer it compares the result to the limit and
+ limits it on overflow. Underflow is handled automatically
+ by the CPU which limits the value to zero.
+
+ Presently this routine is used to divide a time in usecs
+ by a pitch ratio. Since the time could be a very large number,
+ very small pitch ratios can cause the reult to overflow,
+ causing a floating point exception.
+*/
+static
+s32 _DivS32ByF32 (s32 i, f32 f)
+{
+ #define INT_MAX 2147483647 /* Should be in a limits.h file. */
+
+ f64 rd;
+ int ri;
+
+#ifdef _DEBUG
+ assert(f!=0); /* Caller must make sure we do not divide by zero! */
+#endif
+
+ rd = i/f; /* Store result as a double to avoid overflow. */
+
+ if (rd > INT_MAX) /* Limit the value if necessary. */
+ ri = INT_MAX;
+ else
+ ri = rd;
+
+ return ri;
+}
diff --git a/lib/ultralib/src/audio/sndpplay.c b/lib/ultralib/src/audio/sndpplay.c
new file mode 100644
index 0000000..ff5d123
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpplay.c
@@ -0,0 +1,36 @@
+/*====================================================================
+ * sndpplay.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpPlay(ALSndPlayer *sndp)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+ ALFailIf((sState + sndp->target)->state != AL_STOPPED, ERR_ALSNDPPLAY);
+
+ evt.common.type = AL_SNDP_PLAY_EVT;
+ evt.common.state = &sState[sndp->target];
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/sndpplayat.c b/lib/ultralib/src/audio/sndpplayat.c
new file mode 100644
index 0000000..b37f796
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpplayat.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * sndpplayat.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+
+void alSndpPlayAt(ALSndPlayer *sndp, ALMicroTime delta)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+ evt.common.type = AL_SNDP_PLAY_EVT;
+ evt.common.state = &sState[sndp->target];
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, delta);
+}
+
diff --git a/lib/ultralib/src/audio/sndpsetfxmix.c b/lib/ultralib/src/audio/sndpsetfxmix.c
new file mode 100644
index 0000000..147c956
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpsetfxmix.c
@@ -0,0 +1,42 @@
+/*====================================================================
+ * sndpsetfxmix.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpSetFXMix(ALSndPlayer *sndp, u8 mix)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+#ifdef _DEBUG
+ if ((sndp->target >= sndp->maxSounds) || (sndp->target < 0)){
+ __osError(ERR_ALSNDPSETPAR, 2, sndp->target, sndp->maxSounds-1);
+ return;
+ }
+#endif
+
+ evt.fx.type = AL_SNDP_FX_EVT;
+ evt.fx.state = &sState[sndp->target];
+ evt.fx.mix = mix;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/sndpsetpan.c b/lib/ultralib/src/audio/sndpsetpan.c
new file mode 100644
index 0000000..5f98648
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpsetpan.c
@@ -0,0 +1,42 @@
+/*====================================================================
+ * sndpsetpan.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpSetPan(ALSndPlayer *sndp, ALPan pan)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+#ifdef _DEBUG
+ if ((sndp->target >= sndp->maxSounds) || (sndp->target < 0)){
+ __osError(ERR_ALSNDPSETPAR, 2, sndp->target, sndp->maxSounds-1);
+ return;
+ }
+#endif
+
+ evt.pan.type = AL_SNDP_PAN_EVT;
+ evt.pan.pan = pan;
+ evt.pan.state = &sState[sndp->target];
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/sndpsetpitch.c b/lib/ultralib/src/audio/sndpsetpitch.c
new file mode 100644
index 0000000..0ee174c
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpsetpitch.c
@@ -0,0 +1,48 @@
+/*====================================================================
+ * sndpsetpitch.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpSetPitch(ALSndPlayer *sndp, f32 pitch)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+ /*
+ * If this is set during playback there will be
+ * a the envelope lengths won't be accurate - but you can still
+ * do it.
+ */
+
+#ifdef _DEBUG
+ if ((sndp->target >= sndp->maxSounds) || (sndp->target < 0)){
+ __osError(ERR_ALSNDPSETPAR, 2, sndp->target, sndp->maxSounds-1);
+ return;
+ }
+#endif
+
+ evt.pitch.type = AL_SNDP_PITCH_EVT;
+ evt.pitch.state = &sState[sndp->target];
+ evt.pitch.pitch = pitch;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/sndpsetpriority.c b/lib/ultralib/src/audio/sndpsetpriority.c
new file mode 100644
index 0000000..0d0fbc0
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpsetpriority.c
@@ -0,0 +1,38 @@
+/*====================================================================
+ * sndpsetsound.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpSetPriority(ALSndPlayer *sndp, ALSndId id, u8 priority)
+{
+ ALSoundState *sState = sndp->sndState;
+
+#ifdef _DEBUG
+ if ((id >= sndp->maxSounds) || (id < 0)){
+ __osError(ERR_ALSNDPSETPRIORITY, 2, id, sndp->maxSounds-1);
+ return;
+ }
+#endif
+
+ sState[id].priority = priority;
+}
+
diff --git a/lib/ultralib/src/audio/sndpsetsound.c b/lib/ultralib/src/audio/sndpsetsound.c
new file mode 100644
index 0000000..3d341ec
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpsetsound.c
@@ -0,0 +1,36 @@
+/*====================================================================
+ * sndpsetsound.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpSetSound(ALSndPlayer *sndp, ALSndId id)
+{
+#ifdef _DEBUG
+ if ((id >= sndp->maxSounds) || (id < 0)){
+ __osError(ERR_ALSNDPSETSOUND, 2, id, sndp->maxSounds-1);
+ return;
+ }
+#endif
+
+ sndp->target = id;
+}
+
diff --git a/lib/ultralib/src/audio/sndpsetvol.c b/lib/ultralib/src/audio/sndpsetvol.c
new file mode 100644
index 0000000..ad79f5f
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpsetvol.c
@@ -0,0 +1,42 @@
+/*====================================================================
+ * sndpsetvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSndpSetVol(ALSndPlayer *sndp, s16 vol)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+#ifdef _DEBUG
+ if ((sndp->target >= sndp->maxSounds) || (sndp->target < 0)){
+ __osError(ERR_ALSNDPSETPAR, 2, sndp->target, sndp->maxSounds-1);
+ return;
+ }
+#endif
+
+ evt.vol.type = AL_SNDP_VOL_EVT;
+ evt.vol.state = &sState[sndp->target];
+ evt.vol.vol = vol;
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/sndpstop.c b/lib/ultralib/src/audio/sndpstop.c
new file mode 100644
index 0000000..69aead6
--- /dev/null
+++ b/lib/ultralib/src/audio/sndpstop.c
@@ -0,0 +1,35 @@
+/*====================================================================
+ * sndpstop.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "sndp.h"
+
+void alSndpStop(ALSndPlayer *sndp)
+{
+ ALSndpEvent evt;
+ ALSoundState *sState = sndp->sndState;
+
+ /*
+ * Go immediately into the release phase
+ */
+ evt.common.type = AL_SNDP_STOP_EVT;
+ evt.common.state = &sState[sndp->target];
+ alEvtqPostEvent(&sndp->evtq, (ALEvent *)&evt, 0);
+}
+
diff --git a/lib/ultralib/src/audio/synaddplayer.c b/lib/ultralib/src/audio/synaddplayer.c
new file mode 100644
index 0000000..77efb29
--- /dev/null
+++ b/lib/ultralib/src/audio/synaddplayer.c
@@ -0,0 +1,34 @@
+/*====================================================================
+ * synaddplayer.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+
+void alSynAddPlayer(ALSynth *drvr, ALPlayer *client)
+{
+ OSIntMask mask = osSetIntMask(OS_IM_NONE);
+
+ client->samplesLeft = drvr->curSamples;
+ client->next = drvr->head;
+ drvr->head = client;
+
+ osSetIntMask(mask);
+}
+
diff --git a/lib/ultralib/src/audio/synallocfx.c b/lib/ultralib/src/audio/synallocfx.c
new file mode 100644
index 0000000..e0e7f26
--- /dev/null
+++ b/lib/ultralib/src/audio/synallocfx.c
@@ -0,0 +1,32 @@
+/*====================================================================
+ * synallocfx.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+
+ALFxRef *alSynAllocFX(ALSynth *s, s16 bus, ALSynConfig *c, ALHeap *hp)
+{
+ alFxNew(&s->auxBus[bus].fx[0], c, hp);
+ alFxParam(&s->auxBus[bus].fx[0], AL_FILTER_SET_SOURCE,
+ &s->auxBus[bus]);
+ alMainBusParam(s->mainBus, AL_FILTER_ADD_SOURCE,&s->auxBus[bus].fx[0]);
+
+ return (ALFxRef)(&s->auxBus[bus].fx[0]);
+}
+
diff --git a/lib/ultralib/src/audio/synallocvoice.c b/lib/ultralib/src/audio/synallocvoice.c
new file mode 100644
index 0000000..73d608d
--- /dev/null
+++ b/lib/ultralib/src/audio/synallocvoice.c
@@ -0,0 +1,132 @@
+/*====================================================================
+ * synallocvoice.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <os_internal.h>
+#include <ultraerror.h>
+#include "synthInternals.h"
+
+s32 _allocatePVoice(ALSynth *drvr, PVoice **pvoice, s16 priority);
+
+s32 alSynAllocVoice(ALSynth *drvr, ALVoice *voice, ALVoiceConfig *vc)
+{
+ PVoice *pvoice = 0;
+ ALFilter *f;
+ ALParam *update;
+ s32 stolen;
+
+#ifdef _DEBUG
+ /* need two updates if voice is stolen */
+ if (drvr->paramList == 0) {
+ __osError(ERR_ALSYN_NO_UPDATE, 0);
+ return 0;
+ } else if (drvr->paramList->next == 0) {
+ __osError(ERR_ALSYN_NO_UPDATE, 0);
+ return 0;
+ }
+#endif
+
+ voice->priority = vc->priority;
+ voice->unityPitch = vc->unityPitch;
+ voice->table = 0;
+ voice->fxBus = vc->fxBus;
+ voice->state = AL_STOPPED;
+ voice->pvoice = 0;
+
+ stolen = _allocatePVoice(drvr, &pvoice, vc->priority);
+
+ if (pvoice) { /* if we were able to allocate a voice */
+
+ f = pvoice->channelKnob;
+
+ if (stolen) {
+
+ pvoice->offset = 512;
+ pvoice->vvoice->pvoice = 0; /* zero stolen voice */
+
+ /*
+ * ramp down stolen voice
+ */
+ update = __allocParam();
+ update->delta = drvr->paramSamples;
+ update->type = AL_FILTER_SET_VOLUME;
+ update->data.i = 0;
+ update->moredata.i = pvoice->offset - 64;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+
+ /*
+ * stop stolen voice
+ */
+ update = __allocParam();
+ if (update) {
+ update->delta = drvr->paramSamples + pvoice->offset;
+ update->type = AL_FILTER_STOP_VOICE;
+ update->next = 0;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ } else {
+#ifdef _DEBUG
+ __osError(ERR_ALSYN_NO_UPDATE, 0);
+#endif
+ }
+
+ } else {
+ pvoice->offset = 0;
+ }
+
+ pvoice->vvoice = voice; /* assign new voice */
+ voice->pvoice = pvoice;
+
+ }
+
+ return (pvoice != 0);
+}
+
+s32 _allocatePVoice(ALSynth *drvr, PVoice **pvoice, s16 priority)
+{
+ ALLink *dl;
+ PVoice *pv;
+ s32 stolen = 0;
+
+ if ((dl = drvr->pLameList.next) != 0) { /* check the lame list first */
+ *pvoice = (PVoice *) dl;
+ alUnlink(dl);
+ alLink(dl, &drvr->pAllocList);
+ } else if ((dl = drvr->pFreeList.next) != 0) { /* from the free list */
+ *pvoice = (PVoice *) dl;
+ alUnlink(dl);
+ alLink(dl, &drvr->pAllocList);
+ } else { /* steal one */
+ for (dl = drvr->pAllocList.next; dl != 0; dl = dl->next) {
+ pv = (PVoice *)dl;
+
+ /*
+ * if it is lower priority and not already stolen, keep it
+ * as a candidate for stealing
+ */
+ if ((pv->vvoice->priority <= priority) && (pv->offset == 0)) {
+ *pvoice = pv;
+ priority = pv->vvoice->priority;
+ stolen = 1;
+ }
+ }
+ }
+
+ return stolen;
+}
+
diff --git a/lib/ultralib/src/audio/syndelete.c b/lib/ultralib/src/audio/syndelete.c
new file mode 100644
index 0000000..900fe76
--- /dev/null
+++ b/lib/ultralib/src/audio/syndelete.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * syndelete.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+
+void alSynDelete(ALSynth *drvr)
+{
+ drvr->head = 0;
+}
+
diff --git a/lib/ultralib/src/audio/synfreefx.c b/lib/ultralib/src/audio/synfreefx.c
new file mode 100644
index 0000000..be436ea
--- /dev/null
+++ b/lib/ultralib/src/audio/synfreefx.c
@@ -0,0 +1,26 @@
+/*====================================================================
+ * synfreefx.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+
+void alSynFreeFX(ALSynth *s, ALFxRef *fx)
+{
+}
+
diff --git a/lib/ultralib/src/audio/synfreevoice.c b/lib/ultralib/src/audio/synfreevoice.c
new file mode 100644
index 0000000..eaa71ac
--- /dev/null
+++ b/lib/ultralib/src/audio/synfreevoice.c
@@ -0,0 +1,54 @@
+/*====================================================================
+ * synfreevoice.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <ultraerror.h>
+#include <os_internal.h>
+#include "synthInternals.h"
+
+#include <os.h>
+
+void alSynFreeVoice(ALSynth *drvr, ALVoice *voice)
+{
+ ALFilter *f;
+ ALFreeParam *update;
+
+ if (voice->pvoice) {
+
+ if (voice->pvoice->offset) { /* if voice was stolen */
+ update = (ALFreeParam *)__allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ /*
+ * set voice data
+ */
+ update->delta = drvr->paramSamples + voice->pvoice->offset;
+ update->type = AL_FILTER_FREE_VOICE;
+ update->pvoice = voice->pvoice;
+
+ f = voice->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ } else {
+ _freePVoice(drvr, voice->pvoice);
+ }
+
+ voice->pvoice = 0;
+
+ }
+}
diff --git a/lib/ultralib/src/audio/syngetfxref.c b/lib/ultralib/src/audio/syngetfxref.c
new file mode 100644
index 0000000..b0fa577
--- /dev/null
+++ b/lib/ultralib/src/audio/syngetfxref.c
@@ -0,0 +1,33 @@
+/*====================================================================
+ * syngetfxref.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+
+ALFxRef alSynGetFXRef(ALSynth *s, s16 bus, s16 index)
+{
+ ALMainBus *m = (ALMainBus *) s->mainBus;
+ ALFilter **sources = m->sources;
+
+ if (sources[0]->type == AL_FX)
+ return (ALFxRef)(&s->auxBus[bus].fx[index]);
+ else
+ return 0;
+}
+
diff --git a/lib/ultralib/src/audio/syngetpriority.c b/lib/ultralib/src/audio/syngetpriority.c
new file mode 100644
index 0000000..68de365
--- /dev/null
+++ b/lib/ultralib/src/audio/syngetpriority.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * syngetpriority.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+
+s16 alSynGetPriority(ALSynth *s, ALVoice *voice)
+{
+ return voice->priority;
+}
+
diff --git a/lib/ultralib/src/audio/synremoveplayer.c b/lib/ultralib/src/audio/synremoveplayer.c
new file mode 100644
index 0000000..0248a7e
--- /dev/null
+++ b/lib/ultralib/src/audio/synremoveplayer.c
@@ -0,0 +1,49 @@
+/*====================================================================
+ * synremoveplayer.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+
+void alSynRemovePlayer(ALSynth *drvr, ALPlayer *client)
+{
+ ALPlayer *thing;
+ ALPlayer *prev = 0;
+
+ if (drvr->head != 0)
+ {
+ OSIntMask mask = osSetIntMask(OS_IM_NONE);
+
+ for (thing = drvr->head; thing != 0; thing = thing->next) {
+ if (thing == client) {
+ if(prev)
+ prev->next = thing->next;
+ else
+ drvr->head = thing->next;
+
+ client->next = 0;
+ break;
+ }
+ prev = thing;
+ }
+
+ osSetIntMask(mask);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synsetfxmix.c b/lib/ultralib/src/audio/synsetfxmix.c
new file mode 100644
index 0000000..8c156ab
--- /dev/null
+++ b/lib/ultralib/src/audio/synsetfxmix.c
@@ -0,0 +1,51 @@
+/*====================================================================
+ * synsetfxmix.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSynSetFXMix(ALSynth *synth, ALVoice *v, u8 fxmix)
+{
+ ALParam *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+ /*
+ * get new update struct from the free list
+ */
+ update = __allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ /*
+ * set offset and fxmix data
+ */
+ update->delta = synth->paramSamples + v->pvoice->offset;
+ update->type = AL_FILTER_SET_FXAMT;
+ if (fxmix > 127)
+ fxmix = 127;
+ update->data.i = fxmix;
+ update->next = 0;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synsetfxparam.c b/lib/ultralib/src/audio/synsetfxparam.c
new file mode 100644
index 0000000..b3991f6
--- /dev/null
+++ b/lib/ultralib/src/audio/synsetfxparam.c
@@ -0,0 +1,29 @@
+/*====================================================================
+ * synsetfxparam.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+
+void alSynSetFXParam(ALSynth *synth, ALFxRef fx, s16 paramID, void *param)
+{
+ ALFx *f = (ALFx *)fx;
+
+ (*f->paramHdl)(f, (s32)paramID, param);
+}
+
diff --git a/lib/ultralib/src/audio/synsetpan.c b/lib/ultralib/src/audio/synsetpan.c
new file mode 100644
index 0000000..0d68538
--- /dev/null
+++ b/lib/ultralib/src/audio/synsetpan.c
@@ -0,0 +1,50 @@
+/*====================================================================
+ * synsetpan.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSynSetPan(ALSynth *synth, ALVoice *v, u8 pan)
+{
+ ALParam *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+
+ /*
+ * get new update struct from the free list
+ */
+ update = __allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ /*
+ * set offset and pan data
+ */
+ update->delta = synth->paramSamples + v->pvoice->offset;
+ update->type = AL_FILTER_SET_PAN;
+ update->data.i = pan;
+ update->next = 0;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synsetpitch.c b/lib/ultralib/src/audio/synsetpitch.c
new file mode 100644
index 0000000..0bfb7ba
--- /dev/null
+++ b/lib/ultralib/src/audio/synsetpitch.c
@@ -0,0 +1,50 @@
+/*====================================================================
+ * synsetpitch.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSynSetPitch(ALSynth *synth, ALVoice *v, f32 pitch)
+{
+ ALParam *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+ /*
+ * get new update struct from the free list
+ */
+
+ update = __allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ /*
+ * set offset and pitch data
+ */
+ update->delta = synth->paramSamples + v->pvoice->offset;
+ update->type = AL_FILTER_SET_PITCH;
+ update->data.f = pitch;
+ update->next = 0;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synsetpriority.c b/lib/ultralib/src/audio/synsetpriority.c
new file mode 100644
index 0000000..c680bcc
--- /dev/null
+++ b/lib/ultralib/src/audio/synsetpriority.c
@@ -0,0 +1,27 @@
+/*====================================================================
+ * synsetpriority.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <libaudio.h>
+
+void alSynSetPriority(ALSynth *s, ALVoice *voice, s16 priority)
+{
+ voice->priority = priority;
+}
+
diff --git a/lib/ultralib/src/audio/synsetvol.c b/lib/ultralib/src/audio/synsetvol.c
new file mode 100644
index 0000000..181c96f
--- /dev/null
+++ b/lib/ultralib/src/audio/synsetvol.c
@@ -0,0 +1,50 @@
+/*====================================================================
+ * synsetvol.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSynSetVol(ALSynth *synth, ALVoice *v, s16 volume, ALMicroTime t)
+{
+ ALParam *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+ /*
+ * get new update struct from the free list
+ */
+ update = __allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ /*
+ * set offset and volume data
+ */
+ update->delta = synth->paramSamples + v->pvoice->offset;
+ update->type = AL_FILTER_SET_VOLUME;
+ update->data.i = volume;
+ update->moredata.i = _timeToSamples(synth, t);
+ update->next = 0;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synstartvoice.c b/lib/ultralib/src/audio/synstartvoice.c
new file mode 100644
index 0000000..9ad1d89
--- /dev/null
+++ b/lib/ultralib/src/audio/synstartvoice.c
@@ -0,0 +1,48 @@
+/*====================================================================
+ * synstartvoice.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+void alSynStartVoice(ALSynth *synth, ALVoice *v, ALWaveTable *table)
+{
+ ALStartParam *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+
+ update = (ALStartParam *)__allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ /*
+ * send the start message to the motion control filter
+ */
+ update->delta = synth->paramSamples + v->pvoice->offset;
+ update->type = AL_FILTER_START_VOICE;
+ update->wave = table;
+ update->next = 0;
+ update->unity = v->unityPitch;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synstartvoiceparam.c b/lib/ultralib/src/audio/synstartvoiceparam.c
new file mode 100644
index 0000000..dbede0f
--- /dev/null
+++ b/lib/ultralib/src/audio/synstartvoiceparam.c
@@ -0,0 +1,64 @@
+/*====================================================================
+ * synquickstartvoice
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <libaudio.h>
+#include <ultraerror.h>
+#include <os_internal.h>
+
+void alSynStartVoiceParams(ALSynth *s, ALVoice *v, ALWaveTable *w,
+ f32 pitch, s16 vol, ALPan pan, u8 fxmix,
+ ALMicroTime t)
+{
+ ALStartParamAlt *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+ /*
+ * get new update struct from the free list
+ */
+ update = (ALStartParamAlt *)__allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ if (fxmix > 127)
+ fxmix = 127;
+
+ /*
+ * set offset and fxmix data
+ */
+ update->delta = s->paramSamples + v->pvoice->offset;
+ update->next = 0;
+ update->type = AL_FILTER_START_VOICE_ALT;
+
+ update->unity = v->unityPitch;
+ update->pan = pan;
+ update->volume = vol;
+ update->fxMix = fxmix;
+ update->pitch = pitch;
+ update->samples = _timeToSamples(s, t);
+ update->wave = w;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+
+}
+
+
diff --git a/lib/ultralib/src/audio/synstopvoice.c b/lib/ultralib/src/audio/synstopvoice.c
new file mode 100644
index 0000000..69c09d8
--- /dev/null
+++ b/lib/ultralib/src/audio/synstopvoice.c
@@ -0,0 +1,44 @@
+/*====================================================================
+ * synstopvoice.c
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <os_internal.h>
+#include <ultraerror.h>
+
+
+void alSynStopVoice(ALSynth *synth, ALVoice *v)
+{
+ ALParam *update;
+ ALFilter *f;
+
+ if (v->pvoice) {
+
+ update = __allocParam();
+ ALFailIf(update == 0, ERR_ALSYN_NO_UPDATE);
+
+ update->delta = synth->paramSamples + v->pvoice->offset;
+ update->type = AL_FILTER_STOP_VOICE;
+ update->next = 0;
+
+ f = v->pvoice->channelKnob;
+ (*f->setParam)(f, AL_FILTER_ADD_UPDATE, update);
+ }
+}
+
diff --git a/lib/ultralib/src/audio/synthInternals.h b/lib/ultralib/src/audio/synthInternals.h
new file mode 100644
index 0000000..07c08bc
--- /dev/null
+++ b/lib/ultralib/src/audio/synthInternals.h
@@ -0,0 +1,338 @@
+/*====================================================================
+ * audioInternals.h
+ *
+ * Synopsis:
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#ifndef __audioInternals__
+#define __audioInternals__
+
+#include <libaudio.h>
+
+/*
+ * filter message ids
+ */
+enum {
+ AL_FILTER_FREE_VOICE,
+ AL_FILTER_SET_SOURCE,
+ AL_FILTER_ADD_SOURCE,
+ AL_FILTER_ADD_UPDATE,
+ AL_FILTER_RESET,
+ AL_FILTER_SET_WAVETABLE,
+/* AL_FILTER_SET_DMA_PROC,*/
+/* AL_FILTER_SKIP_LOOP,*/
+ AL_FILTER_SET_DRAM,
+ AL_FILTER_SET_PITCH,
+ AL_FILTER_SET_UNITY_PITCH,
+ AL_FILTER_START,
+/* AL_FILTER_SET_DECAY,*/
+/* AL_FILTER_SET_FC,*/
+ AL_FILTER_SET_STATE,
+ AL_FILTER_SET_VOLUME,
+ AL_FILTER_SET_PAN,
+ AL_FILTER_START_VOICE_ALT,
+ AL_FILTER_START_VOICE,
+ AL_FILTER_STOP_VOICE,
+ AL_FILTER_SET_FXAMT
+};
+
+#define AL_MAX_RSP_SAMPLES 160
+
+/*
+ * buffer locations based on AL_MAX_RSP_SAMPLES
+ */
+#define AL_DECODER_IN 0
+#define AL_RESAMPLER_OUT 0
+#define AL_TEMP_0 0
+#define AL_DECODER_OUT 320
+#define AL_TEMP_1 320
+#define AL_TEMP_2 640
+#define AL_MAIN_L_OUT 1088
+#define AL_MAIN_R_OUT 1408
+#define AL_AUX_L_OUT 1728
+#define AL_AUX_R_OUT 2048
+
+/*
+ * filter types
+ */
+enum {
+ AL_ADPCM,
+ AL_RESAMPLE,
+ AL_BUFFER,
+ AL_SAVE,
+ AL_ENVMIX,
+ AL_FX,
+ AL_AUXBUS,
+ AL_MAINBUS
+};
+
+typedef struct ALParam_s {
+ struct ALParam_s *next;
+ s32 delta;
+ s16 type;
+ union {
+ f32 f;
+ s32 i;
+ } data;
+ union {
+ f32 f;
+ s32 i;
+ } moredata;
+ union {
+ f32 f;
+ s32 i;
+ } stillmoredata;
+ union {
+ f32 f;
+ s32 i;
+ } yetstillmoredata;
+} ALParam;
+
+typedef struct {
+ struct ALParam_s *next;
+ s32 delta;
+ s16 type;
+ s16 unity; /* disable resampler */
+ f32 pitch;
+ s16 volume;
+ ALPan pan;
+ u8 fxMix;
+ s32 samples;
+ struct ALWaveTable_s *wave;
+} ALStartParamAlt;
+
+typedef struct {
+ struct ALParam_s *next;
+ s32 delta;
+ s16 type;
+ s16 unity; /* disable resampler */
+ struct ALWaveTable_s *wave;
+} ALStartParam;
+
+typedef struct {
+ struct ALParam_s *next;
+ s32 delta;
+ s16 type;
+ struct PVoice_s *pvoice;
+} ALFreeParam;
+
+typedef Acmd *(*ALCmdHandler)(void *, s16 *, s32, s32, Acmd *);
+typedef s32 (*ALSetParam)(void *, s32, void *);
+
+typedef struct ALFilter_s {
+ struct ALFilter_s *source;
+ ALCmdHandler handler;
+ ALSetParam setParam;
+ s16 inp;
+ s16 outp;
+ s32 type;
+} ALFilter;
+
+void alFilterNew(ALFilter *f, ALCmdHandler h, ALSetParam s, s32 type);
+
+#define AL_MAX_ADPCM_STATES 3 /* Depends on number of subframes
+ * per frame and loop length
+ */
+typedef struct {
+ ALFilter filter;
+ ADPCM_STATE *state;
+ ADPCM_STATE *lstate;
+ ALRawLoop loop;
+ struct ALWaveTable_s *table;
+ s32 bookSize;
+ ALDMAproc dma;
+ void *dmaState;
+ s32 sample;
+ s32 lastsam;
+ s32 first;
+ s32 memin;
+} ALLoadFilter;
+
+void alLoadNew(ALLoadFilter *f, ALDMANew dma, ALHeap *hp);
+Acmd *alAdpcmPull(void *f, s16 *outp, s32 byteCount, s32 sampleOffset, Acmd *p);
+Acmd *alRaw16Pull(void *f, s16 *outp, s32 byteCount, s32 sampleOffset, Acmd *p);
+s32 alLoadParam(void *filter, s32 paramID, void *param);
+
+typedef struct ALResampler_s {
+ ALFilter filter;
+ RESAMPLE_STATE *state;
+ f32 ratio;
+ s32 upitch;
+ f32 delta;
+ s32 first;
+ ALParam *ctrlList;
+ ALParam *ctrlTail;
+ s32 motion;
+} ALResampler;
+
+typedef struct {
+ s16 fc;
+ s16 fgain;
+ union {
+ s16 fccoef[16];
+ s64 force_aligned;
+ } fcvec;
+ POLEF_STATE *fstate;
+ s32 first;
+} ALLowPass;
+
+typedef struct {
+ u32 input;
+ u32 output;
+ s16 ffcoef;
+ s16 fbcoef;
+ s16 gain;
+ f32 rsinc;
+ f32 rsval;
+ s32 rsdelta;
+ f32 rsgain;
+ ALLowPass *lp;
+ ALResampler *rs;
+} ALDelay;
+
+typedef s32 (*ALSetFXParam)(void *, s32, void *);
+typedef struct {
+ struct ALFilter_s filter;
+ s16 *base;
+ s16 *input;
+ u32 length;
+ ALDelay *delay;
+ u8 section_count;
+ ALSetFXParam paramHdl;
+} ALFx;
+
+void alFxNew(ALFx *r, ALSynConfig *c, ALHeap *hp);
+Acmd *alFxPull(void *f, s16 *outp, s32 out, s32 sampleOffset, Acmd *p);
+s32 alFxParam(void *filter, s32 paramID, void *param);
+s32 alFxParamHdl(void *filter, s32 paramID, void *param);
+
+#define AL_MAX_MAIN_BUS_SOURCES 1
+typedef struct ALMainBus_s {
+ ALFilter filter;
+ s32 sourceCount;
+ s32 maxSources;
+ ALFilter **sources;
+} ALMainBus;
+
+void alMainBusNew(ALMainBus *m, void *ptr, s32 len);
+Acmd *alMainBusPull(void *f, s16 *outp, s32 outCount, s32 sampleOffset, Acmd *p);
+s32 alMainBusParam(void *filter, s32 paramID, void *param);
+
+#define AL_MAX_AUX_BUS_SOURCES 8
+#define AL_MAX_AUX_BUS_FX 1
+typedef struct ALAuxBus_s {
+ ALFilter filter;
+ s32 sourceCount;
+ s32 maxSources;
+ ALFilter **sources;
+ ALFx fx[AL_MAX_AUX_BUS_FX];
+} ALAuxBus;
+
+void alAuxBusNew(ALAuxBus *m, void *ptr, s32 len);
+Acmd *alAuxBusPull(void *f, s16 *outp, s32 outCount, s32 sampleOffset, Acmd *p);
+s32 alAuxBusParam(void *filter, s32 paramID, void *param);
+
+void alResampleNew(ALResampler *r, ALHeap *hp);
+Acmd *alResamplePull(void *f, s16 *outp, s32 out, s32 sampleOffset, Acmd *p);
+s32 alResampleParam(void *f, s32 paramID, void *param);
+
+typedef struct ALSave_s {
+ ALFilter filter;
+ s32 dramout;
+ s32 first;
+} ALSave;
+
+void alSaveNew(ALSave *r);
+Acmd *alSavePull(void *f, s16 *outp, s32 outCount, s32 sampleOffset, Acmd *p);
+s32 alSaveParam(void *f, s32 paramID, void *param);
+
+typedef struct ALEnvMixer_s {
+ ALFilter filter;
+ ENVMIX_STATE *state;
+ s16 pan;
+ s16 volume;
+ s16 cvolL;
+ s16 cvolR;
+ s16 dryamt;
+ s16 wetamt;
+ u16 lratl;
+ s16 lratm;
+ s16 ltgt;
+ u16 rratl;
+ s16 rratm;
+ s16 rtgt;
+ s32 delta;
+ s32 segEnd;
+ s32 first;
+ ALParam *ctrlList;
+ ALParam *ctrlTail;
+ ALFilter **sources;
+ s32 motion;
+} ALEnvMixer;
+
+void alEnvmixerNew(ALEnvMixer *e, ALHeap *hp);
+Acmd *alEnvmixerPull(void *f, s16 *outp, s32 out, s32 sampleOffset, Acmd *p);
+s32 alEnvmixerParam(void *filter, s32 paramID, void *param);
+
+
+/*
+ * heap stuff
+ */
+typedef struct {
+ s32 magic; /* check structure integrety */
+ s32 size; /* size of this allocated block */
+ u8 *file; /* file that this alloc was called from */
+ s32 line; /* line that it was called from */
+ s32 count; /* heap call number */
+ s32 pad0;
+ s32 pad1;
+ s32 pad2; /* Make it 32 bytes */
+} HeapInfo;
+
+#define AL_CACHE_ALIGN 15
+
+/*
+ * synth stuff
+ */
+
+typedef struct PVoice_s {
+ ALLink node;
+ struct ALVoice_s *vvoice;
+ ALFilter *channelKnob;
+ ALLoadFilter decoder;
+ ALResampler resampler;
+ ALEnvMixer envmixer;
+ s32 offset;
+} PVoice;
+
+/*
+ * prototypes for private driver functions
+ */
+ALParam *__allocParam(void);
+void __freeParam(ALParam *param);
+void _freePVoice(ALSynth *drvr, PVoice *pvoice);
+void _collectPVoices(ALSynth *drvr);
+
+s32 _timeToSamples(ALSynth *ALSynth, s32 micros);
+ALMicroTime _samplesToTime(ALSynth *synth, s32 samples);
+
+void _init_lpfilter(ALLowPass *lp);
+
+#endif
+
diff --git a/lib/ultralib/src/audio/synthesizer.c b/lib/ultralib/src/audio/synthesizer.c
new file mode 100644
index 0000000..d42a21a
--- /dev/null
+++ b/lib/ultralib/src/audio/synthesizer.c
@@ -0,0 +1,327 @@
+/*====================================================================
+ * synthesizer.c
+ *
+ * Copyright 1993, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include "synthInternals.h"
+#include <assert.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+#ifdef AUD_PROFILE
+#include <os.h>
+extern u32 cnt_index, drvr_num, drvr_cnt, drvr_max, drvr_min, lastCnt[];
+extern u32 client_num, client_cnt, client_max, client_min;
+#endif
+
+#ifndef MIN
+# define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+static s32 __nextSampleTime(ALSynth *drvr, ALPlayer **client);
+static s32 _timeToSamplesNoRound(ALSynth *ALSynth, s32 micros);
+
+/***********************************************************************
+ * Synthesis driver public interfaces
+ ***********************************************************************/
+void alSynNew(ALSynth *drvr, ALSynConfig *c)
+{
+ s32 i;
+ ALVoice *vv;
+ PVoice *pv;
+ ALVoice *vvoices;
+ PVoice *pvoices;
+ ALHeap *hp = c->heap;
+ ALSave *save;
+ ALFilter *sources;
+ ALParam *params;
+ ALParam *paramPtr;
+
+ drvr->head = NULL;
+ drvr->numPVoices = c->maxPVoices;
+ drvr->curSamples = 0;
+ drvr->paramSamples = 0;
+ drvr->outputRate = c->outputRate;
+ drvr->maxOutSamples = AL_MAX_RSP_SAMPLES;
+ drvr->dma = (ALDMANew) c->dmaproc;
+
+ save = alHeapAlloc(hp, 1, sizeof(ALSave));
+ alSaveNew(save);
+ drvr->outputFilter = (ALFilter *)save;
+
+ /*
+ * allocate and initialize the auxilliary effects bus. at present
+ * we only support 1 effects bus.
+ */
+ drvr->auxBus = alHeapAlloc(hp, 1, sizeof(ALAuxBus));
+ drvr->maxAuxBusses = 1;
+ sources = alHeapAlloc(hp, c->maxPVoices, sizeof(ALFilter *));
+ alAuxBusNew(drvr->auxBus, sources, c->maxPVoices);
+
+ /*
+ * allocate and initialize the main bus.
+ */
+ drvr->mainBus = alHeapAlloc(hp, 1, sizeof(ALMainBus));
+ sources = alHeapAlloc(hp, c->maxPVoices, sizeof(ALFilter *));
+ alMainBusNew(drvr->mainBus, sources, c->maxPVoices);
+
+ if (c->fxType != AL_FX_NONE){
+ /*
+ * Allocate an effect and set parameters
+ */
+ alSynAllocFX(drvr, 0, c, hp);
+ } else
+ /*
+ * Connect the aux bus to the main bus
+ */
+ alMainBusParam(drvr->mainBus, AL_FILTER_ADD_SOURCE, &drvr->auxBus[0]);
+
+ /*
+ * Build the physical voice lists
+ */
+ drvr->pFreeList.next = 0;
+ drvr->pFreeList.prev = 0;
+ drvr->pLameList.next = 0;
+ drvr->pLameList.prev = 0;
+ drvr->pAllocList.next = 0;
+ drvr->pAllocList.prev = 0;
+
+ pvoices = alHeapAlloc(hp, c->maxPVoices, sizeof(PVoice));
+ for (i = 0; i < c->maxPVoices; i++) {
+ pv = &pvoices[i];
+ alLink((ALLink *)pv, &drvr->pFreeList);
+ pv->vvoice = 0;
+
+ alLoadNew(&pv->decoder, drvr->dma, hp);
+ alLoadParam(&pv->decoder, AL_FILTER_SET_SOURCE, 0);
+
+ alResampleNew(&pv->resampler, hp);
+ alResampleParam(&pv->resampler, AL_FILTER_SET_SOURCE, &pv->decoder);
+
+ alEnvmixerNew(&pv->envmixer, hp);
+ alEnvmixerParam(&pv->envmixer, AL_FILTER_SET_SOURCE, &pv->resampler);
+
+ alAuxBusParam(drvr->auxBus, AL_FILTER_ADD_SOURCE, &pv->envmixer);
+
+ pv->channelKnob = (ALFilter *)&pv->envmixer;
+ }
+
+ alSaveParam(save, AL_FILTER_SET_SOURCE, drvr->mainBus);
+
+ /*
+ * build the parameter update list
+ */
+ params = alHeapAlloc(hp, c->maxUpdates, sizeof(ALParam));
+ drvr->paramList = 0;
+ for (i = 0; i < c->maxUpdates; i++) {
+ paramPtr= &params[i];
+ paramPtr->next = drvr->paramList;
+ drvr->paramList = paramPtr;
+ }
+
+ drvr->heap = hp;
+}
+
+/*
+ * slAudioFrame() is called every video frame, and is based on the video
+ * frame interrupt. It is assumed to be an accurate time source for the
+ * clients.
+ */
+Acmd *alAudioFrame(Acmd *cmdList, s32 *cmdLen, s16 *outBuf, s32 outLen)
+{
+ ALPlayer *client;
+ ALFilter *output;
+ ALSynth *drvr = &alGlobals->drvr;
+ s16 tmp = 0; /* Starting buffer in DMEM */
+ Acmd *cmdlEnd = cmdList;
+ Acmd *cmdPtr;
+ s32 nOut;
+ s16 *lOutBuf = outBuf;
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ if (drvr->head == 0) {
+ *cmdLen = 0;
+ return cmdList; /* nothing to do */
+ }
+
+ /*
+ * run down list of clients and execute callback if needed this
+ * subframe. Here we do all the work for the frame at the
+ * start. Time offsets that occur before the next frame are
+ * executed "early".
+ */
+
+#ifdef AUD_PROFILE
+ lastCnt[++cnt_index] = osGetCount();
+#endif
+
+ /*
+ * paramSamples = time of next parameter change.
+ * curSamples = current sample time.
+ * so paramSamples - curSamples is the time until the next parameter change.
+ * if the next parameter change occurs within this frame time (outLen),
+ * then call back the client that contains the parameter change.
+ * Note, paramSamples must be rounded down to 16 sample boundary for use
+ * during the client handler.
+ */
+
+ for (drvr->paramSamples = __nextSampleTime(drvr, &client);
+ drvr->paramSamples - drvr->curSamples < outLen;
+ drvr->paramSamples = __nextSampleTime(drvr, &client))
+ {
+ drvr->paramSamples &= ~0xf;
+ client->samplesLeft += _timeToSamplesNoRound(drvr, (*client->handler)(client));
+ }
+
+ /* for safety's sake, always store paramSamples aligned to 16 sample boundary.
+ * this way, if an voice handler routine gets called outside the ALVoiceHandler
+ * routine (alSynAllocVoice) it will get timestamped with an aligned value and
+ * will be processed immediately next audio frame.
+ */
+ drvr->paramSamples &= ~0xf;
+
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(client_num, client_cnt, client_max, client_min);
+#endif
+
+ /*
+ * Now build the command list in small chunks
+ */
+ while (outLen > 0){
+ nOut = MIN(drvr->maxOutSamples, outLen);
+
+ /*
+ * construct the command list for each physical voice by calling
+ * the head of the filter chain.
+ */
+ cmdPtr = cmdlEnd;
+ aSegment(cmdPtr++, 0, 0);
+ output = drvr->outputFilter;
+ (*output->setParam)(output, AL_FILTER_SET_DRAM, lOutBuf);
+ cmdlEnd = (*output->handler)(output, &tmp, nOut, drvr->curSamples,
+ cmdPtr);
+
+ outLen -= nOut;
+ lOutBuf += nOut<<1; /* For Stereo */
+ drvr->curSamples += nOut;
+
+ }
+ *cmdLen = (s32) (cmdlEnd - cmdList);
+
+ _collectPVoices(drvr); /* collect free physical voices */
+
+#ifdef AUD_PROFILE
+ PROFILE_AUD(drvr_num, drvr_cnt, drvr_max, drvr_min);
+#endif
+ return cmdlEnd;
+}
+
+/***********************************************************************
+ * Synthesis driver private interfaces
+ ***********************************************************************/
+
+ALParam *__allocParam()
+{
+ ALParam *update = 0;
+ ALSynth *drvr = &alGlobals->drvr;
+
+ if (drvr->paramList) {
+ update = drvr->paramList;
+ drvr->paramList = drvr->paramList->next;
+ update->next = 0;
+ }
+ return update;
+}
+
+void __freeParam(ALParam *param)
+{
+ ALSynth *drvr = &alGlobals->drvr;
+ param->next = drvr->paramList;
+ drvr->paramList = param;
+}
+
+void _collectPVoices(ALSynth *drvr)
+{
+ ALLink *dl;
+ PVoice *pv;
+
+ while ((dl = drvr->pLameList.next) != 0) {
+ pv = (PVoice *)dl;
+
+ /* ### remove from mixer */
+
+ alUnlink(dl);
+ alLink(dl, &drvr->pFreeList);
+ }
+}
+
+void _freePVoice(ALSynth *drvr, PVoice *pvoice)
+{
+ /*
+ * move the voice from the allocated list to the lame list
+ */
+ alUnlink((ALLink *)pvoice);
+ alLink((ALLink *)pvoice, &drvr->pLameList);
+}
+
+
+/*
+ Add 0.5 to adjust the average affect of
+ the truncation error produced by casting
+ a float to an int.
+*/
+s32 _timeToSamplesNoRound(ALSynth *synth, s32 micros)
+{
+ f32 tmp = ((f32)micros) * synth->outputRate / 1000000.0 + 0.5;
+
+ return (s32)tmp;
+}
+
+s32 _timeToSamples(ALSynth *synth, s32 micros)
+{
+ return _timeToSamplesNoRound(synth, micros) & ~0xf;
+}
+
+static s32 __nextSampleTime(ALSynth *drvr, ALPlayer **client)
+{
+ ALMicroTime delta = 0x7fffffff; /* max delta for s32 */
+ ALPlayer *cl;
+
+#ifdef _DEBUG
+ assert(drvr->head);
+#endif
+
+ *client = 0;
+
+ for (cl = drvr->head; cl != 0; cl = cl->next) {
+ if ((cl->samplesLeft - drvr->curSamples) < delta) {
+ *client = cl;
+ delta = cl->samplesLeft - drvr->curSamples;
+ }
+ }
+
+ return (*client)->samplesLeft;
+}
+
+
+
diff --git a/lib/ultralib/src/debug/osint_debug.h b/lib/ultralib/src/debug/osint_debug.h
new file mode 100644
index 0000000..b493035
--- /dev/null
+++ b/lib/ultralib/src/debug/osint_debug.h
@@ -0,0 +1,11 @@
+#include "PR/os_internal.h"
+
+extern s32 __osThprofFlag;
+extern void (*__osThprofFunc)(OSThread*);
+extern u32 __osThprofLastTimer;
+extern u32 __osThprofCount;
+extern __OSThreadprofile_s thprof[THPROF_IDMAX];
+extern u64 __osThprofHeap[THPROF_STACKSIZE];
+extern void* __osThprofStack;
+
+void osThreadProfileCallback(OSThread*);
diff --git a/lib/ultralib/src/debug/threadprofile.c b/lib/ultralib/src/debug/threadprofile.c
new file mode 100644
index 0000000..e383773
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofile.c
@@ -0,0 +1,22 @@
+#include "osint_debug.h"
+
+#include "macros.h"
+
+s32 __osThprofFlag = 0;
+void (*__osThprofFunc)(OSThread*) = NULL;
+
+u32 __osThprofLastTimer;
+u32 __osThprofCount;
+__OSThreadprofile_s thprof[THPROF_IDMAX] ALIGNED(0x10);
+u64 __osThprofHeap[THPROF_STACKSIZE] ALIGNED(0x10);
+void* __osThprofStack;
+
+void osThreadProfileCallback(OSThread* osthread) {
+ register u32 now_time = osGetCount();
+ __OSThreadprofile_s* thprof = osthread->thprof;
+
+ thprof->time += now_time - __osThprofLastTimer;
+ thprof->count++;
+ __osThprofCount++;
+ __osThprofLastTimer = now_time;
+}
diff --git a/lib/ultralib/src/debug/threadprofileclear.c b/lib/ultralib/src/debug/threadprofileclear.c
new file mode 100644
index 0000000..42788f8
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofileclear.c
@@ -0,0 +1,11 @@
+#include "osint_debug.h"
+
+void osThreadProfileClear(OSId id) {
+ register OSIntMask saveMask = __osDisableInt();
+
+ thprof[id].flag = 0;
+ thprof[id].count = 0;
+ thprof[id].time = 0;
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/debug/threadprofileinit.c b/lib/ultralib/src/debug/threadprofileinit.c
new file mode 100644
index 0000000..7fef229
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofileinit.c
@@ -0,0 +1,16 @@
+#include "osint_debug.h"
+
+void osThreadProfileInit(void) {
+ register u32 saveMask = __osDisableInt();
+ OSId i;
+
+ __osThprofFunc = NULL;
+ __osThprofFlag = 1;
+ __osThprofCount = 0;
+ __osThprofStack = &__osThprofHeap[(THPROF_STACKSIZE - 8) / sizeof(*__osThprofHeap)];
+ __osRestoreInt(saveMask);
+
+ for (i = 0; i < THPROF_IDMAX; i++) {
+ osThreadProfileClear(i);
+ }
+}
diff --git a/lib/ultralib/src/debug/threadprofilereadcount.c b/lib/ultralib/src/debug/threadprofilereadcount.c
new file mode 100644
index 0000000..c12d313
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofilereadcount.c
@@ -0,0 +1,31 @@
+#include "osint_debug.h"
+
+u32 osThreadProfileReadCount(OSId id) {
+ if (!__osThprofFlag) {
+ __osError(139, 0);
+ return 0;
+ }
+
+ if (id >= THPROF_IDMAX) {
+ __osError(143, 1, id);
+ return 0;
+ }
+ return thprof[id].count;
+}
+
+u32 osThreadProfileReadCountTh(OSThread* thread) {
+ OSId id;
+
+ if (!__osThprofFlag) {
+ __osError(141, 0);
+ return 0;
+ }
+
+ id = osGetThreadId(thread);
+
+ if (id >= THPROF_IDMAX) {
+ __osError(145, 1, id);
+ return 0;
+ }
+ return thprof[id].count;
+}
diff --git a/lib/ultralib/src/debug/threadprofilereadtime.c b/lib/ultralib/src/debug/threadprofilereadtime.c
new file mode 100644
index 0000000..c5c4cca
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofilereadtime.c
@@ -0,0 +1,43 @@
+#include "osint_debug.h"
+
+OSTime osThreadProfileReadTime(OSId id) {
+ OSTime adjust = 0;
+ u32 now_time = osGetCount();
+
+ if (!__osThprofFlag) {
+ __osError(140, 0);
+ return 0;
+ }
+ if (id >= THPROF_IDMAX) {
+ __osError(144, 1, id);
+ return 0;
+ }
+
+ if (id == osGetThreadId(NULL) && __osThprofFunc != NULL) {
+ adjust = now_time - __osThprofLastTimer;
+ }
+ return thprof[id].time + adjust;
+}
+
+OSTime osThreadProfileReadTimeTh(OSThread* thread) {
+ OSId id;
+ OSTime adjust = 0;
+ u32 now_time = osGetCount();
+
+ if (!__osThprofFlag) {
+ __osError(142, 0);
+ return 0;
+ }
+
+ id = osGetThreadId(thread);
+
+ if (id >= THPROF_IDMAX) {
+ __osError(146, 1, id);
+ return 0;
+ }
+
+ if (id == osGetThreadId(NULL) && __osThprofFunc != NULL) {
+ adjust = now_time - __osThprofLastTimer;
+ }
+ return thprof[id].time + adjust;
+}
diff --git a/lib/ultralib/src/debug/threadprofilestart.c b/lib/ultralib/src/debug/threadprofilestart.c
new file mode 100644
index 0000000..0891ad7
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofilestart.c
@@ -0,0 +1,20 @@
+#include "osint_debug.h"
+
+void osThreadProfileStart(void) {
+ register u32 saveMask;
+
+ if (!__osThprofFlag) {
+ __osError(136, 0);
+ return;
+ }
+ if (__osThprofFunc != NULL) {
+ __osError(137, 0);
+ return;
+ }
+
+ saveMask = __osDisableInt();
+
+ __osThprofLastTimer = osGetCount();
+ __osThprofFunc = osThreadProfileCallback;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/debug/threadprofilestop.c b/lib/ultralib/src/debug/threadprofilestop.c
new file mode 100644
index 0000000..666d7cd
--- /dev/null
+++ b/lib/ultralib/src/debug/threadprofilestop.c
@@ -0,0 +1,34 @@
+#include "osint_debug.h"
+
+void osThreadProfileStop(void) {
+ register u32 saveMask;
+ int i;
+ OSId id;
+ u32 now_time = osGetCount();
+
+ saveMask = __osDisableInt();
+
+ if (__osThprofFlag == 0) {
+ __osRestoreInt(saveMask);
+ __osError(138, 0);
+ return;
+ }
+
+ if (__osThprofFunc != NULL) {
+ id = osGetThreadId(0);
+
+ if (id < THPROF_IDMAX) {
+ thprof[id].time += now_time - __osThprofLastTimer;
+ } else {
+ __osRestoreInt(saveMask);
+ __osError(147, 1, id);
+ saveMask = __osDisableInt();
+ }
+ }
+ __osThprofFunc = NULL;
+
+ for (i = 0; i < THPROF_IDMAX; i++) {
+ thprof[i].flag = 0;
+ }
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/flash/flashallerase.c b/lib/ultralib/src/flash/flashallerase.c
new file mode 100644
index 0000000..c66dbd6
--- /dev/null
+++ b/lib/ultralib/src/flash/flashallerase.c
@@ -0,0 +1,31 @@
+#include "PR/os_internal.h"
+
+s32 osFlashAllErase(void) {
+ u32 status;
+ OSTimer mytimer;
+ OSMesgQueue timerMesgQueue;
+ OSMesg dummy;
+
+ // start chip erase operation
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_CHIP_ERASE);
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE);
+
+ // wait for completion by polling erase-busy flag
+ osCreateMesgQueue(&timerMesgQueue, &dummy, 1);
+ do {
+ osSetTimer(&mytimer, OS_USEC_TO_CYCLES(15000), 0, &timerMesgQueue, &dummy);
+ osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK);
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+ } while ((status & FLASH_STATUS_ERASE_BUSY) == FLASH_STATUS_ERASE_BUSY);
+
+ // check erase operation status, clear status
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+ osFlashClearStatus();
+
+ // check for success
+ if (((status & 0xFF) == 8) || ((status & 0xFF) == 0x48) || ((status & 8) == 8)) {
+ return FLASH_STATUS_ERASE_OK;
+ } else {
+ return FLASH_STATUS_ERASE_ERROR;
+ }
+}
diff --git a/lib/ultralib/src/flash/flashallerasethrough.c b/lib/ultralib/src/flash/flashallerasethrough.c
new file mode 100644
index 0000000..9e52b97
--- /dev/null
+++ b/lib/ultralib/src/flash/flashallerasethrough.c
@@ -0,0 +1,7 @@
+#include "PR/os_internal.h"
+
+void osFlashAllEraseThrough(void) {
+ // start chip erase operation, no waiting for completion
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_CHIP_ERASE);
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE);
+}
diff --git a/lib/ultralib/src/flash/flashchange.c b/lib/ultralib/src/flash/flashchange.c
new file mode 100644
index 0000000..e667668
--- /dev/null
+++ b/lib/ultralib/src/flash/flashchange.c
@@ -0,0 +1,8 @@
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+
+void osFlashChange(u32 flash_num) {
+ __osFlashHandler.baseAddress = PHYS_TO_K1((FLASH_START_ADDR + flash_num * FLASH_SIZE));
+ __osFlashHandler.type = DEVICE_TYPE_FLASH + flash_num;
+ return;
+}
diff --git a/lib/ultralib/src/flash/flashcheckeraseend.c b/lib/ultralib/src/flash/flashcheckeraseend.c
new file mode 100644
index 0000000..47faf5c
--- /dev/null
+++ b/lib/ultralib/src/flash/flashcheckeraseend.c
@@ -0,0 +1,21 @@
+#include "PR/os_internal.h"
+
+s32 osFlashCheckEraseEnd(void) {
+ u8 status;
+
+ osFlashReadStatus(&status);
+
+ if (!(status & FLASH_STATUS_ERASE_BUSY)) {
+ // not busy, read and clear status
+ osFlashReadStatus(&status);
+ osFlashClearStatus();
+
+ // check for success
+ if (((status & 0xFF) == 8) || ((status & 0xFF) == 0x48) || ((status & 8) == 8)) {
+ return FLASH_STATUS_ERASE_OK;
+ } else {
+ return FLASH_STATUS_ERASE_ERROR;
+ }
+ }
+ return FLASH_STATUS_ERASE_BUSY;
+}
diff --git a/lib/ultralib/src/flash/flashclearstatus.c b/lib/ultralib/src/flash/flashclearstatus.c
new file mode 100644
index 0000000..7622f9c
--- /dev/null
+++ b/lib/ultralib/src/flash/flashclearstatus.c
@@ -0,0 +1,10 @@
+#include "PR/os_internal.h"
+
+void osFlashClearStatus(void) {
+ // select status mode
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_STATUS);
+ // clear status
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress, 0);
+
+ return;
+}
diff --git a/lib/ultralib/src/flash/flashgetaddr.c b/lib/ultralib/src/flash/flashgetaddr.c
new file mode 100644
index 0000000..3fe2e37
--- /dev/null
+++ b/lib/ultralib/src/flash/flashgetaddr.c
@@ -0,0 +1,7 @@
+#include "PR/os_internal.h"
+
+u32 __osFlashGetAddr(u32 page_num) {
+ u32 devAddr = (__osFlashVersion == OLD_FLASH) ? page_num << 6 : page_num << 7;
+
+ return devAddr;
+}
diff --git a/lib/ultralib/src/flash/flashinit.c b/lib/ultralib/src/flash/flashinit.c
new file mode 100644
index 0000000..9b51a25
--- /dev/null
+++ b/lib/ultralib/src/flash/flashinit.c
@@ -0,0 +1,43 @@
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+#include "macros.h"
+
+OSMesgQueue __osFlashMessageQ ALIGNED(8);
+OSMesg __osFlashMsgBuf[1];
+OSPiHandle __osFlashHandler ALIGNED(8);
+s32 __osFlashVersion;
+OSIoMesg __osFlashMsg ALIGNED(8);
+u32 __osFlashID[4] ALIGNED(8);
+
+OSPiHandle* osFlashInit(void) {
+ u32 flash_type;
+ u32 flash_maker;
+
+ osCreateMesgQueue(&__osFlashMessageQ, __osFlashMsgBuf, ARRLEN(__osFlashMsgBuf));
+
+ if (__osFlashHandler.baseAddress == PHYS_TO_K1(FLASH_START_ADDR)) {
+ return &__osFlashHandler;
+ }
+
+ __osFlashHandler.type = DEVICE_TYPE_FLASH;
+ __osFlashHandler.baseAddress = PHYS_TO_K1(FLASH_START_ADDR);
+ __osFlashHandler.latency = FLASH_LATENCY;
+ __osFlashHandler.pulse = FLASH_PULSE;
+ __osFlashHandler.pageSize = FLASH_PAGE_SIZE;
+ __osFlashHandler.relDuration = FLASH_REL_DURATION;
+ __osFlashHandler.domain = PI_DOMAIN2;
+ __osFlashHandler.speed = 0;
+
+ bzero(&__osFlashHandler.transferInfo, sizeof(__OSTranxInfo));
+
+ osEPiLinkHandle(&__osFlashHandler);
+ osFlashReadId(&flash_type, &flash_maker);
+
+ if (flash_maker == FLASH_VERSION_MX_C || flash_maker == FLASH_VERSION_MX_A || flash_maker == FLASH_VERSION_MX_PROTO_A) {
+ __osFlashVersion = OLD_FLASH;
+ } else {
+ __osFlashVersion = NEW_FLASH;
+ }
+
+ return &__osFlashHandler;
+}
diff --git a/lib/ultralib/src/flash/flashreadarray.c b/lib/ultralib/src/flash/flashreadarray.c
new file mode 100644
index 0000000..6134d33
--- /dev/null
+++ b/lib/ultralib/src/flash/flashreadarray.c
@@ -0,0 +1,49 @@
+#include "PR/os_internal.h"
+
+s32 osFlashReadArray(OSIoMesg* mb, s32 priority, u32 page_num, void* dramAddr, u32 n_pages, OSMesgQueue* mq) {
+ u32 ret;
+ u32 tmp;
+ u32 end_page;
+ u32 one_dma_pages;
+
+ // select read array mode
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_READ_ARRAY);
+ // dummy read?
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &tmp);
+
+ // DMA requested pages
+ mb->hdr.pri = priority;
+ mb->hdr.retQueue = mq;
+ mb->dramAddr = dramAddr;
+
+ end_page = page_num + n_pages - 1;
+
+ if ((end_page & 0xF00) != (page_num & 0xF00)) {
+ one_dma_pages = 256 - (page_num & 0xFF);
+ n_pages -= one_dma_pages;
+ mb->size = one_dma_pages * FLASH_BLOCK_SIZE;
+ mb->devAddr = __osFlashGetAddr(page_num);
+ osEPiStartDma(&__osFlashHandler, mb, OS_READ);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ page_num = (page_num + 256) & 0xF00;
+ mb->dramAddr = (u32)mb->dramAddr + mb->size;
+ }
+
+ while (n_pages > 256) {
+ one_dma_pages = 256;
+ n_pages -= 256;
+ mb->size = one_dma_pages * FLASH_BLOCK_SIZE;
+ mb->devAddr = __osFlashGetAddr(page_num);
+ osEPiStartDma(&__osFlashHandler, mb, OS_READ);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ page_num += 256;
+ mb->dramAddr = (u32)mb->dramAddr + mb->size;
+ }
+
+ mb->size = n_pages * FLASH_BLOCK_SIZE;
+ mb->devAddr = __osFlashGetAddr(page_num);
+
+ ret = osEPiStartDma(&__osFlashHandler, mb, OS_READ);
+
+ return ret;
+}
diff --git a/lib/ultralib/src/flash/flashreadid.c b/lib/ultralib/src/flash/flashreadid.c
new file mode 100644
index 0000000..7c8a2c0
--- /dev/null
+++ b/lib/ultralib/src/flash/flashreadid.c
@@ -0,0 +1,27 @@
+#include "PR/os_internal.h"
+
+void osFlashReadId(u32* flash_type, u32* flash_maker) {
+ u8 tmp;
+
+ // why read status ?
+ osFlashReadStatus(&tmp);
+
+ // select silicon id read mode
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_ID);
+
+ // read silicon id using DMA
+ __osFlashMsg.hdr.pri = OS_MESG_PRI_NORMAL;
+ __osFlashMsg.hdr.retQueue = &__osFlashMessageQ;
+ __osFlashMsg.dramAddr = __osFlashID;
+ __osFlashMsg.devAddr = 0;
+ __osFlashMsg.size = 2 * sizeof(u32);
+
+ osInvalDCache(__osFlashID, sizeof(__osFlashID));
+ osEPiStartDma(&__osFlashHandler, &__osFlashMsg, OS_READ);
+ osRecvMesg(&__osFlashMessageQ, NULL, OS_MESG_BLOCK);
+
+ *flash_type = __osFlashID[0];
+ *flash_maker = __osFlashID[1];
+
+ return;
+}
diff --git a/lib/ultralib/src/flash/flashreadstatus.c b/lib/ultralib/src/flash/flashreadstatus.c
new file mode 100644
index 0000000..6bb582b
--- /dev/null
+++ b/lib/ultralib/src/flash/flashreadstatus.c
@@ -0,0 +1,17 @@
+#include "PR/os_internal.h"
+
+void osFlashReadStatus(u8* flash_status) {
+ u32 status;
+
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_STATUS);
+ // read status
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+
+ // why twice ?
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_STATUS);
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+
+ *flash_status = status & 0xFF;
+
+ return;
+}
diff --git a/lib/ultralib/src/flash/flashreinit.c b/lib/ultralib/src/flash/flashreinit.c
new file mode 100644
index 0000000..deb6070
--- /dev/null
+++ b/lib/ultralib/src/flash/flashreinit.c
@@ -0,0 +1,14 @@
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+
+OSPiHandle* osFlashReInit(u8 latency, u8 pulse, u8 page_size, u8 rel_duration, u32 start) {
+ __osFlashHandler.baseAddress = PHYS_TO_K1(start);
+ __osFlashHandler.type++;
+ __osFlashHandler.latency = latency;
+ __osFlashHandler.pulse = pulse;
+ __osFlashHandler.pageSize = page_size;
+ __osFlashHandler.relDuration = rel_duration;
+ __osFlashHandler.domain = PI_DOMAIN2;
+
+ return &__osFlashHandler;
+}
diff --git a/lib/ultralib/src/flash/flashsectorerase.c b/lib/ultralib/src/flash/flashsectorerase.c
new file mode 100644
index 0000000..fcccc6e
--- /dev/null
+++ b/lib/ultralib/src/flash/flashsectorerase.c
@@ -0,0 +1,31 @@
+#include "PR/os_internal.h"
+
+s32 osFlashSectorErase(u32 page_num) {
+ u32 status;
+ OSTimer mytimer;
+ OSMesgQueue timerMesgQueue;
+ OSMesg dummy;
+
+ // start sector erase operation
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_SECTOR_ERASE | page_num);
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE);
+
+ // wait for completion by polling erase-busy flag
+ osCreateMesgQueue(&timerMesgQueue, &dummy, 1);
+
+ do {
+ osSetTimer(&mytimer, OS_USEC_TO_CYCLES(12500), 0, &timerMesgQueue, &dummy);
+ osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK);
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+ } while ((status & FLASH_STATUS_ERASE_BUSY) == FLASH_STATUS_ERASE_BUSY);
+
+ // check erase operation status, clear status
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+ osFlashClearStatus();
+
+ if (((status & 0xFF) == 8) || ((status & 0xFF) == 0x48) || ((status & 8) == 8)) {
+ return FLASH_STATUS_ERASE_OK;
+ } else {
+ return FLASH_STATUS_ERASE_ERROR;
+ }
+}
diff --git a/lib/ultralib/src/flash/flashsectorerasethrough.c b/lib/ultralib/src/flash/flashsectorerasethrough.c
new file mode 100644
index 0000000..52097e1
--- /dev/null
+++ b/lib/ultralib/src/flash/flashsectorerasethrough.c
@@ -0,0 +1,7 @@
+#include "PR/os_internal.h"
+
+void osFlashSectorEraseThrough(u32 page_num) {
+ // start sector erase operation
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_SECTOR_ERASE | page_num);
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_EXECUTE_ERASE);
+}
diff --git a/lib/ultralib/src/flash/flashwritearray.c b/lib/ultralib/src/flash/flashwritearray.c
new file mode 100644
index 0000000..555f1df
--- /dev/null
+++ b/lib/ultralib/src/flash/flashwritearray.c
@@ -0,0 +1,33 @@
+#include "PR/os_internal.h"
+
+s32 osFlashWriteArray(u32 page_num) {
+ u32 status;
+ OSTimer mytimer;
+ OSMesgQueue timerMesgQueue;
+ OSMesg dummy;
+
+ if (__osFlashVersion == NEW_FLASH) {
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_PAGE_PROGRAM);
+ }
+
+ // start program page operation
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_PROGRAM_PAGE | page_num);
+
+ // wait for completion by polling write-busy flag
+ osCreateMesgQueue(&timerMesgQueue, &dummy, 1);
+ do {
+ osSetTimer(&mytimer, OS_USEC_TO_CYCLES(200), 0, &timerMesgQueue, &dummy);
+ osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK);
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+ } while ((status & FLASH_STATUS_WRITE_BUSY) == FLASH_STATUS_WRITE_BUSY);
+
+ // check program operation status, clear status
+ osEPiReadIo(&__osFlashHandler, __osFlashHandler.baseAddress, &status);
+ osFlashClearStatus();
+
+ if (((status & 0xFF) == 4) || ((status & 0xFF) == 0x44) || ((status & 4) == 4)) {
+ return FLASH_STATUS_WRITE_OK;
+ } else {
+ return FLASH_STATUS_WRITE_ERROR;
+ }
+}
diff --git a/lib/ultralib/src/flash/flashwritebuffer.c b/lib/ultralib/src/flash/flashwritebuffer.c
new file mode 100644
index 0000000..8cbd0c9
--- /dev/null
+++ b/lib/ultralib/src/flash/flashwritebuffer.c
@@ -0,0 +1,19 @@
+#include "PR/os_internal.h"
+
+s32 osFlashWriteBuffer(OSIoMesg* mb, s32 priority, void* dramAddr, OSMesgQueue* mq) {
+ s32 ret;
+
+ // select page program mode
+ osEPiWriteIo(&__osFlashHandler, __osFlashHandler.baseAddress | FLASH_CMD_REG, FLASH_CMD_PAGE_PROGRAM);
+
+ // DMA 128-byte page
+ mb->hdr.pri = priority;
+ mb->hdr.retQueue = mq;
+ mb->dramAddr = dramAddr;
+ mb->devAddr = 0;
+ mb->size = FLASH_BLOCK_SIZE;
+
+ ret = osEPiStartDma(&__osFlashHandler, mb, OS_WRITE);
+
+ return ret;
+}
diff --git a/lib/ultralib/src/gio/giointerrupt.c b/lib/ultralib/src/gio/giointerrupt.c
new file mode 100644
index 0000000..3abc04f
--- /dev/null
+++ b/lib/ultralib/src/gio/giointerrupt.c
@@ -0,0 +1,8 @@
+#include "PR/os_internal.h"
+#include "../io/piint.h"
+
+void __osGIOInterrupt(s32 value) {
+ __osPiGetAccess();
+ __osGIORawInterrupt(value);
+ __osPiRelAccess();
+}
diff --git a/lib/ultralib/src/gio/giorawinterrupt.c b/lib/ultralib/src/gio/giorawinterrupt.c
new file mode 100644
index 0000000..64652d3
--- /dev/null
+++ b/lib/ultralib/src/gio/giorawinterrupt.c
@@ -0,0 +1,18 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+void __osGIORawInterrupt(s32 value) {
+ register u32 stat;
+
+ stat = IO_READ(PI_STATUS_REG);
+ while (stat & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) {
+ stat = IO_READ(PI_STATUS_REG);
+ }
+
+ IO_WRITE(GIO_GIO_INTR_REG, value);
+
+ stat = IO_READ(PI_STATUS_REG);
+ while (stat & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) {
+ stat = IO_READ(PI_STATUS_REG);
+ }
+}
diff --git a/lib/ultralib/src/gt/Makefile b/lib/ultralib/src/gt/Makefile
new file mode 100644
index 0000000..b0868fd
--- /dev/null
+++ b/lib/ultralib/src/gt/Makefile
@@ -0,0 +1,19 @@
+#!smake
+#
+# Makefile for the gt subdirectory
+#
+
+include $(ROOT)/usr/include/make/PRdefs
+
+
+# LCOPTS = -mips2 -non_shared -fullwarn -G 0
+
+LCINCS = -I. -I$(ROOT)/usr/include/PR -I$(ROOT)/usr/include
+
+CFILES = dumpturbo.c gt.c
+
+OBJECTS = $(CFILES:.c=.o)
+
+default: $(OBJECTS)
+
+include $(COMMONRULES)
diff --git a/lib/ultralib/src/gt/dumpturbo.c b/lib/ultralib/src/gt/dumpturbo.c
new file mode 100644
index 0000000..095c8a4
--- /dev/null
+++ b/lib/ultralib/src/gt/dumpturbo.c
@@ -0,0 +1,255 @@
+
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ *************************************************************************/
+
+/*
+ * Interpret & dump a turbo display list for RSPSIM debugging
+ *
+ */
+
+#include <ultra64.h>
+#include <gt.h>
+
+#undef PRINTF
+#define PRINTF rmonPrintf
+
+
+#define TX_MAX 100
+static u32 textures[TX_MAX];
+static u32 numtextures;
+
+#define UNSEG_ADDR(sa) ((u32 *) (((globp)? \
+ (((int)(sa) & 0x00ffffff) + \
+ globp->sp.segBases[(int)(sa)>>24]) \
+ : (int)(sa)) | 0x80000000))
+#define PHYS(a) ((int) ((int)(a) & 0x7fffffff))
+#define UNPHYS(a) ((u32 *) ((int)(a) | 0x80000000))
+
+#define DOPRINT(a,r) \
+rmonPrintf("UNSEG: %x ->(seg%x = %06x)-> %08x\n",(int)(a),(int)(a)>>24,((globp)?(globp->sp.segBases[(int)(a)>>24]):0), (int)(r))
+
+
+
+#define UCODE_SIZE_MAX (4096*1)
+void
+gtDumpTurbo(OSTask *tp,u8 flags)
+{
+ int i;
+ gtGfx *gtlistp;
+ gtGlobState *globp=0;
+ gtState *statep;
+ u32 dat,*datp,*addr;
+
+
+ PRINTF("\nGBI_DUMP_START:\n");
+ PRINTF("$ %08x\n",PHYS(tp));
+
+ for (i=(int)tp; i<(int)tp+sizeof(OSTask); i+=4) {
+ PRINTF("<%08x\n",(int) *((u32 *) i));
+ }
+
+#if 1
+ PRINTF("? %08x\n",PHYS(tp->t.ucode_boot));
+ for (i=(int)tp->t.ucode_boot;
+ i<(int)tp->t.ucode_boot+tp->t.ucode_boot_size; i+=4) {
+ PRINTF("|%08x\n",(int) *((u32 *) i));
+ }
+
+ PRINTF("? %08x\n",PHYS(tp->t.ucode));
+ for (i=(int)tp->t.ucode; i<(int)tp->t.ucode+UCODE_SIZE_MAX; i+=4) {
+ PRINTF("|%08x\n",(int) *((u32 *) i));
+ }
+
+ PRINTF("? %08x\n",PHYS(tp->t.ucode_data));
+ for (i=(int)tp->t.ucode_data;
+ i<(int)tp->t.ucode_data+tp->t.ucode_data_size; i+=4) {
+ PRINTF("|%08x\n",(int) *((u32 *) i));
+ }
+
+#endif
+
+
+
+ gtlistp = (gtGfx *) tp->t.data_ptr;
+ PRINTF("@ %08x\n",PHYS(gtlistp));
+
+/*
+ * Dump turbo display list
+ */
+ while (gtlistp->obj.statep) {
+ PRINTF(">%08x\n",(int) gtlistp->obj.gstatep);
+ PRINTF("-%08x\n",(int) gtlistp->obj.statep);
+ PRINTF("-%08x\n",(int) gtlistp->obj.vtxp);
+ PRINTF("-%08x\n",(int) gtlistp->obj.trip);
+ gtlistp++;
+ }
+ PRINTF(">%08x\n",(int) gtlistp->obj.gstatep);
+ PRINTF("-%08x\n",(int) gtlistp->obj.statep);
+ PRINTF("-%08x\n",(int) gtlistp->obj.vtxp);
+ PRINTF("-%08x\n",(int) gtlistp->obj.trip);
+
+/*
+ * Dump infor pointed to by DL
+ */
+ gtlistp = (gtGfx *) tp->t.data_ptr;
+ while (gtlistp->obj.statep) {
+/*rmonPrintf("=============== DUMP A DL ENTRY (%x)\n",(int)gtlistp);*/
+
+/*
+ * Dump global state
+ */
+ if (gtlistp->obj.gstatep) {
+ addr = UNSEG_ADDR(gtlistp->obj.gstatep);
+ globp = (gtGlobState *) addr;
+/*rmonPrintf("======= DUMP GlobalState (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = addr;
+ (u8 *) datp < (u8 *) addr + sizeof(gtGlobState);
+ datp++) {
+ PRINTF("+%08x\n",*datp);
+ }
+ if (globp->sp.rdpCmds) {
+ addr = UNSEG_ADDR(globp->sp.rdpCmds);
+/*rmonPrintf("GlobalState RDP cmds (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = addr;
+ *datp || *(datp+1);
+ datp+=2) {
+ PRINTF("+%08x\n",*datp);
+ PRINTF("+%08x\n",*(datp+1));
+ }
+ PRINTF("+%08x\n",*datp);
+ PRINTF("+%08x\n",*(datp+1));
+ }
+ }
+
+/*
+ * Dump state
+ */
+ addr = UNSEG_ADDR(gtlistp->obj.statep);
+ statep = (gtState *) addr;
+/*rmonPrintf("======= DUMP State (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = addr;
+ (u8 *) datp < (u8 *) addr + sizeof(gtState);
+ datp++) {
+ PRINTF("+%08x\n",*datp);
+ }
+ if (statep->sp.rdpCmds) {
+ addr = UNSEG_ADDR(statep->sp.rdpCmds);
+/*rmonPrintf("DUMP State RDP cmds (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = addr;
+ *datp || *(datp+1);
+ datp+=2) {
+ PRINTF("+%08x\n",*datp);
+ PRINTF("+%08x\n",*(datp+1));
+ }
+ PRINTF("+%08x\n",*datp);
+ PRINTF("+%08x\n",*(datp+1));
+ }
+
+/*
+ * Dump vertices
+ */
+ if (gtlistp->obj.vtxp) {
+ addr = UNSEG_ADDR(gtlistp->obj.vtxp);
+/*rmonPrintf("======= DUMP VTX (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = (u32 *) addr;
+ (u8 *) datp < (u8 *) addr +
+ (statep->sp.vtxCount * sizeof(Vtx));
+ datp++) {
+ PRINTF("+%08x\n",*datp);
+ }
+ }
+
+/*
+ * Dump triangles
+ */
+ if (gtlistp->obj.trip) {
+ addr = UNSEG_ADDR(gtlistp->obj.trip);
+/*rmonPrintf("======= DUMP TRI (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = (u32 *) addr;
+ (u8 *) datp < (u8 *) addr +
+ (statep->sp.triCount * sizeof(gtTriN));
+ datp++) {
+ PRINTF("+%08x\n",*datp);
+ }
+ }
+
+
+
+ gtlistp++;
+ }
+
+
+/*
+ * Dump Last global state
+ */
+ if (gtlistp->obj.gstatep) {
+ addr = UNSEG_ADDR(gtlistp->obj.gstatep);
+ globp = (gtGlobState *) addr;
+/*rmonPrintf("======= DUMP GlobalState (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = addr;
+ (u8 *) datp < (u8 *) addr + sizeof(gtGlobState);
+ datp++) {
+ PRINTF("+%08x\n",*datp);
+ }
+ if (globp->sp.rdpCmds) {
+ addr = UNSEG_ADDR(globp->sp.rdpCmds);
+/*rmonPrintf("GlobalState RDP cmds (%x)\n",(int)addr);*/
+ PRINTF("& %08x\n",PHYS(addr));
+ for (datp = addr;
+ *datp || *(datp+1);
+ datp+=2) {
+ PRINTF("+%08x\n",*datp);
+ PRINTF("+%08x\n",*(datp+1));
+ }
+ PRINTF("+%08x\n",*datp);
+ PRINTF("+%08x\n",*(datp+1));
+ }
+ }
+
+ PRINTF("^\nGBI_DUMP_END:\n");
+
+
+ if (flags & GT_DUMPTURBO_HANGAFTER) {
+ for (i=0; i<1000;i++)
+ rmonPrintf("=======================================\n");
+ while(1);
+ }
+
+
+/*
+ * Dumps stuff
+ * each line is either an address for data to follow or data itself
+ * 1st char on line indicates what it is:
+ *
+ * $ task header address
+ * @ display list address
+ * & dma data address
+ * % texture address
+ * ? code/code data address
+ *
+ * < task header data
+ * > 1st half of display list command
+ * - 2nd half of display list command
+ * + dma data
+ * * texture data
+ * | code/code data
+ *
+ */
+
+}
diff --git a/lib/ultralib/src/gt/gt.c b/lib/ultralib/src/gt/gt.c
new file mode 100644
index 0000000..bf99e85
--- /dev/null
+++ b/lib/ultralib/src/gt/gt.c
@@ -0,0 +1,155 @@
+
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ */
+
+/*
+ * File: gt.c
+ * Creator: hsa@sgi.com
+ * Create Date: Fri Oct 13 14:23:48 PDT 1995
+ *
+ */
+
+
+#include "gtint.h"
+
+
+/*
+ * Set the cached RDP othermode word in the gt state structure.
+ */
+void
+gtStateSetOthermode(Gfx *om, gtStateOthermode_t mode, int data)
+{
+ int shift, length;
+ u32 mask;
+
+ if (mode == GT_CLEAR) { /* special case */
+ om->words.w0 = (G_RDPSETOTHERMODE << 24);
+ om->words.w1 = 0x0;
+ }
+
+ if (mode <= GT_RENDERMODE) {
+ /* these are OTHERMODE_L */
+ switch (mode) {
+
+ case GT_ALPHACOMPARE:
+ shift = G_MDSFT_ALPHACOMPARE;
+ length = 2;
+ break;
+
+ case GT_ZSRCSEL:
+ shift = G_MDSFT_ZSRCSEL;
+ length = 1;
+ break;
+
+ case GT_RENDERMODE:
+ shift = G_MDSFT_RENDERMODE;
+ length = 29;
+ break;
+
+ default:
+ break;
+ }
+
+ mask = (0x01 << length);
+ mask = mask - 1;
+ mask = (mask << shift);
+ mask = mask ^ 0xffffffff;
+ om->words.w1 &= mask;
+ om->words.w1 |= data;
+
+ } else {
+ /* these are OTHERMODE_H */
+ switch (mode) {
+ case GT_ALPHADITHER:
+ shift = G_MDSFT_ALPHADITHER;
+ length = 2;
+ break;
+
+ case GT_RGBDITHER:
+ shift = G_MDSFT_RGBDITHER;
+ length = 2;
+ break;
+
+ case GT_COMBKEY:
+ shift = G_MDSFT_COMBKEY;
+ length = 1;
+ break;
+
+ case GT_TEXTCONV:
+ shift = G_MDSFT_TEXTCONV;
+ length = 3;
+ break;
+
+ case GT_TEXTFILT:
+ shift = G_MDSFT_TEXTFILT;
+ length = 2;
+ break;
+
+ case GT_TEXTLUT:
+ shift = G_MDSFT_TEXTLUT;
+ length = 2;
+ break;
+
+ case GT_TEXTLOD:
+ shift = G_MDSFT_TEXTLOD;
+ length = 1;
+ break;
+
+ case GT_TEXTDETAIL:
+ shift = G_MDSFT_TEXTDETAIL;
+ length = 2;
+ break;
+
+ case GT_TEXTPERSP:
+ shift = G_MDSFT_TEXTPERSP;
+ length = 1;
+ break;
+
+ case GT_CYCLETYPE:
+ shift = G_MDSFT_CYCLETYPE;
+ length = 2;
+ break;
+
+ case GT_PIPELINE:
+ shift = G_MDSFT_PIPELINE;
+ length = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ mask = (0x01 << length);
+ mask = mask - 1;
+ mask = (mask << shift);
+ mask = mask ^ 0xffffffff;
+ om->words.w0 &= mask;
+ om->words.w0 |= data;
+ }
+
+ /* force cached othermode word to have proper command id: */
+ om->words.w0 &= 0x00ffffff;
+ om->words.w0 |= (G_RDPSETOTHERMODE << 24);
+}
+
diff --git a/lib/ultralib/src/gt/gtint.h b/lib/ultralib/src/gt/gtint.h
new file mode 100644
index 0000000..31ddd7c
--- /dev/null
+++ b/lib/ultralib/src/gt/gtint.h
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ */
+
+/*
+ * File: gtint.h
+ * Creator: hsa@sgi.com
+ * Create Date: Fri Oct 13 14:24:36 PDT 1995
+ *
+ */
+
+#include "mbi.h"
+#include "gu.h"
+#include "gt.h"
+
diff --git a/lib/ultralib/src/gu/Makefile b/lib/ultralib/src/gu/Makefile
new file mode 100644
index 0000000..ad6e2fa
--- /dev/null
+++ b/lib/ultralib/src/gu/Makefile
@@ -0,0 +1,52 @@
+#!smake
+#
+# Makefile for the gu subdirectory
+#
+
+include $(ROOT)/usr/include/make/PRdefs
+
+
+# LCOPTS = -mips2 -non_shared -fullwarn -G 0
+LCINCS = -I. -I$(ROOT)/usr/include/PR -I$(ROOT)/usr/include
+LCOPTS = -G 0 -g -O
+
+CFILES = \
+ align.c \
+ cosf.c \
+ coss.c \
+ frustum.c \
+ guloadtile_bug.c \
+ loadtextureblockmipmap.c\
+ lookat.c \
+ lookathil.c \
+ lookatref.c \
+ lookatstereo.c \
+ mtxcatf.c \
+ mtxcatl.c \
+ mtxutil.c \
+ normalize.c \
+ ortho.c \
+ perspective.c \
+ position.c \
+ poslight.c \
+ poslighthil.c \
+ random.c \
+ rotate.c \
+ rotaterpy.c \
+ scale.c \
+ sinf.c \
+ sins.c \
+ translate.c \
+ us2dex.c \
+ us2dex_emu.c \
+ us2dex2_emu.c \
+ usprite.c
+
+ASFILES = \
+ libm_vals.s \
+ sqrtf.s
+OBJECTS = $(CFILES:.c=.o)
+
+default: $(OBJECTS)
+
+include $(COMMONRULES)
diff --git a/lib/ultralib/src/gu/align.c b/lib/ultralib/src/gu/align.c
new file mode 100644
index 0000000..9be7b4a
--- /dev/null
+++ b/lib/ultralib/src/gu/align.c
@@ -0,0 +1,75 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/*
+ * S = sin (a)
+ * C = cos (a)
+ * H = sqrt (X*X + Z*Z)
+ *
+ * [ v ] [ C S ] [ 1 ] [ -Z/H X/H ]
+ * [ -S C ] [ H Y ] [ 1 ]
+ * [ 1 ] [ -Y H ] [ -X/H -Z/H ]
+ * [ 1 ] [ 1 ] [ 1 ]
+ *
+ */
+
+void guAlignF(float mf[4][4], float a, float x, float y, float z)
+{
+ static float dtor = 3.1415926 / 180.0;
+ float s, c, h, hinv;
+
+ guNormalize(&x, &y, &z);
+
+ a *= dtor;
+ s = sinf (a);
+ c = cosf (a);
+ h = sqrtf (x*x + z*z);
+
+ guMtxIdentF(mf);
+
+ if (h != 0) {
+ hinv = 1 / h;
+
+ mf[0][0] = (-z*c - s*y*x) * hinv;
+ mf[1][0] = (z*s - c*y*x) * hinv;
+ mf[2][0] = -x;
+ mf[3][0] = 0;
+
+ mf[0][1] = s*h;
+ mf[1][1] = c*h;
+ mf[2][1] = -y;
+ mf[3][1] = 0;
+
+ mf[0][2] = (c*x - s*y*z) * hinv;
+ mf[1][2] = (-s*x - c*y*z) * hinv;
+ mf[2][2] = -z;
+ mf[3][2] = 0;
+
+ mf[0][3] = 0;
+ mf[1][3] = 0;
+ mf[2][3] = 0;
+ mf[3][3] = 1;
+ } else {
+ /* XXX: should do this right */
+ }
+}
+
+void guAlign(Mtx *m, float a, float x, float y, float z)
+{
+ Matrix mf;
+
+ guAlignF(mf, a, x, y, z);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/cosf.c b/lib/ultralib/src/gu/cosf.c
new file mode 100644
index 0000000..5a66c1b
--- /dev/null
+++ b/lib/ultralib/src/gu/cosf.c
@@ -0,0 +1,137 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/* ====================================================================
+ * ====================================================================
+ *
+ * Module: fcos.c
+ * $Revision: 1.3 $
+ * $Date: 1998/10/09 06:10:53 $
+ * $Author: has $
+ * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/libultra/monegi/gu/cosf.c,v $
+ *
+ * Revision history:
+ * 09-Jun-93 - Original Version
+ *
+ * Description: source code for fcos function
+ *
+ * ====================================================================
+ * ====================================================================
+ */
+
+#pragma weak fcos = __cosf
+#pragma weak cosf = __cosf
+#define fcos __cosf
+
+/* coefficients for polynomial approximation of cos on +/- pi/2 */
+
+static const du P[] =
+{
+{0x3ff00000, 0x00000000},
+{0xbfc55554, 0xbc83656d},
+{0x3f8110ed, 0x3804c2a0},
+{0xbf29f6ff, 0xeea56814},
+{0x3ec5dbdf, 0x0e314bfe},
+};
+
+static const du rpi =
+{0x3fd45f30, 0x6dc9c883};
+
+static const du pihi =
+{0x400921fb, 0x50000000};
+
+static const du pilo =
+{0x3e6110b4, 0x611a6263};
+
+static const fu zero = {0x00000000};
+
+
+/* ====================================================================
+ *
+ * FunctionName fcos
+ *
+ * Description computes cosine of arg
+ *
+ * ====================================================================
+ */
+
+float
+fcos( float x )
+{
+float absx;
+double dx, xsq, poly;
+double dn;
+int n;
+double result;
+int ix, xpt;
+
+
+ ix = *(int *)&x;
+ xpt = (ix >> 22);
+ xpt &= 0x1ff;
+
+ /* xpt is exponent(x) + 1 bit of mantissa */
+
+
+ if ( xpt < 0x136 )
+ {
+ /* |x| < 2^28 */
+
+ /* use the standard algorithm from Cody and Waite, doing
+ the computations in double precision
+ */
+
+ absx = ABS(x);
+
+ dx = absx;
+
+ dn = dx*rpi.d + 0.5;
+ n = ROUND(dn);
+ dn = n;
+
+ dn -= 0.5;
+
+ dx = dx - dn*pihi.d;
+ dx = dx - dn*pilo.d; /* dx = x - (n - 0.5)*pi */
+
+ xsq = dx*dx;
+
+ poly = ((P[4].d*xsq + P[3].d)*xsq + P[2].d)*xsq + P[1].d;
+
+ result = dx + (dx*xsq)*poly;
+
+ /* negate result if n is odd */
+
+ if ( (n & 1) == 0 )
+ return ( (float)result );
+
+ return ( -(float)result );
+ }
+
+ if ( x != x )
+ {
+ /* x is a NaN; return a quiet NaN */
+
+#ifdef _IP_NAN_SETS_ERRNO
+
+ *__errnoaddr = EDOM;
+#endif
+
+ return ( __libm_qnan_f );
+ }
+
+ /* just give up and return 0.0 */
+
+ return ( zero.f );
+}
diff --git a/lib/ultralib/src/gu/coss.c b/lib/ultralib/src/gu/coss.c
new file mode 100644
index 0000000..0d95530
--- /dev/null
+++ b/lib/ultralib/src/gu/coss.c
@@ -0,0 +1,45 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/* ====================================================================
+ * ====================================================================
+ *
+ * Module: coss.c
+ * $Revision: 1.3 $
+ * $Date: 1998/10/09 06:11:01 $
+ * $Author: has $
+ * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/libultra/monegi/gu/coss.c,v $
+ *
+ * ====================================================================
+ * ====================================================================
+ */
+
+/* coefficients for polynomial approximation of sin on +/- pi/2 */
+
+/* ====================================================================
+ *
+ * FunctionName coss
+ *
+ * Description computes cosine of arg
+ *
+ * ====================================================================
+ */
+
+signed short
+coss( unsigned short x )
+{
+ /* 0 <= x < 0x10000 ==> 0 <= x < 2PI */
+
+ return sins ((unsigned short) (x + 0x4000));
+}
diff --git a/lib/ultralib/src/gu/dump_gbi.c b/lib/ultralib/src/gu/dump_gbi.c
new file mode 100644
index 0000000..a5e5e12
--- /dev/null
+++ b/lib/ultralib/src/gu/dump_gbi.c
@@ -0,0 +1,274 @@
+
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ *************************************************************************/
+
+/*
+ * Interpret Task with GBI display list and dump it for debugging.
+ */
+
+
+/**************************************************
+ *
+ * guDumpGbiDL no longer supported
+ * applications should use guParseGbiDL with the
+ * GU_PARSEGBI_DUMPONLY flag set.
+ *
+ **************************************************/
+
+
+#if 0
+
+
+#include "ultra64.h"
+#include "bstring.h"
+
+#undef PRINTF
+#define PRINTF osSyncPrintf
+
+#define DL_STACKSIZE 11
+static u32 *Gp[DL_STACKSIZE];
+
+#define TX_MAX 100
+static u32 textures[TX_MAX];
+static u32 numtextures;
+
+static u32 segment_base[16];
+static u32 dotextures = TRUE;
+static int dl_depth = 0;
+
+
+/*
+ * dump a DMA-type display list command.
+ */
+static void
+dump_dma(u32 *bufp)
+{
+ u32 addr,
+ *data;
+ u8 seg_id;
+ u16 len;
+ char op,
+ b0;
+
+ op = ((*bufp & 0xff000000) >> 24);
+
+ /*
+ * DMA op addressing is all the same:
+ */
+ seg_id = (u8) ((bufp[1] & 0x0f000000) >> 24);
+ addr = segment_base[seg_id] + (bufp[1] & 0x00ffffff);
+
+
+ addr = (u32) osPhysicalToVirtual(addr);
+
+ len = (u16) (bufp[0] & 0x0000ffff);
+
+ PRINTF(">%08x\n-%08x\n", bufp[0], bufp[1]);
+ if (op == (char) G_DL) {
+ b0 = (char) ((bufp[0] & 0x00ff0000) >> 16);
+ ++dl_depth;
+ if (dl_depth > (DL_STACKSIZE - 1)) {
+ PRINTF("***** Error, max levels of display lists exceeded\n");
+ return;
+ }
+ Gp[dl_depth] = (u32 *) addr;
+ PRINTF("@ %08x\n",(int)Gp[dl_depth]&0x7fffffff);
+ } else {
+ PRINTF("& %08x\n", (int)addr&0x7fffffff);
+ data = (u32 *) addr;
+ while(len>0) {
+ PRINTF("+%08x\n", *data);
+ data++;
+ len -= 4;
+ }
+ PRINTF("@ %08x\n",(int)(Gp[dl_depth] + (sizeof(Gfx) >> 2))&0x7fffffff);
+ }
+}
+
+/*
+ * dump a IMM-type display list command.
+ */
+static void
+dump_imm(u32 *bufp)
+{
+ char op,
+ b0;
+
+ op = ((*bufp & 0xff000000) >> 24);
+
+ PRINTF(">%08x\n-%08x\n", bufp[0], bufp[1]);
+ if (op == (char) G_ENDDL) {
+ dl_depth--;
+ if (dl_depth >= 0) {
+ PRINTF("@ %08x\n",(int)(Gp[dl_depth] + (sizeof(Gfx) >> 2))&0x7fffffff);
+ }
+ }
+ if (op == (char) G_MOVEWORD) {
+ if (((bufp[0] ) & 0xff) == G_MW_SEGMENT) {
+ b0 = (char) ((bufp[0] & 0xff00)>>10);
+ segment_base[b0] = bufp[1] & 0x00ffffff;
+ }
+ }
+}
+
+/*
+ * dump a RDP-type display list command.
+ */
+static void
+dump_rdp(u32 *bufp)
+{
+ u8 seg_id;
+ u32 addr;
+ int i0,
+ i1;
+ char op;
+
+ op = ((*bufp & 0xff000000) >> 24);
+
+ PRINTF(">%08x\n-%08x\n", bufp[0], bufp[1]);
+ if (op == (char) G_SETTIMG && dotextures) {
+ if (numtextures>=TX_MAX) {
+ PRINTF("GBI DUMP ERROR: too many textures (max=%d)\n",TX_MAX);
+ return;
+ }
+ seg_id = (u8) ((bufp[1] & 0x0f000000) >> 24);
+ addr = segment_base[seg_id] + (bufp[1] & 0x00ffffff);
+ addr = (u32) osPhysicalToVirtual(addr);
+ i1=1;
+ for (i0=0;i0<numtextures;i0++)
+ if (textures[i0] == addr) i1=0;
+ if (i1) textures[numtextures++]=addr;
+ }
+}
+
+/*
+ * Takes a pointer in DRAM, and a length in bytes. Dumps
+ * the display list, until a G_ENDDL command is found.
+ */
+static void
+guDumpGbi(u32 *gfxp)
+{
+ u8 op;
+ u32 readBuf[4];
+
+ Gp[dl_depth] = gfxp;
+ numtextures=0;
+
+ PRINTF("@ %08x\n",(int)Gp[dl_depth]&0x7fffffff);
+
+ while ((dl_depth >= 0) && (dl_depth < (DL_STACKSIZE - 1))) {
+
+ op = (u8) ((*Gp[dl_depth] & 0xff000000) >> 24);
+ bcopy((char *) Gp[dl_depth], (char *) &(readBuf[0]), sizeof(Gfx));
+
+ switch (op & 0xc0) {
+
+ case (u8) 0x00:
+ dump_dma(readBuf);
+ break;
+
+ case (u8) 0x80:
+ dump_imm(readBuf);
+ break;
+
+ case (u8) 0xc0:
+ dump_rdp(readBuf);
+ break;
+
+ default:
+ PRINTF("ERROR : display list is lost, op = %02x\n", op);
+ break;
+
+ }
+
+ if (op != (u8) G_DL) {
+ Gp[dl_depth] += (sizeof(Gfx) >> 2);
+ }
+ }
+ if (dotextures) {
+ u32 i,j;
+ for (i=0; i<numtextures; i++) {
+ PRINTF("%% %08x\n",textures[i]&0x7fffffff);
+ for (j=textures[i]; j<textures[i]+0x400; j+=4) {
+ PRINTF("*%08x\n",(int) *((u32 *) j));
+ }
+ }
+ }
+}
+
+#define UCODE_SIZE_MAX (4096*3)
+void
+guDumpGbiDL(OSTask *tp,u8 flags)
+{
+ int i;
+
+ if (flags & GU_PARSEGBI_NOTEXTURES) dotextures=0;
+
+ PRINTF("\nGBI_DUMP_START:\n");
+ PRINTF("$ %08x\n",(int) tp & 0x7fffffff);
+
+ for (i=(int)tp; i<(int)tp+sizeof(OSTask); i+=4) {
+ PRINTF("<%08x\n",(int) *((u32 *) i));
+ }
+
+ PRINTF("? %08x\n",(int) tp->t.ucode_boot & 0x7fffffff);
+ for (i=(int)tp->t.ucode_boot; i<(int)tp->t.ucode_boot+tp->t.ucode_boot_size; i+=4) {
+ PRINTF("|%08x\n",(int) *((u32 *) i));
+ }
+
+ PRINTF("? %08x\n",(int) tp->t.ucode& 0x7fffffff);
+ for (i=(int)tp->t.ucode; i<(int)tp->t.ucode+UCODE_SIZE_MAX; i+=4) {
+ PRINTF("|%08x\n",(int) *((u32 *) i));
+ }
+
+ PRINTF("? %08x\n",(int) tp->t.ucode_data & 0x7fffffff);
+ for (i=(int)tp->t.ucode_data; i<(int)tp->t.ucode_data+tp->t.ucode_data_size; i+=4) {
+ PRINTF("|%08x\n",(int) *((u32 *) i));
+ }
+
+
+ guDumpGbi((u32 *) tp->t.data_ptr);
+
+
+ PRINTF("^\nGBI_DUMP_END:\n");
+
+ if (flags & GU_PARSEGBI_HANGAFTER) {
+ int i;
+ for (i=0; i<1000;i++)
+ PRINTF("=============================================================\n");
+ while(1);
+ }
+
+
+/*
+ * Dumps stuff
+ * each line is either an address for data to follow or data itself
+ * 1st char on line indicates what it is:
+ *
+ * $ task header address
+ * @ display list address
+ * & dma data address
+ * % texture address
+ * ? code/code data address
+ *
+ * < task header data
+ * > 1st half of display list command
+ * - 2nd half of display list command
+ * + dma data
+ * * texture data
+ * | code/code data
+ *
+ */
+
+}
+
+#endif
diff --git a/lib/ultralib/src/gu/frustum.c b/lib/ultralib/src/gu/frustum.c
new file mode 100644
index 0000000..4af9c5d
--- /dev/null
+++ b/lib/ultralib/src/gu/frustum.c
@@ -0,0 +1,42 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+void guFrustumF(float mf[4][4], float l, float r, float b, float t, float n, float f, float scale)
+{
+ int i, j;
+
+ guMtxIdentF(mf);
+
+ mf[0][0] = 2*n/(r-l);
+ mf[1][1] = 2*n/(t-b);
+ mf[2][0] = (r+l)/(r-l);
+ mf[2][1] = (t+b)/(t-b);
+ mf[2][2] = -(f+n)/(f-n);
+ mf[2][3] = -1;
+ mf[3][2] = -2*f*n/(f-n);
+ mf[3][3] = 0;
+
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++)
+ mf[i][j] *= scale;
+}
+
+void guFrustum(Mtx *m, float l, float r, float b, float t, float n, float f, float scale)
+{
+ Matrix mf;
+
+ guFrustumF(mf, l, r, b, t, n, f, scale);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/guint.h b/lib/ultralib/src/gu/guint.h
new file mode 100644
index 0000000..c3206dd
--- /dev/null
+++ b/lib/ultralib/src/gu/guint.h
@@ -0,0 +1,42 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "mbi.h"
+#include "gu.h"
+
+typedef union
+{
+ struct
+ {
+ unsigned int hi;
+ unsigned int lo;
+ } word;
+
+ double d;
+} du;
+
+typedef union
+{
+ unsigned int i;
+ float f;
+} fu;
+
+#ifndef __GL_GL_H__
+
+typedef float Matrix[4][4];
+
+#endif
+
+#define ROUND(d) (int)(((d) >= 0.0) ? ((d) + 0.5) : ((d) - 0.5))
+#define ABS(d) ((d) > 0) ? (d) : -(d)
+
+extern float __libm_qnan_f;
diff --git a/lib/ultralib/src/gu/guloadtile_bug.c b/lib/ultralib/src/gu/guloadtile_bug.c
new file mode 100644
index 0000000..e16e250
--- /dev/null
+++ b/lib/ultralib/src/gu/guloadtile_bug.c
@@ -0,0 +1,235 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "ultra64.h"
+
+/*
+ * Inidicates how many words will be added to display list
+ * by guDPLoadTextureTile function.
+ */
+int
+guGetDPLoadTextureTileSz(int ult, int lrt)
+{
+ return (((lrt - ult + 1) / 2) * 4 + 3);
+}
+
+/*
+ * Workaround for load_tile bug on tapeout one hardware. Uses
+ * load blocks for each line. ~25% more dma traffic + memory for
+ * extra commands.
+ */
+void
+guDPLoadTextureTile(Gfx * temp, void *timg,
+ int texl_fmt, int texl_size,
+ int img_width, int img_height,
+ int uls, int ult, int lrs, int lrt,
+ int palette,
+ int cms, int cmt,
+ int masks, int maskt,
+ int shifts, int shiftt)
+{
+ int line;
+ int tile_width,
+ tile_height; /*
+
+ * in texels
+ */
+ int dxt;
+ int sizeb;
+ int lineb;
+ int line_size; /*
+
+ * in 64-bit words
+ */
+ int texel_num_pad; /*
+
+ * in texels, pad to 64-bit word size
+ */
+ int count;
+ int tmem;
+ int tile;
+ int s,
+ t;
+
+ tile_width = lrs - uls + 1;
+ tile_height = lrt - ult + 1;
+
+ switch (texl_size) {
+ case G_IM_SIZ_8b:
+ sizeb = G_IM_SIZ_8b_BYTES;
+ lineb = G_IM_SIZ_8b_LINE_BYTES;
+ break;
+ case G_IM_SIZ_16b:
+ sizeb = G_IM_SIZ_16b_BYTES;
+ lineb = G_IM_SIZ_16b_LINE_BYTES;
+ break;
+ case G_IM_SIZ_32b:
+ sizeb = G_IM_SIZ_32b_BYTES;
+ lineb = G_IM_SIZ_32b_LINE_BYTES;
+ break;
+ }
+
+ dxt = CALC_DXT(tile_width, sizeb);
+ line_size = ((tile_width * lineb) + 7) >> 3;
+ /*
+ * pad line to word boundary
+ */
+ texel_num_pad = ((((tile_width * sizeb) + 7) >> 3) * 8) / sizeb;
+
+ gDPSetTextureImage(temp++, texl_fmt, texl_size, img_width, timg);
+
+ for (line = 0; line < tile_height; line += 2) {
+ t = (ult + line) & ~1; /*
+ * load from even line
+ */
+ tmem = line * line_size;
+
+ /*
+ * set for both loads, avoid sync by alternating tiles
+ */
+ tile = (line % 4) ? 1 : 0;
+
+ gDPSetTile(temp++, texl_fmt, texl_size, 0, tmem, G_TX_LOADTILE - tile, 0,
+ cmt, maskt, shiftt,
+ cms, masks, shifts);
+
+ /*
+ * do odd line first
+ */
+ s = uls + img_width - texel_num_pad;
+ count = (texel_num_pad * 2) - 1;
+
+ gDPLoadBlock(temp++, G_TX_LOADTILE - tile, s, t, s + count, dxt);
+
+ /*
+ * do even line
+ */
+ s = uls;
+ count = tile_width - 1;
+
+ gDPLoadSync(temp++);
+ gDPLoadBlock(temp++, G_TX_LOADTILE - tile, s, t, s + count, dxt);
+
+ }
+
+ /*
+ * set final tile
+ */
+ gDPSetTile(temp++, texl_fmt, texl_size, line_size, 0, G_TX_RENDERTILE, 0,
+ cmt, maskt, shiftt,
+ cms, masks, shifts);
+
+ gDPSetTileSize(temp++, G_TX_RENDERTILE,
+ (uls) << G_TEXTURE_IMAGE_FRAC,
+ (ult) << G_TEXTURE_IMAGE_FRAC,
+ (lrs) << G_TEXTURE_IMAGE_FRAC,
+ (lrt) << G_TEXTURE_IMAGE_FRAC);
+}
+
+/*
+ * 4-BIT VERSION
+ */
+
+/*
+ * Inidicates how many words will be added to display list
+ * by guDPLoadTextureTile function.
+ */
+int
+guGetDPLoadTextureTile_4bSz(int ult, int lrt)
+{
+ return (((lrt - ult + 1) / 2) * 4 + 3);
+}
+
+/*
+ * Workaround for load_tile bug on version 1.0 hardware. Uses
+ * load blocks for each line. ~25% more dma traffic + memory for
+ * extra commands.
+ */
+void
+guDPLoadTextureTile_4b(Gfx * temp, void *timg,
+ int texl_fmt,
+ int img_width, int img_height,
+ int uls, int ult, int lrs, int lrt,
+ int palette,
+ int cms, int cmt,
+ int masks, int maskt,
+ int shifts, int shiftt)
+{
+ int line;
+ int tile_width,
+ tile_height;
+ int dxt;
+ int sizeb;
+ int lineb;
+ int line_size;
+ int count;
+ int tmem;
+ int tile;
+ int s,
+ t;
+
+ tile_width = (lrs - uls + 1) >> 1;
+ tile_height = lrt - ult + 1;
+ sizeb = G_IM_SIZ_8b_BYTES;
+ lineb = G_IM_SIZ_8b_LINE_BYTES;
+ line_size = ((tile_width * lineb) + 7) >> 3;
+ dxt = CALC_DXT_4b(tile_width);
+
+ gDPSetTextureImage(temp++, texl_fmt, G_IM_SIZ_8b, ((img_width) >> 1), timg);
+
+ for (line = 0; line < tile_height; line += 2) {
+ t = (ult + line) & ~1; /*
+ * load from even line
+ */
+ tmem = line * line_size;
+
+ /*
+ * set for both loads, avoid sync by alternating tiles
+ */
+ tile = (line % 4) ? 1 : 0;
+
+ gDPSetTile(temp++, texl_fmt, G_IM_SIZ_8b, 0, tmem, G_TX_LOADTILE - tile, 0,
+ cmt, maskt, shiftt,
+ cms, masks, shifts);
+
+ /*
+ * do odd line first
+ */
+ s = uls + img_width - line_size * 8;
+ count = (line_size * 8 * 2) - 1;
+
+ gDPLoadBlock(temp++, G_TX_LOADTILE - tile, s, t, s + count, dxt);
+
+ /*
+ * do even line
+ */
+ s = uls;
+ count = tile_width - 1;
+
+ gDPLoadSync(temp++);
+ gDPLoadBlock(temp++, G_TX_LOADTILE - tile, s, t, s + count, dxt);
+
+ }
+
+ /*
+ * set final tile
+ */
+ gDPSetTile(temp++, texl_fmt, G_IM_SIZ_4b, line_size, 0, G_TX_RENDERTILE, 0,
+ cmt, maskt, shiftt,
+ cms, masks, shifts);
+
+ gDPSetTileSize(temp++, G_TX_RENDERTILE,
+ (uls) << G_TEXTURE_IMAGE_FRAC,
+ (ult) << G_TEXTURE_IMAGE_FRAC,
+ (lrs) << G_TEXTURE_IMAGE_FRAC,
+ (lrt) << G_TEXTURE_IMAGE_FRAC);
+}
diff --git a/lib/ultralib/src/gu/libm_vals.s b/lib/ultralib/src/gu/libm_vals.s
new file mode 100644
index 0000000..b88ad98
--- /dev/null
+++ b/lib/ultralib/src/gu/libm_vals.s
@@ -0,0 +1,5 @@
+ .rdata
+ .align 4
+ .globl __libm_qnan_f
+__libm_qnan_f:
+ .word 0x7F810000
diff --git a/lib/ultralib/src/gu/loadtextureblockmipmap.c b/lib/ultralib/src/gu/loadtextureblockmipmap.c
new file mode 100644
index 0000000..786f64a
--- /dev/null
+++ b/lib/ultralib/src/gu/loadtextureblockmipmap.c
@@ -0,0 +1,716 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+/****************************************************************************
+ * NOTE: To view this file correctly, set tabstop=3
+*****************************************************************************/
+#include "guint.h"
+#include <stdio.h>
+#include "ultra64.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.49 $"
+
+#define TRAM_SIZE 4096 /* in bytes */
+#define TRAM_WSIZE 8 /* TRAM word size in bytes */
+#define TRAM_LSIZE 8 /* TRAM load word size in bytes */
+#define MM_MAX_LEVEL 7 /* number of mipmap levels 0 to MM_MAX_LEVEL */
+#define MM_MIN_SIZE 1 /* smallest mipmap tile */
+
+struct texelSizeParams
+{
+ unsigned char gran;
+ unsigned char shift;
+ unsigned char tsize;
+ unsigned char shiftr;
+};
+
+/* texture ram tile */
+struct Tile
+{
+ int w; /* width of tile in texels, padded to tram line sz */
+ int s, t; /* size of tile in texels */
+ int addr; /* address in tram of tile */
+};
+
+/* tram mipmaps */
+static struct Tile mipmap[MM_MAX_LEVEL+1];
+static struct texelSizeParams sizeParams[4] =
+ { 16, 3, 1, 0,
+ 8, 2, 2, 1,
+ 4, 1, 4, 2,
+ 2, 0, 8, 3
+ };
+
+
+static int max_mipmap;
+static unsigned char *tram;
+static int txlsize;
+static int errNo = 0;
+static int NA = 0; /* Not applicable */
+static unsigned int length; /* total texels in mipmap */
+static int level; /* total levels in mipmap */
+
+static void get3x3(struct Tile *tile, int *s, int *t, int *texel, int shift, int size);
+static void stuffDisplayList(Gfx **glistp, Image *im, char *tbuf, unsigned char startTile,
+ unsigned char pal, unsigned char cms, unsigned char cmt,
+ unsigned char masks, unsigned char maskt, unsigned char shifts,
+ unsigned char shiftt);
+static void kernel(int i, int r1, int g1, int b1, int a1, float *r2, float *g2,
+ float *b2, float *a2);
+
+#define unpack_ia16(c,i,a) \
+ i = (c & 0xff00) >> 8, a = (c & 0xff)
+#define pack_ia16(i,a) \
+ (i << 8) | a
+
+#define unpack_ia8(c,i,a) \
+ i = ((c & 0xf0) >> 4), a = (c & 0xf)
+#define pack_ia8(i,a) \
+ (a & 0xf) | ((i & 0xf) << 4)
+
+#define unpack_ia4(c,i,a) \
+ i = ((c & 0xe) >> 1), a = (c & 0x1)
+#define pack_ia4(i,a) \
+ ((i & 0x7) << 1) | ((a & 0x1))
+
+#define unpack_i4(c,i) \
+ i = (c & 0xf)
+#define pack_i4(i) \
+ (i)
+
+#define unpack_i8(c,i) \
+ i = (c & 0xff)
+#define pack_i8(i) \
+ (i)
+
+#define unpack_ci8(c,ci) unpack_i8(c,ci)
+#define pack_ci8(ci) pack_i8(ci)
+
+#define unpack_ci4(c,ci) unpack_i4(c,ci)
+#define pack_ci4(ci) pack_i4(ci)
+
+#define unpack_rgba(c,r,g,b,a) \
+ (r = (c & 0xf800) >> 11), g = ((c & 0x07c0) >> 6), b = ((c & 0x003e) >> 1), \
+ a = (c & 0x1)
+
+#define pack_rgba( r, g, b, a) ((r&0x1f) << 11) | (g&0x1f) << 6 | \
+ ((b&0x1f) << 1) | (a)
+
+/*************************************************************************
+ * Generates all levels of a power-of-two mipmap from an input array. *
+ * Also stuffs display list with entries for loading and rendering the *
+ * texture. Filtering Color-Index maps makes sense only if the lookup *
+ * is a linear ramp. Billboards and trees cutout using alpha will change *
+ * shape as the level changes due to change in map resolution. Texel *
+ * formats with only one bit of alpha will not be filtered very well. *
+ *************************************************************************
+ * ErrNo value error description *
+ *-----------------------------------------------------------------------*
+ * 1 Mipmap too big to load into tmem. Not Fatal, *
+ * will load as many levels as there is space for. *
+ * *
+ * 2 Texel format not supported, Fatal error *
+ ************************************************************************/
+
+int guLoadTextureBlockMipMap(Gfx **glistp, unsigned char *tbuf, Image *im,
+ unsigned char startTile, unsigned char pal, unsigned char cms, unsigned char cmt,
+ unsigned char masks, unsigned char maskt, unsigned char shifts, unsigned char shiftt,
+ unsigned char cfs, unsigned char cft)
+{
+
+ unsigned char *iaddr, *taddr;
+ int im_bytes, tr_bytes;
+ int h, b;
+ int flip;
+ char startUnAligned;
+ char endUnAligned;
+
+ txlsize = sizeParams[im->siz].tsize; /* texel size in nibbles */
+ /* to next line size */
+
+ /*
+ * Do top level map, swizzle bytes on odd t's *
+ */
+ /* base char address of tile to be loaded */
+ iaddr = ((im->t * im->lsize)+((im->s * txlsize) >> 1) + im->base);
+
+ /*check tile line starting and ending alignments along 4bit bndries */
+ startUnAligned = ((im->s & 0x1) && (im->siz == G_IM_SIZ_4b));
+ endUnAligned = (((im->s + im->w) & 0x1) && (im->siz == G_IM_SIZ_4b));
+
+ im_bytes = ((im->w * txlsize + 1) >> 1); /* siz of 1 tile line in bytes */
+ tr_bytes = im_bytes / TRAM_LSIZE; /* no of tram lines per tile line */
+ tr_bytes = tr_bytes * TRAM_LSIZE; /* tile line size in bytes */
+ if (im_bytes > tr_bytes) tr_bytes += TRAM_LSIZE;
+
+ taddr = &tbuf[im->addr]; /* why ? make this zero?*/
+
+ if (startUnAligned)
+ {
+ for (h=0; h<im->h; h++)
+ {
+ flip = (h & 1) << 2; /*shift does not depend on txlsize*/
+ for (b=0; b<im_bytes; b++)
+ {
+ *(taddr+(b^flip)) = ((*(iaddr+b) & 0x0f) << 4)
+ | ((*(iaddr+b+1) & 0xf0) >> 4);
+ }
+ /* add last aligned nibble */
+ if (!endUnAligned) *(taddr+((b-1)^flip)) &= (0xf0);
+ /* pickup trailing bytes */
+ for (b=im_bytes; b<tr_bytes; b++) *(taddr+(b^flip)) = 0;
+ iaddr += im->lsize;
+ taddr += tr_bytes;
+ }
+ }
+ else /* if start aligned */
+ {
+ for (h=0; h<im->h; h++)
+ {
+ flip = (h & 1) << 2; /*shift does not depend on txlsize*/
+ for (b=0; b<im_bytes; b++)
+ *(taddr+(b^flip)) = *(iaddr+b);
+
+ /* zero out last extra nibble */
+ if (endUnAligned) *(taddr+((b-1)^flip)) &= (0xf0);
+ /* pad trailing bytes with zeroes */
+ for (b=im_bytes; b<tr_bytes; b++) *(taddr+(b^flip)) = 0;
+
+ iaddr += im->lsize;
+ taddr += tr_bytes;
+ }
+ }
+
+ tram = tbuf;
+
+ /* save tile attributes in top mipmap */
+ mipmap[0].s = im->w; /* tile width */
+ mipmap[0].t = im->h; /* tile height */
+ /* guaranteed no remainder ? */
+ mipmap[0].w = ((tr_bytes / txlsize) << 1); /* tile line width in texels*/
+ mipmap[0].addr = im->addr;
+ max_mipmap = MM_MAX_LEVEL;
+ length = mipmap[0].w*mipmap[0].t; /* total texels in level 0 */
+/**
+ rmonPrintf("level0 w,t,l = %d %d %d\n",mipmap[0].w, mipmap[0].t,length);
+***/
+
+/******************************************************************************
+ Generate other levels of mipmap using a box filter
+******************************************************************************/
+
+{/* generate mip map for this tile */
+ unsigned char *taddr, *saddr;
+ int shift = (int) sizeParams[im->siz].shift;
+ int s, t, si, ti, sii, tii;
+ int s4[9];
+ int t4[9];
+ int tex4[9];
+ int r0, g0, b0, a0, r1, g1, b1, a1;
+ float r2 ,g2, b2, a2;
+ float dummy;
+ int i0, ci0, ia0, i1, ci1, ia1;
+ float i2, ci2, ia2;
+ int texel;
+ int i,trip;
+ unsigned int tempaddr;
+ int ntexels = ((TRAM_LSIZE/txlsize) << 1); /* texels per line */
+
+ level = 0; /* need to check for memory overflow */
+ while ((mipmap[level].s > 1) || (mipmap[level].t > 1))
+ {
+ level++;
+ /*
+ * set new mipmap level address in bytes
+ */
+ mipmap[level].addr = mipmap[level-1].addr +
+ (mipmap[level-1].w * txlsize * mipmap[level-1].t >> 1);
+
+ /*
+ * grab location in tram pointing to the current level address
+ */
+ taddr = &(tram[ mipmap[level].addr ]);
+
+ /*
+ * downfilter by 2X, bump odd size
+ * compute parameters for new mipmap level
+ */
+ mipmap[level].s = (mipmap[0].s) >> level;
+ mipmap[level].t = (mipmap[0].t) >> level;
+
+ if (mipmap[level].s == 0) mipmap[level].s = 1;
+ if (mipmap[level].t == 0) mipmap[level].t = 1;
+
+ /*
+ * width must be a multiple of 8 bytes (padding for tram line size)
+ */
+ mipmap[level].w =
+ ((mipmap[level].s + (ntexels -1)) >> (shift +1) << (shift +1));
+
+ /*
+ * compute total no of texels to be loaded
+ */
+ length += mipmap[level].w*mipmap[level].t;
+/**
+ rmonPrintf("level, w,t,l = %d %d %d %d\n", level, mipmap[level].w, mipmap[level].t,length);
+**/
+ if ((length*txlsize >> 1) >= TRAM_SIZE)
+ {
+ errNo = 1;
+ length -= mipmap[level].w*mipmap[level].t;
+ break;
+ }
+
+ /*
+ * for each scanline
+ */
+ for (t=0; t<mipmap[level-1].t; t+=2)
+ {
+ flip = 0;
+ trip = (t & 2) << 1; /* invert bit 4 on odd line */
+ ti = t + 1;
+ tii = t - 1;
+
+ /*
+ * check filtering clamp/wrap flag and do accordingly
+ */
+ if ( cft) {
+ if (ti >= mipmap[level-1].t) ti = t;
+ if (tii < 0) tii = t;
+ } else {
+ if (ti >= mipmap[level-1].t) ti = 0;
+ if (tii < 0) tii = mipmap[level-1].t - 1;
+ }
+
+ tempaddr = 0;
+
+ for (s=0; s<mipmap[level-1].s; s+=2)
+ {
+ si = s + 1;
+ sii = s - 1;
+ /*
+ * duplicate last texel for odd sizes for filtering
+ */
+ if (cfs) {
+ if (si >= mipmap[level-1].s) si = s;
+ if (sii < 0) sii = s;
+ } else {
+ if (si >= mipmap[level-1].s) si = 0;
+ if (sii < 0) sii = mipmap[level-1].s - 1;
+ }
+
+/***
+ if (level == 6)
+ rmonPrintf("sts = %d %d %d %d %d %d\n",
+ s, si, sii, t, ti, tii);
+***/
+
+ /*
+ * grab the nine neighbours to apply kernel function
+ */
+ s4[0] = s; t4[0] = tii;
+ s4[1] = si; t4[1] = tii;
+ s4[2] = si; t4[2] = t;
+ s4[3] = si; t4[3] = ti;
+ s4[4] = s; t4[4] = ti;
+ s4[5] = sii; t4[5] = ti;
+ s4[6] = sii; t4[6] = t;
+ s4[7] = sii; t4[7] = tii;
+ s4[8] = s; t4[8] = t;
+
+ get3x3( &mipmap[level-1], s4, t4, tex4, shift, im->siz);
+
+ saddr = taddr + ((tempaddr >> 1)^trip);
+ r1 = g1 = b1 = a1 = ci1 = i1 = 0;
+ r2 = g2 = b2 = a2 = ci2 = i2 = 0;
+
+ /*
+ * Extract R,G and B components of the 9 texels and
+ * apply the filter kernel
+ */
+ switch (im->fmt)
+ {
+ case (G_IM_FMT_RGBA):
+ if (im->siz == G_IM_SIZ_16b)
+ {
+ for (i=0; i< 9; i++)
+ {
+ unpack_rgba(tex4[i], r0, g0, b0, a0);
+ kernel(i, r0, g0, b0, a0, &r2, &g2, &b2, &a2);
+/***
+ if (level == 6)
+ rmonPrintf("r0, g0, b0, a0 = %d %d %d %d\n",
+ r0, g0, b0, a0);
+**/
+ }
+ r1 = (int)(r2/16.0 + 0.5);
+ g1 = (int)(g2/16.0 + 0.5);
+ b1 = (int)(b2/16.0 + 0.5);
+ a1 = (int)(a2/16.0 + 0.5);
+ }
+ else
+ {
+ /*
+ * RGBA32 is not supported
+ */
+ errNo = 2;
+ return errNo;
+ }
+ break;
+
+ case (G_IM_FMT_YUV):
+ errNo = 2;
+ return errNo;
+ break;
+
+ case (G_IM_FMT_CI):
+ if (im->siz == G_IM_SIZ_4b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_ci4(tex4[i],ci0);
+ kernel(i, ci0, 0, 0, 0, &ci2, &dummy, &dummy,
+ &dummy);
+ }
+ ci1 = (int)(ci2/16.0 + 0.5);
+ }
+ else
+ if (im->siz == G_IM_SIZ_8b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_ci8(tex4[i],ci0);
+ kernel(i, ci0, 0, 0, 0, &ci2, &dummy,
+ &dummy, &dummy);
+ }
+ ci1 = (int)(ci2/16.0 + 0.5);
+ }
+ else
+ {
+ errNo=2;
+ return errNo;
+ }
+ break;
+
+ case (G_IM_FMT_IA):
+ if (im->siz == G_IM_SIZ_4b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_ia4(tex4[i],i0,a0);
+ kernel(i, i0, a0, 0, 0, &i2, &a2, &dummy,
+ &dummy);
+ }
+ i1 = (int)(i2/16.0 +0.5);
+ a1 = (int)(a2/16.0 +0.5);
+ }
+ else if (im->siz == G_IM_SIZ_8b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_ia8(tex4[i],i0,a0);
+ kernel(i, i0, a0, 0, 0, &i2, &a2, &dummy,
+ &dummy);
+ }
+ i1 = (int)(i2/16.0 +0.5);
+ a1 = (int)(a2/16.0 +0.5);
+ }
+ else
+ if (im->siz == G_IM_SIZ_16b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_ia16(tex4[i],i0,a0);
+ kernel(i, i0, a0, 0, 0, &i2, &a2, &dummy,
+ &dummy);
+ }
+ i1 = (int)(i2/16.0 +0.5);
+ a1 = (int)(a2/16.0 +0.5);
+ }
+ else
+ {
+ errNo = 2;
+ return errNo;
+ }
+ break;
+
+ case (G_IM_FMT_I):
+ if (im->siz == G_IM_SIZ_4b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_i4(tex4[i],i0);
+ kernel(i, i0, 0, 0, 0, &i2, &dummy, &dummy,
+ &dummy);
+ }
+ i1 = (int)(i2/16.0 + 0.5);
+ }
+ else
+ if (im->siz == G_IM_SIZ_8b)
+ {
+ for (i=0; i<9; i++)
+ {
+ unpack_i8(tex4[i],i0);
+ kernel(i, i0, 0, 0, 0, &i2, &dummy, &dummy,
+ &dummy);
+ }
+ i1 = (int)(i2/16.0 +0.5);
+ }
+ else
+ {
+ errNo = 2;
+ return errNo;
+ }
+
+ default:
+ break;
+ }
+
+ /*
+ * Pack fields into destination texel
+ */
+ switch (im->fmt)
+ {
+
+ case (G_IM_FMT_RGBA):
+ texel = pack_rgba(r1,g1,b1,a1);
+ *(short *)((int)saddr^flip) = texel;
+ break;
+
+ case (G_IM_FMT_YUV):
+ break;
+
+ case (G_IM_FMT_CI):
+
+ if (im->siz == G_IM_SIZ_4b)
+ {
+ texel = pack_ci4(ci1);
+ *(char *)((int)saddr^flip) |= (s & 0x2)?
+ (texel): (texel << 4);
+ }
+ else
+ if (im->siz == G_IM_SIZ_8b)
+ {
+ texel = pack_ci8(ci1);
+ *(char *)((int)saddr^flip) = texel;
+ }
+ break;
+
+ case (G_IM_FMT_IA):
+ if (im->siz == G_IM_SIZ_4b)
+ {
+ texel = pack_ia4(i1,a1);
+ *(char *)((int)saddr^flip) |= (s & 0x2)?
+ (texel): (texel << 4);
+ }
+ else
+ if (im->siz == G_IM_SIZ_8b)
+ {
+ texel = pack_ia8(i1,a1);
+ *(char *)((int)saddr^flip) = texel;
+ }
+ else
+ if (im->siz == G_IM_SIZ_16b)
+ {
+ texel = pack_ia16(i1,a1);
+ *(short *)((int)saddr^flip) = texel;
+ }
+ break;
+
+ case (G_IM_FMT_I):
+ if (im->siz == G_IM_SIZ_4b)
+ {
+ texel = pack_i4(i1);
+ *(char *)((int)saddr^flip) |= (s & 0x2)?
+ (texel): (texel << 4);
+ }
+ else
+ if (im->siz == G_IM_SIZ_8b)
+ {
+ texel = pack_i8(i1);
+ *(char *)((int)saddr^flip) = texel;
+ }
+ break;
+ }
+
+ tempaddr += txlsize;
+
+ } /* end s */
+
+ taddr += ((mipmap[level].w * txlsize) >> 1);
+
+ } /* end t */
+
+ if (mipmap[level].s <= MM_MIN_SIZE &&
+ mipmap[level].t <= MM_MIN_SIZE)
+ {
+ max_mipmap = level;
+ break;
+ }
+ } /* end level */
+
+}/* end generate mipmap */
+/*
+ * Add entries for texture loading and rendering in DL
+ */
+stuffDisplayList(glistp, im, tbuf, startTile, pal, cms, cmt, masks, maskt, shifts, shiftt);
+
+return errNo;
+} /* end guLoadTextureBlockMipMap */
+
+/******************************************************************************
+ *
+ * Apply Kernel :
+ * 1 2 1
+ * 2 4 1
+ * 1 2 1
+ ******************************************************************************/
+static void kernel(int i, int r0, int g0, int b0, int a0, float *r2, float *g2, float *b2, float *a2)
+{
+ if (i == 8)
+ {
+ *r2 += r0*4; *g2 += g0*4; *b2 += b0*4; *a2 += a0*4;
+ } else
+ if (i%2 == 0)
+ {
+ *r2 += r0*2;
+ *g2 += g0*2;
+ *b2 += b0*2;
+ *a2 += a0*2;
+ } else
+ {
+ *r2 += r0;
+ *g2 += g0;
+ *b2 += b0;
+ *a2 += a0;
+ }
+}
+
+/********************************************************************
+ Add entries for loading and rendering textures into the display list
+*********************************************************************/
+static void stuffDisplayList(Gfx **glistp, Image *im, char *tbuf, unsigned char startTile,
+ unsigned char pal, unsigned char cms, unsigned char cmt,
+ unsigned char masks, unsigned char maskt, unsigned char shifts,
+ unsigned char shiftt)
+{
+ int tile;
+ int Smask, Tmask;
+ int Sshift, Tshift;
+
+ /*
+ * set LOADTILE for loading texture
+ * 4-bit textures are loaded in 8-bit chunks
+ */
+ if (im->siz == G_IM_SIZ_4b) {
+ gDPSetTextureImage((*glistp)++, im->fmt, G_IM_SIZ_8b, 1,
+ osVirtualToPhysical((unsigned short *)tbuf));
+ gDPSetTile((*glistp)++, im->fmt, G_IM_SIZ_8b, NA, 0, G_TX_LOADTILE, NA,
+ NA, NA, NA, NA, NA, NA);
+ /* Wait until all primitives are done */
+ gDPLoadSync((*glistp)++);
+ gDPLoadBlock((*glistp)++, G_TX_LOADTILE, 0, 0, length/2, 0x0);
+ } else {
+ gDPSetTextureImage((*glistp)++, im->fmt, im->siz, 1,
+ osVirtualToPhysical((unsigned short *)tbuf));
+ gDPSetTile((*glistp)++, im->fmt, im->siz, NA, 0, G_TX_LOADTILE, NA,
+ NA, NA, NA, NA, NA, NA);
+ /* Wait until all primitives are done */
+ gDPLoadSync((*glistp)++);
+ gDPLoadBlock((*glistp)++, G_TX_LOADTILE, 0, 0, length, 0x0);
+ }
+
+ for (tile = 0; tile <= level; tile ++)
+ {
+ Tmask = maskt-tile;
+ if (Tmask < 0){
+ Tmask = 0;
+ } else {
+ Tshift = tile;
+ }
+
+ Smask = masks-tile;
+ if (Smask < 0){
+ Smask = 0;
+ } else {
+ Sshift = tile;
+ }
+
+/***
+ rmonPrintf("tile, Tmask, Tshift, Smask, Sshift %d %d %d %d %d\n",
+ tile, Tmask, Tshift, Smask, Sshift);
+ rmonPrintf("%d\n",startTile);
+***/
+
+
+ gDPSetTile((*glistp)++,im->fmt, im->siz, (mipmap[tile].w*txlsize >> 4),
+ (mipmap[tile].addr >> 3), tile+startTile, pal, cmt, Tmask, Tshift, cms,
+ Smask, Sshift);
+
+ gDPSetTileSize((*glistp)++,tile+startTile, (0 <<G_TEXTURE_IMAGE_FRAC),
+ (0 <<G_TEXTURE_IMAGE_FRAC), (mipmap[tile].s-1) <<G_TEXTURE_IMAGE_FRAC,
+ (mipmap[tile].t-1) << G_TEXTURE_IMAGE_FRAC);
+ }
+}
+
+/******************************************************************************
+ Extract quad of texels for filtering. Compute bank and row addresses.
+******************************************************************************/
+static void get3x3(struct Tile *tile, int *s, int *t, int *texel, int shift, int size)
+{
+ int i;
+ int bank, row;
+ unsigned int addr;
+ int overlap;
+ unsigned char r, g, b, a;
+ unsigned long tex;
+ struct Image *im;
+ unsigned int ss,tt;
+
+ for (i=0; i< 9; i++)
+ {
+ ss = s[i];
+ tt = t[i];
+ /* bank and row indexing */
+ bank = (((ss & (0x3 << (shift-1))) >> (shift-1)) ^ ((tt & 0x1) << 1)) << 1;
+ row = (((tt * tile->w + ss) * txlsize) >> 1) / TRAM_LSIZE;
+ addr = tile->addr + row * TRAM_WSIZE + bank;
+
+ overlap = (i == 0) ? bank : overlap ^ bank;
+
+ switch (size)
+ {
+ case G_IM_SIZ_4b:
+ texel[i] = (tram[addr + ((ss & 0x2) >> 1)]
+ & (0xf0 >> ((ss & 0x1) << 2)));
+ if (!(ss & 0x1)) texel[i] = texel[i] >> 4;
+ break;
+
+ case G_IM_SIZ_8b:
+ texel[i] = tram[addr + (ss & 0x1)];
+ break;
+
+ case G_IM_SIZ_16b:
+ texel[i] = (tram[addr] << 8) | tram[addr+1];
+ break;
+
+ case G_IM_SIZ_32b:
+ errNo = 2; /* Format not supported */
+ break;
+
+ default:
+ break;
+ }
+
+ }
+}
diff --git a/lib/ultralib/src/gu/lookat.c b/lib/ultralib/src/gu/lookat.c
new file mode 100644
index 0000000..1fadc17
--- /dev/null
+++ b/lib/ultralib/src/gu/lookat.c
@@ -0,0 +1,83 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp)
+{
+ float len, xLook, yLook, zLook, xRight, yRight, zRight;
+
+ guMtxIdentF(mf);
+
+ xLook = xAt - xEye;
+ yLook = yAt - yEye;
+ zLook = zAt - zEye;
+
+ /* Negate because positive Z is behind us: */
+ len = -1.0 / sqrtf (xLook*xLook + yLook*yLook + zLook*zLook);
+ xLook *= len;
+ yLook *= len;
+ zLook *= len;
+
+ /* Right = Up x Look */
+
+ xRight = yUp * zLook - zUp * yLook;
+ yRight = zUp * xLook - xUp * zLook;
+ zRight = xUp * yLook - yUp * xLook;
+ len = 1.0 / sqrtf (xRight*xRight + yRight*yRight + zRight*zRight);
+ xRight *= len;
+ yRight *= len;
+ zRight *= len;
+
+ /* Up = Look x Right */
+
+ xUp = yLook * zRight - zLook * yRight;
+ yUp = zLook * xRight - xLook * zRight;
+ zUp = xLook * yRight - yLook * xRight;
+ len = 1.0 / sqrtf (xUp*xUp + yUp*yUp + zUp*zUp);
+ xUp *= len;
+ yUp *= len;
+ zUp *= len;
+
+ mf[0][0] = xRight;
+ mf[1][0] = yRight;
+ mf[2][0] = zRight;
+ mf[3][0] = -(xEye * xRight + yEye * yRight + zEye * zRight);
+
+ mf[0][1] = xUp;
+ mf[1][1] = yUp;
+ mf[2][1] = zUp;
+ mf[3][1] = -(xEye * xUp + yEye * yUp + zEye * zUp);
+
+ mf[0][2] = xLook;
+ mf[1][2] = yLook;
+ mf[2][2] = zLook;
+ mf[3][2] = -(xEye * xLook + yEye * yLook + zEye * zLook);
+
+ mf[0][3] = 0;
+ mf[1][3] = 0;
+ mf[2][3] = 0;
+ mf[3][3] = 1;
+}
+
+void guLookAt (Mtx *m, float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp)
+{
+ Matrix mf;
+
+ guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/lookathil.c b/lib/ultralib/src/gu/lookathil.c
new file mode 100644
index 0000000..a848688
--- /dev/null
+++ b/lib/ultralib/src/gu/lookathil.c
@@ -0,0 +1,185 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+
+void guLookAtHiliteF(float mf[4][4], LookAt *l, Hilite *h,
+ float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp,
+ float xl1, float yl1, float zl1, /* light 1 direction */
+ float xl2, float yl2, float zl2, /* light 2 direction */
+ int twidth, int theight) /* highlight txtr size*/
+{
+ float len, xLook, yLook, zLook, xRight, yRight, zRight;
+ float xHilite, yHilite, zHilite;
+
+ guMtxIdentF(mf);
+
+ xLook = xAt - xEye;
+ yLook = yAt - yEye;
+ zLook = zAt - zEye;
+
+ /* Negate because positive Z is behind us: */
+ len = -1.0 / sqrtf (xLook*xLook + yLook*yLook + zLook*zLook);
+ xLook *= len;
+ yLook *= len;
+ zLook *= len;
+
+ /* Right = Up x Look */
+
+ xRight = yUp * zLook - zUp * yLook;
+ yRight = zUp * xLook - xUp * zLook;
+ zRight = xUp * yLook - yUp * xLook;
+ len = 1.0 / sqrtf (xRight*xRight + yRight*yRight + zRight*zRight);
+ xRight *= len;
+ yRight *= len;
+ zRight *= len;
+
+ /* Up = Look x Right */
+
+ xUp = yLook * zRight - zLook * yRight;
+ yUp = zLook * xRight - xLook * zRight;
+ zUp = xLook * yRight - yLook * xRight;
+ len = 1.0 / sqrtf (xUp*xUp + yUp*yUp + zUp*zUp);
+ xUp *= len;
+ yUp *= len;
+ zUp *= len;
+
+ /* hilite vectors */
+
+ len = 1.0 / sqrtf (xl1*xl1 + yl1*yl1 + zl1*zl1);
+ xl1 *= len;
+ yl1 *= len;
+ zl1 *= len;
+
+#define THRESH2 0.1
+ xHilite = xl1 + xLook;
+ yHilite = yl1 + yLook;
+ zHilite = zl1 + zLook;
+
+ len = sqrtf (xHilite*xHilite + yHilite*yHilite + zHilite*zHilite);
+
+ if (len>THRESH2)
+ {
+ len = 1.0 / len;
+ xHilite *= len;
+ yHilite *= len;
+ zHilite *= len;
+
+ h->h.x1 =
+ twidth*4 + (xHilite*xRight +
+ yHilite*yRight +
+ zHilite*zRight)*twidth*2;
+
+ h->h.y1 =
+ theight*4 + (xHilite*xUp +
+ yHilite*yUp +
+ zHilite*zUp)*theight*2;
+ }
+ else
+ {
+ h->h.x1 = twidth*2;
+ h->h.y1 = theight*2;
+ }
+
+ len = 1.0 / sqrtf (xl2*xl2 + yl2*yl2 + zl2*zl2);
+ xl2 *= len;
+ yl2 *= len;
+ zl2 *= len;
+
+ xHilite = xl2 + xLook;
+ yHilite = yl2 + yLook;
+ zHilite = zl2 + zLook;
+ len = sqrtf (xHilite*xHilite + yHilite*yHilite + zHilite*zHilite);
+ if (len>THRESH2)
+ {
+ len = 1.0 / len;
+ xHilite *= len;
+ yHilite *= len;
+ zHilite *= len;
+
+ h->h.x2 = twidth*4 +
+ (xHilite*xRight + yHilite*yRight + zHilite*zRight)*twidth*2;
+
+ h->h.y2 = theight*4 +
+ (xHilite*xUp + yHilite*yUp + zHilite*zUp)*theight*2;
+ }
+ else
+ {
+ h->h.x2 = twidth*2;
+ h->h.y2 = theight*2;
+ }
+
+ /* reflectance vectors = Up and Right */
+
+ l->l[0].l.dir[0] = FTOFRAC8(xRight);
+ l->l[0].l.dir[1] = FTOFRAC8(yRight);
+ l->l[0].l.dir[2] = FTOFRAC8(zRight);
+ l->l[1].l.dir[0] = FTOFRAC8(xUp);
+ l->l[1].l.dir[1] = FTOFRAC8(yUp);
+ l->l[1].l.dir[2] = FTOFRAC8(zUp);
+ l->l[0].l.col[0] = 0x00;
+ l->l[0].l.col[1] = 0x00;
+ l->l[0].l.col[2] = 0x00;
+ l->l[0].l.pad1 = 0x00;
+ l->l[0].l.colc[0] = 0x00;
+ l->l[0].l.colc[1] = 0x00;
+ l->l[0].l.colc[2] = 0x00;
+ l->l[0].l.pad2 = 0x00;
+ l->l[1].l.col[0] = 0x00;
+ l->l[1].l.col[1] = 0x80;
+ l->l[1].l.col[2] = 0x00;
+ l->l[1].l.pad1 = 0x00;
+ l->l[1].l.colc[0] = 0x00;
+ l->l[1].l.colc[1] = 0x80;
+ l->l[1].l.colc[2] = 0x00;
+ l->l[1].l.pad2 = 0x00;
+
+ mf[0][0] = xRight;
+ mf[1][0] = yRight;
+ mf[2][0] = zRight;
+ mf[3][0] = -(xEye * xRight + yEye * yRight + zEye * zRight);
+
+ mf[0][1] = xUp;
+ mf[1][1] = yUp;
+ mf[2][1] = zUp;
+ mf[3][1] = -(xEye * xUp + yEye * yUp + zEye * zUp);
+
+ mf[0][2] = xLook;
+ mf[1][2] = yLook;
+ mf[2][2] = zLook;
+ mf[3][2] = -(xEye * xLook + yEye * yLook + zEye * zLook);
+
+ mf[0][3] = 0;
+ mf[1][3] = 0;
+ mf[2][3] = 0;
+ mf[3][3] = 1;
+}
+
+void guLookAtHilite (Mtx *m, LookAt *l, Hilite *h,
+ float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp,
+ float xl1, float yl1, float zl1, /* light 1 direction */
+ float xl2, float yl2, float zl2, /* light 2 direction */
+ int twidth, int theight) /* highlight txtr size*/
+{
+ Matrix mf;
+
+ guLookAtHiliteF(mf, l, h, xEye, yEye, zEye, xAt, yAt, zAt,
+ xUp, yUp, zUp, xl1, yl1, zl1, xl2, yl2, zl2,
+ twidth, theight);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/lookatref.c b/lib/ultralib/src/gu/lookatref.c
new file mode 100644
index 0000000..3cd3b65
--- /dev/null
+++ b/lib/ultralib/src/gu/lookatref.c
@@ -0,0 +1,111 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+
+void guLookAtReflectF(float mf[4][4], LookAt *l,
+ float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp)
+{
+ float len, xLook, yLook, zLook, xRight, yRight, zRight;
+
+ guMtxIdentF(mf);
+
+ xLook = xAt - xEye;
+ yLook = yAt - yEye;
+ zLook = zAt - zEye;
+
+ /* Negate because positive Z is behind us: */
+ len = -1.0 / sqrtf (xLook*xLook + yLook*yLook + zLook*zLook);
+ xLook *= len;
+ yLook *= len;
+ zLook *= len;
+
+ /* Right = Up x Look */
+
+ xRight = yUp * zLook - zUp * yLook;
+ yRight = zUp * xLook - xUp * zLook;
+ zRight = xUp * yLook - yUp * xLook;
+ len = 1.0 / sqrtf (xRight*xRight + yRight*yRight + zRight*zRight);
+ xRight *= len;
+ yRight *= len;
+ zRight *= len;
+
+ /* Up = Look x Right */
+
+ xUp = yLook * zRight - zLook * yRight;
+ yUp = zLook * xRight - xLook * zRight;
+ zUp = xLook * yRight - yLook * xRight;
+ len = 1.0 / sqrtf (xUp*xUp + yUp*yUp + zUp*zUp);
+ xUp *= len;
+ yUp *= len;
+ zUp *= len;
+
+ /* reflectance vectors = Up and Right */
+
+ l->l[0].l.dir[0] = FTOFRAC8(xRight);
+ l->l[0].l.dir[1] = FTOFRAC8(yRight);
+ l->l[0].l.dir[2] = FTOFRAC8(zRight);
+ l->l[1].l.dir[0] = FTOFRAC8(xUp);
+ l->l[1].l.dir[1] = FTOFRAC8(yUp);
+ l->l[1].l.dir[2] = FTOFRAC8(zUp);
+ l->l[0].l.col[0] = 0x00;
+ l->l[0].l.col[1] = 0x00;
+ l->l[0].l.col[2] = 0x00;
+ l->l[0].l.pad1 = 0x00;
+ l->l[0].l.colc[0] = 0x00;
+ l->l[0].l.colc[1] = 0x00;
+ l->l[0].l.colc[2] = 0x00;
+ l->l[0].l.pad2 = 0x00;
+ l->l[1].l.col[0] = 0x00;
+ l->l[1].l.col[1] = 0x80;
+ l->l[1].l.col[2] = 0x00;
+ l->l[1].l.pad1 = 0x00;
+ l->l[1].l.colc[0] = 0x00;
+ l->l[1].l.colc[1] = 0x80;
+ l->l[1].l.colc[2] = 0x00;
+ l->l[1].l.pad2 = 0x00;
+
+ mf[0][0] = xRight;
+ mf[1][0] = yRight;
+ mf[2][0] = zRight;
+ mf[3][0] = -(xEye * xRight + yEye * yRight + zEye * zRight);
+
+ mf[0][1] = xUp;
+ mf[1][1] = yUp;
+ mf[2][1] = zUp;
+ mf[3][1] = -(xEye * xUp + yEye * yUp + zEye * zUp);
+
+ mf[0][2] = xLook;
+ mf[1][2] = yLook;
+ mf[2][2] = zLook;
+ mf[3][2] = -(xEye * xLook + yEye * yLook + zEye * zLook);
+
+ mf[0][3] = 0;
+ mf[1][3] = 0;
+ mf[2][3] = 0;
+ mf[3][3] = 1;
+}
+
+void guLookAtReflect (Mtx *m, LookAt *l, float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp)
+{
+ float mf[4][4];
+
+ guLookAtReflectF(mf, l, xEye, yEye, zEye, xAt, yAt, zAt,
+ xUp, yUp, zUp);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/lookatstereo.c b/lib/ultralib/src/gu/lookatstereo.c
new file mode 100644
index 0000000..b60ca08
--- /dev/null
+++ b/lib/ultralib/src/gu/lookatstereo.c
@@ -0,0 +1,111 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+void guLookAtStereoF(float mf[4][4], float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp, float eyedist)
+{
+ float len, xLook, yLook, zLook, xRight, yRight, zRight;
+
+ guMtxIdentF(mf);
+
+ xLook = xAt - xEye;
+ yLook = yAt - yEye;
+ zLook = zAt - zEye;
+
+ /* Negate because positive Z is behind us: */
+ len = -1.0 / sqrtf (xLook*xLook + yLook*yLook + zLook*zLook);
+ xLook *= len;
+ yLook *= len;
+ zLook *= len;
+
+ /* Right = Up x Look */
+
+ xRight = yUp * zLook - zUp * yLook;
+ yRight = zUp * xLook - xUp * zLook;
+ zRight = xUp * yLook - yUp * xLook;
+ len = 1.0 / sqrtf (xRight*xRight + yRight*yRight + zRight*zRight);
+ xRight *= len;
+ yRight *= len;
+ zRight *= len;
+
+ /* Move eye for stereo */
+ xEye += eyedist*xRight;
+ yEye += eyedist*yRight;
+ zEye += eyedist*zRight;
+
+ /* recalculate using new eye */
+ xLook = xAt - xEye;
+ yLook = yAt - yEye;
+ zLook = zAt - zEye;
+
+ /* Negate because positive Z is behind us: */
+ len = -1.0 / sqrtf (xLook*xLook + yLook*yLook + zLook*zLook);
+ xLook *= len;
+ yLook *= len;
+ zLook *= len;
+
+ /* Right = Up x Look */
+
+ xRight = yUp * zLook - zUp * yLook;
+ yRight = zUp * xLook - xUp * zLook;
+ zRight = xUp * yLook - yUp * xLook;
+ len = 1.0 / sqrtf (xRight*xRight + yRight*yRight + zRight*zRight);
+ xRight *= len;
+ yRight *= len;
+ zRight *= len;
+
+
+ /* Up = Look x Right */
+
+ xUp = yLook * zRight - zLook * yRight;
+ yUp = zLook * xRight - xLook * zRight;
+ zUp = xLook * yRight - yLook * xRight;
+ len = 1.0 / sqrtf (xUp*xUp + yUp*yUp + zUp*zUp);
+ xUp *= len;
+ yUp *= len;
+ zUp *= len;
+
+ mf[0][0] = xRight;
+ mf[1][0] = yRight;
+ mf[2][0] = zRight;
+ mf[3][0] = -(xEye * xRight + yEye * yRight + zEye * zRight);
+
+ mf[0][1] = xUp;
+ mf[1][1] = yUp;
+ mf[2][1] = zUp;
+ mf[3][1] = -(xEye * xUp + yEye * yUp + zEye * zUp);
+
+ mf[0][2] = xLook;
+ mf[1][2] = yLook;
+ mf[2][2] = zLook;
+ mf[3][2] = -(xEye * xLook + yEye * yLook + zEye * zLook);
+
+ mf[0][3] = 0;
+ mf[1][3] = 0;
+ mf[2][3] = 0;
+ mf[3][3] = 1;
+}
+
+void guLookAtStereo (Mtx *m, float xEye, float yEye, float zEye,
+ float xAt, float yAt, float zAt,
+ float xUp, float yUp, float zUp, float eyedist)
+{
+ Matrix mf;
+
+ guLookAtStereoF(mf, xEye, yEye, zEye, xAt, yAt, zAt,
+ xUp, yUp, zUp, eyedist);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/mtxcatl.c b/lib/ultralib/src/gu/mtxcatl.c
new file mode 100644
index 0000000..11f43a1
--- /dev/null
+++ b/lib/ultralib/src/gu/mtxcatl.c
@@ -0,0 +1,45 @@
+
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ */
+
+/*
+ * File: mtxcatl.c
+ * Creator: hsa@sgi.com
+ * Create Date: Thu Nov 2 13:03:02 PST 1995
+ *
+ */
+
+#include "guint.h"
+
+void guMtxCatL(Mtx *m, Mtx *n, Mtx *res)
+{
+ float mf[4][4], nf[4][4], resf[4][4];
+
+ guMtxL2F(mf, m);
+ guMtxL2F(nf, n);
+
+ guMtxCatF(mf, nf, resf);
+
+ guMtxF2L(resf, res);
+}
diff --git a/lib/ultralib/src/gu/mtxutil.c b/lib/ultralib/src/gu/mtxutil.c
new file mode 100644
index 0000000..2510558
--- /dev/null
+++ b/lib/ultralib/src/gu/mtxutil.c
@@ -0,0 +1,73 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+void guMtxF2L(float mf[4][4], Mtx *m)
+{
+ int i, j;
+ int e1,e2;
+ int *ai,*af;
+
+
+ ai=(int *) &m->m[0][0];
+ af=(int *) &m->m[2][0];
+
+ for (i=0; i<4; i++)
+ for (j=0; j<2; j++) {
+ e1=FTOFIX32(mf[i][j*2]);
+ e2=FTOFIX32(mf[i][j*2+1]);
+ *(ai++) = ( e1 & 0xffff0000 ) | ((e2 >> 16)&0xffff);
+ *(af++) = ((e1 << 16) & 0xffff0000) | (e2 & 0xffff);
+ }
+}
+
+void guMtxL2F(float mf[4][4], Mtx *m)
+{
+ int i, j;
+ unsigned int e1,e2;
+ unsigned int *ai,*af;
+ int q1,q2;
+
+ ai=(unsigned int *) &m->m[0][0];
+ af=(unsigned int *) &m->m[2][0];
+
+ for (i=0; i<4; i++)
+ for (j=0; j<2; j++) {
+ e1 = (*ai & 0xffff0000) | ((*af >> 16) & 0xffff);
+ e2 = ((*(ai++) << 16) & 0xffff0000) | (*(af++) & 0xffff);
+ q1 = *((int *)&e1);
+ q2 = *((int *)&e2);
+
+ mf[i][j*2] = FIX32TOF(q1);
+ mf[i][j*2+1] = FIX32TOF(q2);
+ }
+}
+
+void guMtxIdentF(float mf[4][4])
+{
+ int i, j;
+
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++)
+ if (i == j) mf[i][j] = 1.0;
+ else mf[i][j] = 0.0;
+}
+
+void guMtxIdent(Mtx *m)
+{
+ float mf[4][4];
+
+ guMtxIdentF(mf);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/ortho.c b/lib/ultralib/src/gu/ortho.c
new file mode 100644
index 0000000..9e52cb3
--- /dev/null
+++ b/lib/ultralib/src/gu/ortho.c
@@ -0,0 +1,41 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+void guOrthoF(float mf[4][4], float l, float r, float b, float t, float n, float f, float scale)
+{
+ int i, j;
+
+ guMtxIdentF(mf);
+
+ mf[0][0] = 2/(r-l);
+ mf[1][1] = 2/(t-b);
+ mf[2][2] = -2/(f-n);
+ mf[3][0] = -(r+l)/(r-l);
+ mf[3][1] = -(t+b)/(t-b);
+ mf[3][2] = -(f+n)/(f-n);
+ mf[3][3] = 1;
+
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++)
+ mf[i][j] *= scale;
+}
+
+void guOrtho(Mtx *m, float l, float r, float b, float t, float n, float f, float scale)
+{
+ Matrix mf;
+
+ guOrthoF(mf, l, r, b, t, n, f, scale);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/parse_gbi.c b/lib/ultralib/src/gu/parse_gbi.c
new file mode 100644
index 0000000..21cf9c3
--- /dev/null
+++ b/lib/ultralib/src/gu/parse_gbi.c
@@ -0,0 +1,131 @@
+
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ *************************************************************************/
+#include <ultra64.h>
+#include <ultrahost.h>
+#include <gu.h>
+
+#ifndef _FINALROM
+
+/*
+ * guParseGbiDL works in conjunction with the dlprint tool. dlprint must be
+ * running on the host Indy. guParseGbiDL, sends a bunch of blocks of data,
+ * with a minimum of one display list, but typically, the principle display
+ * list with a bunch of branched or nested display lists, as well as all the
+ * vertex and matrix data that will be used. After all the blocks of data
+ * are sent, a GU_PARSE_READY command is sent, and dlprint parses out the
+ * data printing it to stdout.
+ *
+ * In order to know what data to send, guParseGbiDL must step through the
+ * display list, find all the gSPDisplayList and gSPBranchList calls, go
+ * to those lists, and also find and send info for all the matrix and vertex
+ * calls.
+ */
+void guParseGbiDL(u64 *gbi_dl, u32 nbytes, u8 flags)
+{
+ guDLPrintCB cntlBlk;
+ Gfx* dlStk[11];
+ s32 dlcount = 0;
+ Gfx *curGfx,*dlPtr,*vaddr;
+ s8 op;
+ u32 *word0;
+ u32 *word1;
+ u32 segments[16];
+ u32 param, seg;
+ u32 paddr,len;
+
+
+ cntlBlk.dataSize = nbytes;
+ cntlBlk.flags = flags;
+ cntlBlk.dlType = GU_PARSE_GBI_TYPE;
+ cntlBlk.paddr = osVirtualToPhysical(gbi_dl);
+
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+ osWriteHost(gbi_dl,nbytes);
+
+ dlStk[0] = (Gfx*)gbi_dl;
+ while((dlcount >= 0) && (dlcount <= 10))
+ {
+ curGfx = dlStk[dlcount]; /* get the current graphics display list */
+ op = *((s8*)curGfx); /* get the first byte */
+ dlStk[dlcount]++; /* increment to next gfx command */
+ switch(op)
+ {
+ case G_MOVEWORD:
+ word0 = (u32*)curGfx; /* get ptr to first word */
+ if(((*word0) & 0x000000ff) == G_MW_SEGMENT)
+ {
+ u32 seg;
+ seg = (((*word0) & 0x00ffff00) >> 8) >> 2;
+ word1 = word0 + 1;
+ segments[seg] = *word1;
+ }
+ break;
+ case G_ENDDL:
+ dlcount--;
+ break;
+ case G_DL:
+ word0 = (u32*)curGfx; /* get ptr to first word */
+ param = ((*word0) & 0x00ff0000) >> 16; /* get param */
+ word1 = word0 + 1; /* get pointer to second word */
+ seg = ((*word1) & 0x0f000000) >> 24; /* get the segment */
+ paddr = segments[seg] + ((*word1) & 0x00ffffff);
+ vaddr = (Gfx*)osPhysicalToVirtual(paddr);
+ len = 1;
+ dlPtr = vaddr;
+ while((*(s8*)dlPtr) != G_ENDDL)
+ {
+ len++;
+ dlPtr++;
+ }
+ len *= sizeof(Gfx);
+
+ cntlBlk.dataSize = len;
+ cntlBlk.dlType = GU_PARSE_GBI_TYPE;
+ cntlBlk.paddr = paddr;
+
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+ osWriteHost((u8*)vaddr,len);
+ if(param == G_DL_PUSH)
+ {
+ if(dlcount < 10)
+ dlcount++;
+ else
+ osSyncPrintf("Display lists nested too deep!!!\n");
+ }
+ dlStk[dlcount] = (Gfx*)vaddr;
+ break;
+ case G_VTX:
+ case G_MOVEMEM:
+ case G_MTX:
+ word0 = (u32*)curGfx; /* get ptr to first word */
+ word1 = word0 + 1; /* get pointer to second word */
+ seg = ((*word1) & 0x0f000000) >> 24; /* get the segment */
+ paddr = segments[seg] + ((*word1) & 0x00ffffff);
+ vaddr = (Gfx*)osPhysicalToVirtual(paddr);
+ len = (*word0) & 0x0000ffff;
+ cntlBlk.dataSize = len; /* always send 32 bytes, the most used */
+ cntlBlk.dlType = GU_PARSE_MEM_BLOCK;
+ cntlBlk.paddr = paddr;
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+ osWriteHost((u8*)vaddr,len);
+ break;
+
+ }
+ }
+
+ cntlBlk.dlType = GU_PARSE_READY;
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+}
+
+#endif
+
diff --git a/lib/ultralib/src/gu/parse_rdp.c b/lib/ultralib/src/gu/parse_rdp.c
new file mode 100644
index 0000000..c17c978
--- /dev/null
+++ b/lib/ultralib/src/gu/parse_rdp.c
@@ -0,0 +1,36 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1995, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ *************************************************************************/
+#include <ultra64.h>
+#include <ultrahost.h>
+#include <gu.h>
+
+/* guParseRdpDL works in conjunction with dlprint which must be running on
+ * the host Indy. guParseRdpDL simple uses the hostio routines to send the
+ * display list to the Indy, and dlprint does all the parsing.
+ */
+
+#ifndef _FINALROM
+void guParseRdpDL(u64 *rdp_dl, u64 nbytes, u8 flags)
+{
+ guDLPrintCB cntlBlk;
+
+ cntlBlk.dataSize = nbytes;
+ cntlBlk.flags = flags;
+ cntlBlk.dlType = GU_PARSE_RDP_TYPE;
+ cntlBlk.paddr = osVirtualToPhysical(rdp_dl);
+
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+ osWriteHost(rdp_dl,nbytes);
+
+}
+
+#endif
diff --git a/lib/ultralib/src/gu/parse_string.c b/lib/ultralib/src/gu/parse_string.c
new file mode 100644
index 0000000..71a58a8
--- /dev/null
+++ b/lib/ultralib/src/gu/parse_string.c
@@ -0,0 +1,35 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1995, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ *************************************************************************/
+#include <ultra64.h>
+#include <ultrahost.h>
+#include <gu.h>
+
+/* guParseString works in conjunction with dlprint which must be running on
+ * the host Indy. guParseString simply uses the hostio routines to send the
+ * string to the Indy, and dlprint does all the parsing.
+ */
+
+#ifndef _FINALROM
+void guParseString(char *StringPointer, u64 nbytes)
+{
+ guDLPrintCB cntlBlk;
+
+ cntlBlk.dataSize = nbytes /* /8 + ((nbytes%8) != 0) */;
+ cntlBlk.dlType = GU_PARSE_STRING_TYPE;
+ cntlBlk.paddr = osVirtualToPhysical((u64 *) StringPointer);
+
+ osWriteHost(&cntlBlk,sizeof(cntlBlk));
+ osWriteHost((u64 *) StringPointer,nbytes);
+
+}
+
+#endif
diff --git a/lib/ultralib/src/gu/perspective.c b/lib/ultralib/src/gu/perspective.c
new file mode 100644
index 0000000..be571d4
--- /dev/null
+++ b/lib/ultralib/src/gu/perspective.c
@@ -0,0 +1,58 @@
+
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+#include <ultratypes.h>
+
+void guPerspectiveF(float mf[4][4], u16 *perspNorm, float fovy, float aspect, float near, float far, float scale)
+{
+ float cot;
+ int i, j;
+
+ guMtxIdentF(mf);
+
+ fovy *= 3.1415926 / 180.0;
+ cot = cosf (fovy/2) / sinf (fovy/2);
+
+ mf[0][0] = cot / aspect;
+ mf[1][1] = cot;
+ mf[2][2] = (near + far) / (near - far);
+ mf[2][3] = -1;
+ mf[3][2] = (2 * near * far) / (near - far);
+ mf[3][3] = 0;
+
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++)
+ mf[i][j] *= scale;
+
+ if (perspNorm != (u16 *) NULL) {
+ if (near+far<=2.0) {
+ *perspNorm = (u16) 0xFFFF;
+ } else {
+ *perspNorm = (u16) ((2.0*65536.0)/(near+far));
+ if (*perspNorm<=0)
+ *perspNorm = (u16) 0x0001;
+ }
+ }
+}
+
+void guPerspective(Mtx *m, u16 *perspNorm, float fovy, float aspect, float near, float far, float scale)
+{
+ Matrix mf;
+
+ guPerspectiveF(mf, perspNorm, fovy, aspect, near, far, scale);
+
+ guMtxF2L(mf, m);
+}
+
+
diff --git a/lib/ultralib/src/gu/position.c b/lib/ultralib/src/gu/position.c
new file mode 100644
index 0000000..52cdd96
--- /dev/null
+++ b/lib/ultralib/src/gu/position.c
@@ -0,0 +1,73 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1995, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/*
+ * Return position matrix given roll, pitch, and yaw in degrees
+ * plus scale and position.
+ *
+ * r = roll (degrees)
+ * p = pitch (degrees)
+ * h = yaw (degrees)
+ * s = scale
+ * x,y,z = position (world coordinates)
+ *
+ */
+
+void guPositionF(float mf[4][4], float r, float p, float h, float s,
+ float x, float y, float z)
+{
+ static float dtor = 3.1415926 / 180.0;
+ float sinr, sinp, sinh;
+ float cosr, cosp, cosh;
+
+ r *= dtor;
+ p *= dtor;
+ h *= dtor;
+ sinr = sinf(r);
+ cosr = cosf(r);
+ sinp = sinf(p);
+ cosp = cosf(p);
+ sinh = sinf(h);
+ cosh = cosf(h);
+
+ mf[0][0] = (cosp*cosh) * s;
+ mf[0][1] = (cosp*sinh) * s;
+ mf[0][2] = (-sinp) * s;
+ mf[0][3] = 0.0;
+
+ mf[1][0] = (sinr*sinp*cosh - cosr*sinh) * s;
+ mf[1][1] = (sinr*sinp*sinh + cosr*cosh) * s;
+ mf[1][2] = (sinr*cosp) * s;
+ mf[1][3] = 0.0;
+
+ mf[2][0] = (cosr*sinp*cosh + sinr*sinh) * s;
+ mf[2][1] = (cosr*sinp*sinh - sinr*cosh) * s;
+ mf[2][2] = (cosr*cosp) * s;
+ mf[2][3] = 0.0;
+
+ mf[3][0] = x;
+ mf[3][1] = y;
+ mf[3][2] = z;
+ mf[3][3] = 1.0;
+}
+
+void guPosition(Mtx *m, float r, float p, float h, float s,
+ float x, float y, float z)
+{
+ float mf[4][4];
+
+ guPositionF(mf, r, p, h, s, x, y, z);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/poslight.c b/lib/ultralib/src/gu/poslight.c
new file mode 100644
index 0000000..389a04d
--- /dev/null
+++ b/lib/ultralib/src/gu/poslight.c
@@ -0,0 +1,69 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1995, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+
+/*
+ * define a positional light.
+ * this function must be called anytime the light or object moves.
+ *
+ * pl = (input) positional light description.
+ * l = (output) directiona light description for gSPLight or gSPSetLightsN.
+ * *Ob = position of (center of) object to be lit.
+ *
+ */
+#define THRESH1 0.01
+#define THRESH2 0.1
+void guPosLight(PositionalLight *pl, Light *l,
+ float xOb, float yOb, float zOb)
+{
+ float x,y,z,d,a;
+
+
+ x = pl->pos[0]-xOb;
+ y = pl->pos[1]-yOb;
+ z = pl->pos[2]-zOb;
+ d = sqrtf(x*x + y*y + z*z);
+
+ a = d*pl->a1 + pl->a2;
+ if (a<THRESH1)
+ a=100.0;
+ else
+ a = 1/a;
+
+ if (d<THRESH1) {
+ l->l.dir[0] = 0;
+ l->l.dir[1] = 0;
+ l->l.dir[2] = -120;
+
+ l->l.col[0] = 0;
+ l->l.col[1] = 0;
+ l->l.col[2] = 0;
+ l->l.colc[0] = 0;
+ l->l.colc[1] = 0;
+ l->l.colc[2] = 0;
+ } else {
+ d = 1/d;
+ l->l.dir[0] = 120.0*x*d;
+ l->l.dir[1] = 120.0*y*d;
+ l->l.dir[2] = 120.0*z*d;
+
+ l->l.col[0] = pl->col[0]*a;
+ l->l.col[1] = pl->col[1]*a;
+ l->l.col[2] = pl->col[2]*a;
+ l->l.colc[0] = pl->col[0]*a;
+ l->l.colc[1] = pl->col[1]*a;
+ l->l.colc[2] = pl->col[2]*a;
+ }
+
+}
diff --git a/lib/ultralib/src/gu/poslighthil.c b/lib/ultralib/src/gu/poslighthil.c
new file mode 100644
index 0000000..259fe8c
--- /dev/null
+++ b/lib/ultralib/src/gu/poslighthil.c
@@ -0,0 +1,168 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1995, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+
+/*
+ * define 2 positional lights with highlights.
+ * this function must be called anytime the viewpoint, light or object moves.
+ *
+ * pl1 = (input) positional light#1 description.
+ * pl2 = (input) positional light#2 description.
+ * l1 = (output) directional light desc. #1 for gSPLight or gSPSetLightsN.
+ * l2 = (output) directional light desc. #2 for gSPLight or gSPSetLightsN.
+ * *Eye = position of eye (viewpoint). (usually same as in LookAt command.)
+ * *Ob = position of (center of) object to be lit.
+ * *Ob = up vector (usually same as in LookAt command).
+ * twidth = width of texture map used for highlight.
+ * theight = height of texture map used for highlight.
+ *
+ */
+#define THRESH2 0.01
+#define THRESH3 0.1
+void guPosLightHilite(PositionalLight *pl1, PositionalLight *pl2,
+ Light *l1, Light *l2,
+ LookAt *l, Hilite *h,
+ float xEye, float yEye, float zEye,
+ float xOb, float yOb, float zOb,
+ float xUp, float yUp, float zUp,
+ int twidth, int theight) /* hilite txtr size*/
+{
+ float x,y,z,d,a;
+ Mtx m;
+
+
+/*
+ * light 1, diffuse
+ */
+ x = pl1->pos[0]-xOb;
+ y = pl1->pos[1]-yOb;
+ z = pl1->pos[2]-zOb;
+ d = sqrtf(x*x + y*y + z*z);
+
+ a=d*pl1->a1 + pl1->a2;
+ if (a<THRESH2)
+ a=100.0;
+ else
+ a = 1/a;
+
+ if (d<THRESH2) {
+ l1->l.dir[0] = 0;
+ l1->l.dir[1] = 0;
+ l1->l.dir[2] = -120;
+
+ l1->l.col[0] = 0;
+ l1->l.col[1] = 0;
+ l1->l.col[2] = 0;
+ l1->l.colc[0] = 0;
+ l1->l.colc[1] = 0;
+ l1->l.colc[2] = 0;
+ } else {
+ d = 1/d;
+ l1->l.dir[0] = 120.0*x*d;
+ l1->l.dir[1] = 120.0*y*d;
+ l1->l.dir[2] = 120.0*z*d;
+
+ l1->l.col[0] = pl1->col[0]*a;
+ l1->l.col[1] = pl1->col[1]*a;
+ l1->l.col[2] = pl1->col[2]*a;
+ l1->l.colc[0] = pl1->col[0]*a;
+ l1->l.colc[1] = pl1->col[1]*a;
+ l1->l.colc[2] = pl1->col[2]*a;
+ }
+
+
+/*
+ * light 2, diffuse
+ */
+ x = pl2->pos[0]-xOb;
+ y = pl2->pos[1]-yOb;
+ z = pl2->pos[2]-zOb;
+ d = sqrtf(x*x + y*y + z*z);
+
+ a = d*pl2->a1 + pl2->a2;
+ if (a<THRESH2)
+ a=100.0;
+ else
+ a = 1/a;
+
+ if (d<THRESH2) {
+ l2->l.dir[0] = 0;
+ l2->l.dir[1] = 0;
+ l2->l.dir[2] = -120;
+
+ l2->l.col[0] = 0;
+ l2->l.col[1] = 0;
+ l2->l.col[2] = 0;
+ l2->l.colc[0] = 0;
+ l2->l.colc[1] = 0;
+ l2->l.colc[2] = 0;
+ } else {
+ d = 1/d;
+ l2->l.dir[0] = 120.0*x*d;
+ l2->l.dir[1] = 120.0*y*d;
+ l2->l.dir[2] = 120.0*z*d;
+
+ l2->l.col[0] = pl2->col[0]*a;
+ l2->l.col[1] = pl2->col[1]*a;
+ l2->l.col[2] = pl2->col[2]*a;
+ l2->l.colc[0] = pl2->col[0]*a;
+ l2->l.colc[1] = pl2->col[1]*a;
+ l2->l.colc[2] = pl2->col[2]*a;
+ }
+
+
+/*
+ * Hilight factors
+ */
+ x = xOb-xEye;
+ y = yOb-yEye;
+ z = zOb-zEye;
+ if (sqrtf(x*x + y*y + z*z)<THRESH3) {
+ h->h.x1 = twidth*2;
+ h->h.y1 = twidth*2;
+ h->h.x2 = twidth*2;
+ h->h.y2 = twidth*2;
+ l->l[0].l.dir[0] = 0;
+ l->l[0].l.dir[1] = 0;
+ l->l[0].l.dir[2] = 0;
+ l->l[1].l.dir[0] = 0;
+ l->l[1].l.dir[1] = 0;
+ l->l[1].l.dir[2] = 0;
+ l->l[0].l.col[0] = 0x00;
+ l->l[0].l.col[1] = 0x00;
+ l->l[0].l.col[2] = 0x00;
+ l->l[0].l.pad1 = 0x00;
+ l->l[0].l.colc[0] = 0x00;
+ l->l[0].l.colc[1] = 0x00;
+ l->l[0].l.colc[2] = 0x00;
+ l->l[0].l.pad2 = 0x00;
+ l->l[1].l.col[0] = 0x00;
+ l->l[1].l.col[1] = 0x80;
+ l->l[1].l.col[2] = 0x00;
+ l->l[1].l.pad1 = 0x00;
+ l->l[1].l.colc[0] = 0x00;
+ l->l[1].l.colc[1] = 0x80;
+ l->l[1].l.colc[2] = 0x00;
+ l->l[1].l.pad2 = 0x00;
+ } else {
+ guLookAtHilite(&m, l, h,
+ xEye, yEye, zEye,
+ xOb, yOb, zOb,
+ xUp, yUp, zUp,
+ l1->l.dir[0], l1->l.dir[1], l1->l.dir[2],
+ l2->l.dir[0], l2->l.dir[1], l2->l.dir[2],
+ twidth, theight);
+ }
+}
+
diff --git a/lib/ultralib/src/gu/random.c b/lib/ultralib/src/gu/random.c
new file mode 100644
index 0000000..32cfde3
--- /dev/null
+++ b/lib/ultralib/src/gu/random.c
@@ -0,0 +1,33 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1995, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/*
+ * Return a pseudorandom 32 bit number
+ * try the RAND macro too
+ *
+ */
+int guRandom(void)
+{
+ static unsigned int xseed = 174823885;
+ unsigned int x;
+
+ x = (xseed<<2) + 2;
+
+ x *= (x+1);
+ x = x >> 2;
+
+ xseed = x;
+
+ return( x );
+}
diff --git a/lib/ultralib/src/gu/readme.txt b/lib/ultralib/src/gu/readme.txt
new file mode 100644
index 0000000..114174e
--- /dev/null
+++ b/lib/ultralib/src/gu/readme.txt
@@ -0,0 +1,17 @@
+Among the gu Functions, the following were replaced with the newly
+created high speed versions. With the current version OS they are
+not being used.
+
+guMtxIdent
+guMtxIdentF
+guScale
+guScaleF
+guNormalize
+guTranslate
+guTranslateF
+guMtxF2L
+guRotateF
+guMtxL2F
+guMtxCatF
+
+The newly created functions are installed in the mgu directory.
diff --git a/lib/ultralib/src/gu/rotate.c b/lib/ultralib/src/gu/rotate.c
new file mode 100644
index 0000000..eceb096
--- /dev/null
+++ b/lib/ultralib/src/gu/rotate.c
@@ -0,0 +1,63 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+void guRotateF(float mf[4][4], float a, float x, float y, float z)
+{
+ static float dtor = 3.1415926 / 180.0;
+ float sine;
+ float cosine;
+ float ab, bc, ca, t;
+ float xxsine;
+ float yxsine;
+ float zxsine;
+
+ guNormalize(&x, &y, &z);
+ a *= dtor;
+ sine = sinf(a);
+ cosine = cosf(a);
+ t = (1-cosine);
+ ab = x*y*t;
+ bc = y*z*t;
+ ca = z*x*t;
+
+ guMtxIdentF(mf);
+
+ xxsine = x * sine;
+ yxsine = y * sine;
+ zxsine = z * sine;
+
+ t = x*x;
+ mf[0][0] = t+cosine*(1-t);
+ mf[2][1] = bc-xxsine;
+ mf[1][2] = bc+xxsine;
+
+ t = y*y;
+ mf[1][1] = t+cosine*(1-t);
+ mf[2][0] = ca+yxsine;
+ mf[0][2] = ca-yxsine;
+
+ t = z*z;
+ mf[2][2] = t+cosine*(1-t);
+ mf[1][0] = ab-zxsine;
+ mf[0][1] = ab+zxsine;
+}
+
+void guRotate(Mtx *m, float a, float x, float y, float z)
+{
+ Matrix mf;
+
+ guRotateF(mf, a, x, y, z);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/rotaterpy.c b/lib/ultralib/src/gu/rotaterpy.c
new file mode 100644
index 0000000..c239d21
--- /dev/null
+++ b/lib/ultralib/src/gu/rotaterpy.c
@@ -0,0 +1,58 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/*
+ * Return rotation matrix given roll, pitch, and yaw in degrees
+ *
+ */
+
+void guRotateRPYF(float mf[4][4], float r, float p, float h)
+{
+ static float dtor = 3.1415926 / 180.0;
+ float sinr, sinp, sinh;
+ float cosr, cosp, cosh;
+
+ r *= dtor;
+ p *= dtor;
+ h *= dtor;
+ sinr = sinf(r);
+ cosr = cosf(r);
+ sinp = sinf(p);
+ cosp = cosf(p);
+ sinh = sinf(h);
+ cosh = cosf(h);
+
+ guMtxIdentF(mf);
+
+ mf[0][0] = cosp*cosh;
+ mf[0][1] = cosp*sinh;
+ mf[0][2] = -sinp;
+
+ mf[1][0] = sinr*sinp*cosh - cosr*sinh;
+ mf[1][1] = sinr*sinp*sinh + cosr*cosh;
+ mf[1][2] = sinr*cosp;
+
+ mf[2][0] = cosr*sinp*cosh + sinr*sinh;
+ mf[2][1] = cosr*sinp*sinh - sinr*cosh;
+ mf[2][2] = cosr*cosp;
+}
+
+void guRotateRPY(Mtx *m, float r, float p, float h)
+{
+ Matrix mf;
+
+ guRotateRPYF(mf, r, p, h);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/gu/sinf.c b/lib/ultralib/src/gu/sinf.c
new file mode 100644
index 0000000..f4bb1ad
--- /dev/null
+++ b/lib/ultralib/src/gu/sinf.c
@@ -0,0 +1,157 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/* ====================================================================
+ * ====================================================================
+ *
+ * Module: fsin.c
+ * $Revision: 1.3 $
+ * $Date: 1998/10/09 06:14:51 $
+ * $Author: has $
+ * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/libultra/monegi/gu/sinf.c,v $
+ *
+ * Revision history:
+ * 09-Jun-93 - Original Version
+ *
+ * Description: source code for fsin function
+ *
+ * ====================================================================
+ * ====================================================================
+ */
+
+#pragma weak fsin = __sinf
+#pragma weak sinf = __sinf
+#define fsin __sinf
+
+/* coefficients for polynomial approximation of sin on +/- pi/2 */
+
+static const du P[] =
+{
+{0x3ff00000, 0x00000000},
+{0xbfc55554, 0xbc83656d},
+{0x3f8110ed, 0x3804c2a0},
+{0xbf29f6ff, 0xeea56814},
+{0x3ec5dbdf, 0x0e314bfe},
+};
+
+static const du rpi =
+{0x3fd45f30, 0x6dc9c883};
+
+static const du pihi =
+{0x400921fb, 0x50000000};
+
+static const du pilo =
+{0x3e6110b4, 0x611a6263};
+
+static const fu zero = {0x00000000};
+
+
+/* ====================================================================
+ *
+ * FunctionName fsin
+ *
+ * Description computes sine of arg
+ *
+ * ====================================================================
+ */
+
+float
+fsin( float x )
+{
+double dx, xsq, poly;
+double dn;
+int n;
+double result;
+int ix, xpt;
+
+
+ ix = *(int *)&x;
+ xpt = (ix >> 22);
+ xpt &= 0x1ff;
+
+ /* xpt is exponent(x) + 1 bit of mantissa */
+
+ if ( xpt < 0xff )
+ {
+ /* |x| < 1.5 */
+
+ dx = x;
+
+ if ( xpt >= 0xe6 )
+ {
+ /* |x| >= 2^(-12) */
+
+ /* compute sin(x) with a standard polynomial approximation */
+
+ xsq = dx*dx;
+
+ poly = ((P[4].d*xsq + P[3].d)*xsq + P[2].d)*xsq + P[1].d;
+
+ result = dx + (dx*xsq)*poly;
+
+ return ( (float)result );
+ }
+
+ return ( x );
+ }
+
+ if ( xpt < 0x136 )
+ {
+ /* |x| < 2^28 */
+
+ dx = x;
+
+ /* reduce argument to +/- pi/2 */
+
+ dn = dx*rpi.d;
+
+ n = ROUND(dn);
+ dn = n;
+
+ dx = dx - dn*pihi.d;
+ dx = dx - dn*pilo.d; /* dx = x - n*pi */
+
+ /* compute sin(dx) as before, negating result if n is odd
+ */
+
+ xsq = dx*dx;
+
+ poly = ((P[4].d*xsq + P[3].d)*xsq + P[2].d)*xsq + P[1].d;
+
+ result = dx + (dx*xsq)*poly;
+
+
+ if ( (n & 1) == 0 )
+ return ( (float)result );
+
+ return ( -(float)result );
+ }
+
+ if ( x != x )
+ {
+ /* x is a NaN; return a quiet NaN */
+
+#ifdef _IP_NAN_SETS_ERRNO
+
+ *__errnoaddr = EDOM;
+#endif
+
+ return ( __libm_qnan_f );
+ }
+
+ /* just give up and return 0.0 */
+
+ return ( zero.f );
+}
+
diff --git a/lib/ultralib/src/gu/sins.c b/lib/ultralib/src/gu/sins.c
new file mode 100644
index 0000000..b24851f
--- /dev/null
+++ b/lib/ultralib/src/gu/sins.c
@@ -0,0 +1,61 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "guint.h"
+
+/* ====================================================================
+ * ====================================================================
+ *
+ * Module: sins.c
+ * $Revision: 1.3 $
+ * $Date: 1998/10/09 06:15:00 $
+ * $Author: has $
+ * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/libultra/monegi/gu/sins.c,v $
+ *
+ * ====================================================================
+ * ====================================================================
+ */
+
+/* coefficients for polynomial approximation of sin on +/- pi/2 */
+
+/* ====================================================================
+ *
+ * FunctionName sins
+ *
+ * Description computes sine of arg
+ *
+ * ====================================================================
+ */
+
+#include "sintable.h"
+
+signed short
+sins( unsigned short x )
+{
+ /* 0 <= x < 0x10000 ==> 0 <= x < 2PI */
+
+ signed short val;
+
+ x >>= 4; /* Now range 0 <= x < 0x1000 */
+
+ if (x & 0x400) {
+ val = sintable[0x3ff - (x & 0x3ff)];
+ } else {
+ val = sintable[x & 0x3ff];
+ }
+
+ if (x & 0x800) {
+ return -val;
+ } else {
+ return val;
+ }
+}
diff --git a/lib/ultralib/src/gu/sintable.h b/lib/ultralib/src/gu/sintable.h
new file mode 100644
index 0000000..b5e1a45
--- /dev/null
+++ b/lib/ultralib/src/gu/sintable.h
@@ -0,0 +1,1031 @@
+
+/*
+ * Do not edit this file -- it was generated by "maketable".
+ */
+
+static signed short sintable[0x400] = {
+ 0x0000,
+ 0x0032,
+ 0x0064,
+ 0x0096,
+ 0x00c9,
+ 0x00fb,
+ 0x012d,
+ 0x0160,
+ 0x0192,
+ 0x01c4,
+ 0x01f7,
+ 0x0229,
+ 0x025b,
+ 0x028e,
+ 0x02c0,
+ 0x02f2,
+ 0x0324,
+ 0x0357,
+ 0x0389,
+ 0x03bb,
+ 0x03ee,
+ 0x0420,
+ 0x0452,
+ 0x0484,
+ 0x04b7,
+ 0x04e9,
+ 0x051b,
+ 0x054e,
+ 0x0580,
+ 0x05b2,
+ 0x05e4,
+ 0x0617,
+ 0x0649,
+ 0x067b,
+ 0x06ad,
+ 0x06e0,
+ 0x0712,
+ 0x0744,
+ 0x0776,
+ 0x07a9,
+ 0x07db,
+ 0x080d,
+ 0x083f,
+ 0x0871,
+ 0x08a4,
+ 0x08d6,
+ 0x0908,
+ 0x093a,
+ 0x096c,
+ 0x099f,
+ 0x09d1,
+ 0x0a03,
+ 0x0a35,
+ 0x0a67,
+ 0x0a99,
+ 0x0acb,
+ 0x0afe,
+ 0x0b30,
+ 0x0b62,
+ 0x0b94,
+ 0x0bc6,
+ 0x0bf8,
+ 0x0c2a,
+ 0x0c5c,
+ 0x0c8e,
+ 0x0cc0,
+ 0x0cf2,
+ 0x0d25,
+ 0x0d57,
+ 0x0d89,
+ 0x0dbb,
+ 0x0ded,
+ 0x0e1f,
+ 0x0e51,
+ 0x0e83,
+ 0x0eb5,
+ 0x0ee7,
+ 0x0f19,
+ 0x0f4b,
+ 0x0f7c,
+ 0x0fae,
+ 0x0fe0,
+ 0x1012,
+ 0x1044,
+ 0x1076,
+ 0x10a8,
+ 0x10da,
+ 0x110c,
+ 0x113e,
+ 0x116f,
+ 0x11a1,
+ 0x11d3,
+ 0x1205,
+ 0x1237,
+ 0x1269,
+ 0x129a,
+ 0x12cc,
+ 0x12fe,
+ 0x1330,
+ 0x1361,
+ 0x1393,
+ 0x13c5,
+ 0x13f6,
+ 0x1428,
+ 0x145a,
+ 0x148c,
+ 0x14bd,
+ 0x14ef,
+ 0x1520,
+ 0x1552,
+ 0x1584,
+ 0x15b5,
+ 0x15e7,
+ 0x1618,
+ 0x164a,
+ 0x167b,
+ 0x16ad,
+ 0x16df,
+ 0x1710,
+ 0x1741,
+ 0x1773,
+ 0x17a4,
+ 0x17d6,
+ 0x1807,
+ 0x1839,
+ 0x186a,
+ 0x189b,
+ 0x18cd,
+ 0x18fe,
+ 0x1930,
+ 0x1961,
+ 0x1992,
+ 0x19c3,
+ 0x19f5,
+ 0x1a26,
+ 0x1a57,
+ 0x1a88,
+ 0x1aba,
+ 0x1aeb,
+ 0x1b1c,
+ 0x1b4d,
+ 0x1b7e,
+ 0x1baf,
+ 0x1be1,
+ 0x1c12,
+ 0x1c43,
+ 0x1c74,
+ 0x1ca5,
+ 0x1cd6,
+ 0x1d07,
+ 0x1d38,
+ 0x1d69,
+ 0x1d9a,
+ 0x1dcb,
+ 0x1dfc,
+ 0x1e2d,
+ 0x1e5d,
+ 0x1e8e,
+ 0x1ebf,
+ 0x1ef0,
+ 0x1f21,
+ 0x1f52,
+ 0x1f82,
+ 0x1fb3,
+ 0x1fe4,
+ 0x2015,
+ 0x2045,
+ 0x2076,
+ 0x20a7,
+ 0x20d7,
+ 0x2108,
+ 0x2139,
+ 0x2169,
+ 0x219a,
+ 0x21ca,
+ 0x21fb,
+ 0x222b,
+ 0x225c,
+ 0x228c,
+ 0x22bd,
+ 0x22ed,
+ 0x231d,
+ 0x234e,
+ 0x237e,
+ 0x23ae,
+ 0x23df,
+ 0x240f,
+ 0x243f,
+ 0x2470,
+ 0x24a0,
+ 0x24d0,
+ 0x2500,
+ 0x2530,
+ 0x2560,
+ 0x2591,
+ 0x25c1,
+ 0x25f1,
+ 0x2621,
+ 0x2651,
+ 0x2681,
+ 0x26b1,
+ 0x26e1,
+ 0x2711,
+ 0x2740,
+ 0x2770,
+ 0x27a0,
+ 0x27d0,
+ 0x2800,
+ 0x2830,
+ 0x285f,
+ 0x288f,
+ 0x28bf,
+ 0x28ee,
+ 0x291e,
+ 0x294e,
+ 0x297d,
+ 0x29ad,
+ 0x29dd,
+ 0x2a0c,
+ 0x2a3c,
+ 0x2a6b,
+ 0x2a9b,
+ 0x2aca,
+ 0x2af9,
+ 0x2b29,
+ 0x2b58,
+ 0x2b87,
+ 0x2bb7,
+ 0x2be6,
+ 0x2c15,
+ 0x2c44,
+ 0x2c74,
+ 0x2ca3,
+ 0x2cd2,
+ 0x2d01,
+ 0x2d30,
+ 0x2d5f,
+ 0x2d8e,
+ 0x2dbd,
+ 0x2dec,
+ 0x2e1b,
+ 0x2e4a,
+ 0x2e79,
+ 0x2ea8,
+ 0x2ed7,
+ 0x2f06,
+ 0x2f34,
+ 0x2f63,
+ 0x2f92,
+ 0x2fc0,
+ 0x2fef,
+ 0x301e,
+ 0x304c,
+ 0x307b,
+ 0x30a9,
+ 0x30d8,
+ 0x3107,
+ 0x3135,
+ 0x3163,
+ 0x3192,
+ 0x31c0,
+ 0x31ef,
+ 0x321d,
+ 0x324b,
+ 0x3279,
+ 0x32a8,
+ 0x32d6,
+ 0x3304,
+ 0x3332,
+ 0x3360,
+ 0x338e,
+ 0x33bc,
+ 0x33ea,
+ 0x3418,
+ 0x3446,
+ 0x3474,
+ 0x34a2,
+ 0x34d0,
+ 0x34fe,
+ 0x352b,
+ 0x3559,
+ 0x3587,
+ 0x35b5,
+ 0x35e2,
+ 0x3610,
+ 0x363d,
+ 0x366b,
+ 0x3698,
+ 0x36c6,
+ 0x36f3,
+ 0x3721,
+ 0x374e,
+ 0x377c,
+ 0x37a9,
+ 0x37d6,
+ 0x3803,
+ 0x3831,
+ 0x385e,
+ 0x388b,
+ 0x38b8,
+ 0x38e5,
+ 0x3912,
+ 0x393f,
+ 0x396c,
+ 0x3999,
+ 0x39c6,
+ 0x39f3,
+ 0x3a20,
+ 0x3a4d,
+ 0x3a79,
+ 0x3aa6,
+ 0x3ad3,
+ 0x3b00,
+ 0x3b2c,
+ 0x3b59,
+ 0x3b85,
+ 0x3bb2,
+ 0x3bde,
+ 0x3c0b,
+ 0x3c37,
+ 0x3c64,
+ 0x3c90,
+ 0x3cbc,
+ 0x3ce9,
+ 0x3d15,
+ 0x3d41,
+ 0x3d6d,
+ 0x3d99,
+ 0x3dc5,
+ 0x3df1,
+ 0x3e1d,
+ 0x3e49,
+ 0x3e75,
+ 0x3ea1,
+ 0x3ecd,
+ 0x3ef9,
+ 0x3f25,
+ 0x3f50,
+ 0x3f7c,
+ 0x3fa8,
+ 0x3fd3,
+ 0x3fff,
+ 0x402b,
+ 0x4056,
+ 0x4082,
+ 0x40ad,
+ 0x40d8,
+ 0x4104,
+ 0x412f,
+ 0x415a,
+ 0x4186,
+ 0x41b1,
+ 0x41dc,
+ 0x4207,
+ 0x4232,
+ 0x425d,
+ 0x4288,
+ 0x42b3,
+ 0x42de,
+ 0x4309,
+ 0x4334,
+ 0x435f,
+ 0x4389,
+ 0x43b4,
+ 0x43df,
+ 0x4409,
+ 0x4434,
+ 0x445f,
+ 0x4489,
+ 0x44b4,
+ 0x44de,
+ 0x4508,
+ 0x4533,
+ 0x455d,
+ 0x4587,
+ 0x45b1,
+ 0x45dc,
+ 0x4606,
+ 0x4630,
+ 0x465a,
+ 0x4684,
+ 0x46ae,
+ 0x46d8,
+ 0x4702,
+ 0x472c,
+ 0x4755,
+ 0x477f,
+ 0x47a9,
+ 0x47d2,
+ 0x47fc,
+ 0x4826,
+ 0x484f,
+ 0x4879,
+ 0x48a2,
+ 0x48cc,
+ 0x48f5,
+ 0x491e,
+ 0x4948,
+ 0x4971,
+ 0x499a,
+ 0x49c3,
+ 0x49ec,
+ 0x4a15,
+ 0x4a3e,
+ 0x4a67,
+ 0x4a90,
+ 0x4ab9,
+ 0x4ae2,
+ 0x4b0b,
+ 0x4b33,
+ 0x4b5c,
+ 0x4b85,
+ 0x4bad,
+ 0x4bd6,
+ 0x4bfe,
+ 0x4c27,
+ 0x4c4f,
+ 0x4c78,
+ 0x4ca0,
+ 0x4cc8,
+ 0x4cf0,
+ 0x4d19,
+ 0x4d41,
+ 0x4d69,
+ 0x4d91,
+ 0x4db9,
+ 0x4de1,
+ 0x4e09,
+ 0x4e31,
+ 0x4e58,
+ 0x4e80,
+ 0x4ea8,
+ 0x4ed0,
+ 0x4ef7,
+ 0x4f1f,
+ 0x4f46,
+ 0x4f6e,
+ 0x4f95,
+ 0x4fbd,
+ 0x4fe4,
+ 0x500b,
+ 0x5032,
+ 0x505a,
+ 0x5081,
+ 0x50a8,
+ 0x50cf,
+ 0x50f6,
+ 0x511d,
+ 0x5144,
+ 0x516b,
+ 0x5191,
+ 0x51b8,
+ 0x51df,
+ 0x5205,
+ 0x522c,
+ 0x5253,
+ 0x5279,
+ 0x52a0,
+ 0x52c6,
+ 0x52ec,
+ 0x5313,
+ 0x5339,
+ 0x535f,
+ 0x5385,
+ 0x53ab,
+ 0x53d1,
+ 0x53f7,
+ 0x541d,
+ 0x5443,
+ 0x5469,
+ 0x548f,
+ 0x54b5,
+ 0x54da,
+ 0x5500,
+ 0x5525,
+ 0x554b,
+ 0x5571,
+ 0x5596,
+ 0x55bb,
+ 0x55e1,
+ 0x5606,
+ 0x562b,
+ 0x5650,
+ 0x5675,
+ 0x569b,
+ 0x56c0,
+ 0x56e5,
+ 0x5709,
+ 0x572e,
+ 0x5753,
+ 0x5778,
+ 0x579d,
+ 0x57c1,
+ 0x57e6,
+ 0x580a,
+ 0x582f,
+ 0x5853,
+ 0x5878,
+ 0x589c,
+ 0x58c0,
+ 0x58e5,
+ 0x5909,
+ 0x592d,
+ 0x5951,
+ 0x5975,
+ 0x5999,
+ 0x59bd,
+ 0x59e1,
+ 0x5a04,
+ 0x5a28,
+ 0x5a4c,
+ 0x5a6f,
+ 0x5a93,
+ 0x5ab7,
+ 0x5ada,
+ 0x5afd,
+ 0x5b21,
+ 0x5b44,
+ 0x5b67,
+ 0x5b8b,
+ 0x5bae,
+ 0x5bd1,
+ 0x5bf4,
+ 0x5c17,
+ 0x5c3a,
+ 0x5c5d,
+ 0x5c7f,
+ 0x5ca2,
+ 0x5cc5,
+ 0x5ce7,
+ 0x5d0a,
+ 0x5d2d,
+ 0x5d4f,
+ 0x5d71,
+ 0x5d94,
+ 0x5db6,
+ 0x5dd8,
+ 0x5dfa,
+ 0x5e1d,
+ 0x5e3f,
+ 0x5e61,
+ 0x5e83,
+ 0x5ea5,
+ 0x5ec6,
+ 0x5ee8,
+ 0x5f0a,
+ 0x5f2c,
+ 0x5f4d,
+ 0x5f6f,
+ 0x5f90,
+ 0x5fb2,
+ 0x5fd3,
+ 0x5ff4,
+ 0x6016,
+ 0x6037,
+ 0x6058,
+ 0x6079,
+ 0x609a,
+ 0x60bb,
+ 0x60dc,
+ 0x60fd,
+ 0x611e,
+ 0x613e,
+ 0x615f,
+ 0x6180,
+ 0x61a0,
+ 0x61c1,
+ 0x61e1,
+ 0x6202,
+ 0x6222,
+ 0x6242,
+ 0x6263,
+ 0x6283,
+ 0x62a3,
+ 0x62c3,
+ 0x62e3,
+ 0x6303,
+ 0x6323,
+ 0x6342,
+ 0x6362,
+ 0x6382,
+ 0x63a1,
+ 0x63c1,
+ 0x63e0,
+ 0x6400,
+ 0x641f,
+ 0x643f,
+ 0x645e,
+ 0x647d,
+ 0x649c,
+ 0x64bb,
+ 0x64da,
+ 0x64f9,
+ 0x6518,
+ 0x6537,
+ 0x6556,
+ 0x6574,
+ 0x6593,
+ 0x65b2,
+ 0x65d0,
+ 0x65ef,
+ 0x660d,
+ 0x662b,
+ 0x664a,
+ 0x6668,
+ 0x6686,
+ 0x66a4,
+ 0x66c2,
+ 0x66e0,
+ 0x66fe,
+ 0x671c,
+ 0x673a,
+ 0x6757,
+ 0x6775,
+ 0x6792,
+ 0x67b0,
+ 0x67cd,
+ 0x67eb,
+ 0x6808,
+ 0x6825,
+ 0x6843,
+ 0x6860,
+ 0x687d,
+ 0x689a,
+ 0x68b7,
+ 0x68d4,
+ 0x68f1,
+ 0x690d,
+ 0x692a,
+ 0x6947,
+ 0x6963,
+ 0x6980,
+ 0x699c,
+ 0x69b9,
+ 0x69d5,
+ 0x69f1,
+ 0x6a0e,
+ 0x6a2a,
+ 0x6a46,
+ 0x6a62,
+ 0x6a7e,
+ 0x6a9a,
+ 0x6ab5,
+ 0x6ad1,
+ 0x6aed,
+ 0x6b08,
+ 0x6b24,
+ 0x6b40,
+ 0x6b5b,
+ 0x6b76,
+ 0x6b92,
+ 0x6bad,
+ 0x6bc8,
+ 0x6be3,
+ 0x6bfe,
+ 0x6c19,
+ 0x6c34,
+ 0x6c4f,
+ 0x6c6a,
+ 0x6c84,
+ 0x6c9f,
+ 0x6cba,
+ 0x6cd4,
+ 0x6cef,
+ 0x6d09,
+ 0x6d23,
+ 0x6d3e,
+ 0x6d58,
+ 0x6d72,
+ 0x6d8c,
+ 0x6da6,
+ 0x6dc0,
+ 0x6dda,
+ 0x6df3,
+ 0x6e0d,
+ 0x6e27,
+ 0x6e40,
+ 0x6e5a,
+ 0x6e73,
+ 0x6e8d,
+ 0x6ea6,
+ 0x6ebf,
+ 0x6ed9,
+ 0x6ef2,
+ 0x6f0b,
+ 0x6f24,
+ 0x6f3d,
+ 0x6f55,
+ 0x6f6e,
+ 0x6f87,
+ 0x6fa0,
+ 0x6fb8,
+ 0x6fd1,
+ 0x6fe9,
+ 0x7002,
+ 0x701a,
+ 0x7032,
+ 0x704a,
+ 0x7062,
+ 0x707a,
+ 0x7092,
+ 0x70aa,
+ 0x70c2,
+ 0x70da,
+ 0x70f2,
+ 0x7109,
+ 0x7121,
+ 0x7138,
+ 0x7150,
+ 0x7167,
+ 0x717e,
+ 0x7196,
+ 0x71ad,
+ 0x71c4,
+ 0x71db,
+ 0x71f2,
+ 0x7209,
+ 0x7220,
+ 0x7236,
+ 0x724d,
+ 0x7264,
+ 0x727a,
+ 0x7291,
+ 0x72a7,
+ 0x72bd,
+ 0x72d4,
+ 0x72ea,
+ 0x7300,
+ 0x7316,
+ 0x732c,
+ 0x7342,
+ 0x7358,
+ 0x736e,
+ 0x7383,
+ 0x7399,
+ 0x73ae,
+ 0x73c4,
+ 0x73d9,
+ 0x73ef,
+ 0x7404,
+ 0x7419,
+ 0x742e,
+ 0x7443,
+ 0x7458,
+ 0x746d,
+ 0x7482,
+ 0x7497,
+ 0x74ac,
+ 0x74c0,
+ 0x74d5,
+ 0x74ea,
+ 0x74fe,
+ 0x7512,
+ 0x7527,
+ 0x753b,
+ 0x754f,
+ 0x7563,
+ 0x7577,
+ 0x758b,
+ 0x759f,
+ 0x75b3,
+ 0x75c7,
+ 0x75da,
+ 0x75ee,
+ 0x7601,
+ 0x7615,
+ 0x7628,
+ 0x763b,
+ 0x764f,
+ 0x7662,
+ 0x7675,
+ 0x7688,
+ 0x769b,
+ 0x76ae,
+ 0x76c1,
+ 0x76d3,
+ 0x76e6,
+ 0x76f9,
+ 0x770b,
+ 0x771e,
+ 0x7730,
+ 0x7742,
+ 0x7754,
+ 0x7767,
+ 0x7779,
+ 0x778b,
+ 0x779d,
+ 0x77af,
+ 0x77c0,
+ 0x77d2,
+ 0x77e4,
+ 0x77f5,
+ 0x7807,
+ 0x7818,
+ 0x782a,
+ 0x783b,
+ 0x784c,
+ 0x785d,
+ 0x786e,
+ 0x787f,
+ 0x7890,
+ 0x78a1,
+ 0x78b2,
+ 0x78c3,
+ 0x78d3,
+ 0x78e4,
+ 0x78f4,
+ 0x7905,
+ 0x7915,
+ 0x7925,
+ 0x7936,
+ 0x7946,
+ 0x7956,
+ 0x7966,
+ 0x7976,
+ 0x7985,
+ 0x7995,
+ 0x79a5,
+ 0x79b5,
+ 0x79c4,
+ 0x79d4,
+ 0x79e3,
+ 0x79f2,
+ 0x7a02,
+ 0x7a11,
+ 0x7a20,
+ 0x7a2f,
+ 0x7a3e,
+ 0x7a4d,
+ 0x7a5b,
+ 0x7a6a,
+ 0x7a79,
+ 0x7a87,
+ 0x7a96,
+ 0x7aa4,
+ 0x7ab3,
+ 0x7ac1,
+ 0x7acf,
+ 0x7add,
+ 0x7aeb,
+ 0x7af9,
+ 0x7b07,
+ 0x7b15,
+ 0x7b23,
+ 0x7b31,
+ 0x7b3e,
+ 0x7b4c,
+ 0x7b59,
+ 0x7b67,
+ 0x7b74,
+ 0x7b81,
+ 0x7b8e,
+ 0x7b9b,
+ 0x7ba8,
+ 0x7bb5,
+ 0x7bc2,
+ 0x7bcf,
+ 0x7bdc,
+ 0x7be8,
+ 0x7bf5,
+ 0x7c02,
+ 0x7c0e,
+ 0x7c1a,
+ 0x7c27,
+ 0x7c33,
+ 0x7c3f,
+ 0x7c4b,
+ 0x7c57,
+ 0x7c63,
+ 0x7c6f,
+ 0x7c7a,
+ 0x7c86,
+ 0x7c92,
+ 0x7c9d,
+ 0x7ca9,
+ 0x7cb4,
+ 0x7cbf,
+ 0x7ccb,
+ 0x7cd6,
+ 0x7ce1,
+ 0x7cec,
+ 0x7cf7,
+ 0x7d02,
+ 0x7d0c,
+ 0x7d17,
+ 0x7d22,
+ 0x7d2c,
+ 0x7d37,
+ 0x7d41,
+ 0x7d4b,
+ 0x7d56,
+ 0x7d60,
+ 0x7d6a,
+ 0x7d74,
+ 0x7d7e,
+ 0x7d88,
+ 0x7d91,
+ 0x7d9b,
+ 0x7da5,
+ 0x7dae,
+ 0x7db8,
+ 0x7dc1,
+ 0x7dcb,
+ 0x7dd4,
+ 0x7ddd,
+ 0x7de6,
+ 0x7def,
+ 0x7df8,
+ 0x7e01,
+ 0x7e0a,
+ 0x7e13,
+ 0x7e1b,
+ 0x7e24,
+ 0x7e2c,
+ 0x7e35,
+ 0x7e3d,
+ 0x7e45,
+ 0x7e4d,
+ 0x7e56,
+ 0x7e5e,
+ 0x7e66,
+ 0x7e6d,
+ 0x7e75,
+ 0x7e7d,
+ 0x7e85,
+ 0x7e8c,
+ 0x7e94,
+ 0x7e9b,
+ 0x7ea3,
+ 0x7eaa,
+ 0x7eb1,
+ 0x7eb8,
+ 0x7ebf,
+ 0x7ec6,
+ 0x7ecd,
+ 0x7ed4,
+ 0x7edb,
+ 0x7ee1,
+ 0x7ee8,
+ 0x7eee,
+ 0x7ef5,
+ 0x7efb,
+ 0x7f01,
+ 0x7f08,
+ 0x7f0e,
+ 0x7f14,
+ 0x7f1a,
+ 0x7f20,
+ 0x7f25,
+ 0x7f2b,
+ 0x7f31,
+ 0x7f36,
+ 0x7f3c,
+ 0x7f41,
+ 0x7f47,
+ 0x7f4c,
+ 0x7f51,
+ 0x7f56,
+ 0x7f5b,
+ 0x7f60,
+ 0x7f65,
+ 0x7f6a,
+ 0x7f6f,
+ 0x7f74,
+ 0x7f78,
+ 0x7f7d,
+ 0x7f81,
+ 0x7f85,
+ 0x7f8a,
+ 0x7f8e,
+ 0x7f92,
+ 0x7f96,
+ 0x7f9a,
+ 0x7f9e,
+ 0x7fa2,
+ 0x7fa6,
+ 0x7fa9,
+ 0x7fad,
+ 0x7fb0,
+ 0x7fb4,
+ 0x7fb7,
+ 0x7fba,
+ 0x7fbe,
+ 0x7fc1,
+ 0x7fc4,
+ 0x7fc7,
+ 0x7fca,
+ 0x7fcc,
+ 0x7fcf,
+ 0x7fd2,
+ 0x7fd4,
+ 0x7fd7,
+ 0x7fd9,
+ 0x7fdc,
+ 0x7fde,
+ 0x7fe0,
+ 0x7fe2,
+ 0x7fe4,
+ 0x7fe6,
+ 0x7fe8,
+ 0x7fea,
+ 0x7fec,
+ 0x7fed,
+ 0x7fef,
+ 0x7ff1,
+ 0x7ff2,
+ 0x7ff3,
+ 0x7ff5,
+ 0x7ff6,
+ 0x7ff7,
+ 0x7ff8,
+ 0x7ff9,
+ 0x7ffa,
+ 0x7ffb,
+ 0x7ffb,
+ 0x7ffc,
+ 0x7ffd,
+ 0x7ffd,
+ 0x7ffe,
+ 0x7ffe,
+ 0x7ffe,
+ 0x7ffe,
+ 0x7ffe,
+ 0x7fff,
+};
diff --git a/lib/ultralib/src/gu/sqrtf.s b/lib/ultralib/src/gu/sqrtf.s
new file mode 100644
index 0000000..475a827
--- /dev/null
+++ b/lib/ultralib/src/gu/sqrtf.s
@@ -0,0 +1,25 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+/*
+ * Due to compiler bug, it won't insert a sqrt.s opcode in the stream so we
+ * make a function and call it for now. When compiler fixed, also remove the
+ * seperate Makefile rules
+ */
+
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+LEAF(sqrtf)
+ sqrt.s fv0, fa0
+ j ra
+END(sqrtf)
diff --git a/lib/ultralib/src/gu/us2dex.c b/lib/ultralib/src/gu/us2dex.c
new file mode 100644
index 0000000..cf977f9
--- /dev/null
+++ b/lib/ultralib/src/gu/us2dex.c
@@ -0,0 +1,62 @@
+/*---------------------------------------------------------------------
+ $Id: us2dex.c,v 1.4 1998/10/09 06:15:30 has Exp $
+
+ File : us2dex.c
+
+ Coded by Yoshitaka Yasumoto. Mar 19, 1997.
+ Copyright by Nintendo, Co., Ltd. 1997.
+ ---------------------------------------------------------------------*/
+#include <ultra64.h>
+#include <PR/gs2dex.h>
+
+/*
+ * Routines that support processing of S2DEX microcode
+ */
+
+/*
+ * guS2DInitBG
+ * Set BG screen draw parameters
+ *
+ * If called at time of initialization, then it only needs to be
+ * called again when changes made to imageFmt, imageSiz, imageLoad, * imageW, frameW. However, if imageLoad == G_BGLT_LOADBLOCK and * only frameW is changed, another call is unnecessary.
+ */
+void guS2DInitBg(uObjBg *bg)
+{
+ u16 tmemUse;
+ u16 shift;
+ u32 tsize;
+
+ /*
+ * Get the useable volume for TMEM
+ * If imageFmt is CI then TLUT will use half
+ */
+ tmemUse = (bg->b.imageFmt == G_IM_FMT_CI) ? 256 : 512;
+
+ /*
+ * Get shift volume for conversion to TMEM word
+ */
+ shift = 6 - bg->b.imageSiz;
+
+ /*
+ * Set other parameters for Load Mode
+ */
+ if (bg->b.imageLoad == G_BGLT_LOADBLOCK){
+ bg->b.tmemW = bg->b.imageW >> shift;
+ bg->b.tmemH = (tmemUse / bg->b.tmemW) << 2;
+ bg->b.tmemSizeW = bg->b.tmemW << 1;
+ bg->b.tmemSize = bg->b.tmemH * bg->b.tmemSizeW;
+ bg->b.tmemLoadSH = (bg->b.tmemSize>>1) - 1;
+ bg->b.tmemLoadTH = GS_CALC_DXT(bg->b.tmemW);
+ } else {
+ bg->b.tmemW = (bg->b.frameW >> shift) + 3;
+ bg->b.tmemH = (tmemUse / bg->b.tmemW) << 2;
+ bg->b.tmemSizeW = (bg->b.imageW >> shift) * 2;
+ tsize = bg->b.tmemH * bg->b.tmemSizeW;
+ bg->b.tmemSize = tsize >> 16;
+ bg->b.tmemLoadSH = tsize & 0xffff;
+ bg->b.tmemLoadTH = bg->b.tmemH - 1;
+ }
+ return;
+}
+
+/*======== End of us2dex.c ========*/
diff --git a/lib/ultralib/src/gu/us2dex2_emu.c b/lib/ultralib/src/gu/us2dex2_emu.c
new file mode 100644
index 0000000..cc32179
--- /dev/null
+++ b/lib/ultralib/src/gu/us2dex2_emu.c
@@ -0,0 +1,12 @@
+/*---------------------------------------------------------------------*
+ Copyright (C) 1998, Nintendo.
+
+ File us2dex2_emu.c
+ Coded by Yoshitaka Yasumoto. Apr 10, 1998.
+
+ $Id: us2dex2_emu.c,v 1.3 1998/10/09 06:15:40 has Exp $
+ *---------------------------------------------------------------------*/
+#define F3DEX_GBI_2
+#include "us2dex_emu.c"
+
+/*======== End of us2dex2_emu.c ========*/
diff --git a/lib/ultralib/src/gu/us2dex_emu.c b/lib/ultralib/src/gu/us2dex_emu.c
new file mode 100644
index 0000000..e79ff7b
--- /dev/null
+++ b/lib/ultralib/src/gu/us2dex_emu.c
@@ -0,0 +1,502 @@
+/*---------------------------------------------------------------------*
+ Copyright (C) 1998, Nintendo.
+
+ File us2dex_emu.c
+ Coded by Yoshitaka Yasumoto. Apr 9, 1998.
+
+ $Id: us2dex_emu.c,v 1.9 1999/07/08 05:02:04 yurugi Exp $
+ *---------------------------------------------------------------------*/
+#define F3DEX_GBI
+#include <ultra64.h>
+#include <PR/gs2dex.h>
+
+#define RSP_DEBUG
+
+static u16 scissorX0 = 0; /* (s13.2) */
+static u16 scissorY0 = 0; /* (s13.2) */
+static u16 scissorX1 = 320<<2; /* (s13.2) */
+static u16 scissorY1 = 240<<2; /* (s13.2) */
+static u8 flagBilerp = 0;
+
+static u32 rdpSetTimg_w0, rdpSetTile_w0;
+static u16 tmemSliceWmax;
+static u16 imageSrcWsize;
+static s16 flagSplit;
+static u16 imagePtrX0;
+static u32 imageTop;
+static s16 tmemSrcLines;
+
+/* Addition 99/05/31(Y) */
+static s8 bgflg;
+
+/*----------------------------------------------------------------------------*
+ * Set scissoring parameters
+ * *---------------------------------------------------------------------------*/
+void guS2DEmuSetScissor(u32 ulx, u32 uly, u32 lrx, u32 lry, u8 flag)
+{
+ scissorX0 = (u16)ulx << 2;
+ scissorY0 = (u16)uly << 2;
+ scissorX1 = (u16)lrx << 2;
+ scissorY1 = (u16)lry << 2;
+ flagBilerp = (flag) ? 1 : 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * Create texture load RDP commands
+ *---------------------------------------------------------------------------*/
+static void tmemLoad_B(Gfx **pkt, u32 imagePtr, s16 loadLines, s16 tmemSH)
+{
+ /*
+ * Load 16-bit texture of tmemSH word width starting from imagePtr
+ * into the loadLines amount of lines of tmem.
+ */
+
+ /* [SetTImg] CMD=0x3d FMT=RGBA(0) SIZ=16b(2) */
+ (*pkt)->words.w0 = rdpSetTimg_w0;
+ (*pkt)->words.w1 = imagePtr;
+ (*pkt) ++;
+
+ /* [LoadSync] Wait for completion of preceding primitive draw */
+ (*pkt)->words.w0 = (G_RDPLOADSYNC<<24);
+ (*pkt) ++;
+
+ /* [LoadTile] CMD=0x34 TILE=7 SH=TMEMW*16-1 TMEMH*4-1 */
+ (*pkt)->words.w0 = (G_LOADTILE<<24)|0x000000;
+/* addition 99/5/31(Y) */
+ if(bgflg==3) (*pkt)->words.w1 = 0x07000000 | (tmemSH-1)<<16;
+ else (*pkt)->words.w1 = 0x07000000 | (tmemSH-1)<<16 | (loadLines<<2)-1;
+ (*pkt) ++;
+}
+
+static void tmemLoad_A(Gfx **pkt, u32 imagePtr,
+ s16 loadLines, s16 tmemAdrs, s16 tmemSH)
+{
+ /*
+ * Load 16-bit texture of tmemSH word width starting from imagePtr into
+ * the loadLines amount of lines of the tmemAdrs of tmem.
+ */
+
+ /* [TileSync] Wait for completion of Tile access of preceding command */
+ (*pkt)->words.w0 = 0xe8000000;
+ (*pkt) ++;
+
+ /* [SetTile] */
+ (*pkt)->words.w0 = rdpSetTile_w0|tmemAdrs;
+ (*pkt)->words.w1 = 0x07000000;
+ (*pkt) ++;
+
+ tmemLoad_B(pkt, imagePtr, loadLines, tmemSH);
+}
+
+static void tmemLoad(Gfx **pkt, u32 *imagePtr,
+ s16 *imageRemain, s16 drawLines, s16 flagBilerp)
+{
+ s16 loadLines = drawLines + flagBilerp;
+ s16 iLoadable = (*imageRemain) - flagSplit;
+
+ if (iLoadable >= loadLines){ /* If load can be done all at once */
+ tmemLoad_B(pkt, *imagePtr, loadLines, tmemSliceWmax);
+ (*imagePtr) += imageSrcWsize * drawLines;
+ (*imageRemain) -= drawLines;
+
+ } else { /* If load is to be partitioned */
+ s16 SubSliceL2, SubSliceD2, SubSliceY2;
+ u32 imageTopSeg = imageTop & 0xff000000;
+
+ SubSliceY2 = *imageRemain;
+ SubSliceL2 = loadLines - SubSliceY2;
+ SubSliceD2 = drawLines - SubSliceY2;
+
+ if (SubSliceL2 > 0){
+ u32 imagePtr2;
+
+ imagePtr2 = imageTop + imagePtrX0;
+ if (SubSliceY2 & 1){
+ imagePtr2 -= imageSrcWsize;
+ imagePtr2 = imageTopSeg | (imagePtr2 & 0x00ffffff); /*Segment counterm */
+ SubSliceY2 --;
+ SubSliceL2 ++;
+ }
+ tmemLoad_A(pkt, imagePtr2,
+ SubSliceL2, SubSliceY2 * tmemSliceWmax, tmemSliceWmax);
+ }
+ if (flagSplit){
+ u32 imagePtr1A, imagePtr1B;
+ s16 SubSliceY1, SubSliceL1;
+ s16 tmemSH_A, tmemSH_B;
+
+ imagePtr1A = (*imagePtr) + iLoadable * imageSrcWsize;
+ imagePtr1B = imageTop;
+ SubSliceY1 = iLoadable;
+ if (SubSliceL1 = iLoadable & 1){
+ imagePtr1A -= imageSrcWsize;
+ imagePtr1B -= imageSrcWsize;
+ imagePtr1B = imageTopSeg | (imagePtr1B & 0x00ffffff); /*Segment countermeasure */
+ SubSliceY1 --;
+ }
+ SubSliceL1 ++;
+ tmemSH_A = (imageSrcWsize - imagePtrX0) >> 3;
+ tmemSH_B = tmemSliceWmax - tmemSH_A;
+ tmemLoad_A(pkt, imagePtr1B,
+ SubSliceL1, SubSliceY1 * tmemSliceWmax + tmemSH_A, tmemSH_B);
+ tmemLoad_A(pkt, imagePtr1A,
+ SubSliceL1, SubSliceY1 * tmemSliceWmax, tmemSH_A);
+ }
+ if (iLoadable > 0){
+
+ tmemLoad_A(pkt, *imagePtr, iLoadable, 0, tmemSliceWmax);
+
+ } else {
+
+ /* [SetTile] */
+ (*pkt)->words.w0 = rdpSetTile_w0;
+ (*pkt)->words.w1 = 0x07000000;
+ (*pkt) ++;
+ }
+
+ (*imageRemain) -= drawLines;
+ if ((*imageRemain) > 0){
+ (*imagePtr) += imageSrcWsize * drawLines;
+ } else {
+ (*imageRemain) = tmemSrcLines - SubSliceD2;
+ (*imagePtr) = imageTop + SubSliceD2 * imageSrcWsize + imagePtrX0;
+ }
+
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Scalable BG serface draw process
+ *---------------------------------------------------------------------------*/
+void guS2DEmuBgRect1Cyc(Gfx **pkt, uObjBg *bg)
+{
+ s16 frameX0, frameX1, framePtrY0, frameRemain;
+ s16 imageX0, imageY0, imageSliceW, imageW;
+ s32 imageYorig;
+ s16 scaleW, scaleH;
+
+ s16 imageSrcW, imageSrcH;
+ s16 tmemSliceLines, imageSliceLines;
+ s32 frameSliceLines, frameSliceCount;
+ u16 imageS, imageT;
+ u32 imagePtr;
+
+ s16 imageISliceL0, imageIY0;
+ s32 frameLSliceL0;
+
+ scaleW = bg->s.scaleW;
+ scaleH = bg->s.scaleH;
+
+/* addition 99/05/31(Y) */
+ bgflg=bg->s.imageSiz;
+ if(scaleW==0) scaleW=1;
+ if(scaleH==0) scaleH=1;
+
+
+{
+ /*-------------------------------------------------*
+ Scissoring process
+ *-------------------------------------------------*/
+ /*
+ / frameX0, frameX1, framePtrY0, frameRemain
+ / imageX0, imageY0, tmemSliceW
+ / imageSrcW, imageSrcH
+ */
+ s16 pixX0, pixY0, pixX1, pixY1; /* (s13.2) */
+ s16 frameY0, frameW, frameH;
+ s32 frameWmax, frameHmax;
+
+ /* Determine maximum frame size from image and enlargement ratio */
+ frameWmax = ((((s32)bg->s.imageW << 10) / scaleW)-1) & ~3;
+ frameHmax = ((((s32)bg->s.imageH << 10) / scaleH)-1) & ~3;
+
+ /* Clamp the frame size */
+ frameW = bg->s.frameW;
+ frameH = bg->s.frameH;
+ frameX0 = bg->s.frameX;
+ frameY0 = bg->s.frameY;
+ if ((frameWmax = bg->s.frameW - frameWmax) < 0) frameWmax = 0;
+ if ((frameHmax = bg->s.frameH - frameHmax) < 0) frameHmax = 0;
+ frameW -= frameWmax;
+ frameH -= frameHmax;
+ if (bg->s.imageFlip & G_BG_FLAG_FLIPS){
+ frameX0 += frameWmax;
+ }
+
+ /* Caluculate amount of projection from screen */
+ pixX0 = scissorX0 - frameX0; /* (s13.2) */
+ pixY0 = scissorY0 - frameY0; /* (s13.2) */
+ pixX1 = frameW - scissorX1 + frameX0; /* (s13.2) */
+ pixY1 = frameH - scissorY1 + frameY0; /* (s13.2) */
+
+ /* Clamp if no projection */
+ if (pixX0 < 0) pixX0 = 0;
+ if (pixY0 < 0) pixY0 = 0;
+ if (pixX1 < 0) pixX1 = 0;
+ if (pixY1 < 0) pixY1 = 0;
+
+ /* Cut the part that is projecting */
+ frameW = frameW - (pixX0 + pixX1); /* (s13.2) */
+ frameH = frameH - (pixY0 + pixY1); /* (s13.2) */
+ frameX0 = frameX0 + pixX0; /* (s13.2) */
+ frameY0 = frameY0 + pixY0; /* (s13.2) */
+
+ /* Terminate if no draw range remains */
+ if (frameW <= 0 || frameH <= 0) return;
+
+ /* Caluculate frame */
+ frameX1 = frameX0 + frameW; /* (s13.2) */
+ framePtrY0 = frameY0 >> 2; /* (s15.0) */
+ frameRemain = frameH >> 2; /* (s15.0) */
+
+ /* Join image columns */
+ imageSrcW = bg->s.imageW << 3; /* (u11.5) */
+ imageSrcH = bg->s.imageH << 3; /* (u11.5) */
+
+ /* Get image range (u14.2)*(u6.10)=(u20.12)->(u11.5) */
+ imageSliceW = (imageW = frameW * scaleW >> 7) + flagBilerp * 32;
+ if (bg->s.imageFlip & G_BG_FLAG_FLIPS){
+ imageX0 = bg->s.imageX + (pixX1 * scaleW >> 7); /* (s10.5) */
+ } else {
+ imageX0 = bg->s.imageX + (pixX0 * scaleW >> 7); /* (s10.5) */
+ }
+ imageY0 = bg->s.imageY + (pixY0 * scaleH >> 7); /* (s10.5) */
+ imageYorig = bg->s.imageYorig;
+
+ /* Loop one step down when left end of image area is greater than right end of image source */
+ while (imageX0 >= imageSrcW){
+ imageX0 -= imageSrcW;
+ imageY0 += 32;
+ imageYorig += 32; /* Add 1 to carrier */
+ }
+
+ /* Loop when top end of image area is greater than bottom end of image source */
+ while (imageY0 >= imageSrcH){
+ imageY0 -= imageSrcH;
+ imageYorig -= imageSrcH;
+ }
+}
+
+{
+ /*-------------------------------------------------*
+ Check process connecting top and bottom of image
+ *-------------------------------------------------*/
+ /*
+ // flagSplit
+ // tmemSrcLines
+ // imageSrcLines
+ */
+ /* Top/bottom connection process necessary when image range straddles right
+end */
+ flagSplit = (imageX0 + imageSliceW >= imageSrcW);
+
+ /* Number of image lines that can be loaded at once */
+ tmemSrcLines = imageSrcH >> 5;
+}
+
+{
+ /*-------------------------------------------------*
+ Get load data for TMEM
+ *-------------------------------------------------*/
+ /*
+ //Calculate number of lines that can be loaded into TMEM.
+ // If the slice width changes due to scissoring and the linked
+ // load line number is changed, then the frame division line will
+ // change and the result will be the generation of unnatural wrinkles.
+ // To prevent this, the division region is set such that scissoring
+ // does not occur.
+ //
+ */
+ s16 tmemSize, tmemMask, tmemShift;
+ s32 imageNumSlice;
+ s32 imageSliceWmax;
+ s32 imageLYoffset, frameLYoffset;
+ s32 imageLHidden, frameLHidden;
+ s32 frameLYslice;
+
+ static s16 TMEMSIZE[] = { 512, 512, 256, 512, 512 };
+ static s16 TMEMMASK[] = { 0x1ff, 0xff, 0x7f, 0x3f };
+ static s16 TMEMSHIFT[] = { 0x200, 0x100, 0x80, 0x40 };
+ tmemSize = TMEMSIZE[bg->s.imageFmt]; /* (s15.0) */
+ tmemMask = TMEMMASK[bg->s.imageSiz]; /* (s10.5) */
+ tmemShift = TMEMSHIFT[bg->s.imageSiz]; /* (s10.5)->(s15.0) */
+
+ /* Calculate tmem width to accommodate the slice image width */
+ /* o Extra is needed at Bilerp time.
+ // o Clamp slice image width based on image source width.
+ // o Cut image width end number at TMEM Word boundary.
+ // o tmem width + 1 when start position not in agreement with Word boundary */
+/* addition 99/05/31(Y) */
+ if(bgflg==3){
+ tmemSize=480;
+ imageSliceWmax = 0x2800;
+ }
+ else{
+ imageSliceWmax = (((s32)bg->s.frameW * (s32)scaleW)>>7) + (flagBilerp<<5);
+ if (imageSliceWmax > imageSrcW) imageSliceWmax = imageSrcW;
+ }
+ tmemSliceWmax = (imageSliceWmax + tmemMask) / tmemShift + 1;
+
+ /* Get TMEM/image/frame line number that can be loaded at once */
+ tmemSliceLines = tmemSize / tmemSliceWmax; /* (s15.0) */
+ imageSliceLines = tmemSliceLines - flagBilerp; /* (s15.0) */
+ frameSliceLines = (imageSliceLines << 20) / scaleH; /* (s21.10) */
+
+ /* Line up image Y coordinate offset value with frame image */
+ imageLYoffset = ((s32)imageY0 - imageYorig) << 5;
+ if (imageLYoffset < 0) imageLYoffset -= (scaleH - 1);
+ frameLYoffset = imageLYoffset / scaleH;
+ frameLYoffset <<= 10;
+
+ /* Get slice number corresponding to image Y */
+ if (frameLYoffset >= 0){
+ imageNumSlice = frameLYoffset / frameSliceLines;
+ } else {
+ imageNumSlice = (frameLYoffset - frameSliceLines + 1) / frameSliceLines;
+ }
+
+ /* Calculate extent to which first draw slice is hidden at top of frame */
+ frameLYslice = (frameLSliceL0 = frameSliceLines * imageNumSlice) & ~1023;
+ frameLHidden = frameLYoffset - frameLYslice;
+ imageLHidden = (frameLHidden >> 10) * scaleH;
+
+ /* Calculate fram size of first draw slice */
+ frameLSliceL0 = (frameLSliceL0 & 1023) + frameSliceLines - frameLHidden;
+
+ /* Calculate image parameters for draw in midst of slice */
+ imageT = (imageLHidden >> 5) & 31;
+ imageLHidden >>= 10;
+ imageISliceL0 = imageSliceLines - imageLHidden;
+ imageIY0 =
+ imageSliceLines * imageNumSlice + (imageYorig & ~31) / 32 + imageLHidden;
+ if (imageIY0 < 0) imageIY0 += (bg->s.imageH >> 2);
+ if (imageIY0 >= (bg->s.imageH >> 2)) imageIY0 -= (bg->s.imageH >> 2);
+ imageTop = (u32)bg->s.imagePtr; /* (u32.0) */
+ imageSrcWsize = (imageSrcW / tmemShift) << 3; /* (u16.0) */
+ imagePtrX0 = (imageX0 / tmemShift) << 3; /* (u16.0) */
+ imagePtr = imageTop + imageSrcWsize * imageIY0 + imagePtrX0;
+
+ /* S invert process */
+ imageS = imageX0 & tmemMask; /* (u10.5) */
+ if (bg->s.imageFlip & G_BG_FLAG_FLIPS){
+ imageS = - (imageS + imageW);
+ }
+}
+
+{
+ /*-------------------------------------------------*
+ Creating RDP command constant values
+ *-------------------------------------------------*/
+ /* u32 rdpSetTimg_w0;
+ u32 rdpSetTile_w0; */
+/* Addition 99/05/31(Y) */
+ if(bgflg==3){
+ rdpSetTimg_w0 = (G_SETTIMG<<24)+0x180000+(imageSrcWsize>>1)-1;
+ rdpSetTile_w0 = (G_SETTILE<<24)+0x180000+(tmemSliceWmax<<9);
+ }
+ else{
+ rdpSetTimg_w0 = (G_SETTIMG<<24)+0x100000+(imageSrcWsize>>1)-1;
+ rdpSetTile_w0 = (G_SETTILE<<24)+0x100000+(tmemSliceWmax<<9);
+ }
+ /* [SetTile:7] */
+ (*pkt)->words.w0 = rdpSetTile_w0;
+ (*pkt)->words.w1 = 0x07000000;
+ (*pkt)++;
+ /* [SetTile:0] */
+ (*pkt)->words.w0 = rdpSetTile_w0;
+ ((u8 *)&((*pkt)->words.w0))[1] = (bg->s.imageFmt<<5)|(bg->s.imageSiz<<3);
+ (*pkt)->words.w1 = 0x0007c1f0 | (bg->s.imagePal<<20);
+ (*pkt)++;
+ /* [SetTileSize:7] */
+ (*pkt)->words.w0 = (G_SETTILESIZE<<24)|0x000000;
+ (*pkt)->words.w1 = 0x00000000;
+ (*pkt)++;
+}
+
+{
+ s16 imageRemain;
+ s16 imageSliceH, frameSliceH;
+
+ imageRemain = tmemSrcLines - imageIY0;
+ imageSliceH = imageISliceL0;
+ frameSliceCount = frameLSliceL0;
+
+ while(1){
+
+ /* Calculate draw line number and determine whether to perform a draw */
+ frameSliceH = frameSliceCount >> 10;
+ if (frameSliceH <= 0){
+ /* If no draw to be performed */
+ imageRemain -= imageSliceH;
+ if (imageRemain > 0){
+ imagePtr += imageSrcWsize * imageSliceH;
+ } else {
+ imagePtr = imageTop - (imageRemain * imageSrcWsize) + imagePtrX0;
+ imageRemain += tmemSrcLines;
+ }
+
+ } else {
+ /* If draw to be performed */
+ s16 framePtrY1;
+
+ frameSliceCount &= 1023;
+ if ((frameRemain -= frameSliceH) < 0){
+ /* Determine final slice */
+ frameSliceH += frameRemain;
+ imageSliceH += ((frameRemain * scaleH) >> 10) + 1;
+ if (imageSliceH > imageSliceLines) imageSliceH = imageSliceLines;
+ }
+ tmemLoad(pkt, &imagePtr, &imageRemain, imageSliceH, flagBilerp);
+
+ /* Get draw frame range */
+ framePtrY1 = framePtrY0 + frameSliceH; /* (s15.0) */
+
+ /* [PipeSync] Wait for end of preceding LOADTILE command */
+ (*pkt)->words.w0 = (G_RDPPIPESYNC<<24);
+ (*pkt) ++;
+
+ /* Rectangle draw */
+ /* Here an RSP command is created. With ucode an RDP command is created */
+#if 1
+ {
+ /* [TextureRectangle] */
+ (*pkt)->words.w0 = (G_TEXRECT<<24)|(frameX1<<12)|(framePtrY1<<2);
+ (*pkt)->words.w1 = (frameX0<<12)|(framePtrY0<<2);
+ (*pkt) ++;
+#else
+ /* Code for checking slice division line */
+ if (frameSliceH > 1){
+ (*pkt)->words.w0 = (G_TEXRECT<<24)|(frameX1<<12)|(framePtrY1<<2)-4;
+ (*pkt)->words.w1 = (frameX0<<12)|(framePtrY0<<2);
+ (*pkt) ++;
+#endif
+
+#if 0 /* At RDP command creation time */
+ (*pkt)->words.w0 = (imageS<<16) | imageT;
+ (*pkt)->words.w1 = (scaleW<<16) | scaleH;
+#else /* At RSP command creation time */
+ (*pkt)->words.w0 = (G_RDPHALF_1<<24);
+ (*pkt)->words.w1 = (imageS<<16) | imageT;
+ (*pkt) ++;
+ (*pkt)->words.w0 = (G_RDPHALF_2<<24);
+ (*pkt)->words.w1 = (scaleW<<16) | scaleH;
+#endif
+ (*pkt) ++;
+ }
+
+ /* Update region */
+ framePtrY0 = framePtrY1;
+
+ /* End if no more undrawn line numbers for frame */
+ if (frameRemain <= 0){
+ return;
+ }
+ }
+ frameSliceCount += frameSliceLines;
+ imageSliceH = imageSliceLines;
+ imageT = 0;
+ }
+}
+}
+
+/*======== End of us2dex_emu.c ========*/
diff --git a/lib/ultralib/src/gu/usprite.c b/lib/ultralib/src/gu/usprite.c
new file mode 100644
index 0000000..a10ed34
--- /dev/null
+++ b/lib/ultralib/src/gu/usprite.c
@@ -0,0 +1,39 @@
+
+/**************************************************************************
+ * *
+ * Copyright (C) 1996, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "gbi.h"
+
+void guSprite2DInit(uSprite *SpritePointer,
+ void *SourceImagePointer,
+ void *TlutPointer,
+ short Stride,
+ short SubImageWidth,
+ short SubImageHeight,
+ char SourceImageType,
+ char SourceImageBitSize,
+ short SourceImageOffsetS,
+ short SourceImageOffsetT)
+{
+ SpritePointer->s.SourceImagePointer = SourceImagePointer;
+ SpritePointer->s.TlutPointer = TlutPointer;
+ SpritePointer->s.Stride = Stride;
+ SpritePointer->s.SubImageWidth = SubImageWidth;
+ SpritePointer->s.SubImageHeight = SubImageHeight;
+ SpritePointer->s.SourceImageType = SourceImageType;
+ SpritePointer->s.SourceImageBitSize = SourceImageBitSize;
+ SpritePointer->s.SourceImageOffsetS = SourceImageOffsetS;
+ SpritePointer->s.SourceImageOffsetT = SourceImageOffsetT;
+}
+
+
+
diff --git a/lib/ultralib/src/host/host_ptn64.c b/lib/ultralib/src/host/host_ptn64.c
new file mode 100644
index 0000000..9e6fbd6
--- /dev/null
+++ b/lib/ultralib/src/host/host_ptn64.c
@@ -0,0 +1,203 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "../io/piint.h"
+
+#include "macros.h"
+
+static volatile unsigned int* ptwtmode = (unsigned*)0xbff08014;
+static volatile unsigned int* ptstat = (unsigned*)0xbff08004;
+static volatile unsigned int* ptport = (unsigned*)0xbff08000;
+static volatile unsigned int* n64piok = (unsigned*)PHYS_TO_K1(PI_STATUS_REG);
+
+static OSMesgQueue waitPtQueue;
+static OSMesg waitPtQueueBuf;
+static u32 isWaitPtQueueCreated = FALSE;
+
+static void createWaitPtQueue(void) {
+ osCreateMesgQueue(&waitPtQueue, &waitPtQueueBuf, 1);
+ isWaitPtQueueCreated = TRUE;
+}
+
+static u32 getPT_wait(void) {
+ OSTimer waitTimer;
+ u32 status UNUSED;
+
+ for (;;) {
+ while (*n64piok & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) {
+ ;
+ }
+
+ if (*ptstat & 2) {
+ return *ptport;
+ }
+ __osPiRelAccess();
+
+ osRecvMesg(&waitPtQueue, NULL, OS_MESG_NOBLOCK);
+ osSetTimer(&waitTimer, OS_USEC_TO_CYCLES(1000), 0, &waitPtQueue, NULL);
+ osRecvMesg(&waitPtQueue, NULL, OS_MESG_BLOCK);
+
+ __osPiGetAccess();
+ }
+}
+
+static void putPT(u32 c) {
+ while (*n64piok & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) {
+ ;
+ }
+ while (!(*ptstat & 4)) {
+ ;
+ }
+ *ptport = c;
+}
+
+static u32 getPT(void) {
+ while (*n64piok & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) {
+ ;
+ }
+ while (!(*ptstat & 2)) {
+ ;
+ }
+ return *ptport;
+}
+
+void osReadHost_pt(void* dramAddr, u32 nbytes) {
+ u8 * tPtr;
+ u32 buf[256];
+ u32 * bp;
+ u32 data;
+ u32 ct;
+ u32 ct1;
+ u32 ct1_bak;
+ u32 shift;
+ u32 cmd;
+ u32 size;
+
+ if (nbytes == 0) {
+ return;
+ }
+
+ if (!isWaitPtQueueCreated) {
+ createWaitPtQueue();
+ }
+
+ __osPiGetAccess();
+
+ putPT(0x82U);
+
+ cmd = getPT_wait();
+
+ size = getPT();
+
+ if (cmd != 2) {
+ nbytes = -1U;
+ }
+
+ putPT(nbytes);
+
+ if (size != nbytes) {
+ goto osReadHost_ret;
+ }
+
+ tPtr = dramAddr;
+ ct = nbytes / 4;
+
+ while (ct != 0) {
+ if (ct > 0x100) {
+ ct1 = 0x100;
+ ct1_bak = 0x100;
+ ct -= 0x100;
+ } else {
+ ct1_bak = ct1 = ct;
+ ct = 0;
+ }
+ bp = &buf;
+
+ while (ct1 != 0) {
+ *(bp++) = getPT();
+ ct1--;
+ }
+
+ memcpy(tPtr, &buf, ct1_bak * 4);
+ tPtr += ct1_bak * 4;
+ }
+
+ nbytes &= 3;
+
+ if (nbytes != 0) {
+ data = getPT();
+ shift = 0x18;
+
+ do {
+ *(tPtr++) = (data >> shift);
+ nbytes--;
+ shift -= 8;
+ } while (nbytes != 0);
+ }
+
+osReadHost_ret:
+ __osPiRelAccess();
+ return;
+}
+
+void osWriteHost_pt(void* dramAddr, u32 nbytes) {
+ u8 *tPtr;
+ u32 buf[256];
+ u32 *bp;
+ u32 ct;
+ u32 ct1;
+ u32 ct1_bak;
+ u32 cmd;
+ u32 size;
+
+ if (nbytes == 0) {
+ return;
+ }
+
+ if (!isWaitPtQueueCreated) {
+ createWaitPtQueue();
+ }
+
+ __osPiGetAccess();
+ putPT(0x82);
+
+ cmd = getPT_wait();
+
+ size = getPT();
+
+ if (cmd != 3) {
+ nbytes = -1;
+ }
+
+ putPT(nbytes);
+
+ if (size != nbytes) {
+ goto osWriteHost_ret;
+ }
+
+ tPtr = dramAddr;
+ ct = (nbytes + 3) >> 2;
+
+ while (ct != 0) {
+ if (ct > 0x100) {
+ ct1 = 0x100;
+ ct1_bak = 0x100;
+ ct -= 0x100;
+ } else {
+ ct1_bak = ct1 = ct;
+ ct = 0;
+ }
+
+ memcpy(bp = buf, tPtr, ct1_bak * 4);
+
+ while (ct1 != 0) {
+ putPT(*(bp++));
+ ct1--;
+ }
+
+ tPtr += ct1_bak * 4;
+ }
+
+osWriteHost_ret:
+ __osPiRelAccess();
+ return;
+}
diff --git a/lib/ultralib/src/host/readhost.c b/lib/ultralib/src/host/readhost.c
new file mode 100644
index 0000000..5cc1974
--- /dev/null
+++ b/lib/ultralib/src/host/readhost.c
@@ -0,0 +1,36 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/rdb.h"
+
+#include "macros.h"
+
+u32 __osRdb_Read_Data_Buf;
+u32 __osRdb_Read_Data_Ct;
+
+static int readHostInitialized = FALSE;
+static OSMesgQueue readHostMesgQueue;
+static OSMesg readHostMesgBuf[1];
+
+void osReadHost(void* dramAddr, u32 nbytes) {
+ char tstr[4];
+ u32 sent = 0;
+
+ if (!readHostInitialized) {
+ osCreateMesgQueue(&readHostMesgQueue, readHostMesgBuf, ARRLEN(readHostMesgBuf));
+ osSetEventMesg(OS_EVENT_RDB_READ_DONE, &readHostMesgQueue, NULL);
+ readHostInitialized = TRUE;
+ }
+
+ __osRdb_Read_Data_Buf = dramAddr;
+ __osRdb_Read_Data_Ct = nbytes;
+
+ while (sent == 0) {
+ sent += __osRdbSend(tstr, 1, RDB_TYPE_GtoH_READY_FOR_DATA);
+ }
+
+ osRecvMesg(&readHostMesgQueue, NULL, OS_MESG_BLOCK);
+ return;
+}
+
+#endif
diff --git a/lib/ultralib/src/host/writehost.c b/lib/ultralib/src/host/writehost.c
new file mode 100644
index 0000000..92e9587
--- /dev/null
+++ b/lib/ultralib/src/host/writehost.c
@@ -0,0 +1,54 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/rdb.h"
+
+#include "macros.h"
+
+static int writeHostInitialized = FALSE;
+static OSMesgQueue writeHostMesgQueue;
+static OSMesg writeHostMesgBuf[1];
+
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+
+void osWriteHost(void * dramAddr, u32 nbytes) {
+ u8* tPtr = dramAddr;
+ u32 sent;
+ u8 dCount[3];
+ u32 count;
+
+ if (nbytes == 0) {
+ __osError(73, 1, nbytes);
+ return;
+ }
+
+ if (writeHostInitialized == FALSE) {
+ osCreateMesgQueue(&writeHostMesgQueue, writeHostMesgBuf, ARRLEN(writeHostMesgBuf));
+ osSetEventMesg(OS_EVENT_RDB_DATA_DONE, &writeHostMesgQueue, NULL);
+ writeHostInitialized = TRUE;
+ }
+
+ while (nbytes != 0) {
+ count = MIN(nbytes, 0x8000);
+
+ dCount[0] = (count & 0xFF0000) >> 0x10;
+ dCount[1] = (count & 0xFF00) >> 8;
+ dCount[2] = count & 0xFF;
+
+ sent = 0;
+ while (sent < ARRLEN(dCount)) {
+ sent += __osRdbSend(dCount + sent, ARRLEN(dCount) - sent, RDB_TYPE_GtoH_DATA_CT);
+ }
+
+ sent = 0;
+ while (sent < count) {
+ sent += __osRdbSend(tPtr + sent, count - sent, RDB_TYPE_GtoH_DATA);
+ }
+
+ nbytes -= count;
+ tPtr += count;
+ osRecvMesg(&writeHostMesgQueue, NULL, OS_MESG_BLOCK);
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/io/ai.c b/lib/ultralib/src/io/ai.c
new file mode 100755
index 0000000..5e345dc
--- /dev/null
+++ b/lib/ultralib/src/io/ai.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osAiDeviceBusy(void) {
+ register s32 status = IO_READ(AI_STATUS_REG);
+
+ if (status & AI_STATUS_FIFO_FULL) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/lib/ultralib/src/io/aigetlen.c b/lib/ultralib/src/io/aigetlen.c
new file mode 100755
index 0000000..6b83682
--- /dev/null
+++ b/lib/ultralib/src/io/aigetlen.c
@@ -0,0 +1,8 @@
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+u32 osAiGetLength(void) {
+ return IO_READ(AI_LEN_REG);
+}
diff --git a/lib/ultralib/src/io/aigetstat.c b/lib/ultralib/src/io/aigetstat.c
new file mode 100755
index 0000000..c7a3cf7
--- /dev/null
+++ b/lib/ultralib/src/io/aigetstat.c
@@ -0,0 +1,8 @@
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+u32 osAiGetStatus() {
+ return IO_READ(AI_STATUS_REG);
+}
diff --git a/lib/ultralib/src/io/aisetfreq.c b/lib/ultralib/src/io/aisetfreq.c
new file mode 100755
index 0000000..52cd8c3
--- /dev/null
+++ b/lib/ultralib/src/io/aisetfreq.c
@@ -0,0 +1,29 @@
+#include "PR/rcp.h"
+#include "../os/osint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 osAiSetFrequency(u32 frequency) {
+ register unsigned int dacRate;
+ register unsigned char bitRate;
+ register float f;
+
+ f = osViClock / (float)frequency + .5f;
+ dacRate = f;
+
+ if (dacRate < AI_MIN_DAC_RATE) {
+ return -1;
+ }
+
+ bitRate = dacRate / 66;
+
+ if (bitRate > AI_MAX_BIT_RATE) {
+ bitRate = AI_MAX_BIT_RATE;
+ }
+
+ IO_WRITE(AI_DACRATE_REG, dacRate - 1);
+ IO_WRITE(AI_BITRATE_REG, bitRate - 1);
+ // IO_WRITE(AI_CONTROL_REG, AI_CONTROL_DMA_ON);
+ return osViClock / (s32)dacRate;
+}
diff --git a/lib/ultralib/src/io/aisetnextbuf.c b/lib/ultralib/src/io/aisetnextbuf.c
new file mode 100755
index 0000000..d4295d3
--- /dev/null
+++ b/lib/ultralib/src/io/aisetnextbuf.c
@@ -0,0 +1,31 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "../os/osint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 osAiSetNextBuffer(void *bufPtr, u32 size) {
+ static u8 hdwrBugFlag = FALSE;
+ char *bptr;
+
+ if (__osAiDeviceBusy()) {
+ return -1;
+ }
+
+ bptr = bufPtr;
+
+ if (hdwrBugFlag) {
+ bptr -= 0x2000;
+ }
+
+ if ((((u32)bufPtr + size) & 0x1fff) == 0) {
+ hdwrBugFlag = TRUE;
+ } else {
+ hdwrBugFlag = FALSE;
+ }
+
+ IO_WRITE(AI_DRAM_ADDR_REG, osVirtualToPhysical(bptr));
+ IO_WRITE(AI_LEN_REG, size);
+ return 0;
+}
diff --git a/lib/ultralib/src/io/cartrominit.c b/lib/ultralib/src/io/cartrominit.c
new file mode 100644
index 0000000..9cd1617
--- /dev/null
+++ b/lib/ultralib/src/io/cartrominit.c
@@ -0,0 +1,65 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+#include "PR/rcp.h"
+
+OSPiHandle __CartRomHandle ALIGNED(8);
+OSPiHandle *osCartRomInit(void)
+{
+ u32 value;
+ u32 saveMask;
+ static int first = 1;
+ register u32 stat;
+ u32 latency;
+ u32 pulse;
+ u32 pageSize;
+ u32 relDuration;
+
+ __osPiGetAccess();
+
+ if (!first) {
+ __osPiRelAccess();
+ return &__CartRomHandle;
+ }
+
+ first = 0;
+ __CartRomHandle.type = DEVICE_TYPE_CART;
+ __CartRomHandle.baseAddress = PHYS_TO_K1(PI_DOM1_ADDR2);
+ __CartRomHandle.domain = PI_DOMAIN1;
+ __CartRomHandle.speed = 0;
+
+ bzero(&__CartRomHandle.transferInfo, sizeof(__OSTranxInfo));
+
+ while (stat = IO_READ(PI_STATUS_REG), stat & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) {
+ ;
+ }
+
+ latency = IO_READ(PI_BSD_DOM1_LAT_REG);
+ pageSize = IO_READ(PI_BSD_DOM1_PGS_REG);
+ relDuration = IO_READ(PI_BSD_DOM1_RLS_REG);
+ pulse = IO_READ(PI_BSD_DOM1_PWD_REG);
+
+ IO_WRITE(PI_BSD_DOM1_LAT_REG, 0xFF);
+ IO_WRITE(PI_BSD_DOM1_PGS_REG, 0);
+ IO_WRITE(PI_BSD_DOM1_RLS_REG, 3);
+ IO_WRITE(PI_BSD_DOM1_PWD_REG, 0xFF);
+
+ value = IO_READ(__CartRomHandle.baseAddress);
+ __CartRomHandle.latency = value & 0xFF;
+ __CartRomHandle.pageSize = (value >> 0x10) & 0xF;
+ __CartRomHandle.relDuration = (value >> 0x14) & 0xF;
+ __CartRomHandle.pulse = (value >> 8) & 0xFF;
+
+ IO_WRITE(PI_BSD_DOM1_LAT_REG, latency);
+ IO_WRITE(PI_BSD_DOM1_PGS_REG, pageSize);
+ IO_WRITE(PI_BSD_DOM1_RLS_REG, relDuration);
+ IO_WRITE(PI_BSD_DOM1_PWD_REG, pulse);
+
+ saveMask = __osDisableInt();
+ __CartRomHandle.next = __osPiTable;
+ __osPiTable = &__CartRomHandle;
+ __osRestoreInt(saveMask);
+ __osPiRelAccess();
+
+ return &__CartRomHandle;
+}
diff --git a/lib/ultralib/src/io/contchannelreset.c b/lib/ultralib/src/io/contchannelreset.c
new file mode 100644
index 0000000..d209ffc
--- /dev/null
+++ b/lib/ultralib/src/io/contchannelreset.c
@@ -0,0 +1,27 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 __osContChannelReset(OSMesgQueue* mq, int channel) {
+ s32 i;
+ s32 ret;
+ u8* ptr = (u8*)&__osPfsPifRam;
+
+ __osSiGetAccess();
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = CONT_CMD_REQUEST_STATUS;
+ }
+
+ *ptr++ = CONT_CMD_CHANNEL_RESET;
+ *ptr = CONT_CMD_END;
+
+ ret = __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ __osSiRelAccess();
+ return ret;
+}
diff --git a/lib/ultralib/src/io/conteeplongread.c b/lib/ultralib/src/io/conteeplongread.c
new file mode 100755
index 0000000..15af27c
--- /dev/null
+++ b/lib/ultralib/src/io/conteeplongread.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int length) {
+ s32 ret = 0;
+
+ while (length > 0) {
+ ERRCK(osEepromRead(mq, address, buffer));
+ length -= EEPROM_BLOCK_SIZE;
+ address++;
+ buffer += EEPROM_BLOCK_SIZE;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/conteeplongwrite.c b/lib/ultralib/src/io/conteeplongwrite.c
new file mode 100755
index 0000000..ea92431
--- /dev/null
+++ b/lib/ultralib/src/io/conteeplongwrite.c
@@ -0,0 +1,17 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int length) {
+ s32 ret = 0;
+
+ while (length > 0) {
+ ERRCK(osEepromWrite(mq, address, buffer));
+ length -= EEPROM_BLOCK_SIZE;
+ address++;
+ buffer += EEPROM_BLOCK_SIZE;
+ osSetTimer(&__osEepromTimer, 562500, 0, &__osEepromTimerQ, &__osEepromTimerMsg);
+ osRecvMesg(&__osEepromTimerQ, NULL, OS_MESG_BLOCK);
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/conteepprobe.c b/lib/ultralib/src/io/conteepprobe.c
new file mode 100755
index 0000000..d24ff06
--- /dev/null
+++ b/lib/ultralib/src/io/conteepprobe.c
@@ -0,0 +1,32 @@
+#include "controller.h"
+#include "siint.h"
+
+s32 osEepromProbe(OSMesgQueue *mq) {
+ s32 ret = 0;
+ u16 type;
+ OSContStatus sdata;
+
+ __osSiGetAccess();
+ ret = __osEepStatus(mq, &sdata);
+ type = sdata.type & (CONT_EEPROM | CONT_EEP16K);
+
+ if (ret != 0) {
+ ret = 0;
+ } else {
+ switch (type) {
+ case CONT_EEPROM:
+ ret = EEPROM_TYPE_4K;
+ break;
+ case CONT_EEPROM | CONT_EEP16K:
+ ret = EEPROM_TYPE_16K;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ }
+
+ __osEepromRead16K = 0;
+ __osSiRelAccess();
+ return ret;
+}
diff --git a/lib/ultralib/src/io/conteepread.c b/lib/ultralib/src/io/conteepread.c
new file mode 100755
index 0000000..887ada6
--- /dev/null
+++ b/lib/ultralib/src/io/conteepread.c
@@ -0,0 +1,100 @@
+#include "macros.h"
+#include "PR/rcp.h"
+#include "controller.h"
+#include "siint.h"
+
+static void __osPackEepReadData(u8 address);
+OSPifRam __osEepPifRam ALIGNED(16);
+s32 __osEepromRead16K;
+
+s32 osEepromRead(OSMesgQueue *mq, u8 address, u8 *buffer)
+{
+ s32 ret = 0;
+ int i = 0;
+ u16 type;
+ u8 *ptr;
+ OSContStatus sdata;
+ __OSContEepromFormat eepromformat;
+
+ ptr = (u8 *)&__osEepPifRam.ramarray;
+ __osSiGetAccess();
+ ret = __osEepStatus(mq, &sdata);
+ type = sdata.type & (CONT_EEPROM | CONT_EEP16K);
+
+ if (ret != 0) {
+ __osSiRelAccess();
+ return ret;
+ }
+
+ switch (type) {
+ case CONT_EEPROM:
+ if (address >= EEPROM_MAXBLOCKS) {
+ ret = CONT_RANGE_ERROR;
+ }
+ break;
+ case CONT_EEPROM | CONT_EEP16K:
+ __osEepromRead16K = 1;
+ if (address >= EEP16K_MAXBLOCKS) {
+ //not technically possible
+ ret = CONT_RANGE_ERROR;
+ }
+ break;
+ default:
+ ret = CONT_NO_RESPONSE_ERROR;
+ break;
+ }
+
+ if (ret != 0) {
+ __osSiRelAccess();
+ return ret;
+ }
+
+ while (sdata.status & CONT_EEPROM_BUSY) {
+ __osEepStatus(mq, &sdata);
+ }
+
+ __osPackEepReadData(address);
+ ret = __osSiRawStartDma(OS_WRITE, &__osEepPifRam); //send command to pif
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ ret = __osSiRawStartDma(OS_READ, &__osEepPifRam); //recv response
+ __osContLastCmd = CONT_CMD_READ_EEPROM;
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ //skip the first 4 bytes
+ ptr++;
+ }
+
+ eepromformat = *(__OSContEepromFormat *)ptr;
+ ret = CHNL_ERR(eepromformat);
+
+ if (ret == 0) {
+ for (i = 0; i < ARRLEN(eepromformat.data); i++) {
+ *buffer++ = eepromformat.data[i];
+ }
+ }
+
+ __osSiRelAccess();
+ return ret;
+}
+
+static void __osPackEepReadData(u8 address) {
+ u8 *ptr = (u8 *)&__osEepPifRam.ramarray;
+ __OSContEepromFormat eepromformat;
+ int i;
+
+ __osEepPifRam.pifstatus = CONT_CMD_EXE;
+
+ eepromformat.txsize = CONT_CMD_READ_EEPROM_TX;
+ eepromformat.rxsize = CONT_CMD_READ_EEPROM_RX;
+ eepromformat.cmd = CONT_CMD_READ_EEPROM;
+ eepromformat.address = address;
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ *ptr++ = 0;
+ }
+
+ *(__OSContEepromFormat *)(ptr) = eepromformat;
+ ptr += sizeof(__OSContEepromFormat);
+ ptr[0] = CONT_CMD_END;
+}
diff --git a/lib/ultralib/src/io/conteepwrite.c b/lib/ultralib/src/io/conteepwrite.c
new file mode 100755
index 0000000..aa351fd
--- /dev/null
+++ b/lib/ultralib/src/io/conteepwrite.c
@@ -0,0 +1,158 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "controller.h"
+#include "siint.h"
+
+static void __osPackEepWriteData(u8 address, u8 *buffer);
+s32 osEepromWrite(OSMesgQueue *mq, u8 address, u8 *buffer)
+{
+ s32 ret = 0;
+ u16 type;
+ u8 *ptr = (u8 *)&__osEepPifRam.ramarray;
+ __OSContEepromFormat eepromformat;
+ OSContStatus sdata;
+ u8 temp[8];
+
+ __osSiGetAccess();
+ ret = __osEepStatus(mq, &sdata);
+
+ type = sdata.type & (CONT_EEPROM | CONT_EEP16K);
+
+ if (ret != 0) {
+ __osSiRelAccess();
+ return ret;
+ }
+
+ switch (type) {
+ case CONT_EEPROM:
+ if (address >= EEPROM_MAXBLOCKS) {
+ ret = CONT_RANGE_ERROR;
+ }
+ break;
+ case CONT_EEPROM | CONT_EEP16K:
+ if (address >= EEP16K_MAXBLOCKS) {
+ //not technically possible
+ ret = CONT_RANGE_ERROR;
+ }
+ if (__osEepromRead16K)
+ {
+ __osEepromRead16K = 0;
+ __osSiRelAccess();
+ osEepromRead(mq, (address ^ 1), temp);
+ __osSiGetAccess();
+ }
+ break;
+ default:
+ ret = CONT_NO_RESPONSE_ERROR;
+ break;
+ }
+
+ if (ret != 0) {
+ __osSiRelAccess();
+ return ret;
+ }
+
+ while (sdata.status & CONT_EEPROM_BUSY) {
+ __osEepStatus(mq, &sdata);
+ }
+
+ __osPackEepWriteData(address, buffer);
+ ret = __osSiRawStartDma(OS_WRITE, &__osEepPifRam); //send command to pif
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ ret = __osSiRawStartDma(OS_READ, &__osEepPifRam); //recv response
+ __osContLastCmd = CONT_CMD_WRITE_EEPROM;
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ //skip the first 4 bytes
+ ptr += 4;
+
+ eepromformat = *(__OSContEepromFormat *)ptr;
+
+ ret = CHNL_ERR(eepromformat);
+
+ __osSiRelAccess();
+ return ret;
+}
+
+static void __osPackEepWriteData(u8 address, u8 *buffer) {
+ u8 *ptr = (u8 *)&__osEepPifRam.ramarray;
+ __OSContEepromFormat eepromformat;
+ int i;
+
+ __osEepPifRam.pifstatus = CONT_CMD_EXE;
+
+ eepromformat.txsize = CONT_CMD_WRITE_EEPROM_TX;
+ eepromformat.rxsize = CONT_CMD_WRITE_EEPROM_RX;
+ eepromformat.cmd = CONT_CMD_WRITE_EEPROM;
+ eepromformat.address = address;
+
+ for (i = 0; i < ARRLEN(eepromformat.data); i++) {
+ eepromformat.data[i] = *buffer++;
+ }
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ *ptr++ = 0;
+ }
+
+ *(__OSContEepromFormat *)(ptr) = eepromformat;
+ ptr += sizeof(__OSContEepromFormat);
+ ptr[0] = CONT_CMD_END;
+}
+
+
+s32 __osEepStatus(OSMesgQueue *mq, OSContStatus *data) {
+ s32 ret = 0;
+ int i;
+ u8 *ptr = (u8 *)__osEepPifRam.ramarray;
+ __OSContRequesFormat requestformat;
+
+ for (i = 0; i < ARRLEN(__osEepPifRam.ramarray) + 1; i++) {
+ __osEepPifRam.ramarray[i] = 0;
+ }
+
+ __osEepPifRam.pifstatus = CONT_CMD_EXE;
+ ptr = (u8 *)__osEepPifRam.ramarray;
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ *ptr++ = CONT_CMD_REQUEST_STATUS;
+ }
+
+ requestformat.dummy = CONT_CMD_NOP;
+ requestformat.txsize = CONT_CMD_REQUEST_STATUS_TX;
+ requestformat.rxsize = CONT_CMD_REQUEST_STATUS_RX;
+ requestformat.cmd = CONT_CMD_REQUEST_STATUS;
+ requestformat.typeh = CONT_CMD_NOP;
+ requestformat.typel = CONT_CMD_NOP;
+ requestformat.status = CONT_CMD_NOP;
+ requestformat.dummy1 = CONT_CMD_NOP;
+ *(__OSContRequesFormat *)ptr = requestformat;
+ ptr += sizeof(__OSContRequesFormat);
+ *ptr = CONT_CMD_END;
+
+ ret = __osSiRawStartDma(OS_WRITE, &__osEepPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ __osContLastCmd = CONT_CMD_END;
+ ret = __osSiRawStartDma(OS_READ, &__osEepPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ptr = (u8 *)&__osEepPifRam;
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ *ptr++ = 0;
+ }
+
+ requestformat = *(__OSContRequesFormat *)ptr;
+ data->errno = CHNL_ERR(requestformat);
+ data->type = (requestformat.typel << 8) | requestformat.typeh;
+ data->status = requestformat.status;
+
+ if (data->errno != 0) {
+ return data->errno;
+ }
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/contpfs.c b/lib/ultralib/src/io/contpfs.c
new file mode 100755
index 0000000..5121426
--- /dev/null
+++ b/lib/ultralib/src/io/contpfs.c
@@ -0,0 +1,297 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+
+__OSInode __osPfsInodeCache ALIGNED(8);
+s32 __osPfsInodeCacheChannel = -1;
+u8 __osPfsInodeCacheBank = 250;
+
+u16 __osSumcalc(u8 *ptr, int length) {
+ int i;
+ u32 sum = 0;
+ u8 *tmp = ptr;
+
+ for (i = 0; i < length; i++) {
+ sum += *tmp++;
+ }
+
+ return sum;
+}
+
+s32 __osIdCheckSum(u16 *ptr, u16 *csum, u16 *icsum) {
+ u16 data = 0;
+ u32 j;
+
+ *icsum = 0;
+ *csum = *icsum;
+
+ for (j = 0; j < ((sizeof(__OSPackId) - sizeof(u32)) / sizeof(u8)); j += 2) {
+ data = *(u16 *)((u8 *)ptr + j);
+ *csum += data;
+ *icsum += ~data;
+ }
+
+ return 0;
+}
+
+s32 __osRepairPackId(OSPfs *pfs, __OSPackId *badid, __OSPackId *newid) {
+ s32 ret = 0;
+ u8 temp[BLOCKSIZE];
+ u8 comp[BLOCKSIZE];
+ u8 mask = 0;
+ int i;
+ int j = 0;
+ u16 index[4];
+
+ newid->repaired = -1;
+ newid->random = osGetCount();
+ newid->serial_mid = badid->serial_mid;
+ newid->serial_low = badid->serial_low;
+
+ SET_ACTIVEBANK_TO_ZERO;
+
+ do {
+ ERRCK(__osPfsSelectBank(pfs, j));
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, 0, temp));
+
+ temp[0] = j | 0x80;
+
+ for (i = 1; i < BLOCKSIZE; i++) {
+ temp[i] = ~temp[i];
+ }
+
+ ERRCK(__osContRamWrite(pfs->queue, pfs->channel, 0, temp, FALSE));
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, 0, comp));
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ if (comp[i] != temp[i]) {
+ break;
+ }
+ }
+
+ if (i != BLOCKSIZE) {
+ break;
+ }
+
+ if (j > 0) {
+ ERRCK(__osPfsSelectBank(pfs, 0));
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, 0, (u8*)temp));
+
+ if (temp[0] != 0x80) {
+ break;
+ }
+ }
+
+ j++;
+ } while (j < PFS_MAX_BANKS);
+
+ SET_ACTIVEBANK_TO_ZERO;
+
+ if (j > 0) {
+ mask = 1;
+ } else {
+ mask = 0;
+ }
+
+ newid->deviceid = (badid->deviceid & (u16)~1) | mask;
+ newid->banks = j;
+ newid->version = badid->version;
+ __osIdCheckSum((u16*)newid, &newid->checksum, &newid->inverted_checksum);
+ index[0] = PFS_ID_0AREA;
+ index[1] = PFS_ID_1AREA;
+ index[2] = PFS_ID_2AREA;
+ index[3] = PFS_ID_3AREA;
+
+ for (i = 0; i < ARRLEN(index); i++) {
+ ERRCK(__osContRamWrite(pfs->queue, pfs->channel, index[i], (u8*)newid, TRUE));
+ }
+
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, PFS_ID_0AREA, (u8*)temp));
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ if (temp[i] != ((u8 *)newid)[i]) {
+ return PFS_ERR_DEVICE;
+ }
+ }
+ return 0;
+}
+
+s32 __osCheckPackId(OSPfs *pfs, __OSPackId *temp) {
+ u16 index[4];
+ s32 ret = 0;
+ u16 sum;
+ u16 isum;
+ int i;
+ int j;
+
+ SET_ACTIVEBANK_TO_ZERO;
+ index[0] = PFS_ID_0AREA;
+ index[1] = PFS_ID_1AREA;
+ index[2] = PFS_ID_2AREA;
+ index[3] = PFS_ID_3AREA;
+ for (i = 1; i < ARRLEN(index); i++) {
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, index[i], (u8*)temp));
+ __osIdCheckSum((u16 *)temp, &sum, &isum);
+ if (temp->checksum == sum && temp->inverted_checksum == isum) {
+ break;
+ }
+ }
+
+ if (i == ARRLEN(index)) {
+ return PFS_ERR_ID_FATAL;
+ }
+
+ for (j = 0; j < ARRLEN(index); j++) {
+ if (j != i) {
+ ERRCK(__osContRamWrite(pfs->queue, pfs->channel, index[j], (u8*)temp, TRUE));
+ }
+ }
+
+ return 0;
+}
+
+s32 __osGetId(OSPfs *pfs) {
+ int k;
+ u16 sum;
+ u16 isum;
+ u8 temp[BLOCKSIZE];
+ __OSPackId newid;
+ s32 ret;
+ __OSPackId *id;
+
+ SET_ACTIVEBANK_TO_ZERO;
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, PFS_ID_0AREA, (u8*)temp));
+ __osIdCheckSum((u16*)temp, &sum, &isum);
+ id = (__OSPackId*)temp;
+
+ if (id->checksum != sum || id->inverted_checksum != isum) {
+ ret = __osCheckPackId(pfs, id);
+
+ if (ret == PFS_ERR_ID_FATAL) {
+ ERRCK(__osRepairPackId(pfs, id, &newid));
+ id = &newid;
+ } else if (ret != 0) {
+ return ret;
+ }
+ }
+
+ if ((id->deviceid & 1) == 0) {
+ ERRCK(__osRepairPackId(pfs, id, &newid));
+ id = &newid;
+
+ if ((id->deviceid & 1) == 0) {
+ return PFS_ERR_DEVICE;
+ }
+ }
+
+ bcopy(id, pfs->id, BLOCKSIZE);
+ pfs->version = id->version;
+ pfs->banks = id->banks;
+ pfs->inode_start_page = 1 + DEF_DIR_PAGES + (2 * pfs->banks);
+ pfs->dir_size = 16;
+ pfs->inode_table = PFS_ONE_PAGE;
+ pfs->minode_table = (1 + pfs->banks) * PFS_ONE_PAGE;
+ pfs->dir_table = pfs->minode_table + pfs->banks * PFS_ONE_PAGE;
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, PFS_LABEL_AREA, pfs->label));
+ return 0;
+}
+
+s32 __osCheckId(OSPfs *pfs) {
+ u8 temp[BLOCKSIZE];
+ s32 ret;
+
+ if (pfs->activebank != 0) {
+ ret = __osPfsSelectBank(pfs, 0);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = __osPfsSelectBank(pfs, 0);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = __osContRamRead(pfs->queue, pfs->channel, PFS_ID_0AREA, (u8*)temp);
+
+ if (ret != 0) {
+ if (ret != PFS_ERR_NEW_PACK) {
+ return ret;
+ } else {
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, PFS_ID_0AREA, (u8*)temp));
+ }
+ }
+
+ if (bcmp(pfs->id, temp, BLOCKSIZE) != 0) {
+ return PFS_ERR_NEW_PACK;
+ }
+
+ return 0;
+}
+
+s32 __osPfsRWInode(OSPfs *pfs, __OSInode *inode, u8 flag, u8 bank) {
+ u8 sum;
+ int j;
+ s32 ret;
+ int offset;
+ u8 *addr;
+
+ if (flag == PFS_READ && bank == __osPfsInodeCacheBank && (pfs->channel == __osPfsInodeCacheChannel)) {
+ bcopy(&__osPfsInodeCache, inode, sizeof(__OSInode));
+ return 0;
+ }
+
+ SET_ACTIVEBANK_TO_ZERO;
+
+ if (bank > 0) {
+ offset = 1;
+ } else {
+ offset = pfs->inode_start_page;
+ }
+
+ if (flag == PFS_WRITE) {
+ inode->inode_page[0].inode_t.page = __osSumcalc((u8*)&inode->inode_page[offset], (PFS_INODE_SIZE_PER_PAGE - offset) * 2);
+ }
+
+ for (j = 0; j < PFS_ONE_PAGE; j++) {
+ addr = ((u8 *)inode->inode_page + j * BLOCKSIZE);
+
+ if (flag == PFS_WRITE) {
+ ret = __osContRamWrite(pfs->queue, pfs->channel, pfs->inode_table + bank * PFS_ONE_PAGE + j, addr, FALSE);
+ ret = __osContRamWrite(pfs->queue, pfs->channel, pfs->minode_table + bank * PFS_ONE_PAGE + j, addr, FALSE);
+ } else {
+ ret = __osContRamRead(pfs->queue, pfs->channel, pfs->inode_table + bank * 8 + j, addr);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ if (flag == PFS_READ) {
+ sum = __osSumcalc((u8*)&inode->inode_page[offset], (PFS_INODE_SIZE_PER_PAGE - offset) * 2);
+ if (sum != inode->inode_page[0].inode_t.page) {
+ for (j = 0; j < PFS_ONE_PAGE; j++) {
+ addr = ((u8 *)inode->inode_page + j * BLOCKSIZE);
+ ret = __osContRamRead(pfs->queue, pfs->channel, pfs->minode_table + bank * PFS_ONE_PAGE + j, addr);
+ }
+
+ sum = __osSumcalc((u8*)&inode->inode_page[offset], (PFS_INODE_SIZE_PER_PAGE - offset) * 2);
+
+ if (sum != inode->inode_page[0].inode_t.page) {
+ return PFS_ERR_INCONSISTENT;
+ }
+
+ for (j = 0; j < PFS_ONE_PAGE; j++) {
+ addr = ((u8 *)inode->inode_page + j * BLOCKSIZE);
+ ret = __osContRamWrite(pfs->queue, pfs->channel, pfs->inode_table + bank * PFS_ONE_PAGE + j, addr, FALSE);
+ }
+ }
+ }
+
+ __osPfsInodeCacheBank = bank;
+ bcopy(inode, &__osPfsInodeCache, sizeof(__OSInode));
+ __osPfsInodeCacheChannel = pfs->channel;
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/contquery.c b/lib/ultralib/src/io/contquery.c
new file mode 100755
index 0000000..d042ecf
--- /dev/null
+++ b/lib/ultralib/src/io/contquery.c
@@ -0,0 +1,25 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+s32 osContStartQuery(OSMesgQueue *mq) {
+ s32 ret = 0;
+
+ __osSiGetAccess();
+
+ if (__osContLastCmd != CONT_CMD_REQUEST_STATUS) {
+ __osPackRequestData(CONT_CMD_REQUEST_STATUS);
+ ret = __osSiRawStartDma(OS_WRITE, __osContPifRam.ramarray);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ }
+
+ ret = __osSiRawStartDma(OS_READ, __osContPifRam.ramarray);
+ __osContLastCmd = CONT_CMD_REQUEST_STATUS;
+ __osSiRelAccess();
+ return ret;
+}
+
+void osContGetQuery(OSContStatus *data) {
+ u8 pattern;
+ __osContGetInitData(&pattern, data);
+}
diff --git a/lib/ultralib/src/io/contramread.c b/lib/ultralib/src/io/contramread.c
new file mode 100644
index 0000000..0afa93a
--- /dev/null
+++ b/lib/ultralib/src/io/contramread.c
@@ -0,0 +1,75 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "controller.h"
+#include "siint.h"
+
+s32 __osPfsLastChannel = -1;
+
+#define READFORMAT(ptr) ((__OSContRamReadFormat*)(ptr))
+
+s32 __osContRamRead(OSMesgQueue* mq, int channel, u16 address, u8* buffer) {
+ s32 ret;
+ s32 i;
+ u8* ptr;
+ s32 retry = 2;
+
+ __osSiGetAccess();
+
+ do {
+ ptr = (u8*)&__osPfsPifRam;
+
+ if (__osContLastCmd != CONT_CMD_READ_PAK || __osPfsLastChannel != channel) {
+ __osContLastCmd = CONT_CMD_READ_PAK;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = CONT_CMD_REQUEST_STATUS;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ READFORMAT(ptr)->dummy = CONT_CMD_NOP;
+ READFORMAT(ptr)->txsize = CONT_CMD_READ_PAK_TX;
+ READFORMAT(ptr)->rxsize = CONT_CMD_READ_PAK_RX;
+ READFORMAT(ptr)->cmd = CONT_CMD_READ_PAK;
+ READFORMAT(ptr)->datacrc = 0xFF;
+
+ ptr[sizeof(__OSContRamReadFormat)] = CONT_CMD_END;
+ } else {
+ ptr += channel;
+ }
+
+ READFORMAT(ptr)->addrh = address >> 3;
+ READFORMAT(ptr)->addrl = (u8)(__osContAddressCrc(address) | (address << 5));
+
+ __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = CHNL_ERR(*READFORMAT(ptr));
+
+ if (!ret) {
+ if (__osContDataCrc(&READFORMAT(ptr)->data) != READFORMAT(ptr)->datacrc) {
+ ret = __osPfsGetStatus(mq, channel);
+
+ if (ret) {
+ break;
+ }
+
+ ret = PFS_ERR_CONTRFAIL;
+ } else {
+ bcopy(&READFORMAT(ptr)->data, buffer, BLOCKSIZE);
+ }
+ } else {
+ ret = PFS_ERR_NOPACK;
+ }
+ if (ret != PFS_ERR_CONTRFAIL) {
+ break;
+ }
+ } while (0 <= retry--);
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/contramwrite.c b/lib/ultralib/src/io/contramwrite.c
new file mode 100644
index 0000000..1478480
--- /dev/null
+++ b/lib/ultralib/src/io/contramwrite.c
@@ -0,0 +1,77 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "controller.h"
+#include "siint.h"
+
+extern s32 __osPfsLastChannel;
+
+#define READFORMAT(ptr) ((__OSContRamReadFormat*)(ptr))
+
+s32 __osContRamWrite(OSMesgQueue* mq, int channel, u16 address, u8* buffer, int force) {
+ s32 ret = 0;
+ s32 i;
+ u8* ptr;
+ s32 retry = 2;
+ u8 crc;
+
+ if ((force != TRUE) && (address < PFS_LABEL_AREA) && (address != 0)) {
+ return 0;
+ }
+
+ __osSiGetAccess();
+
+ do {
+ ptr = __osPfsPifRam.ramarray;
+
+ if (__osContLastCmd != CONT_CMD_WRITE_PAK || __osPfsLastChannel != channel) {
+ __osContLastCmd = CONT_CMD_WRITE_PAK;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = CONT_CMD_REQUEST_STATUS;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ READFORMAT(ptr)->dummy = CONT_CMD_NOP;
+ READFORMAT(ptr)->txsize = CONT_CMD_WRITE_PAK_TX;
+ READFORMAT(ptr)->rxsize = CONT_CMD_WRITE_PAK_RX;
+ READFORMAT(ptr)->cmd = CONT_CMD_WRITE_PAK;
+ READFORMAT(ptr)->datacrc = 0xFF;
+
+ ptr[sizeof(__OSContRamReadFormat)] = CONT_CMD_END;
+ } else {
+ ptr += channel;
+ }
+
+ READFORMAT(ptr)->addrh = address >> 3;
+ READFORMAT(ptr)->addrl = ((address << 5) | __osContAddressCrc(address));
+
+ bcopy(buffer, READFORMAT(ptr)->data, BLOCKSIZE);
+
+ ret = __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ crc = __osContDataCrc(buffer);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = CHNL_ERR(*READFORMAT(ptr));
+
+ if (!ret) {
+ if (crc != READFORMAT(ptr)->datacrc) {
+ if ((ret = __osPfsGetStatus(mq, channel))) {
+ break;
+ } else {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ }
+ } else {
+ ret = PFS_ERR_NOPACK;
+ }
+ } while ((ret == PFS_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+} \ No newline at end of file
diff --git a/lib/ultralib/src/io/contreaddata.c b/lib/ultralib/src/io/contreaddata.c
new file mode 100644
index 0000000..60b9493
--- /dev/null
+++ b/lib/ultralib/src/io/contreaddata.c
@@ -0,0 +1,68 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+static void __osPackReadData(void);
+
+s32 osContStartReadData(OSMesgQueue* mq) {
+ s32 ret = 0;
+
+ __osSiGetAccess();
+
+ if (__osContLastCmd != CONT_CMD_READ_BUTTON) {
+ __osPackReadData();
+ ret = __osSiRawStartDma(OS_WRITE, __osContPifRam.ramarray);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ }
+
+ ret = __osSiRawStartDma(OS_READ, __osContPifRam.ramarray);
+ __osContLastCmd = CONT_CMD_READ_BUTTON;
+ __osSiRelAccess();
+
+ return ret;
+}
+
+void osContGetReadData(OSContPad* data) {
+ u8* ptr = __osContPifRam.ramarray;
+ __OSContReadFormat readformat;
+ int i;
+
+ for (i = 0; i < __osMaxControllers; i++, ptr += sizeof(__OSContReadFormat), data++) {
+ readformat = *(__OSContReadFormat*)ptr;
+ data->errno = CHNL_ERR(readformat);
+
+ if (data->errno != 0) {
+ continue;
+ }
+
+ data->button = readformat.button;
+ data->stick_x = readformat.stick_x;
+ data->stick_y = readformat.stick_y;
+ }
+}
+
+static void __osPackReadData(void) {
+ u8* ptr = __osContPifRam.ramarray;
+ __OSContReadFormat readformat;
+ int i;
+
+ for (i = 0; i < ARRLEN(__osContPifRam.ramarray); i++) {
+ __osContPifRam.ramarray[i] = 0;
+ }
+
+ __osContPifRam.pifstatus = CONT_CMD_EXE;
+ readformat.dummy = CONT_CMD_NOP;
+ readformat.txsize = CONT_CMD_READ_BUTTON_TX;
+ readformat.rxsize = CONT_CMD_READ_BUTTON_RX;
+ readformat.cmd = CONT_CMD_READ_BUTTON;
+ readformat.button = 0xFFFF;
+ readformat.stick_x = -1;
+ readformat.stick_y = -1;
+
+ for (i = 0; i < __osMaxControllers; i++) {
+ *(__OSContReadFormat*)ptr = readformat;
+ ptr += sizeof(__OSContReadFormat);
+ }
+
+ *ptr = CONT_CMD_END;
+}
diff --git a/lib/ultralib/src/io/contreset.c b/lib/ultralib/src/io/contreset.c
new file mode 100644
index 0000000..ab30a47
--- /dev/null
+++ b/lib/ultralib/src/io/contreset.c
@@ -0,0 +1,51 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+void __osPackResetData(void);
+
+s32 osContReset(OSMesgQueue *mq, OSContStatus *data) {
+ u8 pattern;
+ s32 ret;
+
+ __osSiGetAccess();
+
+ if (__osContLastCmd != CONT_CMD_RESET) {
+ __osPackResetData();
+
+ ret = __osSiRawStartDma(OS_WRITE, __osContPifRam.ramarray);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = __osSiRawStartDma(OS_READ, __osContPifRam.ramarray);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ __osPackRequestData(CONT_CMD_RESET);
+
+ ret = __osSiRawStartDma(OS_WRITE, __osContPifRam.ramarray);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ __osContLastCmd = CONT_CMD_RESET;
+ }
+
+ ret = __osSiRawStartDma(OS_READ, __osContPifRam.ramarray);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ __osContGetInitData(&pattern, data);
+ __osSiRelAccess();
+
+ return ret;
+}
+
+void __osPackResetData(void) {
+ u8 *ptr;
+ int i;
+
+ __osContPifRam.pifstatus = CONT_CMD_EXE;
+ ptr = __osContPifRam.ramarray;
+
+ for (i = 0; i < MAXCONTROLLERS; i++) {
+ *ptr++ = CONT_CMD_CHANNEL_RESET;
+ }
+
+ *ptr = CONT_CMD_END;
+}
diff --git a/lib/ultralib/src/io/controller.c b/lib/ultralib/src/io/controller.c
new file mode 100644
index 0000000..db9b769
--- /dev/null
+++ b/lib/ultralib/src/io/controller.c
@@ -0,0 +1,99 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 __osContinitialized = 0;
+
+OSPifRam __osContPifRam ALIGNED(16);
+u8 __osContLastCmd;
+u8 __osMaxControllers;
+
+OSTimer __osEepromTimer;
+OSMesgQueue __osEepromTimerQ ALIGNED(8);
+OSMesg __osEepromTimerMsg;
+
+s32 osContInit(OSMesgQueue* mq, u8* bitpattern, OSContStatus* data) {
+ OSMesg dummy;
+ s32 ret = 0;
+ OSTime t;
+ OSTimer mytimer;
+ OSMesgQueue timerMesgQueue;
+
+ if (__osContinitialized != 0) {
+ return 0;
+ }
+
+ __osContinitialized = 1;
+
+ t = osGetTime();
+ if (t < OS_USEC_TO_CYCLES(500000)) {
+ osCreateMesgQueue(&timerMesgQueue, &dummy, 1);
+ osSetTimer(&mytimer, OS_USEC_TO_CYCLES(500000) - t, 0, &timerMesgQueue, &dummy);
+ osRecvMesg(&timerMesgQueue, &dummy, OS_MESG_BLOCK);
+ }
+
+ __osMaxControllers = 4;
+
+ __osPackRequestData(CONT_CMD_REQUEST_STATUS);
+
+ ret = __osSiRawStartDma(OS_WRITE, __osContPifRam.ramarray);
+ osRecvMesg(mq, &dummy, OS_MESG_BLOCK);
+
+ ret = __osSiRawStartDma(OS_READ, __osContPifRam.ramarray);
+ osRecvMesg(mq, &dummy, OS_MESG_BLOCK);
+
+ __osContGetInitData(bitpattern, data);
+ __osContLastCmd = CONT_CMD_REQUEST_STATUS;
+ __osSiCreateAccessQueue();
+ osCreateMesgQueue(&__osEepromTimerQ, &__osEepromTimerMsg, 1);
+
+ return ret;
+}
+
+void __osContGetInitData(u8* pattern, OSContStatus* data) {
+ u8* ptr;
+ __OSContRequesFormat requestHeader;
+ s32 i;
+ u8 bits;
+
+ bits = 0;
+ ptr = __osContPifRam.ramarray;
+ for (i = 0; i < __osMaxControllers; i++, ptr += sizeof(requestHeader), data++) {
+ requestHeader = *(__OSContRequesFormat*)ptr;
+ data->errno = CHNL_ERR(requestHeader);
+ if (data->errno == 0) {
+ data->type = requestHeader.typel << 8 | requestHeader.typeh;
+ data->status = requestHeader.status;
+
+ bits |= 1 << i;
+ }
+ }
+ *pattern = bits;
+}
+
+void __osPackRequestData(u8 cmd) {
+ u8* ptr;
+ __OSContRequesFormat requestHeader;
+ s32 i;
+
+ for (i = 0; i < ARRLEN(__osContPifRam.ramarray); i++) {
+ __osContPifRam.ramarray[i] = 0;
+ }
+
+ __osContPifRam.pifstatus = CONT_CMD_EXE;
+ ptr = __osContPifRam.ramarray;
+ requestHeader.dummy = CONT_CMD_NOP;
+ requestHeader.txsize = CONT_CMD_RESET_TX;
+ requestHeader.rxsize = CONT_CMD_RESET_RX;
+ requestHeader.cmd = cmd;
+ requestHeader.typeh = CONT_CMD_NOP;
+ requestHeader.typel = CONT_CMD_NOP;
+ requestHeader.status = CONT_CMD_NOP;
+ requestHeader.dummy1 = CONT_CMD_NOP;
+
+ for (i = 0; i < __osMaxControllers; i++) {
+ *(__OSContRequesFormat*)ptr = requestHeader;
+ ptr += sizeof(requestHeader);
+ }
+ *ptr = CONT_CMD_END;
+}
diff --git a/lib/ultralib/src/io/controller.h b/lib/ultralib/src/io/controller.h
new file mode 100755
index 0000000..efce970
--- /dev/null
+++ b/lib/ultralib/src/io/controller.h
@@ -0,0 +1,257 @@
+#ifndef _CONTROLLER_H
+#define _CONTROLLER_H
+
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+//should go somewhere else but
+#define ARRLEN(x) ((s32)(sizeof(x) / sizeof(x[0])))
+#define CHNL_ERR(format) (((format).rxsize & CHNL_ERR_MASK) >> 4)
+
+typedef struct
+{
+ /* 0x0 */ u32 ramarray[15];
+ /* 0x3C */ u32 pifstatus;
+} OSPifRam;
+
+typedef struct
+{
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u16 button;
+ /* 0x6 */ s8 stick_x;
+ /* 0x7 */ s8 stick_y;
+} __OSContReadFormat;
+
+typedef struct
+{
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u8 typeh;
+ /* 0x5 */ u8 typel;
+ /* 0x6 */ u8 status;
+ /* 0x7 */ u8 dummy1;
+} __OSContRequesFormat;
+
+typedef struct
+{
+ /* 0x0 */ u8 txsize;
+ /* 0x1 */ u8 rxsize;
+ /* 0x2 */ u8 cmd;
+ /* 0x3 */ u8 typeh;
+ /* 0x4 */ u8 typel;
+ /* 0x5 */ u8 status;
+} __OSContRequesFormatShort;
+
+typedef struct
+{
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u8 addrh;
+ /* 0x5 */ u8 addrl;
+ /* 0x6 */ u8 data[BLOCKSIZE];
+ /* 0x26 */ u8 datacrc;
+} __OSContRamReadFormat;
+
+typedef union {
+ /* 0x0 */ struct
+ {
+ /* 0x0 */ u8 bank;
+ /* 0x1 */ u8 page;
+ } inode_t;
+ /* 0x0 */ u16 ipage;
+} __OSInodeUnit;
+
+typedef struct
+{
+ /* 0x0 */ u32 game_code;
+ /* 0x4 */ u16 company_code;
+ /* 0x6 */ __OSInodeUnit start_page;
+ /* 0x8 */ u8 status;
+ /* 0x9 */ s8 reserved;
+ /* 0xA */ u16 data_sum;
+ /* 0xC */ u8 ext_name[PFS_FILE_EXT_LEN];
+ /* 0x10 */ u8 game_name[PFS_FILE_NAME_LEN];
+} __OSDir;
+
+typedef struct
+{
+ /* 0x0 */ __OSInodeUnit inode_page[128];
+} __OSInode;
+
+typedef struct
+{
+ /* 0x0 */ u32 repaired;
+ /* 0x4 */ u32 random;
+ /* 0x8 */ u64 serial_mid;
+ /* 0x10 */ u64 serial_low;
+ /* 0x18 */ u16 deviceid;
+ /* 0x1A */ u8 banks;
+ /* 0x1B */ u8 version;
+ /* 0x1C */ u16 checksum;
+ /* 0x1E */ u16 inverted_checksum;
+} __OSPackId;
+
+typedef struct
+{
+ /* 0x0 */ u8 txsize;
+ /* 0x1 */ u8 rxsize;
+ /* 0x2 */ u8 cmd;
+ /* 0x3 */ u8 address;
+ /* 0x4 */ u8 data[EEPROM_BLOCK_SIZE];
+} __OSContEepromFormat;
+
+// Joybus commands
+//from: http://en64.shoutwiki.com/wiki/SI_Registers_Detailed#CONT_CMD_Usage
+#define CONT_CMD_REQUEST_STATUS 0
+#define CONT_CMD_READ_BUTTON 1
+#define CONT_CMD_READ_PAK 2
+#define CONT_CMD_WRITE_PAK 3
+#define CONT_CMD_READ_EEPROM 4
+#define CONT_CMD_WRITE_EEPROM 5
+#define CONT_CMD_READ36_VOICE 9
+#define CONT_CMD_WRITE20_VOICE 10
+#define CONT_CMD_READ2_VOICE 11
+#define CONT_CMD_WRITE4_VOICE 12
+#define CONT_CMD_SWRITE_VOICE 13
+#define CONT_CMD_CHANNEL_RESET 0xFD
+#define CONT_CMD_RESET 0xFF
+
+// Bytes transmitted for each joybus command
+#define CONT_CMD_REQUEST_STATUS_TX 1
+#define CONT_CMD_READ_BUTTON_TX 1
+#define CONT_CMD_READ_PAK_TX 3
+#define CONT_CMD_WRITE_PAK_TX 35
+#define CONT_CMD_READ_EEPROM_TX 2
+#define CONT_CMD_WRITE_EEPROM_TX 10
+#define CONT_CMD_READ36_VOICE_TX 3
+#define CONT_CMD_WRITE20_VOICE_TX 23
+#define CONT_CMD_READ2_VOICE_TX 3
+#define CONT_CMD_WRITE4_VOICE_TX 7
+#define CONT_CMD_SWRITE_VOICE_TX 3
+#define CONT_CMD_RESET_TX 1
+
+// Bytes received for each joybus command
+#define CONT_CMD_REQUEST_STATUS_RX 3
+#define CONT_CMD_READ_BUTTON_RX 4
+#define CONT_CMD_READ_PAK_RX 33
+#define CONT_CMD_WRITE_PAK_RX 1
+#define CONT_CMD_READ_EEPROM_RX 8
+#define CONT_CMD_WRITE_EEPROM_RX 1
+#define CONT_CMD_READ36_VOICE_RX 37
+#define CONT_CMD_WRITE20_VOICE_RX 1
+#define CONT_CMD_READ2_VOICE_RX 3
+#define CONT_CMD_WRITE4_VOICE_RX 1
+#define CONT_CMD_SWRITE_VOICE_RX 1
+#define CONT_CMD_RESET_RX 3
+
+#define CONT_CMD_NOP 0xff
+#define CONT_CMD_END 0xfe //indicates end of a command
+#define CONT_CMD_EXE 1 //set pif ram status byte to this to do a command
+
+#define DIR_STATUS_EMPTY 0
+#define DIR_STATUS_UNKNOWN 1
+#define DIR_STATUS_OCCUPIED 2
+
+// Controller accessory addresses
+// https://github.com/joeldipops/TransferBoy/blob/master/docs/TransferPakReference.md
+
+// Accesory detection
+#define CONT_ADDR_DETECT 0x8000
+// Rumble
+#define CONT_ADDR_RUMBLE 0xC000
+// Controller Pak
+// Transfer Pak
+#define CONT_ADDR_GB_POWER 0x8000 // Same as the detection address, but semantically different
+#define CONT_ADDR_GB_BANK 0xA000
+#define CONT_ADDR_GB_STATUS 0xB000
+
+// Addresses sent to controller accessories are in blocks, not bytes
+#define CONT_BLOCKS(x) ((x) / BLOCKSIZE)
+
+// Block addresses of the above
+#define CONT_BLOCK_DETECT CONT_BLOCKS(CONT_ADDR_DETECT)
+#define CONT_BLOCK_RUMBLE CONT_BLOCKS(CONT_ADDR_RUMBLE)
+#define CONT_BLOCK_GB_POWER CONT_BLOCKS(CONT_ADDR_GB_POWER)
+#define CONT_BLOCK_GB_BANK CONT_BLOCKS(CONT_ADDR_GB_BANK)
+#define CONT_BLOCK_GB_STATUS CONT_BLOCKS(CONT_ADDR_GB_STATUS)
+
+
+// Transfer pak
+
+#define GB_POWER_ON 0x84
+#define GB_POWER_OFF 0xFE
+
+
+typedef struct
+{
+ /* 0x0 */ __OSInode inode;
+ /* 0x100 */ u8 bank;
+ /* 0x101 */ u8 map[PFS_INODE_DIST_MAP];
+} __OSInodeCache;
+
+extern s32 __osEepStatus(OSMesgQueue *, OSContStatus *);
+u16 __osSumcalc(u8 *ptr, int length);
+s32 __osIdCheckSum(u16 *ptr, u16 *csum, u16 *icsum);
+s32 __osRepairPackId(OSPfs *pfs, __OSPackId *badid, __OSPackId *newid);
+s32 __osCheckPackId(OSPfs *pfs, __OSPackId *temp);
+s32 __osGetId(OSPfs *pfs);
+s32 __osCheckId(OSPfs *pfs);
+s32 __osPfsRWInode(OSPfs *pfs, __OSInode *inode, u8 flag, u8 bank);
+s32 __osPfsSelectBank(OSPfs *pfs, u8 bank);
+s32 __osPfsDeclearPage(OSPfs *pfs, __OSInode *inode, int file_size_in_pages, int *first_page, u8 bank, int *decleared, int *last_page);
+s32 __osPfsReleasePages(OSPfs *pfs, __OSInode *inode, u8 start_page, u8 bank, __OSInodeUnit *last_page);
+s32 __osBlockSum(OSPfs *pfs, u8 page_no, u16 *sum, u8 bank);
+s32 __osContRamRead(OSMesgQueue *mq, int channel, u16 address, u8 *buffer);
+s32 __osContRamWrite(OSMesgQueue *mq, int channel, u16 address, u8 *buffer, int force);
+void __osContGetInitData(u8 *pattern, OSContStatus *data);
+void __osPackRequestData(u8 cmd);
+void __osPfsRequestData(u8 cmd);
+void __osPfsGetInitData(u8* pattern, OSContStatus* data);
+u8 __osContAddressCrc(u16 addr);
+u8 __osContDataCrc(u8 *data);
+s32 __osPfsGetStatus(OSMesgQueue *queue, int channel);
+
+extern u8 __osContLastCmd;
+extern OSTimer __osEepromTimer;
+extern OSMesg __osEepromTimerMsg;
+extern OSMesgQueue __osEepromTimerQ;
+extern OSPifRam __osEepPifRam;
+extern OSPifRam __osContPifRam;
+extern OSPifRam __osPfsPifRam;
+extern u8 __osMaxControllers;
+
+//some version of this almost certainly existed since there's plenty of times where it's used right before a return 0
+#define ERRCK(fn) \
+ ret = fn; \
+ if (ret != 0) \
+ return ret;
+
+#define SET_ACTIVEBANK_TO_ZERO \
+ if (pfs->activebank != 0) \
+ { \
+ ERRCK(__osPfsSelectBank(pfs, 0)) \
+ }
+
+#define PFS_CHECK_ID \
+ if (__osCheckId(pfs) == PFS_ERR_NEW_PACK) \
+ return PFS_ERR_NEW_PACK;
+
+#define PFS_CHECK_STATUS \
+ if ((pfs->status & PFS_INITIALIZED) == 0) \
+ return PFS_ERR_INVALID;
+
+#define PFS_GET_STATUS \
+ __osSiGetAccess(); \
+ ret = __osPfsGetStatus(queue, channel); \
+ __osSiRelAccess(); \
+ if (ret != 0) \
+ return ret;
+
+#endif
diff --git a/lib/ultralib/src/io/controller_gbpak.h b/lib/ultralib/src/io/controller_gbpak.h
new file mode 100644
index 0000000..db98bd4
--- /dev/null
+++ b/lib/ultralib/src/io/controller_gbpak.h
@@ -0,0 +1,8 @@
+#ifndef _CONTROLLER_GBPAK_H
+#define _CONTROLLER_GBPAK_H
+
+extern OSTimer __osGbpakTimer;
+extern OSMesg __osGbpakTimerMsg;
+extern OSMesgQueue __osGbpakTimerQ;
+
+#endif
diff --git a/lib/ultralib/src/io/controller_voice.h b/lib/ultralib/src/io/controller_voice.h
new file mode 100644
index 0000000..7223d06
--- /dev/null
+++ b/lib/ultralib/src/io/controller_voice.h
@@ -0,0 +1,59 @@
+#ifndef CONTROLLER_VOICE_H
+#define CONTROLLER_VOICE_H
+
+#include <PR/ultratypes.h>
+
+typedef struct {
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u8 addrh;
+ /* 0x5 */ u8 addrl;
+ /* 0x6 */ u8 data[2];
+ /* 0x8 */ u8 datacrc;
+} __OSVoiceRead2Format;
+
+typedef struct {
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u8 addrh;
+ /* 0x5 */ u8 addrl;
+ /* 0x6 */ u8 data[36];
+ /* 0x2A */ u8 datacrc;
+} __OSVoiceRead36Format;
+
+typedef struct {
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u8 addrh;
+ /* 0x5 */ u8 addrl;
+ /* 0x6 */ u8 data[4];
+ /* 0xA */ u8 datacrc;
+} __OSVoiceWrite4Format;
+
+typedef struct {
+ /* 0x0 */ u8 dummy;
+ /* 0x1 */ u8 txsize;
+ /* 0x2 */ u8 rxsize;
+ /* 0x3 */ u8 cmd;
+ /* 0x4 */ u8 addrh;
+ /* 0x5 */ u8 addrl;
+ /* 0x6 */ u8 data[20];
+ /* 0x1A */ u8 datacrc;
+} __OSVoiceWrite20Format;
+
+typedef struct {
+ /* 0x0 */ u8 txsize;
+ /* 0x1 */ u8 rxsize;
+ /* 0x2 */ u8 cmd;
+ /* 0x3 */ u8 data;
+ /* 0x4 */ u8 scrc;
+ /* 0x5 */ u8 datacrc;
+} __OSVoiceSWriteFormat;
+
+#endif // CONTROLLER_VOICE_H
diff --git a/lib/ultralib/src/io/contsetch.c b/lib/ultralib/src/io/contsetch.c
new file mode 100644
index 0000000..eff63a6
--- /dev/null
+++ b/lib/ultralib/src/io/contsetch.c
@@ -0,0 +1,19 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+s32 osContSetCh(u8 ch) {
+ s32 ret = 0;
+
+ __osSiGetAccess();
+
+ if (ch > MAXCONTROLLERS) {
+ __osMaxControllers = MAXCONTROLLERS;
+ } else {
+ __osMaxControllers = ch;
+ }
+
+ __osContLastCmd = CONT_CMD_END;
+ __osSiRelAccess();
+ return ret;
+} \ No newline at end of file
diff --git a/lib/ultralib/src/io/crc.c b/lib/ultralib/src/io/crc.c
new file mode 100644
index 0000000..e266152
--- /dev/null
+++ b/lib/ultralib/src/io/crc.c
@@ -0,0 +1,64 @@
+#include "PR/os_internal.h"
+
+u8 __osContAddressCrc(u16 addr) {
+ u32 temp = 0;
+ u32 i;
+
+ for (i = 0x400; i != 0;) {
+ temp <<= 1;
+
+ if (addr & i) {
+ if (temp & 0x20) {
+ temp ^= 0x14;
+ } else {
+ ++temp;
+ }
+ } else if (temp & 0x20) {
+ temp ^= 0x15;
+ }
+
+ i >>= 1;
+ }
+
+ for (i = 5; i != 0; --i) {
+ temp <<= 1;
+ if (temp & 0x20) {
+ temp ^= 0x15;
+ }
+ }
+
+ return temp & 0x1F;
+}
+
+u8 __osContDataCrc(u8 *data) {
+ u32 temp = 0;
+ u32 i;
+ u32 j;
+
+ for (i = 0x20; i; --i) {
+ for (j = 0x80; j; j >>= 1) {
+ temp <<= 1;
+
+ if ((*data & j) != 0) {
+ if ((temp & 0x100) != 0) {
+ temp ^= 0x84;
+ } else {
+ ++temp;
+ }
+ } else if (temp & 0x100) {
+ temp ^= 0x85;
+ }
+ }
+
+ data++;
+ }
+ do {
+ temp <<= 1;
+
+ if (temp & 0x100) {
+ temp ^= 0x85;
+ }
+ } while (++i < 8U);
+
+ return temp;
+}
diff --git a/lib/ultralib/src/io/devmgr.c b/lib/ultralib/src/io/devmgr.c
new file mode 100644
index 0000000..2d22774
--- /dev/null
+++ b/lib/ultralib/src/io/devmgr.c
@@ -0,0 +1,110 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "piint.h"
+
+void __osDevMgrMain(void *args)
+{
+ OSIoMesg *mb = NULL;
+ OSMesg em;
+ OSMesg dummy;
+ s32 ret = 0;
+ OSDevMgr *dm = (OSDevMgr *)args;
+ s32 messageSend = 0;
+
+ while (TRUE)
+ {
+ osRecvMesg(dm->cmdQueue, (OSMesg)&mb, OS_MESG_BLOCK);
+
+ if (mb->piHandle != NULL &&
+ mb->piHandle->type == DEVICE_TYPE_64DD &&
+ (mb->piHandle->transferInfo.cmdType == LEO_CMD_TYPE_0 ||
+ mb->piHandle->transferInfo.cmdType == LEO_CMD_TYPE_1))
+ {
+ __OSBlockInfo *blockInfo;
+ __OSTranxInfo *info;
+ info = &mb->piHandle->transferInfo;
+ blockInfo = &info->block[info->blockNum];
+ info->sectorNum = -1;
+
+ if (info->transferMode != LEO_SECTOR_MODE) {
+ blockInfo->dramAddr = (void *)((u32)blockInfo->dramAddr - blockInfo->sectorSize);
+ }
+
+ if (info->transferMode == LEO_TRACK_MODE && mb->piHandle->transferInfo.cmdType == LEO_CMD_TYPE_0) {
+ messageSend = 1;
+ } else {
+ messageSend = 0;
+ }
+
+ osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
+ __osResetGlobalIntMask(OS_IM_PI);
+ __osEPiRawWriteIo(mb->piHandle, LEO_BM_CTL, (info->bmCtlShadow | 0x80000000));
+
+readblock1:
+ osRecvMesg(dm->evtQueue, &em, OS_MESG_BLOCK);
+ info = &mb->piHandle->transferInfo;
+ blockInfo = &info->block[info->blockNum];
+
+ if (blockInfo->errStatus == LEO_ERROR_29) {
+ u32 stat;
+ __osEPiRawWriteIo(mb->piHandle, LEO_BM_CTL, info->bmCtlShadow | LEO_BM_CTL_RESET);
+ __osEPiRawWriteIo(mb->piHandle, LEO_BM_CTL, info->bmCtlShadow);
+ __osEPiRawReadIo(mb->piHandle, LEO_STATUS, &stat);
+
+ if (stat & LEO_STATUS_MECHANIC_INTERRUPT) {
+ __osEPiRawWriteIo(mb->piHandle, LEO_BM_CTL, info->bmCtlShadow | LEO_BM_CTL_CLR_MECHANIC_INTR);
+ }
+
+ blockInfo->errStatus = LEO_ERROR_4;
+ IO_WRITE(PI_STATUS_REG, PI_CLR_INTR);
+ __osSetGlobalIntMask(OS_IM_PI | SR_IBIT4);
+ }
+
+ osSendMesg(mb->hdr.retQueue, mb, OS_MESG_NOBLOCK);
+
+ if (messageSend == 1 && mb->piHandle->transferInfo.block[0].errStatus == LEO_ERROR_GOOD) {
+ messageSend = 0;
+ goto readblock1;
+ }
+
+ osSendMesg(dm->acsQueue, NULL, OS_MESG_NOBLOCK);
+ if (mb->piHandle->transferInfo.blockNum == 1) {
+ osYieldThread();
+ }
+ } else {
+ switch (mb->hdr.type) {
+ case OS_MESG_TYPE_DMAREAD:
+ osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
+ ret = dm->dma(OS_READ, mb->devAddr, mb->dramAddr, mb->size);
+ break;
+ case OS_MESG_TYPE_DMAWRITE:
+ osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
+ ret = dm->dma(OS_WRITE, mb->devAddr, mb->dramAddr, mb->size);
+ break;
+ case OS_MESG_TYPE_EDMAREAD:
+ osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
+ ret = dm->edma(mb->piHandle, OS_READ, mb->devAddr, mb->dramAddr,
+ mb->size);
+ break;
+ case OS_MESG_TYPE_EDMAWRITE:
+ osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
+ ret = dm->edma(mb->piHandle, OS_WRITE, mb->devAddr, mb->dramAddr,
+ mb->size);
+ break;
+ case OS_MESG_TYPE_LOOPBACK:
+ osSendMesg(mb->hdr.retQueue, mb, OS_MESG_NOBLOCK);
+ ret = -1;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ if (ret == 0) {
+ osRecvMesg(dm->evtQueue, &em, OS_MESG_BLOCK);
+ osSendMesg(mb->hdr.retQueue, mb, OS_MESG_NOBLOCK);
+ osSendMesg(dm->acsQueue, NULL, OS_MESG_NOBLOCK);
+ }
+ }
+ }
+}
diff --git a/lib/ultralib/src/io/dp.c b/lib/ultralib/src/io/dp.c
new file mode 100755
index 0000000..e4d0254
--- /dev/null
+++ b/lib/ultralib/src/io/dp.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+int __osDpDeviceBusy(void) {
+ register u32 stat = IO_READ(DPC_STATUS_REG);
+
+ if (stat & DPC_STATUS_DMA_BUSY) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/lib/ultralib/src/io/dpctr.c b/lib/ultralib/src/io/dpctr.c
new file mode 100755
index 0000000..0c2164b
--- /dev/null
+++ b/lib/ultralib/src/io/dpctr.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+void osDpGetCounters(u32 *array) {
+ *array++ = IO_READ(DPC_CLOCK_REG);
+ *array++ = IO_READ(DPC_BUFBUSY_REG);
+ *array++ = IO_READ(DPC_PIPEBUSY_REG);
+ *array++ = IO_READ(DPC_TMEM_REG);
+}
diff --git a/lib/ultralib/src/io/dpgetstat.c b/lib/ultralib/src/io/dpgetstat.c
new file mode 100755
index 0000000..af3ccee
--- /dev/null
+++ b/lib/ultralib/src/io/dpgetstat.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+u32 osDpGetStatus() {
+ return IO_READ(DPC_STATUS_REG);
+}
diff --git a/lib/ultralib/src/io/dpsetnextbuf.c b/lib/ultralib/src/io/dpsetnextbuf.c
new file mode 100755
index 0000000..fa9a0d4
--- /dev/null
+++ b/lib/ultralib/src/io/dpsetnextbuf.c
@@ -0,0 +1,24 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "../os/osint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 osDpSetNextBuffer(void *bufPtr, u64 size) {
+ register u32 stat;
+
+ if (__osDpDeviceBusy()) {
+ return -1;
+ }
+
+ IO_WRITE(DPC_STATUS_REG, DPC_CLR_XBUS_DMEM_DMA);
+
+ do {
+ stat = IO_READ(DPC_STATUS_REG);
+ } while (stat & DPC_STATUS_XBUS_DMEM_DMA);
+
+ IO_WRITE(DPC_START_REG, osVirtualToPhysical(bufPtr));
+ IO_WRITE(DPC_END_REG, osVirtualToPhysical(bufPtr) + size);
+ return 0;
+}
diff --git a/lib/ultralib/src/io/dpsetstat.c b/lib/ultralib/src/io/dpsetstat.c
new file mode 100755
index 0000000..5b53867
--- /dev/null
+++ b/lib/ultralib/src/io/dpsetstat.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osDpSetStatus(u32 data) {
+ IO_WRITE(DPC_STATUS_REG, data);
+}
diff --git a/lib/ultralib/src/io/epidma.c b/lib/ultralib/src/io/epidma.c
new file mode 100644
index 0000000..d122791
--- /dev/null
+++ b/lib/ultralib/src/io/epidma.c
@@ -0,0 +1,24 @@
+#include "piint.h"
+
+s32 osEPiStartDma(OSPiHandle* pihandle, OSIoMesg* mb, s32 direction) {
+ s32 ret;
+
+ if (!__osPiDevMgr.active) {
+ return -1;
+ }
+ mb->piHandle = pihandle;
+
+ if (direction == OS_READ) {
+ mb->hdr.type = OS_MESG_TYPE_EDMAREAD;
+ } else {
+ mb->hdr.type = OS_MESG_TYPE_EDMAWRITE;
+ }
+
+ if (mb->hdr.pri == OS_MESG_PRI_HIGH) {
+ ret = osJamMesg(osPiGetCmdQueue(), (OSMesg)mb, OS_MESG_NOBLOCK);
+ } else {
+ ret = osSendMesg(osPiGetCmdQueue(), (OSMesg)mb, OS_MESG_NOBLOCK);
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/epigettype.c b/lib/ultralib/src/io/epigettype.c
new file mode 100644
index 0000000..ef749ea
--- /dev/null
+++ b/lib/ultralib/src/io/epigettype.c
@@ -0,0 +1,8 @@
+#include "piint.h"
+
+s32 osEPiGetDeviceType(OSPiHandle *pihandle, OSPiInfo *info)
+{
+ info->type = pihandle->type;
+ info->address = pihandle->baseAddress;
+ return 0;
+}
diff --git a/lib/ultralib/src/io/epilinkhandle.c b/lib/ultralib/src/io/epilinkhandle.c
new file mode 100644
index 0000000..8785bdb
--- /dev/null
+++ b/lib/ultralib/src/io/epilinkhandle.c
@@ -0,0 +1,12 @@
+#include "piint.h"
+
+s32 osEPiLinkHandle(OSPiHandle *EPiHandle)
+{
+ register s32 saveMask = __osDisableInt();
+
+ EPiHandle->next = __osPiTable;
+ __osPiTable = EPiHandle;
+
+ __osRestoreInt(saveMask);
+ return 0;
+}
diff --git a/lib/ultralib/src/io/epirawdma.c b/lib/ultralib/src/io/epirawdma.c
new file mode 100644
index 0000000..63ad6cf
--- /dev/null
+++ b/lib/ultralib/src/io/epirawdma.c
@@ -0,0 +1,27 @@
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osEPiRawStartDma(OSPiHandle *pihandle, s32 direction, u32 devAddr, void *dramAddr, u32 size)
+{
+ u32 stat;
+ u32 domain;
+
+ EPI_SYNC(pihandle, stat, domain);
+ IO_WRITE(PI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr));
+ IO_WRITE(PI_CART_ADDR_REG, K1_TO_PHYS(pihandle->baseAddress | devAddr));
+
+ switch (direction)
+ {
+ case OS_READ:
+ IO_WRITE(PI_WR_LEN_REG, size - 1);
+ break;
+ case OS_WRITE:
+ IO_WRITE(PI_RD_LEN_REG, size - 1);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
diff --git a/lib/ultralib/src/io/epirawread.c b/lib/ultralib/src/io/epirawread.c
new file mode 100644
index 0000000..7871f56
--- /dev/null
+++ b/lib/ultralib/src/io/epirawread.c
@@ -0,0 +1,14 @@
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osEPiRawReadIo(OSPiHandle* pihandle, u32 devAddr, u32* data) {
+ u32 stat;
+ u32 domain;
+
+ EPI_SYNC(pihandle, stat, domain);
+ *data = IO_READ(pihandle->baseAddress | devAddr);
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/epirawwrite.c b/lib/ultralib/src/io/epirawwrite.c
new file mode 100644
index 0000000..5cc1752
--- /dev/null
+++ b/lib/ultralib/src/io/epirawwrite.c
@@ -0,0 +1,14 @@
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osEPiRawWriteIo(OSPiHandle* pihandle, u32 devAddr, u32 data) {
+ u32 stat;
+ u32 domain;
+
+ EPI_SYNC(pihandle, stat, domain);
+ IO_WRITE(pihandle->baseAddress | devAddr, data);
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/epiread.c b/lib/ultralib/src/io/epiread.c
new file mode 100644
index 0000000..3918c5f
--- /dev/null
+++ b/lib/ultralib/src/io/epiread.c
@@ -0,0 +1,13 @@
+#include "piint.h"
+
+s32 __osEPiRawReadIo(OSPiHandle*, u32, u32*);
+
+s32 osEPiReadIo(OSPiHandle* pihandle, u32 devAddr, u32* data) {
+ register s32 ret;
+
+ __osPiGetAccess();
+ ret = __osEPiRawReadIo(pihandle, devAddr, data);
+ __osPiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/epiwrite.c b/lib/ultralib/src/io/epiwrite.c
new file mode 100644
index 0000000..1a4c462
--- /dev/null
+++ b/lib/ultralib/src/io/epiwrite.c
@@ -0,0 +1,13 @@
+#include "piint.h"
+
+s32 __osEPiRawWriteIo(OSPiHandle*, u32, u32);
+
+s32 osEPiWriteIo(OSPiHandle* pihandle, u32 devAddr, u32 data) {
+ register s32 ret;
+
+ __osPiGetAccess();
+ ret = __osEPiRawWriteIo(pihandle, devAddr, data);
+ __osPiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpakcheckconnector.c b/lib/ultralib/src/io/gbpakcheckconnector.c
new file mode 100644
index 0000000..7fbef18
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakcheckconnector.c
@@ -0,0 +1,131 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osGbpakCheckConnector(OSPfs* pfs, u8* status) {
+ s32 ret;
+ s32 bufn = 1;
+ s32 oldbufn = 0;
+ u16 address = 0;
+ u16 oldaddr = 0;
+ u16 daddr = 0;
+ u16 num;
+ u8 buf[3][4][BLOCKSIZE];
+ u8 buf_status[3][4];
+
+ ret = osGbpakGetStatus(pfs, status);
+
+ if (ret == PFS_ERR_NEW_GBCART) {
+ ret = osGbpakGetStatus(pfs, status);
+ }
+
+ if (ret == PFS_ERR_NEW_GBCART) {
+ return PFS_ERR_CONTRFAIL;
+ } else if (ret == 0) {
+ if (!(*status & OS_GBPAK_POWER)) {
+ ERRCK(osGbpakPower(pfs, OS_GBPAK_POWER_ON));
+ }
+
+ bzero(buf_status, sizeof(buf_status));
+
+ for (address = 0x80; address <= 0x4000; address <<= 1) {
+ num = 0;
+ daddr = 0;
+
+ do {
+ ERRCK(osGbpakReadWrite(pfs, OS_READ, address + daddr, buf[bufn][num], BLOCKSIZE));
+ buf_status[bufn][num] = 1;
+
+ if (buf_status[oldbufn][num] == 0) {
+ ret = osGbpakReadWrite(pfs, OS_READ, oldaddr + daddr, buf[oldbufn][num], BLOCKSIZE);
+
+ if (ret != 0) {
+ return ret;
+ } else {
+ buf_status[oldbufn][num] = 1;
+ }
+ }
+
+ if (bcmp(buf[bufn][num], buf[oldbufn][num], BLOCKSIZE) != 0) {
+ num = 0;
+ break;
+ }
+
+ daddr += BLOCKSIZE;
+ } while (num++ < ARRLEN(buf[0]) - 1);
+
+ if (num != 0) {
+ return PFS_ERR_CONTRFAIL;
+ }
+
+ if (oldbufn != 0) {
+ num = 0;
+ daddr = 0;
+
+ do {
+ if (buf_status[bufn][num] == 0) {
+ ERRCK(osGbpakReadWrite(pfs, OS_READ, address + daddr, buf[bufn][num], BLOCKSIZE));
+ buf_status[bufn][num] = 1;
+ }
+
+ if (buf_status[0][num] == 0) {
+ ret = osGbpakReadWrite(pfs, OS_READ, daddr, buf[0][num], BLOCKSIZE);
+ if (ret != 0) {
+ return ret;
+ } else {
+ buf_status[0][num] = 1;
+ }
+ }
+
+ if (bcmp(buf[bufn][num], buf[0][num], BLOCKSIZE)) {
+ num = 0;
+ break;
+ }
+
+ daddr += BLOCKSIZE;
+ } while (num++ < ARRLEN(buf_status[0]) - 1);
+ }
+
+ if (num != 0) {
+ return PFS_ERR_CONTRFAIL;
+ }
+
+ if (oldbufn != 0) {
+ bzero(buf_status[oldbufn], ARRLEN(buf_status[oldbufn]));
+ }
+
+ oldaddr = address;
+ oldbufn = bufn;
+ bufn ^= 3;
+ }
+
+ if ((pfs->dir_size >= 2) || (pfs->version == 2)) {
+ num = 0;
+ daddr = 0;
+
+ do {
+ ERRCK(osGbpakReadWrite(pfs, OS_READ, daddr + 0xA000, buf[bufn][num], BLOCKSIZE));
+ ERRCK(osGbpakReadWrite(pfs, OS_READ, daddr + 0x2000, buf[oldbufn][num], BLOCKSIZE));
+
+ if (bcmp(buf[bufn][num], buf[oldbufn][num], BLOCKSIZE)) {
+ num = 0;
+ break;
+ }
+
+ daddr += BLOCKSIZE;
+ } while (num++ < ARRLEN(buf[0]) - 1);
+
+ if (num != 0) {
+ return PFS_ERR_CONTRFAIL;
+ }
+ }
+
+ ret = osGbpakGetStatus(pfs, status);
+
+ if (ret == PFS_ERR_NEW_GBCART) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpakgetbank.c b/lib/ultralib/src/io/gbpakgetbank.c
new file mode 100644
index 0000000..622e707
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakgetbank.c
@@ -0,0 +1,28 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 __osGbpakGetBank(OSPfs* pfs, u8* bank) {
+ s32 ret;
+ u32 temp[BLOCKSIZE / sizeof(u32)];
+
+ ret = __osContRamRead(pfs->queue, pfs->channel, CONT_BLOCK_GB_BANK, (u8*)temp);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = osGbpakInit(pfs->queue, pfs, pfs->channel);
+
+ if (ret == 0) {
+ ret = __osContRamRead(pfs->queue, pfs->channel, CONT_BLOCK_GB_BANK, (u8*)temp);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ }
+ }
+
+ if (ret == 0) {
+ *bank = ((u8*)temp)[0];
+ pfs->banks = *bank;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpakgetstatus.c b/lib/ultralib/src/io/gbpakgetstatus.c
new file mode 100644
index 0000000..d17d15c
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakgetstatus.c
@@ -0,0 +1,39 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osGbpakGetStatus(OSPfs* pfs, u8* status) {
+ s32 ret;
+ s32 i;
+ u32 temp[BLOCKSIZE / sizeof(u32)];
+
+ ret = __osContRamRead(pfs->queue, pfs->channel, CONT_BLOCK_GB_POWER, (u8*)temp);
+
+ if ((ret == PFS_ERR_NEW_PACK) || (((u8*)temp)[BLOCKSIZE - 1] != GB_POWER_ON)) {
+ ERRCK(osGbpakInit(pfs->queue, pfs, pfs->channel));
+ }
+
+ ret = __osContRamRead(pfs->queue, pfs->channel, CONT_BLOCK_GB_STATUS, (u8*)temp);
+
+ if (ret == 0) {
+ ERRCK(__osPfsGetStatus(pfs->queue, pfs->channel));
+
+ *status = ((u8*)temp)[0];
+
+ for (i = 1; i < BLOCKSIZE; i++) {
+ *status |= ((u8*)temp)[i];
+ }
+
+ *status &= (OS_GBPAK_GBCART_PULL | OS_GBPAK_RSTB_DETECTION);
+ *status |= ((u8*)temp)[BLOCKSIZE - 1];
+
+ if (!(*status & OS_GBPAK_GBCART_ON)) {
+ ret = PFS_ERR_NO_GBCART;
+ } else if (*status & OS_GBPAK_GBCART_PULL) {
+ ret = PFS_ERR_NEW_GBCART;
+ }
+ } else if (ret == 2) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpakinit.c b/lib/ultralib/src/io/gbpakinit.c
new file mode 100644
index 0000000..604bafa
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakinit.c
@@ -0,0 +1,90 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "controller_gbpak.h"
+
+OSTimer __osGbpakTimer;
+OSMesg __osGbpakTimerMsg;
+OSMesgQueue __osGbpakTimerQ ALIGNED(8);
+
+s32 osGbpakInit(OSMesgQueue* mq, OSPfs* pfs, int channel) {
+ int i;
+ s32 ret;
+ u8 temp[BLOCKSIZE];
+
+ pfs->status = 0;
+
+ // Turn off the transfer pak
+ for (i = 0; i < BLOCKSIZE; i++) {
+ temp[i] = GB_POWER_OFF;
+ }
+
+ ret = __osContRamWrite(mq, channel, CONT_BLOCK_GB_POWER, temp, FALSE);
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = __osContRamWrite(mq, channel, CONT_BLOCK_GB_POWER, temp, FALSE);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = __osContRamRead(mq, channel, CONT_BLOCK_GB_POWER, temp);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ } else {
+ // Check if the power is still off as set earlier
+ if (temp[BLOCKSIZE - 1] == GB_POWER_OFF) {
+ return PFS_ERR_DEVICE;
+ }
+ }
+
+ // Turn on the transfer pak
+ for (i = 0; i < BLOCKSIZE; i++) {
+ temp[i] = GB_POWER_ON;
+ }
+
+ ret = __osContRamWrite(mq, channel, CONT_BLOCK_GB_POWER, temp, FALSE);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = __osContRamRead(mq, channel, CONT_BLOCK_GB_POWER, temp);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ } else {
+ // Check if the power is still on as set earlier
+ if (temp[BLOCKSIZE - 1] != GB_POWER_ON) {
+ return PFS_ERR_DEVICE;
+ }
+ }
+
+ ERRCK(__osPfsGetStatus(mq, channel));
+
+ osCreateMesgQueue(&__osGbpakTimerQ, &__osGbpakTimerMsg, 1);
+ osSetTimer(&__osGbpakTimer, 9000000, 0, &__osGbpakTimerQ, &__osGbpakTimerMsg);
+ osRecvMesg(&__osGbpakTimerQ, NULL, OS_MESG_BLOCK);
+ pfs->queue = mq;
+ pfs->status = PFS_GBPAK_INITIALIZED;
+ pfs->channel = channel;
+ pfs->activebank = 0x84;
+ pfs->banks = 0xFF;
+ pfs->version = 0xFF;
+ pfs->dir_size = 0xFF;
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/gbpakpower.c b/lib/ultralib/src/io/gbpakpower.c
new file mode 100644
index 0000000..c0b78cb
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakpower.c
@@ -0,0 +1,34 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "controller_gbpak.h"
+
+s32 osGbpakPower(OSPfs* pfs, s32 flag) {
+ s32 i;
+ s32 ret;
+ u8 temp[BLOCKSIZE];
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ temp[i] = (u8) flag;
+ }
+
+ ret = __osContRamWrite(pfs->queue, pfs->channel, CONT_BLOCK_GB_STATUS, temp, 0);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = osGbpakInit(pfs->queue, pfs, pfs->channel);
+
+ if (ret == 0) {
+ ret = __osContRamWrite(pfs->queue, pfs->channel, CONT_BLOCK_GB_STATUS, temp, 0);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ }
+ }
+
+ if (flag != OS_GBPAK_POWER_OFF) {
+ osSetTimer(&__osGbpakTimer, OS_USEC_TO_CYCLES(120000), 0, &__osGbpakTimerQ, &__osGbpakTimerMsg);
+ osRecvMesg(&__osGbpakTimerQ, NULL, OS_MESG_BLOCK);
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpakreadid.c b/lib/ultralib/src/io/gbpakreadid.c
new file mode 100644
index 0000000..d0cf467
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakreadid.c
@@ -0,0 +1,84 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osGbpakReadId(OSPfs* pfs, OSGbpakId* id, u8* status) {
+ s32 i;
+ s32 ret;
+ u8 isum;
+ u8 buf[96];
+ u8 temp[32];
+ static u8 nintendo[] = {0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E};
+ static u8 mmc_type[] = {0x00, 0x01, 0x01, 0x01, 0xFF, 0x02, 0x02, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03};
+
+ ret = osGbpakGetStatus(pfs, status);
+
+ if (ret == PFS_ERR_NEW_GBCART) {
+ ret = osGbpakGetStatus(pfs, status);
+ }
+
+ if (ret == PFS_ERR_NEW_GBCART) {
+ return PFS_ERR_CONTRFAIL;
+ } else if (ret == 0) {
+ if (!(*status & OS_GBPAK_POWER)) {
+ ERRCK(osGbpakPower(pfs, OS_GBPAK_POWER_ON));
+ }
+
+ ERRCK(osGbpakReadWrite(pfs, OS_READ, 0x100U, buf, ARRLEN(buf)));
+
+ ret = osGbpakGetStatus(pfs, status);
+
+ if (ret == 0xD) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (!(*status & OS_GBPAK_RSTB_STATUS)) {
+ return PFS_ERR_CONTRFAIL;
+ }
+
+ if (bcmp(nintendo, buf + 4, ARRLEN(nintendo))) {
+ for (i = 0; i < ARRLEN(temp); i++) {
+ temp[i] = 0;
+ }
+
+ ERRCK(osGbpakReadWrite(pfs, OS_WRITE, 0x6000U, temp, ARRLEN(temp)));
+ ret = osGbpakReadWrite(pfs, OS_READ, 0x100U, buf, ARRLEN(buf));
+ ERRCK(osGbpakReadWrite(pfs, OS_READ, 0x100U, buf, ARRLEN(buf)));
+
+ ret = osGbpakGetStatus(pfs, status);
+
+ if (ret == PFS_ERR_NEW_GBCART) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (bcmp(nintendo, buf + 4, ARRLEN(nintendo))) {
+ return 4;
+ }
+ }
+ for (i = 0x34, isum = 0; i < 0x4E; i++) {
+ isum += buf[i];
+ }
+
+ if ((isum + 0x19) & 0xFF) {
+ return 4;
+ }
+
+ bcopy(buf, id, 0x50);
+
+ if (id->cart_type < 0x14) {
+ pfs->version = (int)mmc_type[id->cart_type];
+ }
+
+ pfs->dir_size = (int)id->ram_size;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpakreadwrite.c b/lib/ultralib/src/io/gbpakreadwrite.c
new file mode 100644
index 0000000..5fac5ce
--- /dev/null
+++ b/lib/ultralib/src/io/gbpakreadwrite.c
@@ -0,0 +1,69 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osGbpakReadWrite(OSPfs* pfs, u16 flag, u16 address, u8* buffer, u16 size) {
+ s32 i;
+ s32 ret;
+ u8 bank;
+
+ bank = (u8) (address >> 0xE);
+
+ if (bank != pfs->banks) {
+ ret = __osGbpakSetBank(pfs, bank);
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ size = (u16)(size >> 5);
+ address = (u16)((address | 0xC000) >> 5);
+
+ if (flag == 1) {
+ for (i = 0; i < (s32)size; i++, buffer += BLOCKSIZE) {
+ ret = __osContRamWrite(pfs->queue, pfs->channel, address, buffer, 0);
+
+ if (ret != 0) {
+ break;
+ }
+
+ if ((++address >= 0x800) && (i < (s32)(size - 1))) {
+ ret = __osGbpakSetBank(pfs, ++bank);
+
+ if (ret != 0) {
+ break;
+ }
+
+ address = 0x600U;
+ }
+ }
+ } else {
+ for (i = 0; i < (s32)size; i++, buffer += BLOCKSIZE) {
+ ret = __osContRamRead(pfs->queue, pfs->channel, address, buffer);
+
+ if (ret != 0) {
+ break;
+ }
+
+ if (++address >= 0x800 && (i < (s32)(size - 1))) {
+ ret = __osGbpakSetBank(pfs, ++bank);
+
+ if (ret != 0) {
+ break;
+ }
+
+ address = 0x600U;
+ }
+ }
+ }
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/gbpaksetbank.c b/lib/ultralib/src/io/gbpaksetbank.c
new file mode 100644
index 0000000..134cad8
--- /dev/null
+++ b/lib/ultralib/src/io/gbpaksetbank.c
@@ -0,0 +1,35 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 __osGbpakSetBank(OSPfs* pfs, u8 bank) {
+ int i;
+ s32 ret;
+ u8 temp[BLOCKSIZE];
+
+ if (bank > 2) {
+ return PFS_ERR_INVALID;
+ }
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ temp[i] = bank;
+ }
+
+ ret = __osContRamWrite(pfs->queue, pfs->channel, CONT_BLOCK_GB_BANK, temp, FALSE);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = osGbpakInit(pfs->queue, pfs, pfs->channel);
+
+ if (ret == 0) {
+ ret = __osContRamWrite(pfs->queue, pfs->channel, CONT_BLOCK_GB_BANK, temp, FALSE);
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ }
+ }
+
+ if (ret == 0) {
+ pfs->banks = bank;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/motor.c b/lib/ultralib/src/io/motor.c
new file mode 100644
index 0000000..df36414
--- /dev/null
+++ b/lib/ultralib/src/io/motor.c
@@ -0,0 +1,136 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+static OSPifRam __MotorDataBuf[MAXCONTROLLERS];
+
+#define READFORMAT(ptr) ((__OSContRamReadFormat*)(ptr))
+
+s32 __osMotorAccess(OSPfs* pfs, s32 flag) {
+ int i;
+ s32 ret;
+ u8* ptr = (u8*)&__MotorDataBuf[pfs->channel];
+
+ if (!(pfs->status & PFS_MOTOR_INITIALIZED)) {
+ return 5;
+ }
+
+ __osSiGetAccess();
+ __MotorDataBuf[pfs->channel].pifstatus = CONT_CMD_EXE;
+ ptr += pfs->channel;
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ READFORMAT(ptr)->data[i] = flag;
+ }
+
+ __osContLastCmd = CONT_CMD_END;
+ __osSiRawStartDma(OS_WRITE, &__MotorDataBuf[pfs->channel]);
+ osRecvMesg(pfs->queue, NULL, OS_MESG_BLOCK);
+ __osSiRawStartDma(OS_READ, &__MotorDataBuf[pfs->channel]);
+ osRecvMesg(pfs->queue, NULL, OS_MESG_BLOCK);
+
+ ret = READFORMAT(ptr)->rxsize & CHNL_ERR_MASK;
+ if (!ret) {
+ if (!flag) {
+ if (READFORMAT(ptr)->datacrc != 0) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ } else {
+ if (READFORMAT(ptr)->datacrc != 0xEB) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+ }
+ }
+
+ __osSiRelAccess();
+
+ return ret;
+}
+
+static void _MakeMotorData(int channel, OSPifRam *mdata) {
+ u8 *ptr = (u8 *)mdata->ramarray;
+ __OSContRamReadFormat ramreadformat;
+ int i;
+
+ ramreadformat.dummy = CONT_CMD_NOP;
+ ramreadformat.txsize = CONT_CMD_WRITE_PAK_TX;
+ ramreadformat.rxsize = CONT_CMD_WRITE_PAK_RX;
+ ramreadformat.cmd = CONT_CMD_WRITE_PAK;
+ ramreadformat.addrh = CONT_BLOCK_RUMBLE >> 3;
+ ramreadformat.addrl = (u8)(__osContAddressCrc(CONT_BLOCK_RUMBLE) | (CONT_BLOCK_RUMBLE << 5));
+
+ if (channel != 0) {
+ for (i = 0; i < channel; i++) {
+ *ptr++ = CONT_CMD_REQUEST_STATUS;
+ }
+ }
+
+ *READFORMAT(ptr) = ramreadformat;
+ ptr += sizeof(__OSContRamReadFormat);
+ ptr[0] = CONT_CMD_END;
+}
+
+s32 osMotorInit(OSMesgQueue *mq, OSPfs *pfs, int channel)
+{
+ s32 ret;
+ u8 temp[32];
+
+ pfs->queue = mq;
+ pfs->channel = channel;
+ pfs->activebank = 0xFF;
+ pfs->status = 0;
+
+ ret = __osPfsSelectBank(pfs, 0xFE);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = __osPfsSelectBank(pfs, 0x80);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = __osContRamRead(mq, channel, CONT_BLOCK_DETECT, temp);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (temp[31] == 254) {
+ return PFS_ERR_DEVICE;
+ }
+
+ ret = __osPfsSelectBank(pfs, 0x80);
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = __osContRamRead(mq, channel, CONT_BLOCK_DETECT, temp);
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = PFS_ERR_CONTRFAIL;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (temp[31] != 0x80) {
+ return PFS_ERR_DEVICE;
+ }
+
+ if (!(pfs->status & PFS_MOTOR_INITIALIZED)) {
+ _MakeMotorData(channel, &__MotorDataBuf[channel]);
+ }
+
+ pfs->status = PFS_MOTOR_INITIALIZED;
+ return 0;
+}
diff --git a/lib/ultralib/src/io/pfsallocatefile.c b/lib/ultralib/src/io/pfsallocatefile.c
new file mode 100644
index 0000000..84ef32f
--- /dev/null
+++ b/lib/ultralib/src/io/pfsallocatefile.c
@@ -0,0 +1,148 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+#define ROUND_UP_DIVIDE(numerator, denominator) (((numerator) + (denominator) - 1) / (denominator))
+
+s32 osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int file_size_in_bytes, s32 *file_no) {
+ int start_page;
+ int decleared;
+ int last_page;
+ int old_last_page = 0;
+ s32 ret = 0;
+ int file_size_in_pages;
+ __OSInode inode;
+ __OSInode backup_inode;
+ __OSDir dir;
+ u8 bank;
+ u8 old_bank = 0;
+ int firsttime = 0;
+ s32 bytes;
+ __OSInodeUnit fpage;
+
+ if (company_code == 0 || game_code == 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ file_size_in_pages = ROUND_UP_DIVIDE(file_size_in_bytes, BLOCKSIZE * PFS_ONE_PAGE);
+
+ ret = osPfsFindFile(pfs, company_code, game_code, game_name, ext_name, file_no);
+
+ if (ret != 0) {
+ if (ret != PFS_ERR_INVALID) {
+ return ret;
+ }
+ }
+
+ if (*file_no != -1) {
+ return PFS_ERR_EXIST;
+ }
+
+ ret = osPfsFreeBlocks(pfs, &bytes);
+
+ if (file_size_in_bytes > bytes) {
+ return PFS_DATA_FULL;
+ }
+
+ if (file_size_in_pages == 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ ret = osPfsFindFile(pfs, 0, 0, NULL, NULL, file_no);
+ if (ret != 0) {
+ if (ret != PFS_ERR_INVALID) {
+ return ret;
+ }
+ }
+
+ if (*file_no == -1) {
+ return PFS_DIR_FULL;
+ }
+
+ for (bank = 0; bank < pfs->banks; bank++) {
+ ERRCK(__osPfsRWInode(pfs, &inode, OS_READ, bank));
+ ERRCK(__osPfsDeclearPage(pfs, &inode, file_size_in_pages, &start_page, bank, &decleared, &last_page));
+
+ if (start_page != -1) {
+ if (firsttime == 0) {
+ fpage.inode_t.page = start_page;
+ fpage.inode_t.bank = bank;
+ } else {
+ backup_inode.inode_page[old_last_page].inode_t.bank = bank;
+ backup_inode.inode_page[old_last_page].inode_t.page = start_page;
+ ERRCK(__osPfsRWInode(pfs, &backup_inode, OS_WRITE, old_bank));
+ }
+
+ if (file_size_in_pages > decleared) {
+ bcopy(&inode, &backup_inode, sizeof(__OSInode));
+ old_last_page = last_page;
+ old_bank = bank;
+ file_size_in_pages -= decleared;
+ firsttime++;
+ } else {
+ file_size_in_pages = 0;
+ ERRCK(__osPfsRWInode(pfs, &inode, PFS_WRITE, bank));
+ break;
+ }
+ }
+ }
+
+ if (file_size_in_pages > 0 || start_page == -1) {
+ return PFS_ERR_INCONSISTENT;
+ }
+
+ dir.start_page = fpage;
+ dir.company_code = company_code;
+ dir.game_code = game_code;
+ dir.data_sum = 0;
+
+ bcopy(game_name, dir.game_name, PFS_FILE_NAME_LEN);
+ bcopy(ext_name, dir.ext_name, PFS_FILE_EXT_LEN);
+
+ return __osContRamWrite(pfs->queue, pfs->channel, pfs->dir_table + *file_no, (u8*)&dir, FALSE);
+}
+
+s32 __osPfsDeclearPage(OSPfs *pfs, __OSInode *inode, int file_size_in_pages, int *first_page, u8 bank, int *decleared, int *last_page)
+{
+ int j;
+ int spage;
+ int old_page;
+ int i;
+ s32 ret = 0;
+ int offset = bank > 0 ? 1 : pfs->inode_start_page;
+
+ for (j = offset; j < ARRLEN(inode->inode_page); j++) {
+ if (inode->inode_page[j].ipage == 3) {
+ break;
+ }
+ }
+
+ if (j == ARRLEN(inode->inode_page)) {
+ *first_page = -1;
+ return ret;
+ }
+
+ spage = j;
+ *decleared = 1;
+ old_page = j++;
+
+ while (file_size_in_pages > *decleared && j < ARRLEN(inode->inode_page)) {
+ if (inode->inode_page[j].ipage == 3) {
+ inode->inode_page[old_page].inode_t.bank = bank;
+ inode->inode_page[old_page].inode_t.page = j;
+ old_page = j;
+ (*decleared)++;
+ }
+ j++;
+ }
+
+ *first_page = spage;
+
+ if (j == ARRLEN(inode->inode_page) && file_size_in_pages > *decleared) {
+ *last_page = old_page;
+ } else {
+ inode->inode_page[old_page].ipage = 1;
+ *last_page = 0;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pfschecker.c b/lib/ultralib/src/io/pfschecker.c
new file mode 100644
index 0000000..ee71830
--- /dev/null
+++ b/lib/ultralib/src/io/pfschecker.c
@@ -0,0 +1,203 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 corrupted_init(OSPfs *pfs, __OSInodeCache *cache);
+s32 corrupted(OSPfs *pfs, __OSInodeUnit fpage, __OSInodeCache *cache);
+
+#define CHECK_IPAGE(p) \
+ (((p).ipage >= pfs->inode_start_page) && ((p).inode_t.bank < pfs->banks) && ((p).inode_t.page >= 0x01) && \
+ ((p).inode_t.page < 0x80))
+
+s32 osPfsChecker(OSPfs *pfs) {
+ int j;
+ s32 ret;
+ __OSInodeUnit next_page;
+ __OSInode checked_inode;
+ __OSInode tmp_inode;
+ __OSDir tmp_dir;
+ __OSInodeUnit file_next_node[16];
+ __OSInodeCache cache;
+ int fixed = 0;
+ u8 bank;
+ u8 oldbank = 254;
+ s32 cc;
+ s32 cl;
+ int offset;
+
+ ret = __osCheckId(pfs);
+
+ if (ret == PFS_ERR_NEW_PACK) {
+ ret = __osGetId(pfs);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ERRCK(corrupted_init(pfs, &cache));
+
+ for (j = 0; j < pfs->dir_size; j++) {
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&tmp_dir));
+
+ if (tmp_dir.company_code != 0 || tmp_dir.game_code != 0) {
+ if (tmp_dir.company_code == 0 || tmp_dir.game_code == 0) {
+ cc = -1;
+ } else {
+ next_page = tmp_dir.start_page;
+ cl = cc = 0;
+ bank = 255;
+
+ while (CHECK_IPAGE(next_page)) {
+ if (bank != next_page.inode_t.bank) {
+ bank = next_page.inode_t.bank;
+
+ if (oldbank != bank) {
+ ret = __osPfsRWInode(pfs, &tmp_inode, OS_READ, bank);
+ oldbank = bank;
+ }
+
+ if (ret != 0 && ret != PFS_ERR_INCONSISTENT) {
+ return ret;
+ }
+ }
+
+ cc = corrupted(pfs, next_page, &cache) - cl;
+
+ if (cc != 0) {
+ break;
+ }
+
+ cl = 1;
+ next_page = tmp_inode.inode_page[next_page.inode_t.page];
+ }
+ }
+
+ if (cc != 0 || next_page.ipage != PFS_EOF) {
+ bzero(&tmp_dir, sizeof(__OSDir));
+
+ SET_ACTIVEBANK_TO_ZERO;
+ ERRCK(__osContRamWrite(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&tmp_dir, FALSE));
+ fixed++;
+ }
+ }
+ }
+ for (j = 0; j < pfs->dir_size; j++) {
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&tmp_dir));
+
+ if (tmp_dir.company_code != 0 && tmp_dir.game_code != 0 &&
+ tmp_dir.start_page.ipage >= (u16)pfs->inode_start_page) {
+ file_next_node[j].ipage = tmp_dir.start_page.ipage;
+ } else {
+ file_next_node[j].ipage = 0;
+ }
+ }
+
+ for (bank = 0; bank < pfs->banks; bank++) {
+ ret = __osPfsRWInode(pfs, &tmp_inode, 0, bank);
+
+ if (ret != 0 && ret != PFS_ERR_INCONSISTENT) {
+ return ret;
+ }
+
+ offset = (bank > 0) ? 1 : pfs->inode_start_page;
+
+ for (j = 0; j < offset; j++) {
+ checked_inode.inode_page[j].ipage = tmp_inode.inode_page[j].ipage;
+ }
+
+ for (; j < 128; j++) {
+ checked_inode.inode_page[j].ipage = PFS_PAGE_NOT_USED;
+ }
+
+ for (j = 0; j < pfs->dir_size; j++) {
+ while (file_next_node[j].inode_t.bank == bank && file_next_node[j].ipage >= (u16)pfs->inode_start_page) {
+ u8 pp = file_next_node[j].inode_t.page;
+ file_next_node[j] = checked_inode.inode_page[pp] = tmp_inode.inode_page[pp];
+ }
+ }
+ ERRCK(__osPfsRWInode(pfs, &checked_inode, OS_WRITE, bank));
+ }
+
+ if (fixed) {
+ pfs->status |= PFS_CORRUPTED;
+ } else {
+ pfs->status &= ~PFS_CORRUPTED;
+ }
+
+ return 0;
+}
+
+s32 corrupted_init(OSPfs *pfs, __OSInodeCache *cache) {
+ int i;
+ int n;
+ int offset;
+ u8 bank;
+ __OSInodeUnit tpage;
+ __OSInode tmp_inode;
+ s32 ret;
+
+ for (i = 0; i < PFS_INODE_DIST_MAP; i++) {
+ cache->map[i] = 0;
+ }
+
+ cache->bank = -1;
+ for (bank = 0; bank < pfs->banks; bank++) {
+ offset = bank > 0 ? 1 : pfs->inode_start_page;
+
+ ret = __osPfsRWInode(pfs, &tmp_inode, OS_READ, bank);
+
+ if (ret != 0 && ret != PFS_ERR_INCONSISTENT) {
+ return ret;
+ }
+
+ for (i = offset; i < ARRLEN(tmp_inode.inode_page); i++) {
+ tpage = tmp_inode.inode_page[i];
+
+ if (tpage.ipage >= pfs->inode_start_page && tpage.inode_t.bank != bank) {
+ n = ((tpage.inode_t.page & 0x7F) / PFS_SECTOR_SIZE) + ((tpage.inode_t.bank % PFS_BANK_LAPPED_BY) * BLOCKSIZE);
+ cache->map[n] |= 1 << (bank % PFS_BANK_LAPPED_BY);
+ }
+ }
+ }
+ return 0;
+}
+
+s32 corrupted(OSPfs *pfs, __OSInodeUnit fpage, __OSInodeCache *cache) {
+ int j;
+ int n;
+ int hit;
+ u8 bank;
+ int offset;
+ s32 ret;
+
+ hit = 0;
+ ret = 0;
+ n = (fpage.inode_t.page / PFS_SECTOR_SIZE) + (fpage.inode_t.bank % PFS_BANK_LAPPED_BY) * BLOCKSIZE;
+
+ for (bank = 0; bank < pfs->banks; bank++) {
+ offset = bank > 0 ? 1 : pfs->inode_start_page;
+
+ if (bank == fpage.inode_t.bank || cache->map[n] & (1 << (bank % PFS_BANK_LAPPED_BY))) {
+ if (bank != cache->bank) {
+ ret = __osPfsRWInode(pfs, &cache->inode, 0, bank);
+
+ if (ret != 0 && ret != PFS_ERR_INCONSISTENT) {
+ return ret;
+ }
+
+ cache->bank = bank;
+ }
+
+ for (j = offset; hit < 2 && (j < ARRLEN(cache->inode.inode_page)); j++) {
+ if (cache->inode.inode_page[j].ipage == fpage.ipage) {
+ hit++;
+ }
+ }
+
+ if (hit >= 2) {
+ return PFS_ERR_NEW_PACK;
+ }
+ }
+ }
+ return hit;
+}
diff --git a/lib/ultralib/src/io/pfsdeletefile.c b/lib/ultralib/src/io/pfsdeletefile.c
new file mode 100644
index 0000000..6ca88eb
--- /dev/null
+++ b/lib/ultralib/src/io/pfsdeletefile.c
@@ -0,0 +1,64 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsDeleteFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name,
+ u8 *ext_name) {
+ s32 file_no;
+ s32 ret;
+ __OSInode inode;
+ __OSDir dir;
+ __OSInodeUnit last_page;
+ u8 startpage;
+ u8 bank;
+
+ if (company_code == 0 || game_code == 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ ERRCK(osPfsFindFile(pfs, company_code, game_code, game_name, ext_name, &file_no));
+ SET_ACTIVEBANK_TO_ZERO;
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + file_no, (u8*)&dir));
+
+ startpage = dir.start_page.inode_t.page;
+
+ for (bank = dir.start_page.inode_t.bank; bank < pfs->banks;) {
+ ERRCK(__osPfsRWInode(pfs, &inode, OS_READ, bank));
+ ERRCK(__osPfsReleasePages(pfs, &inode, startpage, bank, &last_page));
+ ERRCK(__osPfsRWInode(pfs, &inode, OS_WRITE, bank));
+
+ if (last_page.ipage == PFS_EOF) {
+ break;
+ }
+
+ bank = last_page.inode_t.bank;
+ startpage = last_page.inode_t.page;
+ }
+
+ if (bank >= pfs->banks) {
+ return PFS_ERR_INCONSISTENT;
+ }
+
+ bzero(&dir, sizeof(__OSDir));
+
+ ret = __osContRamWrite(pfs->queue, pfs->channel, pfs->dir_table + file_no, (u8*)&dir, FALSE);
+
+ return ret;
+}
+
+s32 __osPfsReleasePages(OSPfs *pfs, __OSInode *inode, u8 start_page, u8 bank, __OSInodeUnit *last_page) {
+ __OSInodeUnit next_page;
+ __OSInodeUnit old_page;
+ s32 ret = 0;
+
+ next_page.ipage = (bank << 8) + start_page;
+
+ do {
+ old_page = next_page;
+ next_page = inode->inode_page[next_page.inode_t.page];
+ inode->inode_page[old_page.inode_t.page].ipage = PFS_PAGE_NOT_USED;
+ } while (next_page.ipage >= pfs->inode_start_page && next_page.inode_t.bank == bank);
+
+ *last_page = next_page;
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pfsfilestate.c b/lib/ultralib/src/io/pfsfilestate.c
new file mode 100644
index 0000000..7f5cb8b
--- /dev/null
+++ b/lib/ultralib/src/io/pfsfilestate.c
@@ -0,0 +1,55 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsFileState(OSPfs *pfs, s32 file_no, OSPfsState *state) {
+ s32 ret;
+ int pages;
+ __OSInode inode;
+ __OSDir dir;
+ __OSInodeUnit next_page;
+ u8 bank;
+
+ if (file_no >= pfs->dir_size || file_no < 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ PFS_CHECK_STATUS;
+ ERRCK(__osCheckId(pfs));
+ SET_ACTIVEBANK_TO_ZERO;
+
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + file_no, (u8*)&dir));
+
+ if (dir.company_code == 0 || dir.game_code == 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ next_page = dir.start_page;
+ pages = 0;
+ bank = 0xFF;
+
+ while (TRUE) {
+ if (next_page.ipage < pfs->inode_start_page) {
+ break;
+ }
+
+ if (next_page.inode_t.bank != bank) {
+ bank = next_page.inode_t.bank;
+ ERRCK(__osPfsRWInode(pfs, &inode, PFS_READ, bank));
+ }
+
+ pages++;
+ next_page = inode.inode_page[next_page.inode_t.page];
+ }
+
+ if (next_page.ipage != PFS_EOF) {
+ return PFS_ERR_INCONSISTENT;
+ }
+
+ state->file_size = pages * PFS_ONE_PAGE * BLOCKSIZE;
+ state->company_code = dir.company_code;
+ state->game_code = dir.game_code;
+ bcopy(&dir.game_name, state->game_name, PFS_FILE_NAME_LEN);
+ bcopy(&dir.ext_name, state->ext_name, PFS_FILE_EXT_LEN);
+
+ return __osPfsGetStatus(pfs->queue, pfs->channel);
+}
diff --git a/lib/ultralib/src/io/pfsfreeblocks.c b/lib/ultralib/src/io/pfsfreeblocks.c
new file mode 100644
index 0000000..a1fd848
--- /dev/null
+++ b/lib/ultralib/src/io/pfsfreeblocks.c
@@ -0,0 +1,27 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsFreeBlocks(OSPfs *pfs, s32 *bytes_not_used) {
+ int j;
+ int pages = 0;
+ __OSInode inode;
+ s32 ret = 0;
+ u8 bank;
+ int offset;
+
+ PFS_CHECK_STATUS;
+ ERRCK(__osCheckId(pfs));
+ for (bank = 0; bank < pfs->banks; bank++) {
+ ERRCK(__osPfsRWInode(pfs, &inode, OS_READ, bank));
+ offset = ((bank > 0) ? 1 : pfs->inode_start_page);
+
+ for (j = offset; j < ARRLEN(inode.inode_page); j++) {
+ if (inode.inode_page[j].ipage == PFS_PAGE_NOT_USED) {
+ pages++;
+ }
+ }
+ }
+
+ *bytes_not_used = pages * PFS_ONE_PAGE * BLOCKSIZE;
+ return 0;
+}
diff --git a/lib/ultralib/src/io/pfsgetlabel.c b/lib/ultralib/src/io/pfsgetlabel.c
new file mode 100644
index 0000000..960bd30
--- /dev/null
+++ b/lib/ultralib/src/io/pfsgetlabel.c
@@ -0,0 +1,23 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsGetLabel(OSPfs *pfs, u8 *label, int *len) {
+ int i;
+
+ if (label == NULL) {
+ return PFS_ERR_INVALID;
+ }
+
+ PFS_CHECK_ID;
+
+ for (i = 0; i < ARRLEN(pfs->label); i++) {
+ if(*(pfs->label + i) == 0) {
+ break;
+ }
+
+ *label++ = *(pfs->label + i);
+ }
+
+ *len = i;
+ return 0;
+}
diff --git a/lib/ultralib/src/io/pfsgetstatus.c b/lib/ultralib/src/io/pfsgetstatus.c
new file mode 100644
index 0000000..6640728
--- /dev/null
+++ b/lib/ultralib/src/io/pfsgetstatus.c
@@ -0,0 +1,78 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+void __osPfsRequestOneChannel(int channel, u8 cmd);
+void __osPfsGetOneChannelData(int channel, OSContStatus *data);
+
+s32 __osPfsGetStatus(OSMesgQueue *queue, int channel) {
+ s32 ret = 0;
+ OSMesg dummy;
+ OSContStatus data;
+
+ __osPfsInodeCacheBank = 250;
+
+ __osPfsRequestOneChannel(channel, CONT_CMD_REQUEST_STATUS);
+
+ ret = __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(queue, &dummy, OS_MESG_BLOCK);
+
+ ret = __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(queue, &dummy, OS_MESG_BLOCK);
+
+ __osPfsGetOneChannelData(channel, &data);
+
+ if (((data.status & CONT_CARD_ON) != 0) && ((data.status & CONT_CARD_PULL) != 0)) {
+ return PFS_ERR_NEW_PACK;
+ } else if ((data.errno != 0) || ((data.status & CONT_CARD_ON) == 0)) {
+ return PFS_ERR_NOPACK;
+ } else if ((data.status & CONT_ADDR_CRC_ER) != 0) {
+ return PFS_ERR_CONTRFAIL;
+ }
+
+ return ret;
+}
+
+void __osPfsRequestOneChannel(int channel, u8 cmd) {
+ u8 *ptr;
+ __OSContRequesFormatShort requestformat;
+ int i;
+
+ __osContLastCmd = CONT_CMD_END;
+ __osPfsPifRam.pifstatus = CONT_CMD_READ_BUTTON;
+
+ ptr = (u8 *)&__osPfsPifRam;
+
+ requestformat.txsize = CONT_CMD_REQUEST_STATUS_TX;
+ requestformat.rxsize = CONT_CMD_REQUEST_STATUS_RX;
+ requestformat.cmd = cmd;
+ requestformat.typeh = CONT_CMD_NOP;
+ requestformat.typel = CONT_CMD_NOP;
+ requestformat.status = CONT_CMD_NOP;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = CONT_CMD_REQUEST_STATUS;
+ }
+
+ *(__OSContRequesFormatShort *)ptr = requestformat;
+ ptr += sizeof(__OSContRequesFormatShort);
+ *ptr = CONT_CMD_END;
+}
+
+void __osPfsGetOneChannelData(int channel, OSContStatus *data) {
+ u8 *ptr = (u8*)&__osPfsPifRam;
+ __OSContRequesFormatShort requestformat;
+ int i;
+
+ for (i = 0; i < channel; i++) {
+ ptr++;
+ }
+
+ requestformat = *(__OSContRequesFormatShort *)ptr;
+ data->errno = CHNL_ERR(requestformat);
+
+ if (data->errno == 0) {
+ data->type = (requestformat.typel << 8) | (requestformat.typeh);
+ data->status = requestformat.status;
+ }
+}
diff --git a/lib/ultralib/src/io/pfsinit.c b/lib/ultralib/src/io/pfsinit.c
new file mode 100644
index 0000000..e290cda
--- /dev/null
+++ b/lib/ultralib/src/io/pfsinit.c
@@ -0,0 +1,25 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+s32 osPfsInit(OSMesgQueue *queue, OSPfs *pfs, int channel) {
+ s32 ret = 0;
+
+ __osSiGetAccess();
+ ret = __osPfsGetStatus(queue, channel);
+ __osSiRelAccess();
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ pfs->queue = queue;
+ pfs->channel = channel;
+ pfs->status = 0;
+ pfs->activebank = -1;
+ ERRCK(__osGetId(pfs));
+
+ ret = osPfsChecker(pfs);
+ pfs->status |= PFS_INITIALIZED;
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pfsinitpak.c b/lib/ultralib/src/io/pfsinitpak.c
new file mode 100644
index 0000000..927636f
--- /dev/null
+++ b/lib/ultralib/src/io/pfsinitpak.c
@@ -0,0 +1,101 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+static s32 __osPfsCheckRamArea(OSPfs* pfs);
+
+s32 osPfsInitPak(OSMesgQueue* queue, OSPfs* pfs, int channel) {
+ s32 ret;
+ u16 sum;
+ u16 isum;
+ u8 temp[BLOCKSIZE];
+ __OSPackId* id;
+ __OSPackId newid;
+
+ __osSiGetAccess();
+
+ ret = __osPfsGetStatus(queue, channel);
+
+ __osSiRelAccess();
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ pfs->queue = queue;
+ pfs->channel = channel;
+ pfs->status = 0;
+
+ ERRCK(__osPfsCheckRamArea(pfs));
+ ERRCK(__osPfsSelectBank(pfs, 0));
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, PFS_ID_0AREA, temp));
+
+ __osIdCheckSum((u16*)temp, &sum, &isum);
+ id = (__OSPackId*)temp;
+
+ if ((id->checksum != sum) || (id->inverted_checksum != isum)) {
+ ret = __osCheckPackId(pfs, id);
+
+ if (ret != 0) {
+ pfs->status |= PFS_ID_BROKEN;
+ return ret;
+ }
+ }
+
+ if (!(id->deviceid & 1)) {
+ ret = __osRepairPackId(pfs, id, &newid);
+
+ if (ret != 0) {
+ if (ret == PFS_ERR_ID_FATAL) {
+ pfs->status |= PFS_ID_BROKEN;
+ }
+ return ret;
+ }
+
+ id = &newid;
+
+ if (!(id->deviceid & 1)) {
+ return PFS_ERR_DEVICE;
+ }
+ }
+
+ bcopy(id, pfs->id, BLOCKSIZE);
+
+ pfs->version = id->version;
+ pfs->banks = id->banks;
+ pfs->inode_start_page = 1 + DEF_DIR_PAGES + (2 * pfs->banks);
+ pfs->dir_size = DEF_DIR_PAGES * PFS_ONE_PAGE;
+ pfs->inode_table = 1 * PFS_ONE_PAGE;
+ pfs->minode_table = (1 + pfs->banks) * PFS_ONE_PAGE;
+ pfs->dir_table = pfs->minode_table + (pfs->banks * PFS_ONE_PAGE);
+
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, PFS_LABEL_AREA, pfs->label));
+
+ ret = osPfsChecker(pfs);
+ pfs->status |= PFS_INITIALIZED;
+
+ return ret;
+}
+
+static s32 __osPfsCheckRamArea(OSPfs* pfs) {
+ s32 i = 0;
+ s32 ret = 0;
+ u8 temp1[BLOCKSIZE];
+ u8 temp2[BLOCKSIZE];
+ u8 save[BLOCKSIZE];
+
+ ERRCK(__osPfsSelectBank(pfs, 0));
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, 0, save));
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ temp1[i] = i;
+ }
+
+ ERRCK(__osContRamWrite(pfs->queue, pfs->channel, 0, temp1, FALSE));
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, 0, temp2));
+
+ if (bcmp(temp1, temp2, BLOCKSIZE) != 0) {
+ return PFS_ERR_DEVICE;
+ }
+
+ return __osContRamWrite(pfs->queue, pfs->channel, 0, save, FALSE);
+}
diff --git a/lib/ultralib/src/io/pfsisplug.c b/lib/ultralib/src/io/pfsisplug.c
new file mode 100644
index 0000000..71a18d9
--- /dev/null
+++ b/lib/ultralib/src/io/pfsisplug.c
@@ -0,0 +1,96 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "controller.h"
+
+OSPifRam __osPfsPifRam ALIGNED(16);
+
+s32 osPfsIsPlug(OSMesgQueue* mq, u8* pattern) {
+ s32 ret = 0;
+ OSMesg msg;
+ u8 bitpattern;
+ OSContStatus contData[MAXCONTROLLERS];
+ s32 channel;
+ u8 bits = 0;
+ s32 crcErrorCount = 3;
+
+ __osSiGetAccess();
+
+ do {
+ __osPfsRequestData(CONT_CMD_REQUEST_STATUS);
+
+ ret = __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(mq, &msg, OS_MESG_BLOCK);
+
+ ret = __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, &msg, OS_MESG_BLOCK);
+
+ __osPfsGetInitData(&bitpattern, &contData[0]);
+
+ for (channel = 0; channel < __osMaxControllers; channel++) {
+ if ((contData[channel].status & CONT_ADDR_CRC_ER) == 0) {
+ crcErrorCount--;
+ break;
+ }
+ }
+
+ if (channel == __osMaxControllers) {
+ crcErrorCount = 0;
+ }
+ } while (crcErrorCount > 0);
+
+ for (channel = 0; channel < __osMaxControllers; channel++) {
+ if ((contData[channel].errno == 0) && ((contData[channel].status & CONT_CARD_ON) != 0)) {
+ bits |= (1 << channel);
+ }
+ }
+ __osSiRelAccess();
+ *pattern = bits;
+ return ret;
+}
+
+void __osPfsRequestData(u8 cmd) {
+ u8* ptr = (u8*)&__osPfsPifRam;
+ __OSContRequesFormat requestformat;
+ int i;
+
+ __osContLastCmd = cmd;
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+ requestformat.dummy = CONT_CMD_NOP;
+ requestformat.txsize = CONT_CMD_REQUEST_STATUS_TX;
+ requestformat.rxsize = CONT_CMD_REQUEST_STATUS_RX;
+ requestformat.cmd = cmd;
+ requestformat.typeh = CONT_CMD_NOP;
+ requestformat.typel = CONT_CMD_NOP;
+ requestformat.status = CONT_CMD_NOP;
+ requestformat.dummy1 = CONT_CMD_NOP;
+
+ for (i = 0; i < __osMaxControllers; i++) {
+ *((__OSContRequesFormat*)ptr) = requestformat;
+ ptr += sizeof(__OSContRequesFormat);
+ }
+
+ *ptr = CONT_CMD_END;
+}
+
+void __osPfsGetInitData(u8* pattern, OSContStatus* data) {
+ u8* ptr;
+ __OSContRequesFormat requestformat;
+ int i;
+ u8 bits = 0;
+
+ ptr = (u8*)&__osPfsPifRam;
+
+ for (i = 0; i < __osMaxControllers; i++, ptr += sizeof(requestformat), data++) {
+ requestformat = *((__OSContRequesFormat*)ptr);
+ data->errno = CHNL_ERR(requestformat);
+
+ if (data->errno) {
+ continue;
+ }
+
+ data->type = ((requestformat.typel << 8) | requestformat.typeh);
+ data->status = requestformat.status;
+ bits |= (1 << i);
+ }
+ *pattern = bits;
+}
diff --git a/lib/ultralib/src/io/pfsnumfiles.c b/lib/ultralib/src/io/pfsnumfiles.c
new file mode 100644
index 0000000..e4480bd
--- /dev/null
+++ b/lib/ultralib/src/io/pfsnumfiles.c
@@ -0,0 +1,24 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsNumFiles(OSPfs *pfs, s32 *max_files, s32 *files_used) {
+ int j;
+ s32 ret;
+ __OSDir dir;
+ int files = 0;
+
+ PFS_CHECK_STATUS;
+ ERRCK(__osCheckId(pfs));
+ SET_ACTIVEBANK_TO_ZERO;
+
+ for (j = 0; j < pfs->dir_size; j++) {
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&dir));
+
+ if (dir.company_code != 0 && dir.game_code != 0) {
+ files++;
+ }
+ }
+ *files_used = files;
+ *max_files = pfs->dir_size;
+ return __osPfsGetStatus(pfs->queue, pfs->channel);
+}
diff --git a/lib/ultralib/src/io/pfsreadwritefile.c b/lib/ultralib/src/io/pfsreadwritefile.c
new file mode 100644
index 0000000..14a6e45
--- /dev/null
+++ b/lib/ultralib/src/io/pfsreadwritefile.c
@@ -0,0 +1,119 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+static s32 __osPfsGetNextPage(OSPfs *pfs, u8 *bank, __OSInode *inode, __OSInodeUnit *page) {
+ s32 ret;
+
+ if (page->inode_t.bank != *bank) {
+ *bank = page->inode_t.bank;
+ ERRCK(__osPfsRWInode(pfs, inode, 0, *bank));
+ }
+
+ *page = inode->inode_page[page->inode_t.page];
+
+ if (page->ipage < pfs->inode_start_page ||
+ page->inode_t.bank >= pfs->banks ||
+ page->inode_t.page <= 0 ||
+ page->inode_t.page >= ARRLEN(inode->inode_page)) {
+
+ if (page->ipage == 1) {
+ return PFS_ERR_INVALID;
+ }
+
+ return PFS_ERR_INCONSISTENT;
+ }
+ return 0;
+}
+s32 osPfsReadWriteFile(OSPfs *pfs, s32 file_no, u8 flag, int offset, int size_in_bytes, u8 *data_buffer) {
+ s32 ret;
+ __OSDir dir;
+ __OSInode inode;
+ __OSInodeUnit cur_page;
+ int cur_block;
+ int siz_block;
+ u8 *buffer;
+ u8 bank;
+ u16 blockno;
+
+ if (file_no >= pfs->dir_size || file_no < 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ if (size_in_bytes <= 0 || ((size_in_bytes & (BLOCKSIZE - 1)) != 0)) {
+ return PFS_ERR_INVALID;
+ }
+
+ if (offset < 0 || ((offset & (BLOCKSIZE - 1)) != 0)) {
+ return PFS_ERR_INVALID;
+ }
+
+ PFS_CHECK_STATUS;
+ PFS_CHECK_ID;
+ SET_ACTIVEBANK_TO_ZERO;
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + file_no, (u8*)&dir));
+
+ if (dir.company_code == 0 || dir.game_code == 0) {
+ return PFS_ERR_INVALID;
+ }
+
+ if (dir.start_page.ipage < pfs->inode_start_page ||
+ dir.start_page.inode_t.bank >= pfs->banks ||
+ dir.start_page.inode_t.page <= 0 ||
+ dir.start_page.inode_t.page >= ARRLEN(inode.inode_page)) {
+ if ((dir.start_page.ipage == 1)) {
+ return PFS_ERR_INVALID;
+ }
+
+ return PFS_ERR_INCONSISTENT;
+ }
+
+ if (flag == PFS_READ && (dir.status & DIR_STATUS_OCCUPIED) == 0) {
+ return PFS_ERR_BAD_DATA;
+ }
+
+ bank = -1;
+ cur_block = offset / BLOCKSIZE;
+ cur_page = dir.start_page;
+
+ while (cur_block >= PFS_ONE_PAGE) {
+ ERRCK(__osPfsGetNextPage(pfs, &bank, &inode, &cur_page));
+ cur_block -= PFS_ONE_PAGE;
+ }
+
+ siz_block = size_in_bytes / BLOCKSIZE;
+ buffer = data_buffer;
+
+ while (siz_block > 0) {
+ if (cur_block == PFS_ONE_PAGE) {
+ ERRCK(__osPfsGetNextPage(pfs, &bank, &inode, &cur_page));
+ cur_block = 0;
+ }
+
+ if (pfs->activebank != cur_page.inode_t.bank) {
+ ERRCK(__osPfsSelectBank(pfs, cur_page.inode_t.bank));
+ }
+
+ blockno = cur_page.inode_t.page * PFS_ONE_PAGE + cur_block;
+
+ if (flag == OS_READ) {
+ ret = __osContRamRead(pfs->queue, pfs->channel, blockno, buffer);
+ } else {
+ ret = __osContRamWrite(pfs->queue, pfs->channel, blockno, buffer, FALSE);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ buffer += BLOCKSIZE;
+ cur_block++;
+ siz_block--;
+ }
+
+ if (flag == PFS_WRITE && (dir.status & DIR_STATUS_OCCUPIED) == 0) {
+ dir.status |= DIR_STATUS_OCCUPIED;
+ SET_ACTIVEBANK_TO_ZERO;
+ ERRCK(__osContRamWrite(pfs->queue, pfs->channel, pfs->dir_table + file_no, (u8*)&dir, FALSE));
+ }
+
+ return __osPfsGetStatus(pfs->queue, pfs->channel);
+}
diff --git a/lib/ultralib/src/io/pfsreformat.c b/lib/ultralib/src/io/pfsreformat.c
new file mode 100644
index 0000000..cbd4b6a
--- /dev/null
+++ b/lib/ultralib/src/io/pfsreformat.c
@@ -0,0 +1,70 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+#include "siint.h"
+
+s32 osPfsReFormat(OSPfs *pfs, OSMesgQueue *queue, int channel) {
+ int j;
+ int i;
+ __OSInode inode;
+ u8 tmp_data[32];
+ u8 *ptr;
+ s32 ret;
+ __osSiGetAccess();
+ ret = __osPfsGetStatus(queue, channel);
+
+ if (ret != 0) {
+ __osSiRelAccess();
+ return ret;
+ }
+
+ pfs->status ^= PFS_INITIALIZED;
+ pfs->queue = queue;
+ pfs->channel = channel;
+ __osSiRelAccess();
+ ERRCK(__osGetId(pfs));
+
+ SET_ACTIVEBANK_TO_ZERO;
+
+ for (j = 0; j < ARRLEN(tmp_data); j++) {
+ tmp_data[j] = 0;
+ }
+
+ for (j = 0; j < pfs->dir_size; j++)
+ {
+ ERRCK(__osContRamWrite(queue, channel, pfs->dir_table + j, tmp_data, FALSE));
+ }
+
+ for (j = 0; j < pfs->inode_start_page; j++) {
+ inode.inode_page[j].ipage = 0;
+ }
+
+ for (j = pfs->inode_start_page; j < ARRLEN(inode.inode_page); j++) {
+ inode.inode_page[j].ipage = 3;
+ }
+
+ inode.inode_page[0].ipage = __osSumcalc((u8*)(inode.inode_page + pfs->inode_start_page),
+ (ARRLEN(inode.inode_page) - pfs->inode_start_page) * sizeof(__OSInodeUnit));
+ ptr = (u8 *)&inode;
+
+ for (j = 0; j < PFS_ONE_PAGE; j++) {
+ ERRCK(__osContRamWrite(queue, channel, pfs->inode_table + j, ptr + j * BLOCKSIZE, FALSE));
+ ERRCK(__osContRamWrite(queue, channel, pfs->minode_table + j, ptr + j * BLOCKSIZE, FALSE));
+ }
+
+ for (i = 1; i < pfs->banks; i++) {
+ for (j = 1; j < ARRLEN(inode.inode_page); j++) {
+ inode.inode_page[j].ipage = 3;
+ }
+
+ inode.inode_page[0].ipage = __osSumcalc((u8*)(inode.inode_page + 1),
+ (ARRLEN(inode.inode_page) - 1) * sizeof(__OSInodeUnit));
+ ptr = (u8 *)&inode;
+
+ for (j = 0; j < PFS_ONE_PAGE; j++) {
+ ERRCK(__osContRamWrite(queue, channel, pfs->inode_table + i * PFS_ONE_PAGE + j, ptr + j * BLOCKSIZE, FALSE));
+ ERRCK(__osContRamWrite(queue, channel, pfs->minode_table + i * PFS_ONE_PAGE + j, ptr + j * BLOCKSIZE, FALSE));
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/pfsrepairid.c b/lib/ultralib/src/io/pfsrepairid.c
new file mode 100644
index 0000000..f29590a
--- /dev/null
+++ b/lib/ultralib/src/io/pfsrepairid.c
@@ -0,0 +1,18 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsRepairId(OSPfs *pfs) {
+ s32 ret = 0;
+
+ if ((pfs->status & (PFS_INITIALIZED | PFS_ID_BROKEN))) {
+ ret = __osGetId(pfs);
+
+ if (ret == 0) {
+ pfs->status &= ~(PFS_ID_BROKEN);
+ }
+ } else {
+ ret = PFS_ERR_INVALID;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pfssearchfile.c b/lib/ultralib/src/io/pfssearchfile.c
new file mode 100644
index 0000000..04a4155
--- /dev/null
+++ b/lib/ultralib/src/io/pfssearchfile.c
@@ -0,0 +1,51 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsFindFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, s32 *file_no) {
+ s32 j;
+ int i;
+ __OSDir dir;
+ s32 ret = 0;
+ int fail;
+
+ if (!(pfs->status & PFS_INITIALIZED)) {
+ return PFS_ERR_INVALID;
+ }
+
+ ERRCK(__osCheckId(pfs));
+
+ for (j = 0; j < pfs->dir_size; j++) {
+ ERRCK(__osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&dir));
+ ERRCK(__osPfsGetStatus(pfs->queue, pfs->channel));
+
+ if ((dir.company_code == company_code) && dir.game_code == game_code) {
+ fail = FALSE;
+
+ if (game_name != NULL) {
+ for (i = 0; i < ARRLEN(dir.game_name); i++) {
+ if (dir.game_name[i] != game_name[i]) {
+ fail = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (ext_name != NULL && !fail) {
+ for (i = 0; i < ARRLEN(dir.ext_name); i++) {
+ if (dir.ext_name[i] != ext_name[i]) {
+ fail = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!fail) {
+ *file_no = j;
+ return ret;
+ }
+ }
+ }
+
+ *file_no = -1;
+ return PFS_ERR_INVALID;
+}
diff --git a/lib/ultralib/src/io/pfsselectbank.c b/lib/ultralib/src/io/pfsselectbank.c
new file mode 100644
index 0000000..fb0ab48
--- /dev/null
+++ b/lib/ultralib/src/io/pfsselectbank.c
@@ -0,0 +1,20 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 __osPfsSelectBank(OSPfs* pfs, u8 bank) {
+ u8 temp[BLOCKSIZE];
+ int i;
+ s32 ret = 0;
+
+ for (i = 0; i < BLOCKSIZE; i++) {
+ temp[i] = bank;
+ }
+
+ ret = __osContRamWrite(pfs->queue, pfs->channel, CONT_BLOCK_DETECT, temp, FALSE);
+
+ if (ret == 0) {
+ pfs->activebank = bank;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pfssetlabel.c b/lib/ultralib/src/io/pfssetlabel.c
new file mode 100644
index 0000000..a0584cf
--- /dev/null
+++ b/lib/ultralib/src/io/pfssetlabel.c
@@ -0,0 +1,31 @@
+#include "PR/os_internal.h"
+#include "controller.h"
+
+s32 osPfsSetLabel(OSPfs *pfs, u8 *label) {
+ int i;
+ s32 ret;
+
+ if (!(pfs->status & PFS_INITIALIZED)) {
+ return PFS_ERR_INVALID;
+ }
+
+ ERRCK(__osCheckId(pfs));
+
+ if (label != NULL) {
+ for (i = 0; i < ARRLEN(pfs->label); i++) {
+ if (*label == 0) {
+ break;
+ }
+
+ *(pfs->label + i) = *label++;
+ }
+ }
+
+ if (pfs->activebank != 0) {
+ ret = (__osPfsSelectBank(pfs, 0));
+ if (ret == 0) {
+ ret = (__osContRamWrite(pfs->queue, pfs->channel, PFS_LABEL_AREA, pfs->label, FALSE));
+ }
+ }
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pi.c b/lib/ultralib/src/io/pi.c
new file mode 100644
index 0000000..1c350c5
--- /dev/null
+++ b/lib/ultralib/src/io/pi.c
@@ -0,0 +1,13 @@
+
+#include "PR/os_internal.h"
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+int __osPiDeviceBusy() {
+ register u32 stat = IO_READ(PI_STATUS_REG);
+ if (stat & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY))
+ return 1;
+ return 0;
+}
diff --git a/lib/ultralib/src/io/piacs.c b/lib/ultralib/src/io/piacs.c
new file mode 100644
index 0000000..03ab11e
--- /dev/null
+++ b/lib/ultralib/src/io/piacs.c
@@ -0,0 +1,24 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+
+#define PI_Q_BUF_LEN 1
+u32 __osPiAccessQueueEnabled = 0;
+OSMesgQueue __osPiAccessQueue ALIGNED(8);
+static OSMesg piAccessBuf[PI_Q_BUF_LEN];
+
+void __osPiCreateAccessQueue(void) {
+ __osPiAccessQueueEnabled = 1;
+ osCreateMesgQueue(&__osPiAccessQueue, piAccessBuf, PI_Q_BUF_LEN);
+ osSendMesg(&__osPiAccessQueue, NULL, OS_MESG_NOBLOCK);
+}
+
+void __osPiGetAccess(void) {
+ OSMesg dummyMesg;
+ if (!__osPiAccessQueueEnabled)
+ __osPiCreateAccessQueue();
+ osRecvMesg(&__osPiAccessQueue, &dummyMesg, OS_MESG_BLOCK);
+}
+
+void __osPiRelAccess(void) {
+ osSendMesg(&__osPiAccessQueue, NULL, OS_MESG_NOBLOCK);
+}
diff --git a/lib/ultralib/src/io/pidma.c b/lib/ultralib/src/io/pidma.c
new file mode 100644
index 0000000..077f13a
--- /dev/null
+++ b/lib/ultralib/src/io/pidma.c
@@ -0,0 +1,30 @@
+#include "PR/os_internal.h"
+#include "piint.h"
+
+s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, u32 devAddr, void *dramAddr, u32 size, OSMesgQueue *mq) {
+ register s32 ret;
+ if (!__osPiDevMgr.active) {
+ return -1;
+ }
+
+ if (direction == OS_READ) {
+ mb->hdr.type = OS_MESG_TYPE_DMAREAD;
+ } else {
+ mb->hdr.type = OS_MESG_TYPE_DMAWRITE;
+ }
+
+ mb->hdr.pri = priority;
+ mb->hdr.retQueue = mq;
+ mb->dramAddr = dramAddr;
+ mb->devAddr = devAddr;
+ mb->size = size;
+ mb->piHandle = NULL;
+
+ if (priority == OS_MESG_PRI_HIGH) {
+ ret = osJamMesg(osPiGetCmdQueue(), (OSMesg)mb, OS_MESG_NOBLOCK);
+ } else {
+ ret = osSendMesg(osPiGetCmdQueue(), (OSMesg)mb, OS_MESG_NOBLOCK);
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/pigetcmdq.c b/lib/ultralib/src/io/pigetcmdq.c
new file mode 100644
index 0000000..809cdb2
--- /dev/null
+++ b/lib/ultralib/src/io/pigetcmdq.c
@@ -0,0 +1,10 @@
+#include "PR/os_internal.h"
+#include "piint.h"
+
+OSMesgQueue *osPiGetCmdQueue(void) {
+ if (!__osPiDevMgr.active) {
+ return NULL;
+ }
+
+ return __osPiDevMgr.cmdQueue;
+}
diff --git a/lib/ultralib/src/io/pigetstat.c b/lib/ultralib/src/io/pigetstat.c
new file mode 100644
index 0000000..43e9a27
--- /dev/null
+++ b/lib/ultralib/src/io/pigetstat.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+u32 osPiGetStatus() {
+ return IO_READ(PI_STATUS_REG);
+}
diff --git a/lib/ultralib/src/io/pigettype.c b/lib/ultralib/src/io/pigettype.c
new file mode 100644
index 0000000..f918306
--- /dev/null
+++ b/lib/ultralib/src/io/pigettype.c
@@ -0,0 +1,8 @@
+#include "PR/os_internal.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 osPiGetDeviceType() {
+ return osRomType;
+}
diff --git a/lib/ultralib/src/io/piint.h b/lib/ultralib/src/io/piint.h
new file mode 100644
index 0000000..734fdde
--- /dev/null
+++ b/lib/ultralib/src/io/piint.h
@@ -0,0 +1,154 @@
+#ifndef _PIINT_H_
+#define _PIINT_H_
+
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+//https://github.com/LuigiBlood/64dd/wiki/Memory-Map
+
+#define LEO_BASE_REG 0x05000000
+
+#define LEO_CMD (LEO_BASE_REG + 0x508)
+#define LEO_STATUS (LEO_BASE_REG + 0x508)
+
+#define LEO_BM_CTL (LEO_BASE_REG + 0x510)
+#define LEO_BM_STATUS (LEO_BASE_REG + 0x510)
+
+#define LEO_SEQ_CTL (LEO_BASE_REG + 0x518)
+#define LEO_SEQ_STATUS (LEO_BASE_REG + 0x518)
+
+#define LEO_C2_BUFF (LEO_BASE_REG + 0x000) //C2 Sector Buffer
+#define LEO_SECTOR_BUFF (LEO_BASE_REG + 0x400) //Data Sector Buffer
+#define LEO_DATA (LEO_BASE_REG + 0x500) //Data
+#define LEO_MISC_REG (LEO_BASE_REG + 0x504) //Misc Register
+#define LEO_CUR_TK (LEO_BASE_REG + 0x50C) //Current Track
+#define LEO_ERR_SECTOR (LEO_BASE_REG + 0x514) //Sector Error Status
+#define LEO_CUR_SECTOR (LEO_BASE_REG + 0x51C) //Current Sector
+#define LEO_HARD_RESET (LEO_BASE_REG + 0x520) //Hard Reset
+#define LEO_C1_S0 (LEO_BASE_REG + 0x524) //C1
+#define LEO_HOST_SECBYTE (LEO_BASE_REG + 0x528) //Sector Size (in bytes)
+#define LEO_C1_S2 (LEO_BASE_REG + 0x52C) //C1
+#define LEO_SEC_BYTE (LEO_BASE_REG + 0x530) //Sectors per Block, Full Size
+#define LEO_C1_S4 (LEO_BASE_REG + 0x534) //C1
+#define LEO_C1_S6 (LEO_BASE_REG + 0x538) //C1
+#define LEO_CUR_ADDR (LEO_BASE_REG + 0x53C) //Current Address?
+#define LEO_ID_REG (LEO_BASE_REG + 0x540) //ID
+#define LEO_TEST_REG (LEO_BASE_REG + 0x544) //Test Read
+#define LEO_TEST_PIN_SEL (LEO_BASE_REG + 0x548) //Test Write
+#define LEO_RAM_ADDR (LEO_BASE_REG + 0x580) //Microsequencer RAM
+
+#define LEO_STATUS_PRESENCE_MASK 0xFFFF
+
+#define LEO_STATUS_DATA_REQUEST 0x40000000
+#define LEO_STATUS_C2_TRANSFER 0x10000000
+#define LEO_STATUS_BUFFER_MANAGER_ERROR 0x08000000
+#define LEO_STATUS_BUFFER_MANAGER_INTERRUPT 0x04000000
+#define LEO_STATUS_MECHANIC_INTERRUPT 0x02000000
+#define LEO_STATUS_DISK_PRESENT 0x01000000
+#define LEO_STATUS_BUSY_STATE 0x00800000
+#define LEO_STATUS_RESET_STATE 0x00400000
+#define LEO_STATUS_MOTOR_NOT_SPINNING 0x00100000
+#define LEO_STATUS_HEAD_RETRACTED 0x00080000
+#define LEO_STATUS_WRITE_PROTECT_ERROR 0x00040000
+#define LEO_STATUS_MECHANIC_ERROR 0x00020000
+#define LEO_STATUS_DISK_CHANGE 0x00010000
+
+#define LEO_STATUS_MODE_MASK (LEO_STATUS_MOTOR_NOT_SPINNING | LEO_STATUS_HEAD_RETRACTED)
+#define LEO_STATUS_MODE_SLEEP (LEO_STATUS_MOTOR_NOT_SPINNING | LEO_STATUS_HEAD_RETRACTED)
+#define LEO_STATUS_MODE_STANDBY (LEO_STATUS_HEAD_RETRACTED)
+#define LEO_STATUS_MODE_ACTIVE 0
+
+#define LEO_CUR_TK_INDEX_LOCK 0x60000000
+
+#define LEO_BM_STATUS_RUNNING 0x80000000 //Running
+#define LEO_BM_STATUS_ERROR 0x04000000 //Error
+#define LEO_BM_STATUS_MICRO 0x02000000 //Micro Status?
+#define LEO_BM_STATUS_BLOCK 0x01000000 //Block Transfer
+#define LEO_BM_STATUS_C1CORRECTION 0x00800000 //C1 Correction
+#define LEO_BM_STATUS_C1DOUBLE 0x00400000 //C1 Double
+#define LEO_BM_STATUS_C1SINGLE 0x00200000 //C1 Single
+#define LEO_BM_STATUS_C1ERROR 0x00010000 //C1 Error
+
+#define LEO_BM_CTL_START 0x80000000 //Start Buffer Manager
+#define LEO_BM_CTL_MODE 0x40000000 //Buffer Manager Mode
+#define LEO_BM_CTL_IMASK 0x20000000 //BM Interrupt Mask
+#define LEO_BM_CTL_RESET 0x10000000 //Buffer Manager Reset
+#define LEO_BM_CTL_DISABLE_OR 0x08000000 //Disable OR Check?
+#define LEO_BM_CTL_DISABLE_C1 0x04000000 //Disable C1 Correction
+#define LEO_BM_CTL_BLOCK 0x02000000 //Block Transfer
+#define LEO_BM_CTL_CLR_MECHANIC_INTR 0x01000000 //Mechanic Interrupt Reset
+
+#define LEO_BM_CTL_CONTROL_MASK 0xFF000000
+#define LEO_BM_CTL_SECTOR_MASK 0x00FF0000
+#define LEO_BM_CTL_SECTOR_SHIFT 16
+
+#define LEO_CMD_TYPE_0 0 //TODO: name
+#define LEO_CMD_TYPE_1 1 //TODO: name
+#define LEO_CMD_TYPE_2 2 //TODO: name
+
+#define LEO_ERROR_GOOD 0
+#define LEO_ERROR_4 4 //maybe busy?
+#define LEO_ERROR_22 22 //
+#define LEO_ERROR_23 23 //unrecovered read error?
+#define LEO_ERROR_24 24 //no reference position found?
+#define LEO_ERROR_29 29 //
+
+extern OSDevMgr __osPiDevMgr;
+extern OSPiHandle *__osCurrentHandle[2];
+extern OSPiHandle CartRomHandle;
+extern OSPiHandle LeoDiskHandle;
+extern OSMesgQueue __osPiAccessQueue;
+extern u32 __osPiAccessQueueEnabled;
+
+int __osPiDeviceBusy(void);
+void __osDevMgrMain(void *);
+void __osPiCreateAccessQueue(void);
+void __osPiRelAccess(void);
+void __osPiGetAccess(void);
+s32 __osPiRawStartDma(s32, u32 , void *, u32 );
+s32 __osPiRawWriteIo(u32, u32);
+s32 __osPiRawReadIo(u32, u32 *);
+s32 __osEPiRawWriteIo(OSPiHandle *, u32 , u32);
+s32 __osEPiRawReadIo(OSPiHandle *, u32 , u32 *);
+s32 __osEPiRawStartDma(OSPiHandle *, s32 , u32 , void *, u32 );
+OSMesgQueue *osPiGetCmdQueue(void);
+
+#define WAIT_ON_IOBUSY(stat) \
+ while (stat = IO_READ(PI_STATUS_REG), stat & (PI_STATUS_IO_BUSY | PI_STATUS_DMA_BUSY)) \
+ ; \
+ (void)0
+
+#define UPDATE_REG(pihandle, reg, var) \
+ if (cHandle->var != pihandle->var) \
+ IO_WRITE(reg, pihandle->var)
+
+#define EPI_SYNC(pihandle, stat, domain) \
+ \
+ WAIT_ON_IOBUSY(stat); \
+ \
+ domain = pihandle->domain; \
+ if (__osCurrentHandle[domain]->type != pihandle->type) \
+ { \
+ OSPiHandle *cHandle = __osCurrentHandle[domain]; \
+ if (domain == PI_DOMAIN1) \
+ { \
+ UPDATE_REG(pihandle, PI_BSD_DOM1_LAT_REG, latency); \
+ UPDATE_REG(pihandle, PI_BSD_DOM1_PGS_REG, pageSize); \
+ UPDATE_REG(pihandle, PI_BSD_DOM1_RLS_REG, relDuration); \
+ UPDATE_REG(pihandle, PI_BSD_DOM1_PWD_REG, pulse); \
+ } \
+ else \
+ { \
+ UPDATE_REG(pihandle, PI_BSD_DOM2_LAT_REG, latency); \
+ UPDATE_REG(pihandle, PI_BSD_DOM2_PGS_REG, pageSize); \
+ UPDATE_REG(pihandle, PI_BSD_DOM2_RLS_REG, relDuration); \
+ UPDATE_REG(pihandle, PI_BSD_DOM2_PWD_REG, pulse); \
+ } \
+ cHandle->type = pihandle->type; \
+ cHandle->latency = pihandle->latency; \
+ cHandle->pageSize = pihandle->pageSize; \
+ cHandle->relDuration = pihandle->relDuration; \
+ cHandle->pulse = pihandle->pulse; \
+ }(void)0
+
+#endif
diff --git a/lib/ultralib/src/io/pimgr.c b/lib/ultralib/src/io/pimgr.c
new file mode 100644
index 0000000..c757532
--- /dev/null
+++ b/lib/ultralib/src/io/pimgr.c
@@ -0,0 +1,53 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "piint.h"
+
+OSDevMgr __osPiDevMgr = {0};
+OSPiHandle *__osPiTable = NULL;
+OSPiHandle __Dom1SpeedParam ALIGNED(8);
+OSPiHandle __Dom2SpeedParam ALIGNED(8);
+OSPiHandle *__osCurrentHandle[2] ALIGNED(8) = {&__Dom1SpeedParam, &__Dom2SpeedParam};
+static OSThread piThread;
+static char piThreadStack[OS_PIM_STACKSIZE];
+static OSMesgQueue piEventQueue;
+static OSMesg piEventBuf[1];
+
+void osCreatePiManager(OSPri pri, OSMesgQueue *cmdQ, OSMesg *cmdBuf, s32 cmdMsgCnt) {
+ u32 savedMask;
+ OSPri oldPri;
+ OSPri myPri;
+
+ if (!__osPiDevMgr.active) {
+ osCreateMesgQueue(cmdQ, cmdBuf, cmdMsgCnt);
+ osCreateMesgQueue(&piEventQueue, (OSMesg*)piEventBuf, 1);
+
+ if (!__osPiAccessQueueEnabled) {
+ __osPiCreateAccessQueue();
+ }
+
+ osSetEventMesg(OS_EVENT_PI, &piEventQueue, (OSMesg)0x22222222);
+ oldPri = -1;
+ myPri = osGetThreadPri(NULL);
+
+ if (myPri < pri) {
+ oldPri = myPri;
+ osSetThreadPri(NULL, pri);
+ }
+
+ savedMask = __osDisableInt();
+ __osPiDevMgr.active = 1;
+ __osPiDevMgr.thread = &piThread;
+ __osPiDevMgr.cmdQueue = cmdQ;
+ __osPiDevMgr.evtQueue = &piEventQueue;
+ __osPiDevMgr.acsQueue = &__osPiAccessQueue;
+ __osPiDevMgr.dma = __osPiRawStartDma;
+ __osPiDevMgr.edma = __osEPiRawStartDma;
+ osCreateThread(&piThread, 0, __osDevMgrMain, &__osPiDevMgr, &piThreadStack[OS_PIM_STACKSIZE], pri);
+ osStartThread(&piThread);
+ __osRestoreInt(savedMask);
+
+ if (oldPri != -1) {
+ osSetThreadPri(NULL, oldPri);
+ }
+ }
+}
diff --git a/lib/ultralib/src/io/pirawdma.c b/lib/ultralib/src/io/pirawdma.c
new file mode 100644
index 0000000..d766064
--- /dev/null
+++ b/lib/ultralib/src/io/pirawdma.c
@@ -0,0 +1,25 @@
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osPiRawStartDma(s32 direction, u32 devAddr, void* dramAddr, u32 size) {
+ register u32 stat;
+
+ WAIT_ON_IOBUSY(stat);
+
+ IO_WRITE(PI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr));
+ IO_WRITE(PI_CART_ADDR_REG, K1_TO_PHYS((u32)osRomBase | devAddr));
+
+ switch (direction) {
+ case OS_READ:
+ IO_WRITE(PI_WR_LEN_REG, size - 1);
+ break;
+ case OS_WRITE:
+ IO_WRITE(PI_RD_LEN_REG, size - 1);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
diff --git a/lib/ultralib/src/io/pirawread.c b/lib/ultralib/src/io/pirawread.c
new file mode 100644
index 0000000..8531d17
--- /dev/null
+++ b/lib/ultralib/src/io/pirawread.c
@@ -0,0 +1,13 @@
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osPiRawReadIo(u32 devAddr, u32* data) {
+ register u32 stat;
+
+ WAIT_ON_IOBUSY(stat);
+ *data = IO_READ((u32)osRomBase | devAddr);
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/pirawwrite.c b/lib/ultralib/src/io/pirawwrite.c
new file mode 100644
index 0000000..5e9d7c5
--- /dev/null
+++ b/lib/ultralib/src/io/pirawwrite.c
@@ -0,0 +1,13 @@
+#include "piint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osPiRawWriteIo(u32 devAddr, u32 data) {
+ register u32 stat;
+
+ WAIT_ON_IOBUSY(stat);
+ IO_WRITE((u32)osRomBase | devAddr, data);
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/piread.c b/lib/ultralib/src/io/piread.c
new file mode 100644
index 0000000..2fed7a6
--- /dev/null
+++ b/lib/ultralib/src/io/piread.c
@@ -0,0 +1,13 @@
+#include "piint.h"
+
+s32 __osPiRawReadIo(u32, u32*);
+
+s32 osPiReadIo(u32 devAddr, u32* data) {
+ register s32 ret;
+
+ __osPiGetAccess();
+ ret = __osPiRawReadIo(devAddr, data);
+ __osPiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/piwrite.c b/lib/ultralib/src/io/piwrite.c
new file mode 100644
index 0000000..9935331
--- /dev/null
+++ b/lib/ultralib/src/io/piwrite.c
@@ -0,0 +1,13 @@
+#include "piint.h"
+
+s32 __osPiRawWriteIo(u32, u32);
+
+s32 osPiWriteIo(u32 devAddr, u32 data) {
+ register s32 ret;
+
+ __osPiGetAccess();
+ ret = __osPiRawWriteIo(devAddr, data);
+ __osPiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/io/si.c b/lib/ultralib/src/io/si.c
new file mode 100644
index 0000000..f97691b
--- /dev/null
+++ b/lib/ultralib/src/io/si.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+#include "siint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+int __osSiDeviceBusy() {
+ register u32 stat = IO_READ(SI_STATUS_REG);
+
+ if (stat & (SI_STATUS_DMA_BUSY | SI_STATUS_RD_BUSY)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/lib/ultralib/src/io/siacs.c b/lib/ultralib/src/io/siacs.c
new file mode 100644
index 0000000..f515c49
--- /dev/null
+++ b/lib/ultralib/src/io/siacs.c
@@ -0,0 +1,24 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+
+#define SI_Q_BUF_LEN 1
+static OSMesg siAccessBuf[SI_Q_BUF_LEN] ALIGNED(8);
+OSMesgQueue __osSiAccessQueue ALIGNED(8);
+u32 __osSiAccessQueueEnabled = 0;
+
+void __osSiCreateAccessQueue(void) {
+ __osSiAccessQueueEnabled = 1;
+ osCreateMesgQueue(&__osSiAccessQueue, siAccessBuf, SI_Q_BUF_LEN);
+ osSendMesg(&__osSiAccessQueue, NULL, OS_MESG_NOBLOCK);
+}
+
+void __osSiGetAccess(void) {
+ OSMesg dummyMesg;
+ if (!__osSiAccessQueueEnabled)
+ __osSiCreateAccessQueue();
+ osRecvMesg(&__osSiAccessQueue, &dummyMesg, OS_MESG_BLOCK);
+}
+
+void __osSiRelAccess(void) {
+ osSendMesg(&__osSiAccessQueue, NULL, OS_MESG_NOBLOCK);
+}
diff --git a/lib/ultralib/src/io/sigetstat.c b/lib/ultralib/src/io/sigetstat.c
new file mode 100644
index 0000000..0225445
--- /dev/null
+++ b/lib/ultralib/src/io/sigetstat.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "siint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+u32 __osSiGetStatus() {
+ return IO_READ(SI_STATUS_REG);
+}
diff --git a/lib/ultralib/src/io/siint.h b/lib/ultralib/src/io/siint.h
new file mode 100755
index 0000000..636a87f
--- /dev/null
+++ b/lib/ultralib/src/io/siint.h
@@ -0,0 +1,15 @@
+#ifndef _SIINT_H
+#define _SIINT_H
+
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+extern s32 __osEepromRead16K;
+extern u8 __osPfsInodeCacheBank;
+
+void __osSiGetAccess(void);
+void __osSiRelAccess(void);
+int __osSiDeviceBusy(void);
+void __osSiCreateAccessQueue(void);
+
+#endif
diff --git a/lib/ultralib/src/io/sirawdma.c b/lib/ultralib/src/io/sirawdma.c
new file mode 100644
index 0000000..e27ff10
--- /dev/null
+++ b/lib/ultralib/src/io/sirawdma.c
@@ -0,0 +1,29 @@
+#include "PR/os_internal.h"
+#include "siint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSiRawStartDma(s32 direction, void *dramAddr) {
+ if (IO_READ(SI_STATUS_REG) & (SI_STATUS_DMA_BUSY | SI_STATUS_RD_BUSY)) {
+ return -1;
+ }
+
+ if (direction == OS_WRITE) {
+ osWritebackDCache(dramAddr, 64);
+ }
+
+ IO_WRITE(SI_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr));
+
+ if (direction == OS_READ) {
+ IO_WRITE(SI_PIF_ADDR_RD64B_REG, PIF_RAM_START);
+ } else {
+ IO_WRITE(SI_PIF_ADDR_WR64B_REG, PIF_RAM_START);
+ }
+
+ if (direction == OS_READ) {
+ osInvalDCache(dramAddr, 64);
+ }
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/sirawread.c b/lib/ultralib/src/io/sirawread.c
new file mode 100644
index 0000000..5381cf1
--- /dev/null
+++ b/lib/ultralib/src/io/sirawread.c
@@ -0,0 +1,14 @@
+#include "PR/os_internal.h"
+#include "siint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSiRawReadIo(u32 devAddr, u32* data) {
+ if (__osSiDeviceBusy()) {
+ return -1;
+ }
+
+ *data = IO_READ(devAddr);
+ return 0;
+}
diff --git a/lib/ultralib/src/io/sirawwrite.c b/lib/ultralib/src/io/sirawwrite.c
new file mode 100644
index 0000000..9967c1d
--- /dev/null
+++ b/lib/ultralib/src/io/sirawwrite.c
@@ -0,0 +1,14 @@
+#include "PR/os_internal.h"
+#include "siint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSiRawWriteIo(u32 devAddr, u32 data) {
+ if (__osSiDeviceBusy()) {
+ return -1;
+ }
+
+ IO_WRITE(devAddr, data);
+ return 0;
+}
diff --git a/lib/ultralib/src/io/sp.c b/lib/ultralib/src/io/sp.c
new file mode 100755
index 0000000..95d5b20
--- /dev/null
+++ b/lib/ultralib/src/io/sp.c
@@ -0,0 +1,17 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "PR/sptask.h"
+#include "../os/osint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+int __osSpDeviceBusy() {
+ register u32 stat = IO_READ(SP_STATUS_REG);
+
+ if (stat & (SP_STATUS_DMA_BUSY | SP_STATUS_DMA_FULL | SP_STATUS_IO_FULL)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/lib/ultralib/src/io/spgetstat.c b/lib/ultralib/src/io/spgetstat.c
new file mode 100755
index 0000000..0cdfda6
--- /dev/null
+++ b/lib/ultralib/src/io/spgetstat.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+u32 __osSpGetStatus() {
+ return IO_READ(SP_STATUS_REG);
+}
diff --git a/lib/ultralib/src/io/sprawdma.c b/lib/ultralib/src/io/sprawdma.c
new file mode 100755
index 0000000..41239b1
--- /dev/null
+++ b/lib/ultralib/src/io/sprawdma.c
@@ -0,0 +1,30 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "../os/osint.h"
+#include "assert.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSpRawStartDma(s32 direction, u32 devAddr, void *dramAddr, u32 size) {
+ // These asserts are present in debug builds, but the line numbers won't match as-is
+ // TODO Add an assert spoofing macro that lets you specify a line number
+ assert(((u32)devAddr & 0x7) == 0);
+ assert(((u32)dramAddr & 0x7) == 0);
+ assert(((u32)size & 0x7) == 0);
+
+ if (__osSpDeviceBusy()) {
+ return -1;
+ }
+
+ IO_WRITE(SP_MEM_ADDR_REG, devAddr);
+ IO_WRITE(SP_DRAM_ADDR_REG, osVirtualToPhysical(dramAddr));
+
+ if (direction == OS_READ) {
+ IO_WRITE(SP_WR_LEN_REG, size - 1);
+ } else {
+ IO_WRITE(SP_RD_LEN_REG, size - 1);
+ }
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/sprawread.c b/lib/ultralib/src/io/sprawread.c
new file mode 100755
index 0000000..affc78b
--- /dev/null
+++ b/lib/ultralib/src/io/sprawread.c
@@ -0,0 +1,16 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "../os/osint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSpRawReadIo(u32 devAddr, u32 *data) {
+ if (__osSpDeviceBusy()) {
+ return -1;
+ }
+
+ *data = IO_READ(devAddr);
+ return 0;
+}
+
diff --git a/lib/ultralib/src/io/sprawwrite.c b/lib/ultralib/src/io/sprawwrite.c
new file mode 100755
index 0000000..f6451ae
--- /dev/null
+++ b/lib/ultralib/src/io/sprawwrite.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "../os/osint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSpRawWriteIo(u32 devAddr, u32 data) {
+ if (__osSpDeviceBusy()) {
+ return -1;
+ }
+
+ IO_WRITE(devAddr, data);
+ return 0;
+}
diff --git a/lib/ultralib/src/io/spsetpc.c b/lib/ultralib/src/io/spsetpc.c
new file mode 100644
index 0000000..dce0b5d
--- /dev/null
+++ b/lib/ultralib/src/io/spsetpc.c
@@ -0,0 +1,15 @@
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 __osSpSetPc(u32 pc) {
+ register u32 status = IO_READ(SP_STATUS_REG);
+
+ if (!(status & SP_STATUS_HALT)) {
+ return -1;
+ }
+ IO_WRITE(SP_PC_REG, pc);
+
+ return 0;
+}
diff --git a/lib/ultralib/src/io/spsetstat.c b/lib/ultralib/src/io/spsetstat.c
new file mode 100755
index 0000000..2ab47e0
--- /dev/null
+++ b/lib/ultralib/src/io/spsetstat.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void __osSpSetStatus(u32 data) {
+ IO_WRITE(SP_STATUS_REG, data);
+}
diff --git a/lib/ultralib/src/io/sptask.c b/lib/ultralib/src/io/sptask.c
new file mode 100755
index 0000000..13d6f00
--- /dev/null
+++ b/lib/ultralib/src/io/sptask.c
@@ -0,0 +1,63 @@
+#include "PR/os_internal.h"
+#include "PR/sptask.h"
+#include "PR/rcp.h"
+#include "../os/osint.h"
+
+#define _osVirtualToPhysical(ptr) \
+ if (ptr != NULL) \
+ { \
+ ptr = (void *)osVirtualToPhysical(ptr); \
+ }
+
+static OSTask tmp_task;
+
+static OSTask *_VirtualToPhysicalTask(OSTask *intp) {
+ OSTask *tp;
+ tp = &tmp_task;
+ bcopy(intp, tp, sizeof(OSTask));
+
+ _osVirtualToPhysical(tp->t.ucode);
+ _osVirtualToPhysical(tp->t.ucode_data);
+ _osVirtualToPhysical(tp->t.dram_stack);
+ _osVirtualToPhysical(tp->t.output_buff);
+ _osVirtualToPhysical(tp->t.output_buff_size);
+ _osVirtualToPhysical(tp->t.data_ptr);
+ _osVirtualToPhysical(tp->t.yield_data_ptr);
+ return tp;
+}
+
+void osSpTaskLoad(OSTask *intp) {
+ OSTask *tp;
+
+ tp = _VirtualToPhysicalTask(intp);
+
+ if (tp->t.flags & OS_TASK_YIELDED) {
+ tp->t.ucode_data = tp->t.yield_data_ptr;
+ tp->t.ucode_data_size = tp->t.yield_data_size;
+ intp->t.flags &= ~OS_TASK_YIELDED;
+ if (tp->t.flags & OS_TASK_LOADABLE)
+ tp->t.ucode = (u64 *)IO_READ((u32)intp->t.yield_data_ptr + OS_YIELD_DATA_SIZE - 4);
+ }
+
+ osWritebackDCache(tp, sizeof(OSTask));
+ __osSpSetStatus(SP_CLR_YIELD | SP_CLR_YIELDED | SP_CLR_TASKDONE | SP_SET_INTR_BREAK);
+
+ while (__osSpSetPc(SP_IMEM_START) == -1) {
+ }
+
+ while (__osSpRawStartDma(1, (SP_IMEM_START - sizeof(*tp)), tp, sizeof(OSTask)) == -1) {
+ }
+
+ while (__osSpDeviceBusy()) {
+ }
+
+ while (__osSpRawStartDma(1, SP_IMEM_START, tp->t.ucode_boot, tp->t.ucode_boot_size) == -1) {
+ }
+}
+
+void osSpTaskStartGo(OSTask *tp) {
+ while (__osSpDeviceBusy()) {
+ }
+
+ __osSpSetStatus(SP_SET_INTR_BREAK | SP_CLR_SSTEP | SP_CLR_BROKE | SP_CLR_HALT);
+}
diff --git a/lib/ultralib/src/io/sptaskyield.c b/lib/ultralib/src/io/sptaskyield.c
new file mode 100755
index 0000000..78bacae
--- /dev/null
+++ b/lib/ultralib/src/io/sptaskyield.c
@@ -0,0 +1,6 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+void osSpTaskYield(void) {
+ __osSpSetStatus(SP_SET_YIELD);
+}
diff --git a/lib/ultralib/src/io/sptaskyielded.c b/lib/ultralib/src/io/sptaskyielded.c
new file mode 100755
index 0000000..6c18c21
--- /dev/null
+++ b/lib/ultralib/src/io/sptaskyielded.c
@@ -0,0 +1,18 @@
+#include "PR/os_internal.h"
+#include "PR/sptask.h"
+#include "PR/rcp.h"
+
+OSYieldResult osSpTaskYielded(OSTask *tp) {
+ u32 status;
+ OSYieldResult result;
+
+ status = __osSpGetStatus();
+ result = status >> 8;
+ result &= 1;
+
+ if (status & SP_STATUS_YIELD) {
+ tp->t.flags = ~(OS_TASK_DP_WAIT) & (tp->t.flags | result);
+ }
+
+ return result;
+}
diff --git a/lib/ultralib/src/io/vi.c b/lib/ultralib/src/io/vi.c
new file mode 100644
index 0000000..bffed92
--- /dev/null
+++ b/lib/ultralib/src/io/vi.c
@@ -0,0 +1,39 @@
+#include <macros.h>
+#include <PR/os_internal.h>
+#include <PR/R4300.h>
+#include <PR/rcp.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+static __OSViContext vi[2] ALIGNED(8) = {0};
+__OSViContext *__osViCurr = &vi[0];
+__OSViContext *__osViNext = &vi[1];
+
+void __osViInit(void) {
+ bzero(vi, sizeof(vi));
+ __osViCurr = &vi[0];
+ __osViNext = &vi[1];
+ __osViNext->retraceCount = 1;
+ __osViCurr->retraceCount = 1;
+ __osViNext->framep = (void*)K0BASE;
+ __osViCurr->framep = (void*)K0BASE;
+
+ if (osTvType == OS_TV_TYPE_PAL) {
+ __osViNext->modep = &osViModePalLan1;
+ } else if (osTvType == OS_TV_TYPE_MPAL) {
+ __osViNext->modep = &osViModeMpalLan1;
+ } else {
+ __osViNext->modep = &osViModeNtscLan1;
+ }
+
+ __osViNext->state = VI_STATE_BLACK;
+ __osViNext->control = __osViNext->modep->comRegs.ctrl;
+
+ while (IO_READ(VI_CURRENT_REG) > 10) { //wait for vsync?
+ }
+
+ IO_WRITE(VI_CONTROL_REG, 0); //pixel size blank (no data, no sync)
+ __osViSwapContext();
+}
diff --git a/lib/ultralib/src/io/viblack.c b/lib/ultralib/src/io/viblack.c
new file mode 100644
index 0000000..7e8ea81
--- /dev/null
+++ b/lib/ultralib/src/io/viblack.c
@@ -0,0 +1,17 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViBlack(u8 active) {
+ register u32 saveMask = __osDisableInt();
+
+ if (active) {
+ __osViNext->state |= VI_STATE_BLACK;
+ } else {
+ __osViNext->state &= ~VI_STATE_BLACK;
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/viextendvstart.c b/lib/ultralib/src/io/viextendvstart.c
new file mode 100644
index 0000000..8fa8074
--- /dev/null
+++ b/lib/ultralib/src/io/viextendvstart.c
@@ -0,0 +1,6 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+void osViExtendVStart(u32 value) {
+ __additional_scanline = value;
+}
diff --git a/lib/ultralib/src/io/vifade.c b/lib/ultralib/src/io/vifade.c
new file mode 100644
index 0000000..2812860
--- /dev/null
+++ b/lib/ultralib/src/io/vifade.c
@@ -0,0 +1,18 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViFade(u8 active, u16 factor) {
+ register u32 saveMask = __osDisableInt();
+
+ if (active) {
+ __osViNext->y.offset = factor & VI_2_10_FPART_MASK;
+ __osViNext->state |= VI_STATE_FADE;
+ } else {
+ __osViNext->state &= ~VI_STATE_FADE;
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/vigetcurrcontext.c b/lib/ultralib/src/io/vigetcurrcontext.c
new file mode 100644
index 0000000..729d902
--- /dev/null
+++ b/lib/ultralib/src/io/vigetcurrcontext.c
@@ -0,0 +1,9 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+__OSViContext *__osViGetCurrentContext(void) {
+ return __osViCurr;
+}
diff --git a/lib/ultralib/src/io/vigetcurrframebuf.c b/lib/ultralib/src/io/vigetcurrframebuf.c
new file mode 100644
index 0000000..987e86b
--- /dev/null
+++ b/lib/ultralib/src/io/vigetcurrframebuf.c
@@ -0,0 +1,10 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+void *osViGetCurrentFramebuffer(void) {
+ register u32 saveMask = __osDisableInt();
+ void *framep = __osViCurr->framep;
+
+ __osRestoreInt(saveMask);
+ return framep;
+}
diff --git a/lib/ultralib/src/io/vigetfield.c b/lib/ultralib/src/io/vigetfield.c
new file mode 100644
index 0000000..395e912
--- /dev/null
+++ b/lib/ultralib/src/io/vigetfield.c
@@ -0,0 +1,6 @@
+#include <PR/os_internal.h>
+#include <PR/rcp.h>
+
+u32 osViGetCurrentField(void) {
+ return IO_READ(VI_CURRENT_REG) & 1;
+}
diff --git a/lib/ultralib/src/io/vigetline.c b/lib/ultralib/src/io/vigetline.c
new file mode 100644
index 0000000..1eed3cd
--- /dev/null
+++ b/lib/ultralib/src/io/vigetline.c
@@ -0,0 +1,6 @@
+#include <PR/os_internal.h>
+#include <PR/rcp.h>
+
+u32 osViGetCurrentLine(void) {
+ return IO_READ(VI_CURRENT_REG);
+}
diff --git a/lib/ultralib/src/io/vigetmode.c b/lib/ultralib/src/io/vigetmode.c
new file mode 100644
index 0000000..bb3fcd0
--- /dev/null
+++ b/lib/ultralib/src/io/vigetmode.c
@@ -0,0 +1,10 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+u32 osViGetCurrentMode(void) {
+ register u32 savedMask = __osDisableInt();
+ register u32 modeType = __osViCurr->modep->type;
+
+ __osRestoreInt(savedMask);
+ return modeType;
+}
diff --git a/lib/ultralib/src/io/vigetnextcontext.c b/lib/ultralib/src/io/vigetnextcontext.c
new file mode 100644
index 0000000..5692890
--- /dev/null
+++ b/lib/ultralib/src/io/vigetnextcontext.c
@@ -0,0 +1,6 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+__OSViContext *__osViGetNextContext(void) {
+ return __osViNext;
+}
diff --git a/lib/ultralib/src/io/vigetnextframebuf.c b/lib/ultralib/src/io/vigetnextframebuf.c
new file mode 100644
index 0000000..9158281
--- /dev/null
+++ b/lib/ultralib/src/io/vigetnextframebuf.c
@@ -0,0 +1,10 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+void *osViGetNextFramebuffer(void) {
+ register u32 saveMask = __osDisableInt();
+ void *framep = __osViNext->framep;
+
+ __osRestoreInt(saveMask);
+ return framep;
+}
diff --git a/lib/ultralib/src/io/vigetstat.c b/lib/ultralib/src/io/vigetstat.c
new file mode 100644
index 0000000..eea94a7
--- /dev/null
+++ b/lib/ultralib/src/io/vigetstat.c
@@ -0,0 +1,6 @@
+#include <PR/os_internal.h>
+#include <PR/rcp.h>
+
+u32 osViGetStatus(void) {
+ return IO_READ(VI_STATUS_REG);
+}
diff --git a/lib/ultralib/src/io/viint.h b/lib/ultralib/src/io/viint.h
new file mode 100644
index 0000000..3ae94c8
--- /dev/null
+++ b/lib/ultralib/src/io/viint.h
@@ -0,0 +1,70 @@
+#ifndef _VIINT_H
+#define _VIINT_H
+#include "PR/os_internal.h"
+
+#define OS_TV_TYPE_PAL 0
+#define OS_TV_TYPE_NTSC 1
+#define OS_TV_TYPE_MPAL 2
+
+#define VI_STATE_MODE_UPDATED 0x01
+#define VI_STATE_XSCALE_UPDATED 0x02
+#define VI_STATE_YSCALE_UPDATED 0x04
+#define VI_STATE_CTRL_UPDATED 0x08 // related to control regs changing
+#define VI_STATE_BUFFER_UPDATED 0x10 // swap buffer
+#define VI_STATE_BLACK 0x20 // probably related to a black screen
+#define VI_STATE_REPEATLINE 0x40 // repeat line?
+#define VI_STATE_FADE 0x80 // fade
+
+#define VI_CTRL_ANTIALIAS_MODE_3 0x00300 /* Bit [9:8] anti-alias mode */
+#define VI_CTRL_ANTIALIAS_MODE_2 0x00200 /* Bit [9:8] anti-alias mode */
+#define VI_CTRL_ANTIALIAS_MODE_1 0x00100 /* Bit [9:8] anti-alias mode */
+
+#define VI_SCALE_MASK 0xfff //see rcp scale_x/scale_y
+#define VI_2_10_FPART_MASK 0x3ff
+#define VI_SUBPIXEL_SH 0x10
+
+#define BURST(hsync_width, color_width, vsync_width, color_start) \
+ (hsync_width | (color_width << 8) | (vsync_width << 16) | (color_start << 20))
+#define WIDTH(v) v
+#define VSYNC(v) v
+#define HSYNC(duration, leap) (duration | (leap << 16))
+#define LEAP(upper, lower) ((upper << 16) | lower)
+#define START(start, end) ((start << 16) | end)
+
+#define FTOFIX(val, i, f) ((u32)(val * (f32)(1 << f)) & ((1 << (i + f)) - 1))
+
+#define F210(val) FTOFIX(val, 2, 10)
+#define SCALE(scaleup, off) (F210((1.0f / (f32)scaleup)) | (F210((f32)off) << 16))
+
+#define VCURRENT(v) v //seemingly unused
+#define ORIGIN(v) v
+#define VINTR(v) v
+#define HSTART START
+
+typedef struct
+{
+ /* 0x0 */ f32 factor;
+ /* 0x4 */ u16 offset;
+ /* 0x8 */ u32 scale;
+} __OSViScale;
+
+typedef struct
+{
+ /* 0x0 */ u16 state;
+ /* 0x2 */ u16 retraceCount;
+ /* 0x4 */ void *framep;
+ /* 0x8 */ OSViMode *modep;
+ /* 0xC */ u32 control;
+ /* 0x10 */ OSMesgQueue *msgq;
+ /* 0x14 */ OSMesg msg;
+ /* 0x18 */ __OSViScale x;
+ /* 0x24 */ __OSViScale y;
+} __OSViContext; // 0x30 bytes
+
+void __osViSwapContext(void);
+extern __OSViContext *__osViCurr;
+extern __OSViContext *__osViNext;
+extern u32 __additional_scanline;
+__OSViContext *__osViGetCurrentContext(void);
+void __osViInit(void);
+#endif
diff --git a/lib/ultralib/src/io/vimgr.c b/lib/ultralib/src/io/vimgr.c
new file mode 100644
index 0000000..d4766b5
--- /dev/null
+++ b/lib/ultralib/src/io/vimgr.c
@@ -0,0 +1,110 @@
+#include <macros.h>
+#include <PR/os_internal.h>
+#include <PR/rcp.h>
+#include "viint.h"
+#include "../os/osint.h"
+
+OSDevMgr __osViDevMgr = {0};
+u32 __additional_scanline = 0;
+static OSThread viThread;
+static unsigned char viThreadStack[OS_VIM_STACKSIZE] ALIGNED(16);
+static OSMesgQueue viEventQueue;
+static OSMesg viEventBuf[5] ALIGNED(8);
+static OSIoMesg viRetraceMsg ALIGNED(8);
+static OSIoMesg viCounterMsg ALIGNED(8);
+
+static void viMgrMain(void *arg);
+void osCreateViManager(OSPri pri)
+{
+ u32 savedMask;
+ OSPri myPri;
+ OSPri oldPri;
+
+ if (!__osViDevMgr.active) {
+ __osTimerServicesInit();
+ __additional_scanline = 0;
+ osCreateMesgQueue(&viEventQueue, viEventBuf, ARRLEN(viEventBuf));
+ viRetraceMsg.hdr.type = OS_MESG_TYPE_VRETRACE;
+ viRetraceMsg.hdr.pri = OS_MESG_PRI_NORMAL;
+ viRetraceMsg.hdr.retQueue = NULL;
+ viCounterMsg.hdr.type = OS_MESG_TYPE_COUNTER;
+ viCounterMsg.hdr.pri = OS_MESG_PRI_NORMAL;
+ viCounterMsg.hdr.retQueue = NULL;
+ osSetEventMesg(OS_EVENT_VI, &viEventQueue, &viRetraceMsg);
+ osSetEventMesg(OS_EVENT_COUNTER, &viEventQueue, &viCounterMsg);
+ oldPri = -1;
+ myPri = osGetThreadPri(NULL);
+
+ if (myPri < pri) {
+ oldPri = myPri;
+ osSetThreadPri(NULL, pri);
+ }
+
+ savedMask = __osDisableInt();
+ __osViDevMgr.active = TRUE;
+ __osViDevMgr.thread = &viThread;
+ __osViDevMgr.cmdQueue = &viEventQueue;
+ __osViDevMgr.evtQueue = &viEventQueue;
+ __osViDevMgr.acsQueue = NULL;
+ __osViDevMgr.dma = NULL;
+ __osViDevMgr.edma = NULL;
+ osCreateThread(&viThread, 0, viMgrMain, &__osViDevMgr, &viThreadStack[OS_VIM_STACKSIZE], pri);
+ __osViInit();
+ osStartThread(&viThread);
+ __osRestoreInt(savedMask);
+
+ if (oldPri != -1) {
+ osSetThreadPri(0, oldPri);
+ }
+ }
+}
+
+static void viMgrMain(void *arg) {
+ __OSViContext *vc;
+ OSDevMgr *dm;
+ OSIoMesg *mb;
+ static u16 retrace;
+ s32 first;
+ u32 count;
+
+ mb = NULL;
+ first = 0;
+ vc = __osViGetCurrentContext();
+ retrace = vc->retraceCount;
+ if (retrace == 0)
+ retrace = 1;
+ dm = (OSDevMgr *)arg;
+
+ while (TRUE) {
+ osRecvMesg(dm->evtQueue, (OSMesg)&mb, OS_MESG_BLOCK);
+ switch (mb->hdr.type) {
+ case OS_MESG_TYPE_VRETRACE:
+ __osViSwapContext();
+ retrace--;
+
+ if (retrace == 0) {
+ vc = __osViGetCurrentContext();
+ if (vc->msgq != NULL)
+ osSendMesg(vc->msgq, vc->msg, OS_MESG_NOBLOCK);
+ retrace = vc->retraceCount;
+ }
+
+ __osViIntrCount++;
+
+ if (first) {
+ count = osGetCount();
+ __osCurrentTime = count;
+ first = 0;
+ }
+
+ count = __osBaseCounter;
+ __osBaseCounter = osGetCount();
+ count = __osBaseCounter - count;
+ __osCurrentTime = __osCurrentTime + count;
+ break;
+ case OS_MESG_TYPE_COUNTER:
+ __osTimerInterrupt();
+ break;
+ }
+ }
+}
diff --git a/lib/ultralib/src/io/virepeatline.c b/lib/ultralib/src/io/virepeatline.c
new file mode 100644
index 0000000..905538e
--- /dev/null
+++ b/lib/ultralib/src/io/virepeatline.c
@@ -0,0 +1,17 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViRepeatLine(u8 active) {
+ register u32 saveMask = __osDisableInt();
+
+ if (active) {
+ __osViNext->state |= VI_STATE_REPEATLINE;
+ } else {
+ __osViNext->state &= ~VI_STATE_REPEATLINE;
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/visetevent.c b/lib/ultralib/src/io/visetevent.c
new file mode 100644
index 0000000..589647a
--- /dev/null
+++ b/lib/ultralib/src/io/visetevent.c
@@ -0,0 +1,14 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViSetEvent(OSMesgQueue *mq, OSMesg m, u32 retraceCount) {
+ register u32 saveMask = __osDisableInt();
+
+ __osViNext->msgq = mq;
+ __osViNext->msg = m;
+ __osViNext->retraceCount = retraceCount;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/visetmode.c b/lib/ultralib/src/io/visetmode.c
new file mode 100644
index 0000000..655cba6
--- /dev/null
+++ b/lib/ultralib/src/io/visetmode.c
@@ -0,0 +1,14 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViSetMode(OSViMode *modep) {
+ register u32 saveMask = __osDisableInt();
+
+ __osViNext->modep = modep;
+ __osViNext->state = VI_STATE_MODE_UPDATED;
+ __osViNext->control = __osViNext->modep->comRegs.ctrl;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/visetspecial.c b/lib/ultralib/src/io/visetspecial.c
new file mode 100644
index 0000000..e8f90b8
--- /dev/null
+++ b/lib/ultralib/src/io/visetspecial.c
@@ -0,0 +1,48 @@
+#include <PR/os_internal.h>
+#include <PR/rcp.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViSetSpecialFeatures(u32 func) {
+ register u32 saveMask = __osDisableInt();
+
+ if ((func & OS_VI_GAMMA_ON) != 0) {
+ __osViNext->control |= VI_CTRL_GAMMA_ON;
+ }
+
+ if ((func & OS_VI_GAMMA_OFF) != 0) {
+ __osViNext->control &= ~VI_CTRL_GAMMA_ON;
+ }
+
+ if ((func & OS_VI_GAMMA_DITHER_ON) != 0) {
+ __osViNext->control |= VI_CTRL_GAMMA_DITHER_ON;
+ }
+
+ if ((func & OS_VI_GAMMA_DITHER_OFF) != 0) {
+ __osViNext->control &= ~VI_CTRL_GAMMA_DITHER_ON;
+ }
+
+ if ((func & OS_VI_DIVOT_ON) != 0) {
+ __osViNext->control |= VI_CTRL_DIVOT_ON;
+ }
+
+ if ((func & OS_VI_DIVOT_OFF) != 0) {
+ __osViNext->control &= ~VI_CTRL_DIVOT_ON;
+ }
+
+ if ((func & OS_VI_DITHER_FILTER_ON) != 0) {
+ __osViNext->control |= VI_CTRL_DITHER_FILTER_ON;
+ __osViNext->control &= ~VI_CTRL_ANTIALIAS_MASK;
+ }
+
+ if ((func & OS_VI_DITHER_FILTER_OFF) != 0) {
+ __osViNext->control &= ~VI_CTRL_DITHER_FILTER_ON;
+ __osViNext->control |= __osViNext->modep->comRegs.ctrl & VI_CTRL_ANTIALIAS_MASK;
+ }
+
+ __osViNext->state |= VI_STATE_CTRL_UPDATED;
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/visetxscale.c b/lib/ultralib/src/io/visetxscale.c
new file mode 100644
index 0000000..328987c
--- /dev/null
+++ b/lib/ultralib/src/io/visetxscale.c
@@ -0,0 +1,16 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViSetXScale(f32 value) {
+ register u32 nomValue;
+ register u32 saveMask = __osDisableInt();
+
+ __osViNext->x.factor = value;
+ __osViNext->state |= VI_STATE_XSCALE_UPDATED;
+ nomValue = __osViNext->modep->comRegs.xScale & VI_SCALE_MASK;
+ __osViNext->x.scale = (u32)(__osViNext->x.factor * nomValue) & VI_SCALE_MASK;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/visetyscale.c b/lib/ultralib/src/io/visetyscale.c
new file mode 100644
index 0000000..525e0eb
--- /dev/null
+++ b/lib/ultralib/src/io/visetyscale.c
@@ -0,0 +1,13 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViSetYScale(f32 value) {
+ register u32 saveMask = __osDisableInt();
+
+ __osViNext->y.factor = value;
+ __osViNext->state |= VI_STATE_YSCALE_UPDATED;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/viswapbuf.c b/lib/ultralib/src/io/viswapbuf.c
new file mode 100644
index 0000000..327ed60
--- /dev/null
+++ b/lib/ultralib/src/io/viswapbuf.c
@@ -0,0 +1,13 @@
+#include <PR/os_internal.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osViSwapBuffer(void* frameBufPtr) {
+ u32 saveMask = __osDisableInt();
+
+ __osViNext->framep = frameBufPtr;
+ __osViNext->state |= VI_STATE_BUFFER_UPDATED;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/io/viswapcontext.c b/lib/ultralib/src/io/viswapcontext.c
new file mode 100644
index 0000000..3095d51
--- /dev/null
+++ b/lib/ultralib/src/io/viswapcontext.c
@@ -0,0 +1,72 @@
+#include <PR/os_internal.h>
+#include <PR/rcp.h>
+#include "viint.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void __osViSwapContext() {
+ register OSViMode *vm;
+ register __OSViContext *vc;
+ u32 origin;
+ u32 vStart;
+ u32 hStart;
+ u32 nomValue;
+ u32 field;
+
+ field = 0;
+ vc = __osViNext;
+ vm = vc->modep;
+
+ field = IO_READ(VI_CURRENT_REG) & 1; //field num
+
+ origin = osVirtualToPhysical(vc->framep) + (vm->fldRegs[field].origin);
+ if (vc->state & VI_STATE_XSCALE_UPDATED) {
+ vc->x.scale |= (vm->comRegs.xScale & ~VI_SCALE_MASK);
+ } else {
+ vc->x.scale = vm->comRegs.xScale;
+ }
+
+ if (vc->state & VI_STATE_YSCALE_UPDATED) {
+ nomValue = vm->fldRegs[field].yScale & VI_SCALE_MASK;
+ vc->y.scale = vc->y.factor * nomValue;
+ vc->y.scale |= vm->fldRegs[field].yScale & ~VI_SCALE_MASK;
+ } else {
+ vc->y.scale = vm->fldRegs[field].yScale;
+ }
+
+ vStart = (vm->fldRegs[field].vStart - (__additional_scanline << 0x10)) + __additional_scanline;
+ hStart = vm->comRegs.hStart;
+
+ if (vc->state & VI_STATE_BLACK) {
+ hStart = 0;
+ }
+
+ if (vc->state & VI_STATE_REPEATLINE) {
+ vc->y.scale = 0;
+ origin = osVirtualToPhysical(vc->framep);
+ }
+
+ if (vc->state & VI_STATE_FADE) {
+ vc->y.scale = (vc->y.offset << VI_SUBPIXEL_SH) & (VI_2_10_FPART_MASK << VI_SUBPIXEL_SH);
+ origin = osVirtualToPhysical(vc->framep);
+ }
+
+ IO_WRITE(VI_ORIGIN_REG, origin);
+ IO_WRITE(VI_WIDTH_REG, vm->comRegs.width);
+ IO_WRITE(VI_BURST_REG, vm->comRegs.burst);
+ IO_WRITE(VI_V_SYNC_REG, vm->comRegs.vSync);
+ IO_WRITE(VI_H_SYNC_REG, vm->comRegs.hSync);
+ IO_WRITE(VI_LEAP_REG, vm->comRegs.leap);
+ IO_WRITE(VI_H_START_REG, hStart);
+ IO_WRITE(VI_V_START_REG, vStart);
+ IO_WRITE(VI_V_BURST_REG, vm->fldRegs[field].vBurst);
+ IO_WRITE(VI_INTR_REG, vm->fldRegs[field].vIntr);
+ IO_WRITE(VI_X_SCALE_REG, vc->x.scale);
+ IO_WRITE(VI_Y_SCALE_REG, vc->y.scale);
+ IO_WRITE(VI_CONTROL_REG, vc->control);
+
+ __osViNext = __osViCurr;
+ __osViCurr = vc;
+ *__osViNext = *__osViCurr;
+}
diff --git a/lib/ultralib/src/io/vitbl.c b/lib/ultralib/src/io/vitbl.c
new file mode 100644
index 0000000..89e57e7
--- /dev/null
+++ b/lib/ultralib/src/io/vitbl.c
@@ -0,0 +1,1742 @@
+#include <PR/os.h>
+#include <PR/rcp.h>
+#include "../io/viint.h"
+
+OSViMode osViModeTable[56] = {
+ {
+ OS_VI_NTSC_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_NTSC_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_PAL_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { //[0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { //[1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_MPAL_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ },
+ {
+ OS_VI_FPAL_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+ }
+};
diff --git a/lib/ultralib/src/libc/bcmp.s b/lib/ultralib/src/libc/bcmp.s
new file mode 100644
index 0000000..f6fcc8b
--- /dev/null
+++ b/lib/ultralib/src/libc/bcmp.s
@@ -0,0 +1,92 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+WEAK(_bcmp, bcmp)
+LEAF(bcmp)
+ xor v0, a0, a1
+ blt a2, 16, bytecmp
+
+ andi v0, v0, 0x3
+ negu t8, a0
+ bnez v0, unalgncmp
+
+ andi t8, t8, 0x3
+ subu a2, a2, t8
+ beqz t8, wordcmp
+
+ move v0, v1
+ lwl v0, 0(a0)
+ lwl v1, 0(a1)
+ addu a0, a0, t8
+ addu a1, a1, t8
+ bne v0, v1, cmpne
+
+wordcmp:
+ and a3, a2, ~3
+ subu a2, a2, a3
+ beqz a3, bytecmp
+
+ addu a3, a3, a0
+1:
+ lw v0, 0(a0)
+ lw v1, 0(a1)
+ addiu a0, a0, 4
+ addiu a1, a1, 4
+ bne v0, v1, cmpne
+ bne a0, a3, 1b
+
+ b bytecmp
+unalgncmp:
+ negu a3, a1
+ andi a3, a3, 0x3
+ subu a2, a2, a3
+ beqz a3, partaligncmp
+
+ addu a3, a3, a0
+
+1:
+ lbu v0, 0(a0)
+ lbu v1, 0(a1)
+ addiu a0, a0, 1
+ addiu a1, a1, 1
+ bne v0, v1, cmpne
+ bne a0, a3, 1b
+
+partaligncmp:
+ and a3, a2, ~3
+ subu a2, a2, a3
+ beqz a3, bytecmp
+
+ addu a3, a3, a0
+
+1:
+ lwl v0, 0(a0)
+ lwr v0, 3(a0)
+ lw v1, 0(a1)
+ addiu a0, a0, 4
+ addiu a1, a1, 4
+ bne v0, v1, cmpne
+ bne a0, a3, 1b
+
+bytecmp:
+ addu a3, a2, a0
+ blez a2, cmpdone
+
+1:
+ lbu v0, 0(a0)
+ lbu v1, 0(a1)
+ addiu a0, a0, 1
+ addiu a1, a1, 1
+ bne v0, v1, cmpne
+ bne a0, a3, 1b
+
+cmpdone:
+ move v0, zero
+ jr ra
+cmpne:
+ li v0, 1
+ jr ra
+
+END(bcmp)
diff --git a/lib/ultralib/src/libc/bcopy.s b/lib/ultralib/src/libc/bcopy.s
new file mode 100644
index 0000000..9bf1583
--- /dev/null
+++ b/lib/ultralib/src/libc/bcopy.s
@@ -0,0 +1,218 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+WEAK(_bcopy, bcopy)
+LEAF(bcopy)
+ move a3, a1
+ beqz a2, ret
+ beq a0, a1, ret
+ blt a1, a0, goforwards
+
+ add v0, a0, a2
+ bge a1, v0, goforwards
+ b gobackwards
+
+goforwards:
+
+ blt a2, 16, forwards_bytecopy
+
+ andi v0, a0, 0x3
+ andi v1, a1, 0x3
+ beq v0, v1,forwalignable
+
+
+forwards_bytecopy:
+ beqz a2, ret
+ addu v1, a0, a2
+99:
+ lb v0, 0(a0)
+ addiu a0, a0, 1
+ sb v0, 0(a1)
+ addiu a1, a1, 1
+ bne a0, v1, 99b
+ret:
+ move v0, a3
+ jr ra
+
+forwalignable:
+ beqz v0, forwards
+ beq v0, 1, forw_copy3
+ beq v0, 2, forw_copy2
+
+ lb v0, 0(a0)
+ addiu a0, a0, 1
+ sb v0, 0(a1)
+ addiu a1, a1, 1
+ addiu a2, a2, -1
+ b forwards
+
+forw_copy2:
+ lh v0, 0(a0)
+ addiu a0, a0, 2
+ sh v0, 0(a1)
+ addiu a1, a1, 2
+ addiu a2, a2, -2
+ b forwards
+
+forw_copy3:
+ lb v0, 0(a0)
+ lh v1, 1(a0)
+ addiu a0, a0, 3
+ sb v0, 0(a1)
+ sh v1, 1(a1)
+ addiu a1, a1, 3
+ addiu a2, a2, -3
+
+forwards:
+forwards_32:
+ blt a2, 32, forwards_16
+ lw v0, 0(a0)
+ lw v1, 4(a0)
+ lw t0, 8(a0)
+ lw t1, 12(a0)
+ lw t2, 16(a0)
+ lw t3, 20(a0)
+ lw ta0, 24(a0)
+ lw ta1, 28(a0)
+ addiu a0, a0, 32
+ sw v0, 0(a1)
+ sw v1, 4(a1)
+ sw t0, 8(a1)
+ sw t1, 12(a1)
+ sw t2, 16(a1)
+ sw t3, 20(a1)
+ sw ta0, 24(a1)
+ sw ta1, 28(a1)
+ addiu a1, a1, 32
+ addiu a2, a2, -32
+ b forwards_32
+
+forwards_16:
+ blt a2, 16, forwards_4
+ lw v0, 0(a0)
+ lw v1, 4(a0)
+ lw t0, 8(a0)
+ lw t1, 12(a0)
+ addiu a0, a0, 16
+ sw v0, 0(a1)
+ sw v1, 4(a1)
+ sw t0, 8(a1)
+ sw t1, 12(a1)
+ addiu a1, a1, 16
+ addiu a2, a2, -16
+ b forwards_16
+
+forwards_4:
+ blt a2, 4, forwards_bytecopy
+
+ lw v0, 0(a0)
+ addiu a0, a0, 4
+ sw v0, 0(a1)
+ addiu a1, a1, 4
+ addiu a2, a2, -4
+ b forwards_4
+
+gobackwards:
+ add a0, a0,a2
+ add a1, a1,a2
+ blt a2, 16, backwards_bytecopy
+
+ andi v0, a0, 0x3
+ andi v1, a1, 0x3
+ beq v0, v1,backalignable
+
+backwards_bytecopy:
+ beqz a2, ret
+ addiu a0, a0, -1
+ addiu a1, a1, -1
+ subu v1, a0,a2
+99:
+ lb v0, 0(a0)
+ addiu a0, a0, -1
+ sb v0, 0(a1)
+ addiu a1, a1, -1
+ bne a0, v1,99b
+
+ move v0, a3
+ jr ra
+backalignable:
+ beqz v0, backwards
+ beq v0, 3, back_copy3
+ beq v0, 2, back_copy2
+ lb v0, -1(a0)
+ addiu a0, a0, -1
+ sb v0, -1(a1)
+ addiu a1, a1, -1
+ addiu a2, a2, -1
+ b backwards
+
+back_copy2:
+ lh v0, -2(a0)
+ addiu a0, a0, -2
+ sh v0, -2(a1)
+ addiu a1, a1, -2
+ addiu a2, a2, -2
+ b backwards
+
+back_copy3:
+ lb v0, -1(a0)
+ lh v1, -3(a0)
+ addiu a0, a0, -3
+ sb v0, -1(a1)
+ sh v1, -3(a1)
+ addiu a1, a1, -3
+ addiu a2, a2, -3
+
+backwards:
+backwards_32:
+ blt a2, 32, backwards_16
+ lw v0, -4(a0)
+ lw v1, -8(a0)
+ lw t0, -12(a0)
+ lw t1, -16(a0)
+ lw t2, -20(a0)
+ lw t3, -24(a0)
+ lw ta0, -28(a0)
+ lw ta1, -32(a0)
+ addiu a0, a0, -32
+ sw v0, -4(a1)
+ sw v1, -8(a1)
+ sw t0, -12(a1)
+ sw t1, -16(a1)
+ sw t2, -20(a1)
+ sw t3, -24(a1)
+ sw ta0, -28(a1)
+ sw ta1, -32(a1)
+ addiu a1, a1, -32
+ addiu a2, a2, -32
+ b backwards_32
+
+backwards_16:
+ blt a2, 16, backwards_4
+ lw v0, -4(a0)
+ lw v1, -8(a0)
+ lw t0, -12(a0)
+ lw t1, -16(a0)
+ addiu a0, a0, -16
+ sw v0, -4(a1)
+ sw v1, -8(a1)
+ sw t0, -12(a1)
+ sw t1, -16(a1)
+ addiu a1, a1, -16
+ addiu a2, a2, -16
+ b backwards_16
+
+backwards_4:
+ blt a2, 4, backwards_bytecopy
+ lw v0, -4(a0)
+ addiu a0, a0, -4
+ sw v0, -4(a1)
+ addiu a1, a1, -4
+ addiu a2, a2, -4
+ b backwards_4
+
+END(bcopy)
+/*
+*/
diff --git a/lib/ultralib/src/libc/bzero.s b/lib/ultralib/src/libc/bzero.s
new file mode 100644
index 0000000..13dcfa2
--- /dev/null
+++ b/lib/ultralib/src/libc/bzero.s
@@ -0,0 +1,58 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+WEAK(_bzero, bzero)
+WEAK(_blkclr, blkclr)
+LEAF(bzero)
+XLEAF(blkclr)
+ negu v1, a0
+ blt a1, 12, bytezero
+
+ andi v1, v1, 0x3
+ subu a1, a1, v1
+
+ beqz v1, blkzero
+ swl zero, 0(a0)
+ addu a0, a0, v1
+blkzero:
+ and a3, a1, ~31
+ subu a1, a1, a3
+ beqz a3, wordzero
+
+ addu a3, a3, a0
+1:
+ sw zero, 0(a0)
+ sw zero, 4(a0)
+ sw zero, 8(a0)
+ sw zero, 12(a0)
+ addiu a0, a0, 32
+ sw zero, -16(a0)
+ sw zero, -12(a0)
+ sw zero, -8(a0)
+ sw zero, -4(a0)
+ bne a0, a3, 1b
+
+wordzero:
+ and a3, a1, ~3
+ subu a1, a1, a3
+ beqz a3, bytezero
+
+ addu a3, a3, a0
+1:
+ addiu a0, a0, 4
+ sw zero, -4(a0)
+ bne a0, a3, 1b
+
+bytezero:
+ blez a1, zerodone
+ #nop
+ addu a1, a1, a0
+1:
+ addiu a0, a0, 1
+ sb zero, -1(a0)
+ bne a0, a1, 1b
+zerodone:
+ jr ra
+END(bzero)
diff --git a/lib/ultralib/src/libc/ldiv.c b/lib/ultralib/src/libc/ldiv.c
new file mode 100755
index 0000000..59644e9
--- /dev/null
+++ b/lib/ultralib/src/libc/ldiv.c
@@ -0,0 +1,33 @@
+#include "stdlib.h"
+
+// TODO: these come from headers
+#ident "$Revision: 1.34 $"
+#ident "$Revision: 1.5 $"
+
+ldiv_t ldiv(long num, long denom) {
+ ldiv_t ret;
+
+ ret.quot = num / denom;
+ ret.rem = num - denom * ret.quot;
+
+ if (ret.quot < 0 && ret.rem > 0) {
+ ret.quot++;
+ ret.rem -= denom;
+ }
+
+ return ret;
+}
+
+lldiv_t lldiv(long long num, long long denom) {
+ lldiv_t ret;
+
+ ret.quot = num / denom;
+ ret.rem = num - denom * ret.quot;
+
+ if (ret.quot < 0 && ret.rem > 0) {
+ ret.quot++;
+ ret.rem -= denom;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/libc/ll.c b/lib/ultralib/src/libc/ll.c
new file mode 100755
index 0000000..71582bf
--- /dev/null
+++ b/lib/ultralib/src/libc/ll.c
@@ -0,0 +1,46 @@
+unsigned long long __ull_rshift(unsigned long long a0, unsigned long long a1) {
+ return a0 >> a1;
+}
+
+unsigned long long __ull_rem(unsigned long long a0, unsigned long long a1) {
+ return a0 % a1;
+}
+
+unsigned long long __ull_div(unsigned long long a0, unsigned long long a1) {
+ return a0 / a1;
+}
+
+unsigned long long __ll_lshift(unsigned long long a0, unsigned long long a1) {
+ return a0 << a1;
+}
+
+long long __ll_rem(unsigned long long a0, long long a1) {
+ return a0 % a1;
+}
+
+long long __ll_div(long long a0, long long a1) {
+ return a0 / a1;
+}
+
+unsigned long long __ll_mul(unsigned long long a0, unsigned long long a1) {
+ return a0 * a1;
+}
+
+void __ull_divremi(unsigned long long *div, unsigned long long *rem, unsigned long long a2, unsigned short a3) {
+ *div = a2 / a3;
+ *rem = a2 % a3;
+}
+
+long long __ll_mod(long long a0, long long a1) {
+ long long tmp = a0 % a1;
+
+ if ((tmp < 0 && a1 > 0) || (tmp > 0 && a1 < 0)) {
+ tmp += a1;
+ }
+
+ return tmp;
+}
+
+long long __ll_rshift(long long a0, long long a1) {
+ return a0 >> a1;
+}
diff --git a/lib/ultralib/src/libc/llbit.c b/lib/ultralib/src/libc/llbit.c
new file mode 100755
index 0000000..73d6056
--- /dev/null
+++ b/lib/ultralib/src/libc/llbit.c
@@ -0,0 +1,50 @@
+#include "PR/ultratypes.h"
+
+s64 __ll_bit_extract(u64 *addr, unsigned int start_bit, unsigned int length) {
+ unsigned int words;
+ unsigned int lbits;
+ unsigned int rbits;
+ u64 mask;
+
+ words = start_bit >> 6;
+ lbits = start_bit & ((1 << 6) - 1);
+ rbits = 64 - (lbits + length);
+ addr += words;
+ mask = ((u64)1 << length) - 1;
+ mask = mask << rbits;
+ return (s64)((*addr & mask) >> rbits);
+}
+
+u64 __ull_bit_extract(u64 *addr, unsigned int start_bit, unsigned int length) {
+ unsigned int words;
+ unsigned int lbits;
+ unsigned int rbits;
+ u64 mask;
+
+ words = start_bit >> 6;
+ lbits = start_bit & ((1 << 6) - 1);
+ rbits = 64 - (lbits + length);
+ addr += words;
+ mask = ((u64)1 << length) - 1;
+ mask = mask << rbits;
+ return (u64)((*addr & mask) >> rbits);
+}
+
+u64 __ll_bit_insert(u64 *addr, unsigned int start_bit, unsigned int length, u64 val) {
+ unsigned int words;
+ unsigned int lbits;
+ unsigned int rbits;
+ unsigned long long llval;
+ unsigned long long mask;
+
+ words = start_bit >> 6;
+ lbits = start_bit & 0x3f;
+ rbits = 64 - (lbits + length);
+ addr += words;
+ mask = ((u64)1 << length) - 1;
+ mask <<= rbits;
+ llval = (val << (64 - length)) >> lbits;
+ *addr = (*addr & ~mask) | llval;
+ llval = llval >> rbits;
+ return llval;
+}
diff --git a/lib/ultralib/src/libc/llcvt.c b/lib/ultralib/src/libc/llcvt.c
new file mode 100755
index 0000000..2c423dd
--- /dev/null
+++ b/lib/ultralib/src/libc/llcvt.c
@@ -0,0 +1,31 @@
+long long __d_to_ll(double d) {
+ return d;
+}
+
+long long __f_to_ll(float f) {
+ return f;
+}
+
+unsigned long long __d_to_ull(double d) {
+ return d;
+}
+
+unsigned long long __f_to_ull(float f) {
+ return f;
+}
+
+double __ll_to_d(long long s) {
+ return s;
+}
+
+float __ll_to_f(long long s) {
+ return s;
+}
+
+double __ull_to_d(unsigned long long u) {
+ return u;
+}
+
+float __ull_to_f(unsigned long long u) {
+ return u;
+}
diff --git a/lib/ultralib/src/libc/sprintf.c b/lib/ultralib/src/libc/sprintf.c
new file mode 100755
index 0000000..8d619f5
--- /dev/null
+++ b/lib/ultralib/src/libc/sprintf.c
@@ -0,0 +1,24 @@
+#include "xstdio.h"
+#include "string.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.23 $"
+
+static char *proutSprintf(char *dst, const char *src, size_t count);
+
+int sprintf(char *dst, const char *fmt, ...)
+{
+ s32 ans;
+ va_list ap;
+ va_start(ap, fmt);
+ ans = _Printf(proutSprintf, dst, fmt, ap);
+ if (ans >= 0)
+ {
+ dst[ans] = 0;
+ }
+ return ans;
+}
+static char *proutSprintf(char *dst, const char *src, size_t count)
+{
+ return (char *)memcpy((u8 *)dst, (u8 *)src, count) + count;
+}
diff --git a/lib/ultralib/src/libc/string.c b/lib/ultralib/src/libc/string.c
new file mode 100755
index 0000000..c9a2b97
--- /dev/null
+++ b/lib/ultralib/src/libc/string.c
@@ -0,0 +1,34 @@
+#include "PR/ultratypes.h"
+#include "string.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.23 $"
+
+char *strchr(const char *s, int c) {
+ const char ch = c;
+ while (*s != ch)
+ {
+ if (*s == 0)
+ return NULL;
+ s++;
+ }
+ return (char *)s;
+}
+
+size_t strlen(const char *s) {
+ const char *sc = s;
+ while (*sc)
+ sc++;
+ return sc - s;
+}
+
+void *memcpy(void *s1, const void *s2, size_t n) {
+ char *su1 = (char *)s1;
+ const char *su2 = (const char *)s2;
+ while (n > 0)
+ {
+ *su1++ = *su2++;
+ n--;
+ }
+ return (void *)s1;
+}
diff --git a/lib/ultralib/src/libc/syncprintf.c b/lib/ultralib/src/libc/syncprintf.c
new file mode 100755
index 0000000..f2e758c
--- /dev/null
+++ b/lib/ultralib/src/libc/syncprintf.c
@@ -0,0 +1,17 @@
+#include "stdarg.h"
+#include "PR/os.h"
+
+void __osSyncVPrintf(const char *fmt, va_list args) {
+ // these functions intentionally left blank. ifdeffed out in rom release
+}
+
+void osSyncPrintf(const char *fmt, ...) {
+ int ans;
+ va_list ap;
+ // these functions intentionally left blank. ifdeffed out in rom release
+}
+
+void rmonPrintf(const char *fmt, ...) {
+ int ans;
+ va_list ap;
+}
diff --git a/lib/ultralib/src/libc/xldtob.c b/lib/ultralib/src/libc/xldtob.c
new file mode 100644
index 0000000..b032e57
--- /dev/null
+++ b/lib/ultralib/src/libc/xldtob.c
@@ -0,0 +1,311 @@
+#include "stdlib.h"
+#include "string.h"
+#include "xstdio.h"
+
+// TODO: these come from headers
+#ident "$Revision: 1.23 $"
+#ident "$Revision: 1.34 $"
+#ident "$Revision: 1.5 $"
+
+#define BUFF_LEN 0x20
+
+static s16 _Ldunscale(s16* pex, _Pft* px);
+static void _Genld(_Pft* px, char code, u8* p, s16 nsig, s16 xexp);
+
+static const double pows[] = {10e0L, 10e1L, 10e3L, 10e7L, 10e15L, 10e31L, 10e63L, 10e127L, 10e255L};
+
+// float properties
+#define _D0 0
+#define _DBIAS 0x3ff
+#define _DLONG 1
+#define _DOFF 4
+#define _FBIAS 0x7e
+#define _FOFF 7
+#define _FRND 1
+#define _LBIAS 0x3ffe
+#define _LOFF 15
+// integer properties
+#define _C2 1
+#define _CSIGN 1
+#define _ILONG 0
+#define _MBMAX 8
+#define NAN 2
+#define INF 1
+#define FINITE -1
+#define _DFRAC ((1 << _DOFF) - 1)
+#define _DMASK (0x7fff & ~_DFRAC)
+#define _DMAX ((1 << (15 - _DOFF)) - 1)
+#define _DNAN (0x8000 | _DMAX << _DOFF | 1 << (_DOFF - 1))
+#define _DSIGN 0x8000
+#define _D1 1 // big-endian order
+#define _D2 2
+#define _D3 3
+
+#define ALIGN(s, align) (((u32)(s) + ((align)-1)) & ~((align)-1))
+
+void _Ldtob(_Pft* px, char code) {
+ char buff[BUFF_LEN];
+ char *p;
+ f64 ldval;
+ s16 err;
+ s16 nsig;
+ s16 xexp;
+
+ // char unused[0x4];
+ p = buff;
+ ldval = px->v.ld;
+
+ if (px->prec < 0) {
+ px->prec = 6;
+ } else if (px->prec == 0 && (code == 'g' || code == 'G')) {
+ px->prec = 1;
+ }
+
+ err = _Ldunscale(&xexp, px);
+ if (err > 0) {
+ memcpy(px->s, err == 2 ? "NaN" : "Inf", px->n1 = 3);
+ return;
+ } else if (err == 0) {
+ nsig = 0;
+ xexp = 0;
+ } else {
+ int i;
+ int n;
+
+ if (ldval < 0) {
+ ldval = -ldval;
+ }
+
+ // what
+ if ((xexp = xexp * 30103 / 100000 - 4) < 0) {
+ n = ALIGN(-xexp, 4), xexp = -n;
+
+ for (i = 0; n > 0; n >>= 1, i++) {
+ if (n & 1) {
+ ldval *= pows[i];
+ }
+ }
+ } else if (xexp > 0) {
+ f64 factor = 1;
+
+ xexp &= ~3;
+
+ for (n = xexp, i = 0; n > 0; n >>= 1, i++) {
+ if (n & 1) {
+ factor *= pows[i];
+ }
+ }
+
+ ldval /= factor;
+ }
+ {
+ int gen = px->prec + ((code == 'f') ? 10 + xexp : 6);
+
+ if (gen > 0x13) {
+ gen = 0x13;
+ }
+
+ for (*p++ = '0'; gen > 0 && 0 < ldval; p += 8) {
+ int j;
+ int lo = ldval;
+
+ if ((gen -= 8) > 0) {
+ ldval = (ldval - lo) * 1e8;
+ }
+
+ for (p += 8, j = 8; lo > 0 && --j >= 0;) {
+ ldiv_t qr = ldiv(lo, 10);
+ *--p = qr.rem + '0', lo = qr.quot;
+ }
+
+ while (--j >= 0) {
+ *--p = '0';
+ }
+ }
+
+ gen = p - &buff[1];
+
+ for (p = &buff[1], xexp += 7; *p == '0'; p++) {
+ --gen, --xexp;
+ }
+
+ nsig = px->prec + ((code == 'f') ? xexp + 1 : ((code == 'e' || code == 'E') ? 1 : 0));
+
+ if (gen < nsig) {
+ nsig = gen;
+ }
+
+ if (nsig > 0) {
+ char drop = nsig < gen && '5' <= p[nsig] ? '9' : '0';
+ int n;
+
+ for (n = nsig; p[--n] == drop;) {
+ --nsig;
+ }
+
+ if (drop == '9') {
+ ++p[n];
+ }
+
+ if (n < 0) {
+ --p, ++nsig, ++xexp;
+ }
+ }
+ }
+ }
+
+ _Genld(px, code, p, nsig, xexp);
+}
+
+s16 _Ldunscale(s16* pex, _Pft* px) {
+ u16* ps = px;
+ s16 xchar = (ps[_D0] & _DMASK) >> _DOFF;
+
+
+ if (xchar == _DMAX) {
+ *pex = 0;
+
+ return (ps[_D0] & _DFRAC) || ps[_D1] || ps[_D2] || ps[_D3] ? 2 : 1;
+ } else if (xchar > 0) {
+ ps[_D0] = (ps[_D0] & ~_DMASK) | 0x3FF0;
+ *pex = xchar - 0x3FE;
+ return -1;
+ } else if (xchar < 0) {
+ return 2;
+ } else {
+ *pex = 0;
+ return 0;
+ }
+}
+
+void _Genld(_Pft* px, char code, u8* p, s16 nsig, s16 xexp) {
+ const unsigned char point = '.';
+
+ if (nsig <= 0) {
+ nsig = 1, p = "0"; // memes
+ }
+
+ if (code == 'f' || (code == 'g' || code == 'G') && xexp >= -4 && xexp < px->prec) {
+ xexp += 1;
+ if (code != 'f') {
+ if (((px->flags & 8) == 0) && nsig < px->prec) {
+ px->prec = nsig;
+ }
+
+ px->prec -= xexp;
+ if (px->prec < 0) {
+ px->prec = 0;
+ }
+ }
+
+ if (xexp <= 0) {
+ px->s[px->n1++] = '0';
+
+ if (px->prec > 0 || (px->flags & 8)) {
+ px->s[px->n1++] = point;
+ }
+
+ if (px->prec < -xexp) {
+ xexp = -px->prec;
+ }
+
+ px->nz1 = -xexp;
+ px->prec += xexp;
+
+ if (px->prec < nsig) {
+ nsig = px->prec;
+ }
+
+ memcpy(&px->s[px->n1], p, px->n2 = nsig); // , memes (this one is insane)
+ px->nz2 = px->prec - nsig;
+ } else if (nsig < xexp) {
+ memcpy(&px->s[px->n1], p, nsig);
+ px->n1 += nsig;
+ px->nz1 = xexp - nsig;
+ if (px->prec > 0 || (px->flags & 8)) {
+ px->s[px->n1] = point;
+ px->n2 += 1;
+ }
+
+ px->nz2 = px->prec;
+ } else {
+ memcpy(&px->s[px->n1], p, xexp);
+ px->n1 += xexp;
+ nsig -= xexp;
+
+ if (px->prec > 0 || (px->flags & 8)) {
+ px->s[px->n1++] = point;
+ }
+
+ if (px->prec < nsig) {
+ nsig = px->prec;
+ }
+
+ memcpy(&px->s[px->n1], &p[xexp], nsig);
+ px->n1 += nsig;
+ px->nz1 = px->prec - nsig;
+ }
+ } else {
+ if (code == 'g' || code == 'G') {
+ if (nsig < px->prec) {
+ px->prec = nsig;
+ }
+
+ if (--px->prec < 0) {
+ px->prec = 0;
+ }
+
+ if (code == 'g') {
+ code = 'e';
+ } else {
+ code = 'E';
+ }
+ }
+
+ px->s[px->n1++] = *p++;
+
+ if (px->prec > 0 || (px->flags & 8)) {
+ px->s[px->n1++] = point;
+ }
+
+ if (px->prec > 0) {
+ if (px->prec < --nsig) {
+ nsig = px->prec;
+ }
+
+ memcpy(&px->s[px->n1], p, nsig);
+ px->n1 += nsig;
+ px->nz1 = px->prec - nsig;
+ }
+
+ p = &px->s[px->n1];
+ *p++ = code;
+
+ if (xexp >= 0) {
+ *p++ = '+';
+ } else {
+ *p++ = '-';
+ xexp = -xexp;
+ }
+
+ if (xexp >= 100) {
+ if (xexp >= 1000) {
+ *p++ = (xexp / 1000) + '0', xexp %= 1000; // , memes
+ }
+ *p++ = (xexp / 100) + '0', xexp %= 100; // , memes
+ }
+ *p++ = (xexp / 10) + '0', xexp %= 10; // , memes
+
+ *p++ = xexp + '0';
+ px->n2 = (size_t)p - ((size_t)px->s + px->n1);
+ }
+
+ if ((px->flags & 0x14) == 0x10) {
+ s32 n = px->n0 + px->n1 + px->nz1 + px->n2 + px->nz2;
+
+ if (n < px->width) {
+ px->nz0 = px->width - n;
+ }
+ }
+}
+
diff --git a/lib/ultralib/src/libc/xlitob.c b/lib/ultralib/src/libc/xlitob.c
new file mode 100755
index 0000000..f297df4
--- /dev/null
+++ b/lib/ultralib/src/libc/xlitob.c
@@ -0,0 +1,64 @@
+#include "stdlib.h"
+#include "string.h"
+#include "xstdio.h"
+
+// TODO: these come from headers
+#ident "$Revision: 1.34 $"
+#ident "$Revision: 1.5 $"
+#ident "$Revision: 1.23 $"
+
+#define BUFF_LEN 0x18
+
+static char ldigs[] = "0123456789abcdef";
+static char udigs[] = "0123456789ABCDEF";
+
+void _Litob(_Pft *args, char type) {
+ char buff[BUFF_LEN];
+ const char *digs;
+ s32 base;
+ s32 i;
+ unsigned long long ullval;
+
+ if (type == 'X') {
+ digs = udigs;
+ } else {
+ digs = ldigs;
+ }
+
+ base = (type == 'o') ? 8 : ((type != 'x' && type != 'X') ? 10 : 16);
+ i = BUFF_LEN;
+ ullval = args->v.ll;
+
+ if ((type == 'd' || type == 'i') && args->v.ll < 0) {
+ ullval = -ullval;
+ }
+
+ if (ullval != 0 || args->prec != 0) {
+ buff[--i] = digs[ullval % base];
+ }
+
+ args->v.ll = ullval / base;
+
+ while (args->v.ll > 0 && i > 0) {
+ lldiv_t qr = lldiv(args->v.ll, base);
+
+ args->v.ll = qr.quot;
+ buff[--i] = digs[qr.rem];
+ }
+
+ args->n1 = BUFF_LEN - i;
+
+ memcpy(args->s, buff + i, args->n1);
+
+ if (args->n1 < args->prec) {
+ args->nz0 = args->prec - args->n1;
+ }
+
+ if (args->prec < 0 && (args->flags & (FLAGS_ZERO | FLAGS_MINUS)) == FLAGS_ZERO) {
+ i = args->width - args->n0 - args->nz0 - args->n1;
+
+ if (i > 0) {
+ args->nz0 += i;
+ }
+ }
+}
diff --git a/lib/ultralib/src/libc/xprintf.c b/lib/ultralib/src/libc/xprintf.c
new file mode 100755
index 0000000..d9f1003
--- /dev/null
+++ b/lib/ultralib/src/libc/xprintf.c
@@ -0,0 +1,241 @@
+#include "macros.h"
+#include "string.h"
+#include "stdarg.h"
+#include "xstdio.h"
+
+// TODO: these come from headers
+#ident "$Revision: 1.34 $"
+#ident "$Revision: 1.5 $"
+#ident "$Revision: 1.23 $"
+
+#define isdigit(x) ((x >= '0' && x <= '9'))
+#define LDSIGN(x) (((unsigned short *)&(x))[0] & 0x8000)
+
+#define ATOI(dst, src) \
+ for (dst = 0; isdigit(*src); ++src) \
+ { \
+ if (dst < 999) \
+ dst = dst * 10 + *src - '0'; \
+ }
+
+#define MAX_PAD ((sizeof(spaces) - 1))
+#define PAD(s, n) \
+ if (0 < (n)) \
+ { \
+ int i, j = (n); \
+ for (; 0 < j; j -= i) \
+ { \
+ i = MAX_PAD < (unsigned int)j ? (int)MAX_PAD : j; \
+ PUT(s, i); \
+ } \
+ }
+#define PUT(s, n) \
+ if (0 < (n)) \
+ { \
+ if ((arg = (*prout)(arg, s, n)) != NULL) \
+ x.nchar += (n); \
+ else \
+ return x.nchar; \
+ }
+static char spaces[] = " ";
+static char zeroes[] = "00000000000000000000000000000000";
+
+static void _Putfld(_Pft *pf, va_list *pap, char code, char *ac);
+
+int _Printf(outfun prout, char *arg, const char *fmt, va_list args) {
+ _Pft x;
+ const char *s;
+ char c;
+ const char *t;
+ static const char fchar[] = {' ', '+', '-', '#', '0', '\0'};
+ static const int fbit[] = {FLAGS_SPACE, FLAGS_PLUS, FLAGS_MINUS, FLAGS_HASH, FLAGS_ZERO, 0};
+ char ac[32];
+
+ x.nchar = 0;
+
+ for (;;) {
+ s = fmt;
+
+ for (c = *s; c != 0 && c != '%';) {
+ c = *++s;
+ }
+
+ PUT(fmt, s - fmt);
+
+ if (c == 0) {
+ return x.nchar;
+ }
+
+ fmt = ++s;
+
+ for (x.flags = 0; (t = strchr(fchar, *s)) != NULL; s++) {
+ x.flags |= fbit[t - fchar];
+ }
+
+ if (*s == '*') {
+ x.width = va_arg(args, int);
+
+ if (x.width < 0) {
+ x.width = -x.width;
+ x.flags |= FLAGS_MINUS;
+ }
+ s++;
+ } else {
+ ATOI(x.width, s);
+ }
+
+ if (*s != '.') {
+ x.prec = -1;
+ } else if (*++s == '*') {
+ x.prec = va_arg(args, int);
+ ++s;
+ } else {
+ ATOI(x.prec, s);
+ }
+
+ x.qual = strchr("hlL", *s) ? *s++ : '\0';
+
+ if (x.qual == 'l' && *s == 'l') {
+ x.qual = 'L';
+ ++s;
+ }
+
+ _Putfld(&x, &args, *s, ac);
+ x.width -= x.n0 + x.nz0 + x.n1 + x.nz1 + x.n2 + x.nz2;
+
+ if (!(x.flags & FLAGS_MINUS)) {
+ PAD(spaces, x.width);
+ }
+
+ PUT(ac, x.n0);
+ PAD(zeroes, x.nz0);
+ PUT(x.s, x.n1);
+ PAD(zeroes, x.nz1);
+ PUT(x.s + x.n1, x.n2);
+ PAD(zeroes, x.nz2);
+
+ if (x.flags & FLAGS_MINUS) {
+ PAD(spaces, x.width);
+ }
+
+ fmt = s + 1;
+ }
+ return 0;
+}
+
+static void _Putfld(_Pft *x, va_list *args, char type, char *buff) {
+ x->n0 = x->nz0 = x->n1 = x->nz1 = x->n2 =
+ x->nz2 = 0;
+
+ switch (type) {
+ case 'c':
+ buff[x->n0++] = va_arg(*args, int);
+ break;
+ case 'd':
+ case 'i':
+ if (x->qual == 'l') {
+ x->v.ll = va_arg(*args, int);
+ } else if (x->qual == 'L') {
+ x->v.ll = va_arg(*args, s64);
+ } else {
+ x->v.ll = va_arg(*args, int);
+ }
+
+ if (x->qual == 'h') {
+ x->v.ll = (s16)x->v.ll;
+ }
+
+ if (x->v.ll < 0) {
+ buff[x->n0++] = '-';
+ } else if (x->flags & FLAGS_PLUS) {
+ buff[x->n0++] = '+';
+ } else if (x->flags & FLAGS_SPACE) {
+ buff[x->n0++] = ' ';
+ }
+
+ x->s = (char *)&buff[x->n0];
+
+ _Litob(x, type);
+ break;
+ case 'x':
+ case 'X':
+ case 'u':
+ case 'o':
+ if (x->qual == 'l') {
+ x->v.ll = va_arg(*args, int);
+ } else if (x->qual == 'L') {
+ x->v.ll = va_arg(*args, s64);
+ } else {
+ x->v.ll = va_arg(*args, int);
+ }
+
+ if (x->qual == 'h') {
+ x->v.ll = (u16)x->v.ll;
+ } else if (x->qual == 0) {
+ x->v.ll = (unsigned int)x->v.ll;
+ }
+
+ if (x->flags & FLAGS_HASH) {
+ buff[x->n0++] = '0';
+
+ if (type == 'x' || type == 'X') {
+ buff[x->n0++] = type;
+ }
+ }
+
+ x->s = (char *)&buff[x->n0];
+ _Litob(x, type);
+ break;
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ //... okay?
+ x->v.ld = x->qual == 'L' ? va_arg(*args, f64) : va_arg(*args, f64);
+
+ if (LDSIGN(x->v.ld))
+ buff[x->n0++] = '-';
+ else if (x->flags & FLAGS_PLUS)
+ buff[x->n0++] = '+';
+ else if (x->flags & FLAGS_SPACE)
+ buff[x->n0++] = ' ';
+
+ x->s = (char *)&buff[x->n0];
+ _Ldtob(x, type);
+ break;
+
+ case 'n':
+ if (x->qual == 'h') {
+ *(va_arg(*args, u16 *)) = x->nchar;
+ } else if (x->qual == 'l') {
+ *va_arg(*args, unsigned int *) = x->nchar;
+ } else if (x->qual == 'L') {
+ *va_arg(*args, u64 *) = x->nchar;
+ } else {
+ *va_arg(*args, unsigned int *) = x->nchar;
+ }
+
+ break;
+ case 'p':
+ x->v.ll = (long)va_arg(*args, void *);
+ x->s = (char *)&buff[x->n0];
+ _Litob(x, 'x');
+ break;
+ case 's':
+ x->s = va_arg(*args, char *);
+ x->n1 = strlen(x->s);
+
+ if (x->prec >= 0 && x->n1 > x->prec) {
+ x->n1 = x->prec;
+ }
+
+ break;
+ case '%':
+ buff[x->n0++] = '%';
+ break;
+ default:
+ buff[x->n0++] = type;
+ break;
+ }
+}
diff --git a/lib/ultralib/src/libc/xstdio.h b/lib/ultralib/src/libc/xstdio.h
new file mode 100755
index 0000000..bd70de8
--- /dev/null
+++ b/lib/ultralib/src/libc/xstdio.h
@@ -0,0 +1,37 @@
+#ifndef _XSTDIO_H
+#define _XSTDIO_H
+#include "PR/ultratypes.h"
+#include "stdlib.h"
+#include "stdarg.h"
+
+typedef struct {
+ /* 0x0 */ union {
+ /* 0x0 */ long long ll;
+ /* 0x0 */ double ld;
+ } v;
+ /* 0x8 */ unsigned char* s;
+ /* 0xC */ int n0;
+ /* 0x10 */ int nz0;
+ /* 0x14 */ int n1;
+ /* 0x18 */ int nz1;
+ /* 0x1C */ int n2;
+ /* 0x20 */ int nz2;
+ /* 0x24 */ int prec;
+ /* 0x28 */ int width;
+ /* 0x2C */ size_t nchar;
+ /* 0x30 */ unsigned int flags;
+ /* 0x34 */ char qual;
+} _Pft;
+
+#define FLAGS_SPACE 1
+#define FLAGS_PLUS 2
+#define FLAGS_MINUS 4
+#define FLAGS_HASH 8
+#define FLAGS_ZERO 16
+typedef char *outfun(char*,const char*,size_t);
+
+int _Printf(outfun prout, char *arg, const char *fmt, va_list args);
+void _Litob(_Pft *args, char type);
+void _Ldtob(_Pft* args, char type);
+
+#endif
diff --git a/lib/ultralib/src/mgu/Makefile b/lib/ultralib/src/mgu/Makefile
new file mode 100644
index 0000000..52c29f6
--- /dev/null
+++ b/lib/ultralib/src/mgu/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for the gu subdirectory
+#
+
+include $(ROOT)/usr/include/make/PRdefs
+
+LCINCS = -I. -I../gu -I$(ROOT)/usr/include/PR -I$(ROOT)/usr/include
+LASINCS = -I. -I$(ROOT)/usr/include/PR -I$(ROOT)/include
+LCOPTS = -G 0 -g -O
+
+CFILES = mtxcatl.c \
+ mtxxfml.c \
+ mtxxfmf.c \
+ rotate.c
+
+ASFILES = mtxident.s \
+ mtxidentf.s \
+ mtxf2l.s \
+ mtxl2f.s \
+ mtxcatf.s \
+ scale.s \
+ scalef.s \
+ normalize.s \
+ translate.s \
+ translatef.s
+
+OBJECTS = $(CFILES:.c=.o) $(ASFILES:.s=.o)
+
+default: $(OBJECTS)
+
+include $(COMMONRULES)
+
+.s.o:
+ cpp $(F_ROM) -DLANG_JAPANESE -E -DMIPSEB -DLANGUAGE_ASSEMBLY -D_MIPS_SIM=1 -D_ULTRA64 -I. -I$(LIBDEPTH)\include $*.s $*.ss2
+ as -mips3 -G0 -o $*.o $*.ss2
+ del $*.ss?
diff --git a/lib/ultralib/src/mgu/asm.h b/lib/ultralib/src/mgu/asm.h
new file mode 100644
index 0000000..0c417fa
--- /dev/null
+++ b/lib/ultralib/src/mgu/asm.h
@@ -0,0 +1,49 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO Co,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO Co,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO Co,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/07/06 13:21:13 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+
+#ifndef __ASM_H__
+#define __ASM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _MIPS_ISA_MIPS1 1 /* R2/3K */
+#define _MIPS_ISA_MIPS2 2 /* R4K/6K */
+#define _MIPS_ISA_MIPS3 3 /* R4K */
+#define _MIPS_ISA_MIPS4 4 /* TFP */
+
+#define _MIPS_SIM_ABI32 1 /* MIPS MSIG calling convention */
+#define _MIPS_SIM_NABI32 2 /* MIPS new 32-bit abi */
+ /* NABI32 is 64bit calling convention but 32bit type sizes) */
+#define _MIPS_SIM_ABI64 3 /* MIPS 64 calling convention */
+
+#define LEAF(x) \
+ .globl x; \
+ .ent x,0; \
+x:; \
+ .frame sp,0,ra
+
+#define END(proc) \
+ .end proc
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__ASM_H__ */
diff --git a/lib/ultralib/src/mgu/mtxcatf.s b/lib/ultralib/src/mgu/mtxcatf.s
new file mode 100644
index 0000000..4b96124
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxcatf.s
@@ -0,0 +1,103 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:37 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guMtxCatF(float mf[4][4], float nf[4][4], float res[4][4])
+ * res = mf * nf
+ */
+#define FRAME_SIZE 64
+ .text
+ .align 5
+ .globl guMtxCatF
+ .ent guMtxCatF, 0
+guMtxCatF:
+ .set reorder
+ subu sp, FRAME_SIZE
+ .frame sp, FRAME_SIZE, ra
+
+ addu v0, a0, 64
+ addu v1, a1, 16
+ move t2, sp
+label_loop_i:
+ move a3, a1
+label_loop_j:
+ l.s ft0, 0(a0) /* mf[i][0] * nf[0][j] */
+ l.s ft1, 0(a3)
+ mul.s ft2, ft0, ft1
+ l.s ft3, 4(a0) /* + mf[i][1] * nf[1][j] */
+ l.s ft4, 16(a3)
+ mul.s ft5, ft3, ft4
+ add.s ft2, ft2, ft5
+ l.s ft0, 8(a0) /* + mf[i][2] * nf[2][j] */
+ l.s ft1, 32(a3)
+ mul.s ft5, ft0, ft1
+ add.s ft2, ft2, ft5
+ l.s ft3, 12(a0) /* + mf[i][3] * nf[3][j] */
+ l.s ft4, 48(a3)
+ mul.s ft5, ft3, ft4
+ add.s ft2, ft2, ft5
+
+ s.s ft2, 0(t2)
+ addu a3, a3, 4
+ addu t2, t2, 4
+ bne a3, v1, label_loop_j
+/* loop_j_end */
+ addu a0, a0, 16
+ bne a0, v0, label_loop_i
+/* loop_i_end */
+ s.s ft2, 60(a2)
+ lw t0, 0(sp)
+ lw t1, 4(sp)
+ lw t2, 8(sp)
+ lw t3, 12(sp)
+ lw ta0, 16(sp)
+ lw ta1, 20(sp)
+ lw ta2, 24(sp)
+ lw ta3, 28(sp)
+ lw t8, 32(sp)
+ lw t9, 36(sp)
+ lw v0, 40(sp)
+ lw v1, 44(sp)
+ lw a0, 48(sp)
+ lw a1, 52(sp)
+ lw a3, 56(sp)
+
+ sw t0, 0(a2)
+ sw t1, 4(a2)
+ sw t2, 8(a2)
+ sw t3, 12(a2)
+ sw ta0, 16(a2)
+ sw ta1, 20(a2)
+ sw ta2, 24(a2)
+ sw ta3, 28(a2)
+ sw t8, 32(a2)
+ sw t9, 36(a2)
+ sw v0, 40(a2)
+ sw v1, 44(a2)
+ sw a0, 48(a2)
+ sw a1, 52(a2)
+ sw a3, 56(a2)
+
+ addu sp , FRAME_SIZE
+ j ra
+
+ .end guMtxCatF
+
+/* end of file */
diff --git a/lib/ultralib/src/mgu/mtxcatl.c b/lib/ultralib/src/mgu/mtxcatl.c
new file mode 100644
index 0000000..86a978a
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxcatl.c
@@ -0,0 +1,34 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:37 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+
+#include <ultra64.h>
+#include "../gu/guint.h"
+#include "gu.h"
+
+void guMtxCatL(Mtx *m, Mtx *n, Mtx *res)
+{
+ float mf[4][4], nf[4][4], resf[4][4];
+
+ guMtxL2F(mf, m);
+ guMtxL2F(nf, n);
+
+ guMtxCatF(mf, nf, resf);
+
+ guMtxF2L(resf, res);
+}
+
+/* End of file */
diff --git a/lib/ultralib/src/mgu/mtxf2l.s b/lib/ultralib/src/mgu/mtxf2l.s
new file mode 100644
index 0000000..43bbe7e
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxf2l.s
@@ -0,0 +1,80 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:38 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guMtxF2L(float mf[4][4], Mtx *m)
+ *
+ * Input
+ * float mf[4][4]
+ * Output
+ * Mtx *m
+ */
+
+#define HALF_SIZE_MTX 32
+#define MASK_LOW 0x0000FFFF
+#define MASK_HIGH 0xFFFF0000
+#define MAGNIFICANT 65536.0 /* = 0x10000 */
+
+#define ptr_fl a0 /* argument */
+#define ptr_mtx a1 /* argument */
+#define end_mtx t8
+#define mask_hi t9
+#define magni fv0
+
+ .text
+ .align 5
+LEAF( guMtxF2L )
+ .set reorder
+
+ li.s magni, MAGNIFICANT
+ li mask_hi, MASK_HIGH
+ addu end_mtx, ptr_mtx, HALF_SIZE_MTX
+label_loop:
+ l.s ft0, 0(ptr_fl) /* FTOFIX32( ) */
+ mul.s ft1, ft0, magni
+ trunc.w.s ft2, ft1
+
+ l.s ft3, 4(ptr_fl) /* FTOFIX32( ) */
+ mul.s ft4, ft3, magni
+ trunc.w.s ft5, ft4
+
+ mfc1 t0, ft2 /* t0 <- FIXED */
+ mfc1 t1, ft5 /* t1 <- FIXED */
+
+ and t2, t0, mask_hi /* integral part */
+ srl t3, t1, 16
+ or ta0, t2, t3
+ sw ta0, 0(ptr_mtx)
+
+ sll ta1, t0, 16 /* decimal part */
+ and ta2, t1, MASK_LOW
+ or ta3, ta1, ta2
+ sw ta3, HALF_SIZE_MTX(ptr_mtx)
+
+ addu ptr_mtx, ptr_mtx, 4
+ addu ptr_fl, ptr_fl, 8
+
+ bne ptr_mtx, end_mtx, label_loop
+/* loop-end */
+
+ j ra
+ END( guMtxF2L )
+
+/* End of file */
diff --git a/lib/ultralib/src/mgu/mtxident.s b/lib/ultralib/src/mgu/mtxident.s
new file mode 100644
index 0000000..a9ec491
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxident.s
@@ -0,0 +1,60 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:38 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guMtxIdent( Mtx * matrix )
+ * Substitute unit matrix for matrix
+ * Correspond only when alignment is 4 byte boundary
+ * Input
+ * a0 = matrix
+ * Output
+ * *matrix unit matrix
+ */
+
+#define SIZE_OF_MTX 64 /* sizeof( Mtx ) */
+ .text
+ .align 5
+LEAF(guMtxIdent)
+ .set reorder
+
+ addi t0, zero, 1 /* t0 = 0x00000001 */
+ sll t1, t0, 16 /* t1 = 0x00010000 */
+
+ sw t1, 0(a0) /* Substitution of integers */
+ sw zero, 4(a0)
+ sw t0, 8(a0)
+ sw zero, 12(a0)
+ sw zero, 16(a0)
+ sw t1, 20(a0)
+ sw zero, 24(a0)
+ sw t0, 28(a0)
+
+ sw zero, 32(a0) /* Substitution of fractions */
+ sw zero, 36(a0)
+ sw zero, 40(a0)
+ sw zero, 44(a0)
+ sw zero, 48(a0)
+ sw zero, 52(a0)
+ sw zero, 56(a0)
+ sw zero, 60(a0)
+ j ra
+
+ END(guMtxIdent)
+
+/* End of file */
diff --git a/lib/ultralib/src/mgu/mtxidentf.s b/lib/ultralib/src/mgu/mtxidentf.s
new file mode 100644
index 0000000..a6aa779
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxidentf.s
@@ -0,0 +1,60 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:38 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * guMtxIdentF( float matrix[4][4] )
+ * substitute unit matrix for floating point matrix
+ * correspond only when alignment is four byte boundary
+ * Input
+ * a0 = matrix
+ * Output
+ * *matrix unti matix
+ */
+ .text
+ .align 5
+LEAF( guMtxIdentF )
+ .set reorder
+
+ li t0, 0x3f800000 /* t0 = 1.0 */
+
+ sw t0, 0(a0)
+ sw zero, 4(a0) /* line 1 */
+ sw zero, 8(a0)
+ sw zero, 12(a0)
+
+ sw zero, 16(a0) /* line 2 */
+ sw t0, 20(a0)
+ sw zero, 24(a0)
+ sw zero, 28(a0)
+
+ sw zero, 32(a0) /* line 3 */
+ sw zero, 36(a0)
+ sw t0, 40(a0)
+ sw zero, 44(a0)
+
+ sw zero, 48(a0) /* line 4 */
+ sw zero, 52(a0)
+ sw zero, 56(a0)
+ sw t0, 60(a0)
+
+ j ra
+
+ END( guMtxIdentF )
+
+/* End of file */ \ No newline at end of file
diff --git a/lib/ultralib/src/mgu/mtxl2f.s b/lib/ultralib/src/mgu/mtxl2f.s
new file mode 100644
index 0000000..897acfb
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxl2f.s
@@ -0,0 +1,80 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:38 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guMtxF2L(float mf[4][4], Mtx *m)
+ *
+ * Input
+ * float mf[4][4]
+ * Output
+ * Mtx *m
+ */
+
+#define HALF_SIZE_MTX 32
+#define MASK_LOW 0x0000FFFF
+#define MASK_HIGH 0xFFFF0000
+#define MAGNIFICANT 1.5258789062500000e-05 /* ~ 1 / 0x10000 */
+
+#define ptr_fl a0 /* argument */
+#define ptr_mtx a1 /* argument */
+#define end_mtx t8
+#define mask_hi t9
+#define magni fv0
+
+ .text
+ .align 5
+LEAF( guMtxL2F )
+ .set reorder
+ li.s magni, MAGNIFICANT
+ li mask_hi, MASK_HIGH
+ addu end_mtx, ptr_mtx, HALF_SIZE_MTX
+label_loop:
+ lw t0, 0(ptr_mtx)
+ lw t1, 32(ptr_mtx)
+
+ and t2, t0, mask_hi
+ srl t3, t1, 16
+ or ta0, t2, t3
+
+ sll ta1, t0, 16
+ and ta2, t1, MASK_LOW
+ or ta3, ta1, ta2
+
+ mtc1 ta0, ft0 /* FIX32TOF( ) */
+ cvt.s.w ft1, ft0
+ mul.s ft2, ft1, magni
+
+ mtc1 ta3, ft3 /* FIX32TOF( ) */
+ cvt.s.w ft4, ft3
+ mul.s ft5, ft4, magni
+
+ s.s ft2, 0(ptr_fl)
+ s.s ft5, 4(ptr_fl)
+
+ addu ptr_mtx, ptr_mtx, 4
+ addu ptr_fl, ptr_fl, 8
+
+ bne ptr_mtx, end_mtx, label_loop
+/* loop-end */
+
+ j ra
+ END( guMtxL2F )
+
+/* End of file */
diff --git a/lib/ultralib/src/mgu/mtxxfmf.c b/lib/ultralib/src/mgu/mtxxfmf.c
new file mode 100644
index 0000000..58c6772
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxxfmf.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ */
+
+/*
+ * File: mtxcatf.c
+ * Creator: hsa@sgi.com
+ * Create Date: Thu Nov 2 13:03:02 PST 1995
+ *
+ */
+
+#include "../gu/guint.h"
+
+void guMtxXFMF(float mf[4][4], float x, float y, float z, float *ox, float *oy, float *oz)
+{
+ *ox = mf[0][0]*x + mf[1][0]*y + mf[2][0]*z + mf[3][0];
+ *oy = mf[0][1]*x + mf[1][1]*y + mf[2][1]*z + mf[3][1];
+ *oz = mf[0][2]*x + mf[1][2]*y + mf[2][2]*z + mf[3][2];
+}
+
diff --git a/lib/ultralib/src/mgu/mtxxfml.c b/lib/ultralib/src/mgu/mtxxfml.c
new file mode 100644
index 0000000..1dfa871
--- /dev/null
+++ b/lib/ultralib/src/mgu/mtxxfml.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ */
+
+/*
+ * File: mtxcatl.c
+ * Creator: hsa@sgi.com
+ * Create Date: Thu Nov 2 13:03:02 PST 1995
+ *
+ */
+
+#include "../gu/guint.h"
+
+void guMtxXFML(Mtx *m, float x, float y, float z, float *ox, float *oy, float *oz)
+{
+ float mf[4][4];
+
+ guMtxL2F(mf, m);
+
+ guMtxXFMF(mf, x, y, z, ox, oy, oz);
+}
diff --git a/lib/ultralib/src/mgu/normalize.s b/lib/ultralib/src/mgu/normalize.s
new file mode 100644
index 0000000..58b9093
--- /dev/null
+++ b/lib/ultralib/src/mgu/normalize.s
@@ -0,0 +1,56 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:39 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guNormalize(float *x, float *y, float *z)
+ */
+ .text
+ .align 5
+LEAF( guNormalize )
+ .set noreorder
+
+ l.s ft0, 0(a0) /* ft0 = x */
+ l.s ft1, 0(a1) /* ft1 = y */
+ l.s ft2, 0(a2) /* ft2 = z */
+
+ mul.s ft3, ft0, ft0 /* ft3 = x*x */
+ lui t0, 0x3f80 /* t0 = 1.0f */
+ mul.s ft4, ft1, ft1 /* ft4 = y*y */
+ add.s ft5, ft3, ft4
+ mul.s ft4, ft2, ft2 /* ft4 = z*z */
+
+ add.s ft3, ft4, ft5 /* ft3 = x*x + y*y + z*z */
+ mtc1 t0, ft5
+ sqrt.s ft4, ft3 /* ft4 = sqrt(x*x + y*y + z*z) */
+
+ div.s ft3, ft5, ft4 /* ft3 = 1/sqrt(x*x + y*y + z*z) */
+
+ mul.s ft4, ft0, ft3 /* ft4 = x * 1/sqrt(x*x + y*y + z*z) */
+ nop
+ mul.s ft5, ft1, ft3 /* ft5 = y * 1/sqrt(x*x + y*y + z*z) */
+ nop
+ mul.s ft0, ft2, ft3 /* ft0 = z * 1/sqrt(x*x + y*y + z*z) */
+
+ s.s ft4, 0(a0) /* x = ft4 */
+ s.s ft5, 0(a1) /* y = ft5 */
+ j ra
+ s.s ft0, 0(a2) /* z = ft0 */ /* Use delayed slot */
+
+ END( guNormalize )
+/* end of file */
diff --git a/lib/ultralib/src/mgu/regdef.h b/lib/ultralib/src/mgu/regdef.h
new file mode 100644
index 0000000..ac9c109
--- /dev/null
+++ b/lib/ultralib/src/mgu/regdef.h
@@ -0,0 +1,187 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO Co,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO Co,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO Co,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/07/06 13:21:13 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+
+#ifndef __REGDEF_H__
+#define __REGDEF_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef mips
+
+#if (_MIPS_SIM == _MIPS_SIM_ABI32)
+#define zero $0
+#define AT $at
+#define v0 $2
+#define v1 $3
+#define a0 $4
+#define a1 $5
+#define a2 $6
+#define a3 $7
+#define t0 $8
+#define t1 $9
+#define t2 $10
+#define t3 $11
+#define t4 $12
+#define ta0 $12
+#define t5 $13
+#define ta1 $13
+#define t6 $14
+#define ta2 $14
+#define t7 $15
+#define ta3 $15
+#define s0 $16
+#define s1 $17
+#define s2 $18
+#define s3 $19
+#define s4 $20
+#define s5 $21
+#define s6 $22
+#define s7 $23
+#define t8 $24
+#define t9 $25
+#define jp $25
+#define k0 $26
+#define k1 $27
+#define gp $28
+#define sp $29
+#define fp $30
+#define s8 $30
+#define ra $31
+#endif
+
+#if (_MIPS_SIM == _MIPS_SIM_ABI64)
+#define zero $0
+#define AT $at
+#define v0 $2
+#define v1 $3
+#define a0 $4
+#define a1 $5
+#define a2 $6
+#define a3 $7
+#define a4 $8
+#define ta0 $8
+#define a5 $9
+#define ta1 $9
+#define a6 $10
+#define ta2 $10
+#define a7 $11
+#define ta3 $11
+#define t0 $12
+#define t1 $13
+#define t2 $14
+#define t3 $15
+#define s0 $16
+#define s1 $17
+#define s2 $18
+#define s3 $19
+#define s4 $20
+#define s5 $21
+#define s6 $22
+#define s7 $23
+#define t8 $24
+#define t9 $25
+#define jp $25
+#define k0 $26
+#define k1 $27
+#define gp $28
+#define sp $29
+#define fp $30
+#define s8 $30
+#define ra $31
+#endif
+
+#if (_MIPS_SIM == _MIPS_SIM_ABI32)
+#define fv0 $f0
+#define fv0f $f1
+#define fv1 $f2
+#define fv1f $f3
+#define fa0 $f12
+#define fa0f $f13
+#define fa1 $f14
+#define fa1f $f15
+#define ft0 $f4
+#define ft0f $f5
+#define ft1 $f6
+#define ft1f $f7
+#define ft2 $f8
+#define ft2f $f9
+#define ft3 $f10
+#define ft3f $f11
+#define ft4 $f16
+#define ft4f $f17
+#define ft5 $f18
+#define ft5f $f19
+#define fs0 $f20
+#define fs0f $f21
+#define fs1 $f22
+#define fs1f $f23
+#define fs2 $f24
+#define fs2f $f25
+#define fs3 $f26
+#define fs3f $f27
+#define fs4 $f28
+#define fs4f $f29
+#define fs5 $f30
+#define fs5f $f31
+#endif
+
+#if (_MIPS_SIM == _MIPS_SIM_ABI64)
+#define fv0 $f0
+#define fv1 $f2
+#define fa0 $f12
+#define fa1 $f13
+#define fa2 $f14
+#define fa3 $f15
+#define fa4 $f16
+#define fa5 $f17
+#define fa6 $f18
+#define fa7 $f19
+#define ft0 $f4
+#define ft1 $f5
+#define ft2 $f6
+#define ft3 $f7
+#define ft4 $f8
+#define ft5 $f9
+#define ft6 $f10
+#define ft7 $f11
+#define ft8 $f20
+#define ft9 $f21
+#define ft10 $f22
+#define ft11 $f23
+#define ft12 $f1
+#define ft13 $f3
+#define fs0 $f24
+#define fs1 $f25
+#define fs2 $f26
+#define fs3 $f27
+#define fs4 $f28
+#define fs5 $f29
+#define fs6 $f30
+#define fs7 $f31
+#endif
+
+#define fcr31 $31
+
+#endif /* mips */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__REGDEF_H__ */
diff --git a/lib/ultralib/src/mgu/rotate.c b/lib/ultralib/src/mgu/rotate.c
new file mode 100644
index 0000000..fec2443
--- /dev/null
+++ b/lib/ultralib/src/mgu/rotate.c
@@ -0,0 +1,64 @@
+/**************************************************************************
+ * *
+ * Copyright (C) 1994, Silicon Graphics, Inc. *
+ * *
+ * These coded instructions, statements, and computer programs contain *
+ * unpublished proprietary information of Silicon Graphics, Inc., and *
+ * are protected by Federal copyright law. They may not be disclosed *
+ * to third parties or copied or duplicated in any form, in whole or *
+ * in part, without the prior written consent of Silicon Graphics, Inc. *
+ * *
+ **************************************************************************/
+
+#include "../gu/guint.h"
+#include "gu.h"
+
+void guRotateF(float mf[4][4], float a, float x, float y, float z)
+{
+ static float dtor = 3.1415926 / 180.0;
+ float sine;
+ float cosine;
+ float ab, bc, ca, t;
+ float xxsine;
+ float yxsine;
+ float zxsine;
+
+ guNormalize(&x, &y, &z);
+ a *= dtor;
+ sine = sinf(a);
+ cosine = cosf(a);
+ t = (1-cosine);
+ ab = x*y*t;
+ bc = y*z*t;
+ ca = z*x*t;
+
+ guMtxIdentF(mf);
+
+ xxsine = x * sine;
+ yxsine = y * sine;
+ zxsine = z * sine;
+
+ t = x*x;
+ mf[0][0] = t+cosine*(1-t);
+ mf[2][1] = bc-xxsine;
+ mf[1][2] = bc+xxsine;
+
+ t = y*y;
+ mf[1][1] = t+cosine*(1-t);
+ mf[2][0] = ca+yxsine;
+ mf[0][2] = ca-yxsine;
+
+ t = z*z;
+ mf[2][2] = t+cosine*(1-t);
+ mf[1][0] = ab-zxsine;
+ mf[0][1] = ab+zxsine;
+}
+
+void guRotate(Mtx *m, float a, float x, float y, float z)
+{
+ Matrix mf;
+
+ guRotateF(mf, a, x, y, z);
+
+ guMtxF2L(mf, m);
+}
diff --git a/lib/ultralib/src/mgu/scale.s b/lib/ultralib/src/mgu/scale.s
new file mode 100644
index 0000000..01bc290
--- /dev/null
+++ b/lib/ultralib/src/mgu/scale.s
@@ -0,0 +1,85 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:40 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * FTOFIX32 (float to fix32)
+ * a: input
+ * t: output
+ * ft0 : (float)0x00010000
+ * ft1, ft2, ft3, t0 : work reg
+ */
+#define FTOFIX32(a, t) \
+ mtc1 a, ft1 ; \
+ mul.s ft2, ft1, ft0 ; \
+ trunc.w.s ft3, ft2, t0 ; \
+ mfc1 t, ft3 ;
+
+/*
+ void guScale(Mtx *m, float x, float y, float z)
+ m: a0
+ x: a1
+ y: a2
+ z a3
+ */
+#define SIZE_OF_MTX 64 /* sizeof( Mtx ) */
+#define FLOAT_0x10000 6.5536e+04 /* (float)0x00010000) */
+
+ .text
+ .align 5
+LEAF( guScale )
+ .set reorder
+
+ li.s ft0, FLOAT_0x10000 /* (float)0x00010000 */
+
+ FTOFIX32(a1, t1) /* t1 = FTOFIX32(x) */
+ srl t2, t1, 16
+ sll t0, t2, 16
+ sw t0, 0(a0) /* t0 = x integral part */
+ sll t2, t1, 16
+ sw t2, 32(a0) /* t2 = x decimal part */
+
+ FTOFIX32(a2, t1) /* t1 = FTOFIX32(y) */
+ srl t0, t1, 16
+ sw t0, 8(a0) /* t0 = y integral part */
+ andi t2, t1, 0xffff
+ sw t2, 40(a0) /* t2 = y decimal part */
+
+ FTOFIX32(a3, t1) /* t1 = FTOFIX32(z) */
+ srl t2, t1, 16
+ sll t0, t2, 16
+ sw t0, 20(a0) /* t0 = z integral part */
+ sll t2, t1, 16
+ sw t2, 52(a0) /* t2 = z decimal part */
+
+ li t0, 1 /* t0 = 1.0 integral part */
+ sw t0, 28(a0)
+
+ sw zero, 4(a0)
+ sw zero, 12(a0)
+ sw zero, 16(a0)
+ sw zero, 24(a0)
+ sw zero, 36(a0)
+ sw zero, 44(a0)
+ sw zero, 48(a0)
+ sw zero, 56(a0)
+ sw zero, 60(a0)
+ j ra
+
+ END( guScale )
+/* end of file */
diff --git a/lib/ultralib/src/mgu/scalef.s b/lib/ultralib/src/mgu/scalef.s
new file mode 100644
index 0000000..b27d1e3
--- /dev/null
+++ b/lib/ultralib/src/mgu/scalef.s
@@ -0,0 +1,57 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:40 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guScaleF(float m[4][4], float x, float y, float z)
+ * m: a0
+ * x: a1
+ * y: a2
+ * z: a3
+ */
+ .text
+ .align 5
+LEAF( guScaleF )
+ .set reorder
+
+ sw a1, 0(a0)
+ sw zero, 4(a0) /* line 1 */
+ sw zero, 8(a0)
+ sw zero, 12(a0)
+
+ sw zero, 16(a0) /* line 2 */
+ sw a2, 20(a0)
+ sw zero, 24(a0)
+ sw zero, 28(a0)
+
+ sw zero, 32(a0) /* line 3 */
+ sw zero, 36(a0)
+ sw a3, 40(a0)
+ sw zero, 44(a0)
+
+ li t0, 0x3f800000 /* t0 = 1.0 */
+ sw zero, 48(a0) /* line 4 */
+ sw zero, 52(a0)
+ sw zero, 56(a0)
+ sw t0, 60(a0)
+
+ j ra
+
+ END( guScaleF )
+
+/* End of file */
diff --git a/lib/ultralib/src/mgu/translate.s b/lib/ultralib/src/mgu/translate.s
new file mode 100644
index 0000000..472fd8c
--- /dev/null
+++ b/lib/ultralib/src/mgu/translate.s
@@ -0,0 +1,101 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:40 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ void guTranslate(Mtx *m, float x, float y, float z)
+ m: a0
+ x: a1
+ y: a2
+ z a3
+ */
+
+#define SIZE_OF_MTX 64 /* sizeof( Mtx ) */
+#define FLOAT_0x10000 6.5536e+04 /* (float)0x00010000) */
+
+ .text
+ .align 5
+LEAF( guTranslate )
+ .set reorder
+
+ li.s ft0, FLOAT_0x10000 /* (float)0x00010000 */
+
+ mtc1 a1, ft1
+ mul.s ft2, ft1, ft0
+ trunc.w.s ft3, ft2
+ mfc1 t1, ft3 /* t1 = FTOFIX32(x) */
+
+ mtc1 a2, ft1
+ mul.s ft2, ft1, ft0
+ trunc.w.s ft3, ft2
+ mfc1 t3, ft3 /* t3 = FTOFIX32(y) */
+
+ /* Save t1 and t3 values until fraction process is finished! */
+
+ srl t2, t1, 16 /* x integeral part for t0 interger */
+ sll t0, t2, 16
+ srl t2, t3, 16 /* y integral part for t2 fraction */
+ or t0, t0, t2 /* Compose in t0 */
+ sw t0, 24(a0)
+
+ sll t0,t1,16 /* x fraction part for t0 interger */
+ sll t2,t3,16
+ srl t2,t2,16 /* y fraction part for t2 fraction */
+ or t0,t0,t2 /* Compose in t0 */
+ sw t0,24+32(a0)
+
+
+ mtc1 a3, ft1
+ mul.s ft2, ft1, ft0
+ trunc.w.s ft3, ft2
+ mfc1 t1, ft3 /* t1 = FTOFIX32(z) */
+
+ srl t2,t1,16
+ sll t0,t2,16 /* z integral part for t0 integer */
+ addiu t0,t0,1 /* enter 0x0001 in t0 fraction */
+ sw t0,28(a0)
+
+ sll t2,t1,16 /* z fraction part for t2 integer */
+ sw t2,28+32(a0)
+
+ sw zero, 0(a0)
+ sw zero, 4(a0)
+ sw zero, 8(a0)
+ sw zero, 12(a0)
+ sw zero, 16(a0)
+ sw zero, 20(a0)
+ sw zero, 0+32(a0)
+ sw zero, 4+32(a0)
+ sw zero, 8+32(a0)
+ sw zero, 12+32(a0)
+ sw zero, 16+32(a0)
+ sw zero, 20+32(a0)
+
+ lui t0,0x0001
+ ori t0,0x0000
+ sw t0,0(a0)
+ sw t0,20(a0)
+
+ lui t0,0x0000
+ ori t0,0x0001
+ sw t0,8(a0)
+
+ j ra
+
+ END( guTranslate )
+/* end of file */
diff --git a/lib/ultralib/src/mgu/translatef.s b/lib/ultralib/src/mgu/translatef.s
new file mode 100644
index 0000000..47d14bd
--- /dev/null
+++ b/lib/ultralib/src/mgu/translatef.s
@@ -0,0 +1,58 @@
+/************************************************************************
+ Copyright (C) 1998,1999 NINTENDO CO,Ltd,
+ Copyright (C) 1998,1999 MONEGI CORPORATION,
+ All Rights Reserved
+This program is a trade secret of NINTENDO CO,Ltd and MONEGI Corp.
+and it is not to be reproduced, published, disclosed to others, copied,
+adapted, distributed, or displayed without the prior authorization of
+NINTENDO CO,Ltd. and MONEGI Corp. Licensee agrees to attach or embed
+this Notice on all copies of the program, including partial copies or
+modified versions thereof.
+*************************************************************************/
+/************************************************************************
+ $Date: 1999/06/16 09:15:41 $
+ $Revision: 1.1 $
+ $Author: doseki $
+************************************************************************/
+#include <asm.h>
+#include <regdef.h>
+
+/*
+ * void guTranslateF(float m[4][4], float x, float y, float z)
+ * m: a0
+ * x: a1
+ * y: a2
+ * z: a3
+ */
+ .text
+ .align 5
+LEAF( guTranslateF )
+ .set reorder
+
+ li t0,0x3f800000 /* t0 = 1.0 */
+
+ sw t0, 0(a0)
+ sw zero, 4(a0) /* line 1 */
+ sw zero, 8(a0)
+ sw zero, 12(a0)
+
+ sw zero, 16(a0) /* line 2 */
+ sw t0, 20(a0)
+ sw zero, 24(a0)
+ sw zero, 28(a0)
+
+ sw zero, 32(a0) /* line 3 */
+ sw zero, 36(a0)
+ sw t0, 40(a0)
+ sw zero, 44(a0)
+
+ sw a1, 48(a0) /* line 4 */
+ sw a2, 52(a0)
+ sw a3, 56(a0)
+ sw t0, 60(a0)
+
+ j ra
+
+ END( guTranslateF )
+
+/* End of file */
diff --git a/lib/ultralib/src/os/ackramromread.c b/lib/ultralib/src/os/ackramromread.c
new file mode 100644
index 0000000..4aea863
--- /dev/null
+++ b/lib/ultralib/src/os/ackramromread.c
@@ -0,0 +1,8 @@
+#include "PR/os_internal.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+void osAckRamromRead() {
+
+}
diff --git a/lib/ultralib/src/os/ackramromwrite.c b/lib/ultralib/src/os/ackramromwrite.c
new file mode 100644
index 0000000..34fe2ad
--- /dev/null
+++ b/lib/ultralib/src/os/ackramromwrite.c
@@ -0,0 +1,8 @@
+#include "PR/os_internal.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+void osAckRamromWrite() {
+
+}
diff --git a/lib/ultralib/src/os/afterprenmi.c b/lib/ultralib/src/os/afterprenmi.c
new file mode 100644
index 0000000..03b5b24
--- /dev/null
+++ b/lib/ultralib/src/os/afterprenmi.c
@@ -0,0 +1,5 @@
+#include "PR/os_internal.h"
+
+s32 osAfterPreNMI() {
+ return __osSpSetPc(0);
+}
diff --git a/lib/ultralib/src/os/assert.c b/lib/ultralib/src/os/assert.c
new file mode 100644
index 0000000..d076a24
--- /dev/null
+++ b/lib/ultralib/src/os/assert.c
@@ -0,0 +1,5 @@
+#include "PR/os_internal.h"
+
+void __assert(const char *exp, const char *filename, int line) {
+ osSyncPrintf("\nASSERTION FAULT: %s, %d: \"%s\"\n", filename, line, exp);
+}
diff --git a/lib/ultralib/src/os/atomic.c b/lib/ultralib/src/os/atomic.c
new file mode 100644
index 0000000..f96bb63
--- /dev/null
+++ b/lib/ultralib/src/os/atomic.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+
+int __osAtomicDec(unsigned int *p) {
+ register u32 saveMask = __osDisableInt();
+ int mask;
+
+ if (*p) {
+ (*p)--;
+ mask = 1;
+ } else {
+ mask = 0;
+ }
+ __osRestoreInt(saveMask);
+ return mask;
+}
diff --git a/lib/ultralib/src/os/createmesgqueue.c b/lib/ultralib/src/os/createmesgqueue.c
new file mode 100644
index 0000000..4e71cba
--- /dev/null
+++ b/lib/ultralib/src/os/createmesgqueue.c
@@ -0,0 +1,11 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *msg, s32 msgCount) {
+ mq->mtqueue = &__osThreadTail.next;
+ mq->fullqueue = &__osThreadTail.next;
+ mq->validCount = 0;
+ mq->first = 0;
+ mq->msgCount = msgCount;
+ mq->msg = msg;
+}
diff --git a/lib/ultralib/src/os/createthread.c b/lib/ultralib/src/os/createthread.c
new file mode 100644
index 0000000..1ae9f0b
--- /dev/null
+++ b/lib/ultralib/src/os/createthread.c
@@ -0,0 +1,27 @@
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+#include "osint.h"
+
+void osCreateThread(OSThread *t, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri p) {
+ register u32 saveMask;
+ OSIntMask mask;
+ t->id = id;
+ t->priority = p;
+ t->next = NULL;
+ t->queue = NULL;
+ t->context.pc = (u32)entry;
+ t->context.a0 = (s64)(s32)arg; // Double cast gets rid of compiler warning
+ t->context.sp = (s64)(s32)sp - 16;
+ t->context.ra = (u64)__osCleanupThread;
+ mask = OS_IM_ALL;
+ t->context.sr = SR_IMASK | SR_EXL | SR_IE;
+ t->context.rcp = (mask & RCP_IMASK) >> RCP_IMASKSHIFT;
+ t->context.fpcsr = (u32)(FPCSR_FS | FPCSR_EV);
+ t->fp = 0;
+ t->state = OS_STATE_STOPPED;
+ t->flags = 0;
+ saveMask = __osDisableInt();
+ t->tlnext = __osActiveQueue;
+ __osActiveQueue = t;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/destroythread.c b/lib/ultralib/src/os/destroythread.c
new file mode 100644
index 0000000..43d2436
--- /dev/null
+++ b/lib/ultralib/src/os/destroythread.c
@@ -0,0 +1,37 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osDestroyThread(OSThread *t) {
+ register u32 saveMask;
+ register OSThread *pred;
+ register OSThread *succ;
+
+ saveMask = __osDisableInt();
+
+ if (t == NULL) {
+ t = __osRunningThread;
+ } else if (t->state != OS_STATE_STOPPED) {
+ __osDequeueThread(t->queue, t);
+ }
+
+ if (__osActiveQueue == t) {
+ __osActiveQueue = __osActiveQueue->tlnext;
+ } else {
+ pred = __osActiveQueue;
+ while (pred->priority != -1) {
+ succ = pred->tlnext;
+ if (succ == t) {
+ pred->tlnext = t->tlnext;
+ break;
+ }
+ pred = succ;
+ succ = pred->tlnext;
+ }
+ }
+
+ if (t == __osRunningThread) {
+ __osDispatchThread();
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/exceptasm.h b/lib/ultralib/src/os/exceptasm.h
new file mode 100644
index 0000000..48c1234
--- /dev/null
+++ b/lib/ultralib/src/os/exceptasm.h
@@ -0,0 +1,23 @@
+#ifndef _EXCEPTASM_H
+#define _EXCEPTASM_H
+
+#define MESG(type) (type << 3)
+
+#define MQ_MTQUEUE 0
+#define MQ_FULLQUEUE 4
+#define MQ_VALIDCOUNT 8
+#define MQ_FIRST 12
+#define MQ_MSGCOUNT 16
+#define MQ_MSG 20
+
+#define OS_EVENTSTATE_MESSAGE_QUEUE 0
+#define OS_EVENTSTATE_MESSAGE 4
+
+// __osHwInt struct member offsets
+#define HWINTR_CALLBACK 0x00
+#define HWINTR_SP 0x04
+
+// __osHwInt struct size
+#define HWINTR_SIZE 0x8
+
+#endif
diff --git a/lib/ultralib/src/os/exceptasm.s b/lib/ultralib/src/os/exceptasm.s
new file mode 100644
index 0000000..5a0bdcf
--- /dev/null
+++ b/lib/ultralib/src/os/exceptasm.s
@@ -0,0 +1,1019 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "PR/rdb.h"
+#include "exceptasm.h"
+#include "threadasm.h"
+
+#define KMC_CODE_ENTRY 0xBFF00014
+#define KMC_WPORT 0xBFF08000
+#define KMC_STAT 0xBFF08004
+
+.rdata
+
+#define REDISPATCH 0x00
+#define SW1 0x04
+#define SW2 0x08
+#define RCP 0x0c
+#define CART 0x10
+#define PRENMI 0x14
+#define IP6_HDLR 0x18
+#define IP7_HDLR 0x1c
+#define COUNTER 0x20
+
+__osIntOffTable:
+ .byte REDISPATCH
+ .byte PRENMI
+ .byte IP6_HDLR
+ .byte IP6_HDLR
+ .byte IP7_HDLR
+ .byte IP7_HDLR
+ .byte IP7_HDLR
+ .byte IP7_HDLR
+ .byte COUNTER
+ .byte COUNTER
+ .byte COUNTER
+ .byte COUNTER
+ .byte COUNTER
+ .byte COUNTER
+ .byte COUNTER
+ .byte COUNTER
+ .byte REDISPATCH
+ .byte SW1
+ .byte SW2
+ .byte SW2
+ .byte RCP
+ .byte RCP
+ .byte RCP
+ .byte RCP
+ .byte CART
+ .byte CART
+ .byte CART
+ .byte CART
+ .byte CART
+ .byte CART
+ .byte CART
+ .byte CART
+
+__osIntTable:
+ .word redispatch, sw1, sw2, rcp, cart, prenmi, IP6_Hdlr, IP7_Hdlr, counter
+
+#ifndef _FINALROM
+EXPORT(__osCauseTable_pt)
+ .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0
+ .byte 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
+ .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+#endif
+
+.data
+
+EXPORT(__osHwIntTable)
+ .word 0, 0
+ .word 0, 0
+ .word 0, 0
+ .word 0, 0
+ .word 0, 0
+
+EXPORT(__osPiIntTable)
+ .word 0, 0
+
+#ifndef _FINALROM
+__osRdb_DbgRead_Ct:
+ .word 0
+
+__osRdb_Mesg:
+ .word 0
+
+__os_Kdebug_Pkt:
+ .word 0
+
+__osPreviousThread:
+ .word 0
+#endif
+
+.text
+
+LEAF(__osExceptionPreamble)
+ la k0, __osException
+ jr k0
+END(__osExceptionPreamble)
+
+#ifndef _FINALROM
+LEAF(__ptExceptionPreamble)
+.set noreorder
+ sw k0, -0x10(sp)
+ b pt_next
+ lui k0, %hi(__ptException)
+ nop
+ nop
+pt_next:
+ addiu k0, %lo(__ptException)
+ jr k0
+ nop
+.set reorder
+END(__ptExceptionPreamble)
+
+LEAF(__ptException)
+.set noreorder
+ mfc0 k0, C0_CAUSE
+ andi k0, k0, 0x7c
+ bnez k0, pt_not_Int
+ srl k0, k0, 2
+ mfc0 k0, C0_CAUSE
+ nop
+ andi k0, k0, CAUSE_IP7
+ beqz k0, __osException
+ nop
+ j pt_break
+ nop
+pt_not_Int:
+ sw k1, -8(sp)
+ /* determine if the pt exception handler should deal with this cause */
+ la k1, __osCauseTable_pt
+ add k1, k1, k0
+ lbu k0, (k1)
+ beqz k0, __osException
+ nop
+pt_break:
+pi_ok_loop:
+ lw k0, PHYS_TO_K1(PI_STATUS_REG)
+ nop
+ andi k0, k0, (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)
+ bnez k0, pi_ok_loop
+ nop
+ lw k0, KMC_STAT
+ nop
+ andi k0, k0, 8
+ bnez k0, pt_prof
+ li k0, KMC_CODE_ENTRY
+ lw k1, -8(sp)
+ jr k0
+ addiu sp, sp, -0x60
+pt_prof:
+ mfc0 k0, C0_EPC
+ /* the following two ways is a (necessarily) messy way to write "sw k0, KMC_WPORT" without using at */
+ lui k1, (KMC_WPORT >> 16 + 1)
+ sw k0, -(KMC_WPORT & 0xFFFF)(k1)
+ lw k1, -8(sp)
+ lw k0, -0x10(sp)
+ eret
+ nop
+.set reorder
+END(__ptException)
+#endif
+
+LEAF(__osException)
+ la k0, __osThreadSave
+ /* save AT */
+.set noat
+ sd $1, THREAD_GP1(k0);
+.set at
+ /* save sr */
+STAY2(mfc0 k1, C0_SR)
+ sw k1, THREAD_SR(k0)
+ /* clear interrupts */
+ and k1, k1, -4
+STAY2(mtc0 k1, C0_SR)
+ /* save other regs */
+ sd $8, THREAD_GP8(k0)
+ sd $9, THREAD_GP9(k0)
+ sd $10, THREAD_GP10(k0)
+ /* say fp has not been used */
+ sw zero, THREAD_FP(k0)
+ /* this instruction is useless, leftover because of bad placement of an ifdef for the debug version */
+STAY2(mfc0 t0, C0_CAUSE)
+#ifndef _FINALROM
+ lw t2, __kmc_pt_mode
+ bnez t2, skip_kmc_mode
+ andi t1, t0, 0x7c
+ li t2, 0
+ bne t1, t2, savecontext
+ and t1, k1, t0
+ andi t2, t1, CAUSE_IP7
+ beqz t2, notIP7
+ /* clear rdb write interrupt */
+ li t1, RDB_WRITE_INTR_REG
+ sw zero, (t1)
+IP7check:
+STAY2(mfc0 t0, C0_CAUSE)
+ andi t0, t0, CAUSE_IP7
+ bne zero, t0, IP7check
+ lui t2, (RDB_BASE_REG >> 16)
+ lw t0, (RDB_BASE_REG & 0xFFFF)(t2)
+ srl t1, t0, 0x1a
+ andi t1, t1, 0x3f
+ li t2, RDB_TYPE_HtoG_DATA
+ beq t1, t2, HandData
+ li t2, RDB_TYPE_HtoG_DEBUG
+ beq t1, t2, HandDbg
+ li t2, RDB_TYPE_HtoG_KDEBUG
+ beq t1, t2, HandKDebug
+ li t2, RDB_TYPE_HtoG_DEBUG_CT
+ beq t1, t2, DbgCnt
+ li t2, RDB_TYPE_HtoG_DATA_DONE
+ beq t1, t2, DataRead
+ li t2, RDB_TYPE_HtoG_LOG_DONE
+ beq t1, t2, LogRead
+ li t2, RDB_TYPE_HtoG_REQ_RAMROM
+ beq t1, t2, ReqRamrom
+ li t2, RDB_TYPE_HtoG_FREE_RAMROM
+ beq t1, t2, FreeRamrom
+ li t2, RDB_TYPE_HtoG_PROF_SIGNAL
+ beq t1, t2, SignalProf
+ b rdbout
+SignalProf:
+ li t2, 1
+ srl t1, t0, 0x10
+ andi t1, t1, 0xff
+ beq t1, t2, AckProf
+ li t2, 0xa8
+ sw t2, __osRdb_Mesg
+ b savecontext
+AckProf:
+ li t2, 0xb0
+ sw t2, __osRdb_Mesg
+ b savecontext
+HandKDebug:
+ sw t0, __os_Kdebug_Pkt
+ b savecontext
+DbgCnt:
+ li t2, 0xffffff
+ and t1, t0, t2
+ sw t1, __osRdb_DbgRead_Ct
+ b rdbout
+DataRead:
+ li t2, 0x88
+ sw t2, __osRdb_Mesg
+ b savecontext
+LogRead:
+ li t2, 0x80
+ sw t2, __osRdb_Mesg
+ b savecontext
+ReqRamrom:
+ li t2, 0x90
+ sw t2, __osRdb_Mesg
+ b savecontext
+FreeRamrom:
+ li t2, 0x98
+ sw t2, __osRdb_Mesg
+ b savecontext
+HandData:
+ srl t1, t0, 0x18
+ andi t1, t1, 3
+ beq zero, t1, rdbout
+ lw t2, __osRdb_Read_Data_Ct
+ subu t2, t2, t1
+ sw t2, __osRdb_Read_Data_Ct
+ sd t3, THREAD_GP11(k0)
+ lw t3, __osRdb_Read_Data_Buf
+ srl t2, t0, 0x10
+ andi t2, t2, 0xff
+ sb t2, (t3)
+ addi t3, t3, 1
+ addi t1, t1, -1
+ beq zero, t1, doneData
+ srl t2, t0, 8
+ andi t2, t2, 0xff
+ sb t2, (t3)
+ addi t3, t3, 1
+ addi t1, t1, -1
+ beq zero, t1, doneData
+ andi t0, t0, 0xff
+ sb t0, (t3)
+ addi t3, t3, 1
+doneData:
+ sw t3, __osRdb_Read_Data_Buf
+ ld t3, THREAD_GP11(k0)
+ lw t2, __osRdb_Read_Data_Ct
+ bne zero, t2, rdbout
+ li t2, 0x78
+ sw t2, __osRdb_Mesg
+ b savecontext
+HandDbg:
+ srl t1, t0, 0x18
+ andi t1, t1, 3
+ beq zero, t1, rdbout
+ lw t2, __osRdb_DbgRead_Ct
+ subu t2, t2, t1
+ sw t2, __osRdb_DbgRead_Ct
+ sd t3, THREAD_GP11(k0)
+ lw t3, __osRdb_DbgRead_Buf
+ bne zero, t3, 1f
+ ld t3, THREAD_GP11(k0)
+ b rdbout
+1:
+ srl t2, t0, 0x10
+ andi t2, t2, 0xff
+ sb t2, (t3)
+ addi t3, t3, 1
+ addi t1, t1, -1
+ beq zero, t1, doneDbg
+ srl t2, t0, 8
+ andi t2, t2, 0xff
+ sb t2, (t3)
+ addi t3, t3, 1
+ addi t1, t1, -1
+ beq zero, t1, doneDbg
+ andi t0, t0, 0xff
+ sb t0, (t3)
+ addi t3, t3, 1
+doneDbg:
+ sw t3, __osRdb_DbgRead_Buf
+ ld t3, THREAD_GP11(k0)
+ lw t2, __osRdb_DbgRead_Ct
+ bne zero, t2, rdbout
+ li t2, 0xa0
+ sw t2, __osRdb_Mesg
+ b savecontext
+notIP7:
+ andi t2, t1, CAUSE_IP6
+ beqz t2, savecontext
+ /* clear rdb read interrupt */
+ li t1, RDB_READ_INTR_REG
+ sw zero, (t1)
+ lw t2, __osRdb_IP6_Ct
+ bnez t2, 1f
+ li t2, 1
+ sw t2, __osRdb_IP6_Empty
+ b rdbout
+1:
+ addi t2, t2, -1
+ sw t2, __osRdb_IP6_Ct
+ lw t0, __osRdb_IP6_Data
+ lw t1, __osRdb_IP6_CurSend
+ sll t2, t1, 2
+ add t0, t2, t0
+ lw t2, (t0)
+ addi t1, t1, 1
+ lw t0, __osRdb_IP6_Size
+ sub t0, t0, t1
+ bgtz t0, 5f
+ li t1, 0
+5:
+ sw t1, __osRdb_IP6_CurSend
+checkIP6:
+STAY2(mfc0 t0, C0_CAUSE)
+ andi t0, t0, CAUSE_IP6
+ bne zero, t0, checkIP6
+ lui t0, (RDB_BASE_REG >> 16)
+ sw t2, (RDB_BASE_REG & 0xFFFF)(t0)
+rdbout:
+ ld t0, THREAD_GP8(k0)
+ ld t1, THREAD_GP9(k0)
+ ld t2, THREAD_GP10(k0)
+.set noat
+ ld $1, THREAD_GP1(k0)
+.set at
+ lw k1, THREAD_SR(k0)
+STAY2(mtc0 k1, C0_SR)
+ nop
+ nop
+ nop
+ nop
+ eret
+
+skip_kmc_mode:
+#endif
+
+savecontext:
+ move t0, k0
+ lw k0, __osRunningThread
+#ifndef _FINALROM
+ sw k0, __osPreviousThread
+#endif
+ ld t1, THREAD_GP1(t0)
+ sd t1, THREAD_GP1(k0)
+ ld t1, THREAD_SR(t0)
+ sd t1, THREAD_SR(k0)
+ ld t1, THREAD_GP8(t0)
+ sd t1, THREAD_GP8(k0)
+ ld t1, THREAD_GP9(t0)
+ sd t1, THREAD_GP9(k0)
+ ld t1, THREAD_GP10(t0)
+ sd t1, THREAD_GP10(k0)
+ sd $2, THREAD_GP2(k0)
+ sd $3, THREAD_GP3(k0)
+ sd $4, THREAD_GP4(k0)
+ sd $5, THREAD_GP5(k0)
+ sd $6, THREAD_GP6(k0)
+ sd $7, THREAD_GP7(k0)
+ sd $11, THREAD_GP11(k0)
+ sd $12, THREAD_GP12(k0)
+ sd $13, THREAD_GP13(k0)
+ sd $14, THREAD_GP14(k0)
+ sd $15, THREAD_GP15(k0)
+ sd $16, THREAD_GP16(k0)
+ sd $17, THREAD_GP17(k0)
+ sd $18, THREAD_GP18(k0)
+ sd $19, THREAD_GP19(k0)
+ sd $20, THREAD_GP20(k0)
+ sd $21, THREAD_GP21(k0)
+ sd $22, THREAD_GP22(k0)
+ sd $23, THREAD_GP23(k0)
+ sd $24, THREAD_GP24(k0)
+ sd $25, THREAD_GP25(k0)
+ sd $28, THREAD_GP28(k0)
+ sd $29, THREAD_GP29(k0)
+ sd $30, THREAD_GP30(k0)
+ sd $31, THREAD_GP31(k0)
+
+ mflo t0
+ sd t0, THREAD_LO(k0)
+ mfhi t0
+ sd t0, THREAD_HI(k0)
+
+ lw k1, THREAD_SR(k0)
+ andi t1, k1, SR_IMASK
+ beqz t1, savercp
+
+/*if any interrupts are enabled*/
+ la t0, __OSGlobalIntMask
+ lw t0, 0(t0)
+ xor t2, t0, ~0 /* not except not using not */
+ andi t2, t2, SR_IMASK
+ or ta0, t1, t2
+ and t3, k1, ~SR_IMASK
+ or t3, t3, ta0
+ sw t3, THREAD_SR(k0)
+ andi t0, t0, SR_IMASK
+ and t1, t1, t0
+ and k1, k1, ~SR_IMASK
+ or k1, k1, t1
+savercp:
+
+ lw t1, PHYS_TO_K1(MI_INTR_MASK_REG)
+ beqz t1, endrcp
+
+ la t0, __OSGlobalIntMask
+ lw t0, 0(t0)
+
+ srl t0, t0, 0x10
+ xor t0, t0, ~0
+ andi t0, t0, 0x3f
+ lw ta0, THREAD_RCP(k0)
+ and t0, t0, ta0
+ or t1, t1, t0
+endrcp:
+ sw t1, THREAD_RCP(k0)
+STAY2(mfc0 t0, C0_EPC)
+ sw t0, THREAD_PC(k0)
+ lw t0, THREAD_FP(k0)
+ beqz t0, 1f
+ cfc1 t0, fcr31
+ nop
+ sw t0, THREAD_FPCSR(k0)
+ sdc1 $f0, THREAD_FP0(k0)
+ sdc1 $f2, THREAD_FP2(k0)
+ sdc1 $f4, THREAD_FP4(k0)
+ sdc1 $f6, THREAD_FP6(k0)
+ sdc1 $f8, THREAD_FP8(k0)
+ sdc1 $f10, THREAD_FP10(k0)
+ sdc1 $f12, THREAD_FP12(k0)
+ sdc1 $f14, THREAD_FP14(k0)
+ sdc1 $f16, THREAD_FP16(k0)
+ sdc1 $f18, THREAD_FP18(k0)
+ sdc1 $f20, THREAD_FP20(k0)
+ sdc1 $f22, THREAD_FP22(k0)
+ sdc1 $f24, THREAD_FP24(k0)
+ sdc1 $f26, THREAD_FP26(k0)
+ sdc1 $f28, THREAD_FP28(k0)
+ sdc1 $f30, THREAD_FP30(k0)
+1:
+STAY2(mfc0 t0, C0_CAUSE)
+ sw t0, THREAD_CAUSE(k0)
+
+ li t1, OS_STATE_RUNNABLE
+ sh t1, THREAD_STATE(k0)
+
+#ifndef _FINALROM
+ lw a0, __os_Kdebug_Pkt
+ beqz a0, no_kdebug
+ sw zero, __os_Kdebug_Pkt
+ jal kdebugserver
+ b __osDispatchThreadSave
+no_kdebug:
+ lw a0, __osRdb_Mesg
+ beqz a0, no_rdb_mesg
+ sw zero, __osRdb_Mesg
+ jal send_mesg
+ lw t0, 0x120(k0)
+no_rdb_mesg:
+#endif
+
+ andi t1, t0, CAUSE_EXCMASK
+ li t2, EXC_BREAK
+ beq t1, t2, handle_break
+
+ li t2, EXC_CPU
+ beq t1, t2, handle_CpU
+
+ li t2, EXC_INT
+ bne t1, t2, panic
+handle_interrupt:
+ and s0, k1, t0
+next_interrupt:
+ andi t1, s0, SR_IMASK
+ srl t2, t1, 0xc
+ bnez t2, 1f
+
+ srl t2, t1, SR_IMASKSHIFT
+ addi t2, t2, 16
+1:
+
+ lbu t2, __osIntOffTable(t2)
+
+ lw t2, __osIntTable(t2)
+ jr t2
+
+IP6_Hdlr:
+ and s0, s0, ~CAUSE_IP6
+ b next_interrupt
+
+IP7_Hdlr:
+ and s0, s0, ~CAUSE_IP7
+ b next_interrupt
+
+counter:
+STAY2(mfc0 t1, C0_COMPARE)
+STAY2(mtc0 t1, C0_COMPARE)
+ li a0, MESG(OS_EVENT_COUNTER)
+ jal send_mesg
+ and s0, s0, ~CAUSE_IP8
+ b next_interrupt
+
+cart:
+ and s0, s0, ~CAUSE_IP4
+ la t1, __osHwIntTable
+ add t1, HWINTR_SIZE
+ lw t2, HWINTR_CALLBACK(t1)
+
+ beqz t2, 1f
+
+ lw sp, HWINTR_SP(t1)
+ jalr t2
+
+ beqz v0, 1f
+ b redispatch
+
+1:
+ li a0, MESG(OS_EVENT_CART)
+ jal send_mesg
+ b next_interrupt
+
+rcp:
+ lw s1, PHYS_TO_K1(MI_INTR_REG)
+ la t0, __OSGlobalIntMask
+ lw t0, (t0)
+
+ srl t0, t0, 0x10
+ and s1, s1, t0
+ andi t1, s1, MI_INTR_SP
+ beqz t1, vi
+
+ andi s1, s1, 0x3e
+ lw ta0, PHYS_TO_K1(SP_STATUS_REG)
+ li t1, (SP_CLR_INTR | SP_CLR_SIG3)
+
+ sw t1, PHYS_TO_K1(SP_STATUS_REG)
+ andi ta0, ta0, 0x300
+ beqz ta0, sp_other_break
+
+ li a0, MESG(OS_EVENT_SP)
+ jal send_mesg
+
+ beqz s1, NoMoreRcpInts
+
+ b vi
+
+sp_other_break:
+ li a0, MESG(OS_EVENT_SP_BREAK)
+ jal send_mesg
+
+ beqz s1, NoMoreRcpInts
+
+vi:
+ andi t1, s1, 0x8
+ beqz t1, ai
+
+ andi s1, s1, 0x37
+
+ sw zero, PHYS_TO_K1(VI_CURRENT_REG)
+ li a0, MESG(OS_EVENT_VI)
+ jal send_mesg
+ beqz s1, NoMoreRcpInts
+
+ai:
+ andi t1, s1, 0x4
+ beqz t1, si
+
+ andi s1, s1, 0x3b
+
+ li t1, 1
+ sw t1, PHYS_TO_K1(AI_STATUS_REG)
+
+ li a0, MESG(OS_EVENT_AI)
+ jal send_mesg
+ beqz s1, NoMoreRcpInts
+
+si:
+ andi t1, s1, 0x2
+ beqz t1, pi
+
+ andi s1, s1, 0x3d
+ /* any write clears interrupts */
+ sw zero, PHYS_TO_K1(SI_STATUS_REG)
+ li a0, MESG(OS_EVENT_SI)
+ jal send_mesg
+ beqz s1, NoMoreRcpInts
+
+pi:
+ andi t1, s1, 0x10
+ beqz t1, dp
+
+ andi s1, s1, 0x2f
+
+ li t1, PI_STATUS_CLR_INTR
+ sw t1, PHYS_TO_K1(PI_STATUS_REG)
+
+ la t1, __osPiIntTable
+ lw t2, (t1)
+ beqz t2, 1f
+
+ lw sp, 4(t1)
+ move a0, v0
+ jalr t2
+
+ bnez v0, 2f
+1:
+ li a0, MESG(OS_EVENT_PI)
+ jal send_mesg
+2:
+ beqz s1, NoMoreRcpInts
+
+dp:
+ andi t1, s1, 0x20
+ beqz t1, NoMoreRcpInts
+
+ andi s1, s1, 0x1f
+
+ li t1, MI_CLR_DP_INTR
+ sw t1, PHYS_TO_K1(MI_INIT_MODE_REG)
+
+ li a0, MESG(OS_EVENT_DP)
+ jal send_mesg
+
+NoMoreRcpInts:
+ and s0, s0, ~CAUSE_IP3
+ b next_interrupt
+
+prenmi:
+ lw k1, THREAD_SR(k0)
+
+ and k1, k1, ~CAUSE_IP5
+ sw k1, THREAD_SR(k0)
+ la t1, __osShutdown
+ lw t2, 0(t1)
+ beqz t2, firstnmi
+
+ and s0, s0, ~CAUSE_IP5
+ b redispatch
+
+firstnmi:
+ li t2, 1
+ sw t2, 0(t1) /* __osShutdown */
+ li a0, MESG(OS_EVENT_PRENMI)
+ jal send_mesg
+
+ and s0, s0, ~CAUSE_IP5
+ lw t2, __osRunQueue
+ lw k1, THREAD_SR(t2)
+ and k1, k1, ~CAUSE_IP5
+ sw k1, THREAD_SR(t2)
+ b redispatch
+
+sw2:
+ and t0, t0, ~CAUSE_SW2
+STAY2(mtc0 t0, C0_CAUSE)
+
+ li a0, MESG(OS_EVENT_SW2)
+ jal send_mesg
+
+ and s0, s0, ~CAUSE_SW2
+ b next_interrupt
+
+sw1:
+ and t0, t0, ~CAUSE_SW1
+STAY2(mtc0 t0, C0_CAUSE)
+
+ li a0, MESG(OS_EVENT_SW1)
+ jal send_mesg
+
+ and s0, s0, ~CAUSE_SW1
+ b next_interrupt
+
+handle_break:
+ li t1, OS_FLAG_CPU_BREAK
+ sh t1, THREAD_FLAGS(k0)
+ li a0, MESG(OS_EVENT_CPU_BREAK)
+ jal send_mesg
+ b redispatch
+
+redispatch:
+ lw t1, THREAD_PRI(k0)
+ lw t2, __osRunQueue
+ lw t3, THREAD_PRI(t2)
+
+ bge t1, t3, enqueueRunning
+
+ move a1, k0
+ la a0, __osRunQueue
+
+ jal __osEnqueueThread
+
+ j __osDispatchThread
+
+enqueueRunning:
+ la t1, __osRunQueue
+ lw t2, MQ_MTQUEUE(t1)
+ sw t2, THREAD_NEXT(k0)
+ sw k0, MQ_MTQUEUE(t1)
+ j __osDispatchThread
+panic:
+ sw k0, __osFaultedThread
+ li t1, OS_STATE_STOPPED
+ sh t1, THREAD_STATE(k0)
+ li t1, OS_FLAG_FAULT
+ sh t1, THREAD_FLAGS(k0)
+
+STAY2(mfc0 t2, C0_BADVADDR)
+
+ sw t2, THREAD_BADVADDR(k0)
+
+ li a0, MESG(OS_EVENT_FAULT)
+ jal send_mesg
+ j __osDispatchThread
+END(__osException)
+
+LEAF(send_mesg)
+ move s2, ra
+ la t2, __osEventStateTab
+ addu t2, t2, a0
+ lw t1, OS_EVENTSTATE_MESSAGE_QUEUE(t2)
+ beqz t1, send_done
+
+ lw t3, MQ_VALIDCOUNT(t1)
+ lw ta0, MQ_MSGCOUNT(t1)
+
+ bge t3, ta0, send_done
+
+ lw ta1, MQ_FIRST(t1)
+ addu ta1, ta1, t3
+
+ rem ta1, ta1, ta0
+ lw ta0, MQ_MSG(t1)
+ mul ta1, ta1, 4
+ addu ta0, ta0, ta1
+ lw ta1, OS_EVENTSTATE_MESSAGE(t2)
+ sw ta1, 0(ta0) /* msg[ta1] = */
+ addiu t2, t3, 1
+ sw t2, MQ_VALIDCOUNT(t1)
+ lw t2, MQ_MTQUEUE(t1)
+ lw t3, THREAD_NEXT(t2)
+ beqz t3, send_done
+
+ move a0, t1
+ jal __osPopThread
+
+ move t2, v0
+
+ move a1, t2
+ la a0, __osRunQueue
+ jal __osEnqueueThread
+send_done:
+ jr s2
+END(send_mesg)
+
+LEAF(handle_CpU) /* coprocessor error */
+ and t1, t0, CAUSE_CEMASK
+ srl t1, t1, CAUSE_CESHIFT
+ li t2, 1 /* cp1 error */
+ bne t1, t2, panic
+
+ /* enable cp1 (fpu) for this thread */
+ li t1, 1
+ sw t1, THREAD_FP(k0)
+ lw k1, THREAD_SR(k0)
+ or k1, k1, SR_CU1
+ sw k1, THREAD_SR(k0)
+ b enqueueRunning
+END(handle_CpU)
+
+LEAF(__osEnqueueAndYield)
+ lw a1, __osRunningThread
+#ifndef _FINALROM
+ sw a1, __osPreviousThread
+#endif
+STAY2(mfc0 t0, C0_SR)
+ ori t0, t0, SR_EXL
+ sw t0, THREAD_SR(a1)
+ sd s0, THREAD_GP16(a1)
+ sd s1, THREAD_GP17(a1)
+ sd s2, THREAD_GP18(a1)
+ sd s3, THREAD_GP19(a1)
+ sd s4, THREAD_GP20(a1)
+ sd s5, THREAD_GP21(a1)
+ sd s6, THREAD_GP22(a1)
+ sd s7, THREAD_GP23(a1)
+ sd gp, THREAD_GP28(a1)
+ sd sp, THREAD_GP29(a1)
+ sd s8, THREAD_GP30(a1)
+ sd ra, THREAD_GP31(a1)
+ sw ra, THREAD_PC(a1)
+ lw k1, THREAD_FP(a1)
+ beqz k1, 1f
+ cfc1 k1, fcr31
+ sw k1, THREAD_FPCSR(a1)
+ sdc1 $f20, THREAD_FP20(a1)
+ sdc1 $f22, THREAD_FP22(a1)
+ sdc1 $f24, THREAD_FP24(a1)
+ sdc1 $f26, THREAD_FP26(a1)
+ sdc1 $f28, THREAD_FP28(a1)
+ sdc1 $f30, THREAD_FP30(a1)
+1:
+ lw k1, THREAD_SR(a1)
+ andi t1, k1, SR_IMASK
+ beqz t1, 2f
+
+ la t0, __OSGlobalIntMask
+ lw t0, 0(t0)
+ xor t0, t0, ~0
+ andi t0, t0, SR_IMASK
+ or t1, t1, t0
+ and k1, k1, ~SR_IMASK
+ or k1, k1, t1
+ sw k1, THREAD_SR(a1)
+2:
+ lw k1, PHYS_TO_K1(MI_INTR_MASK_REG)
+ beqz k1, 3f
+
+ la k0, __OSGlobalIntMask
+ lw k0, 0(k0)
+
+ srl k0, k0, 0x10
+ xor k0, k0, ~0
+ andi k0, k0, 0x3f
+ lw t0, THREAD_RCP(a1)
+ and k0, k0, t0
+ or k1, k1, k0
+3:
+ sw k1, THREAD_RCP(a1)
+ beqz a0, noEnqueue
+ jal __osEnqueueThread
+noEnqueue:
+ j __osDispatchThread
+END(__osEnqueueAndYield)
+
+/*__osEnqueueThread(OSThread **, OSThread *)*/
+LEAF(__osEnqueueThread)
+ move t9, a0
+ lw t8, 0(a0)
+ lw ta3, THREAD_PRI(a1)
+ lw ta2, THREAD_PRI(t8)
+ blt ta2, ta3, 1f
+2:
+ move t9, t8
+ lw t8, THREAD_NEXT(t8)
+ lw ta2, THREAD_PRI(t8)
+ bge ta2, ta3, 2b
+1:
+ lw t8, THREAD_NEXT(t9)
+ sw t8, THREAD_NEXT(a1)
+ sw a1, THREAD_NEXT(t9)
+ sw a0, THREAD_QUEUE(a1)
+ jr ra
+END(__osEnqueueThread)
+
+LEAF(__osPopThread)
+ lw v0, 0(a0) /* a0 is OSThread** */
+ lw t9, THREAD_NEXT(v0)
+ sw t9, 0(a0)
+ jr ra
+END(__osPopThread)
+
+LEAF(__osNop)
+ jr ra
+END(__osNop)
+
+LEAF(__osDispatchThread)
+ la a0, __osRunQueue
+ jal __osPopThread
+ sw v0, __osRunningThread
+ li t0, OS_STATE_RUNNING
+ sh t0, THREAD_STATE(v0)
+ move k0, v0
+
+#ifndef _FINALROM
+ la t0, __osThprofFunc
+ lw t0, (t0)
+ beqz t0, __osDispatchThreadSave
+ lw a0, __osPreviousThread
+ lw sp, __osThprofStack
+ jalr t0
+#endif
+
+__osDispatchThreadSave:
+ lw k1, THREAD_SR(k0)
+ la t0, __OSGlobalIntMask
+ lw t0, 0(t0)
+ andi t0, t0, SR_IMASK
+ andi t1, k1, SR_IMASK
+ and t1, t1, t0
+ and k1, k1, ~SR_IMASK
+ or k1, k1, t1
+STAY2(mtc0 k1, C0_SR)
+.set noat
+ ld $1, THREAD_GP1(k0)
+.set at
+ ld $2, THREAD_GP2(k0)
+ ld $3, THREAD_GP3(k0)
+ ld $4, THREAD_GP4(k0)
+ ld $5, THREAD_GP5(k0)
+ ld $6, THREAD_GP6(k0)
+ ld $7, THREAD_GP7(k0)
+ ld $8, THREAD_GP8(k0)
+ ld $9, THREAD_GP9(k0)
+ ld $10, THREAD_GP10(k0)
+ ld $11, THREAD_GP11(k0)
+ ld $12, THREAD_GP12(k0)
+ ld $13, THREAD_GP13(k0)
+ ld $14, THREAD_GP14(k0)
+ ld $15, THREAD_GP15(k0)
+ ld $16, THREAD_GP16(k0)
+ ld $17, THREAD_GP17(k0)
+ ld $18, THREAD_GP18(k0)
+ ld $19, THREAD_GP19(k0)
+ ld $20, THREAD_GP20(k0)
+ ld $21, THREAD_GP21(k0)
+ ld $22, THREAD_GP22(k0)
+ ld $23, THREAD_GP23(k0)
+ ld $24, THREAD_GP24(k0)
+ ld $25, THREAD_GP25(k0)
+ ld $28, THREAD_GP28(k0)
+ ld $29, THREAD_GP29(k0)
+ ld $30, THREAD_GP30(k0)
+ ld $31, THREAD_GP31(k0)
+ ld k1, THREAD_LO(k0)
+ mtlo k1
+ ld k1, THREAD_HI(k0)
+ mthi k1
+ lw k1, THREAD_PC(k0)
+STAY2(mtc0 k1, C0_EPC)
+ lw k1, THREAD_FP(k0)
+ beqz k1, 1f
+
+ lw k1, THREAD_FPCSR(k0)
+STAY2(ctc1 k1, fcr31)
+ ldc1 $f0, THREAD_FP0(k0)
+ ldc1 $f2, THREAD_FP2(k0)
+ ldc1 $f4, THREAD_FP4(k0)
+ ldc1 $f6, THREAD_FP6(k0)
+ ldc1 $f8, THREAD_FP8(k0)
+ ldc1 $f10, THREAD_FP10(k0)
+ ldc1 $f12, THREAD_FP12(k0)
+ ldc1 $f14, THREAD_FP14(k0)
+ ldc1 $f16, THREAD_FP16(k0)
+ ldc1 $f18, THREAD_FP18(k0)
+ ldc1 $f20, THREAD_FP20(k0)
+ ldc1 $f22, THREAD_FP22(k0)
+ ldc1 $f24, THREAD_FP24(k0)
+ ldc1 $f26, THREAD_FP26(k0)
+ ldc1 $f28, THREAD_FP28(k0)
+ ldc1 $f30, THREAD_FP30(k0)
+
+1:
+ lw k1, THREAD_RCP(k0)
+ la k0, __OSGlobalIntMask
+ lw k0, 0(k0)
+ srl k0, k0, 0x10
+ and k1, k1, k0
+ sll k1, k1, 0x1
+ la k0, __osRcpImTable
+ addu k1, k1, k0
+ lhu k1, 0(k1)
+ la k0, PHYS_TO_K1(MI_INTR_MASK_REG)
+ sw k1, 0(k0)
+
+ nop
+ nop
+ nop
+ nop
+ eret
+END(__osDispatchThread)
+
+LEAF(__osCleanupThread)
+ move a0, zero
+ nop
+ jal osDestroyThread
+END(__osCleanupThread)
diff --git a/lib/ultralib/src/os/exit.c b/lib/ultralib/src/os/exit.c
new file mode 100644
index 0000000..d5e60eb
--- /dev/null
+++ b/lib/ultralib/src/os/exit.c
@@ -0,0 +1,8 @@
+#include "PR/os_internal.h"
+
+void osExit() {
+ __osGIOInterrupt(16);
+
+ for (;;);
+}
+
diff --git a/lib/ultralib/src/os/getactivequeue.c b/lib/ultralib/src/os/getactivequeue.c
new file mode 100644
index 0000000..4175e7d
--- /dev/null
+++ b/lib/ultralib/src/os/getactivequeue.c
@@ -0,0 +1,6 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSThread *__osGetActiveQueue(void) {
+ return __osActiveQueue;
+}
diff --git a/lib/ultralib/src/os/getcause.s b/lib/ultralib/src/os/getcause.s
new file mode 100644
index 0000000..873464f
--- /dev/null
+++ b/lib/ultralib/src/os/getcause.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osGetCause)
+ STAY2(mfc0 v0, C0_CAUSE)
+ jr ra
+END(__osGetCause)
diff --git a/lib/ultralib/src/os/getcompare.s b/lib/ultralib/src/os/getcompare.s
new file mode 100644
index 0000000..99c1758
--- /dev/null
+++ b/lib/ultralib/src/os/getcompare.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osGetCompare)
+ STAY2(mfc0 v0, C0_COMPARE)
+ jr ra
+END(__osGetCompare)
diff --git a/lib/ultralib/src/os/getconfig.s b/lib/ultralib/src/os/getconfig.s
new file mode 100644
index 0000000..8165178
--- /dev/null
+++ b/lib/ultralib/src/os/getconfig.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osGetConfig)
+ STAY2(mfc0 v0, C0_CONFIG)
+ jr ra
+END(__osGetConfig)
diff --git a/lib/ultralib/src/os/getcount.s b/lib/ultralib/src/os/getcount.s
new file mode 100644
index 0000000..28d5a79
--- /dev/null
+++ b/lib/ultralib/src/os/getcount.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(osGetCount)
+ STAY2(mfc0 v0, C0_COUNT)
+ jr ra
+END(osGetCount)
diff --git a/lib/ultralib/src/os/getcurrfaultthread.c b/lib/ultralib/src/os/getcurrfaultthread.c
new file mode 100644
index 0000000..7500928
--- /dev/null
+++ b/lib/ultralib/src/os/getcurrfaultthread.c
@@ -0,0 +1,6 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSThread *__osGetCurrFaultedThread() {
+ return __osFaultedThread;
+}
diff --git a/lib/ultralib/src/os/getfpccsr.s b/lib/ultralib/src/os/getfpccsr.s
new file mode 100644
index 0000000..05bb19d
--- /dev/null
+++ b/lib/ultralib/src/os/getfpccsr.s
@@ -0,0 +1,10 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osGetFpcCsr)
+ STAY2(cfc1 v0, fcr31)
+ jr ra
+END(__osGetFpcCsr)
+.globl __osGetSR
diff --git a/lib/ultralib/src/os/gethwinterrupt.c b/lib/ultralib/src/os/gethwinterrupt.c
new file mode 100644
index 0000000..3a0e136
--- /dev/null
+++ b/lib/ultralib/src/os/gethwinterrupt.c
@@ -0,0 +1,13 @@
+#include "PR/os_internal.h"
+
+struct __osHwInt {
+ s32 (*handler)(void);
+ void *stackEnd;
+};
+
+extern struct __osHwInt __osHwIntTable[];
+
+void __osGetHWIntrRoutine(OSHWIntr interrupt, s32 (**handler)(void), void **stackEnd) {
+ *handler = __osHwIntTable[interrupt].handler;
+ *stackEnd = __osHwIntTable[interrupt].stackEnd;
+}
diff --git a/lib/ultralib/src/os/getintmask.s b/lib/ultralib/src/os/getintmask.s
new file mode 100644
index 0000000..deaccb6
--- /dev/null
+++ b/lib/ultralib/src/os/getintmask.s
@@ -0,0 +1,32 @@
+#include "PR/R4300.h"
+#include "PR/rcp.h"
+#include "PR/os.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(osGetIntMask)
+ mfc0 v0, C0_SR
+ andi v0, v0, OS_IM_CPU
+ la t0, __OSGlobalIntMask
+ lw t1, 0(t0)
+ xor t0, t1, -1
+ andi t0, t0, SR_IMASK
+ or v0, v0, t0
+
+ lw t1, PHYS_TO_K1(MI_INTR_MASK_REG)
+ beqz t1, 1f
+
+ la t0, __OSGlobalIntMask #this is intentionally a macro in the branch delay slot
+
+ lw t0, 0(t0)
+ srl t0, t0, 0x10
+ xor t0, t0, -1
+ andi t0, t0, 0x3f
+ or t1, t1, t0
+1:
+ sll t2, t1, 0x10
+ or v0, v0, t2
+ jr ra
+END(osGetIntMask)
diff --git a/lib/ultralib/src/os/getmemsize.c b/lib/ultralib/src/os/getmemsize.c
new file mode 100644
index 0000000..44fbc19
--- /dev/null
+++ b/lib/ultralib/src/os/getmemsize.c
@@ -0,0 +1,35 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "PR/R4300.h"
+
+#define STEP 0x100000
+#define SIZE_4MB 0x400000
+#define SIZE_8MB 0x800000
+
+u32 osGetMemSize(void) {
+ vu32* ptr;
+ u32 size = SIZE_4MB;
+ u32 data0;
+ u32 data1;
+
+ while (size < SIZE_8MB) {
+ ptr = (vu32*)(K1BASE + size);
+
+ data0 = *ptr;
+ data1 = ptr[STEP / 4 - 1];
+
+ *ptr ^= ~0;
+ ptr[STEP / 4 - 1] ^= ~0;
+
+ if ((*ptr != (data0 ^ ~0)) || (ptr[STEP / 4 - 1] != (data1 ^ ~0))) {
+ return size;
+ }
+
+ *ptr = data0;
+ ptr[STEP / 4 - 1] = data1;
+
+ size += STEP;
+ }
+
+ return size;
+}
diff --git a/lib/ultralib/src/os/getnextfaultthread.c b/lib/ultralib/src/os/getnextfaultthread.c
new file mode 100644
index 0000000..9add6dd
--- /dev/null
+++ b/lib/ultralib/src/os/getnextfaultthread.c
@@ -0,0 +1,28 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSThread *__osGetNextFaultedThread(OSThread *lastFault) {
+ register int saveMask = __osDisableInt();
+ register OSThread *fault;
+
+ if (lastFault == NULL) {
+ fault = __osActiveQueue;
+ } else {
+ fault = lastFault;
+ }
+
+ while (fault->priority != -1) {
+ if ((fault->flags & OS_FLAG_FAULT) != 0 && fault != lastFault) {
+ break;
+ }
+ fault = fault->tlnext;
+ }
+
+ if (fault->priority == -1) {
+ fault = NULL;
+ }
+
+ __osRestoreInt(saveMask);
+ return fault;
+}
+
diff --git a/lib/ultralib/src/os/getsr.s b/lib/ultralib/src/os/getsr.s
new file mode 100644
index 0000000..bc9c767
--- /dev/null
+++ b/lib/ultralib/src/os/getsr.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osGetSR)
+ STAY2(mfc0 v0, C0_SR)
+ jr ra
+END(__osGetSR)
diff --git a/lib/ultralib/src/os/getthreadid.c b/lib/ultralib/src/os/getthreadid.c
new file mode 100644
index 0000000..9aac16d
--- /dev/null
+++ b/lib/ultralib/src/os/getthreadid.c
@@ -0,0 +1,10 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSId osGetThreadId(OSThread *thread) {
+ if (thread == NULL) {
+ thread = __osRunningThread;
+ }
+
+ return thread->id;
+}
diff --git a/lib/ultralib/src/os/getthreadpri.c b/lib/ultralib/src/os/getthreadpri.c
new file mode 100644
index 0000000..a1e9ce2
--- /dev/null
+++ b/lib/ultralib/src/os/getthreadpri.c
@@ -0,0 +1,10 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSPri osGetThreadPri(OSThread *thread) {
+ if (thread == NULL) {
+ thread = __osRunningThread;
+ }
+
+ return thread->priority;
+}
diff --git a/lib/ultralib/src/os/gettime.c b/lib/ultralib/src/os/gettime.c
new file mode 100644
index 0000000..aee799a
--- /dev/null
+++ b/lib/ultralib/src/os/gettime.c
@@ -0,0 +1,15 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSTime osGetTime() {
+ u32 tmptime;
+ u32 elapseCount;
+ OSTime currentCount;
+ register u32 saveMask;
+ saveMask = __osDisableInt();
+ tmptime = osGetCount();
+ elapseCount = tmptime - __osBaseCounter;
+ currentCount = __osCurrentTime;
+ __osRestoreInt(saveMask);
+ return currentCount + elapseCount;
+}
diff --git a/lib/ultralib/src/os/gettlbasid.s b/lib/ultralib/src/os/gettlbasid.s
new file mode 100644
index 0000000..a0702ea
--- /dev/null
+++ b/lib/ultralib/src/os/gettlbasid.s
@@ -0,0 +1,11 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.set noreorder
+.text
+LEAF(__osGetTLBASID)
+ mfc0 v0, C0_ENTRYHI
+ jr ra
+ nop
+END(__osGetTLBASID)
diff --git a/lib/ultralib/src/os/gettlbhi.s b/lib/ultralib/src/os/gettlbhi.s
new file mode 100644
index 0000000..04c03e9
--- /dev/null
+++ b/lib/ultralib/src/os/gettlbhi.s
@@ -0,0 +1,17 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.set noreorder
+.text
+LEAF(__osGetTLBHi)
+ mtc0 a0, C0_INX
+ nop
+ tlbr
+ nop
+ nop
+ nop
+ mfc0 v0, C0_ENTRYHI
+ jr ra
+ nop
+END(__osGetTLBHi)
diff --git a/lib/ultralib/src/os/gettlblo0.s b/lib/ultralib/src/os/gettlblo0.s
new file mode 100644
index 0000000..3b2c2ec
--- /dev/null
+++ b/lib/ultralib/src/os/gettlblo0.s
@@ -0,0 +1,17 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.set noreorder
+.text
+LEAF(__osGetTLBLo0)
+ mtc0 a0, C0_INX
+ nop
+ tlbr
+ nop
+ nop
+ nop
+ mfc0 v0, C0_ENTRYLO0
+ jr ra
+ nop
+END(__osGetTLBLo0)
diff --git a/lib/ultralib/src/os/gettlblo1.s b/lib/ultralib/src/os/gettlblo1.s
new file mode 100644
index 0000000..a24baef
--- /dev/null
+++ b/lib/ultralib/src/os/gettlblo1.s
@@ -0,0 +1,17 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.set noreorder
+.text
+LEAF(__osGetTLBLo1)
+ mtc0 a0, C0_INX
+ nop
+ tlbr
+ nop
+ nop
+ nop
+ mfc0 v0, C0_ENTRYLO1
+ jr ra
+ nop
+END(__osGetTLBLo1)
diff --git a/lib/ultralib/src/os/gettlbpagemask.s b/lib/ultralib/src/os/gettlbpagemask.s
new file mode 100644
index 0000000..de9954a
--- /dev/null
+++ b/lib/ultralib/src/os/gettlbpagemask.s
@@ -0,0 +1,17 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.set noreorder
+.text
+LEAF(__osGetTLBPageMask)
+ mtc0 a0, C0_INX
+ nop
+ tlbr
+ nop
+ nop
+ nop
+ mfc0 v0, C0_PAGEMASK
+ jr ra
+ nop
+END(__osGetTLBPageMask)
diff --git a/lib/ultralib/src/os/getwatchlo.s b/lib/ultralib/src/os/getwatchlo.s
new file mode 100644
index 0000000..4eee9ee
--- /dev/null
+++ b/lib/ultralib/src/os/getwatchlo.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osGetWatchLo)
+ STAY2(mfc0 v0, C0_WATCHLO)
+ jr ra
+END(__osGetWatchLo)
diff --git a/lib/ultralib/src/os/initialize.c b/lib/ultralib/src/os/initialize.c
new file mode 100644
index 0000000..ecc001e
--- /dev/null
+++ b/lib/ultralib/src/os/initialize.c
@@ -0,0 +1,105 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+
+typedef struct
+{
+ /* 0x0 */ unsigned int inst1;
+ /* 0x4 */ unsigned int inst2;
+ /* 0x8 */ unsigned int inst3;
+ /* 0xC */ unsigned int inst4;
+} __osExceptionVector;
+extern __osExceptionVector __osExceptionPreamble;
+
+extern OSPiHandle __Dom1SpeedParam;
+extern OSPiHandle __Dom2SpeedParam;
+
+OSTime osClockRate = OS_CLOCK_RATE;
+s32 osViClock = VI_NTSC_CLOCK;
+u32 __osShutdown = 0;
+u32 __OSGlobalIntMask = OS_IM_ALL;
+#ifdef _FINALROM
+u32 __osFinalrom;
+#else
+void* __printfunc = NULL;
+u32 __kmc_pt_mode;
+#endif
+
+void __createSpeedParam(void) {
+ __Dom1SpeedParam.type = DEVICE_TYPE_INIT;
+ __Dom1SpeedParam.latency = IO_READ(PI_BSD_DOM1_LAT_REG);
+ __Dom1SpeedParam.pulse = IO_READ(PI_BSD_DOM1_PWD_REG);
+ __Dom1SpeedParam.pageSize = IO_READ(PI_BSD_DOM1_PGS_REG);
+ __Dom1SpeedParam.relDuration = IO_READ(PI_BSD_DOM1_RLS_REG);
+
+ __Dom2SpeedParam.type = DEVICE_TYPE_INIT;
+ __Dom2SpeedParam.latency = IO_READ(PI_BSD_DOM2_LAT_REG);
+ __Dom2SpeedParam.pulse = IO_READ(PI_BSD_DOM2_PWD_REG);
+ __Dom2SpeedParam.pageSize = IO_READ(PI_BSD_DOM2_PGS_REG);
+ __Dom2SpeedParam.relDuration = IO_READ(PI_BSD_DOM2_RLS_REG);
+}
+
+void __osInitialize_common() {
+ u32 pifdata;
+
+#ifdef _FINALROM
+ __osFinalrom = TRUE;
+#endif
+
+ __osSetSR(__osGetSR() | SR_CU1); //enable fpu
+ __osSetFpcCsr(FPCSR_FS | FPCSR_EV); //flush denorm to zero, enable invalid operation
+ __osSetWatchLo(0x4900000);
+
+ while (__osSiRawReadIo(PIF_RAM_END - 3, &pifdata)) { //last byte of joychannel ram
+ ;
+ }
+ while (__osSiRawWriteIo(PIF_RAM_END - 3, pifdata | 8)) {
+ ; //todo: magic contant
+ }
+ *(__osExceptionVector *)UT_VEC = __osExceptionPreamble;
+ *(__osExceptionVector *)XUT_VEC = __osExceptionPreamble;
+ *(__osExceptionVector *)ECC_VEC = __osExceptionPreamble;
+ *(__osExceptionVector *)E_VEC = __osExceptionPreamble;
+ osWritebackDCache((void *)UT_VEC, E_VEC - UT_VEC + sizeof(__osExceptionVector));
+ osInvalICache((void *)UT_VEC, E_VEC - UT_VEC + sizeof(__osExceptionVector));
+ __createSpeedParam();
+ osUnmapTLBAll();
+ osMapTLBRdb();
+ osClockRate = osClockRate * 3 / 4;
+
+ if (osResetType == 0 ) { // cold reset
+ bzero(osAppNMIBuffer, OS_APP_NMI_BUFSIZE);
+ }
+
+ if (osTvType == OS_TV_PAL) {
+ osViClock = VI_PAL_CLOCK;
+ } else if (osTvType == OS_TV_MPAL) {
+ osViClock = VI_MPAL_CLOCK;
+ } else {
+ osViClock = VI_NTSC_CLOCK;
+ }
+
+ // Wait until there are no RCP interrupts
+ if (__osGetCause() & CAUSE_IP5) {
+ while (TRUE) {
+ ;
+ }
+ }
+
+ IO_WRITE(AI_CONTROL_REG, AI_CONTROL_DMA_ON);
+ IO_WRITE(AI_DACRATE_REG, AI_MAX_DAC_RATE - 1);
+ IO_WRITE(AI_BITRATE_REG, AI_MAX_BIT_RATE - 1);
+}
+
+void __osInitialize_autodetect() {
+#ifndef _FINALROM
+ if (__checkHardware_msp()) {
+ __osInitialize_msp();
+ } else if (__checkHardware_kmc()) {
+ __osInitialize_kmc();
+ } else if (__checkHardware_isv()) {
+ __osInitialize_isv();
+ } else {
+ __osInitialize_emu();
+ }
+#endif
+}
diff --git a/lib/ultralib/src/os/initialize_emu.c b/lib/ultralib/src/os/initialize_emu.c
new file mode 100644
index 0000000..5b68da5
--- /dev/null
+++ b/lib/ultralib/src/os/initialize_emu.c
@@ -0,0 +1,28 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/rdb.h"
+#include "osint.h"
+
+typedef struct
+{
+ /* 0x0 */ unsigned int inst1;
+ /* 0x4 */ unsigned int inst2;
+ /* 0x8 */ unsigned int inst3;
+ /* 0xC */ unsigned int inst4;
+} __osExceptionVector;
+
+static void* proutSyncPrintf(void* str, const char* buf, size_t n) {
+ size_t sent = 0;
+
+ while (sent < n) {
+ sent += __osRdbSend(buf + sent, n - sent, RDB_TYPE_GtoH_PRINT);
+ }
+ return 1;
+}
+
+void __osInitialize_emu(void) {
+ __printfunc = proutSyncPrintf;
+}
+
+#endif
diff --git a/lib/ultralib/src/os/initialize_isv.c b/lib/ultralib/src/os/initialize_isv.c
new file mode 100644
index 0000000..cd64821
--- /dev/null
+++ b/lib/ultralib/src/os/initialize_isv.c
@@ -0,0 +1,176 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "osint.h"
+
+#include "macros.h"
+
+typedef struct
+{
+ /* 0x0 */ unsigned int inst1;
+ /* 0x4 */ unsigned int inst2;
+ /* 0x8 */ unsigned int inst3;
+ /* 0xC */ unsigned int inst4;
+} __osExceptionVector;
+
+extern __osExceptionVector __isExpJP;
+
+void MonitorInitBreak(void);
+
+typedef struct {
+ /* 0x00 */ u32 magic; // IS64
+ /* 0x04 */ u32 get;
+ /* 0x08 */ u8 unk_08[0x14-0x08];
+ /* 0x14 */ u32 put;
+ /* 0x18 */ u8 unk_18[0x20-0x18];
+ /* 0x20 */ u8 data[0x10000-0x20];
+} ISVDbg;
+
+#define IS64_MAGIC 'IS64'
+
+ISVDbg* gISVDbgPrnAdrs;
+
+u32 leoComuBuffAdd;
+u32 gISVFlag;
+u16 gISVChk;
+
+__osExceptionVector ramOldVector ALIGNED(8);
+
+static OSPiHandle* is_Handle;
+
+void isPrintfInit(void) {
+ is_Handle = osCartRomInit();
+
+ osEPiWriteIo(is_Handle, &gISVDbgPrnAdrs->put, 0);
+ osEPiWriteIo(is_Handle, &gISVDbgPrnAdrs->get, 0);
+ osEPiWriteIo(is_Handle, gISVDbgPrnAdrs, IS64_MAGIC);
+}
+
+static void* is_proutSyncPrintf(void* arg, const u8* str, u32 count) {
+ u32 data;
+ s32 p;
+ s32 start;
+ s32 end;
+
+ if (gISVDbgPrnAdrs == NULL) {
+ return 0;
+ }
+
+ osEPiReadIo(is_Handle, (u32)&gISVDbgPrnAdrs->magic, &data);
+ if (data != IS64_MAGIC) {
+ return 1;
+ }
+ osEPiReadIo(is_Handle, (u32)&gISVDbgPrnAdrs->get, &data);
+ p = data;
+ osEPiReadIo(is_Handle, (u32)&gISVDbgPrnAdrs->put, &data);
+
+ start = data;
+ end = start + count;
+
+ if (end >= 0xffe0) {
+ end -= 0xffe0;
+ if (p < end || start < p) {
+ return 1;
+ }
+ } else {
+ if (start < p && p < end) {
+ return 1;
+ }
+ }
+ while (count) {
+ if (*str != '\0') {
+ s32 shift = start & 3;
+ u32 addr = (u32)&gISVDbgPrnAdrs->data[start & 0xFFFFFFC];
+
+ shift = (3 - shift) * 8;
+
+ osEPiReadIo(is_Handle, addr, &data);
+ osEPiWriteIo(is_Handle, addr, (data & ~(0xff << shift)) | (*str << shift));
+
+ start++;
+ if (start >= 0xffe0) {
+ start -= 0xffe0;
+ }
+ }
+ count--;
+ str++;
+ }
+ osEPiWriteIo(is_Handle, (u32)&gISVDbgPrnAdrs->put, start);
+
+ return 1;
+}
+
+int __checkHardware_isv(void) {
+ u32 i = 0;
+ u32 data; // BUG: data is used uninitialized
+ u32 save[4];
+ u32 addr;
+ OSPiHandle* hnd = osCartRomInit();
+
+ gISVDbgPrnAdrs = NULL;
+ leoComuBuffAdd = 0;
+ gISVFlag = IS64_MAGIC;
+ gISVChk = 0;
+
+ for (i = 0; i < 4; i++) {
+ osEPiReadIo(hnd, 0xB0000100 + i * 4, save + i);
+ }
+
+ // data = 0;
+ osEPiWriteIo(hnd, 0xB000010C, data);
+ data = IS64_MAGIC;
+ osEPiWriteIo(hnd, 0xB0000100, IS64_MAGIC);
+
+ for (i = 0; i <= 0x1FFFF; i++) {
+ osEPiReadIo(hnd, 0xB000010C, &data);
+ if (data == IS64_MAGIC) {
+ data = 0;
+ osEPiWriteIo(hnd, 0xB0000100, data);
+ gISVChk |= 1;
+ osEPiReadIo(hnd, 0xB0000104, (void*)&gISVDbgPrnAdrs);
+ osEPiReadIo(hnd, 0xB0000108, &leoComuBuffAdd);
+ break;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ osEPiWriteIo(hnd, 0xB0000100 + i * 4, save[i]);
+ }
+
+ osEPiReadIo(hnd, 0xBFF00000, &data);
+
+ gISVChk |= ((data == IS64_MAGIC) ? 2 : 0);
+
+ return (gISVChk != 0) ? TRUE : FALSE;
+}
+
+void __osInitialize_isv(void) {
+ void (*fn)(void);
+ OSPiHandle* hnd;
+
+ if (gISVFlag == IS64_MAGIC || __checkHardware_isv()) {
+ if (gISVDbgPrnAdrs != NULL) {
+ __printfunc = is_proutSyncPrintf;
+ isPrintfInit();
+ }
+ if (gISVChk & 2) {
+ hnd = osCartRomInit();
+
+ ramOldVector = *(__osExceptionVector*)E_VEC;
+ *(__osExceptionVector*)E_VEC = __isExpJP;
+
+ osWritebackDCache(&ramOldVector, 0x10);
+ osInvalICache(&ramOldVector, 0x10);
+ osWritebackDCache(0x80000000, 0x190);
+ osInvalICache(0x80000000, 0x190);
+ osEPiReadIo(hnd, 0xBFF00010, &fn);
+ fn();
+ }
+ if (gISVChk & 2) {
+ MonitorInitBreak();
+ }
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/os/initialize_kmc.c b/lib/ultralib/src/os/initialize_kmc.c
new file mode 100644
index 0000000..c09b1fa
--- /dev/null
+++ b/lib/ultralib/src/os/initialize_kmc.c
@@ -0,0 +1,154 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "osint.h"
+
+typedef struct
+{
+ /* 0x0 */ unsigned int inst1;
+ /* 0x4 */ unsigned int inst2;
+ /* 0x8 */ unsigned int inst3;
+ /* 0xC */ unsigned int inst4;
+} __osExceptionVector;
+
+extern __osExceptionVector* __ptExceptionPreamble;
+
+static volatile unsigned int* stat = (unsigned*)0xbff08004;
+static volatile unsigned int* wport = (unsigned*)0xbff08000;
+static volatile unsigned int* piok = (unsigned*)PHYS_TO_K1(PI_STATUS_REG);
+
+static void rmonPutchar(char c) {
+ u32 data;
+
+ while (TRUE) {
+ osPiReadIo(stat, &data);
+ if (data & 4) {
+ osPiWriteIo(wport, c);
+ break;
+ }
+ }
+}
+
+static void* kmc_proutSyncPrintf(void* str, const char* buf, int n) {
+ int i;
+ char c;
+ char* p;
+ char* q;
+ char xbuf[128];
+ static int column = 0;
+
+ p = &xbuf;
+
+ for (i = 0; i < n; i++) {
+ c = *buf++;
+
+ switch (c) {
+ case '\n':
+ *p++ = '\n';
+ column = 0;
+ break;
+ case '\t':
+ do {
+ *p++ = ' ';
+ } while (++column % 8);
+ break;
+ default:
+ column++;
+ *p++ = c;
+ break;
+
+ }
+
+ if (c == '\n' || (p - xbuf) > 100) {
+ rmonPutchar((p - xbuf) - 1);
+
+ q = xbuf;
+ while (q != p) {
+ rmonPutchar(*q++);
+ }
+ p = xbuf;
+ }
+ }
+ if (p != xbuf) {
+ rmonPutchar((p - xbuf) - 1);
+
+ q = xbuf;
+ while (q != p) {
+ rmonPutchar(*q++);
+ }
+ }
+ return (void*)1;
+}
+
+extern u32 __kmc_pt_mode;
+
+void __osInitialize_kmc(void) {
+ if (!__kmc_pt_mode) {
+ int (*fnc)();
+ unsigned int* src;
+ unsigned int* dst;
+ unsigned int monadr;
+ volatile unsigned int* mon;
+ volatile unsigned int* stat;
+
+ stat = (unsigned*)0xbff08004;
+ mon = (unsigned*)0xBFF00000;
+ if (*mon != 0x4B4D4300) {
+ return;
+ }
+
+ src = (unsigned*)&__ptExceptionPreamble;
+ dst = (unsigned*)E_VEC;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ src+=2;
+ dst+=2;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+
+ osWritebackDCache(E_VEC, 0x24);
+ osInvalICache(E_VEC, 0x24);
+
+ __kmc_pt_mode = TRUE;
+
+ if ((*stat & 0x10) == 0) {
+ monadr = *(mon + 1);
+ if (monadr != 0xBFF00000) {
+ unsigned int* src;
+ unsigned int* dst = monadr | 0x20000000;
+ unsigned int ct = 0x2000 / 4;
+
+ src = 0xBFF00000;
+
+ while (ct != 0) {
+ *dst++ = *src++;
+ ct--;
+ }
+ }
+ fnc = monadr + 8;
+ fnc(0x4B4D4300, 0);
+ }
+ __printfunc = kmc_proutSyncPrintf;
+ }
+}
+
+int __checkHardware_kmc(void) {
+ volatile unsigned int* mon = (unsigned*)0xBFF00000;
+
+ if (*mon == 0x4B4D4300) {
+ mon = (unsigned*)0xBFF00010;
+
+ if (*mon == 0xB0FFB000) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/os/initialize_msp.c b/lib/ultralib/src/os/initialize_msp.c
new file mode 100644
index 0000000..d0deead
--- /dev/null
+++ b/lib/ultralib/src/os/initialize_msp.c
@@ -0,0 +1,154 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "osint.h"
+
+typedef struct
+{
+ /* 0x0 */ unsigned int inst1;
+ /* 0x4 */ unsigned int inst2;
+ /* 0x8 */ unsigned int inst3;
+ /* 0xC */ unsigned int inst4;
+} __osExceptionVector;
+
+extern __osExceptionVector* __ptExceptionPreamble;
+
+static volatile unsigned int* stat = (unsigned*)0xbff08004;
+static volatile unsigned int* wport = (unsigned*)0xbff08000;
+static volatile unsigned int* piok = (unsigned*)PHYS_TO_K1(PI_STATUS_REG);
+
+static void rmonPutchar(char c) {
+ u32 data;
+
+ while (TRUE) {
+ osPiReadIo(stat, &data);
+ if (data & 4) {
+ osPiWriteIo(wport, c);
+ break;
+ }
+ }
+}
+
+static void* msp_proutSyncPrintf(void* str, const char* buf, int n) {
+ int i;
+ char c;
+ char* p;
+ char* q;
+ char xbuf[128];
+ static int column = 0;
+
+ p = &xbuf;
+
+ for (i = 0; i < n; i++) {
+ c = *buf++;
+
+ switch (c) {
+ case '\n':
+ *p++ = '\n';
+ column = 0;
+ break;
+ case '\t':
+ do {
+ *p++ = ' ';
+ } while (++column % 8);
+ break;
+ default:
+ column++;
+ *p++ = c;
+ break;
+
+ }
+
+ if (c == '\n' || (p - xbuf) > 100) {
+ rmonPutchar((p - xbuf) - 1);
+
+ q = xbuf;
+ while (q != p) {
+ rmonPutchar(*q++);
+ }
+ p = xbuf;
+ }
+ }
+ if (p != xbuf) {
+ rmonPutchar((p - xbuf) - 1);
+
+ q = xbuf;
+ while (q != p) {
+ rmonPutchar(*q++);
+ }
+ }
+ return (void*)1;
+}
+
+extern u32 __kmc_pt_mode;
+
+void __osInitialize_msp(void) {
+ if (!__kmc_pt_mode) {
+ int (*fnc)();
+ unsigned int* src;
+ unsigned int* dst;
+ unsigned int monadr;
+ volatile unsigned int* mon;
+ volatile unsigned int* stat;
+
+ stat = (unsigned*)0xbff08004;
+ mon = (unsigned*)0xBFF00000;
+ if (*mon != 0x4B4D4300) {
+ return;
+ }
+
+ src = (unsigned*)&__ptExceptionPreamble;
+ dst = (unsigned*)E_VEC;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ src+=2;
+ dst+=2;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+
+ osWritebackDCache(E_VEC, 0x24);
+ osInvalICache(E_VEC, 0x24);
+
+ __kmc_pt_mode = TRUE;
+
+ if ((*stat & 0x10) == 0) {
+ monadr = *(mon + 1);
+ if (monadr != 0xBFF00000) {
+ unsigned int* src;
+ unsigned int* dst = monadr | 0x20000000;
+ unsigned int ct = 0x2000 / 4;
+
+ src = 0xBFF00000;
+
+ while (ct != 0) {
+ *dst++ = *src++;
+ ct--;
+ }
+ }
+ fnc = monadr + 8;
+ fnc(0x4B4D4300, 0);
+ }
+ __printfunc = msp_proutSyncPrintf;
+ }
+}
+
+int __checkHardware_msp(void) {
+ volatile unsigned int* mon = (unsigned*)0xBFF00000;
+
+ if (*mon == 0x4B4D4300) {
+ mon = (unsigned*)0xBFF00010;
+
+ if (*mon == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/os/initrdb.c b/lib/ultralib/src/os/initrdb.c
new file mode 100644
index 0000000..a332c29
--- /dev/null
+++ b/lib/ultralib/src/os/initrdb.c
@@ -0,0 +1,30 @@
+#ifndef _FINALROM
+#include "PR/os_internal.h"
+
+void* __osRdb_IP6_Data;
+u32 __osRdb_IP6_Size;
+u32 __osRdb_IP6_Ct;
+u32 __osRdb_IP6_CurWrite;
+u32 __osRdb_IP6_CurSend;
+
+void osInitRdb(u8* sendBuf, u32 sendSize) {
+ u32 mask;
+
+ sendSize /= 4;
+
+ if (((u32)sendBuf & 3) != 0) {
+ sendBuf = ((u32)sendBuf & 3) + 4;
+ sendSize--;
+ }
+ mask = __osDisableInt();
+
+ __osRdb_IP6_Data = sendBuf;
+ __osRdb_IP6_Size = sendSize;
+ __osRdb_IP6_Ct = 0;
+ __osRdb_IP6_CurWrite = 0;
+ __osRdb_IP6_CurSend = 0;
+
+ __osRestoreInt(mask);
+}
+
+#endif
diff --git a/lib/ultralib/src/os/interrupt.s b/lib/ultralib/src/os/interrupt.s
new file mode 100644
index 0000000..8fac481
--- /dev/null
+++ b/lib/ultralib/src/os/interrupt.s
@@ -0,0 +1,41 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(__osDisableInt)
+ la t2, __OSGlobalIntMask
+ lw t3, (t2)
+ andi t3, 0xFF00
+ mfc0 t0, C0_SR
+ and t1, t0, ~SR_IE
+ mtc0 t1, C0_SR
+ andi v0, t0, SR_IE
+ lw t0, (t2)
+ andi t0, 0xFF00
+ beq t0, t3, No_Change_Global_Int
+ la t2, __osRunningThread
+ lw t1, 280(t2)
+ andi t2, t1, 0xFF00
+ and t2, t0
+ and t1, 0xFFFF00FF
+ or t1, t2
+ and t1, -2
+ mtc0 t1, $12
+ nop
+ nop
+No_Change_Global_Int:
+ jr ra
+ nop
+END(__osDisableInt)
+
+LEAF(__osRestoreInt)
+ mfc0 t0, C0_SR
+ or t0, t0, a0
+ mtc0 t0, C0_SR
+ nop
+ nop
+ jr ra
+ nop
+END(__osRestoreInt)
diff --git a/lib/ultralib/src/os/invaldcache.s b/lib/ultralib/src/os/invaldcache.s
new file mode 100644
index 0000000..24cfb1c
--- /dev/null
+++ b/lib/ultralib/src/os/invaldcache.s
@@ -0,0 +1,61 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(osInvalDCache)
+ blez a1, 3f
+ nop
+ li t3, DCACHE_SIZE
+ bgeu a1, t3, 4f
+ nop
+
+ move t0, a0
+ addu t1, a0, a1
+ bgeu t0, t1, 3f
+ nop
+
+ addiu t1, t1, -DCACHE_LINESIZE
+ andi t2, t0, DCACHE_LINEMASK
+ beqz t2, 1f
+ nop
+
+ subu t0, t0, t2
+ CACHE((C_HWBINV|CACH_PD), (t0))
+ bgeu t0, t1, 3f
+ # nop
+
+ addiu t0, t0, DCACHE_LINESIZE
+1:
+ andi t2, t1, DCACHE_LINEMASK
+ beqz t2, 2f
+ # nop
+ subu t1, t1, t2
+ CACHE((C_HWBINV|CACH_PD), 0x10(t1))
+ bltu t1, t0, 3f
+ # nop
+2:
+ CACHE((C_HINV|CACH_PD), (t0))
+ .set noreorder
+ bltu t0, t1, 2b
+ addiu t0, t0, DCACHE_LINESIZE
+ .set reorder
+3:
+ jr ra
+ # nop
+4:
+ li t0, KUSIZE
+ addu t1, t0, t3
+ addiu t1, t1, -DCACHE_LINESIZE
+5:
+ CACHE((C_IINV|CACH_PD), (t0))
+ .set noreorder
+ bltu t0, t1, 5b
+ addiu t0, t0, DCACHE_LINESIZE
+ .set reorder
+
+ jr ra
+ # nop
+ # nop
+END(osInvalDCache)
diff --git a/lib/ultralib/src/os/invalicache.s b/lib/ultralib/src/os/invalicache.s
new file mode 100644
index 0000000..aeaf200
--- /dev/null
+++ b/lib/ultralib/src/os/invalicache.s
@@ -0,0 +1,42 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(osInvalICache)
+ blez a1, 2f
+ nop
+ li t3, ICACHE_SIZE
+ bgeu a1, t3, 3f
+ nop
+ move t0, a0
+ addu t1, a0, a1
+ bgeu t0, t1, 2f
+ nop
+ addiu t1, t1, -ICACHE_LINESIZE
+ andi t2, t0, ICACHE_LINEMASK
+ subu t0, t0, t2
+1:
+ CACHE((C_HINV|CACH_PI), (t0))
+ .set noreorder
+ bltu t0, t1, 1b
+ addiu t0, t0, ICACHE_LINESIZE
+ .set reorder
+2:
+ jr ra
+ #nop
+3:
+ li t0, KUSIZE
+ addu t1, t0, t3
+ addiu t1, t1, -ICACHE_LINESIZE
+4:
+ CACHE((C_IINV|CACH_PI), (t0))
+ .set noreorder
+ bltu t0, t1, 4b
+ addiu t0, t0, ICACHE_LINESIZE
+ .set reorder
+
+ jr ra
+ #nop
+END(osInvalICache)
diff --git a/lib/ultralib/src/os/jammesg.c b/lib/ultralib/src/os/jammesg.c
new file mode 100644
index 0000000..289d850
--- /dev/null
+++ b/lib/ultralib/src/os/jammesg.c
@@ -0,0 +1,27 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+s32 osJamMesg(OSMesgQueue *mq, OSMesg msg, s32 flag) {
+ register u32 saveMask = __osDisableInt();
+
+ while (mq->validCount >= mq->msgCount) {
+ if (flag == OS_MESG_BLOCK) {
+ __osRunningThread->state = OS_STATE_WAITING;
+ __osEnqueueAndYield(&mq->fullqueue);
+ } else {
+ __osRestoreInt(saveMask);
+ return -1;
+ }
+ }
+
+ mq->first = (mq->first + mq->msgCount - 1) % mq->msgCount;
+ mq->msg[mq->first] = msg;
+ mq->validCount++;
+
+ if (mq->mtqueue->next != NULL) {
+ osStartThread(__osPopThread(&mq->mtqueue));
+ }
+
+ __osRestoreInt(saveMask);
+ return 0;
+}
diff --git a/lib/ultralib/src/os/kdebugserver.c b/lib/ultralib/src/os/kdebugserver.c
new file mode 100644
index 0000000..85dc172
--- /dev/null
+++ b/lib/ultralib/src/os/kdebugserver.c
@@ -0,0 +1,96 @@
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "PR/rdb.h"
+#include "osint.h"
+
+extern u32 __osRdb_IP6_Empty;
+
+// not included in final rom, but __osThreadSave is here for some reason
+OSThread __osThreadSave;
+
+#ifndef _FINALROM
+
+static u8 buffer[12];
+static u32 numChars = 0;
+
+static u32 string_to_u32(u8* s) {
+ u32 k;
+
+ k = ((s[0] & 0xFF) << 0x18);
+ k |= ((s[1] & 0xFF) << 0x10);
+ k |= ((s[2] & 0xFF) << 0x8);
+ k |= (s[3] & 0xFF);
+
+ return k;
+}
+
+static void send_packet(u8* s, u32 n) {
+ rdbPacket packet;
+ u32 i;
+
+ packet.type = 0xC;
+ packet.length = n;
+
+ for (i = 0; i < n; i++) {
+ packet.buf[i] = s[i];
+ }
+ *(rdbPacket*)RDB_BASE_REG = packet;
+}
+
+static void clear_IP6(void) {
+ while (!(__osGetCause() & CAUSE_IP6)) {
+ ;
+ }
+ *(u32*)RDB_READ_INTR_REG = 0;
+
+ while (__osGetCause() & CAUSE_IP6) {
+ ;
+ }
+}
+
+static void send(u8* s, u32 n) {
+ u32 ct;
+ u32 i = 0;
+ u32 getLastIP6;
+
+ if (!__osRdb_IP6_Empty) {
+ clear_IP6();
+ getLastIP6 = FALSE;
+ } else {
+ getLastIP6 = TRUE;
+ }
+ while (n != 0) {
+ ct = (n < 3) ? n : 3;
+ send_packet(s + i, ct);
+ n -= ct;
+ i += ct;
+ if (n != 0) {
+ clear_IP6();
+ }
+ }
+ if (getLastIP6) {
+ clear_IP6();
+ }
+}
+
+void kdebugserver(rdbPacket packet) {
+ u32 i;
+ u32 length;
+ u8* addr;
+
+ for (i = 0; i < 3; i++) {
+ buffer[numChars++] = packet.buf[i];
+ }
+
+ if (buffer[0] == 2) {
+ send((char*)&__osRunningThread->context, sizeof(__OSThreadContext));
+ numChars = 0;
+ } else if (numChars >= 9 && buffer[0] == 1) {
+ addr = string_to_u32(&buffer[1]);
+ length = string_to_u32(&buffer[5]);
+ send(addr, length);
+ numChars = 0;
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/os/maptlb.s b/lib/ultralib/src/os/maptlb.s
new file mode 100644
index 0000000..d02e3fd
--- /dev/null
+++ b/lib/ultralib/src/os/maptlb.s
@@ -0,0 +1,64 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+#define index a0
+#define pm a1
+#define vaddr a2
+#define evenpaddr a3
+#define oddpaddr 16(sp)
+#define asid 20(sp)
+.text
+LEAF(osMapTLB)
+ STAY2(mfc0 t0, C0_ENTRYHI)
+ STAY2(mtc0 index, C0_INX)
+ STAY2(mtc0 pm, C0_PAGEMASK)
+.set noreorder
+ lw t1, asid
+ beq t1, -1, 7f
+ li ta0, TLBLO_G
+.set reorder
+ li t2, TLBLO_NONCOHRNT | TLBLO_D | TLBLO_V
+ or vaddr, vaddr, t1
+ b 8f
+
+7:
+ li t2, TLBLO_NONCOHRNT | TLBLO_D | TLBLO_V | TLBLO_G
+8:
+ STAY2(mtc0 vaddr, C0_ENTRYHI)
+ beq evenpaddr, -1, 9f
+ #nop
+ srl t3, evenpaddr, TLBLO_PFNSHIFT
+ or t3, t3, t2
+ STAY2(mtc0 t3, C0_ENTRYLO0)
+ b 10f
+ #nop
+9:
+ STAY2(mtc0 ta0, C0_ENTRYLO0)
+10:
+ lw t3, oddpaddr
+ beq t3, -1, 11f
+ #nop
+ srl t3, t3, TLBLO_PFNSHIFT
+ or t3, t3, t2
+ STAY2(mtc0 t3, C0_ENTRYLO1)
+ b 12f
+ #nop
+11:
+ STAY2(mtc0 ta0, C0_ENTRYLO1)
+ bne evenpaddr, -1, 12f
+ #nop
+ li t3, K0BASE
+ STAY2(mtc0 t3, C0_ENTRYHI)
+12:
+ .set noreorder
+ nop
+ tlbwi
+ nop
+ nop
+ nop
+ nop
+ STAY2(mtc0 t0, C0_ENTRYHI)
+ jr ra
+ #nop
+END(osMapTLB)
diff --git a/lib/ultralib/src/os/maptlbrdb.s b/lib/ultralib/src/os/maptlbrdb.s
new file mode 100644
index 0000000..c004362
--- /dev/null
+++ b/lib/ultralib/src/os/maptlbrdb.s
@@ -0,0 +1,30 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(osMapTLBRdb)
+ mfc0 t0, C0_ENTRYHI
+ li t1, 31
+ mtc0 t1, C0_INX
+ mtc0 zero, C0_PAGEMASK /*4k*/
+ li t2, TLBLO_UNCACHED | TLBLO_D | TLBLO_V | TLBLO_G
+ li t1, K2BASE
+ mtc0 t1, C0_ENTRYHI
+ li t1, KUSIZE
+ srl t3, t1,TLBLO_PFNSHIFT
+ or t3, t3,t2
+ mtc0 t3, C0_ENTRYLO0
+ li t1, TLBLO_G
+ mtc0 t1, C0_ENTRYLO1
+ nop
+ tlbwi
+ nop
+ nop
+ nop
+ nop
+ mtc0 t0, C0_ENTRYHI
+ jr ra
+ nop
+END(osMapTLBRdb)
diff --git a/lib/ultralib/src/os/osint.h b/lib/ultralib/src/os/osint.h
new file mode 100644
index 0000000..7a4c0cd
--- /dev/null
+++ b/lib/ultralib/src/os/osint.h
@@ -0,0 +1,55 @@
+#ifndef _OSINT_H
+#define _OSINT_H
+#include "PR/os_internal.h"
+typedef struct __OSEventState
+{
+ OSMesgQueue *messageQueue;
+ OSMesg message;
+} __OSEventState;
+extern struct __osThreadTail
+{
+ OSThread *next;
+ OSPri priority;
+} __osThreadTail;
+
+//maybe should be in exceptasm.h?
+extern void __osEnqueueAndYield(OSThread **);
+extern void __osDequeueThread(OSThread **, OSThread *);
+extern void __osEnqueueThread(OSThread **, OSThread *);
+extern OSThread *__osPopThread(OSThread **);
+extern void __osDispatchThread(void);
+extern void __osCleanupThread(void);
+
+extern void __osSetTimerIntr(OSTime);
+extern OSTime __osInsertTimer(OSTimer *);
+extern void __osTimerInterrupt(void);
+extern u32 __osProbeTLB(void *);
+extern int __osSpDeviceBusy(void);
+
+extern OSThread *__osRunningThread;
+extern OSThread *__osActiveQueue;
+extern OSThread *__osFaultedThread;
+extern OSThread *__osRunQueue;
+
+extern OSTimer *__osTimerList;
+extern OSTimer __osBaseTimer;
+extern OSTime __osCurrentTime;
+extern u32 __osBaseCounter;
+extern u32 __osViIntrCount;
+extern u32 __osTimerCounter;
+extern u32 __osShutdown;
+
+extern __OSEventState __osEventStateTab[OS_NUM_EVENTS];
+
+
+//not sure if this should be here
+extern s32 osViClock;
+extern void __osTimerServicesInit(void);
+extern s32 __osAiDeviceBusy(void);
+extern int __osDpDeviceBusy(void);
+
+#ifndef _FINALROM
+extern void* __printfunc;
+#endif
+
+#endif
diff --git a/lib/ultralib/src/os/parameters.s b/lib/ultralib/src/os/parameters.s
new file mode 100644
index 0000000..ce6ebb5
--- /dev/null
+++ b/lib/ultralib/src/os/parameters.s
@@ -0,0 +1,16 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+ABS(leoBootID, 0x800001a0)
+ABS(osTvType, 0x80000300)
+ABS(osRomType, 0x80000304)
+ABS(osRomBase, 0x80000308)
+ABS(osResetType, 0x8000030c)
+ABS(osCicId, 0x80000310)
+ABS(osVersion, 0x80000314)
+ABS(osMemSize, 0x80000318)
+ABS(osAppNMIBuffer, 0x8000031c)
+.fill 0x60
+/* padded to 0x60 in the object file */
diff --git a/lib/ultralib/src/os/physicaltovirtual.c b/lib/ultralib/src/os/physicaltovirtual.c
new file mode 100644
index 0000000..a0c1bae
--- /dev/null
+++ b/lib/ultralib/src/os/physicaltovirtual.c
@@ -0,0 +1,6 @@
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+
+void *osPhysicalToVirtual(u32 addr) {
+ return (void *)PHYS_TO_K0(addr);
+}
diff --git a/lib/ultralib/src/os/probetlb.s b/lib/ultralib/src/os/probetlb.s
new file mode 100644
index 0000000..237db23
--- /dev/null
+++ b/lib/ultralib/src/os/probetlb.s
@@ -0,0 +1,54 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(__osProbeTLB)
+ mfc0 t0, C0_ENTRYHI
+ andi t1, t0, TLBHI_PIDMASK
+ and t2, a0, -8192 # This also works: (TLBHI_VPN2MASK << 32) >> 32
+ or t1, t1, t2
+ mtc0 t1, C0_ENTRYHI
+ nop
+ nop
+ nop
+ tlbp
+ nop
+ nop
+ mfc0 t3, C0_INX
+ and t3, t3, TLBINX_PROBE
+ bnez t3, 3f
+ nop
+ tlbr
+ nop
+ nop
+ nop
+ mfc0 t3, C0_PAGEMASK
+ addi t3, t3, DCACHE_SIZE
+ srl t3, t3, 0x1
+ and ta0, t3, a0
+ bnez ta0, 1f
+ addi t3, t3,-1
+ mfc0 v0, C0_ENTRYLO0
+ b 2f
+ nop
+1:
+ mfc0 v0, C0_ENTRYLO1
+2:
+ andi ta1, v0,TLBLO_V
+ beqz ta1, 3f
+ nop
+ and v0, v0, TLBLO_PFNMASK
+ sll v0, v0, TLBLO_PFNSHIFT
+ and ta1, a0, t3
+ add v0, v0, ta1
+ b 4f
+ nop
+3:
+ li v0, -1
+4:
+ mtc0 t0, C0_ENTRYHI
+ jr ra
+ nop
+END(__osProbeTLB)
diff --git a/lib/ultralib/src/os/rdbsend.c b/lib/ultralib/src/os/rdbsend.c
new file mode 100644
index 0000000..b561d99
--- /dev/null
+++ b/lib/ultralib/src/os/rdbsend.c
@@ -0,0 +1 @@
+/* this file is completely empty in the rom release */
diff --git a/lib/ultralib/src/os/recvmesg.c b/lib/ultralib/src/os/recvmesg.c
new file mode 100644
index 0000000..f7f0e63
--- /dev/null
+++ b/lib/ultralib/src/os/recvmesg.c
@@ -0,0 +1,31 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flags) {
+ register u32 saveMask;
+ saveMask = __osDisableInt();
+
+ while (MQ_IS_EMPTY(mq)) {
+ if (flags == OS_MESG_NOBLOCK) {
+ __osRestoreInt(saveMask);
+ return -1;
+ }
+
+ __osRunningThread->state = OS_STATE_WAITING;
+ __osEnqueueAndYield(&mq->mtqueue);
+ }
+
+ if (msg != NULL) {
+ *msg = mq->msg[mq->first];
+ }
+
+ mq->first = (mq->first + 1) % mq->msgCount;
+ mq->validCount--;
+
+ if (mq->fullqueue->next != NULL) {
+ osStartThread(__osPopThread(&mq->fullqueue));
+ }
+
+ __osRestoreInt(saveMask);
+ return 0;
+}
diff --git a/lib/ultralib/src/os/resetglobalintmask.c b/lib/ultralib/src/os/resetglobalintmask.c
new file mode 100644
index 0000000..780da7c
--- /dev/null
+++ b/lib/ultralib/src/os/resetglobalintmask.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+
+void __osResetGlobalIntMask(OSHWIntr mask) {
+ register u32 saveMask = __osDisableInt();
+
+ __OSGlobalIntMask &= ~(mask & ~OS_IM_RCP);
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/sendmesg.c b/lib/ultralib/src/os/sendmesg.c
new file mode 100644
index 0000000..4d48d08
--- /dev/null
+++ b/lib/ultralib/src/os/sendmesg.c
@@ -0,0 +1,28 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flags) {
+ register u32 saveMask;
+ register s32 last;
+ saveMask = __osDisableInt();
+ while (MQ_IS_FULL(mq)) {
+ if (flags == OS_MESG_BLOCK) {
+ __osRunningThread->state = OS_STATE_WAITING;
+ __osEnqueueAndYield(&mq->fullqueue);
+ } else {
+ __osRestoreInt(saveMask);
+ return -1;
+ }
+ }
+
+ last = (mq->first + mq->validCount) % mq->msgCount;
+ mq->msg[last] = msg;
+ mq->validCount++;
+
+ if (mq->mtqueue->next != NULL) {
+ osStartThread(__osPopThread(&mq->mtqueue));
+ }
+
+ __osRestoreInt(saveMask);
+ return 0;
+}
diff --git a/lib/ultralib/src/os/setcause.s b/lib/ultralib/src/os/setcause.s
new file mode 100644
index 0000000..52e4950
--- /dev/null
+++ b/lib/ultralib/src/os/setcause.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetCause)
+ STAY2(mtc0 a0, C0_CAUSE)
+ jr ra
+END(__osSetCause)
diff --git a/lib/ultralib/src/os/setcompare.s b/lib/ultralib/src/os/setcompare.s
new file mode 100644
index 0000000..dec29a2
--- /dev/null
+++ b/lib/ultralib/src/os/setcompare.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetCompare)
+ STAY2(mtc0 a0, C0_COMPARE)
+ jr ra
+END(__osSetCompare)
diff --git a/lib/ultralib/src/os/setconfig.s b/lib/ultralib/src/os/setconfig.s
new file mode 100644
index 0000000..4f062bd
--- /dev/null
+++ b/lib/ultralib/src/os/setconfig.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetConfig)
+ STAY2(mtc0 a0, C0_CONFIG)
+ jr ra
+END(__osSetConfig)
diff --git a/lib/ultralib/src/os/setcount.s b/lib/ultralib/src/os/setcount.s
new file mode 100644
index 0000000..f94f1d2
--- /dev/null
+++ b/lib/ultralib/src/os/setcount.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetCount)
+ STAY2(mtc0 a0, C0_COUNT)
+ jr ra
+END(__osSetCount)
diff --git a/lib/ultralib/src/os/seterrorhandler.c b/lib/ultralib/src/os/seterrorhandler.c
new file mode 100644
index 0000000..4e839e8
--- /dev/null
+++ b/lib/ultralib/src/os/seterrorhandler.c
@@ -0,0 +1,10 @@
+#include "PR/ultraerror.h"
+
+extern OSErrorHandler __osErrorHandler;
+
+OSErrorHandler osSetErrorHandler(OSErrorHandler handler) {
+ OSErrorHandler oldHandler = __osErrorHandler;
+
+ __osErrorHandler = handler;
+ return oldHandler;
+}
diff --git a/lib/ultralib/src/os/seteventmesg.c b/lib/ultralib/src/os/seteventmesg.c
new file mode 100644
index 0000000..dd2ad99
--- /dev/null
+++ b/lib/ultralib/src/os/seteventmesg.c
@@ -0,0 +1,23 @@
+#include "macros.h"
+#include "PR/os_internal.h"
+#include "osint.h"
+
+__OSEventState __osEventStateTab[OS_NUM_EVENTS] ALIGNED(8);
+u32 __osPreNMI = FALSE;
+
+void osSetEventMesg(OSEvent event, OSMesgQueue *mq, OSMesg msg) {
+ register u32 saveMask = __osDisableInt();
+ __OSEventState *es = &__osEventStateTab[event];
+
+ es->messageQueue = mq;
+ es->message = msg;
+
+ if (event == OS_EVENT_PRENMI) {
+ if (__osShutdown && !__osPreNMI) {
+ osSendMesg(mq, msg, OS_MESG_NOBLOCK);
+ }
+ __osPreNMI = TRUE;
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/setfpccsr.s b/lib/ultralib/src/os/setfpccsr.s
new file mode 100644
index 0000000..f96ab33
--- /dev/null
+++ b/lib/ultralib/src/os/setfpccsr.s
@@ -0,0 +1,11 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetFpcCsr)
+ STAY2(cfc1 v0, fcr31)
+ STAY2(ctc1 a0, fcr31)
+ jr ra
+END(__osSetFpcCsr)
+.globl __osSetSR
diff --git a/lib/ultralib/src/os/setglobalintmask.c b/lib/ultralib/src/os/setglobalintmask.c
new file mode 100644
index 0000000..1d82b6e
--- /dev/null
+++ b/lib/ultralib/src/os/setglobalintmask.c
@@ -0,0 +1,9 @@
+#include "PR/os_internal.h"
+
+void __osSetGlobalIntMask(OSHWIntr mask) {
+ register u32 saveMask = __osDisableInt();
+
+ __OSGlobalIntMask |= mask;
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/sethwinterrupt.c b/lib/ultralib/src/os/sethwinterrupt.c
new file mode 100644
index 0000000..0fc9d30
--- /dev/null
+++ b/lib/ultralib/src/os/sethwinterrupt.c
@@ -0,0 +1,16 @@
+#include "PR/os_internal.h"
+
+struct __osHwInt {
+ s32 (*handler)(void);
+ void *stackEnd;
+};
+
+extern struct __osHwInt __osHwIntTable[];
+
+void __osSetHWIntrRoutine(OSHWIntr interrupt, s32 (*handler)(void), void *stackEnd) {
+ register u32 saveMask= __osDisableInt();
+
+ __osHwIntTable[interrupt].handler = handler;
+ __osHwIntTable[interrupt].stackEnd = stackEnd;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/setintmask.s b/lib/ultralib/src/os/setintmask.s
new file mode 100644
index 0000000..f19ed17
--- /dev/null
+++ b/lib/ultralib/src/os/setintmask.s
@@ -0,0 +1,124 @@
+#include "PR/R4300.h"
+#include "PR/rcp.h"
+#include "PR/os.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+#define MI_INTR_MASK ((1 << 6) - 1)
+
+.globl __osRcpImTable
+
+.text
+.set noreorder
+LEAF(osSetIntMask)
+ mfc0 ta0, C0_SR
+
+ andi v0, ta0, OS_IM_CPU
+
+ la t0, __OSGlobalIntMask
+ lw t3, 0(t0)
+
+ xor t0, t3,-1
+ andi t0, t0,(SR_IMASK)
+ or v0, v0,t0
+
+ lw t2, PHYS_TO_K1(MI_INTR_MASK_REG)
+ beqz t2, 1f
+ srl t1, t3,0x10
+
+ xor t1, t1,-1
+ andi t1, t1, MI_INTR_MASK
+ or t2, t2,t1
+1:
+ sll t2, t2,0x10
+ or v0, v0,t2
+
+ and t0, a0, MI_INTR_MASK<<0x10
+ and t0, t0,t3
+ srl t0, t0,0xf
+ lhu t2, __osRcpImTable(t0)
+ sw t2, PHYS_TO_K1(MI_INTR_MASK_REG)
+
+ andi t0, a0, OS_IM_CPU
+ andi t1, t3, SR_IMASK
+ and t0, t0,t1
+
+ and ta0, ta0, ~SR_IMASK
+ or ta0, ta0,t0
+
+ mtc0 ta0, C0_SR
+ nop
+ nop
+ jr ra
+ nop
+END(osSetIntMask)
+
+.rdata
+EXPORT(__osRcpImTable)
+/* LUT to convert between MI_INTR and MI_INTR_MASK */
+/* MI_INTR is status for each interrupt whereas */
+/* MI_INTR_MASK has seperate bits for set/clr */
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_CLR_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_CLR_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
+.half MI_INTR_MASK_SET_SP | MI_INTR_MASK_SET_SI | MI_INTR_MASK_SET_AI | MI_INTR_MASK_SET_VI | MI_INTR_MASK_SET_PI | MI_INTR_MASK_SET_DP
diff --git a/lib/ultralib/src/os/setpiinterrupt.c b/lib/ultralib/src/os/setpiinterrupt.c
new file mode 100644
index 0000000..ddc3f2f
--- /dev/null
+++ b/lib/ultralib/src/os/setpiinterrupt.c
@@ -0,0 +1,16 @@
+#include "PR/os_internal.h"
+
+struct __osHwInt {
+ s32 (*handler)(void);
+ void *stackEnd;
+};
+
+extern struct __osHwInt __osPiIntTable;
+
+void __osSetPIIntrRoutine(struct __osHwInt *ir) {
+ register u32 saveMask= __osDisableInt();
+
+ __osPiIntTable.handler = ir->handler;
+ __osPiIntTable.stackEnd = ir->stackEnd;
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/setsr.s b/lib/ultralib/src/os/setsr.s
new file mode 100644
index 0000000..c2eb1d7
--- /dev/null
+++ b/lib/ultralib/src/os/setsr.s
@@ -0,0 +1,10 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetSR)
+ STAY2(mtc0 a0, C0_SR)
+ nop
+ jr ra
+END(__osSetSR)
diff --git a/lib/ultralib/src/os/setthreadpri.c b/lib/ultralib/src/os/setthreadpri.c
new file mode 100644
index 0000000..ab6b23e
--- /dev/null
+++ b/lib/ultralib/src/os/setthreadpri.c
@@ -0,0 +1,26 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osSetThreadPri(OSThread *t, OSPri pri) {
+ register u32 saveMask = __osDisableInt();
+
+ if (t == NULL) {
+ t = __osRunningThread;
+ }
+
+ if (t->priority != pri) {
+ t->priority = pri;
+
+ if (t != __osRunningThread && t->state != OS_STATE_STOPPED) {
+ __osDequeueThread(t->queue, t);
+ __osEnqueueThread(t->queue, t);
+ }
+
+ if (__osRunningThread->priority < __osRunQueue->priority) {
+ __osRunningThread->state = OS_STATE_RUNNABLE;
+ __osEnqueueAndYield(&__osRunQueue);
+ }
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/settime.c b/lib/ultralib/src/os/settime.c
new file mode 100644
index 0000000..5bae2a2
--- /dev/null
+++ b/lib/ultralib/src/os/settime.c
@@ -0,0 +1,6 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osSetTime(OSTime time) {
+ __osCurrentTime = time;
+}
diff --git a/lib/ultralib/src/os/settimer.c b/lib/ultralib/src/os/settimer.c
new file mode 100644
index 0000000..0b78f27
--- /dev/null
+++ b/lib/ultralib/src/os/settimer.c
@@ -0,0 +1,41 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+int osSetTimer(OSTimer *t, OSTime countdown, OSTime interval, OSMesgQueue *mq, OSMesg msg) {
+ register u32 saveMask;
+ OSTime time;
+ OSTimer* next;
+ u32 count;
+ u32 value;
+
+ t->next = NULL;
+ t->prev = NULL;
+ t->value = countdown;
+ t->interval = interval;
+
+ if (countdown == 0) {
+ t->value = interval;
+ }
+
+ t->mq = mq;
+ t->msg = msg;
+
+ saveMask = __osDisableInt();
+ if (__osTimerList->next != __osTimerList) {
+ next = __osTimerList->next;
+ count = osGetCount();
+ value = count - __osTimerCounter;
+
+ if (value < next->value) {
+ next->value -= value;
+ } else {
+ next->value = 1;
+ }
+ }
+
+ time = __osInsertTimer(t);
+ __osSetTimerIntr(__osTimerList->next->value);
+ __osRestoreInt(saveMask);
+
+ return 0;
+}
diff --git a/lib/ultralib/src/os/settlbasid.s b/lib/ultralib/src/os/settlbasid.s
new file mode 100644
index 0000000..efaed5e
--- /dev/null
+++ b/lib/ultralib/src/os/settlbasid.s
@@ -0,0 +1,9 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(osSetTLBASID)
+ STAY2(mtc0 a0, C0_ENTRYHI)
+ jr ra
+END(osSetTLBASID)
diff --git a/lib/ultralib/src/os/setwatchlo.s b/lib/ultralib/src/os/setwatchlo.s
new file mode 100644
index 0000000..2f645a7
--- /dev/null
+++ b/lib/ultralib/src/os/setwatchlo.s
@@ -0,0 +1,10 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(__osSetWatchLo)
+ STAY2(mtc0 a0, C0_WATCHLO)
+ nop
+ jr ra
+END(__osSetWatchLo)
diff --git a/lib/ultralib/src/os/startthread.c b/lib/ultralib/src/os/startthread.c
new file mode 100644
index 0000000..dfd7f1c
--- /dev/null
+++ b/lib/ultralib/src/os/startthread.c
@@ -0,0 +1,35 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osStartThread(OSThread *t) {
+ register u32 saveMask = __osDisableInt();
+
+ switch (t->state) {
+ case OS_STATE_WAITING:
+ t->state = OS_STATE_RUNNABLE;
+ __osEnqueueThread(&__osRunQueue, t);
+ break;
+ case OS_STATE_STOPPED:
+ if (t->queue == NULL || t->queue == &__osRunQueue)
+ {
+ t->state = OS_STATE_RUNNABLE;
+ __osEnqueueThread(&__osRunQueue, t);
+ }
+ else
+ {
+ t->state = OS_STATE_WAITING;
+ __osEnqueueThread(t->queue, t);
+ __osEnqueueThread(&__osRunQueue, __osPopThread(t->queue));
+ }
+ break;
+ }
+
+ if (__osRunningThread == NULL) {
+ __osDispatchThread();
+ } else if (__osRunningThread->priority < __osRunQueue->priority) {
+ __osRunningThread->state = OS_STATE_RUNNABLE;
+ __osEnqueueAndYield(&__osRunQueue);
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/stopthread.c b/lib/ultralib/src/os/stopthread.c
new file mode 100644
index 0000000..d276b3b
--- /dev/null
+++ b/lib/ultralib/src/os/stopthread.c
@@ -0,0 +1,25 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osStopThread(OSThread *t) {
+ register u32 saveMask = __osDisableInt();
+ register u16 state = OS_STATE_RUNNING;
+
+ if (t != NULL) {
+ state = t->state;
+ }
+
+ switch (state) {
+ case OS_STATE_RUNNING:
+ __osRunningThread->state = OS_STATE_STOPPED;
+ __osEnqueueAndYield(NULL);
+ break;
+ case OS_STATE_RUNNABLE:
+ case OS_STATE_WAITING:
+ t->state = OS_STATE_STOPPED;
+ __osDequeueThread(t->queue, t);
+ break;
+ }
+
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/os/stoptimer.c b/lib/ultralib/src/os/stoptimer.c
new file mode 100644
index 0000000..e9e07af
--- /dev/null
+++ b/lib/ultralib/src/os/stoptimer.c
@@ -0,0 +1,30 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+int osStopTimer(OSTimer *t) {
+ register u32 savedMask;
+ OSTimer *timep;
+
+ if (t->next == NULL) {
+ return -1;
+ }
+
+ savedMask = __osDisableInt();
+ timep = t->next;
+
+ if (timep != __osTimerList) {
+ timep->value += t->value;
+ }
+
+ t->prev->next = t->next;
+ t->next->prev = t->prev;
+ t->next = NULL;
+ t->prev = NULL;
+
+ if (__osTimerList->next == __osTimerList) {
+ __osSetCompare(0);
+ }
+
+ __osRestoreInt(savedMask);
+ return 0;
+}
diff --git a/lib/ultralib/src/os/syncputchars.c b/lib/ultralib/src/os/syncputchars.c
new file mode 100644
index 0000000..9095a04
--- /dev/null
+++ b/lib/ultralib/src/os/syncputchars.c
@@ -0,0 +1,32 @@
+#include "PR/os_internal.h"
+#include "PR/rdb.h"
+#include "PR/rcp.h"
+#include "PR/R4300.h"
+
+unsigned int __osRdbSendMessage = 0;
+unsigned int __osRdbWriteOK = 1;
+
+void __osSyncPutChars(int type, int length, const char *buf) {
+ rdbPacket packet;
+ int i;
+ u32 mask;
+ packet.type = type;
+ packet.length = length;
+
+ for (i = 0; i < length; i++) {
+ packet.buf[i] = buf[i];
+ }
+
+ while (!__osAtomicDec(&__osRdbWriteOK)) {
+ }
+
+ mask = __osDisableInt();
+ *(vu32 *)RDB_BASE_REG = *(vu32 *)&packet;
+
+ while (!(__osGetCause() & CAUSE_IP6)) {
+ }
+
+ *(vu32 *)RDB_READ_INTR_REG = 0;
+ __osRdbWriteOK++;
+ __osRestoreInt(mask);
+}
diff --git a/lib/ultralib/src/os/testhost.c b/lib/ultralib/src/os/testhost.c
new file mode 100644
index 0000000..70514eb
--- /dev/null
+++ b/lib/ultralib/src/os/testhost.c
@@ -0,0 +1,4 @@
+#include "PR/os_internal.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
diff --git a/lib/ultralib/src/os/thread.c b/lib/ultralib/src/os/thread.c
new file mode 100644
index 0000000..767c4cf
--- /dev/null
+++ b/lib/ultralib/src/os/thread.c
@@ -0,0 +1,25 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+struct __osThreadTail __osThreadTail = {NULL, -1};
+OSThread *__osRunQueue = (OSThread *)&__osThreadTail;
+OSThread *__osActiveQueue = (OSThread *)&__osThreadTail;
+OSThread *__osRunningThread = {0};
+OSThread *__osFaultedThread = {0};
+
+void __osDequeueThread(OSThread **queue, OSThread *t) {
+ register OSThread **pred;
+ register OSThread *succ;
+
+ pred = queue;
+ succ = *pred;
+
+ while (succ != NULL) {
+ if (succ == t) {
+ *pred = t->next;
+ return;
+ }
+ pred = succ;
+ succ = *pred;
+ }
+}
diff --git a/lib/ultralib/src/os/threadasm.h b/lib/ultralib/src/os/threadasm.h
new file mode 100644
index 0000000..c5a73da
--- /dev/null
+++ b/lib/ultralib/src/os/threadasm.h
@@ -0,0 +1,68 @@
+#ifndef _THREADASM_H_
+#define _THREADASM_H_
+
+// Offsets of members in the OSThread struct
+#define THREAD_NEXT 0
+#define THREAD_PRI 4
+#define THREAD_QUEUE 8
+#define THREAD_TLNEXT 12
+#define THREAD_STATE 16
+#define THREAD_FLAGS 18
+#define THREAD_ID 20
+#define THREAD_FP 24
+#define THREAD_GP1 32
+#define THREAD_GP2 40
+#define THREAD_GP3 48
+#define THREAD_GP4 56
+#define THREAD_GP5 64
+#define THREAD_GP6 72
+#define THREAD_GP7 80
+#define THREAD_GP8 88
+#define THREAD_GP9 96
+#define THREAD_GP10 104
+#define THREAD_GP11 112
+#define THREAD_GP12 120
+#define THREAD_GP13 128
+#define THREAD_GP14 136
+#define THREAD_GP15 144
+#define THREAD_GP16 152
+#define THREAD_GP17 160
+#define THREAD_GP18 168
+#define THREAD_GP19 176
+#define THREAD_GP20 184
+#define THREAD_GP21 192
+#define THREAD_GP22 200
+#define THREAD_GP23 208
+#define THREAD_GP24 216
+#define THREAD_GP25 224
+// k0 and k1 are reserved for the kernel
+#define THREAD_GP28 232
+#define THREAD_GP29 240
+#define THREAD_GP30 248
+#define THREAD_GP31 256
+#define THREAD_LO 264
+#define THREAD_HI 272
+#define THREAD_SR 280
+#define THREAD_PC 284
+#define THREAD_CAUSE 288
+#define THREAD_BADVADDR 292
+#define THREAD_RCP 296
+#define THREAD_FPCSR 300
+#define THREAD_FP0 304
+#define THREAD_FP2 312
+#define THREAD_FP4 320
+#define THREAD_FP6 328
+#define THREAD_FP8 336
+#define THREAD_FP10 344
+#define THREAD_FP12 352
+#define THREAD_FP14 360
+#define THREAD_FP16 368
+#define THREAD_FP18 376
+#define THREAD_FP20 384
+#define THREAD_FP22 392
+#define THREAD_FP24 400
+#define THREAD_FP26 408
+#define THREAD_FP28 416
+#define THREAD_FP30 424
+
+#endif
diff --git a/lib/ultralib/src/os/timerintr.c b/lib/ultralib/src/os/timerintr.c
new file mode 100644
index 0000000..0f09d1f
--- /dev/null
+++ b/lib/ultralib/src/os/timerintr.c
@@ -0,0 +1,106 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+OSTimer *__osTimerList = &__osBaseTimer;
+OSTimer __osBaseTimer;
+OSTime __osCurrentTime;
+u32 __osBaseCounter;
+u32 __osViIntrCount;
+u32 __osTimerCounter;
+
+void __osTimerServicesInit(void) {
+ __osCurrentTime = 0;
+ __osBaseCounter = 0;
+ __osViIntrCount = 0;
+ __osTimerList->prev = __osTimerList;
+ __osTimerList->next = __osTimerList->prev;
+ __osTimerList->value = 0;
+ __osTimerList->interval = __osTimerList->value;
+ __osTimerList->mq = NULL;
+ __osTimerList->msg = 0;
+}
+
+void __osTimerInterrupt(void) {
+ OSTimer *t;
+ u32 count;
+ u32 elapsed_cycles;
+
+ if (__osTimerList->next != __osTimerList) {
+ while (TRUE) {
+ t = __osTimerList->next;
+ if (t == __osTimerList) {
+ __osSetCompare(0);
+ __osTimerCounter = 0;
+ break;
+ }
+
+ count = osGetCount();
+ elapsed_cycles = count - __osTimerCounter;
+ __osTimerCounter = count;
+
+ if (elapsed_cycles < t->value)
+ {
+ t->value -= elapsed_cycles;
+ __osSetTimerIntr(t->value);
+ break;
+ } else {
+ t->prev->next = t->next;
+ t->next->prev = t->prev;
+ t->next = NULL;
+ t->prev = NULL;
+
+ if (t->mq != NULL) {
+ osSendMesg(t->mq, t->msg, OS_MESG_NOBLOCK);
+ }
+
+ if (t->interval != 0) {
+ t->value = t->interval;
+ __osInsertTimer(t);
+ }
+ }
+ }
+ }
+}
+
+void __osSetTimerIntr(OSTime tim) {
+ OSTime NewTime;
+ u32 savedMask;
+
+ if (tim < 468) {
+ tim = 468;
+ }
+
+ savedMask = __osDisableInt();
+ __osTimerCounter = osGetCount();
+ NewTime = __osTimerCounter + tim;
+ __osSetCompare(NewTime);
+ __osRestoreInt(savedMask);
+}
+
+OSTime __osInsertTimer(OSTimer *t) {
+ OSTimer *timep;
+ OSTime tim;
+ u32 savedMask;
+ savedMask = __osDisableInt();
+
+ timep = __osTimerList->next;
+ tim = t->value;
+
+ while (timep != __osTimerList && tim > timep->value) {
+ tim -= timep->value;
+ timep = timep->next;
+ }
+
+ t->value = tim;
+
+ if (timep != __osTimerList) {
+ timep->value -= tim;
+ }
+
+ t->next = timep;
+ t->prev = timep->prev;
+ timep->prev->next = t;
+ timep->prev = t;
+ __osRestoreInt(savedMask);
+ return tim;
+}
diff --git a/lib/ultralib/src/os/unmaptlb.s b/lib/ultralib/src/os/unmaptlb.s
new file mode 100644
index 0000000..280a42e
--- /dev/null
+++ b/lib/ultralib/src/os/unmaptlb.s
@@ -0,0 +1,24 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(osUnmapTLB)
+ mfc0 t0, C0_ENTRYHI
+ mtc0 a0, C0_INX
+ li t1, K0BASE
+ mtc0 t1, C0_ENTRYHI
+ mtc0 zero, C0_ENTRYLO0
+ mtc0 zero, C0_ENTRYLO1
+ nop
+ tlbwi
+ nop
+ nop
+ nop
+ nop
+ mtc0 t0, C0_ENTRYHI
+ jr ra
+ nop
+END(osUnmapTLB)
+
diff --git a/lib/ultralib/src/os/unmaptlball.s b/lib/ultralib/src/os/unmaptlball.s
new file mode 100644
index 0000000..6d4b264
--- /dev/null
+++ b/lib/ultralib/src/os/unmaptlball.s
@@ -0,0 +1,26 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+.set noreorder
+LEAF(osUnmapTLBAll)
+ mfc0 t0, C0_ENTRYHI
+ li t1, NTLBENTRIES-1 /* last reserved for rdb */
+ li t2, KUSIZE
+ mtc0 t2, C0_ENTRYHI
+ mtc0 zero, C0_ENTRYLO0
+ mtc0 zero, C0_ENTRYLO1
+1:
+ mtc0 t1, C0_INX
+ nop
+ tlbwi
+ nop
+ nop
+ addi t1, t1,-1
+ bgez t1, 1b
+ nop
+ mtc0 t0, C0_ENTRYHI
+ jr ra
+ nop
+END(osUnmapTLBAll)
diff --git a/lib/ultralib/src/os/virtualtophysical.c b/lib/ultralib/src/os/virtualtophysical.c
new file mode 100644
index 0000000..5cf9e86
--- /dev/null
+++ b/lib/ultralib/src/os/virtualtophysical.c
@@ -0,0 +1,13 @@
+#include "PR/os_internal.h"
+#include "PR/R4300.h"
+#include "osint.h"
+
+u32 osVirtualToPhysical(void *addr) {
+ if (IS_KSEG0(addr)) {
+ return K0_TO_PHYS(addr);
+ } else if (IS_KSEG1(addr)) {
+ return K1_TO_PHYS(addr);
+ } else {
+ return __osProbeTLB(addr);
+ }
+}
diff --git a/lib/ultralib/src/os/writebackdcache.s b/lib/ultralib/src/os/writebackdcache.s
new file mode 100644
index 0000000..5f5b485
--- /dev/null
+++ b/lib/ultralib/src/os/writebackdcache.s
@@ -0,0 +1,35 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(osWritebackDCache)
+ blez a1, 2f
+ li t3, DCACHE_SIZE
+ bgeu a1,t3, 3f
+ move t0, a0
+ addu t1, a0,a1
+ bgeu t0, t1, 2f
+ addiu t1, t1, -DCACHE_LINESIZE
+ andi t2, t0, DCACHE_LINEMASK
+ subu t0, t0,t2
+1:
+ .set noreorder
+ cache (C_HWB|CACH_PD), (t0)
+ bltu t0, t1, 1b
+ addiu t0, t0, DCACHE_LINESIZE
+ .set reorder
+2:
+ jr ra
+3:
+ li t0, KUSIZE
+ addu t1, t0,t3
+ addiu t1, t1, -DCACHE_LINESIZE
+4:
+ .set noreorder
+ cache (C_IWBINV|CACH_PD), (t0)
+ bltu t0, t1, 4b
+ addiu t0, t0, DCACHE_LINESIZE
+ .set reorder
+ jr ra
+END(osWritebackDCache)
diff --git a/lib/ultralib/src/os/writebackdcacheall.s b/lib/ultralib/src/os/writebackdcacheall.s
new file mode 100644
index 0000000..ee8df88
--- /dev/null
+++ b/lib/ultralib/src/os/writebackdcacheall.s
@@ -0,0 +1,18 @@
+#include "PR/R4300.h"
+#include "sys/asm.h"
+#include "sys/regdef.h"
+
+.text
+LEAF(osWritebackDCacheAll)
+ li t0, KUSIZE
+ li t2, DCACHE_SIZE
+ addu t1, t0,t2
+ addiu t1, t1, -DCACHE_LINESIZE
+1:
+ .set noreorder
+ cache (C_IWBINV | CACH_PD), (t0)
+ bltu t0, t1, 1b
+ addiu t0, t0, DCACHE_LINESIZE
+ .set reorder
+ jr ra
+END(osWritebackDCacheAll)
diff --git a/lib/ultralib/src/os/yieldthread.c b/lib/ultralib/src/os/yieldthread.c
new file mode 100644
index 0000000..f4ed7c5
--- /dev/null
+++ b/lib/ultralib/src/os/yieldthread.c
@@ -0,0 +1,10 @@
+#include "PR/os_internal.h"
+#include "osint.h"
+
+void osYieldThread(void) {
+ register u32 saveMask = __osDisableInt();
+
+ __osRunningThread->state = OS_STATE_RUNNABLE;
+ __osEnqueueAndYield(&__osRunQueue);
+ __osRestoreInt(saveMask);
+}
diff --git a/lib/ultralib/src/rg/free.c b/lib/ultralib/src/rg/free.c
new file mode 100755
index 0000000..0229b2c
--- /dev/null
+++ b/lib/ultralib/src/rg/free.c
@@ -0,0 +1,15 @@
+#include "PR/region.h"
+#include "PR/R4300.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void osFree(void *region, void *addr) {
+ register OSRegion *rp = region;
+ int i;
+
+ rp = region;
+ i = ((u8 *)addr - rp->r_startBufferAddress) / rp->r_bufferSize;
+ *(u16 *)(&rp->r_startBufferAddress[i * rp->r_bufferSize]) = rp->r_freeList;
+ rp->r_freeList = i;
+}
diff --git a/lib/ultralib/src/rg/getbufcount.c b/lib/ultralib/src/rg/getbufcount.c
new file mode 100755
index 0000000..4f61521
--- /dev/null
+++ b/lib/ultralib/src/rg/getbufcount.c
@@ -0,0 +1,10 @@
+#include "PR/region.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 osGetRegionBufCount(void *region) {
+ register OSRegion *rp = region;
+ return rp->r_bufferCount;
+}
+
diff --git a/lib/ultralib/src/rg/getsize.c b/lib/ultralib/src/rg/getsize.c
new file mode 100755
index 0000000..6bd4b2a
--- /dev/null
+++ b/lib/ultralib/src/rg/getsize.c
@@ -0,0 +1,9 @@
+#include "PR/region.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+s32 osGetRegionBufSize(void *region) {
+ register OSRegion *rp = region;
+ return rp->r_bufferSize;
+}
diff --git a/lib/ultralib/src/rg/malloc.c b/lib/ultralib/src/rg/malloc.c
new file mode 100755
index 0000000..4b26431
--- /dev/null
+++ b/lib/ultralib/src/rg/malloc.c
@@ -0,0 +1,17 @@
+#include "PR/region.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void *osMalloc(void *region) {
+ register OSRegion *rp = region;
+ unsigned char *addr;
+
+ if (rp->r_freeList == MAX_BUFCOUNT) {
+ return NULL;
+ }
+
+ addr = &rp->r_startBufferAddress[rp->r_freeList * rp->r_bufferSize];
+ rp->r_freeList = *(u16 *)addr;
+ return addr;
+}
diff --git a/lib/ultralib/src/rg/region.c b/lib/ultralib/src/rg/region.c
new file mode 100755
index 0000000..181f52f
--- /dev/null
+++ b/lib/ultralib/src/rg/region.c
@@ -0,0 +1,36 @@
+#include "PR/region.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+void *osCreateRegion(void *startAddress, u32 length, u32 bufferSize, u32 alignSize) {
+ register OSRegion *rp;
+ register int i;
+ register unsigned char *addr;
+
+ if (alignSize == 0) {
+ alignSize = OS_RG_ALIGN_DEFAULT;
+ }
+
+ rp = (OSRegion*)ALIGN(startAddress, alignSize);
+ length = length - ((s32)rp - (s32)startAddress);
+ rp->r_bufferSize = ALIGN(bufferSize, alignSize);
+ rp->r_bufferCount = (s32)(length - ALIGN(sizeof(OSRegion), alignSize)) / rp->r_bufferSize;
+
+ if (rp->r_bufferCount > MAX_BUFCOUNT) {
+ rp->r_bufferCount = MAX_BUFCOUNT;
+ }
+
+ rp->r_startBufferAddress = (u8*)rp + ALIGN(sizeof(OSRegion), alignSize);
+ rp->r_endAddress = (u8*)rp + length;
+ addr = rp->r_startBufferAddress;
+
+ for (i = 0; i < rp->r_bufferCount - 1; i++) {
+ *((s16 *)(&addr[i * rp->r_bufferSize])) = i + 1;
+ }
+
+ *((u16 *)(&addr[i * rp->r_bufferSize])) = BUF_FREE_WO_NEXT;
+ rp->r_alignSize = alignSize;
+ rp->r_freeList = 0;
+ return rp;
+}
diff --git a/lib/ultralib/src/rmon/rmonbrk.c b/lib/ultralib/src/rmon/rmonbrk.c
new file mode 100644
index 0000000..ccae395
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonbrk.c
@@ -0,0 +1,423 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "dbgproto.h"
+#include "PR/rcp.h"
+#include "PR/sptask.h"
+#include "rmonint.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+static void rmonFindFaultedThreads(void);
+
+#define TMP_BP 0
+#define NUM_BREAKPOINTS 16
+
+typedef struct {
+ TVushort type;
+ TVushort response;
+ TVid threadID;
+ void* pc;
+} TVExceptionReplyMsg;
+
+typedef struct {
+ u32* breakAddress;
+ u32 oldInstruction;
+} BREAKINFO;
+
+/* first breakpoint is reserved for implementing single-stepping */
+static BREAKINFO breakpoints[NUM_BREAKPOINTS] ALIGNED(8);
+/* breakpoint for alternate branch target */
+static BREAKINFO altBreak;
+
+static BREAKINFO RCPbreakpoints[NUM_BREAKPOINTS] ALIGNED(8);
+
+u8 __rmonRcpAtBreak;
+
+static void SetTempBreakpoint(u32* addr1, u32* addr2) {
+ STUBBED_PRINTF(("Set temp BP at %08x", addr1));
+ if (addr2 != NULL) {
+ STUBBED_PRINTF((" and %08x", addr2));
+ }
+ STUBBED_PRINTF(("\n"));
+
+ /* Save the word at the target address to be restored later */
+ breakpoints[TMP_BP].oldInstruction = *addr1;
+ /* Install a break instruction at the target address */
+ *addr1 = MIPS_BREAK(16);
+ osWritebackDCache(addr1, sizeof(*addr1));
+ osInvalICache(addr1, sizeof(*addr1));
+ breakpoints[TMP_BP].breakAddress = addr1;
+
+ /* Also do so for an alt address if required */
+ if (addr2 != NULL) {
+ altBreak.oldInstruction = *addr2;
+ *addr2 = MIPS_BREAK(16);
+ osWritebackDCache(addr2, sizeof(*addr2));
+ osInvalICache(addr2, sizeof(*addr2));
+ altBreak.breakAddress = addr2;
+ }
+}
+
+static void ClearTempBreakpoint(void) {
+ u32 inst;
+
+ if (breakpoints[TMP_BP].breakAddress != NULL) {
+ inst = *breakpoints[TMP_BP].breakAddress;
+
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ STUBBED_PRINTF(("ClearTempBreak @ %08x\n", breakpoints[TMP_BP].breakAddress));
+
+ /* After confirming that there is a break instruction with code at the target
+ address, restore the original contents of the word at the target address */
+ *breakpoints[TMP_BP].breakAddress = breakpoints[TMP_BP].oldInstruction;
+ osWritebackDCache(breakpoints[TMP_BP].breakAddress, sizeof(*breakpoints[TMP_BP].breakAddress));
+ osInvalICache(breakpoints[TMP_BP].breakAddress, sizeof(*breakpoints[TMP_BP].breakAddress));
+ }
+ breakpoints[TMP_BP].breakAddress = NULL;
+ }
+
+ /* Same as above for the alt breakpoint */
+ if (altBreak.breakAddress != NULL) {
+ inst = *altBreak.breakAddress;
+
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ STUBBED_PRINTF(("ClearTempBreak @ %08x\n", altBreak.breakAddress));
+
+ *altBreak.breakAddress = altBreak.oldInstruction;
+ osWritebackDCache(altBreak.breakAddress, sizeof(*altBreak.breakAddress));
+ osInvalICache(altBreak.breakAddress, sizeof(*altBreak.breakAddress));
+ }
+ altBreak.breakAddress = NULL;
+ }
+}
+
+int __rmonSetBreak(KKHeader* req) {
+ register KKSetBkptRequest* request = (KKSetBkptRequest*)req;
+ register BREAKINFO* breakBase;
+ register BREAKINFO* whichBreak;
+ register BREAKINFO* lastBreak;
+ KKBkptEvent reply;
+
+ STUBBED_PRINTF(("SetBreak at %08x, method %d\n", request->addr, req->method));
+
+ /* Select breakpoint list */
+ if (req->method == RMON_RSP) {
+ breakBase = RCPbreakpoints;
+ whichBreak = &RCPbreakpoints[1];
+ lastBreak = &RCPbreakpoints[NUM_BREAKPOINTS];
+ } else {
+ breakBase = breakpoints;
+ whichBreak = &breakpoints[1];
+ lastBreak = &breakpoints[NUM_BREAKPOINTS];
+ }
+
+ /* Find breakpoint slot */
+ for (; whichBreak < lastBreak; whichBreak++) {
+ if (whichBreak->breakAddress != NULL) {
+ if (whichBreak->breakAddress == (u32*)request->addr) {
+ /* Breakpoint already set here */
+ break;
+ }
+ continue;
+ } else {
+ /* Empty slot */
+ break;
+ }
+ }
+
+ /* No breakpoints available */
+ if (whichBreak == lastBreak) {
+ return TV_ERROR_NO_MORE_IDS;
+ }
+
+ /* Set breakpoint if not already set */
+ if (whichBreak->breakAddress == NULL) {
+ if (req->method == RMON_RSP) {
+ whichBreak->oldInstruction = __rmonReadWordAt((u32*)request->addr);
+ __rmonWriteWordTo((u32*)request->addr, MIPS_BREAK((whichBreak - breakBase) + NUM_BREAKPOINTS));
+ } else {
+ whichBreak->oldInstruction = *(u32*)request->addr;
+ *(u32*)request->addr = MIPS_BREAK((whichBreak - breakBase) + NUM_BREAKPOINTS);
+ osWritebackDCache((void*)request->addr, sizeof(whichBreak->oldInstruction));
+ osInvalICache((void*)request->addr, sizeof(whichBreak->oldInstruction));
+ }
+ whichBreak->breakAddress = (u32*)request->addr;
+ STUBBED_PRINTF(("* (%08x) = %08x (was %08x)\n", whichBreak->breakAddress, *whichBreak->breakAddress, whichBreak->oldInstruction));
+ }
+
+ /* Send reply */
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->object;
+ reply.bp = whichBreak - breakBase;
+ reply.instruction = whichBreak->oldInstruction;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonListBreak(KKHeader* request UNUSED) {
+ STUBBED_PRINTF(("ListBreak\n"));
+
+ return TV_ERROR_ILLEGAL_CALL;
+}
+
+int __rmonClearBreak(KKHeader* req) {
+ register KKClrBkptRequest* request = (KKClrBkptRequest*)req;
+ register BREAKINFO* whichBreak;
+ KKBkptEvent reply;
+ u32 inst;
+
+ STUBBED_PRINTF(("ClearBreak\n"));
+
+ /* Check valid breakpoint index */
+ if (request->bp >= NUM_BREAKPOINTS) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ /* Clear the breakpoint, restore whatever was there before */
+ if (req->method == RMON_RSP) {
+ whichBreak = &RCPbreakpoints[request->bp];
+
+ if (whichBreak->breakAddress == NULL) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ inst = __rmonReadWordAt(whichBreak->breakAddress);
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ __rmonWriteWordTo(whichBreak->breakAddress, whichBreak->oldInstruction);
+ }
+ } else {
+ whichBreak = &breakpoints[request->bp];
+
+ if (whichBreak->breakAddress == NULL) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ inst = *whichBreak->breakAddress;
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ *whichBreak->breakAddress = whichBreak->oldInstruction;
+ osWritebackDCache(whichBreak->breakAddress, sizeof(*whichBreak->breakAddress));
+ osInvalICache(whichBreak->breakAddress, sizeof(*whichBreak->breakAddress));
+ }
+ }
+ whichBreak->breakAddress = NULL;
+
+ /* Send reply */
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->object;
+ reply.bp = request->bp;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+u32 __rmonGetBranchTarget(int method, int thread, char* addr) {
+ int inst;
+
+ if (method == RMON_RSP) {
+ inst = __rmonReadWordAt((u32*)addr);
+ } else {
+ inst = *(u32*)addr;
+ }
+
+ switch ((inst >> 26) & 0x3F) {
+ case 0: /* SPECIAL */
+ if (((inst >> 5) & 0x7FFF) == 0 && (inst & 0x3F) == 8) {
+ /* JR */
+ return __rmonGetRegisterContents(method, thread, (inst >> 21) & 0x1F);
+ }
+ if (((inst >> 16) & 0x1F) == 0 && (inst & 0x7FF) == 9) {
+ /* JALR */
+ return __rmonGetRegisterContents(method, thread, (inst >> 21) & 0x1F);
+ }
+ break;
+ case 1: /* REGIMM */
+ switch ((inst >> 16) & 0x1F) {
+ case 0: /* BLTZ */
+ case 1: /* BGEZ */
+ case 2: /* BLTZL */
+ case 3: /* BGEZL */
+ case 16: /* BLTZAL */
+ case 17: /* BGEZAL */
+ case 18: /* BLTZALL */
+ case 19: /* BGEZALL */
+ return (u32)addr + ((inst << 0x10) >> 0xE) + 4;
+ }
+ break;
+ case 2: /* J */
+ case 3: /* JAL */
+ return (((u32)inst << 6) >> 4) + (((s32)((u32)addr + 4) >> 0x1C) << 0x1C);
+ case 4: /* BEQ */
+ case 5: /* BNE */
+ case 20: /* BEQL */
+ case 21: /* BNEL */
+ return (u32)addr + ((inst << 0x10) >> 0xE) + 4;
+ case 6: /* BLEZ */
+ case 7: /* BGTZ */
+ case 22: /* BLEZL */
+ case 23: /* BGTZL */
+ if (((inst >> 16) & 0x1F) == 0) {
+ return (u32)addr + ((inst << 0x10) >> 0xE) + 4;
+ }
+ break;
+ case 16: /* COP0 */
+ case 17: /* COP1 */
+ case 18: /* COP2 */
+ case 19: /* COP3 */
+ if (((inst >> 21) & 0x1F) == 8) {
+ switch ((inst >> 16) & 0x1F) {
+ case 0: /* BCzF */
+ case 1: /* BCzT */
+ case 2: /* BCzFL */
+ case 3: /* BCzTL */
+ return (u32)addr + ((inst << 0x10) >> 0xE) + 4;
+ }
+ }
+ break;
+ }
+ return -1;
+}
+
+static int IsJump(u32 inst) {
+ switch ((inst >> 26) & 0x3F) {
+ case 0: /* SPECIAL */
+ if (((inst >> 5) & 0x7FFF) == 0 && (inst & 0x3F) == 8) {
+ /* JR */
+ return TRUE;
+ }
+ if (((inst >> 16) & 0x1F) == 0 && (inst & 0x7FF) == 9) {
+ /* JALR */
+ return TRUE;
+ }
+ break;
+ case 2: /* J */
+ case 3: /* JAL */
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int __rmonSetSingleStep(int thread, u32* instptr) {
+ u32 branchTarget = __rmonGetBranchTarget(RMON_CPU, thread, (void*)instptr);
+
+ STUBBED_PRINTF(("SingleStep\n"));
+
+ if ((branchTarget & 3) != 0) {
+ /* no branch target, set breakpoint at next pc */
+ SetTempBreakpoint(instptr + 1, NULL);
+ } else if ((u32*)branchTarget == instptr) {
+ /* branch target is this instruction, can't single step here */
+ return FALSE;
+ } else if (IsJump(*instptr) || (u32*)branchTarget == instptr + 2) {
+ /* unconditional branch, set at branch target */
+ SetTempBreakpoint((u32*)branchTarget, NULL);
+ } else {
+ /* set two breakpoints for handling conditional branches */
+ SetTempBreakpoint((u32*)branchTarget, instptr + 2);
+ }
+ return TRUE;
+}
+
+void __rmonGetExceptionStatus(KKStatusEvent* reply) {
+ reply->status.flags = OS_STATE_STOPPED;
+ reply->status.why = 2;
+ reply->status.what = 0;
+ reply->status.rv = 0;
+ reply->status.info.major = 2;
+ reply->status.info.minor = 4;
+ reply->header.code = KK_CODE_THREAD_STATUS;
+ reply->header.error = TV_ERROR_NO_ERROR;
+ reply->header.length = sizeof(*reply);
+}
+
+#define FAULT_BREAKNUM (NUM_BREAKPOINTS - 1)
+
+static void rmonSendBreakMessage(s32 whichThread, int breakNumber) {
+ KKStatusEvent reply;
+
+ STUBBED_PRINTF(("Break %d in thread %d\n", breakNumber, whichThread));
+
+ /* Build thread exception status */
+ __rmonGetThreadStatus(RMON_CPU, (whichThread != 0) ? whichThread : RMON_TID_NOTHREAD, &reply);
+ __rmonGetExceptionStatus(&reply);
+
+ if (breakNumber == FAULT_BREAKNUM) {
+ /* Hit fault */
+ reply.status.info.major = 1;
+ reply.status.info.minor = 2;
+ }
+ if (breakNumber < NUM_BREAKPOINTS) {
+ breakNumber = 0;
+ } else {
+ breakNumber -= NUM_BREAKPOINTS;
+ }
+ if (breakNumber != 0) {
+ /* Break not set by debugger, or set during single-step */
+ reply.status.instr = MIPS_BREAK_OPCODE;
+ }
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_EXCEPTION);
+}
+
+void __rmonHitBreak(void) {
+ STUBBED_PRINTF(("HitBreak\n"));
+
+ /* Stop all user threads and report faulted threads */
+ ClearTempBreakpoint();
+ __rmonStopUserThreads(0);
+ rmonFindFaultedThreads();
+}
+
+void __rmonHitSpBreak(void) {
+ KKStatusEvent exceptionReply;
+
+ STUBBED_PRINTF(("Hit SP Break\n"));
+
+ /* Rewind RSP PC by one instruction to return to the location of the break instruction */
+ __rmonWriteWordTo((u32*)SP_PC_REG, __rmonReadWordAt((u32*)SP_PC_REG) - 4);
+
+ /* Report RSP break event */
+ __rmonGetThreadStatus(RMON_RSP, RMON_TID_RSP, &exceptionReply);
+ __rmonGetExceptionStatus(&exceptionReply);
+ __rmonSendReply(&exceptionReply.header, sizeof(exceptionReply), KK_TYPE_EXCEPTION);
+ __rmonRcpAtBreak = TRUE;
+}
+
+void __rmonHitCpuFault(void) {
+ STUBBED_PRINTF(("HitCpuFault\n"));
+
+ /* Stop all user threads and report faulted threads */
+ __rmonMaskIdleThreadInts();
+ __rmonStopUserThreads(0);
+ rmonFindFaultedThreads();
+}
+
+static void rmonFindFaultedThreads(void) {
+ register OSThread* tptr = __osGetActiveQueue();
+
+ while (tptr->priority != -1) {
+ if (tptr->priority > OS_PRIORITY_IDLE && tptr->priority <= OS_PRIORITY_APPMAX) {
+ if (tptr->flags & OS_FLAG_CPU_BREAK) {
+ int inst = *(u32*)tptr->context.pc;
+
+ STUBBED_PRINTF(("Brk in thread %d @ %08x, inst %08x\r\n", tptr->id, tptr->context.pc, inst));
+
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ rmonSendBreakMessage(tptr->id, inst >> 6);
+ } else {
+ rmonSendBreakMessage(tptr->id, 0);
+ }
+ }
+ if (tptr->flags & OS_FLAG_FAULT) {
+ __rmonSendFault(tptr);
+ rmonSendBreakMessage(tptr->id, FAULT_BREAKNUM);
+ }
+ }
+ tptr = tptr->tlnext;
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmoncmds.c b/lib/ultralib/src/rmon/rmoncmds.c
new file mode 100644
index 0000000..a2bee99
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmoncmds.c
@@ -0,0 +1,49 @@
+#ifndef _FINALROM
+
+#include "dbgproto.h"
+#include "rmonint.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+static int NotImplemented(KKHeader* dummy UNUSED) {
+ return TV_ERROR_ILLEGAL_CALL;
+}
+
+static FUNPTR dispatchTable[] = {
+ __rmonLoadProgram, __rmonListProcesses, __rmonGetExeName, __rmonListThreads,
+ __rmonThreadStatus, NotImplemented, __rmonStopThread, __rmonRunThread,
+ NotImplemented, NotImplemented, __rmonSetFault, NotImplemented,
+ __rmonGetRegionCount, __rmonGetRegions, __rmonGetGRegisters, __rmonSetGRegisters,
+ __rmonGetFRegisters, __rmonSetFRegisters, __rmonReadMem, __rmonWriteMem,
+ __rmonSetBreak, __rmonClearBreak, __rmonListBreak, NotImplemented,
+ NotImplemented, NotImplemented, NotImplemented, NotImplemented,
+ NotImplemented, NotImplemented, __rmonSetComm, NotImplemented,
+ NotImplemented, NotImplemented, NotImplemented, NotImplemented,
+ NotImplemented, NotImplemented, NotImplemented, NotImplemented,
+ NotImplemented, NotImplemented, NotImplemented, NotImplemented,
+ NotImplemented, NotImplemented, NotImplemented, NotImplemented,
+ NotImplemented, __rmonGetSRegs, __rmonSetSRegs, __rmonGetVRegs,
+ __rmonSetVRegs, NotImplemented,
+};
+
+int __rmonExecute(KKHeader* request) {
+ int retval;
+ KKHeader reply;
+
+ if (request->code >= ARRLEN(dispatchTable) - 1) {
+ return TV_ERROR_ILLEGAL_CALL;
+ }
+
+ retval = dispatchTable[(int)request->code](request);
+ if (retval < TV_ERROR_NO_ERROR) {
+ reply.code = request->code;
+ reply.error = retval;
+ __rmonSendReply(&reply, sizeof(reply), KK_TYPE_REPLY);
+ }
+ return retval;
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonint.h b/lib/ultralib/src/rmon/rmonint.h
new file mode 100644
index 0000000..350b779
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonint.h
@@ -0,0 +1,169 @@
+#ifndef _RMONINT_H
+#define _RMONINT_H
+
+#include "dbgproto.h"
+#include "PR/os_internal.h"
+
+/* mips */
+
+#define MIPS_LWC2_OPCODE 50
+#define MIPS_SWC2_OPCODE 58
+
+#define MIPS_LW_OPCODE 35
+#define MIPS_SW_OPCODE 43
+
+#define MIPS_BREAK_OPCODE 0xD
+#define MIPS_BREAK_MASK 0xFC00003F
+
+#define MIPS_BREAK(code) \
+ ((((code) & 0xFFFFF) << 6) | MIPS_BREAK_OPCODE)
+
+/* R4300 General Purpose Register Indices */
+#define GREG_IDX_ZERO 0
+#define GREG_IDX_AT 1
+#define GREG_IDX_T9 25
+#define GREG_IDX_K0 26
+#define GREG_IDX_GP 28
+#define GREG_IDX_RA 31
+#define GREG_IDX_LO 32
+#define GREG_IDX_HI 33
+#define GREG_IDX_CAUSE 34
+#define GREG_IDX_PC 35
+#define GREG_IDX_SR 36
+
+/* RSP Scalar Register Indices */
+#define SREG_IDX_ZERO 0
+#define SREG_IDX_RA 31
+#define SREG_IDX_DRAM_ADDR (32 + 0)
+#define SREG_IDX_MEM_ADDR (32 + 1)
+#define SREG_IDX_RD_LEN (32 + 2)
+#define SREG_IDX_PC (32 + 3)
+#define SREG_IDX_WR_LEN (32 + 4)
+#define SREG_IDX_STATUS (32 + 5)
+#define SREG_IDX_DMA_FULL (32 + 6)
+#define SREG_IDX_DMA_BUSY (32 + 7)
+
+/* RSP Vector Register Properties */
+#define VREG_NUM 32
+#define VREG_SIZE 0x10
+
+/* rmon */
+
+#define RMON_MESG_CPU_BREAK 2
+#define RMON_MESG_SP_BREAK 4
+#define RMON_MESG_FAULT 8
+
+#define RMON_CPU 0
+#define RMON_RSP 1
+
+/* "thread id" for rsp */
+#define RMON_TID_RSP 1000
+/* "thread priority" for rsp */
+#define RMON_PRI_RSP 42
+
+/* "thread id" for no thread running */
+#define RMON_TID_NOTHREAD 1003
+
+#define RMON_PID_CPU 1002
+#define RMON_PID_RSP 1001
+
+/* Largest serviceable read/write memory request */
+#define RMON_MAX_XFER_SIZE 1024
+
+/* rmonmain */
+
+void __rmonSendHeader(KKHeader* const block, u32 blockSize, u32 type);
+void __rmonSendReply(KKHeader* const block, u32 blockSize, u32 replyType);
+void __rmonSendData(char* const block, unsigned int blockSize);
+
+extern int __rmonActive;
+
+/* rmonmisc */
+
+void __rmonInit(void);
+void __rmonPanic(void);
+
+extern OSMesgQueue __rmonMQ;
+
+/* rmonmem */
+
+void __rmonWriteWordTo(u32* addr, u32 val);
+u32 __rmonReadWordAt(u32* addr);
+void __rmonMemcpy(u8* dest, u8* srce, u32 count);
+void __rmonCopyWords(u32* dest, u32* srce, u32 count);
+
+extern u8 __rmonUtilityBuffer[256];
+
+/* rmonsio */
+
+void __rmonSendFault(OSThread* thread);
+void __rmonIOflush(void);
+void __rmonIOputw(u32 word);
+void __rmonIOhandler(void);
+
+extern void* __osRdb_DbgRead_Buf;
+extern u8 rmonRdbReadBuf[];
+
+/* rmonrcp */
+
+int __rmonRCPrunning(void);
+void __rmonIdleRCP(void);
+void __rmonStepRCP(void);
+void __rmonRunRCP(void);
+
+/* rmonbrk */
+
+u32 __rmonGetBranchTarget(int method, int thread, char* addr);
+int __rmonSetSingleStep(int thread, u32* instptr);
+void __rmonGetExceptionStatus(KKStatusEvent* reply);
+void __rmonHitBreak(void);
+void __rmonHitSpBreak(void);
+void __rmonHitCpuFault(void);
+
+extern u8 __rmonRcpAtBreak;
+
+/* rmonregs */
+
+u32 __rmonGetRegisterContents(int method, int threadNumber, int regNumber);
+
+/* rmontask */
+
+void __rmonMaskIdleThreadInts(void);
+OSThread* __rmonGetTCB(int threadNumber);
+int __rmonStopUserThreads(int whichThread);
+int __rmonGetThreadStatus(int method, int id, KKStatusEvent* reply);
+
+/* rmoncmds */
+
+int __rmonExecute(KKHeader* request);
+
+/* commands */
+
+typedef int (*FUNPTR)();
+
+int __rmonLoadProgram(KKHeader* req);
+int __rmonListProcesses(KKHeader* req);
+int __rmonGetExeName(KKHeader* req);
+int __rmonListThreads(KKHeader* req);
+int __rmonThreadStatus(KKHeader* req);
+int __rmonStopThread(KKHeader* req);
+int __rmonRunThread(KKHeader* req);
+int __rmonSetFault(KKHeader* req);
+int __rmonGetRegionCount(KKHeader* req);
+int __rmonGetRegions(KKHeader* req);
+int __rmonGetGRegisters(KKHeader* req);
+int __rmonSetGRegisters(KKHeader* req);
+int __rmonGetFRegisters(KKHeader* req);
+int __rmonSetFRegisters(KKHeader* req);
+int __rmonReadMem(KKHeader* req);
+int __rmonWriteMem(KKHeader* req);
+int __rmonSetBreak(KKHeader* req);
+int __rmonClearBreak(KKHeader* req);
+int __rmonListBreak(KKHeader* req);
+int __rmonSetComm(KKHeader* req);
+int __rmonGetSRegs(KKHeader* req);
+int __rmonSetSRegs(KKHeader* req);
+int __rmonGetVRegs(KKHeader* req);
+int __rmonSetVRegs(KKHeader* req);
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonmain.c b/lib/ultralib/src/rmon/rmonmain.c
new file mode 100644
index 0000000..6e2ee6d
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonmain.c
@@ -0,0 +1,127 @@
+#ifndef _FINALROM
+
+#include "dbgproto.h"
+#include "PR/os_internal.h"
+#include "rmonint.h"
+#include "PR/rcp.h"
+#include "sptask.h"
+#include "PR/rdb.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+int __rmonActive = FALSE;
+
+static vu32 somethingToDo;
+static u32 inbuffer[280] ALIGNED(0x10);
+static u8 cmdinptr;
+static u8 cmdoutptr;
+static int state;
+static char* inPointer;
+
+void __rmonSendHeader(KKHeader* const block, u32 blockSize, u32 type) {
+ int sent;
+ char* cPtr = (char*)block;
+
+ block->rev = KK_REV;
+ block->type = type;
+
+ sent = 0;
+ while (sent < blockSize) {
+ sent += __osRdbSend(cPtr + sent, blockSize - sent, RDB_TYPE_GtoH_DEBUG);
+ }
+}
+
+void __rmonSendReply(KKHeader* const block, u32 blockSize, u32 replyType) {
+ char* cPtr;
+ int sent = 0;
+
+ block->length = blockSize;
+ cPtr = (char*)&blockSize;
+
+ /* send size */
+ while (sent < (signed)sizeof(blockSize)) {
+ sent += __osRdbSend(cPtr + sent, sizeof(blockSize) - sent, RDB_TYPE_GtoH_DEBUG);
+ }
+
+ /* send data */
+ __rmonSendHeader(block, blockSize, replyType);
+ __rmonIOflush();
+}
+
+void __rmonSendData(char* const block, unsigned int blockSize) {
+ int* blockPointer = (int*)block;
+ unsigned int wordCount = (u32)(blockSize + 3) / 4;
+ u32 data;
+ union {
+ char bufBytes[4];
+ u32 bufWord;
+ } buffer;
+
+ if (((u32)block & 3) == 0) {
+ while (wordCount--) {
+ if ((u32)blockPointer >= SP_DMEM_START && (u32)blockPointer < 0x05000000) {
+ __osSpRawReadIo((u32)blockPointer++, &data);
+ __rmonIOputw(data);
+ } else {
+ __rmonIOputw(*(blockPointer++));
+ }
+ }
+ } else while (wordCount--) {
+ __rmonMemcpy((u8*)buffer.bufBytes, (u8*)blockPointer, sizeof(buffer));
+ __rmonIOputw(buffer.bufWord);
+ blockPointer++;
+ }
+ __rmonIOflush();
+}
+
+void rmonMain(void) {
+ register int newChars UNUSED;
+
+ STUBBED_PRINTF(("rmon: Thread %d created\n"));
+ STUBBED_PRINTF(("rmon: Thread %d destroyed\n"));
+
+ somethingToDo = 0;
+ cmdoutptr = 0;
+ cmdinptr = 0;
+
+ __rmonInit();
+ __rmonActive = TRUE;
+
+ state = 0;
+ newChars = 0;
+ inPointer = (void*)&inbuffer;
+
+ for (;;) {
+ OSMesg work;
+
+ osRecvMesg(&__rmonMQ, &work, OS_MESG_BLOCK);
+
+ somethingToDo |= (u32)work;
+
+ if (somethingToDo & RMON_MESG_CPU_BREAK) {
+ somethingToDo &= ~RMON_MESG_CPU_BREAK;
+ __rmonHitBreak();
+ }
+ if (somethingToDo & RMON_MESG_SP_BREAK) {
+ somethingToDo &= ~RMON_MESG_SP_BREAK;
+ __rmonHitSpBreak();
+ }
+ if (somethingToDo & RMON_MESG_FAULT) {
+ somethingToDo &= ~RMON_MESG_FAULT;
+ __rmonHitCpuFault();
+ }
+ if (somethingToDo & 0x10) {
+ somethingToDo;
+ somethingToDo &= 0xEF;
+ }
+ if (somethingToDo & 0x20) {
+ somethingToDo;
+ somethingToDo &= 0xDF;
+ }
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonmem.c b/lib/ultralib/src/rmon/rmonmem.c
new file mode 100644
index 0000000..3a8a3ab
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonmem.c
@@ -0,0 +1,271 @@
+#ifndef _FINALROM
+
+#include "dbgproto.h"
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "PR/sptask.h"
+#include "rmonint.h"
+#include "PR/rdb.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+u8 __rmonUtilityBuffer[256] ALIGNED(8);
+
+void __rmonWriteWordTo(u32* addr, u32 val) {
+ while (__osSpRawWriteIo((u32)addr, val) != 0) {
+ ;
+ }
+}
+
+u32 __rmonReadWordAt(u32* addr) {
+ u32 data;
+
+ if (addr >= (u32*)SP_DMEM_START && addr < (u32*)0x05000000) {
+ __osSpRawReadIo((u32)addr, &data);
+ return data;
+ }
+ return 0;
+}
+
+void __rmonMemcpy(u8* dest, u8* srce, u32 count) {
+ while (count--) {
+ *dest++ = *srce++;
+ }
+}
+
+void __rmonCopyWords(u32* dest, u32* srce, u32 count) {
+ while (count--) {
+ *dest++ = *srce++;
+ }
+}
+
+static void strcpy(char* dest, char* srce) {
+ while ((*dest++ = *srce++)) {
+ ;
+ }
+}
+
+int __rmonReadMem(KKHeader* req) {
+ char* cPtr;
+ int sent;
+ int dataSize;
+ KKReadRequest* request = (KKReadRequest*)req;
+ KKBufferEvent* reply = (KKBufferEvent*)__rmonUtilityBuffer;
+ u8* blockStart;
+
+ STUBBED_PRINTF(("ReadMem @ %08x for %d\n", request->addr, request->nbytes));
+
+ reply->header.code = request->header.code;
+ reply->object = request->object;
+ reply->header.error = TV_ERROR_NO_ERROR;
+
+ if (request->addr == (u32)-1) {
+ return TV_ERROR_INVALID_ADDRESS;
+ }
+ if (request->nbytes > RMON_MAX_XFER_SIZE) {
+ return TV_ERROR_INVALID_CAPABILITY;
+ }
+
+ if (req->method == RMON_RSP) {
+ if ((request->addr < SP_IMEM_START || (request->addr + request->nbytes) > SP_IMEM_END)) {
+ if ((request->addr < SP_DMEM_START || (request->addr + request->nbytes) > SP_DMEM_END)) {
+ return TV_ERROR_INVALID_ADDRESS;
+ }
+ }
+ } else if (osVirtualToPhysical((void*)request->addr) == (u32)-1) {
+ return TV_ERROR_INVALID_ADDRESS;
+ }
+
+ blockStart = (u8*)request->addr;
+ reply->header.length = request->nbytes + sizeof(reply->header) + sizeof(reply->object);
+ dataSize = request->nbytes + sizeof(reply->header) + sizeof(reply->object);
+
+ cPtr = (char*)&dataSize;
+ sent = 0;
+ while (sent < (signed)sizeof(dataSize)) {
+ sent += __osRdbSend(cPtr + sent, sizeof(dataSize) - sent, RDB_TYPE_GtoH_DEBUG);
+ }
+
+ __rmonSendHeader(&reply->header, sizeof(reply->header) + sizeof(reply->object), KK_TYPE_REPLY);
+ __rmonSendData(blockStart, request->nbytes);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonWriteMem(KKHeader* req) {
+ register KKWriteRequest* request = (KKWriteRequest*)req;
+ KKObjectEvent reply;
+
+ STUBBED_PRINTF(("WriteMem\n"));
+
+ /* Bad virtual address, abort */
+ if (req->method == RMON_CPU && osVirtualToPhysical((u32*)request->writeHeader.addr) == (u32)-1) {
+ return TV_ERROR_INVALID_ADDRESS;
+ }
+
+ /* Transfer size too large, abort */
+ if (request->writeHeader.nbytes > RMON_MAX_XFER_SIZE) {
+ return TV_ERROR_INVALID_CAPABILITY;
+ }
+
+ if ((request->writeHeader.addr >= SP_DMEM_START && (request->writeHeader.addr + request->writeHeader.nbytes) < 0x05000000)) {
+ int align;
+ u32 word;
+
+ if ((align = request->writeHeader.addr & 3) != 0) {
+ STUBBED_PRINTF(("Long unaligned write...\n"));
+
+ if (request->writeHeader.nbytes != 1) {
+ return TV_ERROR_INVALID_ADDRESS;
+ }
+
+ /* Unaligned write; read the word, substitute in the written byte, write it back */
+ word = __rmonReadWordAt((u32*)(request->writeHeader.addr & ~3));
+ if (align == 1) {
+ word = (word & ~0xFF0000) | (request->buffer[0] << 0x10);
+ } else if (align == 2) {
+ word = (word & ~0xFF00) | (request->buffer[0] << 8);
+ } else {
+ word = (word & ~0xFF) | (request->buffer[0] << 0);
+ }
+ __rmonWriteWordTo((u32*)(request->writeHeader.addr & ~3), word);
+ } else {
+ int wordCount = request->writeHeader.nbytes / sizeof(u32);
+ u32* wordPointer = (u32*)request->buffer;
+
+ if (request->writeHeader.nbytes % sizeof(u32) != 0) {
+ STUBBED_PRINTF(("RCP write not an integral number of words\n"));
+ return TV_ERROR_INVALID_ADDRESS;
+ }
+
+ while (wordCount--) {
+ __rmonWriteWordTo((u32*)request->writeHeader.addr, *(wordPointer++));
+ request->writeHeader.addr += sizeof(*wordPointer);
+ }
+ }
+ } else {
+ __rmonMemcpy((u8*)request->writeHeader.addr, (u8*)request->buffer, request->writeHeader.nbytes);
+ }
+
+ reply.header.code = request->writeHeader.header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->writeHeader.object;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonListProcesses(KKHeader* req) {
+ KKObjectRequest* request = (KKObjectRequest*)req;
+ KKObjsEvent reply;
+
+ STUBBED_PRINTF(("ListProcesses\n"));
+
+ reply.object = 0;
+ reply.objs.number = 1;
+ reply.objs.objects[0] = (req->method == RMON_RSP) ? RMON_PID_RSP : RMON_PID_CPU;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonLoadProgram(KKHeader* request UNUSED) {
+ STUBBED_PRINTF(("LoadProgram\n"));
+
+ return TV_ERROR_ILLEGAL_CALL;
+}
+
+int __rmonGetExeName(KKHeader* req) {
+ KKObjectRequest* request = (KKObjectRequest*)req;
+ KKBufferEvent* reply = (KKBufferEvent*)__rmonUtilityBuffer;
+
+ STUBBED_PRINTF(("GetExeName\n"));
+
+ reply->header.code = request->header.code;
+ reply->header.error = TV_ERROR_NO_ERROR;
+ reply->object = request->object;
+
+ if (req->method == RMON_RSP) {
+ strcpy(reply->buffer, "imem");
+ } else {
+ strcpy(reply->buffer, "rmon");
+ }
+ __rmonSendReply(&reply->header, sizeof(reply->header) + sizeof(reply->object) + 8, KK_TYPE_REPLY);
+
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonGetRegionCount(KKHeader* req) {
+ KKObjectRequest* request = (KKObjectRequest*)req;
+ KKNumberEvent reply;
+
+ STUBBED_PRINTF(("GetRegionCount\n"));
+
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->object;
+
+ reply.number = (req->method == RMON_RSP) ? 2 : 5;
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonGetRegions(KKHeader* req) {
+ KKObjectRequest* request = (KKObjectRequest*)req;
+ KKRegionEvent* reply = (KKRegionEvent*)__rmonUtilityBuffer;
+ int numRegions;
+
+ STUBBED_PRINTF(("GetRegions\n"));
+
+ numRegions = (req->method == RMON_RSP) ? 2 : 6;
+
+ reply->header.length = numRegions * sizeof(reply->regions[0]) + sizeof(*reply);
+ reply->header.code = request->header.code;
+ reply->header.error = TV_ERROR_NO_ERROR;
+ reply->object = request->object;
+ reply->number = numRegions;
+
+ reply->regions[1].vaddr = SP_IMEM_START;
+ reply->regions[1].size = SP_IMEM_END + 1 - SP_IMEM_START;
+ reply->regions[1].flags = 1 | 2 | 4;
+ reply->regions[1].paddr = SP_IMEM_START;
+
+ reply->regions[0].vaddr = SP_DMEM_START;
+ reply->regions[0].size = SP_DMEM_END + 1 - SP_DMEM_START;
+ reply->regions[0].flags = 1 | 2;
+ reply->regions[0].paddr = SP_DMEM_START;
+
+ if (numRegions > 2) {
+ reply->regions[2].vaddr = 0x88200000;
+ reply->regions[2].size = 0x6130;
+ reply->regions[2].flags = 1 | 4;
+ reply->regions[2].paddr = 0;
+
+ reply->regions[3].vaddr = 4;
+ reply->regions[3].size = 0x200000;
+ reply->regions[3].flags = 1 | 2;
+ reply->regions[3].paddr = 0;
+
+ reply->regions[4].vaddr = 0x4002000;
+ reply->regions[4].size = 0x800000;
+ reply->regions[4].flags = 1 | 2;
+ reply->regions[4].paddr = 0;
+
+ reply->regions[5].vaddr = 0x88206130;
+ reply->regions[5].size = 0x9000;
+ reply->regions[5].flags = 1 | 2;
+ reply->regions[5].paddr = 0;
+ }
+
+ __rmonSendReply(&reply->header, reply->header.length, KK_TYPE_REPLY);
+
+ return TV_ERROR_NO_ERROR;
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonmisc.c b/lib/ultralib/src/rmon/rmonmisc.c
new file mode 100644
index 0000000..0f9c4cd
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonmisc.c
@@ -0,0 +1,69 @@
+#ifndef _FINALROM
+
+#include "dbgproto.h"
+#include "PR/os_internal.h"
+#include "PR/sptask.h"
+#include "rmonint.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+OSMesgQueue __rmonMQ ALIGNED(8);
+
+int __rmonSetFault(KKHeader* req) {
+ KKFaultRequest* request = (KKFaultRequest*)req;
+ KKObjectEvent reply;
+
+ STUBBED_PRINTF(("SetFault\n"));
+
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->tid;
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+static OSThread rmonIOThread ALIGNED(8);
+static OSMesg rmonMsgs[8] ALIGNED(8);
+static u64 rmonIOStack[2048] ALIGNED(8);
+static OSMesg rmonPiMsgs[8] ALIGNED(8);
+static OSMesgQueue rmonPiMQ ALIGNED(8);
+
+void __rmonInit(void) {
+ osCreateMesgQueue(&__rmonMQ, rmonMsgs, ARRLEN(rmonMsgs));
+ osSetEventMesg(OS_EVENT_CPU_BREAK, &__rmonMQ, (OSMesg)RMON_MESG_CPU_BREAK);
+ osSetEventMesg(OS_EVENT_SP_BREAK, &__rmonMQ, (OSMesg)RMON_MESG_SP_BREAK);
+ osSetEventMesg(OS_EVENT_FAULT, &__rmonMQ, (OSMesg)RMON_MESG_FAULT);
+ osSetEventMesg(OS_EVENT_THREADSTATUS, &__rmonMQ, NULL);
+ osCreateThread(&rmonIOThread, 0, (void (*)(void*))__rmonIOhandler, NULL,
+ rmonIOStack + ARRLEN(rmonIOStack), OS_PRIORITY_MAX);
+ osCreatePiManager(OS_PRIORITY_PIMGR, &rmonPiMQ, rmonPiMsgs, ARRLEN(rmonPiMsgs));
+ osStartThread(&rmonIOThread);
+}
+
+void __rmonPanic(void) {
+ STUBBED_PRINTF(("PANIC!!\n"));
+
+ for (;;) {
+ ;
+ }
+}
+
+int __rmonSetComm(KKHeader* req) {
+ KKObjectEvent reply;
+
+ STUBBED_PRINTF(("SetComm\n"));
+
+ reply.header.code = req->code;
+ reply.object = 0;
+ reply.header.error = TV_ERROR_NO_ERROR;
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+
+ return TV_ERROR_NO_ERROR;
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonprint.c b/lib/ultralib/src/rmon/rmonprint.c
new file mode 100644
index 0000000..8ac91a5
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonprint.c
@@ -0,0 +1 @@
+/* Empty file */
diff --git a/lib/ultralib/src/rmon/rmonrcp.s b/lib/ultralib/src/rmon/rmonrcp.s
new file mode 100644
index 0000000..2128c9a
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonrcp.s
@@ -0,0 +1,59 @@
+#ifndef _FINALROM
+
+#include "sys/asm.h"
+#include "sys/regdef.h"
+#include "PR/rcp.h"
+#include "PR/R4300.h"
+
+.text
+
+/* check if the rsp is currently running by polling HALT or BROKE bits in SP_STATUS */
+LEAF(__rmonRCPrunning)
+ move v0, zero
+ lw t0, PHYS_TO_K1(SP_STATUS_REG)
+ and t0, SP_STATUS_HALT | SP_STATUS_BROKE
+ bnez t0, isHalted
+ ori v0, 1
+isHalted:
+ jr ra
+END(__rmonRCPrunning)
+
+/* stop the rsp, first wait for any ongoing dma to complete before setting HALT in SP_STATUS */
+LEAF(__rmonIdleRCP)
+ li a0, PHYS_TO_K1(SP_DMA_BUSY_REG)
+wait4dma:
+ lw v0, (a0)
+ bnez v0, wait4dma
+ li a1, SP_CLR_INTR_BREAK | SP_SET_HALT
+ li a0, PHYS_TO_K1(SP_STATUS_REG)
+ sw a1, (a0)
+
+/* wait for the rsp to stop */
+awaitIdle:
+ li a0, PHYS_TO_K1(SP_STATUS_REG)
+ lw v0, (a0)
+ and v0, SP_STATUS_HALT | SP_STATUS_BROKE
+ beqz v0, awaitIdle
+ jr ra
+END(__rmonIdleRCP)
+
+/* run the rsp in single-step mode to step one instruction */
+LEAF(__rmonStepRCP)
+ li a0, PHYS_TO_K1(SP_STATUS_REG)
+ li a1, SP_CLR_INTR_BREAK | SP_SET_SSTEP | SP_CLR_BROKE | SP_CLR_HALT
+ sw a1, (a0)
+ b awaitIdle
+END(__rmonStepRCP)
+
+/* run the rsp normally */
+LEAF(__rmonRunRCP)
+ li a0, PHYS_TO_K1(MI_INTR_MASK_REG)
+ li a1, MI_INTR_MASK_SET_SP
+ sw a1, (a0)
+ li a0, PHYS_TO_K1(SP_STATUS_REG)
+ li a1, SP_SET_INTR_BREAK | SP_CLR_SSTEP | SP_CLR_BROKE | SP_CLR_HALT
+ sw a1, (a0)
+ jr ra
+END(__rmonRunRCP)
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonregs.c b/lib/ultralib/src/rmon/rmonregs.c
new file mode 100644
index 0000000..d1e3af2
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonregs.c
@@ -0,0 +1,402 @@
+#ifndef _FINALROM
+
+#include "dbgproto.h"
+#include "PR/os_internal.h"
+#include "PR/rcp.h"
+#include "PR/sptask.h"
+#include "rmonint.h"
+#include "PR/rdb.h"
+
+#include "macros.h"
+
+// TODO: these come from headers
+#ident "$Revision: 1.4 $"
+#ident "$Revision: 3.70 $"
+#ident "$Revision: 1.5 $"
+#ident "$Revision: 1.2 $"
+#ident "$Revision: 1.4 $"
+
+static u32 RCPpc;
+static u32 oldIMEMvalue;
+static u32 DMEMbuffer[4];
+
+typedef union {
+ u32 everything;
+ struct {
+ int opcode : 6;
+ int base : 5;
+ int rt : 5;
+ int offset : 16;
+ } scalarop;
+ struct {
+ int opcode : 6;
+ int base : 5;
+ int rt : 5;
+ int size : 5;
+ int element : 4;
+ int offset : 7;
+ } vectorop;
+} INSTRUCTION;
+
+static void LoadStoreSU(int opcode, int regno) {
+ INSTRUCTION inst;
+
+ /* Prepare a scalar load or store instruction at DMEM address 0 */
+ inst.everything = 0;
+ inst.scalarop.opcode = opcode;
+ inst.scalarop.rt = regno;
+ __rmonWriteWordTo((u32*)SP_IMEM_START, inst.everything);
+ __rmonWriteWordTo((u32*)SP_PC_REG, 0);
+}
+
+static void LoadStoreVU(int opcode, int regno) {
+ INSTRUCTION inst;
+
+ /* Prepare a vector 128-bit load or store instruction at DMEM address 0 */
+ inst.everything = 0;
+ inst.vectorop.opcode = opcode;
+ inst.vectorop.rt = regno;
+ inst.vectorop.size = 4; /* LQV / SQV */
+ __rmonWriteWordTo((u32*)SP_IMEM_START, inst.everything);
+ __rmonWriteWordTo((u32*)SP_PC_REG, 0);
+}
+
+static void SetUpForRCPop(int isVector) {
+ /* Save RSP data that would be overwritten when reading or writing registers */
+ RCPpc = __rmonReadWordAt((u32*)SP_PC_REG);
+ oldIMEMvalue = __rmonReadWordAt((u32*)SP_IMEM_START);
+ DMEMbuffer[0] = __rmonReadWordAt((u32*)SP_DMEM_START);
+ if (isVector) {
+ DMEMbuffer[1] = __rmonReadWordAt((u32*)(SP_DMEM_START + 0x4));
+ DMEMbuffer[2] = __rmonReadWordAt((u32*)(SP_DMEM_START + 0x8));
+ DMEMbuffer[3] = __rmonReadWordAt((u32*)(SP_DMEM_START + 0xC));
+ }
+}
+
+static void CleanupFromRCPop(int isVector) {
+ /* Restore RSP data that was saved to read or write registers */
+ __rmonWriteWordTo((u32*)SP_DMEM_START, DMEMbuffer[0]);
+ if (isVector) {
+ __rmonWriteWordTo((u32*)(SP_DMEM_START + 0x4), DMEMbuffer[1]);
+ __rmonWriteWordTo((u32*)(SP_DMEM_START + 0x8), DMEMbuffer[2]);
+ /* BUG: the last word is not restored properly */
+ __rmonWriteWordTo((u32*)(SP_DMEM_START + 0xC), DMEMbuffer[2]);
+ }
+ __rmonWriteWordTo((u32*)SP_IMEM_START, oldIMEMvalue);
+ __rmonWriteWordTo((u32*)SP_PC_REG, RCPpc);
+}
+
+int __rmonGetGRegisters(KKHeader* req) {
+ register KKObjectRequest* request = (KKObjectRequest*)req;
+ KKGregEvent reply;
+
+ STUBBED_PRINTF(("GetGRegisters\n"));
+
+ reply.tid = request->object;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+
+ if (request->header.method == RMON_CPU) {
+ OSThread* tptr = __rmonGetTCB(request->object);
+ u64* tcbregptr;
+ register s32 i;
+
+ if (tptr == NULL) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ for (i = GREG_IDX_AT, tcbregptr = &tptr->context.at; i < GREG_IDX_K0; i++, tcbregptr++) {
+ reply.registers.gregs[i] = *tcbregptr;
+ }
+ for (i = GREG_IDX_GP, tcbregptr = &tptr->context.gp; i < GREG_IDX_CAUSE; i++, tcbregptr++) {
+ reply.registers.gregs[i] = *tcbregptr;
+ }
+
+ reply.registers.gregs[GREG_IDX_CAUSE] = tptr->context.cause;
+ reply.registers.gregs[GREG_IDX_PC] = tptr->context.pc;
+ reply.registers.gregs[GREG_IDX_SR] = tptr->context.sr;
+ reply.registers.gregs[GREG_IDX_ZERO] = 0;
+ } else {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonSetGRegisters(KKHeader* req) {
+ register KKGRegsetRequest* request = (KKGRegsetRequest*)req;
+ KKObjectEvent reply;
+
+ STUBBED_PRINTF(("SetGRegisters\n"));
+
+ if (request->header.method == RMON_CPU) {
+ OSThread* tptr = __rmonGetTCB(request->tid);
+ u64* tcbregptr;
+ register int i;
+
+ if (tptr == NULL) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ for (i = GREG_IDX_AT, tcbregptr = &tptr->context.at; i < GREG_IDX_K0; i++, tcbregptr++) {
+ *tcbregptr = (s32)request->registers.gregs[i];
+ }
+
+ for (i = GREG_IDX_GP, tcbregptr = &tptr->context.gp; i < GREG_IDX_CAUSE; i++, tcbregptr++) {
+ *tcbregptr = (s32)request->registers.gregs[i];
+ }
+
+ tptr->context.cause = request->registers.gregs[GREG_IDX_CAUSE];
+ tptr->context.pc = request->registers.gregs[GREG_IDX_PC];
+ tptr->context.sr = request->registers.gregs[GREG_IDX_SR];
+ } else {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ reply.object = request->tid;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonGetFRegisters(KKHeader* req) {
+ register KKObjectRequest* request = (KKObjectRequest*)req;
+ KKFPregEvent reply;
+ OSThread* tptr;
+ volatile float f UNUSED;
+
+ STUBBED_PRINTF(("GetFRegisters\n"));
+
+ if (req->method != RMON_CPU) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ /* touch fpu to ensure registers are saved to the context structure */
+ f = 0.0f;
+
+ tptr = __rmonGetTCB(request->object);
+ if (tptr == NULL) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ __rmonCopyWords((u32*)reply.registers.fpregs.regs, (u32*)&tptr->context.fp0, ARRLEN(reply.registers.fpregs.regs));
+
+ reply.registers.fpcsr = tptr->context.fpcsr;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.tid = request->object;
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+
+}
+
+int __rmonSetFRegisters(KKHeader* req) {
+ register KKFPRegsetRequest* request = (KKFPRegsetRequest*)req;
+ KKObjectEvent reply;
+ OSThread* tptr;
+ volatile float f UNUSED;
+
+ STUBBED_PRINTF(("SetFRegisters\n"));
+
+ if (req->method != RMON_CPU) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ /* touch fpu to ensure registers are saved to the context structure */
+ f = 0.0f;
+
+ tptr = __rmonGetTCB(request->tid);
+ if (tptr == NULL) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ __rmonCopyWords((u32*)&tptr->context.fp0, (u32*)request->registers.fpregs.regs, ARRLEN(request->registers.fpregs.regs));
+ tptr->context.fpcsr = request->registers.fpcsr;
+
+ reply.object = request->tid;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+static u32 rmonGetRcpRegister(int regNumber) {
+ u32 contents;
+
+ if (__rmonRCPrunning()) {
+ return 0;
+ }
+
+ SetUpForRCPop(FALSE);
+ LoadStoreSU(MIPS_SW_OPCODE, regNumber);
+ __rmonStepRCP();
+ contents = __rmonReadWordAt((u32*)SP_DMEM_START);
+ CleanupFromRCPop(FALSE);
+
+ return contents;
+
+}
+
+int __rmonGetSRegs(KKHeader* req) {
+ register KKObjectRequest* request = (KKObjectRequest*)req;
+ KKCpSregEvent reply;
+ register int i;
+
+ STUBBED_PRINTF(("GetSRegisters\n"));
+
+ if (__rmonRCPrunning()) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+
+ reply.tid = request->object;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+
+ SetUpForRCPop(FALSE);
+ for (i = SREG_IDX_ZERO; i <= SREG_IDX_RA; i++) {
+ LoadStoreSU(MIPS_SW_OPCODE, i);
+ __rmonStepRCP();
+ reply.registers.sregs[i] = __rmonReadWordAt((u32*)SP_DMEM_START);
+ }
+ CleanupFromRCPop(FALSE);
+
+ reply.registers.sregs[SREG_IDX_DRAM_ADDR] = __rmonReadWordAt((u32*)SP_DRAM_ADDR_REG);
+ reply.registers.sregs[SREG_IDX_MEM_ADDR] = __rmonReadWordAt((u32*)SP_MEM_ADDR_REG);
+ reply.registers.sregs[SREG_IDX_RD_LEN] = __rmonReadWordAt((u32*)SP_RD_LEN_REG);
+ reply.registers.sregs[SREG_IDX_PC] = __rmonReadWordAt((u32*)SP_PC_REG) + SP_IMEM_START;
+ reply.registers.sregs[SREG_IDX_WR_LEN] = __rmonReadWordAt((u32*)SP_WR_LEN_REG);
+ reply.registers.sregs[SREG_IDX_STATUS] = __rmonReadWordAt((u32*)SP_STATUS_REG);
+ reply.registers.sregs[SREG_IDX_DMA_FULL] = __rmonReadWordAt((u32*)SP_DMA_FULL_REG);
+ reply.registers.sregs[SREG_IDX_DMA_BUSY] = __rmonReadWordAt((u32*)SP_DMA_BUSY_REG);
+
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonSetSRegs(KKHeader* req) {
+ register KKCpScalarRegsetRequest* request = (KKCpScalarRegsetRequest*)req;
+ KKObjectEvent reply;
+ register int i;
+
+ STUBBED_PRINTF(("SetSRegisters\n"));
+
+ if (__rmonRCPrunning()) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+
+ SetUpForRCPop(FALSE);
+ for (i = SREG_IDX_ZERO; i <= SREG_IDX_RA; i++) {
+ __rmonWriteWordTo((u32*)SP_DMEM_START, request->registers.sregs[i]);
+ LoadStoreSU(MIPS_LW_OPCODE, i);
+ __rmonStepRCP();
+ }
+ CleanupFromRCPop(FALSE);
+
+ __rmonWriteWordTo((u32*)SP_DRAM_ADDR_REG, request->registers.sregs[SREG_IDX_DRAM_ADDR]);
+ __rmonWriteWordTo((u32*)SP_MEM_ADDR_REG, request->registers.sregs[SREG_IDX_MEM_ADDR]);
+ __rmonWriteWordTo((u32*)SP_PC_REG, request->registers.sregs[SREG_IDX_PC] & 0xFFF);
+ __rmonWriteWordTo((u32*)SP_WR_LEN_REG, request->registers.sregs[SREG_IDX_WR_LEN]);
+ __rmonWriteWordTo((u32*)SP_STATUS_REG, request->registers.sregs[SREG_IDX_STATUS]);
+
+ reply.object = request->tid;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonGetVRegs(KKHeader* req) {
+ char* cPtr;
+ int sent;
+ int dataSize;
+ register KKObjectRequest* request = (KKObjectRequest*)req;
+ KKCpVregEvent reply;
+ register int i;
+
+ STUBBED_PRINTF(("GetVRegisters\n"));
+
+ if (__rmonRCPrunning()) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+
+ reply.tid = request->object;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.header.length = sizeof(reply);
+
+ dataSize = sizeof(reply);
+ cPtr = (char*)&dataSize;
+ sent = 0;
+ while (sent < (signed)sizeof(dataSize)) {
+ sent += __osRdbSend(cPtr + sent, sizeof(dataSize) - sent, RDB_TYPE_GtoH_DEBUG);
+ }
+
+ __rmonSendHeader(&reply.header, VREG_SIZE, KK_TYPE_REPLY);
+
+ SetUpForRCPop(TRUE);
+ for (i = 0; i < VREG_NUM; i++) {
+ LoadStoreVU(MIPS_SWC2_OPCODE, i);
+ __rmonStepRCP();
+ __rmonSendData((void*)SP_DMEM_START, VREG_SIZE);
+ }
+ CleanupFromRCPop(TRUE);
+
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonSetVRegs(KKHeader* req) {
+ register KKCpVectorRegsetRequest* request = (KKCpVectorRegsetRequest*)req;
+ KKObjectEvent reply;
+ register int i;
+
+ STUBBED_PRINTF(("SetVRegs\n"));
+
+ if (__rmonRCPrunning()) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+
+ SetUpForRCPop(TRUE);
+ for (i = 0; i < VREG_NUM; i++) {
+ __rmonCopyWords((u32*)SP_DMEM_START, (u32*)&request->registers.vregs[i], VREG_SIZE / sizeof(u32));
+ LoadStoreVU(MIPS_LWC2_OPCODE, i);
+ __rmonStepRCP();
+ }
+ CleanupFromRCPop(TRUE);
+
+ reply.object = request->tid;
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+u32 __rmonGetRegisterContents(int method, int threadNumber, int regNumber) {
+ if (method == RMON_CPU) {
+ /* CPU register */
+ u32* regPointer;
+ OSThread* tptr;
+
+ if (regNumber >= GREG_IDX_AT && regNumber < GREG_IDX_K0) {
+ regNumber -= GREG_IDX_AT - GREG_IDX_ZERO;
+ } else if (regNumber >= GREG_IDX_GP && regNumber < GREG_IDX_LO) {
+ regNumber -= GREG_IDX_GP - GREG_IDX_T9;
+ } else {
+ return 0;
+ }
+ tptr = __rmonGetTCB(threadNumber);
+ if (tptr == NULL) {
+ return 0;
+ }
+ regPointer = (u32*)&tptr->context;
+ regPointer += regNumber;
+ return *regPointer;
+ } else {
+ /* RSP register */
+ return rmonGetRcpRegister(regNumber);
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmonsio.c b/lib/ultralib/src/rmon/rmonsio.c
new file mode 100644
index 0000000..ffeca17
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmonsio.c
@@ -0,0 +1,77 @@
+#ifndef _FINALROM
+
+#include "PR/os_internal.h"
+#include "PR/ultraerror.h"
+#include "PR/ultralog.h"
+#include "PR/sptask.h"
+#include "dbgproto.h"
+#include "rmonint.h"
+#include "PR/ramrom.h"
+#include "PR/rdb.h"
+#include "PR/rmon.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+static OSMesgQueue IOmq;
+static OSMesg IOmsgs;
+
+void* __osRdb_DbgRead_Buf;
+u8 rmonRdbReadBuf[RMON_DBG_BUF_SIZE] ALIGNED(0x10);
+
+void __rmonSendFault(OSThread* thread) {
+ volatile float f UNUSED;
+ u8* tPtr;
+ u32 sent = 0;
+
+ /* touch fpu to ensure registers are saved to the context structure */
+ f = 0.0f;
+
+ tPtr = (u8*)thread;
+ while (sent < sizeof(OSThread)) {
+ sent += __osRdbSend(tPtr + sent, sizeof(OSThread) - sent, RDB_TYPE_GtoH_FAULT);
+ }
+}
+
+void __rmonIOflush(void) {
+ int sent = 0;
+ char tstr[4];
+
+ while (sent <= 0) {
+ sent += __osRdbSend(tstr, 1, RDB_TYPE_GtoH_DEBUG_DONE);
+ }
+}
+
+void __rmonIOputw(u32 word) {
+ int sent = 0;
+ char* cPtr = (char*)&word;
+
+ while (sent < 4) {
+ sent += __osRdbSend(cPtr + sent, sizeof(word) - sent, RDB_TYPE_GtoH_DEBUG);
+ }
+}
+
+void __rmonIOhandler(void) {
+ int sent;
+ char tstr[4];
+
+ osCreateMesgQueue(&IOmq, &IOmsgs, 1);
+ osSetEventMesg(OS_EVENT_RDB_DBG_DONE, &IOmq, NULL);
+ __osRdb_DbgRead_Buf = rmonRdbReadBuf;
+
+ while (TRUE) {
+ osRecvMesg(&IOmq, NULL, OS_MESG_BLOCK);
+
+ __rmonExecute((KKHeader*)&rmonRdbReadBuf);
+ __osRdb_DbgRead_Buf = rmonRdbReadBuf;
+
+ sent = 0;
+ while (sent <= 0) {
+ sent += __osRdbSend(tstr, 1, RDB_TYPE_GtoH_DEBUG_READY);
+ }
+ }
+}
+
+#endif
diff --git a/lib/ultralib/src/rmon/rmontask.c b/lib/ultralib/src/rmon/rmontask.c
new file mode 100644
index 0000000..8728374
--- /dev/null
+++ b/lib/ultralib/src/rmon/rmontask.c
@@ -0,0 +1,332 @@
+#ifndef _FINALROM
+
+#include "dbgproto.h"
+#include "PR/os_internal.h"
+#include "rmonint.h"
+#include "PR/rcp.h"
+#include "sptask.h"
+
+#include "macros.h"
+
+// TODO: this comes from a header
+#ident "$Revision: 1.4 $"
+
+void __rmonMaskIdleThreadInts(void) {
+ register OSThread* tptr = __osGetActiveQueue();
+
+ while (tptr->priority != -1) {
+ if (tptr->priority == OS_PRIORITY_IDLE) {
+ tptr->context.sr &= ~OS_IM_CPU;
+ tptr->context.sr |= (OS_IM_RDBREAD | OS_IM_RDBWRITE | OS_IM_CART);
+ break;
+ }
+ tptr = tptr->tlnext;
+ }
+}
+
+OSThread* __rmonGetTCB(int threadNumber) {
+ register OSThread* tptr = __osGetActiveQueue();
+
+ if (threadNumber < 1) {
+ return NULL;
+ }
+
+ while (tptr->priority != -1) {
+ if (tptr->id == threadNumber) {
+ return tptr;
+ }
+ tptr = tptr->tlnext;
+ }
+
+ return NULL;
+}
+
+int __rmonStopUserThreads(int whichThread) {
+ register int whichOne = 0;
+ register OSThread* tptr = __osGetActiveQueue();
+
+ STUBBED_PRINTF(("StopThreads %d\n", whichThread));
+
+ if (whichThread != 0) {
+ /* Stop specified thread */
+
+ while (tptr->priority != -1) {
+ if (tptr->id == whichThread) {
+ break;
+ }
+ tptr = tptr->tlnext;
+ }
+
+ if (tptr->priority == -1) {
+ return 0;
+ }
+
+ if (tptr->priority > OS_PRIORITY_IDLE && tptr->priority <= OS_PRIORITY_APPMAX) {
+ osStopThread(tptr);
+ if (tptr->state != OS_STATE_STOPPED) {
+ STUBBED_PRINTF(("Couldn't stop thread %d\n", tptr->id));
+ }
+ whichOne = whichThread;
+ }
+ } else {
+ /* Stop all threads */
+
+ while (tptr->priority != -1) {
+ if (tptr->priority > OS_PRIORITY_IDLE && tptr->priority <= OS_PRIORITY_APPMAX) {
+ osStopThread(tptr);
+ if (tptr->state != OS_STATE_STOPPED) {
+ STUBBED_PRINTF(("Couldn\'t stop thread %d\n", tptr->id));
+ }
+ whichOne = -1;
+ }
+ tptr = tptr->tlnext;
+ }
+ }
+ return whichOne;
+}
+
+int __rmonListThreads(KKHeader* req) {
+ register KKObjectRequest* request = (KKObjectRequest*)req;
+ KKObjsEvent* reply = (KKObjsEvent*)__rmonUtilityBuffer;
+
+ STUBBED_PRINTF(("ListThreads\n"));
+
+ reply->object = (request->object == -1) ? RMON_PID_CPU : request->object;
+
+ if (req->method == RMON_RSP) {
+ reply->objs.number = 1;
+ reply->objs.objects[0] = RMON_TID_RSP;
+ } else {
+ register OSThread* tptr = __osGetActiveQueue();
+
+ reply->objs.number = 0;
+
+ while (tptr->priority != -1) {
+ if (tptr->id != 0) {
+ reply->objs.objects[reply->objs.number] = tptr->id;
+ reply->objs.number++;
+ }
+ tptr = tptr->tlnext;
+ }
+ }
+ reply->header.code = request->header.code;
+ reply->header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply->header, sizeof(*reply) + sizeof(reply->objs.objects[0]) * (reply->objs.number - 1), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonGetThreadStatus(int method, int id, KKStatusEvent* reply) {
+ u32 inst;
+
+ STUBBED_PRINTF(("ThreadStatus %d method %d\n", id, method));
+
+ reply->status.tid = id;
+ reply->status.pid = (method == RMON_RSP) ? RMON_PID_RSP : RMON_PID_CPU;
+ reply->status.why = 1;
+ reply->status.what = 0;
+ reply->status.info.major = 0;
+ reply->status.info.minor = 0;
+ reply->status.rv = 0;
+
+ if (method == RMON_RSP) {
+ reply->status.start = SP_IMEM_START;
+ reply->status.priority = RMON_PRI_RSP;
+
+ if (__rmonRCPrunning()) {
+ reply->status.flags = OS_STATE_RUNNING;
+ /* Cannot read RSP PC or current instruction while the RSP is running */
+ reply->status.info.addr = 0;
+ reply->status.instr = 0;
+ } else {
+ reply->status.flags = OS_STATE_STOPPED;
+ reply->status.info.addr = __rmonReadWordAt((u32*)SP_PC_REG) + SP_IMEM_START;
+ inst = __rmonReadWordAt((u32*)reply->status.info.addr);
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ inst = MIPS_BREAK_OPCODE;
+ }
+ if (__rmonRcpAtBreak) {
+ /* Report RSP break */
+ reply->status.why = 2;
+ reply->status.info.major = 2;
+ reply->status.info.minor = 4;
+ }
+ reply->status.instr = inst;
+ }
+ } else {
+ OSThread* tptr = __osGetActiveQueue();
+
+ while (tptr->priority != -1) {
+ if (tptr->id == id) {
+ break;
+ }
+ tptr = tptr->tlnext;
+ }
+ if (tptr->priority == -1) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ reply->status.priority = tptr->priority;
+ reply->status.flags = (tptr->state != 0) ? tptr->state : OS_STATE_STOPPED;
+ reply->status.info.addr = tptr->context.pc;
+
+ inst = *(u32*)(tptr->context.pc);
+ if ((inst & MIPS_BREAK_MASK) == MIPS_BREAK_OPCODE) {
+ inst = MIPS_BREAK_OPCODE;
+ }
+
+ reply->status.instr = inst;
+ reply->status.start = (int)tptr;
+
+ if (tptr->flags & OS_FLAG_CPU_BREAK) {
+ /* Report break */
+ reply->status.why = 2;
+ reply->status.info.major = 2;
+ reply->status.info.minor = 4;
+ } else if (tptr->flags & OS_FLAG_FAULT) {
+ /* Report fault */
+ reply->status.why = 2;
+ reply->status.info.major = 1;
+ reply->status.info.minor = 2;
+ }
+ }
+
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonThreadStatus(KKHeader* req) {
+ KKObjectRequest* request = (KKObjectRequest*)req;
+ KKStatusEvent reply;
+
+ if (__rmonGetThreadStatus(req->method, request->object, &reply) != TV_ERROR_NO_ERROR) {
+ return TV_ERROR_INVALID_ID;
+ }
+
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ return TV_ERROR_NO_ERROR;
+}
+
+int __rmonStopThread(KKHeader* req) {
+ KKObjectRequest* request = (KKObjectRequest*)req;
+ KKStatusEvent reply;
+ u32* pc;
+
+ STUBBED_PRINTF(("StopThread %d\n", request->object));
+
+ switch (req->method) {
+ case RMON_CPU:
+ __rmonStopUserThreads(request->object);
+ break;
+ case RMON_RSP:
+ if (__rmonRCPrunning()) {
+ /* Stop the rsp */
+ __rmonIdleRCP();
+ pc = (u32*)__rmonReadWordAt((u32*)SP_PC_REG);
+ if (pc == NULL) {
+ break;
+ }
+ pc--;
+ /* Check if the RSP is stopped in a branch delay slot, if it is step out of it. The RSP would otherwise
+ lose information about whether the branch should or should not be taken when reading registers. */
+ if (__rmonGetBranchTarget(RMON_RSP, RMON_TID_RSP, (void*)((u32)pc + SP_IMEM_START)) % 4 == 0) {
+ __rmonStepRCP();
+ }
+ }
+ break;
+ default:
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+
+ if (__rmonGetThreadStatus(req->method, request->object, &reply) != TV_ERROR_NO_ERROR) {
+ return TV_ERROR_INVALID_ID;
+ }
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ if (reply.status.flags == OS_STATE_STOPPED) {
+ reply.header.code = KK_CODE_THREAD_STATUS;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_EXCEPTION);
+ }
+ return TV_ERROR_NO_ERROR;
+
+}
+
+int __rmonRunThread(KKHeader* req) {
+ KKRunThreadRequest* request = (KKRunThreadRequest*)req;
+ KKObjectEvent reply;
+ KKStatusEvent exceptionReply;
+ register OSThread* tptr;
+ register int runNeeded = FALSE;
+
+ STUBBED_PRINTF(("RunThread %d\n", request->tid));
+
+ switch (req->method) {
+ case RMON_CPU:
+ tptr = __osGetActiveQueue();
+ while (tptr->priority != -1) {
+ if (tptr->id == request->tid) {
+ break;
+ }
+ tptr = tptr->tlnext;
+ }
+
+ if (tptr->priority == -1) {
+ return TV_ERROR_INVALID_ID;
+ }
+ if (tptr->state != OS_STATE_STOPPED) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+ tptr->flags &= ~(OS_FLAG_CPU_BREAK | OS_FLAG_FAULT);
+ if (request->actions.flags & KK_RUN_SETPC) {
+ tptr->context.pc = request->actions.vaddr;
+ }
+ if ((request->actions.flags & KK_RUN_SSTEP) && !__rmonSetSingleStep(request->tid, (u32*)tptr->context.pc)) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+ runNeeded = TRUE;
+ break;
+ case RMON_RSP:
+ if (__rmonRCPrunning()) {
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+ if (request->actions.flags & KK_RUN_SETPC) {
+ __rmonWriteWordTo((u32*)SP_PC_REG, request->actions.vaddr - SP_IMEM_START);
+ }
+ if (request->actions.flags & KK_RUN_SSTEP) {
+ /* If the RSP is stopped at a branch step twice so as to not stop in a branch delay slot. */
+ if (__rmonGetBranchTarget(RMON_RSP, RMON_TID_RSP, (void*)(__rmonReadWordAt((u32*)SP_PC_REG) + SP_IMEM_START)) % 4 == 0) {
+ __rmonStepRCP();
+ }
+ __rmonStepRCP();
+ __rmonRcpAtBreak = TRUE;
+ } else {
+ __rmonRcpAtBreak = FALSE;
+ __rmonRunRCP();
+ }
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->tid;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+ if (request->actions.flags & KK_RUN_SSTEP) {
+ __rmonGetThreadStatus(RMON_RSP, RMON_TID_RSP, &exceptionReply);
+ __rmonGetExceptionStatus(&exceptionReply);
+ __rmonSendReply(&exceptionReply.header, sizeof(exceptionReply), KK_TYPE_EXCEPTION);
+ }
+ return TV_ERROR_NO_ERROR;
+ default:
+ return TV_ERROR_OPERATIONS_PROTECTED;
+ }
+
+ reply.header.code = request->header.code;
+ reply.header.error = TV_ERROR_NO_ERROR;
+ reply.object = request->tid;
+ __rmonSendReply(&reply.header, sizeof(reply), KK_TYPE_REPLY);
+
+ if (runNeeded) {
+ osStartThread(tptr);
+ }
+ return 1;
+}
+
+#endif
diff --git a/lib/ultralib/src/sched/Makefile b/lib/ultralib/src/sched/Makefile
new file mode 100644
index 0000000..d4cd659
--- /dev/null
+++ b/lib/ultralib/src/sched/Makefile
@@ -0,0 +1,19 @@
+#!smake
+#
+# Makefile for the scheduler subdirectory
+#
+
+include $(ROOT)/usr/include/make/PRdefs
+
+
+# LCOPTS = -mips2 -non_shared -fullwarn -G 0
+LCINCS = -I. -I$(ROOT)/usr/include/PR -I$(ROOT)/usr/include
+
+CFILES = \
+ sched.c
+
+OBJECTS = $(CFILES:.c=.o)
+
+default: $(OBJECTS)
+
+include $(COMMONRULES)
diff --git a/lib/ultralib/src/sched/sched.c b/lib/ultralib/src/sched/sched.c
new file mode 100644
index 0000000..7cf59dd
--- /dev/null
+++ b/lib/ultralib/src/sched/sched.c
@@ -0,0 +1,623 @@
+/*====================================================================
+ *
+ * Copyright 1995, Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
+ * Inc.; the contents of this file may not be disclosed to third
+ * parties, copied or duplicated in any form, in whole or in part,
+ * without the prior written permission of Silicon Graphics, Inc.
+ *
+ * RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to
+ * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS
+ * 252.227-7013, and/or in similar or successor clauses in the FAR,
+ * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
+ * Copyright Laws of the United States.
+ *====================================================================*/
+
+#include <ultralog.h>
+#include <assert.h>
+#include <sched.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+/*
+ * private typedefs and defines
+ */
+#define VIDEO_MSG 666
+#define RSP_DONE_MSG 667
+#define RDP_DONE_MSG 668
+#define PRE_NMI_MSG 669
+
+/*
+ * OSScTask state
+ */
+#define OS_SC_DP 0x0001 /* set if still needs dp */
+#define OS_SC_SP 0x0002 /* set if still needs sp */
+#define OS_SC_YIELD 0x0010 /* set if yield requested */
+#define OS_SC_YIELDED 0x0020 /* set if yield completed */
+
+/*
+ * OSScTask->flags type identifier
+ */
+#define OS_SC_XBUS (OS_SC_SP | OS_SC_DP)
+#define OS_SC_DRAM (OS_SC_SP | OS_SC_DP | OS_SC_DRAM_DLIST)
+#define OS_SC_DP_XBUS (OS_SC_SP)
+#define OS_SC_DP_DRAM (OS_SC_SP | OS_SC_DRAM_DLIST)
+#define OS_SC_SP_XBUS (OS_SC_DP)
+#define OS_SC_SP_DRAM (OS_SC_DP | OS_SC_DRAM_DLIST)
+
+/*
+ * private functions
+ */
+static void __scMain(void *arg);
+static void __scHandleRetrace(OSSched *s);
+static void __scHandleRSP(OSSched *s);
+static void __scHandleRDP(OSSched *s);
+
+static void __scAppendList(OSSched *s, OSScTask *t);
+OSScTask *__scTaskReady(OSScTask *t);
+static s32 __scTaskComplete(OSSched *s,OSScTask *t);
+static void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp);
+static void __scYield(OSSched *s);
+static s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp,
+ s32 availRCP);
+
+
+/*
+#define SC_LOGGING 1
+*/
+
+
+#ifdef SC_LOGGING
+#define SC_LOG_LEN 32*1024
+static OSLog scLog;
+static OSLog *l = &scLog;
+static u32 logArray[SC_LOG_LEN/sizeof(u32)];
+#endif
+
+/***********************************************************************
+ * Scheduler API
+ **********************************************************************/
+void osCreateScheduler(OSSched *sc, void *stack, OSPri priority,
+ u8 mode, u8 numFields)
+{
+ sc->curRSPTask = 0;
+ sc->curRDPTask = 0;
+ sc->clientList = 0;
+ sc->frameCount = 0;
+ sc->audioListHead = 0;
+ sc->gfxListHead = 0;
+ sc->audioListTail = 0;
+ sc->gfxListTail = 0;
+ sc->retraceMsg.type = OS_SC_RETRACE_MSG; /* sent to apps */
+ sc->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
+
+ osCreateMesgQueue(&sc->interruptQ, sc->intBuf, OS_SC_MAX_MESGS);
+ osCreateMesgQueue(&sc->cmdQ, sc->cmdMsgBuf, OS_SC_MAX_MESGS);
+
+ /*
+ * Set up video manager, listen for Video, RSP, and RDP interrupts
+ */
+ osCreateViManager(OS_PRIORITY_VIMGR);
+ osViSetMode(&osViModeTable[mode]);
+ osViBlack(TRUE);
+ osSetEventMesg(OS_EVENT_SP, &sc->interruptQ, (OSMesg)RSP_DONE_MSG);
+ osSetEventMesg(OS_EVENT_DP, &sc->interruptQ, (OSMesg)RDP_DONE_MSG);
+ osSetEventMesg(OS_EVENT_PRENMI, &sc->interruptQ, (OSMesg)PRE_NMI_MSG);
+
+ osViSetEvent(&sc->interruptQ, (OSMesg)VIDEO_MSG, numFields);
+
+#ifdef SC_LOGGING
+ osCreateLog(l, logArray, sizeof(logArray));
+#endif
+
+ osCreateThread(&sc->thread, 4, __scMain, (void *)sc, stack, priority);
+ osStartThread(&sc->thread);
+}
+
+/*
+ * Add a client to the scheduler. Clients receive messages at retrace time
+ */
+void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ)
+{
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ c->msgQ = msgQ;
+ c->next = sc->clientList;
+ sc->clientList = c;
+
+ osSetIntMask(mask);
+}
+
+void osScRemoveClient(OSSched *sc, OSScClient *c)
+{
+ OSScClient *client = sc->clientList;
+ OSScClient *prev = 0;
+ OSIntMask mask;
+
+ mask = osSetIntMask(OS_IM_NONE);
+
+ while (client != 0) {
+ if (client == c) {
+ if(prev)
+ prev->next = c->next;
+ else
+ sc->clientList = c->next;
+ break;
+ }
+ prev = client;
+ client = client->next;
+ }
+
+ osSetIntMask(mask);
+}
+
+OSMesgQueue *osScGetCmdQ(OSSched *sc)
+{
+ return &sc->cmdQ;
+}
+
+/***********************************************************************
+ * Scheduler implementation
+ **********************************************************************/
+static void __scMain(void *arg)
+{
+ OSMesg msg;
+ OSSched *sc = (OSSched *)arg;
+ OSScClient *client;
+ static int count = 0;
+
+ while (1) {
+
+ osRecvMesg(&sc->interruptQ, (OSMesg *)&msg, OS_MESG_BLOCK);
+
+#ifdef SC_LOGGING
+ if (++count % 1024 == 0)
+ osFlushLog(l);
+#endif
+
+
+ switch ((int) msg) {
+ case (VIDEO_MSG):
+ __scHandleRetrace(sc);
+ break;
+
+ case (RSP_DONE_MSG):
+ __scHandleRSP(sc);
+ break;
+
+ case (RDP_DONE_MSG):
+ __scHandleRDP(sc);
+ break;
+
+ case (PRE_NMI_MSG):
+ /*
+ * notify audio and graphics threads to fade out
+ */
+ for (client = sc->clientList;client != 0;client = client->next) {
+ osSendMesg(client->msgQ, (OSMesg) &sc->prenmiMsg,
+ OS_MESG_NOBLOCK);
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * scHandleRetrace()
+ */
+static int dp_busy = 0;
+static int dpCount = 0;
+
+void __scHandleRetrace(OSSched *sc)
+{
+ OSScTask *rspTask;
+ OSScClient *client;
+ s32 i;
+ s32 state;
+ OSScTask *sp = 0;
+ OSScTask *dp = 0;
+
+ sc->frameCount++;
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 500, 4, sc->frameCount, sc->curRSPTask, sc->curRDPTask);
+#endif
+
+ /*
+ * Read the task command queue and schedule tasks
+ */
+ while (osRecvMesg(&sc->cmdQ, (OSMesg *)&rspTask, OS_MESG_NOBLOCK) != -1) {
+ __scAppendList(sc, rspTask);
+ }
+
+ if (sc->doAudio && sc->curRSPTask) {
+ /*
+ * Preempt the running gfx task. Note: if the RSP
+ * component of the graphics task has finished, but the
+ * RDP component is still running, we can start an audio
+ * task which will freeze the RDP (and save the RDP cmd
+ * FIFO) while the audio RSP code is running.
+ */
+ __scYield(sc);
+ } else {
+ state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0);
+ if ( __scSchedule (sc, &sp, &dp, state) != state)
+ __scExec(sc, sp, dp);
+ }
+
+ /*
+ * notify audio and graphics threads to start building the command
+ * lists for the next frame (client threads may choose not to
+ * build the list in overrun case)
+ */
+ for (client = sc->clientList; client != 0; client = client->next) {
+ osSendMesg(client->msgQ, (OSMesg) &sc->retraceMsg, OS_MESG_NOBLOCK);
+ }
+}
+
+/*
+ * __scHandleRSP is called when an RSP task signals that it has
+ * finished or yielded (at the hosts request)
+ */
+void __scHandleRSP(OSSched *sc)
+{
+ OSScTask *t, *sp = 0, *dp = 0;
+ s32 state;
+
+
+ assert(sc->curRSPTask);
+
+ t = sc->curRSPTask;
+ sc->curRSPTask = 0;
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 510, 3, t, t->state, t->flags);
+#endif
+
+ if ((t->state & OS_SC_YIELD) && osSpTaskYielded(&t->list)) {
+ t->state |= OS_SC_YIELDED;
+#ifndef _FINALROM
+ t->totalTime += osGetTime() - t->startTime;
+#endif
+ if ((t->flags & OS_SC_TYPE_MASK) == OS_SC_XBUS) {
+ /* push the task back on the list */
+ t->next = sc->gfxListHead;
+ sc->gfxListHead = t;
+ if (sc->gfxListTail == 0)
+ sc->gfxListTail = t;
+ }
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 521, 1, t);
+#endif
+
+ } else {
+ t->state &= ~OS_SC_NEEDS_RSP;
+ __scTaskComplete(sc, t);
+ }
+
+ state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0);
+ if ( (__scSchedule (sc, &sp, &dp, state)) != state)
+ __scExec(sc, sp, dp);
+}
+
+/*
+ * __scHandleRDP is called when an RDP task signals that it has
+ * finished
+ */
+void __scHandleRDP(OSSched *sc)
+{
+ OSScTask *t, *sp = 0, *dp = 0;
+ s32 state;
+
+ assert(sc->curRDPTask);
+ assert(sc->curRDPTask->list.t.type == M_GFXTASK);
+
+ t = sc->curRDPTask;
+ sc->curRDPTask = 0;
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 515, 3, t, t->state, t->flags);
+#endif
+
+ t->state &= ~OS_SC_NEEDS_RDP;
+
+ __scTaskComplete(sc, t);
+
+ state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0);
+ if ( (__scSchedule (sc, &sp, &dp, state)) != state)
+ __scExec(sc, sp, dp);
+}
+
+/*
+ * __scTaskReady checks to see if the graphics task is able to run
+ * based on the current state of the RCP.
+ */
+OSScTask *__scTaskReady(OSScTask *t)
+{
+ int rv = 0;
+ void *a;
+ void *b;
+
+ if (t) {
+ /*
+ * If there is a pending swap bail out til later (next
+ * retrace).
+ */
+ if ((a=osViGetCurrentFramebuffer()) != (b=osViGetNextFramebuffer())) {
+#ifdef SC_LOGGING
+ osLogEvent(l, 513, 2, a, b);
+#endif
+ return 0;
+ }
+
+ return t;
+ }
+
+ return 0;
+}
+
+/*
+ * __scTaskComplete checks to see if the task is complete (all RCP
+ * operations have been performed) and sends the done message to the
+ * client if it is.
+ */
+s32 __scTaskComplete(OSSched *sc, OSScTask *t)
+{
+ int rv;
+ static int firsttime = 1;
+
+ if ((t->state & OS_SC_RCP_MASK) == 0) { /* none of the needs bits set */
+
+ assert (t->msgQ);
+
+#ifndef _FINALROM
+ t->totalTime += osGetTime() - t->startTime;
+#endif
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 504, 1, t);
+#endif
+ rv = osSendMesg(t->msgQ, t->msg, OS_MESG_BLOCK);
+
+ if (t->list.t.type == M_GFXTASK) {
+ if ((t->flags & OS_SC_SWAPBUFFER) && (t->flags & OS_SC_LAST_TASK)){
+ if (firsttime) {
+ osViBlack(FALSE);
+ firsttime = 0;
+ }
+ osViSwapBuffer(t->framebuffer);
+#ifdef SC_LOGGING
+ osLogEvent(l, 525, 1, t->framebuffer);
+#endif
+ }
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Place task on either the audio or graphics queue
+ */
+void __scAppendList(OSSched *sc, OSScTask *t)
+{
+ long type = t->list.t.type;
+
+ assert ( (type == M_AUDTASK) || (type == M_GFXTASK));
+
+ if (type == M_AUDTASK) {
+ if (sc->audioListTail)
+ sc->audioListTail->next = t;
+ else
+ sc->audioListHead = t;
+
+ sc->audioListTail = t;
+ sc->doAudio = 1;
+#ifdef SC_LOGGING
+ osLogEvent(l, 506, 1, t);
+#endif
+ } else {
+ if (sc->gfxListTail)
+ sc->gfxListTail->next = t;
+ else
+ sc->gfxListHead = t;
+
+ sc->gfxListTail = t;
+#ifdef SC_LOGGING
+ osLogEvent(l, 507, 1, t);
+#endif
+ }
+
+ t->next = NULL;
+ t->state = t->flags & OS_SC_RCP_MASK;
+}
+
+/*
+ *
+ */
+void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp)
+{
+ int rv;
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 511, 2, sp, dp);
+#endif
+
+ assert(sc->curRSPTask == 0);
+
+ if (sp) {
+ if (sp->list.t.type == M_AUDTASK) {
+ osWritebackDCacheAll(); /* flush the cache */
+ }
+
+ sp->state &= ~(OS_SC_YIELD | OS_SC_YIELDED);
+#ifndef _FINALROM
+ sp->startTime = osGetTime();
+#endif
+ osSpTaskLoad(&sp->list);
+ osSpTaskStartGo(&sp->list);
+ sc->curRSPTask = sp;
+ if (sp == dp)
+ sc->curRDPTask = dp;
+ }
+
+ if (dp && (dp != sp)) {
+ assert(dp->list.t.output_buff);
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 523, 3, dp, dp->list.t.output_buff,
+ (u32)*dp->list.t.output_buff_size);
+#endif
+ rv = osDpSetNextBuffer(dp->list.t.output_buff,
+ *dp->list.t.output_buff_size);
+
+ dp_busy = 1;
+ dpCount = 0;
+
+ assert(rv == 0);
+
+ sc->curRDPTask = dp;
+ }
+}
+
+static void __scYield(OSSched *sc)
+{
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 503, 1, sc->curRSPTask );
+#endif
+
+ if (sc->curRSPTask->list.t.type == M_GFXTASK) {
+
+/* assert(sc->curRSPTask->state & OS_SC_YIELD);*/
+
+ sc->curRSPTask->state |= OS_SC_YIELD;
+
+ osSpTaskYield();
+ } else {
+#ifdef SC_LOGGING
+ osLogEvent(l, 508, 1, sc->curRSPTask);
+#endif
+ }
+}
+
+/*
+ * Schedules the tasks to be run on the RCP
+ */
+s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP)
+{
+ s32 avail = availRCP;
+ OSScTask *gfx = sc->gfxListHead;
+ OSScTask *audio = sc->audioListHead;
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 517, 3, *sp, *dp, availRCP);
+#endif
+
+ if (sc->doAudio && (avail & OS_SC_SP)) {
+
+ if (gfx && (gfx->flags & OS_SC_PARALLEL_TASK)) {
+ *sp = gfx;
+ avail &= ~OS_SC_SP;
+ } else {
+ *sp = audio;
+ avail &= ~OS_SC_SP;
+ sc->doAudio = 0;
+ sc->audioListHead = sc->audioListHead->next;
+ if (sc->audioListHead == NULL)
+ sc->audioListTail = NULL;
+ }
+ } else {
+#ifdef SC_LOGGING
+ osLogEvent(l, 520, 1, gfx);
+#endif
+ if (__scTaskReady(gfx)) {
+
+#ifdef SC_LOGGING
+ osLogEvent(l, 522, 3, gfx, gfx->state, gfx->flags);
+#endif
+ switch (gfx->flags & OS_SC_TYPE_MASK) {
+ case (OS_SC_XBUS):
+ if (gfx->state & OS_SC_YIELDED) {
+#ifdef SC_LOGGING
+ osLogEvent(l, 518, 0);
+#endif
+ /* can hit this if RDP finishes at yield req */
+ /* assert(gfx->state & OS_SC_DP); */
+
+ if (avail & OS_SC_SP) { /* if SP is available */
+#ifdef SC_LOGGING
+ osLogEvent(l, 519, 0);
+#endif
+ *sp = gfx;
+ avail &= ~OS_SC_SP;
+
+ if (gfx->state & OS_SC_DP) { /* if it needs DP */
+ *dp = gfx;
+ avail &= ~OS_SC_DP;
+
+ if (avail & OS_SC_DP == 0)
+ assert(sc->curRDPTask == gfx);
+
+ }
+
+ sc->gfxListHead = sc->gfxListHead->next;
+ if (sc->gfxListHead == NULL)
+ sc->gfxListTail = NULL;
+
+ }
+ } else {
+ if (avail == (OS_SC_SP | OS_SC_DP)) {
+ *sp = *dp = gfx;
+ avail &= ~(OS_SC_SP | OS_SC_DP);
+ sc->gfxListHead = sc->gfxListHead->next;
+ if (sc->gfxListHead == NULL)
+ sc->gfxListTail = NULL;
+ }
+ }
+
+ break;
+
+ case (OS_SC_DRAM):
+ case (OS_SC_DP_DRAM):
+ case (OS_SC_DP_XBUS):
+ if (gfx->state & OS_SC_SP) { /* if needs SP */
+ if (avail & OS_SC_SP) { /* if SP is available */
+ *sp = gfx;
+ avail &= ~OS_SC_SP;
+ }
+ } else if (gfx->state & OS_SC_DP) { /* if needs DP */
+ if (avail & OS_SC_DP) { /* if DP available */
+ *dp = gfx;
+ avail &= ~OS_SC_DP;
+ sc->gfxListHead = sc->gfxListHead->next;
+ if (sc->gfxListHead == NULL)
+ sc->gfxListTail = NULL;
+ }
+ }
+ break;
+
+ case (OS_SC_SP_DRAM):
+ case (OS_SC_SP_XBUS):
+ default:
+ break;
+ }
+ }
+ }
+
+ if (avail != availRCP)
+ avail = __scSchedule(sc, sp, dp, avail);
+
+ return avail;
+
+}
+
diff --git a/lib/ultralib/src/sched/sched_log.fmt b/lib/ultralib/src/sched/sched_log.fmt
new file mode 100644
index 0000000..50e042d
--- /dev/null
+++ b/lib/ultralib/src/sched/sched_log.fmt
@@ -0,0 +1,19 @@
+500 "__scHandleRetrace: framecount %d, curRSPTask 0x%x, curRDPTask 0x%x"
+510 "__scHandleRSP: Current 0x%x state 0x%x flags 0x%x"
+521 "__scHandleRSP: Yielded Task 0x%x"
+515 "__scHandleRDP: Current 0x%x state 0x%x flags 0x%x"
+513 "__scTaskReady: Pending swap bail - current 0x%x next 0x%x"
+514 "__scTaskReady: Rendering bail - current 0x%x"
+504 "__scTaskComplete: Task 0x%x"
+525 "__scTaskComplete: Swapbuffer 0x%x"
+506 "__scAppendList: Audio task 0x%x"
+507 "__scAppendList: Gfx task 0x%x"
+511 "__scExec: sp 0x%x, dp 0x%x"
+523 "__scExec: DP only buf 0x%x, size %d"
+503 "__scYield: curRSPtask 0x%x"
+508 "__scYield: NOT A GFX TASK!! curRSPtask 0x%x"
+517 "__scSchedule: sp 0x%x, dp 0x%x, avail 0x%x"
+520 "__scSchedule: gfx task 0x%x"
+522 "__scSchedule: gfx task ready 0x%x, state 0x%x, flags 0x%x"
+518 "__scSchedule: Yielded"
+519 "__scSchedule: SP available"
diff --git a/lib/ultralib/src/sp/Makefile b/lib/ultralib/src/sp/Makefile
new file mode 100644
index 0000000..7807431
--- /dev/null
+++ b/lib/ultralib/src/sp/Makefile
@@ -0,0 +1,30 @@
+#!smake
+#
+# Makefile for the sp subdirectory
+#
+
+include $(ROOT)/usr/include/make/PRdefs
+
+
+# LCOPTS = -mips2 -non_shared -fullwarn -G 0
+LCINCS = -I. -I$(ROOT)/usr/include/PR -I$(ROOT)/usr/include
+
+CFILES = \
+ clearattribute.c \
+ color.c \
+ hide.c \
+ setattribute.c \
+ show.c \
+ sprite.c \
+ spriteex.c \
+ spriteex2.c \
+ spscale.c
+
+
+ASFILES =
+
+OBJECTS = $(CFILES:.c=.o)
+
+default: $(OBJECTS)
+
+include $(COMMONRULES)
diff --git a/lib/ultralib/src/sp/clearattribute.c b/lib/ultralib/src/sp/clearattribute.c
new file mode 100644
index 0000000..e5faf16
--- /dev/null
+++ b/lib/ultralib/src/sp/clearattribute.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <sp.h>
+
+/*
+ * spClearAttribute()
+ *
+ * Clears attributes about a sprite.
+ */
+void
+spClearAttribute (Sprite *sp, s32 attr)
+{
+ sp->attr &= ~attr;
+}
diff --git a/lib/ultralib/src/sp/color.c b/lib/ultralib/src/sp/color.c
new file mode 100644
index 0000000..a5abc85
--- /dev/null
+++ b/lib/ultralib/src/sp/color.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <sp.h>
+
+/*
+ * spColor()
+ *
+ * Sets the color for IA or I images.
+ */
+void
+spColor (Sprite *sp, unsigned char red, unsigned char green,
+ unsigned char blue, unsigned char alpha)
+{
+ sp->red = red;
+ sp->green = green;
+ sp->blue = blue;
+ sp->alpha = alpha;
+}
diff --git a/lib/ultralib/src/sp/hide.c b/lib/ultralib/src/sp/hide.c
new file mode 100644
index 0000000..6223c2c
--- /dev/null
+++ b/lib/ultralib/src/sp/hide.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <sp.h>
+
+/*
+ * spHide()
+ *
+ * Hides a sprite so that it will not be drawn at the next spUpdate().
+ */
+void
+spHide (Sprite *sp)
+{
+ spSetAttribute (sp, SP_HIDDEN);
+}
diff --git a/lib/ultralib/src/sp/setattribute.c b/lib/ultralib/src/sp/setattribute.c
new file mode 100644
index 0000000..887df08
--- /dev/null
+++ b/lib/ultralib/src/sp/setattribute.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <sp.h>
+
+/*
+ * spSetAttribute()
+ *
+ * Sets attributes about a sprite.
+ */
+void
+spSetAttribute ( Sprite *sp, s32 attr)
+{
+ sp->attr |= attr;
+}
diff --git a/lib/ultralib/src/sp/show.c b/lib/ultralib/src/sp/show.c
new file mode 100644
index 0000000..dc0db54
--- /dev/null
+++ b/lib/ultralib/src/sp/show.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <sp.h>
+
+/*
+ * spShow()
+ *
+ * Shows a sprite so that it will be drawn at the next spUpdate().
+ */
+void
+spShow (Sprite *sp)
+{
+ spClearAttribute (sp, SP_HIDDEN);
+}
diff --git a/lib/ultralib/src/sp/sprite.c b/lib/ultralib/src/sp/sprite.c
new file mode 100644
index 0000000..0779f1f
--- /dev/null
+++ b/lib/ultralib/src/sp/sprite.c
@@ -0,0 +1,757 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <assert.h>
+#include <sp.h>
+
+// TODO: this comes from a header
+#ident "$Revision: 1.17 $"
+
+/*
+ * spSetZ()
+ *
+ */
+void
+spSetZ (Sprite *sp, s32 z)
+{
+
+#ifdef DEBUG
+ emPrintf("spSetZ (Sprite 0x%08x, (%d))\n", sp, z );
+#endif
+
+ sp->zdepth = (s16)z;
+}
+
+/*
+ * spMove()
+ *
+ * Moves a sprite on the screen.
+ */
+void
+spMove (Sprite *sp, s32 x, s32 y)
+{
+
+#ifdef DEBUG
+ emPrintf("spMove (Sprite 0x%08x, (%d,%d))\n", sp, x, y );
+#endif
+
+ sp->x = (s16)x;
+ sp->y = (s16)y;
+}
+
+static s32 scissor_xmax;
+static s32 scissor_ymax;
+
+static s32 scissor_xmin;
+static s32 scissor_ymin;
+
+/*
+ * spScissor()
+ *
+ * Sets the scissoring box to be used for subsequent Sprite Drawing
+ */
+void
+spScissor (s32 xmin, s32 xmax, s32 ymin, s32 ymax )
+{
+ scissor_xmin = xmin;
+ scissor_ymin = ymin;
+
+ scissor_xmax = xmax;
+ scissor_ymax = ymax;
+}
+
+static int *prev_bmbuf = NULL;
+
+/*
+ * drawbitmap()
+ *
+ * Draws a bitmap from a sprite at a location on the screen. If the
+ * "usevert" flag is set, then the routine will use vertices and triangles
+ * to draw the bitmap. Otherwise, the texture rectangle instruction
+ * will be used.
+ */
+
+static void
+drawbitmap (Gfx **glp, Sprite *s, Bitmap *b,
+ s32 x, s32 y, s32 xx, s32 yy, s32 fs, s32 ft, s32 sx, s32 sy)
+{
+ s32 rs, rt;
+ s32 rxh, ryh;
+ s32 rxl, ryl;
+ Gfx *gl;
+ s32 tex_width, tex_height;
+ Gtexrect gt, *g;
+ s32 s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod;
+
+ g = &gt;
+
+ tex_width = b->width_img;
+ tex_height= s->bmHreal;
+
+#ifdef rmDEBUG
+ rmonPrintf("\tdrawbitmap (buf= 0x%08x; x,y= %d,%d; w,h= %d,%d )\n",
+ b->buf, x, y, b->width, s->bmheight );
+#endif
+ gl = *glp;
+
+ /* Scissoring */
+ if( (x >= scissor_xmax) || (y >= scissor_ymax) ) {
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: Upper Left corner (%d,%d) beyond range (%d,%d)\n",
+ x, y, scissor_xmax, scissor_ymax );
+#endif
+ return;
+ }
+
+ if( (xx < scissor_xmin) || (yy < scissor_ymin) ) {
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: Lower Right corner (%d,%d) not in range (%d,%d)\n",
+ xx, yy, scissor_xmin, scissor_ymin );
+#endif
+ return;
+ }
+
+
+ if (x < scissor_xmin) {
+ rxh = scissor_xmin*4;
+ rs = (b->s<<5) + fs + (((scissor_xmin - x)*sx)>>5);
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: Left Edge (%d) not in range (%d,%d)\n",
+ x, scissor_xmin, scissor_xmax );
+#endif
+ } else {
+ rxh = x*4;
+ rs = (b->s<<5) + fs;
+ };
+
+ if (y < scissor_ymin) {
+ ryh = scissor_ymin*4;
+ rt = (b->t<<5) + ft + (((scissor_ymin-y)*sy)>>5);
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: Top Edge (%d) not in range (%d,%d)\n",
+ y, scissor_ymin, scissor_ymax );
+#endif
+ } else {
+ ryh = y*4;
+ rt = (b->t<<5) + ft;
+ }
+
+ if( xx >= scissor_xmax ) {
+ rxl = scissor_xmax*4;
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: Right Edge (%d) not in range (%d,%d)\n",
+ xx, scissor_xmin, scissor_xmax );
+#endif
+ } else {
+ rxl = xx*4;
+ };
+
+ if( yy >= scissor_ymax ) {
+ ryl = scissor_ymax*4;
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: Bottom Edge (%d) not in range (%d,%d)\n",
+ yy, scissor_ymin, scissor_ymax );
+#endif
+ } else {
+ ryl = yy*4;
+ };
+
+ s_clamp = G_TX_CLAMP; t_clamp = G_TX_CLAMP;
+ s_mask = G_TX_NOMASK; t_mask = G_TX_NOMASK;
+ s_lod = G_TX_NOLOD; t_lod = G_TX_NOLOD;
+
+#define LOAD_TEX
+
+#ifdef LOAD_TEX
+ if( b->buf != prev_bmbuf ) {
+ switch(s->bmsiz)
+ {
+ case G_IM_SIZ_DD:
+ gDPLoadTextureTile_4b(gl++, b->buf, s->bmfmt, tex_width, tex_height,
+ b->s, b->t,
+ b->s + b->width,b->t + b->actualHeight,
+ 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ break;
+ case G_IM_SIZ_4b:
+ if (s->attr & SP_TEXSHUF) {
+ gDPLoadTextureBlock_4bS(gl++, b->buf, s->bmfmt,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ } else {
+ gDPLoadTextureBlock_4b(gl++, b->buf, s->bmfmt,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ };
+ break;
+
+ case G_IM_SIZ_8b:
+ if (s->attr & SP_TEXSHUF) {
+ gDPLoadTextureBlockS(gl++, b->buf, s->bmfmt, G_IM_SIZ_8b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ } else {
+ gDPLoadTextureBlock(gl++, b->buf, s->bmfmt, G_IM_SIZ_8b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ };
+ break;
+ case G_IM_SIZ_16b:
+ if (s->bmfmt == G_IM_FMT_YUV ) {
+ if (s->attr & SP_TEXSHUF) {
+ gDPLoadTextureBlockYuvS(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ } else {
+ if( b->LUToffset != 0 ) { /* Split Y and UV areas */
+ unsigned char *uv, *addr;
+ int j;
+ s32 tmem, siz;
+
+ gDPSetTextureImage( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 1, b->buf);
+ gDPSetTile( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 0, 256, G_TX_LOADTILE, 0,
+ t_clamp, t_mask, t_lod,
+ s_clamp, s_mask, s_lod );
+ gDPLoadSync( gl++ );
+ gDPLoadBlock( gl++, G_TX_LOADTILE, 0,0, tex_width*tex_height -1,
+ CALC_DXT(tex_width,1) );
+ gDPLoadSync( gl++ );
+
+ uv = ((unsigned char *)b->buf) +
+ ((tex_width*tex_height)/2)*b->LUToffset;
+
+ for( j=0; j<=(tex_height/2); j++ ) {
+ addr = uv + ((tex_height/2) -2 -j)*tex_width;
+ siz = 3*tex_width;
+ tmem = (tex_width/8)*(tex_height - 2 - 2*j);
+ if( tmem < 0 ) {
+ addr += (-tmem)*8;
+ siz -= (-tmem)*8;
+ tmem = 0;
+ };
+ if( j == 0 )
+ siz = 2*tex_width;
+
+ gDPSetTextureImage( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 1, addr);
+ gDPSetTile( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 0, tmem,
+ G_TX_LOADTILE, 0,
+ t_clamp, t_mask, t_lod,
+ s_clamp, s_mask, s_lod );
+ gDPLoadSync( gl++ );
+ gDPLoadBlock( gl++, G_TX_LOADTILE, 0,0, siz -1,
+ CALC_DXT(tex_width,1) );
+ gDPLoadSync( gl++ );
+ };
+
+ gDPSetTile( gl++, s->bmfmt, G_IM_SIZ_16b, (((tex_width) * 1)+7)>>3, 0,
+ G_TX_RENDERTILE, 0,
+ t_clamp, t_mask, t_lod,
+ s_clamp, s_mask, s_lod );
+ gDPSetTileSize( gl++, G_TX_RENDERTILE, 0, 0,
+ ((tex_width)-1) << G_TEXTURE_IMAGE_FRAC,
+ ((tex_height)-1) << G_TEXTURE_IMAGE_FRAC );
+
+ } else {
+ gDPLoadTextureBlockYuv(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ };
+ };
+ } else {
+ if (s->attr & SP_TEXSHUF) {
+ gDPLoadTextureBlockS(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ } else {
+ gDPLoadTextureBlock(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ };
+ };
+ break;
+ case G_IM_SIZ_32b:
+ if (s->attr & SP_TEXSHUF) {
+ gDPLoadTextureBlockS(gl++, b->buf, s->bmfmt, G_IM_SIZ_32b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ } else {
+ gDPLoadTextureBlock(gl++, b->buf, s->bmfmt, G_IM_SIZ_32b,
+ tex_width, tex_height, 0,
+ s_clamp, t_clamp,
+ s_mask, t_mask,
+ s_lod, t_lod);
+ };
+ break;
+ }
+ prev_bmbuf = b->buf;
+ }
+#endif /* LOAD_TEX */
+
+
+ g->cmd = G_TEXRECT;
+ g->tile = 0;
+
+ g->xh = rxh;
+ g->xl = rxl;
+ g->yh = ryh;
+ g->yl = ryl;
+
+ g->s = rs;
+ g->t = rt;
+
+ if ((s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) )
+ g->dsdx = sx * 4;
+ else
+ g->dsdx = sx;
+
+ g->dtdy = sy;
+
+#ifdef rmDEBUG
+ rmonPrintf("\trect (xh,l= %d,%d, yh,l= %d,%d, s,t= %d,%d, dsdx=%d, dtdy=%d )\n",
+ rxh,rxl,ryh,ryl,rs,rt,g->dsdx,sy );
+#endif
+
+ gSPTextureRectangle(gl++,g->xh,g->yh,g->xl,g->yl,g->tile,g->s,g->t,g->dsdx,g->dtdy);
+
+ gDPPipeSync(gl++);
+
+ *glp = gl;
+}
+
+static u16 sp_attr = 0;
+
+void
+spInit( Gfx **glistp )
+{
+ Gfx *gl;
+
+ gl = *glistp;
+
+#ifdef DEBUG
+ emPrintf("spInit ()\n" );
+#endif
+ sp_attr = 0;
+
+ scissor_xmin = 0;
+ scissor_ymin = 0;
+
+ scissor_xmax = 320;
+ scissor_ymax = 240;
+
+ /* Turn on texturing */
+ gDPPipeSync ( gl++ );
+ gDPSetCycleType ( gl++, G_CYC_1CYCLE);
+ gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON);
+ gDPSetAlphaCompare ( gl++, G_AC_NONE );
+ gDPSetTexturePersp ( gl++, G_TP_NONE );
+ gDPSetTextureFilter ( gl++, G_TF_BILERP );
+ gDPSetTextureConvert( gl++, G_TC_FILT );
+ gDPSetTextureDetail ( gl++, G_TD_CLAMP );
+ gDPSetTextureLOD ( gl++, G_TL_TILE );
+ gDPSetTextureLUT ( gl++, G_TT_NONE );
+
+#define SPRITE_SURF G_RM_TEX_EDGE
+#define SPRITE_SURF2 G_RM_TEX_EDGE2
+
+ gDPSetRenderMode( gl++, SPRITE_SURF, SPRITE_SURF2);
+
+ *glistp = gl;
+}
+
+
+/*
+ * spDraw()
+ *
+ * Draws all of the sprites that are associated with bitmaps and that
+ * are supposed to be drawn (spDraw()). They are drawn from 0 to maxsp,
+ * so sprites with higher numbers will overwrite lower-numbered sprites.
+ *
+ */
+Gfx *
+spDraw ( Sprite *s )
+{
+ int i;
+ s32 x, y;
+ float sx, sy;
+ Bitmap *b;
+ Gfx *gl;
+#ifndef NDEBUG
+ Gfx *ogl;
+#endif
+ Gfx *dl_start;
+ s32 isx, isy;
+ s32 tx, ty;
+ s32 tx2, ty2;
+ s32 x2, y2;
+ float ftx, fty;
+ s32 fs, ft;
+ s32 ex, ey;
+
+#ifdef rmDEBUG
+ rmonPrintf("spDraw (Sprite 0x%08x )\n", s );
+#endif
+
+ if (s->attr & SP_HIDDEN)
+ return(NULL);
+
+ prev_bmbuf = NULL;
+
+ gl = s->rsp_dl_next;
+ if( gl == NULL )
+ gl = s->rsp_dl;
+ dl_start = gl;
+
+#ifndef NDEBUG
+ ogl = gl;
+#endif
+
+ b = s->bitmap;
+ ex = 0;
+ ey = 0;
+
+ if (sp_attr & SP_EXTERN) /* previous attr was extern? */
+ sp_attr = ~s->attr; /* Assume previous modes are all different
+ from new ones */
+
+ if (s->attr & SP_EXTERN) /* current attr is extern? */
+ sp_attr = s->attr; /* Assume all settings should remain the same */
+
+ if (s->attr != sp_attr) {
+ if ((s->attr & SP_TRANSPARENT) && !(sp_attr & SP_TRANSPARENT)) {
+ gDPSetRenderMode( gl++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
+ } else if (!(s->attr & SP_TRANSPARENT) &&
+ (sp_attr & SP_TRANSPARENT)) {
+ gDPSetRenderMode( gl++,
+ SPRITE_SURF, SPRITE_SURF2);
+ }
+
+ if ((s->attr & SP_CUTOUT) && !(sp_attr & SP_CUTOUT)) {
+ gDPSetBlendColor ( gl++, 0xff, 0xff, 0xff, 0x01);
+ gDPSetAlphaCompare ( gl++, G_AC_THRESHOLD) ;
+ } else if (!(s->attr & SP_CUTOUT) && (sp_attr & SP_CUTOUT)) {
+ gDPSetAlphaCompare ( gl++, G_AC_NONE) ;
+ }
+
+ if( (s->attr & SP_TEXSHIFT) && !(sp_attr & SP_TEXSHIFT) ) {
+ gDPSetTextureFilter( gl++, G_TF_AVERAGE );
+ } else if( !(s->attr & SP_TEXSHIFT) && (sp_attr & SP_TEXSHIFT) ) {
+ gDPSetTextureFilter( gl++, G_TF_BILERP );
+ };
+
+ };
+
+ sp_attr = s->attr;
+
+ if( sp_attr & SP_Z ) {
+ gDPSetPrimDepth(gl++, s->zdepth, 0);
+ };
+
+
+ gDPSetPrimColor( gl++, 0, 0, s->red, s->green, s->blue, s->alpha);
+
+ if (s->bmfmt == G_IM_FMT_IA || s->bmfmt == G_IM_FMT_I) {
+ if( s->alpha == 255 ) {
+ gDPSetCombineMode ( gl++,
+ G_CC_MODULATEIDECALA_PRIM,
+ G_CC_MODULATEIDECALA_PRIM);
+ } else {
+ gDPSetCombineMode ( gl++,
+ G_CC_MODULATEIA_PRIM,
+ G_CC_MODULATEIA_PRIM);
+ };
+ } else {
+ if( s->alpha == 255 ) {
+ gDPSetCombineMode ( gl++,
+ G_CC_MODULATEIDECALA_PRIM,
+ G_CC_MODULATEIDECALA_PRIM);
+ } else {
+ gDPSetCombineMode ( gl++,
+ G_CC_MODULATERGBA_PRIM,
+ G_CC_MODULATERGBA_PRIM);
+ };
+ }
+
+
+ if( s->bmfmt == G_IM_FMT_CI ) {
+ gDPSetTextureLUT( gl++, G_TT_RGBA16);
+ gDPLoadTLUT( gl++, s->nTLUT, 256+s->startTLUT, s->LUT );
+ gDPLoadSync( gl++ );
+ };
+
+#define MY_K0 (175 & 0x1ff)
+#define MY_K1 (-43 & 0x1ff)
+#define MY_K2 (-89 & 0x1ff)
+#define MY_K3 (222 & 0x1ff)
+#define MY_K4 (114 & 0x1ff)
+#define MY_K5 (42 & 0x1ff)
+
+ if( (s->bmfmt == G_IM_FMT_YUV) && (s->attr & SP_FASTCOPY) ) {
+ gDPSetTextureConvert( gl++, G_TC_CONV);
+ gDPSetTextureFilter( gl++, G_TF_POINT);
+ gDPSetCombineMode( gl++, G_CC_1CYUV2RGB, G_CC_1CYUV2RGB);
+ gDPSetConvert( gl++, MY_K0, MY_K1, MY_K2, MY_K3, MY_K4, MY_K5);
+ } else if(s->bmfmt == G_IM_FMT_YUV) {
+ gDPSetCycleType( gl++, G_CYC_2CYCLE );
+ gDPSetTextureFilter( gl++, G_TF_BILERP);
+ gDPSetTextureConvert( gl++, G_TC_FILTCONV);
+ gDPSetConvert( gl++, MY_K0, MY_K1, MY_K2, MY_K3, MY_K4, MY_K5);
+ gDPSetCombineMode( gl++, G_CC_YUV2RGB, G_CC_PASS2);
+ }
+
+ if (s->attr & SP_SCALE) {
+ sx = s->scalex;
+ sy = s->scaley;
+ } else {
+ sx = 1.0F;
+ sy = 1.0F;
+ }
+
+ isx = (int) ((1<<10) / sx + 0.5F);
+ isy = (int) ((1<<10) / sy + 0.5F);
+
+ if( b ) {
+
+ if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) )
+ gDPSetCycleType( gl++, G_CYC_COPY);
+
+ x = 0.0F;
+ y = 0.0F;
+
+ fty = s->y+y*sy;
+ ty = (int) ( fty + 0.99999F);
+ ft = (int) (isy * (ty - fty));
+ ft = (ft + 16)>>5;
+ if( s->attr & SP_TEXSHIFT )
+ ft += 16; /* 1/2 Texel for AntiAliasing */
+
+ if( s->attr & SP_FRACPOS )
+ ft += s->frac_t; /* Micro-positioning */
+
+ y2 = y + s->bmheight;
+ ty2 = (int) (s->y+y2*sy + 0.99999F);
+
+ if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) )
+ ty2--;
+
+
+#ifdef rmDEBUG
+ rmonPrintf("\tiscale=(%d,%d), %d bitmaps, sprite_size=(%d,%d)\n",
+ isx, isy, s->nbitmaps, s->width, s->height );
+#endif
+
+ for( i=0; (i < s->nbitmaps) && (b->width > 0); i++, b++ ) {
+
+ if( (x+b->width) > s->width ) { /* Next bitmap hits edge? */
+ int bh;
+
+ x = 0;
+ fs = 0;
+ ex = 0;
+ ey += s->expy;
+ y += s->bmheight; /* Wrap to next line */
+ y2 = y + s->bmheight; /* Wrap to next line */
+
+ fty = s->y+y*sy;
+ ty = (int) ( fty + 0.9999F);
+ ft = (int) (isy * (ty - fty));
+ ft = (ft + 16)>>5;
+ if( s->attr & SP_TEXSHIFT )
+ ft += 16; /* 1/2 Texel for AntiAliasing */
+
+ if( s->attr & SP_FRACPOS )
+ ft += s->frac_t; /* Micro-positioning */
+
+ ty2 = (int) (s->y+y2*sy + 0.9999F);
+
+ ty += ey;
+ ty2 += ey;
+
+ if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) )
+ ty2--;
+
+ /* Fill out to rect. bdy? */
+
+ if( (b->actualHeight != 0) )
+ bh = b->actualHeight;
+ else
+ bh = s->bmheight;
+
+ if( (y + bh) > s->height ) /* Can't wrap any more? */
+ break;
+ };
+
+#ifdef rmDEBUG
+ rmonPrintf("bm# %d, x,y=(%d,%d) width=%d \n", i, x, y, b->width );
+#endif
+
+ ftx = s->x+x*sx;
+ tx = (s32) (ftx + 0.9999F);
+ fs = (s32) (isx * (tx - ftx));
+ fs = (fs + 16)>>5;
+ if( s->attr & SP_TEXSHIFT )
+ fs += 16; /* 1/2 Texel for AntiAliasing */
+
+ if( s->attr & SP_FRACPOS )
+ fs += s->frac_s; /* Micro-positioning */
+
+ x2 = x + b->width;
+ tx2 = (int) (s->x+x2*sx + 0.9999F);
+
+ if( (b->actualHeight != 0) ) {
+ y2 = y + b->actualHeight;
+ ty2 = (s32) (s->y+y2*sy + 0.9999F);
+ ty2 += ey;
+
+ if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) )
+ ty2--;
+ };
+
+#ifdef rmDEBUG
+ rmonPrintf("\tfull(%g,%g) = int(%d,%d) + frac(%d,%d)\n",
+ ftx, fty, tx,ty, fs,ft );
+#endif
+
+ tx += ex;
+ tx2 += ex;
+
+ if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) )
+ tx2--;
+
+ if( b->buf != NULL ) /* Skip over null bitmaps (blanks) */
+ drawbitmap ( &gl, s, b, tx, ty, tx2, ty2, fs, ft, isx, isy);
+
+ x += b->width;
+ ex += s->expx;
+ }
+
+ if (s->attr & SP_FASTCOPY)
+ gDPSetCycleType( gl++, G_CYC_1CYCLE);
+
+ if(s->bmfmt == G_IM_FMT_YUV) {
+ gDPSetCycleType( gl++, G_CYC_1CYCLE);
+ gDPSetTextureFilter ( gl++, G_TF_BILERP );
+ gDPSetTextureConvert( gl++, G_TC_FILT );
+ };
+
+ } else {
+ int rgba;
+
+ x = (s32)s->x;
+ y = (s32)s->y;
+ x2 = s->x + (s->width*sx)-1;
+ y2 = s->y + (s->height*sy)-1;
+
+ if( ( x >= scissor_xmax) || (y >= scissor_ymax) ) {
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: FILL Upper Left corner (%d,%d) beyond range (%d,%d)\n",
+ x, y, scissor_xmax, scissor_ymax );
+#endif
+ } else if( ( x2 < scissor_xmin) || (y2 < scissor_ymin) ) {
+#ifdef DEBUG_SCISSOR
+ emPrintf("Sprite Scissoring: FILL Lower Right corner (%d,%d) below range (%d,%d)\n",
+ x2, y2, scissor_xmin, scissor_ymin );
+#endif
+ } else {
+
+ if( x < scissor_xmin )
+ x = scissor_xmin;
+
+ if( x2 >= scissor_xmax )
+ x2 = scissor_xmax - 1;
+
+ if( y < scissor_ymin )
+ y = scissor_ymin;
+
+ if( y2 >= scissor_ymax )
+ y2 = scissor_ymax - 1;
+
+ rgba = GPACK_RGBA5551((s->red), (s->green), (s->blue), (s->alpha>>7));
+
+ gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF);
+ gDPSetCycleType( gl++, G_CYC_FILL);
+ gDPSetFillColor( gl++, (rgba << 16) | (rgba) );
+
+ gDPFillRectangle( gl++, x,y, x2,y2 );
+ gDPSetCycleType( gl++, G_CYC_1CYCLE);
+ gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON);
+ }
+ }
+
+ if( s->bmfmt == G_IM_FMT_CI ) {
+ gDPSetTextureLUT( gl++, G_TT_NONE);
+ };
+
+ gSPEndDisplayList ( gl++ );
+
+ assert((gl - ogl) < s->ndisplist);
+ s->rsp_dl_next = gl;
+ return( dl_start );
+}
+
+void
+spFinish( Gfx **glistp )
+{
+ Gfx *gl;
+
+ gl = *glistp;
+
+ /* Turn off texturing */
+ gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF);
+ gDPSetCombineMode ( gl++, G_CC_SHADE, G_CC_SHADE);
+
+ if (sp_attr & SP_TRANSPARENT) {
+ /* Turn off transparency */
+ gDPSetRenderMode( gl++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
+ }
+
+ if (sp_attr & SP_CUTOUT) {
+ /* Turn off Alpha write enable */
+ gDPSetAlphaCompare ( gl++, G_AC_NONE) ;
+ }
+
+ gSPEndDisplayList ( gl++ );
+
+ *glistp = gl;
+}
diff --git a/lib/ultralib/src/sp/spriteex.c b/lib/ultralib/src/sp/spriteex.c
new file mode 100644
index 0000000..772036f
--- /dev/null
+++ b/lib/ultralib/src/sp/spriteex.c
@@ -0,0 +1,2 @@
+#define F3DEX_GBI
+#include "sprite.c"
diff --git a/lib/ultralib/src/sp/spriteex2.c b/lib/ultralib/src/sp/spriteex2.c
new file mode 100644
index 0000000..2ef1221
--- /dev/null
+++ b/lib/ultralib/src/sp/spriteex2.c
@@ -0,0 +1,2 @@
+#define F3DEX_GBI_2
+#include "sprite.c"
diff --git a/lib/ultralib/src/sp/spscale.c b/lib/ultralib/src/sp/spscale.c
new file mode 100644
index 0000000..4f1bd92
--- /dev/null
+++ b/lib/ultralib/src/sp/spscale.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States. Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ */
+
+#include <sp.h>
+
+/*
+ * spScale()
+ *
+ * Scales the sprite by a vertical and horizontal factor.
+ */
+void
+spScale (Sprite *sp, float sx, float sy)
+{
+
+ sp->scalex = sx;
+ sp->scaley = sy;
+
+ if( (sx == 1.0F) && (sy == 1.0F) )
+ spClearAttribute( sp, SP_SCALE );
+ else
+ spSetAttribute( sp, SP_SCALE );
+}
diff --git a/lib/ultralib/src/vimodes/vimodefpalhaf1.c b/lib/ultralib/src/vimodes/vimodefpalhaf1.c
new file mode 100644
index 0000000..86e0f80
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpalhaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalHaf1 = {
+ OS_VI_FPAL_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpalhan1.c b/lib/ultralib/src/vimodes/vimodefpalhan1.c
new file mode 100644
index 0000000..857c493
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpalhan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalHan1 = {
+ OS_VI_FPAL_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpalhpf1.c b/lib/ultralib/src/vimodes/vimodefpalhpf1.c
new file mode 100644
index 0000000..366ed78
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpalhpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalHpf1 = {
+ OS_VI_FPAL_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpalhpf2.c b/lib/ultralib/src/vimodes/vimodefpalhpf2.c
new file mode 100644
index 0000000..76eaa13
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpalhpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalHpf2 = {
+ OS_VI_FPAL_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpalhpn1.c b/lib/ultralib/src/vimodes/vimodefpalhpn1.c
new file mode 100644
index 0000000..416e63e
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpalhpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalHpn1 = {
+ OS_VI_FPAL_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpalhpn2.c b/lib/ultralib/src/vimodes/vimodefpalhpn2.c
new file mode 100644
index 0000000..3f3f165
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpalhpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalHpn2 = {
+ OS_VI_FPAL_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallaf1.c b/lib/ultralib/src/vimodes/vimodefpallaf1.c
new file mode 100644
index 0000000..bc86c99
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLaf1 = {
+ OS_VI_FPAL_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallaf2.c b/lib/ultralib/src/vimodes/vimodefpallaf2.c
new file mode 100644
index 0000000..8233460
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallaf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLaf2 = {
+ OS_VI_FPAL_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallan1.c b/lib/ultralib/src/vimodes/vimodefpallan1.c
new file mode 100644
index 0000000..30532a0
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLan1 = {
+ OS_VI_FPAL_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallan2.c b/lib/ultralib/src/vimodes/vimodefpallan2.c
new file mode 100644
index 0000000..76ddf13
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallan2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLan2 = {
+ OS_VI_FPAL_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallpf1.c b/lib/ultralib/src/vimodes/vimodefpallpf1.c
new file mode 100644
index 0000000..d743345
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLpf1 = {
+ OS_VI_FPAL_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallpf2.c b/lib/ultralib/src/vimodes/vimodefpallpf2.c
new file mode 100644
index 0000000..04b4c6c
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLpf2 = {
+ OS_VI_FPAL_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(45, 615), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(47, 617), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallpn1.c b/lib/ultralib/src/vimodes/vimodefpallpn1.c
new file mode 100644
index 0000000..634d984
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLpn1 = {
+ OS_VI_FPAL_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodefpallpn2.c b/lib/ultralib/src/vimodes/vimodefpallpn2.c
new file mode 100644
index 0000000..cc1627a
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodefpallpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeFpalLpn2 = {
+ OS_VI_FPAL_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(47, 617), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempalhaf1.c b/lib/ultralib/src/vimodes/vimodempalhaf1.c
new file mode 100644
index 0000000..0c3d605
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempalhaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalHaf1 = {
+ OS_VI_MPAL_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { //[0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { //[1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempalhan1.c b/lib/ultralib/src/vimodes/vimodempalhan1.c
new file mode 100644
index 0000000..0566ccc
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempalhan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalHan1 = {
+ OS_VI_MPAL_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempalhpf1.c b/lib/ultralib/src/vimodes/vimodempalhpf1.c
new file mode 100644
index 0000000..3aa2b6b
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempalhpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalHpf1 = {
+ OS_VI_MPAL_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempalhpf2.c b/lib/ultralib/src/vimodes/vimodempalhpf2.c
new file mode 100644
index 0000000..128ca15
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempalhpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalHpf2 = {
+ OS_VI_MPAL_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempalhpn1.c b/lib/ultralib/src/vimodes/vimodempalhpn1.c
new file mode 100644
index 0000000..d589ad9
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempalhpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalHpn1 = {
+ OS_VI_MPAL_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempalhpn2.c b/lib/ultralib/src/vimodes/vimodempalhpn2.c
new file mode 100644
index 0000000..57f43cd
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempalhpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalHpn2 = {
+ OS_VI_MPAL_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallaf1.c b/lib/ultralib/src/vimodes/vimodempallaf1.c
new file mode 100644
index 0000000..2d726e7
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLaf1 = {
+ OS_VI_MPAL_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallaf2.c b/lib/ultralib/src/vimodes/vimodempallaf2.c
new file mode 100644
index 0000000..8eac118
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallaf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLaf2 = {
+ OS_VI_MPAL_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallan1.c b/lib/ultralib/src/vimodes/vimodempallan1.c
new file mode 100644
index 0000000..2a4f73a
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLan1 = {
+ OS_VI_MPAL_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallan2.c b/lib/ultralib/src/vimodes/vimodempallan2.c
new file mode 100644
index 0000000..2ff5fad
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallan2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLan2 = {
+ OS_VI_MPAL_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallpf1.c b/lib/ultralib/src/vimodes/vimodempallpf1.c
new file mode 100644
index 0000000..d89f113
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLpf1 = {
+ OS_VI_MPAL_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallpf2.c b/lib/ultralib/src/vimodes/vimodempallpf2.c
new file mode 100644
index 0000000..2e5386b
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLpf2 = {
+ OS_VI_MPAL_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(524), // vSync
+ HSYNC(3088, 0), // hSync
+ LEAP(3100, 3100), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(2, 2, 11, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallpn1.c b/lib/ultralib/src/vimodes/vimodempallpn1.c
new file mode 100644
index 0000000..420d5e6
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLpn1 = {
+ OS_VI_MPAL_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodempallpn2.c b/lib/ultralib/src/vimodes/vimodempallpn2.c
new file mode 100644
index 0000000..8195790
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodempallpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeMpalLpn2 = {
+ OS_VI_MPAL_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 30, 5, 70), // burst
+ VSYNC(525), // vSync
+ HSYNC(3089, 4), // hSync
+ LEAP(3097, 3098), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentschaf1.c b/lib/ultralib/src/vimodes/vimodentschaf1.c
new file mode 100644
index 0000000..071b330
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentschaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscHaf1 = {
+ OS_VI_NTSC_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentschan1.c b/lib/ultralib/src/vimodes/vimodentschan1.c
new file mode 100644
index 0000000..279bb83
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentschan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscHan1 = {
+ OS_VI_NTSC_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentschpf1.c b/lib/ultralib/src/vimodes/vimodentschpf1.c
new file mode 100644
index 0000000..5ad8c2b
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentschpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscHpf1 = {
+ OS_VI_NTSC_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentschpf2.c b/lib/ultralib/src/vimodes/vimodentschpf2.c
new file mode 100644
index 0000000..b9720a5
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentschpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscHpf2 = {
+ OS_VI_NTSC_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentschpn1.c b/lib/ultralib/src/vimodes/vimodentschpn1.c
new file mode 100644
index 0000000..ae8c0a9
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentschpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscHpn1 = {
+ OS_VI_NTSC_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentschpn2.c b/lib/ultralib/src/vimodes/vimodentschpn2.c
new file mode 100644
index 0000000..5c73d69
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentschpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscHpn2 = {
+ OS_VI_NTSC_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclaf1.c b/lib/ultralib/src/vimodes/vimodentsclaf1.c
new file mode 100644
index 0000000..31ff70b
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLaf1 = {
+ OS_VI_NTSC_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclaf2.c b/lib/ultralib/src/vimodes/vimodentsclaf2.c
new file mode 100644
index 0000000..fd15f40
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclaf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLaf2 = {
+ OS_VI_NTSC_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclan1.c b/lib/ultralib/src/vimodes/vimodentsclan1.c
new file mode 100644
index 0000000..9a052be
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLan1 = {
+ OS_VI_NTSC_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclan2.c b/lib/ultralib/src/vimodes/vimodentsclan2.c
new file mode 100644
index 0000000..fa66af4
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclan2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLan2 = {
+ OS_VI_NTSC_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclpf1.c b/lib/ultralib/src/vimodes/vimodentsclpf1.c
new file mode 100644
index 0000000..dd146b9
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLpf1 = {
+ OS_VI_NTSC_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclpf2.c b/lib/ultralib/src/vimodes/vimodentsclpf2.c
new file mode 100644
index 0000000..6cda2a1
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLpf2 = {
+ OS_VI_NTSC_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(524), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(35, 509), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclpn1.c b/lib/ultralib/src/vimodes/vimodentsclpn1.c
new file mode 100644
index 0000000..ff6172c
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLpn1 = {
+ OS_VI_NTSC_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodentsclpn2.c b/lib/ultralib/src/vimodes/vimodentsclpn2.c
new file mode 100644
index 0000000..6340981
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodentsclpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModeNtscLpn2 = {
+ OS_VI_NTSC_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(57, 34, 5, 62), // burst
+ VSYNC(525), // vSync
+ HSYNC(3093, 0), // hSync
+ LEAP(3093, 3093), // leap
+ HSTART(108, 748), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(37, 511), // vStart
+ BURST(4, 2, 14, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepalhaf1.c b/lib/ultralib/src/vimodes/vimodepalhaf1.c
new file mode 100644
index 0000000..791a918
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepalhaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalHaf1 = {
+ OS_VI_PAL_HAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepalhan1.c b/lib/ultralib/src/vimodes/vimodepalhan1.c
new file mode 100644
index 0000000..947a0c1
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepalhan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalHan1 = {
+ OS_VI_PAL_HAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepalhpf1.c b/lib/ultralib/src/vimodes/vimodepalhpf1.c
new file mode 100644
index 0000000..6c9e915
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepalhpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalHpf1 = {
+ OS_VI_PAL_HPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepalhpf2.c b/lib/ultralib/src/vimodes/vimodepalhpf2.c
new file mode 100644
index 0000000..62d162e
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepalhpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalHpf2 = {
+ OS_VI_PAL_HPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(640), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(0.5, 0.5), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepalhpn1.c b/lib/ultralib/src/vimodes/vimodepalhpn1.c
new file mode 100644
index 0000000..a06efac
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepalhpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalHpn1 = {
+ OS_VI_PAL_HPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepalhpn2.c b/lib/ultralib/src/vimodes/vimodepalhpn2.c
new file mode 100644
index 0000000..0ed9dfc
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepalhpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalHpn2 = {
+ OS_VI_PAL_HPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(1280), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(1, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(2560), // origin
+ SCALE(1, 0), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(5120), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallaf1.c b/lib/ultralib/src/vimodes/vimodepallaf1.c
new file mode 100644
index 0000000..1a43489
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallaf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLaf1 = {
+ OS_VI_PAL_LAF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallaf2.c b/lib/ultralib/src/vimodes/vimodepallaf2.c
new file mode 100644
index 0000000..89bd8a2
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallaf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLaf2 = {
+ OS_VI_PAL_LAF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_SERRATE_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallan1.c b/lib/ultralib/src/vimodes/vimodepallan1.c
new file mode 100644
index 0000000..3dd00be
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallan1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLan1 = {
+ OS_VI_PAL_LAN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_ANTIALIAS_MODE_1 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallan2.c b/lib/ultralib/src/vimodes/vimodepallan2.c
new file mode 100644
index 0000000..bc5a270
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallan2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLan2 = {
+ OS_VI_PAL_LAN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_DIVOT_ON | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallpf1.c b/lib/ultralib/src/vimodes/vimodepallpf1.c
new file mode 100644
index 0000000..50828ce
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallpf1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLpf1 = {
+ OS_VI_PAL_LPF1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallpf2.c b/lib/ultralib/src/vimodes/vimodepallpf2.c
new file mode 100644
index 0000000..da2fead
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallpf2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLpf2 = {
+ OS_VI_PAL_LPF2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_SERRATE_ON | VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(624), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.25), // yScale
+ HSTART(93, 567), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0.75), // yScale
+ HSTART(95, 569), // vStart
+ BURST(105, 2, 13, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallpn1.c b/lib/ultralib/src/vimodes/vimodepallpn1.c
new file mode 100644
index 0000000..e27e74b
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallpn1.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLpn1 = {
+ OS_VI_PAL_LPN1, // type
+ { // comRegs
+ VI_CTRL_TYPE_16 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_2 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(640), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/vimodes/vimodepallpn2.c b/lib/ultralib/src/vimodes/vimodepallpn2.c
new file mode 100644
index 0000000..76fa04d
--- /dev/null
+++ b/lib/ultralib/src/vimodes/vimodepallpn2.c
@@ -0,0 +1,35 @@
+#include "PR/os.h"
+#include "PR/rcp.h"
+#include "../io/viint.h"
+
+OSViMode osViModePalLpn2 = {
+ OS_VI_PAL_LPN2, // type
+ { // comRegs
+ VI_CTRL_TYPE_32 | VI_CTRL_GAMMA_DITHER_ON | VI_CTRL_GAMMA_ON |
+ VI_CTRL_ANTIALIAS_MODE_3 | VI_CTRL_PIXEL_ADV_3, // ctrl
+ WIDTH(320), // width
+ BURST(58, 30, 4, 69), // burst
+ VSYNC(625), // vSync
+ HSYNC(3177, 23), // hSync
+ LEAP(3183, 3181), // leap
+ HSTART(128, 768), // hStart
+ SCALE(2, 0), // xScale
+ VCURRENT(0), // vCurrent
+ },
+ { // fldRegs
+ { // [0]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ },
+ { // [1]
+ ORIGIN(1280), // origin
+ SCALE(1, 0), // yScale
+ HSTART(95, 569), // vStart
+ BURST(107, 2, 9, 0), // vBurst
+ VINTR(2), // vIntr
+ }
+ }
+};
diff --git a/lib/ultralib/src/voice/voicecheckresult.c b/lib/ultralib/src/voice/voicecheckresult.c
new file mode 100644
index 0000000..6f615e1
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecheckresult.c
@@ -0,0 +1,23 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+s32 __osVoiceCheckResult(OSVoiceHandle* hd, u8* stat) {
+ s32 ret;
+ u8 buf[2];
+
+ if (ret = __osVoiceGetStatus(hd->__mq, hd->__channel, stat), ret == 0) {
+ if (*stat & 1) {
+ ret = CONT_ERR_VOICE_NO_RESPONSE;
+ } else if (ret = __osVoiceContRead2(hd->__mq, hd->__channel, 0, buf), ret == 0) {
+ hd->cmd_status = buf[0] & 7;
+
+ if (buf[0] & 0x40) {
+ ret = CONT_ERR_VOICE_NO_RESPONSE;
+ } else {
+ ret = buf[1] << 8;
+ }
+ }
+ }
+ return ret;
+} \ No newline at end of file
diff --git a/lib/ultralib/src/voice/voicecheckword.c b/lib/ultralib/src/voice/voicecheckword.c
new file mode 100644
index 0000000..25c51fa
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecheckword.c
@@ -0,0 +1,116 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+s32 osVoiceCheckWord(u8* word) {
+ s32 k;
+ s32 ret = 0;
+ u16 sjis;
+ u16 old = 0;
+
+ for (k = 0; word[k] != 0; k += 2) {
+ sjis = (word[k] << 8) + word[k + 1];
+ if (((sjis != 'ー') && (sjis < 'ぁ'))
+ || ((sjis > 'ん') && (sjis < 'ァ'))
+ || (sjis == 0x837F) || (sjis > 'ヶ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if ((k == 0) && ((sjis == 'ー') || (sjis == 'ん') || (sjis == 'っ')
+ || (sjis == 'ゎ') || (sjis == 'ン') || (sjis == 'ッ')
+ || (sjis == 'ヮ') || (sjis == 'ヵ') || (sjis == 'ヶ'))
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ぁ') || (sjis == 'ァ'))
+ && (old != 'ふ') && (old != 'フ') && (old != 'ヴ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ぃ') || (sjis == 'ィ')) && (old != 'う')
+ && (old != 'て') && (old != 'で') && (old != 'ふ')
+ && (old != 'ウ') && (old != 'テ') && (old != 'デ')
+ && (old != 'フ') && (old != 'ヴ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ぅ') || (sjis == 'ゥ'))
+ && (old != 'と') && (old != 'ど')
+ && (old != 'ふ')
+ && (old != 'ト') && (old != 'ド')
+ && (old != 'フ') && (old != 'ヴ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ぇ') || (sjis == 'ェ'))
+ && (old != 'う')
+ && (old != 'し') && (old != 'じ')
+ && (old != 'ち') && (old != 'ぢ')
+ && (old != 'つ') && (old != 'ふ') && (old != 'ウ')
+ && (old != 'シ') && (old != 'ジ')
+ && (old != 'チ') && (old != 'ヂ')
+ && (old != 'ツ') && (old != 'フ') && (old != 'ヴ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ぉ') || (sjis == 'ォ'))
+ && (old != 'う') && (old != 'ふ') && (old != 'ウ') && (old != 'フ') && (old != 'ヴ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ゃ') || (sjis == 'ゅ') || (sjis == 'ょ')
+ || (sjis == 'ャ') || (sjis == 'ュ') || (sjis == 'ョ'))
+ && (old != 'き') && (old != 'し') && (old != 'ち')
+ && (old != 'に') && (old != 'ひ') && (old != 'み')
+ && (old != 'り') && (old != 'ぎ') && (old != 'じ')
+ && (old != 'ぢ') && (old != 'び') && (old != 'ぴ')
+ && (old != 'キ') && (old != 'シ') && (old != 'チ')
+ && (old != 'ニ') && (old != 'ヒ') && (old != 'ミ')
+ && (old != 'リ') && (old != 'ギ') && (old != 'ジ')
+ && (old != 'ヂ') && (old != 'ビ') && (old != 'ピ')
+ && (old != 'ヴ')
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if ((sjis == 'ー')
+ && ((old == 'ん') || (old == 'っ')
+ || (old == 'ン') || (old == 'ッ'))
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((sjis == 'ん') || (sjis == 'ン'))
+ && ((old == 'ん') || (old == 'ン'))
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (((old == 'っ') || (old == 'ッ'))
+ && ((sjis == 'ー')
+ || (sjis == 'あ') || (sjis == 'い') || (sjis == 'う') || (sjis == 'え') || (sjis == 'お')
+ || (sjis == 'な') || (sjis == 'に') || (sjis == 'ぬ') || (sjis == 'ね') || (sjis == 'の')
+ || (sjis == 'ま') || (sjis == 'み') || (sjis == 'む') || (sjis == 'め') || (sjis == 'も')
+ || (sjis == 'や') || (sjis == 'ゆ') || (sjis == 'よ')
+ || (sjis == 'ら') || (sjis == 'り') || (sjis == 'る') || (sjis == 'れ') || (sjis == 'ろ')
+ || (sjis == 'わ') || (sjis == 'ゐ') || (sjis == 'ゑ') || (sjis == 'を')
+ || (sjis == 'ん')
+ || (sjis == 'ぁ') || (sjis == 'ぃ') || (sjis == 'ぅ') || (sjis == 'ぇ') || (sjis == 'ぉ')
+ || (sjis == 'ゃ') || (sjis == 'ゅ') || (sjis == 'ょ')
+ || (sjis == 'っ') || (sjis == 'ゎ')
+
+ || (sjis == 'ア') || (sjis == 'イ') || (sjis == 'ウ') || (sjis == 'エ') || (sjis == 'オ')
+ || (sjis == 'ナ') || (sjis == 'ニ') || (sjis == 'ヌ') || (sjis == 'ネ') || (sjis == 'ノ')
+ || (sjis == 'マ') || (sjis == 'ミ') || (sjis == 'ム') || (sjis == 'メ') || (sjis == 'モ')
+ || (sjis == 'ヤ') || (sjis == 'ユ') || (sjis == 'ヨ')
+ || (sjis == 'ラ') || (sjis == 'リ') || (sjis == 'ル') || (sjis == 'レ') || (sjis == 'ロ')
+ || (sjis == 'ワ') || (sjis == 'ヰ') || (sjis == 'ヱ') || (sjis == 'ヲ')
+ || (sjis == 'ン')
+ || (sjis == 'ァ') || (sjis == 'ィ') || (sjis == 'ゥ') || (sjis == 'ェ') || (sjis == 'ォ')
+ || (sjis == 'ャ') || (sjis == 'ュ') || (sjis == 'ョ')
+ || (sjis == 'ッ') || (sjis == 'ヮ')
+ )
+ ) {
+ ret = CONT_ERR_VOICE_WORD;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ old = sjis;
+ }
+
+ if ((sjis == 'っ') || (sjis == 'ッ')) {
+ ret = CONT_ERR_VOICE_WORD;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicecleardictionary.c b/lib/ultralib/src/voice/voicecleardictionary.c
new file mode 100644
index 0000000..ef6388f
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecleardictionary.c
@@ -0,0 +1,28 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+s32 osVoiceClearDictionary(OSVoiceHandle* hd, u8 words) {
+ s32 ret;
+ u8 stat;
+ u8 buf[4];
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat));
+
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ *(u32*)buf = 0x02000000;
+ buf[2] = words;
+
+ ERRCK(__osVoiceContWrite4(hd->__mq, hd->__channel, 0, buf));
+
+ ret = __osVoiceCheckResult(hd, &stat);
+ if (ret & 0xFF00) {
+ ret = CONT_ERR_INVALID;
+ }
+
+ return ret;
+}
+
diff --git a/lib/ultralib/src/voice/voicecontread2.c b/lib/ultralib/src/voice/voicecontread2.c
new file mode 100644
index 0000000..ae4b07b
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecontread2.c
@@ -0,0 +1,75 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+#include "io/controller_voice.h"
+
+#define READ2FORMAT(p) ((__OSVoiceRead2Format*)(ptr))
+
+s32 __osVoiceContRead2(OSMesgQueue* mq, int channel, u16 address, u8* buffer) {
+ s32 ret;
+ u8 status;
+ int i;
+ u8* ptr;
+ int retry;
+
+ retry = 2;
+
+ __osSiGetAccess();
+
+ do {
+
+ ptr = (u8*)&__osPfsPifRam.ramarray;
+
+ if ((__osContLastCmd != CONT_CMD_READ2_VOICE) || (__osPfsLastChannel != channel)) {
+ __osContLastCmd = CONT_CMD_READ2_VOICE;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = 0;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ READ2FORMAT(ptr)->dummy = CONT_CMD_NOP;
+ READ2FORMAT(ptr)->txsize = CONT_CMD_READ2_VOICE_TX;
+ READ2FORMAT(ptr)->rxsize = CONT_CMD_READ2_VOICE_RX;
+ READ2FORMAT(ptr)->cmd = CONT_CMD_READ2_VOICE;
+ READ2FORMAT(ptr)->datacrc = 0xFF;
+
+ ptr[sizeof(__OSVoiceRead2Format)] = CONT_CMD_END;
+ } else {
+ ptr = (u8*)&__osPfsPifRam.ramarray + channel;
+ }
+
+ READ2FORMAT(ptr)->addrh = address >> 3;
+ READ2FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5);
+
+ __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = CHNL_ERR(*READ2FORMAT(ptr));
+
+ if (ret == 0) {
+ if (__osVoiceContDataCrc(&READ2FORMAT(ptr)->data, ARRLEN(READ2FORMAT(ptr)->data)) != READ2FORMAT(ptr)->datacrc) {
+ ret = __osVoiceGetStatus(mq, channel, &status);
+ if (ret != 0) {
+ break;
+ }
+
+ ret = CONT_ERR_CONTRFAIL;
+ } else {
+ bcopy(&READ2FORMAT(ptr)->data, buffer, ARRLEN(READ2FORMAT(ptr)->data));
+ }
+ } else {
+ ret = CONT_ERR_NO_CONTROLLER;
+ }
+
+ } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicecontread36.c b/lib/ultralib/src/voice/voicecontread36.c
new file mode 100644
index 0000000..a3c80a4
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecontread36.c
@@ -0,0 +1,73 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+#include "io/controller_voice.h"
+
+#define READ36FORMAT(p) ((__OSVoiceRead36Format*)(ptr))
+
+s32 __osVoiceContRead36(OSMesgQueue* mq, s32 channel, u16 address, u8* buffer) {
+ s32 ret;
+ u8 status;
+ s32 i;
+ u8* ptr;
+ s32 retry = 2;
+
+ __osSiGetAccess();
+
+ do {
+
+ ptr = (u8*)&__osPfsPifRam.ramarray;
+
+ if ((__osContLastCmd != CONT_CMD_READ36_VOICE) || (__osPfsLastChannel != channel)) {
+ __osContLastCmd = CONT_CMD_READ36_VOICE;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = 0;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ READ36FORMAT(ptr)->dummy = CONT_CMD_NOP;
+ READ36FORMAT(ptr)->txsize = CONT_CMD_READ36_VOICE_TX;
+ READ36FORMAT(ptr)->rxsize = CONT_CMD_READ36_VOICE_RX;
+ READ36FORMAT(ptr)->cmd = CONT_CMD_READ36_VOICE;
+ READ36FORMAT(ptr)->datacrc = 0xFF;
+
+ ptr[sizeof(__OSVoiceRead36Format)] = CONT_CMD_END;
+ } else {
+ ptr = (u8*)&__osPfsPifRam + channel;
+ }
+
+ READ36FORMAT(ptr)->addrh = address >> 3;
+ READ36FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5);
+
+ __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = CHNL_ERR(*READ36FORMAT(ptr));
+
+ if (ret == 0) {
+ if (__osVoiceContDataCrc(&READ36FORMAT(ptr)->data, ARRLEN(READ36FORMAT(ptr)->data)) != READ36FORMAT(ptr)->datacrc) {
+ ret = __osVoiceGetStatus(mq, channel, &status);
+ if (ret != 0) {
+ break;
+ }
+
+ ret = CONT_ERR_CONTRFAIL;
+ } else {
+ bcopy(&READ36FORMAT(ptr)->data, buffer, ARRLEN(READ36FORMAT(ptr)->data));
+ }
+ } else {
+ ret = CONT_ERR_NO_CONTROLLER;
+ }
+
+ } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicecontrolgain.c b/lib/ultralib/src/voice/voicecontrolgain.c
new file mode 100644
index 0000000..ffb833c
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecontrolgain.c
@@ -0,0 +1,22 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+s32 __osVoiceSetADConverter(OSMesgQueue*, int ch, u8 cmd);
+
+s32 osVoiceControlGain(OSVoiceHandle *hd, s32 analog, s32 digital) {
+ s32 ret;
+ u8 cmd = (u8) (analog == 0 ? 0x18 : 0x98);
+ static u8 digital_table[] = {0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0};
+
+ ERRCK(__osVoiceSetADConverter(hd->__mq,hd->__channel, cmd));
+
+ if ((digital < ARRLEN(digital_table)) && (digital >= 0)) {
+ cmd = digital_table[digital] + 2;
+ } else {
+ return CONT_ERR_INVALID;
+ }
+
+ ERRCK(__osVoiceSetADConverter(hd->__mq,hd->__channel, cmd));
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicecontwrite20.c b/lib/ultralib/src/voice/voicecontwrite20.c
new file mode 100644
index 0000000..3842e3c
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecontwrite20.c
@@ -0,0 +1,77 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+#include "io/controller_voice.h"
+
+#define WRITE20FORMAT(p) ((__OSVoiceWrite20Format*)(ptr))
+
+s32 __osVoiceContWrite20(OSMesgQueue* mq, int channel, u16 address, u8* buffer) {
+ s32 ret;
+ u8 status;
+ int i;
+ u8* ptr;
+ int retry;
+ u8 crc;
+
+ retry = 2;
+
+ __osSiGetAccess();
+
+ do {
+
+ ptr = (u8*)&__osPfsPifRam;
+
+ if ((__osContLastCmd != CONT_CMD_WRITE20_VOICE) || (__osPfsLastChannel != channel)) {
+ __osContLastCmd = CONT_CMD_WRITE20_VOICE;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = 0;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ WRITE20FORMAT(ptr)->dummy = CONT_CMD_NOP;
+ WRITE20FORMAT(ptr)->txsize = CONT_CMD_WRITE20_VOICE_TX;
+ WRITE20FORMAT(ptr)->rxsize = CONT_CMD_WRITE20_VOICE_RX;
+ WRITE20FORMAT(ptr)->cmd = CONT_CMD_WRITE20_VOICE;
+ WRITE20FORMAT(ptr)->datacrc = 0xFF;
+
+ ptr[sizeof(__OSVoiceWrite20Format)] = CONT_CMD_END;
+ } else {
+ ptr = (u8*)&__osPfsPifRam.ramarray + channel;
+ }
+
+ WRITE20FORMAT(ptr)->addrh = address >> 3;
+ WRITE20FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5);
+
+ bcopy(buffer, &WRITE20FORMAT(ptr)->data, 20);
+
+ __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ crc = __osVoiceContDataCrc(buffer, 20);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = (WRITE20FORMAT(ptr)->rxsize & 0xC0) >> 4;
+
+ if (ret == 0) {
+ if (crc != WRITE20FORMAT(ptr)->datacrc) {
+ ret = __osVoiceGetStatus(mq, channel, &status);
+ if (ret != 0) {
+ break;
+ }
+
+ ret = CONT_ERR_CONTRFAIL;
+ }
+ } else {
+ ret = CONT_ERR_NO_CONTROLLER;
+ }
+
+ } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicecontwrite4.c b/lib/ultralib/src/voice/voicecontwrite4.c
new file mode 100644
index 0000000..c2af86d
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecontwrite4.c
@@ -0,0 +1,75 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+#include "io/controller_voice.h"
+
+#define WRITE4FORMAT(p) ((__OSVoiceWrite4Format*)(ptr))
+
+s32 __osVoiceContWrite4(OSMesgQueue* mq, int channel, u16 address, u8 dst[4]) {
+ s32 ret;
+ u8 status;
+ int i;
+ u8* ptr;
+ s32 retry = 2;
+ u8 crc;
+
+ __osSiGetAccess();
+
+ do {
+
+ ptr = (u8*)&__osPfsPifRam;
+
+ if ((__osContLastCmd != CONT_CMD_WRITE4_VOICE) || (__osPfsLastChannel != channel)) {
+ __osContLastCmd = CONT_CMD_WRITE4_VOICE;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = 0;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ WRITE4FORMAT(ptr)->dummy = CONT_CMD_NOP;
+ WRITE4FORMAT(ptr)->txsize = CONT_CMD_WRITE4_VOICE_TX;
+ WRITE4FORMAT(ptr)->rxsize = CONT_CMD_WRITE4_VOICE_RX;
+ WRITE4FORMAT(ptr)->cmd = CONT_CMD_WRITE4_VOICE;
+ WRITE4FORMAT(ptr)->datacrc = 0xFF;
+
+ ptr[sizeof(__OSVoiceWrite4Format)] = CONT_CMD_END;
+ } else {
+ ptr = (u8*)&__osPfsPifRam + channel;
+ }
+
+ WRITE4FORMAT(ptr)->addrh = address >> 3;
+ WRITE4FORMAT(ptr)->addrl = __osContAddressCrc(address) | (address << 5);
+
+ bcopy(dst, &WRITE4FORMAT(ptr)->data, 4);
+
+ __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ crc = __osVoiceContDataCrc(dst, 4);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = (WRITE4FORMAT(ptr)->rxsize & 0xC0) >> 4;
+
+ if (ret == 0) {
+ if (crc != WRITE4FORMAT(ptr)->datacrc) {
+ ret = __osVoiceGetStatus(mq, channel, &status);
+ if (ret != 0) {
+ break;
+ }
+
+ ret = CONT_ERR_CONTRFAIL;
+ }
+ } else {
+ ret = CONT_ERR_NO_CONTROLLER;
+ }
+
+ } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicecountsyllables.c b/lib/ultralib/src/voice/voicecountsyllables.c
new file mode 100644
index 0000000..89b4c63
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecountsyllables.c
@@ -0,0 +1,59 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+// The VRU can store only 880 semisyllables of words in its dictionary.
+// Use this function to determine the semisyllable count before adding a word with osVoiceSetWord,
+// to properly see whether it will fit.
+
+void osVoiceCountSyllables(u8 *data, u32 *syllable) {
+ s32 k;
+ u16 sjis;
+ u16 old;
+
+ old = 0;
+ *syllable = 1;
+ for (k = 0; data[k] != 0; k += 2) {
+ sjis = data[k + 1] + (data[k] << 8);
+ if ((sjis == 'あ') || (sjis == 'い') || (sjis == 'う') || (sjis == 'え') || (sjis == 'お')
+ || (sjis == 'ア') || (sjis == 'イ') || (sjis == 'ウ') || (sjis == 'エ') || (sjis == 'オ')
+ ) {
+ if (k == 0) {
+ *syllable += 2;
+ } else {
+ *syllable += 1;
+ }
+ } else if ((sjis == 'か') || (sjis == 'き') || (sjis == 'く') || (sjis == 'け') || (sjis == 'こ')
+ || (sjis == 'た') || (sjis == 'ち') || (sjis == 'つ') || (sjis == 'て') || (sjis == 'と')
+ || (sjis == 'ぱ') || (sjis == 'ぴ') || (sjis == 'ぷ') || (sjis == 'ぺ') || (sjis == 'ぽ')
+ || (sjis == 'カ') || (sjis == 'キ') || (sjis == 'ク') || (sjis == 'ケ') || (sjis == 'コ')
+ || (sjis == 'タ') || (sjis == 'チ') || (sjis == 'ツ') || (sjis == 'テ') || (sjis == 'ト')
+ || (sjis == 'パ') || (sjis == 'ピ') || (sjis == 'プ') || (sjis == 'ペ') || (sjis == 'ポ')
+ ) {
+ if (k == 0) {
+ *syllable += 2;
+ } else if ((old == 'っ') || (old == 'ッ')) {
+ *syllable += 2;
+ } else {
+ *syllable += 3;
+ }
+ } else if ((sjis == 'ぁ') || (sjis == 'ぃ') || (sjis == 'ぅ') || (sjis == 'ぇ') || (sjis == 'ぉ')
+ || (sjis == 'ゃ') || (sjis == 'ゅ') || (sjis == 'ょ') || (sjis == 'ゎ')
+
+ || (sjis == 'ァ') || (sjis == 'ィ') || (sjis == 'ゥ') || (sjis == 'ェ') || (sjis == 'ォ')
+ || (sjis == 'ャ') || (sjis == 'ュ') || (sjis == 'ョ') || (sjis == 'ヮ')
+ || (sjis == 'ヵ') || (sjis == 'ヶ')
+ ) {
+ if ((old == 'あ') || (old == 'い') || (old == 'う') || (old == 'え') || (old == 'お')
+ || (old == 'ア') || (old == 'イ') || (old == 'ウ') || (old == 'エ') || (old == 'オ')
+ ) {
+ *syllable += 1;
+ }
+ } else if ((sjis == 'ん') || (sjis == 'ー') || (sjis == 'っ') || (sjis == 'ン') || (sjis == 'ッ')) {
+ *syllable += 1;
+ } else {
+ *syllable += 2;
+ }
+ old = sjis;
+ }
+}
diff --git a/lib/ultralib/src/voice/voicecrc.c b/lib/ultralib/src/voice/voicecrc.c
new file mode 100644
index 0000000..95741e6
--- /dev/null
+++ b/lib/ultralib/src/voice/voicecrc.c
@@ -0,0 +1,40 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+#define VOICE_CRC_LENGTH 8
+#define VOICE_CRC_GENERATOR 0x85
+
+u8 __osVoiceContDataCrc(u8* data, u32 length) {
+ s32 ret = 0;
+ u32 i;
+ u32 j;
+
+ for (j = length; j != 0; j--, data++) {
+ // Loop over each i in the j starting with most significant
+ for (i = (1 << (VOICE_CRC_LENGTH - 1)); i != 0; i >>= 1) {
+ ret <<= 1;
+ if (*data & i) {
+ if (ret & (1 << VOICE_CRC_LENGTH)) {
+ // Same as ret++; ret ^= 0x85 since last i always 0 after the shift
+ ret ^= VOICE_CRC_GENERATOR - 1;
+ } else {
+ ret++;
+ }
+ } else if (ret & (1 << VOICE_CRC_LENGTH)) {
+ ret ^= VOICE_CRC_GENERATOR;
+ }
+ }
+ }
+ // Act like a j of zeros is appended to data
+ do {
+ ret <<= 1;
+ if (ret & (1 << VOICE_CRC_LENGTH)) {
+ ret ^= VOICE_CRC_GENERATOR;
+ }
+ j++;
+ } while (j < VOICE_CRC_LENGTH);
+
+ // Discarding the excess is done automatically by the return type
+ return ret;
+} \ No newline at end of file
diff --git a/lib/ultralib/src/voice/voicegetreaddata.c b/lib/ultralib/src/voice/voicegetreaddata.c
new file mode 100644
index 0000000..5627846
--- /dev/null
+++ b/lib/ultralib/src/voice/voicegetreaddata.c
@@ -0,0 +1,94 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+
+s32 osVoiceGetReadData(OSVoiceHandle* hd, OSVoiceData* micdata) {
+ s32 ret = 0;
+ s32 i;
+ u8 stat;
+ u8 temp[36];
+ static u8 c;
+
+ switch (hd->__mode) {
+ case 1:
+ ret = __osVoiceGetStatus(hd->__mq, hd->__channel, &stat);
+ if (ret != 0) {
+ return ret;
+ } else if (stat & 1) {
+ return CONT_ERR_NOT_READY;
+ }
+
+ ERRCK(__osVoiceContRead2(hd->__mq, hd->__channel, 0, temp));
+
+ c = temp[0] & 7;
+ hd->cmd_status = c;
+ if ((c != 0) && (c != 7)) {
+ return CONT_ERR_NOT_READY;
+ }
+ case 2:
+ hd->__mode = 2;
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat))
+
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ *(u32*)temp = 0x600;
+ ERRCK(__osVoiceContWrite4(hd->__mq, hd->__channel, 0, temp));
+
+ case 3:
+ hd->__mode = 3;
+
+ ret = __osVoiceGetStatus(hd->__mq, hd->__channel, &stat);
+ if (ret != 0) {
+ return ret;
+ } else if (stat & 1) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ ERRCK(__osVoiceContRead36(hd->__mq, hd->__channel, 0, temp));
+
+ micdata->warning = temp[4] + (temp[5] << 8);
+ micdata->answer_num = temp[6];
+ micdata->voice_level = temp[8] + (temp[9] << 8);
+ micdata->voice_sn = temp[10] + (temp[11] << 8);
+ micdata->voice_time = temp[12] + (temp[13] << 8);
+
+ for (i = 0; i < 5; i++) {
+ micdata->answer[i] = temp[14 + (i << 2)] + (temp[15 + (i << 2)] << 8);
+ micdata->distance[i] = temp[16 + (i << 2)] + (temp[17 + (i << 2)] << 8);
+ }
+
+ if (micdata->answer[0] == 0x7FFF) {
+ micdata->answer_num = 0;
+ }
+
+ hd->cmd_status = temp[34] & 7;
+ if ((c == 0) || (hd->cmd_status == 0)) {
+ break;
+ }
+ case 4:
+ hd->__mode = 4;
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat));
+
+ if (stat & 1) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ ERRCK(__osVoiceContRead2(hd->__mq, hd->__channel, 0, temp));
+
+ hd->cmd_status = temp[0] & 7;
+ if (temp[0] & 7) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ break;
+ default:
+ return CONT_ERR_INVALID;
+ }
+ hd->__mode = 0;
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicegetstatus.c b/lib/ultralib/src/voice/voicegetstatus.c
new file mode 100644
index 0000000..8d33f31
--- /dev/null
+++ b/lib/ultralib/src/voice/voicegetstatus.c
@@ -0,0 +1,61 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+
+s32 __osVoiceGetStatus(OSMesgQueue* mq, s32 port, u8* status) {
+ __OSContRequesFormatShort header;
+ s32 ret = 0;
+ s32 i;
+ u8* ptr = (u8*)&__osContPifRam.ramarray;
+ s32 retry = 2;
+
+ __osSiGetAccess();
+
+ do {
+ if (ret != CONT_ERR_CONTRFAIL) {
+ __osContPifRam.pifstatus = CONT_CMD_EXE;
+
+ for (i = 0; i < port; i++, *ptr++ = 0) {
+ ;
+ }
+
+ *ptr++ = CONT_CMD_REQUEST_STATUS_TX;
+ *ptr++ = CONT_CMD_REQUEST_STATUS_RX;
+ *ptr = CONT_CMD_REQUEST_STATUS;
+ ptr += 4;
+ *ptr = CONT_CMD_END;
+
+ __osContLastCmd = CONT_CMD_END;
+ ret = __osSiRawStartDma(OS_WRITE, &__osContPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ }
+ ret = __osSiRawStartDma(OS_READ, &__osContPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ptr = (u8*)&__osContPifRam.ramarray + port;
+
+ header = *((__OSContRequesFormatShort*)ptr);
+
+ ret = CHNL_ERR(header);
+ *status = header.status;
+
+ if (ret == 0) {
+ if (header.typeh == 0 && header.typel == 1) {
+ if (header.status & 4) {
+ ret = CONT_ERR_CONTRFAIL;
+ }
+ } else {
+ ret = CONT_ERR_DEVICE;
+ }
+ } else if (ret & CONT_NO_RESPONSE_ERROR) {
+ ret = CONT_ERR_NO_CONTROLLER;
+ } else {
+ ret = CONT_ERR_CONTRFAIL;
+ }
+ } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voiceinit.c b/lib/ultralib/src/voice/voiceinit.c
new file mode 100644
index 0000000..a60f943
--- /dev/null
+++ b/lib/ultralib/src/voice/voiceinit.c
@@ -0,0 +1,40 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+s32 osVoiceInit(OSMesgQueue* mq, OSVoiceHandle* handle, int channel) {
+ s32 ret;
+ s32 i;
+ u8 stat = 0;
+ u8 buf[4];
+ static u8 cmd[] = {0x1E, 0x6E, 0x08, 0x56, 0x03};
+
+ handle->__channel = channel;
+ handle->__mq = mq;
+ handle->__mode = 0;
+
+ ERRCK(__osVoiceGetStatus(mq, channel, &stat));
+
+ if (__osContChannelReset(mq, channel) != 0) {
+ return CONT_ERR_CONTRFAIL;
+ }
+
+ for (i = 0; i < ARRLEN(cmd); i++) {
+ ERRCK(__osVoiceSetADConverter(mq, channel, cmd[i]));
+ }
+
+ ERRCK(__osVoiceGetStatus(mq, channel, &stat));
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ *(u32*)buf = 0x100;
+ ERRCK(__osVoiceContWrite4(mq, channel, 0, buf));
+
+ ret = __osVoiceCheckResult(handle, &stat);
+ if (ret & 0xFF00) {
+ ret = CONT_ERR_INVALID;
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voiceinternal.h b/lib/ultralib/src/voice/voiceinternal.h
new file mode 100644
index 0000000..899c150
--- /dev/null
+++ b/lib/ultralib/src/voice/voiceinternal.h
@@ -0,0 +1,10 @@
+#ifndef VOICE_INTERNAL_H
+#define VOICE_INTERNAL_H
+
+// Various prototypes and externs that don't show up in os_voice.h
+extern s32 __osPfsLastChannel;
+
+u8 __osVoiceContDataCrc(u8* data, u32 length);
+s32 __osVoiceCheckResult(OSVoiceHandle* hd, u8* stat);
+
+#endif
diff --git a/lib/ultralib/src/voice/voicemaskdictionary.c b/lib/ultralib/src/voice/voicemaskdictionary.c
new file mode 100644
index 0000000..a017e3d
--- /dev/null
+++ b/lib/ultralib/src/voice/voicemaskdictionary.c
@@ -0,0 +1,47 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+
+s32 osVoiceMaskDictionary(OSVoiceHandle* hd, u8* pattern, int size) {
+ s32 ret;
+ s32 i;
+ s32 j;
+ u8 stat;
+ u8 buf[20];
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat));
+
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ if (size & 1) {
+ j = size + 1;
+ } else {
+ j = size;
+ }
+
+ bzero(&buf, ARRLEN(buf));
+
+ buf[18 - j] = 4;
+
+ for (i = 0; i < j; i += 2) {
+ buf[i + ARRLEN(buf) - j] = pattern[i];
+ buf[i + ARRLEN(buf) - j + 1] = pattern[i + 1];
+ }
+
+ if (size & 1) {
+ buf[ARRLEN(buf) - 1] = 0;
+ }
+
+ ret = __osVoiceContWrite20(hd->__mq, hd->__channel, 0, &buf);
+ if (ret == 0) {
+ ret = __osVoiceCheckResult(hd, &stat);
+ if (ret & 0xFF00) {
+ ret = CONT_ERR_INVALID;
+ }
+ }
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicesetadconverter.c b/lib/ultralib/src/voice/voicesetadconverter.c
new file mode 100644
index 0000000..2287c0d
--- /dev/null
+++ b/lib/ultralib/src/voice/voicesetadconverter.c
@@ -0,0 +1,70 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+#include "io/controller_voice.h"
+
+#define SWRITEFORMAT(p) ((__OSVoiceSWriteFormat*)(p))
+
+s32 __osVoiceSetADConverter(OSMesgQueue* mq, s32 channel, u8 data) {
+ s32 ret;
+ int i;
+ u8* ptr;
+ u8 status;
+ int retry = 2;
+
+ __osSiGetAccess();
+
+ do {
+
+ ptr = (u8*)__osPfsPifRam.ramarray;
+
+ if ((__osContLastCmd != CONT_CMD_SWRITE_VOICE) || (__osPfsLastChannel != channel)) {
+ __osContLastCmd = CONT_CMD_SWRITE_VOICE;
+ __osPfsLastChannel = channel;
+
+ for (i = 0; i < channel; i++) {
+ *ptr++ = 0;
+ }
+
+ __osPfsPifRam.pifstatus = CONT_CMD_EXE;
+
+ SWRITEFORMAT(ptr)->txsize = CONT_CMD_SWRITE_VOICE_TX;
+ SWRITEFORMAT(ptr)->rxsize = CONT_CMD_SWRITE_VOICE_RX;
+ SWRITEFORMAT(ptr)->cmd = CONT_CMD_SWRITE_VOICE;
+ SWRITEFORMAT(ptr)->datacrc = 0;
+
+ ptr[sizeof(__OSVoiceSWriteFormat)] = CONT_CMD_END;
+ } else {
+ ptr = (u8*)&__osPfsPifRam + channel;
+ }
+
+ SWRITEFORMAT(ptr)->data = data;
+ SWRITEFORMAT(ptr)->scrc = __osContAddressCrc(data * 8);
+
+ __osSiRawStartDma(OS_WRITE, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ __osSiRawStartDma(OS_READ, &__osPfsPifRam);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+
+ ret = CHNL_ERR(*SWRITEFORMAT(ptr));
+
+ if (ret == 0) {
+ if (SWRITEFORMAT(ptr)->datacrc & 1) {
+ ret = __osVoiceGetStatus(mq, channel, &status);
+ if (ret != 0) {
+ break;
+ }
+
+ ret = CONT_ERR_CONTRFAIL;
+ }
+ } else {
+ ret = CONT_ERR_NO_CONTROLLER;
+ }
+
+ } while ((ret == CONT_ERR_CONTRFAIL) && (retry-- >= 0));
+
+ __osSiRelAccess();
+
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicesetword.c b/lib/ultralib/src/voice/voicesetword.c
new file mode 100644
index 0000000..9a7ed6f
--- /dev/null
+++ b/lib/ultralib/src/voice/voicesetword.c
@@ -0,0 +1,44 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+
+s32 osVoiceSetWord(OSVoiceHandle *hd, u8 *word) {
+ s32 j;
+ s32 k;
+ s32 ret;
+ u8 stat;
+ u8 buf[40];
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat));
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+ for (k = 0; word[k] != 0; k += 2) {
+ ;
+ }
+
+ bzero(buf, ARRLEN(buf));
+
+ for (j = 0; j < k; j += 2) {
+ buf[ARRLEN(buf) - 1 - k + j] = word[j];
+ buf[ARRLEN(buf) - 1 - k + j - 1] = word[j + 1];
+ }
+
+ buf[ARRLEN(buf) - 1 - j - 5] = 3;
+
+ if (k >= 15) {
+ ERRCK(__osVoiceContWrite20(hd->__mq, hd->__channel, 0, buf));
+ }
+ ERRCK(__osVoiceContWrite20(hd->__mq, hd->__channel, 0, buf + 20));
+ ret = __osVoiceCheckResult(hd, &stat);
+ if (ret != 0) {
+ if (ret & 0x100) {
+ ret = CONT_ERR_VOICE_MEMORY;
+ } else if (ret & 0x200) {
+ ret = CONT_ERR_VOICE_WORD;
+ } else if (ret & 0xFF00) {
+ ret = CONT_ERR_INVALID;
+ }
+ }
+ return ret;
+}
diff --git a/lib/ultralib/src/voice/voicestartreaddata.c b/lib/ultralib/src/voice/voicestartreaddata.c
new file mode 100644
index 0000000..0f9fc73
--- /dev/null
+++ b/lib/ultralib/src/voice/voicestartreaddata.c
@@ -0,0 +1,35 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+
+s32 osVoiceStartReadData(OSVoiceHandle* hd) {
+ s32 ret;
+ u8 stat;
+ u8 temp[4];
+
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat));
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ if (hd->__mode != 0) {
+ return CONT_ERR_INVALID;
+ }
+
+ *(u32*)temp = 0x5000000;
+ ret = __osVoiceContWrite4(hd->__mq, hd->__channel, 0, temp);
+
+ if (ret == 0) {
+ ret = __osVoiceCheckResult(hd, &stat);
+
+ if (ret & 0xFF00) {
+ ret = CONT_ERR_INVALID;
+ } else {
+ hd->__mode = 1;
+ }
+ }
+
+ return ret;
+} \ No newline at end of file
diff --git a/lib/ultralib/src/voice/voicestopreaddata.c b/lib/ultralib/src/voice/voicestopreaddata.c
new file mode 100644
index 0000000..e5b97ca
--- /dev/null
+++ b/lib/ultralib/src/voice/voicestopreaddata.c
@@ -0,0 +1,44 @@
+#include "PR/os_internal.h"
+#include "io/controller.h"
+#include "PR/os_voice.h"
+#include "voiceinternal.h"
+
+s32 osVoiceStopReadData(OSVoiceHandle* hd) {
+ s32 ret;
+ s32 i;
+ u8 stat;
+ u8 temp[4];
+
+ ERRCK(__osVoiceGetStatus(hd->__mq, hd->__channel, &stat));
+
+ if (stat & 2) {
+ return CONT_ERR_VOICE_NO_RESPONSE;
+ }
+
+ if (hd->__mode == 0) {
+ return CONT_ERR_INVALID;
+ }
+
+ *(u32*)temp = 0x700;
+ ret = __osVoiceContWrite4(hd->__mq, hd->__channel, 0, temp);
+
+ if (ret == 0) {
+ i = 0;
+ do {
+ ret = __osVoiceCheckResult(hd, &stat);
+ if (ret & 0xFF00) {
+ if (((ret & 7) == 0) || ((ret & 7) == 7)) {
+ ret = 0;
+ hd->__mode = 0;
+ } else {
+ ret = CONT_ERR_INVALID;
+ }
+ } else {
+ hd->__mode = 0;
+ }
+ i++;
+ } while ((ret == CONT_ERR_VOICE_NO_RESPONSE) && (i < 20));
+ }
+
+ return ret;
+} \ No newline at end of file