From d66a21685f45d130f980e8a5ec7b08cfe189e40b Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Tue, 28 Mar 2023 23:42:56 -0300 Subject: [PATCH] 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 * 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 --- .clang-format | 23 + .clang-tidy | 9 + .gitignore | 28 + .vscode/c_cpp_properties.json | 37 + Makefile | 276 + README.md | 71 + animalforest.jp.md5 | 1 + animalforest.jp.yaml | 496 ++ animalforest_uncompressed.jp.md5 | 1 + diff.py | 1 + diff_settings.py | 21 + include/alignment.h | 33 + include/attributes.h | 39 + include/global.h | 19 + include/libc/assert.h | 23 + include/libc/stdbool.h | 30 + include/libc/stddef.h | 25 + include/libc/stdint.h | 29 + include/macro.inc | 87 + include/macros.h | 18 + include/other_types.h | 11 + include/segment_symbols.h | 66 + include/stack.h | 14 + include/unk.h | 19 + include/unknown_structs.h | 10 + lib/ultralib/.github/workflows/ci_egcs.txt | 42 + lib/ultralib/.github/workflows/ci_gcc.yml | 41 + lib/ultralib/.github/workflows/ci_ido.txt | 42 + lib/ultralib/.gitignore | 25 + lib/ultralib/.gitrepo | 12 + lib/ultralib/Makefile | 161 + lib/ultralib/README.md | 43 + lib/ultralib/include/PR/R4300.h | 453 ++ lib/ultralib/include/PR/abi.h | 410 + lib/ultralib/include/PR/gbi.h | 4572 +++++++++++ lib/ultralib/include/PR/gs2dex.h | 392 + lib/ultralib/include/PR/gt.h | 365 + lib/ultralib/include/PR/gu.h | 269 + lib/ultralib/include/PR/libaudio.h | 947 +++ lib/ultralib/include/PR/mbi.h | 100 + lib/ultralib/include/PR/os.h | 108 + lib/ultralib/include/PR/os_ai.h | 92 + lib/ultralib/include/PR/os_cache.h | 96 + lib/ultralib/include/PR/os_cont.h | 208 + lib/ultralib/include/PR/os_convert.h | 111 + lib/ultralib/include/PR/os_debug.h | 117 + lib/ultralib/include/PR/os_eeprom.h | 107 + lib/ultralib/include/PR/os_error.h | 86 + lib/ultralib/include/PR/os_exception.h | 86 + lib/ultralib/include/PR/os_flash.h | 77 + lib/ultralib/include/PR/os_gbpak.h | 107 + lib/ultralib/include/PR/os_gio.h | 86 + lib/ultralib/include/PR/os_host.h | 161 + lib/ultralib/include/PR/os_internal.h | 50 + lib/ultralib/include/PR/os_internal_debug.h | 43 + lib/ultralib/include/PR/os_internal_error.h | 45 + .../include/PR/os_internal_exception.h | 49 + lib/ultralib/include/PR/os_internal_flash.h | 40 + lib/ultralib/include/PR/os_internal_gio.h | 45 + lib/ultralib/include/PR/os_internal_host.h | 42 + lib/ultralib/include/PR/os_internal_reg.h | 57 + lib/ultralib/include/PR/os_internal_rsp.h | 48 + lib/ultralib/include/PR/os_internal_si.h | 46 + lib/ultralib/include/PR/os_internal_thread.h | 43 + lib/ultralib/include/PR/os_internal_tlb.h | 47 + lib/ultralib/include/PR/os_libc.h | 100 + lib/ultralib/include/PR/os_message.h | 162 + lib/ultralib/include/PR/os_motor.h | 83 + lib/ultralib/include/PR/os_pfs.h | 200 + lib/ultralib/include/PR/os_pi.h | 221 + lib/ultralib/include/PR/os_rdp.h | 92 + lib/ultralib/include/PR/os_reg.h | 90 + lib/ultralib/include/PR/os_rsp.h | 86 + lib/ultralib/include/PR/os_si.h | 86 + lib/ultralib/include/PR/os_system.h | 118 + lib/ultralib/include/PR/os_thread.h | 161 + lib/ultralib/include/PR/os_time.h | 114 + lib/ultralib/include/PR/os_tlb.h | 107 + lib/ultralib/include/PR/os_version.h | 16 + lib/ultralib/include/PR/os_vi.h | 298 + lib/ultralib/include/PR/os_voice.h | 108 + lib/ultralib/include/PR/ramrom.h | 113 + lib/ultralib/include/PR/rcp.h | 848 +++ lib/ultralib/include/PR/rdb.h | 93 + lib/ultralib/include/PR/region.h | 123 + lib/ultralib/include/PR/rmon.h | 39 + lib/ultralib/include/PR/sched.h | 115 + lib/ultralib/include/PR/sp.h | 196 + lib/ultralib/include/PR/sptask.h | 201 + lib/ultralib/include/PR/ucode.h | 192 + lib/ultralib/include/PR/ultraerror.h | 165 + lib/ultralib/include/PR/ultralog.h | 74 + lib/ultralib/include/PR/ultratypes.h | 85 + lib/ultralib/include/assert.h | 12 + lib/ultralib/include/dbgdefs.h | 8 + lib/ultralib/include/dbgproto.h | 402 + lib/ultralib/include/gcc/math.h | 1 + lib/ultralib/include/gcc/memory.h | 23 + lib/ultralib/include/gcc/stdarg.h | 121 + lib/ultralib/include/gcc/stdio.h | 1 + lib/ultralib/include/gcc/stdlib.h | 81 + lib/ultralib/include/gcc/string.h | 42 + lib/ultralib/include/macros.h | 16 + lib/ultralib/include/sys/asm.h | 72 + lib/ultralib/include/sys/regdef.h | 187 + lib/ultralib/include/ultra64.h | 40 + lib/ultralib/include/ultrahost.h | 59 + lib/ultralib/src/audio/Makefile | 120 + lib/ultralib/src/audio/auxbus.c | 65 + lib/ultralib/src/audio/bnkf.c | 143 + lib/ultralib/src/audio/cents2ratio.c | 33 + lib/ultralib/src/audio/copy.c | 35 + lib/ultralib/src/audio/cseq.c | 409 + lib/ultralib/src/audio/cseq.h | 11 + lib/ultralib/src/audio/cseqp.h | 10 + lib/ultralib/src/audio/cspdelete.c | 29 + lib/ultralib/src/audio/cspgetchlvol.c | 27 + lib/ultralib/src/audio/cspgetfxmix.c | 27 + lib/ultralib/src/audio/cspgetpan.c | 27 + lib/ultralib/src/audio/cspgetpriority.c | 26 + lib/ultralib/src/audio/cspgetprogram.c | 42 + lib/ultralib/src/audio/cspgetseq.c | 29 + lib/ultralib/src/audio/cspgetstate.c | 29 + lib/ultralib/src/audio/cspgettempo.c | 31 + lib/ultralib/src/audio/cspgetvol.c | 27 + lib/ultralib/src/audio/csplayer.c | 886 +++ lib/ultralib/src/audio/cspplay.c | 34 + lib/ultralib/src/audio/cspsendmidi.c | 40 + lib/ultralib/src/audio/cspsetbank.c | 32 + lib/ultralib/src/audio/cspsetchlvol.c | 35 + lib/ultralib/src/audio/cspsetfxmix.c | 35 + lib/ultralib/src/audio/cspsetpan.c | 35 + lib/ultralib/src/audio/cspsetpriority.c | 32 + lib/ultralib/src/audio/cspsetprogram.c | 35 + lib/ultralib/src/audio/cspsetseq.c | 34 + lib/ultralib/src/audio/cspsettempo.c | 36 + lib/ultralib/src/audio/cspsetvol.c | 32 + lib/ultralib/src/audio/cspstop.c | 32 + lib/ultralib/src/audio/drvrnew.c | 306 + lib/ultralib/src/audio/env.c | 595 ++ lib/ultralib/src/audio/event.c | 272 + lib/ultralib/src/audio/filter.c | 32 + lib/ultralib/src/audio/heapalloc.c | 65 + lib/ultralib/src/audio/heapcheck.c | 71 + lib/ultralib/src/audio/heapinit.c | 37 + lib/ultralib/src/audio/initfx.h | 59 + lib/ultralib/src/audio/load.c | 471 ++ lib/ultralib/src/audio/mainbus.c | 67 + lib/ultralib/src/audio/parse_abi.c | 47 + lib/ultralib/src/audio/resample.c | 150 + lib/ultralib/src/audio/reverb.c | 457 ++ lib/ultralib/src/audio/save.c | 73 + lib/ultralib/src/audio/seq.c | 343 + lib/ultralib/src/audio/seq.h | 9 + lib/ultralib/src/audio/seqp.h | 37 + lib/ultralib/src/audio/seqpdelete.c | 42 + lib/ultralib/src/audio/seqpgetchlvol.c | 27 + lib/ultralib/src/audio/seqpgetfxmix.c | 27 + lib/ultralib/src/audio/seqpgetpan.c | 27 + lib/ultralib/src/audio/seqpgetpriority.c | 26 + lib/ultralib/src/audio/seqpgetprogram.c | 42 + lib/ultralib/src/audio/seqpgetseq.c | 29 + lib/ultralib/src/audio/seqpgetstate.c | 29 + lib/ultralib/src/audio/seqpgettempo.c | 31 + lib/ultralib/src/audio/seqpgetvol.c | 27 + lib/ultralib/src/audio/seqplayer.c | 1231 +++ lib/ultralib/src/audio/seqploop.c | 35 + lib/ultralib/src/audio/seqpplay.c | 48 + lib/ultralib/src/audio/seqpsendmidi.c | 40 + lib/ultralib/src/audio/seqpsetbank.c | 32 + lib/ultralib/src/audio/seqpsetchlvol.c | 35 + lib/ultralib/src/audio/seqpsetfxmix.c | 35 + lib/ultralib/src/audio/seqpsetpan.c | 35 + lib/ultralib/src/audio/seqpsetpriority.c | 32 + lib/ultralib/src/audio/seqpsetprogram.c | 36 + lib/ultralib/src/audio/seqpsetseq.c | 34 + lib/ultralib/src/audio/seqpsettempo.c | 36 + lib/ultralib/src/audio/seqpsetvol.c | 32 + lib/ultralib/src/audio/seqpstop.c | 33 + lib/ultralib/src/audio/sl.c | 65 + lib/ultralib/src/audio/sndp.h | 102 + lib/ultralib/src/audio/sndpallocate.c | 43 + lib/ultralib/src/audio/sndpdeallocate.c | 35 + lib/ultralib/src/audio/sndpdelete.c | 44 + lib/ultralib/src/audio/sndpgetsound.c | 27 + lib/ultralib/src/audio/sndpgetstate.c | 29 + lib/ultralib/src/audio/sndplayer.c | 300 + lib/ultralib/src/audio/sndpplay.c | 36 + lib/ultralib/src/audio/sndpplayat.c | 32 + lib/ultralib/src/audio/sndpsetfxmix.c | 42 + lib/ultralib/src/audio/sndpsetpan.c | 42 + lib/ultralib/src/audio/sndpsetpitch.c | 48 + lib/ultralib/src/audio/sndpsetpriority.c | 38 + lib/ultralib/src/audio/sndpsetsound.c | 36 + lib/ultralib/src/audio/sndpsetvol.c | 42 + lib/ultralib/src/audio/sndpstop.c | 35 + lib/ultralib/src/audio/synaddplayer.c | 34 + lib/ultralib/src/audio/synallocfx.c | 32 + lib/ultralib/src/audio/synallocvoice.c | 132 + lib/ultralib/src/audio/syndelete.c | 27 + lib/ultralib/src/audio/synfreefx.c | 26 + lib/ultralib/src/audio/synfreevoice.c | 54 + lib/ultralib/src/audio/syngetfxref.c | 33 + lib/ultralib/src/audio/syngetpriority.c | 27 + lib/ultralib/src/audio/synremoveplayer.c | 49 + lib/ultralib/src/audio/synsetfxmix.c | 51 + lib/ultralib/src/audio/synsetfxparam.c | 29 + lib/ultralib/src/audio/synsetpan.c | 50 + lib/ultralib/src/audio/synsetpitch.c | 50 + lib/ultralib/src/audio/synsetpriority.c | 27 + lib/ultralib/src/audio/synsetvol.c | 50 + lib/ultralib/src/audio/synstartvoice.c | 48 + lib/ultralib/src/audio/synstartvoiceparam.c | 64 + lib/ultralib/src/audio/synstopvoice.c | 44 + lib/ultralib/src/audio/synthInternals.h | 338 + lib/ultralib/src/audio/synthesizer.c | 327 + lib/ultralib/src/debug/osint_debug.h | 11 + lib/ultralib/src/debug/threadprofile.c | 22 + lib/ultralib/src/debug/threadprofileclear.c | 11 + lib/ultralib/src/debug/threadprofileinit.c | 16 + .../src/debug/threadprofilereadcount.c | 31 + .../src/debug/threadprofilereadtime.c | 43 + lib/ultralib/src/debug/threadprofilestart.c | 20 + lib/ultralib/src/debug/threadprofilestop.c | 34 + lib/ultralib/src/flash/flashallerase.c | 31 + lib/ultralib/src/flash/flashallerasethrough.c | 7 + lib/ultralib/src/flash/flashchange.c | 8 + lib/ultralib/src/flash/flashcheckeraseend.c | 21 + lib/ultralib/src/flash/flashclearstatus.c | 10 + lib/ultralib/src/flash/flashgetaddr.c | 7 + lib/ultralib/src/flash/flashinit.c | 43 + lib/ultralib/src/flash/flashreadarray.c | 49 + lib/ultralib/src/flash/flashreadid.c | 27 + lib/ultralib/src/flash/flashreadstatus.c | 17 + lib/ultralib/src/flash/flashreinit.c | 14 + lib/ultralib/src/flash/flashsectorerase.c | 31 + .../src/flash/flashsectorerasethrough.c | 7 + lib/ultralib/src/flash/flashwritearray.c | 33 + lib/ultralib/src/flash/flashwritebuffer.c | 19 + lib/ultralib/src/gio/giointerrupt.c | 8 + lib/ultralib/src/gio/giorawinterrupt.c | 18 + lib/ultralib/src/gt/Makefile | 19 + lib/ultralib/src/gt/dumpturbo.c | 255 + lib/ultralib/src/gt/gt.c | 155 + lib/ultralib/src/gt/gtint.h | 36 + lib/ultralib/src/gu/Makefile | 52 + lib/ultralib/src/gu/align.c | 75 + lib/ultralib/src/gu/cosf.c | 137 + lib/ultralib/src/gu/coss.c | 45 + lib/ultralib/src/gu/dump_gbi.c | 274 + lib/ultralib/src/gu/frustum.c | 42 + lib/ultralib/src/gu/guint.h | 42 + lib/ultralib/src/gu/guloadtile_bug.c | 235 + lib/ultralib/src/gu/libm_vals.s | 5 + lib/ultralib/src/gu/loadtextureblockmipmap.c | 716 ++ lib/ultralib/src/gu/lookat.c | 83 + lib/ultralib/src/gu/lookathil.c | 185 + lib/ultralib/src/gu/lookatref.c | 111 + lib/ultralib/src/gu/lookatstereo.c | 111 + lib/ultralib/src/gu/mtxcatl.c | 45 + lib/ultralib/src/gu/mtxutil.c | 73 + lib/ultralib/src/gu/ortho.c | 41 + lib/ultralib/src/gu/parse_gbi.c | 131 + lib/ultralib/src/gu/parse_rdp.c | 36 + lib/ultralib/src/gu/parse_string.c | 35 + lib/ultralib/src/gu/perspective.c | 58 + lib/ultralib/src/gu/position.c | 73 + lib/ultralib/src/gu/poslight.c | 69 + lib/ultralib/src/gu/poslighthil.c | 168 + lib/ultralib/src/gu/random.c | 33 + lib/ultralib/src/gu/readme.txt | 17 + lib/ultralib/src/gu/rotate.c | 63 + lib/ultralib/src/gu/rotaterpy.c | 58 + lib/ultralib/src/gu/sinf.c | 157 + lib/ultralib/src/gu/sins.c | 61 + lib/ultralib/src/gu/sintable.h | 1031 +++ lib/ultralib/src/gu/sqrtf.s | 25 + lib/ultralib/src/gu/us2dex.c | 62 + lib/ultralib/src/gu/us2dex2_emu.c | 12 + lib/ultralib/src/gu/us2dex_emu.c | 502 ++ lib/ultralib/src/gu/usprite.c | 39 + lib/ultralib/src/host/host_ptn64.c | 203 + lib/ultralib/src/host/readhost.c | 36 + lib/ultralib/src/host/writehost.c | 54 + lib/ultralib/src/io/ai.c | 15 + lib/ultralib/src/io/aigetlen.c | 8 + lib/ultralib/src/io/aigetstat.c | 8 + lib/ultralib/src/io/aisetfreq.c | 29 + lib/ultralib/src/io/aisetnextbuf.c | 31 + lib/ultralib/src/io/cartrominit.c | 65 + lib/ultralib/src/io/contchannelreset.c | 27 + lib/ultralib/src/io/conteeplongread.c | 15 + lib/ultralib/src/io/conteeplongwrite.c | 17 + lib/ultralib/src/io/conteepprobe.c | 32 + lib/ultralib/src/io/conteepread.c | 100 + lib/ultralib/src/io/conteepwrite.c | 158 + lib/ultralib/src/io/contpfs.c | 297 + lib/ultralib/src/io/contquery.c | 25 + lib/ultralib/src/io/contramread.c | 75 + lib/ultralib/src/io/contramwrite.c | 77 + lib/ultralib/src/io/contreaddata.c | 68 + lib/ultralib/src/io/contreset.c | 51 + lib/ultralib/src/io/controller.c | 99 + lib/ultralib/src/io/controller.h | 257 + lib/ultralib/src/io/controller_gbpak.h | 8 + lib/ultralib/src/io/controller_voice.h | 59 + lib/ultralib/src/io/contsetch.c | 19 + lib/ultralib/src/io/crc.c | 64 + lib/ultralib/src/io/devmgr.c | 110 + lib/ultralib/src/io/dp.c | 15 + lib/ultralib/src/io/dpctr.c | 9 + lib/ultralib/src/io/dpgetstat.c | 9 + lib/ultralib/src/io/dpsetnextbuf.c | 24 + lib/ultralib/src/io/dpsetstat.c | 9 + lib/ultralib/src/io/epidma.c | 24 + lib/ultralib/src/io/epigettype.c | 8 + lib/ultralib/src/io/epilinkhandle.c | 12 + lib/ultralib/src/io/epirawdma.c | 27 + lib/ultralib/src/io/epirawread.c | 14 + lib/ultralib/src/io/epirawwrite.c | 14 + lib/ultralib/src/io/epiread.c | 13 + lib/ultralib/src/io/epiwrite.c | 13 + lib/ultralib/src/io/gbpakcheckconnector.c | 131 + lib/ultralib/src/io/gbpakgetbank.c | 28 + lib/ultralib/src/io/gbpakgetstatus.c | 39 + lib/ultralib/src/io/gbpakinit.c | 90 + lib/ultralib/src/io/gbpakpower.c | 34 + lib/ultralib/src/io/gbpakreadid.c | 84 + lib/ultralib/src/io/gbpakreadwrite.c | 69 + lib/ultralib/src/io/gbpaksetbank.c | 35 + lib/ultralib/src/io/motor.c | 136 + lib/ultralib/src/io/pfsallocatefile.c | 148 + lib/ultralib/src/io/pfschecker.c | 203 + lib/ultralib/src/io/pfsdeletefile.c | 64 + lib/ultralib/src/io/pfsfilestate.c | 55 + lib/ultralib/src/io/pfsfreeblocks.c | 27 + lib/ultralib/src/io/pfsgetlabel.c | 23 + lib/ultralib/src/io/pfsgetstatus.c | 78 + lib/ultralib/src/io/pfsinit.c | 25 + lib/ultralib/src/io/pfsinitpak.c | 101 + lib/ultralib/src/io/pfsisplug.c | 96 + lib/ultralib/src/io/pfsnumfiles.c | 24 + lib/ultralib/src/io/pfsreadwritefile.c | 119 + lib/ultralib/src/io/pfsreformat.c | 70 + lib/ultralib/src/io/pfsrepairid.c | 18 + lib/ultralib/src/io/pfssearchfile.c | 51 + lib/ultralib/src/io/pfsselectbank.c | 20 + lib/ultralib/src/io/pfssetlabel.c | 31 + lib/ultralib/src/io/pi.c | 13 + lib/ultralib/src/io/piacs.c | 24 + lib/ultralib/src/io/pidma.c | 30 + lib/ultralib/src/io/pigetcmdq.c | 10 + lib/ultralib/src/io/pigetstat.c | 9 + lib/ultralib/src/io/pigettype.c | 8 + lib/ultralib/src/io/piint.h | 154 + lib/ultralib/src/io/pimgr.c | 53 + lib/ultralib/src/io/pirawdma.c | 25 + lib/ultralib/src/io/pirawread.c | 13 + lib/ultralib/src/io/pirawwrite.c | 13 + lib/ultralib/src/io/piread.c | 13 + lib/ultralib/src/io/piwrite.c | 13 + lib/ultralib/src/io/si.c | 15 + lib/ultralib/src/io/siacs.c | 24 + lib/ultralib/src/io/sigetstat.c | 9 + lib/ultralib/src/io/siint.h | 15 + lib/ultralib/src/io/sirawdma.c | 29 + lib/ultralib/src/io/sirawread.c | 14 + lib/ultralib/src/io/sirawwrite.c | 14 + lib/ultralib/src/io/sp.c | 17 + lib/ultralib/src/io/spgetstat.c | 9 + lib/ultralib/src/io/sprawdma.c | 30 + lib/ultralib/src/io/sprawread.c | 16 + lib/ultralib/src/io/sprawwrite.c | 15 + lib/ultralib/src/io/spsetpc.c | 15 + lib/ultralib/src/io/spsetstat.c | 9 + lib/ultralib/src/io/sptask.c | 63 + lib/ultralib/src/io/sptaskyield.c | 6 + lib/ultralib/src/io/sptaskyielded.c | 18 + lib/ultralib/src/io/vi.c | 39 + lib/ultralib/src/io/viblack.c | 17 + lib/ultralib/src/io/viextendvstart.c | 6 + lib/ultralib/src/io/vifade.c | 18 + lib/ultralib/src/io/vigetcurrcontext.c | 9 + lib/ultralib/src/io/vigetcurrframebuf.c | 10 + lib/ultralib/src/io/vigetfield.c | 6 + lib/ultralib/src/io/vigetline.c | 6 + lib/ultralib/src/io/vigetmode.c | 10 + lib/ultralib/src/io/vigetnextcontext.c | 6 + lib/ultralib/src/io/vigetnextframebuf.c | 10 + lib/ultralib/src/io/vigetstat.c | 6 + lib/ultralib/src/io/viint.h | 70 + lib/ultralib/src/io/vimgr.c | 110 + lib/ultralib/src/io/virepeatline.c | 17 + lib/ultralib/src/io/visetevent.c | 14 + lib/ultralib/src/io/visetmode.c | 14 + lib/ultralib/src/io/visetspecial.c | 48 + lib/ultralib/src/io/visetxscale.c | 16 + lib/ultralib/src/io/visetyscale.c | 13 + lib/ultralib/src/io/viswapbuf.c | 13 + lib/ultralib/src/io/viswapcontext.c | 72 + lib/ultralib/src/io/vitbl.c | 1742 +++++ lib/ultralib/src/libc/bcmp.s | 92 + lib/ultralib/src/libc/bcopy.s | 218 + lib/ultralib/src/libc/bzero.s | 58 + lib/ultralib/src/libc/ldiv.c | 33 + lib/ultralib/src/libc/ll.c | 46 + lib/ultralib/src/libc/llbit.c | 50 + lib/ultralib/src/libc/llcvt.c | 31 + lib/ultralib/src/libc/sprintf.c | 24 + lib/ultralib/src/libc/string.c | 34 + lib/ultralib/src/libc/syncprintf.c | 17 + lib/ultralib/src/libc/xldtob.c | 311 + lib/ultralib/src/libc/xlitob.c | 64 + lib/ultralib/src/libc/xprintf.c | 241 + lib/ultralib/src/libc/xstdio.h | 37 + lib/ultralib/src/mgu/Makefile | 36 + lib/ultralib/src/mgu/asm.h | 49 + lib/ultralib/src/mgu/mtxcatf.s | 103 + lib/ultralib/src/mgu/mtxcatl.c | 34 + lib/ultralib/src/mgu/mtxf2l.s | 80 + lib/ultralib/src/mgu/mtxident.s | 60 + lib/ultralib/src/mgu/mtxidentf.s | 60 + lib/ultralib/src/mgu/mtxl2f.s | 80 + lib/ultralib/src/mgu/mtxxfmf.c | 40 + lib/ultralib/src/mgu/mtxxfml.c | 41 + lib/ultralib/src/mgu/normalize.s | 56 + lib/ultralib/src/mgu/regdef.h | 187 + lib/ultralib/src/mgu/rotate.c | 64 + lib/ultralib/src/mgu/scale.s | 85 + lib/ultralib/src/mgu/scalef.s | 57 + lib/ultralib/src/mgu/translate.s | 101 + lib/ultralib/src/mgu/translatef.s | 58 + lib/ultralib/src/os/ackramromread.c | 8 + lib/ultralib/src/os/ackramromwrite.c | 8 + lib/ultralib/src/os/afterprenmi.c | 5 + lib/ultralib/src/os/assert.c | 5 + lib/ultralib/src/os/atomic.c | 15 + lib/ultralib/src/os/createmesgqueue.c | 11 + lib/ultralib/src/os/createthread.c | 27 + lib/ultralib/src/os/destroythread.c | 37 + lib/ultralib/src/os/exceptasm.h | 23 + lib/ultralib/src/os/exceptasm.s | 1019 +++ lib/ultralib/src/os/exit.c | 8 + lib/ultralib/src/os/getactivequeue.c | 6 + lib/ultralib/src/os/getcause.s | 9 + lib/ultralib/src/os/getcompare.s | 9 + lib/ultralib/src/os/getconfig.s | 9 + lib/ultralib/src/os/getcount.s | 9 + lib/ultralib/src/os/getcurrfaultthread.c | 6 + lib/ultralib/src/os/getfpccsr.s | 10 + lib/ultralib/src/os/gethwinterrupt.c | 13 + lib/ultralib/src/os/getintmask.s | 32 + lib/ultralib/src/os/getmemsize.c | 35 + lib/ultralib/src/os/getnextfaultthread.c | 28 + lib/ultralib/src/os/getsr.s | 9 + lib/ultralib/src/os/getthreadid.c | 10 + lib/ultralib/src/os/getthreadpri.c | 10 + lib/ultralib/src/os/gettime.c | 15 + lib/ultralib/src/os/gettlbasid.s | 11 + lib/ultralib/src/os/gettlbhi.s | 17 + lib/ultralib/src/os/gettlblo0.s | 17 + lib/ultralib/src/os/gettlblo1.s | 17 + lib/ultralib/src/os/gettlbpagemask.s | 17 + lib/ultralib/src/os/getwatchlo.s | 9 + lib/ultralib/src/os/initialize.c | 105 + lib/ultralib/src/os/initialize_emu.c | 28 + lib/ultralib/src/os/initialize_isv.c | 176 + lib/ultralib/src/os/initialize_kmc.c | 154 + lib/ultralib/src/os/initialize_msp.c | 154 + lib/ultralib/src/os/initrdb.c | 30 + lib/ultralib/src/os/interrupt.s | 41 + lib/ultralib/src/os/invaldcache.s | 61 + lib/ultralib/src/os/invalicache.s | 42 + lib/ultralib/src/os/jammesg.c | 27 + lib/ultralib/src/os/kdebugserver.c | 96 + lib/ultralib/src/os/maptlb.s | 64 + lib/ultralib/src/os/maptlbrdb.s | 30 + lib/ultralib/src/os/osint.h | 55 + lib/ultralib/src/os/parameters.s | 16 + lib/ultralib/src/os/physicaltovirtual.c | 6 + lib/ultralib/src/os/probetlb.s | 54 + lib/ultralib/src/os/rdbsend.c | 1 + lib/ultralib/src/os/recvmesg.c | 31 + lib/ultralib/src/os/resetglobalintmask.c | 9 + lib/ultralib/src/os/sendmesg.c | 28 + lib/ultralib/src/os/setcause.s | 9 + lib/ultralib/src/os/setcompare.s | 9 + lib/ultralib/src/os/setconfig.s | 9 + lib/ultralib/src/os/setcount.s | 9 + lib/ultralib/src/os/seterrorhandler.c | 10 + lib/ultralib/src/os/seteventmesg.c | 23 + lib/ultralib/src/os/setfpccsr.s | 11 + lib/ultralib/src/os/setglobalintmask.c | 9 + lib/ultralib/src/os/sethwinterrupt.c | 16 + lib/ultralib/src/os/setintmask.s | 124 + lib/ultralib/src/os/setpiinterrupt.c | 16 + lib/ultralib/src/os/setsr.s | 10 + lib/ultralib/src/os/setthreadpri.c | 26 + lib/ultralib/src/os/settime.c | 6 + lib/ultralib/src/os/settimer.c | 41 + lib/ultralib/src/os/settlbasid.s | 9 + lib/ultralib/src/os/setwatchlo.s | 10 + lib/ultralib/src/os/startthread.c | 35 + lib/ultralib/src/os/stopthread.c | 25 + lib/ultralib/src/os/stoptimer.c | 30 + lib/ultralib/src/os/syncputchars.c | 32 + lib/ultralib/src/os/testhost.c | 4 + lib/ultralib/src/os/thread.c | 25 + lib/ultralib/src/os/threadasm.h | 68 + lib/ultralib/src/os/timerintr.c | 106 + lib/ultralib/src/os/unmaptlb.s | 24 + lib/ultralib/src/os/unmaptlball.s | 26 + lib/ultralib/src/os/virtualtophysical.c | 13 + lib/ultralib/src/os/writebackdcache.s | 35 + lib/ultralib/src/os/writebackdcacheall.s | 18 + lib/ultralib/src/os/yieldthread.c | 10 + lib/ultralib/src/rg/free.c | 15 + lib/ultralib/src/rg/getbufcount.c | 10 + lib/ultralib/src/rg/getsize.c | 9 + lib/ultralib/src/rg/malloc.c | 17 + lib/ultralib/src/rg/region.c | 36 + lib/ultralib/src/rmon/rmonbrk.c | 423 ++ lib/ultralib/src/rmon/rmoncmds.c | 49 + lib/ultralib/src/rmon/rmonint.h | 169 + lib/ultralib/src/rmon/rmonmain.c | 127 + lib/ultralib/src/rmon/rmonmem.c | 271 + lib/ultralib/src/rmon/rmonmisc.c | 69 + lib/ultralib/src/rmon/rmonprint.c | 1 + lib/ultralib/src/rmon/rmonrcp.s | 59 + lib/ultralib/src/rmon/rmonregs.c | 402 + lib/ultralib/src/rmon/rmonsio.c | 77 + lib/ultralib/src/rmon/rmontask.c | 332 + lib/ultralib/src/sched/Makefile | 19 + lib/ultralib/src/sched/sched.c | 623 ++ lib/ultralib/src/sched/sched_log.fmt | 19 + lib/ultralib/src/sp/Makefile | 30 + lib/ultralib/src/sp/clearattribute.c | 35 + lib/ultralib/src/sp/color.c | 39 + lib/ultralib/src/sp/hide.c | 35 + lib/ultralib/src/sp/setattribute.c | 35 + lib/ultralib/src/sp/show.c | 35 + lib/ultralib/src/sp/sprite.c | 757 ++ lib/ultralib/src/sp/spriteex.c | 2 + lib/ultralib/src/sp/spriteex2.c | 2 + lib/ultralib/src/sp/spscale.c | 42 + lib/ultralib/src/vimodes/vimodefpalhaf1.c | 35 + lib/ultralib/src/vimodes/vimodefpalhan1.c | 35 + lib/ultralib/src/vimodes/vimodefpalhpf1.c | 35 + lib/ultralib/src/vimodes/vimodefpalhpf2.c | 35 + lib/ultralib/src/vimodes/vimodefpalhpn1.c | 35 + lib/ultralib/src/vimodes/vimodefpalhpn2.c | 35 + lib/ultralib/src/vimodes/vimodefpallaf1.c | 35 + lib/ultralib/src/vimodes/vimodefpallaf2.c | 35 + lib/ultralib/src/vimodes/vimodefpallan1.c | 35 + lib/ultralib/src/vimodes/vimodefpallan2.c | 35 + lib/ultralib/src/vimodes/vimodefpallpf1.c | 35 + lib/ultralib/src/vimodes/vimodefpallpf2.c | 35 + lib/ultralib/src/vimodes/vimodefpallpn1.c | 35 + lib/ultralib/src/vimodes/vimodefpallpn2.c | 35 + lib/ultralib/src/vimodes/vimodempalhaf1.c | 35 + lib/ultralib/src/vimodes/vimodempalhan1.c | 35 + lib/ultralib/src/vimodes/vimodempalhpf1.c | 35 + lib/ultralib/src/vimodes/vimodempalhpf2.c | 35 + lib/ultralib/src/vimodes/vimodempalhpn1.c | 35 + lib/ultralib/src/vimodes/vimodempalhpn2.c | 35 + lib/ultralib/src/vimodes/vimodempallaf1.c | 35 + lib/ultralib/src/vimodes/vimodempallaf2.c | 35 + lib/ultralib/src/vimodes/vimodempallan1.c | 35 + lib/ultralib/src/vimodes/vimodempallan2.c | 35 + lib/ultralib/src/vimodes/vimodempallpf1.c | 35 + lib/ultralib/src/vimodes/vimodempallpf2.c | 35 + lib/ultralib/src/vimodes/vimodempallpn1.c | 35 + lib/ultralib/src/vimodes/vimodempallpn2.c | 35 + lib/ultralib/src/vimodes/vimodentschaf1.c | 35 + lib/ultralib/src/vimodes/vimodentschan1.c | 35 + lib/ultralib/src/vimodes/vimodentschpf1.c | 35 + lib/ultralib/src/vimodes/vimodentschpf2.c | 35 + lib/ultralib/src/vimodes/vimodentschpn1.c | 35 + lib/ultralib/src/vimodes/vimodentschpn2.c | 35 + lib/ultralib/src/vimodes/vimodentsclaf1.c | 35 + lib/ultralib/src/vimodes/vimodentsclaf2.c | 35 + lib/ultralib/src/vimodes/vimodentsclan1.c | 35 + lib/ultralib/src/vimodes/vimodentsclan2.c | 35 + lib/ultralib/src/vimodes/vimodentsclpf1.c | 35 + lib/ultralib/src/vimodes/vimodentsclpf2.c | 35 + lib/ultralib/src/vimodes/vimodentsclpn1.c | 35 + lib/ultralib/src/vimodes/vimodentsclpn2.c | 35 + lib/ultralib/src/vimodes/vimodepalhaf1.c | 35 + lib/ultralib/src/vimodes/vimodepalhan1.c | 35 + lib/ultralib/src/vimodes/vimodepalhpf1.c | 35 + lib/ultralib/src/vimodes/vimodepalhpf2.c | 35 + lib/ultralib/src/vimodes/vimodepalhpn1.c | 35 + lib/ultralib/src/vimodes/vimodepalhpn2.c | 35 + lib/ultralib/src/vimodes/vimodepallaf1.c | 35 + lib/ultralib/src/vimodes/vimodepallaf2.c | 35 + lib/ultralib/src/vimodes/vimodepallan1.c | 35 + lib/ultralib/src/vimodes/vimodepallan2.c | 35 + lib/ultralib/src/vimodes/vimodepallpf1.c | 35 + lib/ultralib/src/vimodes/vimodepallpf2.c | 35 + lib/ultralib/src/vimodes/vimodepallpn1.c | 35 + lib/ultralib/src/vimodes/vimodepallpn2.c | 35 + lib/ultralib/src/voice/voicecheckresult.c | 23 + lib/ultralib/src/voice/voicecheckword.c | 116 + lib/ultralib/src/voice/voicecleardictionary.c | 28 + lib/ultralib/src/voice/voicecontread2.c | 75 + lib/ultralib/src/voice/voicecontread36.c | 73 + lib/ultralib/src/voice/voicecontrolgain.c | 22 + lib/ultralib/src/voice/voicecontwrite20.c | 77 + lib/ultralib/src/voice/voicecontwrite4.c | 75 + lib/ultralib/src/voice/voicecountsyllables.c | 59 + lib/ultralib/src/voice/voicecrc.c | 40 + lib/ultralib/src/voice/voicegetreaddata.c | 94 + lib/ultralib/src/voice/voicegetstatus.c | 61 + lib/ultralib/src/voice/voiceinit.c | 40 + lib/ultralib/src/voice/voiceinternal.h | 10 + lib/ultralib/src/voice/voicemaskdictionary.c | 47 + lib/ultralib/src/voice/voicesetadconverter.c | 70 + lib/ultralib/src/voice/voicesetword.c | 44 + lib/ultralib/src/voice/voicestartreaddata.c | 35 + lib/ultralib/src/voice/voicestopreaddata.c | 44 + lib/ultralib/tools/Makefile | 30 + lib/ultralib/tools/asm_differ/.gitignore | 2 + lib/ultralib/tools/asm_differ/.gitrepo | 12 + .../tools/asm_differ/.pre-commit-config.yaml | 6 + lib/ultralib/tools/asm_differ/LICENSE | 24 + lib/ultralib/tools/asm_differ/README.md | 56 + .../tools/asm_differ/diff-stylesheet.css | 67 + lib/ultralib/tools/asm_differ/diff.py | 2923 +++++++ .../tools/asm_differ/diff_settings.py | 11 + lib/ultralib/tools/asm_differ/mypy.ini | 17 + lib/ultralib/tools/asm_differ/screenshot.png | Bin 0 -> 99842 bytes lib/ultralib/tools/compile_sjis.py | 27 + lib/ultralib/tools/disassemble_elf.py | 312 + lib/ultralib/tools/fix_objfile.py | 68 + lib/ultralib/tools/libdiff.py | 150 + lib/ultralib/tools/libelf.py | 1180 +++ lib/ultralib/tools/mdebug.py | 938 +++ lib/ultralib/tools/mips_isa.py | 1309 ++++ lib/ultralib/tools/patch_ar_meta.py | 55 + lib/ultralib/tools/shiftjis_conv.py | 58 + lib/ultralib/tools/util.py | 44 + linker_scripts/common_undef_syms.ld | 0 linker_scripts/jp/hardware_regs.ld | 94 + linker_scripts/jp/ignored_addresses.txt | 11 + linker_scripts/jp/symbol_addrs_boot.txt | 524 ++ linker_scripts/jp/symbol_addrs_code.txt | 6732 +++++++++++++++++ linker_scripts/jp/symbol_addrs_libultra.txt | 449 ++ linker_scripts/jp/undefined_syms.ld | 7 + linker_scripts/libultra_syms.ld | 9 + relocs/reloc_addrs.jp.txt | 0 requirements.txt | 2 + src/boot/boot_main.c | 5 + tools/.gitignore | 2 + tools/Makefile | 47 + tools/asm-differ/.gitignore | 4 + tools/asm-differ/.gitrepo | 12 + tools/asm-differ/.pre-commit-config.yaml | 5 + tools/asm-differ/LICENSE | 24 + tools/asm-differ/README.md | 56 + tools/asm-differ/diff-stylesheet.css | 67 + tools/asm-differ/diff.py | 3465 +++++++++ tools/asm-differ/diff_settings.py | 12 + tools/asm-differ/mypy.ini | 17 + tools/asm-differ/pyproject.toml | 21 + tools/asm-differ/screenshot.png | Bin 0 -> 99842 bytes tools/asm-processor/.gitignore | 2 + tools/asm-processor/.gitrepo | 12 + tools/asm-processor/LICENSE | 24 + tools/asm-processor/README.md | 112 + tools/asm-processor/add-test.sh | 5 + tools/asm-processor/asm_processor.py | 1472 ++++ tools/asm-processor/build.py | 114 + tools/asm-processor/compile-test.sh | 26 + tools/asm-processor/prelude.inc | 43 + tools/asm-processor/run-tests.sh | 6 + tools/asm-processor/tests/ascii.c | 19 + tools/asm-processor/tests/ascii.objdump | 29 + tools/asm-processor/tests/comments.c | 6 + tools/asm-processor/tests/comments.objdump | 21 + tools/asm-processor/tests/force.c | 17 + tools/asm-processor/tests/force.objdump | 47 + tools/asm-processor/tests/kpic-o1.c | 93 + tools/asm-processor/tests/kpic-o1.objdump | 46 + tools/asm-processor/tests/kpic-o2.c | 92 + tools/asm-processor/tests/kpic-o2.objdump | 46 + tools/asm-processor/tests/label-sameline.c | 7 + .../tests/label-sameline.objdump | 25 + tools/asm-processor/tests/large.c | 164 + tools/asm-processor/tests/large.objdump | 58 + tools/asm-processor/tests/late_rodata_align.c | 80 + .../tests/late_rodata_align.objdump | 51 + .../asm-processor/tests/late_rodata_doubles.c | 83 + .../tests/late_rodata_doubles.objdump | 55 + .../tests/late_rodata_doubles_mips1.c | 86 + .../tests/late_rodata_doubles_mips1.objdump | 52 + tools/asm-processor/tests/late_rodata_jtbl.c | 153 + .../tests/late_rodata_jtbl.objdump | 110 + .../tests/late_rodata_jtbl_mips1.c | 155 + .../tests/late_rodata_jtbl_mips1.objdump | 110 + .../tests/late_rodata_misaligned_doubles.c | 77 + .../late_rodata_misaligned_doubles.objdump | 56 + .../tests/line-continuation-separate-file.s | 4 + .../tests/line-continuation.asmproc.d | 3 + tools/asm-processor/tests/line-continuation.c | 22 + .../tests/line-continuation.objdump | 30 + tools/asm-processor/tests/o0.c | 28 + tools/asm-processor/tests/o0.objdump | 44 + tools/asm-processor/tests/o2.c | 26 + tools/asm-processor/tests/o2.objdump | 40 + tools/asm-processor/tests/pascal.objdump | 137 + tools/asm-processor/tests/pascal.p | 95 + tools/asm-processor/tests/static-global.c | 33 + .../asm-processor/tests/static-global.objdump | 58 + tools/asm-processor/tests/static.c | 32 + tools/asm-processor/tests/static.objdump | 58 + tools/asm-processor/tests/test1.c | 71 + tools/asm-processor/tests/test1.objdump | 54 + tools/asm-processor/tests/test2.c | 69 + tools/asm-processor/tests/test2.objdump | 76 + tools/asm-processor/tests/test3.c | 70 + tools/asm-processor/tests/test3.objdump | 64 + tools/decompress_baserom.py | 238 + tools/fado/.clang-format | 23 + tools/fado/.gitignore | 56 + tools/fado/.gitrepo | 12 + tools/fado/LICENSE | 661 ++ tools/fado/Makefile | 74 + tools/fado/README.md | 77 + tools/fado/find_program.sh | 16 + tools/fado/include/fado.h | 8 + tools/fado/include/help.h | 25 + tools/fado/include/macros.h | 23 + tools/fado/include/mido.h | 6 + tools/fado/include/mips_elf.h | 659 ++ tools/fado/lib/fairy/fairy.c | 418 + tools/fado/lib/fairy/fairy.h | 74 + tools/fado/lib/fairy/fairy_data.inc | 126 + tools/fado/lib/fairy/fairy_print.c | 463 ++ tools/fado/lib/fairy/fairy_print.h | 7 + tools/fado/lib/vc_vector/.gitrepo | 12 + tools/fado/lib/vc_vector/.travis.yml | 6 + tools/fado/lib/vc_vector/LICENSE.md | 21 + tools/fado/lib/vc_vector/Makefile | 33 + tools/fado/lib/vc_vector/README.md | 92 + tools/fado/lib/vc_vector/vc_vector.c | 329 + tools/fado/lib/vc_vector/vc_vector.h | 120 + tools/fado/lib/vc_vector/vc_vector_test.c | 353 + tools/fado/lib/vc_vector/vc_vector_test.h | 6 + tools/fado/ovl_En_Hs_reloc.s | 46 + tools/fado/src/fado.c | 308 + tools/fado/src/help.c | 162 + tools/fado/src/main.c | 247 + tools/fado/src/mido.c | 20 + tools/fado/src/version.inc | 5 + tools/fado/z64_relocation_section_format.md | 114 + tools/first_diff.py | 29 + tools/format.py | 188 + tools/m2ctx.py | 83 + tools/permuter_settings.toml | 9 + tools/pj64_syms.py | 24 + tools/splat/.github/workflows/mypy.yml | 26 + tools/splat/.gitignore | 10 + tools/splat/.gitrepo | 12 + tools/splat/CHANGELOG.md | 361 + tools/splat/LICENSE | 21 + tools/splat/Makefile | 11 + tools/splat/README.md | 9 + tools/splat/create_config.py | 192 + tools/splat/mypy.ini | 4 + tools/splat/platforms/gc.py | 5 + tools/splat/platforms/n64.py | 10 + tools/splat/platforms/psx.py | 2 + tools/splat/requirements.txt | 10 + tools/splat/segtypes/__init__.py | 0 tools/splat/segtypes/address_range.py | 10 + tools/splat/segtypes/common/__init__.py | 0 tools/splat/segtypes/common/asm.py | 39 + tools/splat/segtypes/common/bin.py | 28 + tools/splat/segtypes/common/bss.py | 60 + tools/splat/segtypes/common/c.py | 428 ++ tools/splat/segtypes/common/code.py | 371 + tools/splat/segtypes/common/codesubsegment.py | 198 + tools/splat/segtypes/common/data.py | 124 + tools/splat/segtypes/common/decompressor.py | 48 + tools/splat/segtypes/common/group.py | 146 + tools/splat/segtypes/common/hasm.py | 24 + tools/splat/segtypes/common/header.py | 42 + tools/splat/segtypes/common/lib.py | 53 + tools/splat/segtypes/common/rdata.py | 6 + tools/splat/segtypes/common/rodata.py | 97 + tools/splat/segtypes/common/sbss.py | 6 + tools/splat/segtypes/common/sdata.py | 6 + tools/splat/segtypes/common/segment.py | 5 + tools/splat/segtypes/gc/apploader.py | 8 + tools/splat/segtypes/gc/bi2.py | 67 + tools/splat/segtypes/gc/bootinfo.py | 117 + tools/splat/segtypes/gc/dol.py | 8 + tools/splat/segtypes/gc/dolheader.py | 68 + tools/splat/segtypes/gc/fst.py | 8 + tools/splat/segtypes/gc/rarc.py | 321 + tools/splat/segtypes/gc/relheader.py | 114 + tools/splat/segtypes/gc/segment.py | 5 + tools/splat/segtypes/linker_entry.py | 399 + tools/splat/segtypes/n64/__init__.py | 0 tools/splat/segtypes/n64/asm.py | 28 + tools/splat/segtypes/n64/ci.py | 39 + tools/splat/segtypes/n64/ci4.py | 8 + tools/splat/segtypes/n64/ci8.py | 8 + tools/splat/segtypes/n64/gfx.py | 260 + tools/splat/segtypes/n64/hasm.py | 28 + tools/splat/segtypes/n64/header.py | 50 + tools/splat/segtypes/n64/i1.py | 9 + tools/splat/segtypes/n64/i4.py | 9 + tools/splat/segtypes/n64/i8.py | 9 + tools/splat/segtypes/n64/ia16.py | 9 + tools/splat/segtypes/n64/ia4.py | 9 + tools/splat/segtypes/n64/ia8.py | 9 + tools/splat/segtypes/n64/img.py | 83 + tools/splat/segtypes/n64/ipl3.py | 9 + tools/splat/segtypes/n64/linker_offset.py | 10 + tools/splat/segtypes/n64/mio0.py | 10 + tools/splat/segtypes/n64/palette.py | 99 + tools/splat/segtypes/n64/rgba16.py | 9 + tools/splat/segtypes/n64/rgba32.py | 9 + tools/splat/segtypes/n64/rsp.py | 10 + tools/splat/segtypes/n64/segment.py | 5 + tools/splat/segtypes/n64/vtx.py | 106 + tools/splat/segtypes/n64/yay0.py | 10 + tools/splat/segtypes/psx/__init__.py | 0 tools/splat/segtypes/psx/asm.py | 23 + tools/splat/segtypes/psx/header.py | 61 + tools/splat/segtypes/psx/segment.py | 5 + tools/splat/segtypes/segment.py | 615 ++ tools/splat/split.py | 562 ++ tools/splat/stubs/colorama.pyi | 8 + tools/splat/util/__init__.py | 0 tools/splat/util/color.py | 19 + tools/splat/util/compiler.py | 40 + tools/splat/util/floats.py | 63 + tools/splat/util/gc/gcfst.py | 181 + tools/splat/util/gc/gcinfo.py | 88 + tools/splat/util/gc/gcutil.py | 11 + tools/splat/util/log.py | 45 + tools/splat/util/n64/Mio0decompress.py | 108 + tools/splat/util/n64/Yay0decompress.c | 44 + tools/splat/util/n64/Yay0decompress.py | 162 + tools/splat/util/n64/__init__.py | 0 tools/splat/util/n64/decompressor.py | 7 + tools/splat/util/n64/find_code_length.py | 63 + tools/splat/util/n64/rominfo.py | 322 + tools/splat/util/options.py | 422 ++ tools/splat/util/palettes.py | 34 + tools/splat/util/range.py | 17 + tools/splat/util/relocs.py | 125 + tools/splat/util/symbols.py | 640 ++ tools/sym_info.py | 27 + 856 files changed, 88727 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitignore create mode 100644 .vscode/c_cpp_properties.json create mode 100644 Makefile create mode 100644 README.md create mode 100644 animalforest.jp.md5 create mode 100644 animalforest.jp.yaml create mode 100644 animalforest_uncompressed.jp.md5 create mode 120000 diff.py create mode 100644 diff_settings.py create mode 100644 include/alignment.h create mode 100644 include/attributes.h create mode 100644 include/global.h create mode 100644 include/libc/assert.h create mode 100644 include/libc/stdbool.h create mode 100644 include/libc/stddef.h create mode 100644 include/libc/stdint.h create mode 100644 include/macro.inc create mode 100644 include/macros.h create mode 100644 include/other_types.h create mode 100644 include/segment_symbols.h create mode 100644 include/stack.h create mode 100644 include/unk.h create mode 100644 include/unknown_structs.h create mode 100644 lib/ultralib/.github/workflows/ci_egcs.txt create mode 100644 lib/ultralib/.github/workflows/ci_gcc.yml create mode 100644 lib/ultralib/.github/workflows/ci_ido.txt create mode 100644 lib/ultralib/.gitignore create mode 100644 lib/ultralib/.gitrepo create mode 100644 lib/ultralib/Makefile create mode 100644 lib/ultralib/README.md create mode 100644 lib/ultralib/include/PR/R4300.h create mode 100644 lib/ultralib/include/PR/abi.h create mode 100644 lib/ultralib/include/PR/gbi.h create mode 100644 lib/ultralib/include/PR/gs2dex.h create mode 100644 lib/ultralib/include/PR/gt.h create mode 100644 lib/ultralib/include/PR/gu.h create mode 100644 lib/ultralib/include/PR/libaudio.h create mode 100644 lib/ultralib/include/PR/mbi.h create mode 100644 lib/ultralib/include/PR/os.h create mode 100644 lib/ultralib/include/PR/os_ai.h create mode 100644 lib/ultralib/include/PR/os_cache.h create mode 100644 lib/ultralib/include/PR/os_cont.h create mode 100644 lib/ultralib/include/PR/os_convert.h create mode 100644 lib/ultralib/include/PR/os_debug.h create mode 100644 lib/ultralib/include/PR/os_eeprom.h create mode 100644 lib/ultralib/include/PR/os_error.h create mode 100644 lib/ultralib/include/PR/os_exception.h create mode 100644 lib/ultralib/include/PR/os_flash.h create mode 100644 lib/ultralib/include/PR/os_gbpak.h create mode 100644 lib/ultralib/include/PR/os_gio.h create mode 100644 lib/ultralib/include/PR/os_host.h create mode 100644 lib/ultralib/include/PR/os_internal.h create mode 100644 lib/ultralib/include/PR/os_internal_debug.h create mode 100644 lib/ultralib/include/PR/os_internal_error.h create mode 100644 lib/ultralib/include/PR/os_internal_exception.h create mode 100644 lib/ultralib/include/PR/os_internal_flash.h create mode 100644 lib/ultralib/include/PR/os_internal_gio.h create mode 100644 lib/ultralib/include/PR/os_internal_host.h create mode 100644 lib/ultralib/include/PR/os_internal_reg.h create mode 100644 lib/ultralib/include/PR/os_internal_rsp.h create mode 100644 lib/ultralib/include/PR/os_internal_si.h create mode 100644 lib/ultralib/include/PR/os_internal_thread.h create mode 100644 lib/ultralib/include/PR/os_internal_tlb.h create mode 100644 lib/ultralib/include/PR/os_libc.h create mode 100644 lib/ultralib/include/PR/os_message.h create mode 100644 lib/ultralib/include/PR/os_motor.h create mode 100644 lib/ultralib/include/PR/os_pfs.h create mode 100644 lib/ultralib/include/PR/os_pi.h create mode 100644 lib/ultralib/include/PR/os_rdp.h create mode 100644 lib/ultralib/include/PR/os_reg.h create mode 100644 lib/ultralib/include/PR/os_rsp.h create mode 100644 lib/ultralib/include/PR/os_si.h create mode 100644 lib/ultralib/include/PR/os_system.h create mode 100644 lib/ultralib/include/PR/os_thread.h create mode 100644 lib/ultralib/include/PR/os_time.h create mode 100644 lib/ultralib/include/PR/os_tlb.h create mode 100644 lib/ultralib/include/PR/os_version.h create mode 100644 lib/ultralib/include/PR/os_vi.h create mode 100644 lib/ultralib/include/PR/os_voice.h create mode 100644 lib/ultralib/include/PR/ramrom.h create mode 100644 lib/ultralib/include/PR/rcp.h create mode 100644 lib/ultralib/include/PR/rdb.h create mode 100755 lib/ultralib/include/PR/region.h create mode 100644 lib/ultralib/include/PR/rmon.h create mode 100644 lib/ultralib/include/PR/sched.h create mode 100644 lib/ultralib/include/PR/sp.h create mode 100644 lib/ultralib/include/PR/sptask.h create mode 100644 lib/ultralib/include/PR/ucode.h create mode 100644 lib/ultralib/include/PR/ultraerror.h create mode 100644 lib/ultralib/include/PR/ultralog.h create mode 100644 lib/ultralib/include/PR/ultratypes.h create mode 100644 lib/ultralib/include/assert.h create mode 100644 lib/ultralib/include/dbgdefs.h create mode 100644 lib/ultralib/include/dbgproto.h create mode 100644 lib/ultralib/include/gcc/math.h create mode 100644 lib/ultralib/include/gcc/memory.h create mode 100755 lib/ultralib/include/gcc/stdarg.h create mode 100644 lib/ultralib/include/gcc/stdio.h create mode 100644 lib/ultralib/include/gcc/stdlib.h create mode 100755 lib/ultralib/include/gcc/string.h create mode 100644 lib/ultralib/include/macros.h create mode 100644 lib/ultralib/include/sys/asm.h create mode 100644 lib/ultralib/include/sys/regdef.h create mode 100644 lib/ultralib/include/ultra64.h create mode 100644 lib/ultralib/include/ultrahost.h create mode 100644 lib/ultralib/src/audio/Makefile create mode 100644 lib/ultralib/src/audio/auxbus.c create mode 100644 lib/ultralib/src/audio/bnkf.c create mode 100644 lib/ultralib/src/audio/cents2ratio.c create mode 100644 lib/ultralib/src/audio/copy.c create mode 100644 lib/ultralib/src/audio/cseq.c create mode 100644 lib/ultralib/src/audio/cseq.h create mode 100644 lib/ultralib/src/audio/cseqp.h create mode 100644 lib/ultralib/src/audio/cspdelete.c create mode 100644 lib/ultralib/src/audio/cspgetchlvol.c create mode 100644 lib/ultralib/src/audio/cspgetfxmix.c create mode 100644 lib/ultralib/src/audio/cspgetpan.c create mode 100644 lib/ultralib/src/audio/cspgetpriority.c create mode 100644 lib/ultralib/src/audio/cspgetprogram.c create mode 100644 lib/ultralib/src/audio/cspgetseq.c create mode 100644 lib/ultralib/src/audio/cspgetstate.c create mode 100644 lib/ultralib/src/audio/cspgettempo.c create mode 100644 lib/ultralib/src/audio/cspgetvol.c create mode 100644 lib/ultralib/src/audio/csplayer.c create mode 100644 lib/ultralib/src/audio/cspplay.c create mode 100644 lib/ultralib/src/audio/cspsendmidi.c create mode 100644 lib/ultralib/src/audio/cspsetbank.c create mode 100644 lib/ultralib/src/audio/cspsetchlvol.c create mode 100644 lib/ultralib/src/audio/cspsetfxmix.c create mode 100644 lib/ultralib/src/audio/cspsetpan.c create mode 100644 lib/ultralib/src/audio/cspsetpriority.c create mode 100644 lib/ultralib/src/audio/cspsetprogram.c create mode 100644 lib/ultralib/src/audio/cspsetseq.c create mode 100644 lib/ultralib/src/audio/cspsettempo.c create mode 100644 lib/ultralib/src/audio/cspsetvol.c create mode 100644 lib/ultralib/src/audio/cspstop.c create mode 100644 lib/ultralib/src/audio/drvrnew.c create mode 100644 lib/ultralib/src/audio/env.c create mode 100644 lib/ultralib/src/audio/event.c create mode 100644 lib/ultralib/src/audio/filter.c create mode 100644 lib/ultralib/src/audio/heapalloc.c create mode 100644 lib/ultralib/src/audio/heapcheck.c create mode 100644 lib/ultralib/src/audio/heapinit.c create mode 100644 lib/ultralib/src/audio/initfx.h create mode 100644 lib/ultralib/src/audio/load.c create mode 100644 lib/ultralib/src/audio/mainbus.c create mode 100644 lib/ultralib/src/audio/parse_abi.c create mode 100644 lib/ultralib/src/audio/resample.c create mode 100644 lib/ultralib/src/audio/reverb.c create mode 100644 lib/ultralib/src/audio/save.c create mode 100644 lib/ultralib/src/audio/seq.c create mode 100644 lib/ultralib/src/audio/seq.h create mode 100644 lib/ultralib/src/audio/seqp.h create mode 100644 lib/ultralib/src/audio/seqpdelete.c create mode 100644 lib/ultralib/src/audio/seqpgetchlvol.c create mode 100644 lib/ultralib/src/audio/seqpgetfxmix.c create mode 100644 lib/ultralib/src/audio/seqpgetpan.c create mode 100644 lib/ultralib/src/audio/seqpgetpriority.c create mode 100644 lib/ultralib/src/audio/seqpgetprogram.c create mode 100644 lib/ultralib/src/audio/seqpgetseq.c create mode 100644 lib/ultralib/src/audio/seqpgetstate.c create mode 100644 lib/ultralib/src/audio/seqpgettempo.c create mode 100644 lib/ultralib/src/audio/seqpgetvol.c create mode 100644 lib/ultralib/src/audio/seqplayer.c create mode 100644 lib/ultralib/src/audio/seqploop.c create mode 100644 lib/ultralib/src/audio/seqpplay.c create mode 100644 lib/ultralib/src/audio/seqpsendmidi.c create mode 100644 lib/ultralib/src/audio/seqpsetbank.c create mode 100644 lib/ultralib/src/audio/seqpsetchlvol.c create mode 100644 lib/ultralib/src/audio/seqpsetfxmix.c create mode 100644 lib/ultralib/src/audio/seqpsetpan.c create mode 100644 lib/ultralib/src/audio/seqpsetpriority.c create mode 100644 lib/ultralib/src/audio/seqpsetprogram.c create mode 100644 lib/ultralib/src/audio/seqpsetseq.c create mode 100644 lib/ultralib/src/audio/seqpsettempo.c create mode 100644 lib/ultralib/src/audio/seqpsetvol.c create mode 100644 lib/ultralib/src/audio/seqpstop.c create mode 100644 lib/ultralib/src/audio/sl.c create mode 100644 lib/ultralib/src/audio/sndp.h create mode 100644 lib/ultralib/src/audio/sndpallocate.c create mode 100644 lib/ultralib/src/audio/sndpdeallocate.c create mode 100644 lib/ultralib/src/audio/sndpdelete.c create mode 100644 lib/ultralib/src/audio/sndpgetsound.c create mode 100644 lib/ultralib/src/audio/sndpgetstate.c create mode 100644 lib/ultralib/src/audio/sndplayer.c create mode 100644 lib/ultralib/src/audio/sndpplay.c create mode 100644 lib/ultralib/src/audio/sndpplayat.c create mode 100644 lib/ultralib/src/audio/sndpsetfxmix.c create mode 100644 lib/ultralib/src/audio/sndpsetpan.c create mode 100644 lib/ultralib/src/audio/sndpsetpitch.c create mode 100644 lib/ultralib/src/audio/sndpsetpriority.c create mode 100644 lib/ultralib/src/audio/sndpsetsound.c create mode 100644 lib/ultralib/src/audio/sndpsetvol.c create mode 100644 lib/ultralib/src/audio/sndpstop.c create mode 100644 lib/ultralib/src/audio/synaddplayer.c create mode 100644 lib/ultralib/src/audio/synallocfx.c create mode 100644 lib/ultralib/src/audio/synallocvoice.c create mode 100644 lib/ultralib/src/audio/syndelete.c create mode 100644 lib/ultralib/src/audio/synfreefx.c create mode 100644 lib/ultralib/src/audio/synfreevoice.c create mode 100644 lib/ultralib/src/audio/syngetfxref.c create mode 100644 lib/ultralib/src/audio/syngetpriority.c create mode 100644 lib/ultralib/src/audio/synremoveplayer.c create mode 100644 lib/ultralib/src/audio/synsetfxmix.c create mode 100644 lib/ultralib/src/audio/synsetfxparam.c create mode 100644 lib/ultralib/src/audio/synsetpan.c create mode 100644 lib/ultralib/src/audio/synsetpitch.c create mode 100644 lib/ultralib/src/audio/synsetpriority.c create mode 100644 lib/ultralib/src/audio/synsetvol.c create mode 100644 lib/ultralib/src/audio/synstartvoice.c create mode 100644 lib/ultralib/src/audio/synstartvoiceparam.c create mode 100644 lib/ultralib/src/audio/synstopvoice.c create mode 100644 lib/ultralib/src/audio/synthInternals.h create mode 100644 lib/ultralib/src/audio/synthesizer.c create mode 100644 lib/ultralib/src/debug/osint_debug.h create mode 100644 lib/ultralib/src/debug/threadprofile.c create mode 100644 lib/ultralib/src/debug/threadprofileclear.c create mode 100644 lib/ultralib/src/debug/threadprofileinit.c create mode 100644 lib/ultralib/src/debug/threadprofilereadcount.c create mode 100644 lib/ultralib/src/debug/threadprofilereadtime.c create mode 100644 lib/ultralib/src/debug/threadprofilestart.c create mode 100644 lib/ultralib/src/debug/threadprofilestop.c create mode 100644 lib/ultralib/src/flash/flashallerase.c create mode 100644 lib/ultralib/src/flash/flashallerasethrough.c create mode 100644 lib/ultralib/src/flash/flashchange.c create mode 100644 lib/ultralib/src/flash/flashcheckeraseend.c create mode 100644 lib/ultralib/src/flash/flashclearstatus.c create mode 100644 lib/ultralib/src/flash/flashgetaddr.c create mode 100644 lib/ultralib/src/flash/flashinit.c create mode 100644 lib/ultralib/src/flash/flashreadarray.c create mode 100644 lib/ultralib/src/flash/flashreadid.c create mode 100644 lib/ultralib/src/flash/flashreadstatus.c create mode 100644 lib/ultralib/src/flash/flashreinit.c create mode 100644 lib/ultralib/src/flash/flashsectorerase.c create mode 100644 lib/ultralib/src/flash/flashsectorerasethrough.c create mode 100644 lib/ultralib/src/flash/flashwritearray.c create mode 100644 lib/ultralib/src/flash/flashwritebuffer.c create mode 100644 lib/ultralib/src/gio/giointerrupt.c create mode 100644 lib/ultralib/src/gio/giorawinterrupt.c create mode 100644 lib/ultralib/src/gt/Makefile create mode 100644 lib/ultralib/src/gt/dumpturbo.c create mode 100644 lib/ultralib/src/gt/gt.c create mode 100644 lib/ultralib/src/gt/gtint.h create mode 100644 lib/ultralib/src/gu/Makefile create mode 100644 lib/ultralib/src/gu/align.c create mode 100644 lib/ultralib/src/gu/cosf.c create mode 100644 lib/ultralib/src/gu/coss.c create mode 100644 lib/ultralib/src/gu/dump_gbi.c create mode 100644 lib/ultralib/src/gu/frustum.c create mode 100644 lib/ultralib/src/gu/guint.h create mode 100644 lib/ultralib/src/gu/guloadtile_bug.c create mode 100644 lib/ultralib/src/gu/libm_vals.s create mode 100644 lib/ultralib/src/gu/loadtextureblockmipmap.c create mode 100644 lib/ultralib/src/gu/lookat.c create mode 100644 lib/ultralib/src/gu/lookathil.c create mode 100644 lib/ultralib/src/gu/lookatref.c create mode 100644 lib/ultralib/src/gu/lookatstereo.c create mode 100644 lib/ultralib/src/gu/mtxcatl.c create mode 100644 lib/ultralib/src/gu/mtxutil.c create mode 100644 lib/ultralib/src/gu/ortho.c create mode 100644 lib/ultralib/src/gu/parse_gbi.c create mode 100644 lib/ultralib/src/gu/parse_rdp.c create mode 100644 lib/ultralib/src/gu/parse_string.c create mode 100644 lib/ultralib/src/gu/perspective.c create mode 100644 lib/ultralib/src/gu/position.c create mode 100644 lib/ultralib/src/gu/poslight.c create mode 100644 lib/ultralib/src/gu/poslighthil.c create mode 100644 lib/ultralib/src/gu/random.c create mode 100644 lib/ultralib/src/gu/readme.txt create mode 100644 lib/ultralib/src/gu/rotate.c create mode 100644 lib/ultralib/src/gu/rotaterpy.c create mode 100644 lib/ultralib/src/gu/sinf.c create mode 100644 lib/ultralib/src/gu/sins.c create mode 100644 lib/ultralib/src/gu/sintable.h create mode 100644 lib/ultralib/src/gu/sqrtf.s create mode 100644 lib/ultralib/src/gu/us2dex.c create mode 100644 lib/ultralib/src/gu/us2dex2_emu.c create mode 100644 lib/ultralib/src/gu/us2dex_emu.c create mode 100644 lib/ultralib/src/gu/usprite.c create mode 100644 lib/ultralib/src/host/host_ptn64.c create mode 100644 lib/ultralib/src/host/readhost.c create mode 100644 lib/ultralib/src/host/writehost.c create mode 100755 lib/ultralib/src/io/ai.c create mode 100755 lib/ultralib/src/io/aigetlen.c create mode 100755 lib/ultralib/src/io/aigetstat.c create mode 100755 lib/ultralib/src/io/aisetfreq.c create mode 100755 lib/ultralib/src/io/aisetnextbuf.c create mode 100644 lib/ultralib/src/io/cartrominit.c create mode 100644 lib/ultralib/src/io/contchannelreset.c create mode 100755 lib/ultralib/src/io/conteeplongread.c create mode 100755 lib/ultralib/src/io/conteeplongwrite.c create mode 100755 lib/ultralib/src/io/conteepprobe.c create mode 100755 lib/ultralib/src/io/conteepread.c create mode 100755 lib/ultralib/src/io/conteepwrite.c create mode 100755 lib/ultralib/src/io/contpfs.c create mode 100755 lib/ultralib/src/io/contquery.c create mode 100644 lib/ultralib/src/io/contramread.c create mode 100644 lib/ultralib/src/io/contramwrite.c create mode 100644 lib/ultralib/src/io/contreaddata.c create mode 100644 lib/ultralib/src/io/contreset.c create mode 100644 lib/ultralib/src/io/controller.c create mode 100755 lib/ultralib/src/io/controller.h create mode 100644 lib/ultralib/src/io/controller_gbpak.h create mode 100644 lib/ultralib/src/io/controller_voice.h create mode 100644 lib/ultralib/src/io/contsetch.c create mode 100644 lib/ultralib/src/io/crc.c create mode 100644 lib/ultralib/src/io/devmgr.c create mode 100755 lib/ultralib/src/io/dp.c create mode 100755 lib/ultralib/src/io/dpctr.c create mode 100755 lib/ultralib/src/io/dpgetstat.c create mode 100755 lib/ultralib/src/io/dpsetnextbuf.c create mode 100755 lib/ultralib/src/io/dpsetstat.c create mode 100644 lib/ultralib/src/io/epidma.c create mode 100644 lib/ultralib/src/io/epigettype.c create mode 100644 lib/ultralib/src/io/epilinkhandle.c create mode 100644 lib/ultralib/src/io/epirawdma.c create mode 100644 lib/ultralib/src/io/epirawread.c create mode 100644 lib/ultralib/src/io/epirawwrite.c create mode 100644 lib/ultralib/src/io/epiread.c create mode 100644 lib/ultralib/src/io/epiwrite.c create mode 100644 lib/ultralib/src/io/gbpakcheckconnector.c create mode 100644 lib/ultralib/src/io/gbpakgetbank.c create mode 100644 lib/ultralib/src/io/gbpakgetstatus.c create mode 100644 lib/ultralib/src/io/gbpakinit.c create mode 100644 lib/ultralib/src/io/gbpakpower.c create mode 100644 lib/ultralib/src/io/gbpakreadid.c create mode 100644 lib/ultralib/src/io/gbpakreadwrite.c create mode 100644 lib/ultralib/src/io/gbpaksetbank.c create mode 100644 lib/ultralib/src/io/motor.c create mode 100644 lib/ultralib/src/io/pfsallocatefile.c create mode 100644 lib/ultralib/src/io/pfschecker.c create mode 100644 lib/ultralib/src/io/pfsdeletefile.c create mode 100644 lib/ultralib/src/io/pfsfilestate.c create mode 100644 lib/ultralib/src/io/pfsfreeblocks.c create mode 100644 lib/ultralib/src/io/pfsgetlabel.c create mode 100644 lib/ultralib/src/io/pfsgetstatus.c create mode 100644 lib/ultralib/src/io/pfsinit.c create mode 100644 lib/ultralib/src/io/pfsinitpak.c create mode 100644 lib/ultralib/src/io/pfsisplug.c create mode 100644 lib/ultralib/src/io/pfsnumfiles.c create mode 100644 lib/ultralib/src/io/pfsreadwritefile.c create mode 100644 lib/ultralib/src/io/pfsreformat.c create mode 100644 lib/ultralib/src/io/pfsrepairid.c create mode 100644 lib/ultralib/src/io/pfssearchfile.c create mode 100644 lib/ultralib/src/io/pfsselectbank.c create mode 100644 lib/ultralib/src/io/pfssetlabel.c create mode 100644 lib/ultralib/src/io/pi.c create mode 100644 lib/ultralib/src/io/piacs.c create mode 100644 lib/ultralib/src/io/pidma.c create mode 100644 lib/ultralib/src/io/pigetcmdq.c create mode 100644 lib/ultralib/src/io/pigetstat.c create mode 100644 lib/ultralib/src/io/pigettype.c create mode 100644 lib/ultralib/src/io/piint.h create mode 100644 lib/ultralib/src/io/pimgr.c create mode 100644 lib/ultralib/src/io/pirawdma.c create mode 100644 lib/ultralib/src/io/pirawread.c create mode 100644 lib/ultralib/src/io/pirawwrite.c create mode 100644 lib/ultralib/src/io/piread.c create mode 100644 lib/ultralib/src/io/piwrite.c create mode 100644 lib/ultralib/src/io/si.c create mode 100644 lib/ultralib/src/io/siacs.c create mode 100644 lib/ultralib/src/io/sigetstat.c create mode 100755 lib/ultralib/src/io/siint.h create mode 100644 lib/ultralib/src/io/sirawdma.c create mode 100644 lib/ultralib/src/io/sirawread.c create mode 100644 lib/ultralib/src/io/sirawwrite.c create mode 100755 lib/ultralib/src/io/sp.c create mode 100755 lib/ultralib/src/io/spgetstat.c create mode 100755 lib/ultralib/src/io/sprawdma.c create mode 100755 lib/ultralib/src/io/sprawread.c create mode 100755 lib/ultralib/src/io/sprawwrite.c create mode 100644 lib/ultralib/src/io/spsetpc.c create mode 100755 lib/ultralib/src/io/spsetstat.c create mode 100755 lib/ultralib/src/io/sptask.c create mode 100755 lib/ultralib/src/io/sptaskyield.c create mode 100755 lib/ultralib/src/io/sptaskyielded.c create mode 100644 lib/ultralib/src/io/vi.c create mode 100644 lib/ultralib/src/io/viblack.c create mode 100644 lib/ultralib/src/io/viextendvstart.c create mode 100644 lib/ultralib/src/io/vifade.c create mode 100644 lib/ultralib/src/io/vigetcurrcontext.c create mode 100644 lib/ultralib/src/io/vigetcurrframebuf.c create mode 100644 lib/ultralib/src/io/vigetfield.c create mode 100644 lib/ultralib/src/io/vigetline.c create mode 100644 lib/ultralib/src/io/vigetmode.c create mode 100644 lib/ultralib/src/io/vigetnextcontext.c create mode 100644 lib/ultralib/src/io/vigetnextframebuf.c create mode 100644 lib/ultralib/src/io/vigetstat.c create mode 100644 lib/ultralib/src/io/viint.h create mode 100644 lib/ultralib/src/io/vimgr.c create mode 100644 lib/ultralib/src/io/virepeatline.c create mode 100644 lib/ultralib/src/io/visetevent.c create mode 100644 lib/ultralib/src/io/visetmode.c create mode 100644 lib/ultralib/src/io/visetspecial.c create mode 100644 lib/ultralib/src/io/visetxscale.c create mode 100644 lib/ultralib/src/io/visetyscale.c create mode 100644 lib/ultralib/src/io/viswapbuf.c create mode 100644 lib/ultralib/src/io/viswapcontext.c create mode 100644 lib/ultralib/src/io/vitbl.c create mode 100644 lib/ultralib/src/libc/bcmp.s create mode 100644 lib/ultralib/src/libc/bcopy.s create mode 100644 lib/ultralib/src/libc/bzero.s create mode 100755 lib/ultralib/src/libc/ldiv.c create mode 100755 lib/ultralib/src/libc/ll.c create mode 100755 lib/ultralib/src/libc/llbit.c create mode 100755 lib/ultralib/src/libc/llcvt.c create mode 100755 lib/ultralib/src/libc/sprintf.c create mode 100755 lib/ultralib/src/libc/string.c create mode 100755 lib/ultralib/src/libc/syncprintf.c create mode 100644 lib/ultralib/src/libc/xldtob.c create mode 100755 lib/ultralib/src/libc/xlitob.c create mode 100755 lib/ultralib/src/libc/xprintf.c create mode 100755 lib/ultralib/src/libc/xstdio.h create mode 100644 lib/ultralib/src/mgu/Makefile create mode 100644 lib/ultralib/src/mgu/asm.h create mode 100644 lib/ultralib/src/mgu/mtxcatf.s create mode 100644 lib/ultralib/src/mgu/mtxcatl.c create mode 100644 lib/ultralib/src/mgu/mtxf2l.s create mode 100644 lib/ultralib/src/mgu/mtxident.s create mode 100644 lib/ultralib/src/mgu/mtxidentf.s create mode 100644 lib/ultralib/src/mgu/mtxl2f.s create mode 100644 lib/ultralib/src/mgu/mtxxfmf.c create mode 100644 lib/ultralib/src/mgu/mtxxfml.c create mode 100644 lib/ultralib/src/mgu/normalize.s create mode 100644 lib/ultralib/src/mgu/regdef.h create mode 100644 lib/ultralib/src/mgu/rotate.c create mode 100644 lib/ultralib/src/mgu/scale.s create mode 100644 lib/ultralib/src/mgu/scalef.s create mode 100644 lib/ultralib/src/mgu/translate.s create mode 100644 lib/ultralib/src/mgu/translatef.s create mode 100644 lib/ultralib/src/os/ackramromread.c create mode 100644 lib/ultralib/src/os/ackramromwrite.c create mode 100644 lib/ultralib/src/os/afterprenmi.c create mode 100644 lib/ultralib/src/os/assert.c create mode 100644 lib/ultralib/src/os/atomic.c create mode 100644 lib/ultralib/src/os/createmesgqueue.c create mode 100644 lib/ultralib/src/os/createthread.c create mode 100644 lib/ultralib/src/os/destroythread.c create mode 100644 lib/ultralib/src/os/exceptasm.h create mode 100644 lib/ultralib/src/os/exceptasm.s create mode 100644 lib/ultralib/src/os/exit.c create mode 100644 lib/ultralib/src/os/getactivequeue.c create mode 100644 lib/ultralib/src/os/getcause.s create mode 100644 lib/ultralib/src/os/getcompare.s create mode 100644 lib/ultralib/src/os/getconfig.s create mode 100644 lib/ultralib/src/os/getcount.s create mode 100644 lib/ultralib/src/os/getcurrfaultthread.c create mode 100644 lib/ultralib/src/os/getfpccsr.s create mode 100644 lib/ultralib/src/os/gethwinterrupt.c create mode 100644 lib/ultralib/src/os/getintmask.s create mode 100644 lib/ultralib/src/os/getmemsize.c create mode 100644 lib/ultralib/src/os/getnextfaultthread.c create mode 100644 lib/ultralib/src/os/getsr.s create mode 100644 lib/ultralib/src/os/getthreadid.c create mode 100644 lib/ultralib/src/os/getthreadpri.c create mode 100644 lib/ultralib/src/os/gettime.c create mode 100644 lib/ultralib/src/os/gettlbasid.s create mode 100644 lib/ultralib/src/os/gettlbhi.s create mode 100644 lib/ultralib/src/os/gettlblo0.s create mode 100644 lib/ultralib/src/os/gettlblo1.s create mode 100644 lib/ultralib/src/os/gettlbpagemask.s create mode 100644 lib/ultralib/src/os/getwatchlo.s create mode 100644 lib/ultralib/src/os/initialize.c create mode 100644 lib/ultralib/src/os/initialize_emu.c create mode 100644 lib/ultralib/src/os/initialize_isv.c create mode 100644 lib/ultralib/src/os/initialize_kmc.c create mode 100644 lib/ultralib/src/os/initialize_msp.c create mode 100644 lib/ultralib/src/os/initrdb.c create mode 100644 lib/ultralib/src/os/interrupt.s create mode 100644 lib/ultralib/src/os/invaldcache.s create mode 100644 lib/ultralib/src/os/invalicache.s create mode 100644 lib/ultralib/src/os/jammesg.c create mode 100644 lib/ultralib/src/os/kdebugserver.c create mode 100644 lib/ultralib/src/os/maptlb.s create mode 100644 lib/ultralib/src/os/maptlbrdb.s create mode 100644 lib/ultralib/src/os/osint.h create mode 100644 lib/ultralib/src/os/parameters.s create mode 100644 lib/ultralib/src/os/physicaltovirtual.c create mode 100644 lib/ultralib/src/os/probetlb.s create mode 100644 lib/ultralib/src/os/rdbsend.c create mode 100644 lib/ultralib/src/os/recvmesg.c create mode 100644 lib/ultralib/src/os/resetglobalintmask.c create mode 100644 lib/ultralib/src/os/sendmesg.c create mode 100644 lib/ultralib/src/os/setcause.s create mode 100644 lib/ultralib/src/os/setcompare.s create mode 100644 lib/ultralib/src/os/setconfig.s create mode 100644 lib/ultralib/src/os/setcount.s create mode 100644 lib/ultralib/src/os/seterrorhandler.c create mode 100644 lib/ultralib/src/os/seteventmesg.c create mode 100644 lib/ultralib/src/os/setfpccsr.s create mode 100644 lib/ultralib/src/os/setglobalintmask.c create mode 100644 lib/ultralib/src/os/sethwinterrupt.c create mode 100644 lib/ultralib/src/os/setintmask.s create mode 100644 lib/ultralib/src/os/setpiinterrupt.c create mode 100644 lib/ultralib/src/os/setsr.s create mode 100644 lib/ultralib/src/os/setthreadpri.c create mode 100644 lib/ultralib/src/os/settime.c create mode 100644 lib/ultralib/src/os/settimer.c create mode 100644 lib/ultralib/src/os/settlbasid.s create mode 100644 lib/ultralib/src/os/setwatchlo.s create mode 100644 lib/ultralib/src/os/startthread.c create mode 100644 lib/ultralib/src/os/stopthread.c create mode 100644 lib/ultralib/src/os/stoptimer.c create mode 100644 lib/ultralib/src/os/syncputchars.c create mode 100644 lib/ultralib/src/os/testhost.c create mode 100644 lib/ultralib/src/os/thread.c create mode 100644 lib/ultralib/src/os/threadasm.h create mode 100644 lib/ultralib/src/os/timerintr.c create mode 100644 lib/ultralib/src/os/unmaptlb.s create mode 100644 lib/ultralib/src/os/unmaptlball.s create mode 100644 lib/ultralib/src/os/virtualtophysical.c create mode 100644 lib/ultralib/src/os/writebackdcache.s create mode 100644 lib/ultralib/src/os/writebackdcacheall.s create mode 100644 lib/ultralib/src/os/yieldthread.c create mode 100755 lib/ultralib/src/rg/free.c create mode 100755 lib/ultralib/src/rg/getbufcount.c create mode 100755 lib/ultralib/src/rg/getsize.c create mode 100755 lib/ultralib/src/rg/malloc.c create mode 100755 lib/ultralib/src/rg/region.c create mode 100644 lib/ultralib/src/rmon/rmonbrk.c create mode 100644 lib/ultralib/src/rmon/rmoncmds.c create mode 100644 lib/ultralib/src/rmon/rmonint.h create mode 100644 lib/ultralib/src/rmon/rmonmain.c create mode 100644 lib/ultralib/src/rmon/rmonmem.c create mode 100644 lib/ultralib/src/rmon/rmonmisc.c create mode 100644 lib/ultralib/src/rmon/rmonprint.c create mode 100644 lib/ultralib/src/rmon/rmonrcp.s create mode 100644 lib/ultralib/src/rmon/rmonregs.c create mode 100644 lib/ultralib/src/rmon/rmonsio.c create mode 100644 lib/ultralib/src/rmon/rmontask.c create mode 100644 lib/ultralib/src/sched/Makefile create mode 100644 lib/ultralib/src/sched/sched.c create mode 100644 lib/ultralib/src/sched/sched_log.fmt create mode 100644 lib/ultralib/src/sp/Makefile create mode 100644 lib/ultralib/src/sp/clearattribute.c create mode 100644 lib/ultralib/src/sp/color.c create mode 100644 lib/ultralib/src/sp/hide.c create mode 100644 lib/ultralib/src/sp/setattribute.c create mode 100644 lib/ultralib/src/sp/show.c create mode 100644 lib/ultralib/src/sp/sprite.c create mode 100644 lib/ultralib/src/sp/spriteex.c create mode 100644 lib/ultralib/src/sp/spriteex2.c create mode 100644 lib/ultralib/src/sp/spscale.c create mode 100644 lib/ultralib/src/vimodes/vimodefpalhaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpalhan1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpalhpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpalhpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodefpalhpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpalhpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallaf2.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallan1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallan2.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodefpallpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodempalhaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodempalhan1.c create mode 100644 lib/ultralib/src/vimodes/vimodempalhpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodempalhpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodempalhpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodempalhpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodempallaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodempallaf2.c create mode 100644 lib/ultralib/src/vimodes/vimodempallan1.c create mode 100644 lib/ultralib/src/vimodes/vimodempallan2.c create mode 100644 lib/ultralib/src/vimodes/vimodempallpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodempallpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodempallpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodempallpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodentschaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodentschan1.c create mode 100644 lib/ultralib/src/vimodes/vimodentschpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodentschpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodentschpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodentschpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclaf2.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclan1.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclan2.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodentsclpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodepalhaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodepalhan1.c create mode 100644 lib/ultralib/src/vimodes/vimodepalhpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodepalhpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodepalhpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodepalhpn2.c create mode 100644 lib/ultralib/src/vimodes/vimodepallaf1.c create mode 100644 lib/ultralib/src/vimodes/vimodepallaf2.c create mode 100644 lib/ultralib/src/vimodes/vimodepallan1.c create mode 100644 lib/ultralib/src/vimodes/vimodepallan2.c create mode 100644 lib/ultralib/src/vimodes/vimodepallpf1.c create mode 100644 lib/ultralib/src/vimodes/vimodepallpf2.c create mode 100644 lib/ultralib/src/vimodes/vimodepallpn1.c create mode 100644 lib/ultralib/src/vimodes/vimodepallpn2.c create mode 100644 lib/ultralib/src/voice/voicecheckresult.c create mode 100644 lib/ultralib/src/voice/voicecheckword.c create mode 100644 lib/ultralib/src/voice/voicecleardictionary.c create mode 100644 lib/ultralib/src/voice/voicecontread2.c create mode 100644 lib/ultralib/src/voice/voicecontread36.c create mode 100644 lib/ultralib/src/voice/voicecontrolgain.c create mode 100644 lib/ultralib/src/voice/voicecontwrite20.c create mode 100644 lib/ultralib/src/voice/voicecontwrite4.c create mode 100644 lib/ultralib/src/voice/voicecountsyllables.c create mode 100644 lib/ultralib/src/voice/voicecrc.c create mode 100644 lib/ultralib/src/voice/voicegetreaddata.c create mode 100644 lib/ultralib/src/voice/voicegetstatus.c create mode 100644 lib/ultralib/src/voice/voiceinit.c create mode 100644 lib/ultralib/src/voice/voiceinternal.h create mode 100644 lib/ultralib/src/voice/voicemaskdictionary.c create mode 100644 lib/ultralib/src/voice/voicesetadconverter.c create mode 100644 lib/ultralib/src/voice/voicesetword.c create mode 100644 lib/ultralib/src/voice/voicestartreaddata.c create mode 100644 lib/ultralib/src/voice/voicestopreaddata.c create mode 100644 lib/ultralib/tools/Makefile create mode 100644 lib/ultralib/tools/asm_differ/.gitignore create mode 100644 lib/ultralib/tools/asm_differ/.gitrepo create mode 100644 lib/ultralib/tools/asm_differ/.pre-commit-config.yaml create mode 100644 lib/ultralib/tools/asm_differ/LICENSE create mode 100644 lib/ultralib/tools/asm_differ/README.md create mode 100644 lib/ultralib/tools/asm_differ/diff-stylesheet.css create mode 100755 lib/ultralib/tools/asm_differ/diff.py create mode 100644 lib/ultralib/tools/asm_differ/diff_settings.py create mode 100644 lib/ultralib/tools/asm_differ/mypy.ini create mode 100644 lib/ultralib/tools/asm_differ/screenshot.png create mode 100755 lib/ultralib/tools/compile_sjis.py create mode 100755 lib/ultralib/tools/disassemble_elf.py create mode 100755 lib/ultralib/tools/fix_objfile.py create mode 100755 lib/ultralib/tools/libdiff.py create mode 100755 lib/ultralib/tools/libelf.py create mode 100644 lib/ultralib/tools/mdebug.py create mode 100644 lib/ultralib/tools/mips_isa.py create mode 100755 lib/ultralib/tools/patch_ar_meta.py create mode 100755 lib/ultralib/tools/shiftjis_conv.py create mode 100644 lib/ultralib/tools/util.py create mode 100644 linker_scripts/common_undef_syms.ld create mode 100644 linker_scripts/jp/hardware_regs.ld create mode 100644 linker_scripts/jp/ignored_addresses.txt create mode 100644 linker_scripts/jp/symbol_addrs_boot.txt create mode 100644 linker_scripts/jp/symbol_addrs_code.txt create mode 100644 linker_scripts/jp/symbol_addrs_libultra.txt create mode 100644 linker_scripts/jp/undefined_syms.ld create mode 100644 linker_scripts/libultra_syms.ld create mode 100644 relocs/reloc_addrs.jp.txt create mode 100644 requirements.txt create mode 100644 src/boot/boot_main.c create mode 100644 tools/.gitignore create mode 100644 tools/Makefile create mode 100644 tools/asm-differ/.gitignore create mode 100644 tools/asm-differ/.gitrepo create mode 100644 tools/asm-differ/.pre-commit-config.yaml create mode 100644 tools/asm-differ/LICENSE create mode 100644 tools/asm-differ/README.md create mode 100644 tools/asm-differ/diff-stylesheet.css create mode 100755 tools/asm-differ/diff.py create mode 100644 tools/asm-differ/diff_settings.py create mode 100644 tools/asm-differ/mypy.ini create mode 100644 tools/asm-differ/pyproject.toml create mode 100644 tools/asm-differ/screenshot.png create mode 100644 tools/asm-processor/.gitignore create mode 100644 tools/asm-processor/.gitrepo create mode 100644 tools/asm-processor/LICENSE create mode 100644 tools/asm-processor/README.md create mode 100755 tools/asm-processor/add-test.sh create mode 100644 tools/asm-processor/asm_processor.py create mode 100644 tools/asm-processor/build.py create mode 100755 tools/asm-processor/compile-test.sh create mode 100644 tools/asm-processor/prelude.inc create mode 100755 tools/asm-processor/run-tests.sh create mode 100644 tools/asm-processor/tests/ascii.c create mode 100644 tools/asm-processor/tests/ascii.objdump create mode 100644 tools/asm-processor/tests/comments.c create mode 100644 tools/asm-processor/tests/comments.objdump create mode 100644 tools/asm-processor/tests/force.c create mode 100644 tools/asm-processor/tests/force.objdump create mode 100644 tools/asm-processor/tests/kpic-o1.c create mode 100644 tools/asm-processor/tests/kpic-o1.objdump create mode 100644 tools/asm-processor/tests/kpic-o2.c create mode 100644 tools/asm-processor/tests/kpic-o2.objdump create mode 100644 tools/asm-processor/tests/label-sameline.c create mode 100644 tools/asm-processor/tests/label-sameline.objdump create mode 100644 tools/asm-processor/tests/large.c create mode 100644 tools/asm-processor/tests/large.objdump create mode 100644 tools/asm-processor/tests/late_rodata_align.c create mode 100644 tools/asm-processor/tests/late_rodata_align.objdump create mode 100644 tools/asm-processor/tests/late_rodata_doubles.c create mode 100644 tools/asm-processor/tests/late_rodata_doubles.objdump create mode 100644 tools/asm-processor/tests/late_rodata_doubles_mips1.c create mode 100644 tools/asm-processor/tests/late_rodata_doubles_mips1.objdump create mode 100644 tools/asm-processor/tests/late_rodata_jtbl.c create mode 100644 tools/asm-processor/tests/late_rodata_jtbl.objdump create mode 100644 tools/asm-processor/tests/late_rodata_jtbl_mips1.c create mode 100644 tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump create mode 100644 tools/asm-processor/tests/late_rodata_misaligned_doubles.c create mode 100644 tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump create mode 100644 tools/asm-processor/tests/line-continuation-separate-file.s create mode 100644 tools/asm-processor/tests/line-continuation.asmproc.d create mode 100644 tools/asm-processor/tests/line-continuation.c create mode 100644 tools/asm-processor/tests/line-continuation.objdump create mode 100644 tools/asm-processor/tests/o0.c create mode 100644 tools/asm-processor/tests/o0.objdump create mode 100644 tools/asm-processor/tests/o2.c create mode 100644 tools/asm-processor/tests/o2.objdump create mode 100644 tools/asm-processor/tests/pascal.objdump create mode 100644 tools/asm-processor/tests/pascal.p create mode 100644 tools/asm-processor/tests/static-global.c create mode 100644 tools/asm-processor/tests/static-global.objdump create mode 100644 tools/asm-processor/tests/static.c create mode 100644 tools/asm-processor/tests/static.objdump create mode 100644 tools/asm-processor/tests/test1.c create mode 100644 tools/asm-processor/tests/test1.objdump create mode 100644 tools/asm-processor/tests/test2.c create mode 100644 tools/asm-processor/tests/test2.objdump create mode 100644 tools/asm-processor/tests/test3.c create mode 100644 tools/asm-processor/tests/test3.objdump create mode 100755 tools/decompress_baserom.py create mode 100644 tools/fado/.clang-format create mode 100644 tools/fado/.gitignore create mode 100644 tools/fado/.gitrepo create mode 100644 tools/fado/LICENSE create mode 100644 tools/fado/Makefile create mode 100644 tools/fado/README.md create mode 100755 tools/fado/find_program.sh create mode 100644 tools/fado/include/fado.h create mode 100644 tools/fado/include/help.h create mode 100644 tools/fado/include/macros.h create mode 100644 tools/fado/include/mido.h create mode 100644 tools/fado/include/mips_elf.h create mode 100644 tools/fado/lib/fairy/fairy.c create mode 100644 tools/fado/lib/fairy/fairy.h create mode 100644 tools/fado/lib/fairy/fairy_data.inc create mode 100644 tools/fado/lib/fairy/fairy_print.c create mode 100644 tools/fado/lib/fairy/fairy_print.h create mode 100644 tools/fado/lib/vc_vector/.gitrepo create mode 100644 tools/fado/lib/vc_vector/.travis.yml create mode 100644 tools/fado/lib/vc_vector/LICENSE.md create mode 100644 tools/fado/lib/vc_vector/Makefile create mode 100644 tools/fado/lib/vc_vector/README.md create mode 100644 tools/fado/lib/vc_vector/vc_vector.c create mode 100644 tools/fado/lib/vc_vector/vc_vector.h create mode 100644 tools/fado/lib/vc_vector/vc_vector_test.c create mode 100644 tools/fado/lib/vc_vector/vc_vector_test.h create mode 100644 tools/fado/ovl_En_Hs_reloc.s create mode 100644 tools/fado/src/fado.c create mode 100644 tools/fado/src/help.c create mode 100644 tools/fado/src/main.c create mode 100644 tools/fado/src/mido.c create mode 100644 tools/fado/src/version.inc create mode 100644 tools/fado/z64_relocation_section_format.md create mode 100755 tools/first_diff.py create mode 100755 tools/format.py create mode 100755 tools/m2ctx.py create mode 100644 tools/permuter_settings.toml create mode 100755 tools/pj64_syms.py create mode 100644 tools/splat/.github/workflows/mypy.yml create mode 100644 tools/splat/.gitignore create mode 100644 tools/splat/.gitrepo create mode 100644 tools/splat/CHANGELOG.md create mode 100644 tools/splat/LICENSE create mode 100644 tools/splat/Makefile create mode 100644 tools/splat/README.md create mode 100755 tools/splat/create_config.py create mode 100644 tools/splat/mypy.ini create mode 100644 tools/splat/platforms/gc.py create mode 100644 tools/splat/platforms/n64.py create mode 100644 tools/splat/platforms/psx.py create mode 100644 tools/splat/requirements.txt create mode 100644 tools/splat/segtypes/__init__.py create mode 100644 tools/splat/segtypes/address_range.py create mode 100644 tools/splat/segtypes/common/__init__.py create mode 100644 tools/splat/segtypes/common/asm.py create mode 100644 tools/splat/segtypes/common/bin.py create mode 100644 tools/splat/segtypes/common/bss.py create mode 100644 tools/splat/segtypes/common/c.py create mode 100644 tools/splat/segtypes/common/code.py create mode 100644 tools/splat/segtypes/common/codesubsegment.py create mode 100644 tools/splat/segtypes/common/data.py create mode 100644 tools/splat/segtypes/common/decompressor.py create mode 100644 tools/splat/segtypes/common/group.py create mode 100644 tools/splat/segtypes/common/hasm.py create mode 100644 tools/splat/segtypes/common/header.py create mode 100644 tools/splat/segtypes/common/lib.py create mode 100644 tools/splat/segtypes/common/rdata.py create mode 100644 tools/splat/segtypes/common/rodata.py create mode 100644 tools/splat/segtypes/common/sbss.py create mode 100644 tools/splat/segtypes/common/sdata.py create mode 100644 tools/splat/segtypes/common/segment.py create mode 100644 tools/splat/segtypes/gc/apploader.py create mode 100644 tools/splat/segtypes/gc/bi2.py create mode 100644 tools/splat/segtypes/gc/bootinfo.py create mode 100644 tools/splat/segtypes/gc/dol.py create mode 100644 tools/splat/segtypes/gc/dolheader.py create mode 100644 tools/splat/segtypes/gc/fst.py create mode 100644 tools/splat/segtypes/gc/rarc.py create mode 100644 tools/splat/segtypes/gc/relheader.py create mode 100644 tools/splat/segtypes/gc/segment.py create mode 100644 tools/splat/segtypes/linker_entry.py create mode 100644 tools/splat/segtypes/n64/__init__.py create mode 100644 tools/splat/segtypes/n64/asm.py create mode 100644 tools/splat/segtypes/n64/ci.py create mode 100644 tools/splat/segtypes/n64/ci4.py create mode 100644 tools/splat/segtypes/n64/ci8.py create mode 100644 tools/splat/segtypes/n64/gfx.py create mode 100644 tools/splat/segtypes/n64/hasm.py create mode 100644 tools/splat/segtypes/n64/header.py create mode 100644 tools/splat/segtypes/n64/i1.py create mode 100644 tools/splat/segtypes/n64/i4.py create mode 100644 tools/splat/segtypes/n64/i8.py create mode 100644 tools/splat/segtypes/n64/ia16.py create mode 100644 tools/splat/segtypes/n64/ia4.py create mode 100644 tools/splat/segtypes/n64/ia8.py create mode 100644 tools/splat/segtypes/n64/img.py create mode 100644 tools/splat/segtypes/n64/ipl3.py create mode 100644 tools/splat/segtypes/n64/linker_offset.py create mode 100644 tools/splat/segtypes/n64/mio0.py create mode 100644 tools/splat/segtypes/n64/palette.py create mode 100644 tools/splat/segtypes/n64/rgba16.py create mode 100644 tools/splat/segtypes/n64/rgba32.py create mode 100644 tools/splat/segtypes/n64/rsp.py create mode 100644 tools/splat/segtypes/n64/segment.py create mode 100644 tools/splat/segtypes/n64/vtx.py create mode 100644 tools/splat/segtypes/n64/yay0.py create mode 100644 tools/splat/segtypes/psx/__init__.py create mode 100644 tools/splat/segtypes/psx/asm.py create mode 100644 tools/splat/segtypes/psx/header.py create mode 100644 tools/splat/segtypes/psx/segment.py create mode 100644 tools/splat/segtypes/segment.py create mode 100755 tools/splat/split.py create mode 100644 tools/splat/stubs/colorama.pyi create mode 100644 tools/splat/util/__init__.py create mode 100644 tools/splat/util/color.py create mode 100644 tools/splat/util/compiler.py create mode 100644 tools/splat/util/floats.py create mode 100644 tools/splat/util/gc/gcfst.py create mode 100644 tools/splat/util/gc/gcinfo.py create mode 100644 tools/splat/util/gc/gcutil.py create mode 100644 tools/splat/util/log.py create mode 100644 tools/splat/util/n64/Mio0decompress.py create mode 100644 tools/splat/util/n64/Yay0decompress.c create mode 100644 tools/splat/util/n64/Yay0decompress.py create mode 100644 tools/splat/util/n64/__init__.py create mode 100644 tools/splat/util/n64/decompressor.py create mode 100755 tools/splat/util/n64/find_code_length.py create mode 100755 tools/splat/util/n64/rominfo.py create mode 100644 tools/splat/util/options.py create mode 100644 tools/splat/util/palettes.py create mode 100644 tools/splat/util/range.py create mode 100644 tools/splat/util/relocs.py create mode 100644 tools/splat/util/symbols.py create mode 100755 tools/sym_info.py diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..91d6207d --- /dev/null +++ b/.clang-format @@ -0,0 +1,23 @@ +IndentWidth: 4 +Language: Cpp +UseTab: Never +ColumnLimit: 120 +PointerAlignment: Right +BreakBeforeBraces: Attach +SpaceAfterCStyleCast: false +Cpp11BracedListStyle: false +IndentCaseLabels: true +BinPackArguments: true +BinPackParameters: true +AlignAfterOpenBracket: Align +AlignOperands: true +BreakBeforeTernaryOperators: true +BreakBeforeBinaryOperators: None +AllowShortBlocksOnASingleLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AlignEscapedNewlines: Left +AlignTrailingComments: true +SortIncludes: false diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..79af26fb --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,9 @@ +Checks: 'readability-*,-readability-magic-numbers,-readability-uppercase-literal-suffix,-readability-non-const-parameter,-readability-else-after-return,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-security.insecureAPI.*,-clang-analyzer-deadcode.DeadStores,-clang-analyzer-core.uninitialized.ArraySubscript,-clang-analyzer-core.UndefinedBinaryOperatorResult,bugprone*,-bugprone-macro-parentheses,-bugprone-reserved-identifier,-bugprone-narrowing-conversions,-bugprone-too-small-loop-variable,-bugprone-integer-division,-bugprone-sizeof-expression,-bugprone-suspicious-include,modernize*,-bugprone-branch-clone,-bugprone-signed-char-misuse,performance*,portability*,diagnostic-*,analyzer-*,misc*' +WarningsAsErrors: '' +HeaderFilterRegex: '^(src|include)\/.*\.h$' +FormatStyle: 'file' +CheckOptions: + # Require argument names to match exactly (instead of allowing a name to be a prefix/suffix of another) + # Note: 'true' is expected by clang-tidy 12+ but '1' is used for compatibility with older versions + - key: readability-inconsistent-declaration-parameter-name.Strict + value: 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1c65a2a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +.splat/ +asm/ +bin/ +assets/ +build/ + +linker_scripts/jp/auto/ +linker_scripts/cn/auto/ +linker_scripts/jp/animalforest.ld +linker_scripts/cn/animalforest.ld +*_auto.ld +animalforest.ld + +__pycache__/ +.make_options + +ctx.c +ctx.c.m2c +*.o + +*.z64 +*.n64 +*.v64 +*.plf +*.sym + +.vscode/* +!.vscode/c_cpp_properties.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..3aa0c3cf --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,37 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "include", + ".", + "lib/ultralib/include", + "lib/ultralib/include/PR" + ], + "defines": [ + "NON_EQUIVALENT", + "NON_MATCHING", + "AVOID_UB", + "CC_CHECK=1", + "_LANGUAGE_C", + "F3DEX_GBI_2", + "_MIPS_SZLONG=32", + "NDEBUG", + "_FINALROM", + "__USE_ISOC99", + "__mips__" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true + }, + "compilerPath": "/usr/bin/clang", + "intelliSenseMode": "linux-clang-x86", + "compilerArgs": [ + "-m32" + ], + "cStandard": "gnu89" + } + ], + "version": 4 +} diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..f600f2b4 --- /dev/null +++ b/Makefile @@ -0,0 +1,276 @@ +# Build options can be changed by modifying the makefile or by building with 'make SETTING=value'. +# It is also possible to override the settings in Defaults in a file called .make_options as 'SETTING=value'. + +-include .make_options + +MAKEFLAGS += --no-builtin-rules + +#### Defaults #### + +# If COMPARE is 1, check the output md5sum after building +COMPARE ?= 1 +# If NON_MATCHING is 1, define the NON_MATCHING C flag when building +NON_MATCHING ?= 0 +# if WERROR is 1, pass -Werror to CC_CHECK, so warnings would be treated as errors +WERROR ?= 0 +# Keep .mdebug section in build +KEEP_MDEBUG ?= 0 +# Check code syntax with host compiler +RUN_CC_CHECK ?= 1 +CC_CHECK_COMP ?= clang +# Dump build object files +OBJDUMP_BUILD ?= 1 + +# Set prefix to mips binutils binaries (mips-linux-gnu-ld => 'mips-linux-gnu-') - Change at your own risk! +# In nearly all cases, not having 'mips-linux-gnu-*' binaries on the PATH is indicative of missing dependencies +MIPS_BINUTILS_PREFIX ?= mips-linux-gnu- + + +VERSION ?= jp + +BASEROM := baserom.$(VERSION).z64 +BASEROM_UNCOMPRESSED := baserom_uncompressed.$(VERSION).z64 +TARGET := animalforest + + +### Output ### + +BUILD_DIR := build +ROM := $(BUILD_DIR)/$(TARGET)_uncompressed.$(VERSION).z64 +ELF := $(BUILD_DIR)/$(TARGET).$(VERSION).elf +LD_MAP := $(BUILD_DIR)/$(TARGET).$(VERSION).map +LD_SCRIPT := linker_scripts/$(VERSION)/$(TARGET).ld +ROMC := $(BUILD_DIR)/$(TARGET).$(VERSION).z64 + + +#### Setup #### + +BUILD_DEFINES ?= + +ifeq ($(VERSION),jp) + BUILD_DEFINES += -DVERSION_JP=1 +else +ifeq ($(VERSION),cn) + BUILD_DEFINES += -DVERSION_CN=1 -DBBPLAYER=1 +else +$(error Invalid VERSION variable detected. Please use either 'jp' or 'cn') +endif +endif + + +ifeq ($(NON_MATCHING),1) + BUILD_DEFINES += -DNON_MATCHING -DAVOID_UB + COMPARE := 0 +endif + +MAKE = make +CPPFLAGS += -fno-dollars-in-identifiers -P +LDFLAGS := --no-check-sections --accept-unknown-input-arch --emit-relocs + +UNAME_S := $(shell uname -s) +ifeq ($(OS),Windows_NT) +$(error Native Windows is currently unsupported for building this repository, use WSL instead c:) +else ifeq ($(UNAME_S),Linux) + DETECTED_OS := linux +else ifeq ($(UNAME_S),Darwin) + DETECTED_OS := mac + MAKE := gmake + CPPFLAGS += -xc++ +endif + +#### Tools #### +ifneq ($(shell type $(MIPS_BINUTILS_PREFIX)ld >/dev/null 2>/dev/null; echo $$?), 0) +$(error Unable to find $(MIPS_BINUTILS_PREFIX)ld. Please install or build MIPS binutils, commonly mips-linux-gnu. (or set MIPS_BINUTILS_PREFIX if your MIPS binutils install uses another prefix)) +endif + + +CC := tools/ido/$(DETECTED_OS)/7.1/cc +CC_OLD := tools/ido/$(DETECTED_OS)/5.3/cc + + +AS := $(MIPS_BINUTILS_PREFIX)as +LD := $(MIPS_BINUTILS_PREFIX)ld +OBJCOPY := $(MIPS_BINUTILS_PREFIX)objcopy +OBJDUMP := $(MIPS_BINUTILS_PREFIX)objdump +CPP := cpp +ICONV := iconv +ASM_PROC := python3 tools/asm-processor/build.py + +ASM_PROC_FLAGS := --input-enc=utf-8 --output-enc=euc-jp --convert-statics=global-with-filename + +SPLAT ?= tools/splat/split.py +SPLAT_YAML ?= $(TARGET).$(VERSION).yaml + + + +IINC := -Iinclude -Ibin/$(VERSION) -I. +IINC += -Ilib/ultralib/include -Ilib/ultralib/include/PR + +ifeq ($(KEEP_MDEBUG),0) + RM_MDEBUG = $(OBJCOPY) --remove-section .mdebug $@ +else + RM_MDEBUG = @: +endif + +# Check code syntax with host compiler +CHECK_WARNINGS := -Wall -Wextra -Wimplicit-fallthrough -Wno-unknown-pragmas -Wno-missing-braces -Wno-sign-compare -Wno-uninitialized +# Have CC_CHECK pretend to be a MIPS compiler +MIPS_BUILTIN_DEFS := -DMIPSEB -D_MIPS_FPSET=16 -D_MIPS_ISA=2 -D_ABIO32=1 -D_MIPS_SIM=_ABIO32 -D_MIPS_SZINT=32 -D_MIPS_SZPTR=32 +ifneq ($(RUN_CC_CHECK),0) +# The -MMD flags additionaly creates a .d file with the same name as the .o file. + CC_CHECK := $(CC_CHECK_COMP) + CC_CHECK_FLAGS := -MMD -MP -fno-builtin -fsyntax-only -funsigned-char -fdiagnostics-color -std=gnu89 -m32 -DNON_MATCHING -DAVOID_UB -DCC_CHECK=1 + ifneq ($(WERROR), 0) + CHECK_WARNINGS += -Werror + endif +else + CC_CHECK := @: +endif + + +CFLAGS += -G 0 -non_shared -Xcpluscomm -nostdinc -Wab,-r4300_mul + +WARNINGS := -fullwarn -verbose -woff 624,649,838,712,516,513,596,564,594 +ASFLAGS := -march=vr4300 -32 -G0 +COMMON_DEFINES := -D_MIPS_SZLONG=32 +GBI_DEFINES := -DF3DEX_GBI_2 +RELEASE_DEFINES := -DNDEBUG -D_FINALROM +AS_DEFINES := -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_ULTRA64 +C_DEFINES := -DLANGUAGE_C -D_LANGUAGE_C +ENDIAN := -EB + +OPTFLAGS := -O2 +MIPS_VERSION := -mips2 +ICONV_FLAGS := --from-code=UTF-8 --to-code=EUC-JP + +# Use relocations and abi fpr names in the dump +OBJDUMP_FLAGS := --disassemble --reloc --disassemble-zeroes -Mreg-names=32 -Mno-aliases + +ifneq ($(OBJDUMP_BUILD), 0) + OBJDUMP_CMD = $(OBJDUMP) $(OBJDUMP_FLAGS) $@ > $(@:.o=.dump.s) + OBJCOPY_BIN = $(OBJCOPY) -O binary $@ $@.bin +else + OBJDUMP_CMD = @: + OBJCOPY_BIN = @: +endif + + +#### Files #### + +$(shell mkdir -p asm bin linker_scripts/$(VERSION)/auto) + +SRC_DIRS := $(shell find src -type d) +ASM_DIRS := $(shell find asm/$(VERSION) -type d -not -path "asm/$(VERSION)/nonmatchings/*") +BIN_DIRS := $(shell find bin -type d) + +C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) +S_FILES := $(foreach dir,$(ASM_DIRS) $(SRC_DIRS),$(wildcard $(dir)/*.s)) +BIN_FILES := $(foreach dir,$(BIN_DIRS),$(wildcard $(dir)/*.bin)) +O_FILES := $(foreach f,$(C_FILES:.c=.o),$(BUILD_DIR)/$f) \ + $(foreach f,$(S_FILES:.s=.o),$(BUILD_DIR)/$f) \ + $(foreach f,$(BIN_FILES:.bin=.o),$(BUILD_DIR)/$f) + + +# Automatic dependency files +DEP_FILES := $(O_FILES:.o=.d) \ + $(O_FILES:.o=.asmproc.d) + +# create build directories +$(shell mkdir -p $(BUILD_DIR)/linker_scripts/$(VERSION) $(BUILD_DIR)/linker_scripts/$(VERSION)/auto $(foreach dir,$(SRC_DIRS) $(ASM_DIRS) $(BIN_DIRS),$(BUILD_DIR)/$(dir))) + + +# directory flags + +# per-file flags + +# cc & asm-processor +build/src/%.o: CC := $(ASM_PROC) $(ASM_PROC_FLAGS) $(CC) -- $(AS) $(ASFLAGS) -- + + +#### Main Targets ### + +all: uncompressed + +uncompressed: $(ROM) +ifneq ($(COMPARE),0) + @md5sum $(ROM) + @md5sum -c $(TARGET)_uncompressed.$(VERSION).md5 +endif + +# TODO +# compressed: $(ROMC) +# ifneq ($(COMPARE),0) +# @md5sum $(ROMC) +# @md5sum -c $(TARGET).$(VERSION).md5 +# endif + +clean: + $(RM) -r $(BUILD_DIR)/asm $(BUILD_DIR)/bin $(BUILD_DIR)/src $(ROM) $(ROMC) $(ELF) + +libclean: + $(RM) -r $(BUILD_DIR)/lib + +distclean: clean + $(RM) -r $(BUILD_DIR) asm/ bin/ .splat/ + $(RM) -r linker_scripts/$(VERSION)/auto $(LD_SCRIPT) + $(MAKE) -C tools distclean + +setup: + $(MAKE) -C tools + python3 tools/decompress_baserom.py + +extract: + $(RM) -r asm/$(VERSION) bin/$(VERSION) + $(SPLAT) $(SPLAT_YAML) + +diff-init: all + $(RM) -rf expected/ + mkdir -p expected/ + cp -r $(BUILD_DIR) expected/$(BUILD_DIR) + +init: + $(MAKE) distclean + $(MAKE) setup + $(MAKE) extract + $(MAKE) all + $(MAKE) diff-init + +.PHONY: all compressed uncompressed clean distclean setup extract diff-init init +.DEFAULT_GOAL := all +# Prevent removing intermediate files +.SECONDARY: + + +#### Various Recipes #### + +$(ROM): $(ELF) + $(OBJCOPY) -O binary --pad-to=0x1914000 --gap-fill=0xFF $< $@ + +# TODO: avoid using auto/undefined +$(ELF): $(O_FILES) $(LD_SCRIPT) $(BUILD_DIR)/linker_scripts/$(VERSION)/hardware_regs.ld $(BUILD_DIR)/linker_scripts/$(VERSION)/undefined_syms.ld $(BUILD_DIR)/linker_scripts/common_undef_syms.ld $(BUILD_DIR)/linker_scripts/libultra_syms.ld $(BUILD_DIR)/linker_scripts/$(VERSION)/auto/undefined_syms_auto.ld $(BUILD_DIR)/linker_scripts/$(VERSION)/auto/undefined_funcs_auto.ld + $(LD) $(LDFLAGS) -T $(LD_SCRIPT) \ + -T $(BUILD_DIR)/linker_scripts/$(VERSION)/hardware_regs.ld -T $(BUILD_DIR)/linker_scripts/$(VERSION)/undefined_syms.ld -T $(BUILD_DIR)/linker_scripts/common_undef_syms.ld -T $(BUILD_DIR)/linker_scripts/libultra_syms.ld \ + -T $(BUILD_DIR)/linker_scripts/$(VERSION)/auto/undefined_syms_auto.ld -T $(BUILD_DIR)/linker_scripts/$(VERSION)/auto/undefined_funcs_auto.ld \ + -Map $(LD_MAP) -o $@ + + +$(BUILD_DIR)/%.ld: %.ld + $(CPP) $(CPPFLAGS) $(BUILD_DEFINES) $(IINC) $< > $@ + +$(BUILD_DIR)/%.o: %.bin + $(OBJCOPY) -I binary -O elf32-big $< $@ + +$(BUILD_DIR)/%.o: %.s + $(CPP) $(CPPFLAGS) $(BUILD_DEFINES) $(IINC) -I $(dir $*) $(COMMON_DEFINES) $(RELEASE_DEFINES) $(GBI_DEFINES) $(AS_DEFINES) $< | $(ICONV) $(ICONV_FLAGS) | $(AS) $(ASFLAGS) $(ENDIAN) $(IINC) -I $(dir $*) -o $@ + $(OBJDUMP_CMD) + +$(BUILD_DIR)/%.o: %.c + $(CC_CHECK) $(CC_CHECK_FLAGS) $(IINC) -I $(dir $*) $(CHECK_WARNINGS) $(BUILD_DEFINES) $(COMMON_DEFINES) $(RELEASE_DEFINES) $(GBI_DEFINES) $(C_DEFINES) $(MIPS_BUILTIN_DEFS) -o $@ $< + $(CC) -c $(CFLAGS) $(BUILD_DEFINES) $(IINC) $(WARNINGS) $(MIPS_VERSION) $(ENDIAN) $(COMMON_DEFINES) $(RELEASE_DEFINES) $(GBI_DEFINES) $(C_DEFINES) $(OPTFLAGS) -o $@ $< + $(OBJDUMP_CMD) + $(RM_MDEBUG) + +-include $(DEP_FILES) + +# Print target for debugging +print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true diff --git a/README.md b/README.md new file mode 100644 index 00000000..ff95b33f --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# Animal Forest + +```diff +- WARNING! - + +This repository is a work in progress, and while it can be used to make certain changes, it's +still constantly evolving. If you wish to use it for modding purposes in its current state, +please be aware that the codebase could drastically change at any time. Also note that some +parts of the ROM may not be 'shiftable' yet, so modifying them could currently be difficult. +``` + +## Setup + +### Linux + +#### 1. Install build dependencies + +The build process has the following package requirements: + +* make +* git +* build-essential +* clang +* binutils-mips-linux-gnu +* python3 +* pip3 + +Under Debian / Ubuntu (which we recommend using), you can install them with the following commands: + +```bash +sudo apt update +sudo apt install make git build-essential clang binutils-mips-linux-gnu python3 python3-pip +``` + +#### 2. Install python dependencies + +The build process has a few python packages required that are located in `requirements.txt`. + +To install them simply run in a terminal: + +```bash +python3 -m pip install -U -r requirements.txt +``` + +#### 3. Prepare a base ROM + +Copy your ROM to inside the root of this new project directory, and rename the file of the baserom to reflect the version of ROM you are using. ex: `baserom.jp.z64` + +#### 4. Make and Build the ROM + +To start the extraction/build process, run the following command: + +```bash +make setup +make extract +make +``` + +## Note about licensing + +The contents of the `src` and `include` folders are, as far as possible, licensed under CC0. + +Other folders and files in the repository are CC0 unless they specify another license. + +The licensing of this repository does not cover subrepos, namely: + +* `tools/asm-differ` +* `tools/asm-processor` +* `tools/fado` +* `tools/splat` +* `lib/ultralib` diff --git a/animalforest.jp.md5 b/animalforest.jp.md5 new file mode 100644 index 00000000..431ad1dc --- /dev/null +++ b/animalforest.jp.md5 @@ -0,0 +1 @@ +a4f7c57c180297b2e7ba5a5feb44fe0b build/animalforest.jp.z64 diff --git a/animalforest.jp.yaml b/animalforest.jp.yaml new file mode 100644 index 00000000..2d42b8bd --- /dev/null +++ b/animalforest.jp.yaml @@ -0,0 +1,496 @@ +name: Doubutsunomori (Japanese) +sha1: 3ee1f866eb08c0ce57a30e09f0c8b0a16a760c8f +options: + basename: animalforest + target_path: baserom_uncompressed.jp.z64 + ld_script_path: linker_scripts/jp/animalforest.ld + base_path: . + compiler: IDO + find_file_boundaries: True + header_encoding: ASCII + platform: n64 + + undefined_funcs_auto_path: linker_scripts/jp/auto/undefined_funcs_auto.ld + undefined_syms_auto_path: linker_scripts/jp/auto/undefined_syms_auto.ld + + symbol_addrs_path: + - linker_scripts/jp/symbol_addrs_boot.txt + - linker_scripts/jp/symbol_addrs_libultra.txt + - linker_scripts/jp/symbol_addrs_code.txt + - linker_scripts/jp/ignored_addresses.txt + reloc_addrs_path: + - relocs/reloc_addrs.jp.txt + + asm_path: asm/jp + src_path: src + asset_path: bin/jp + + build_path: build + + extensions_path: tools/splat_ext + mips_abi_float_regs: o32 + + do_c_func_detection: True + o_as_suffix: True + gfx_ucode: f3dex2 + mnemonic_ljust: 12 + rom_address_padding: True + dump_symbols: True + generated_c_preamble: | + #include "global.h" + asm_inc_header: "" + use_legacy_include_asm: False + create_asm_dependencies: True + asm_function_macro: glabel + asm_jtbl_label_macro: jlabel + asm_data_macro: dlabel + include_macro_inc: False + libultra_symbols: True + hardware_regs: True + auto_all_sections: [] +segments: + - name: header + type: header + start: 0x0 + + - name: ipl3 + type: bin + start: 0x40 + + - name: entry + type: code + start: 0x001000 + vram: 0x80025C00 + subsegments: + - [0x1000, hasm, entry] + + - name: boot + type: code + start: 0x001060 + vram: 0x80025C60 + follows_vram: entry + bss_size: 0x5D50 + subsegments: + - [0x001060, c, boot/boot_main] + + - [0x0011F0, asm, boot/0011F0] + + - [0x0014A0, asm, boot/0014A0] + - [0x001640, asm, boot/001640] + - [0x0017F0, asm, boot/0017F0] + - [0x0022A0, asm, boot/0022A0] + - [0x002720, asm, boot/002720] + - [0x004F70, asm, boot/004F70] + - [0x0059F0, asm, boot/0059F0] + - [0x005BE0, asm, boot/005BE0] + - [0x005E30, asm, boot/005E30] + - [0x006BA0, asm, boot/006BA0] + - [0x006D10, asm, boot/006D10] + - [0x007000, asm, boot/007000] + - [0x007060, asm, boot/007060] + - [0x007530, asm, boot/007530] + - [0x007F30, asm, boot/007F30] + - [0x008C50, asm, boot/008C50] + - [0x008D20, asm, boot/008D20] + + # libultra + - [0x008F20, asm, libultra/sendmesg] # c + - [0x009070, asm, libultra/pfsfreeblocks] # c + - [0x009210, asm, libultra/stopthread] # c + - [0x0092D0, asm, libultra/flashreadid] # c + - [0x0093A0, asm, libultra/recvmesg] # c + - [0x0094E0, hasm, libultra/setintmask] + - [0x009580, hasm, libultra/getintmask] + - [0x0095E0, asm, libultra/scale] # c + - [0x009690, asm, libultra/sinf] # c + - [0x009850, asm, libultra/sins] # c + - [0x0098C0, asm, libultra/sptask] # c + - [0x009B80, asm, libultra/destroythread] # c + - [0x009C90, asm, libultra/ll] # c + - [0x009F50, hasm, libultra/exceptasm] + - [0x00A880, asm, libultra/thread] # c + - [0x00A8C0, hasm, libultra/bzero] + - [0x00A960, asm, libultra/controller] # c + - [0x00AC40, asm, boot/00AC40] + - [0x00AD00, asm, libultra/flashsectorerase] # c + - [0x00AE50, asm, libultra/createthread] # c + - [0x00AFA0, asm, libultra/contreaddata] # c + - [0x00B180, asm, libultra/virtualtophysical] # c + - [0x00B200, hasm, libultra/writebackdcache] + - [0x00B280, asm, libultra/initialize] # c + - [0x00B5D0, asm, boot/00B5D0] + - [0x00B630, hasm, libultra/setsr] + - [0x00B640, hasm, libultra/getsr] + - [0x00B650, asm, boot/00B650] + - [0x00B690, asm, libultra/perspective] # c + - [0x00B920, asm, libultra/sprawdma] # c + - [0x00B9B0, asm, libultra/sirawdma] # c + - [0x00BA60, asm, libultra/epilinkhandle] # c + - [0x00BAB0, asm, libultra/viblack] # c + - [0x00BB20, asm, boot/00BB20] + # - [0x00BB20, asm, libultra/sirawread] # ambiguous # c + # - [0x00BB20, asm, libultra/sprawread] # ambiguous # c + - [0x00BB70, asm, libultra/getthreadid] # c + - [0x00BB90, asm, libultra/sptaskyield] # c + - [0x00BBB0, asm, libultra/pfsreadwritefile] # c + - [0x00C000, asm, libultra/pfsgetstatus] # c + - [0x00C230, asm, boot/00C230] + - [0x00C240, asm, libultra/mtxidentf] # c + - [0x00C290, asm, libultra/visetmode] # c + - [0x00C2F0, asm, libultra/flashinit] # c + - [0x00C3E0, asm, libultra/lookat] # c + - [0x00C700, asm, libultra/motor] # c + - [0x00CAD0, asm, libultra/pfsallocatefile] # c + - [0x00CF50, asm, libultra/stoptimer] # c + - [0x00D040, hasm, libultra/probetlb] + - [0x00D100, asm, libultra/pimgr] # c + - [0x00D270, asm, boot/00D270] + - [0x00D340, asm, libultra/devmgr] # c + - [0x00D750, asm, libultra/pirawdma] # c + - [0x00D820, asm, libultra/contpfs] # c + - [0x00E3A0, hasm, libultra/getcount] + - [0x00E3B0, asm, boot/00E3B0] + - [0x00E3C0, asm, libultra/mtxl2f] # c + - [0x00E430, asm, libultra/flashreadstatus] # c + - [0x00E4C0, asm, libultra/getmemsize] # c + - [0x00E5E0, asm, libultra/pfssearchfile] # c + - [0x00E7B0, asm, libultra/seteventmesg] # c + - [0x00E870, hasm, libultra/sqrtf] + - [0x00E880, asm, libultra/afterprenmi] # c + - [0x00E8A0, asm, libultra/contquery] # c + - [0x00E940, asm, libultra/lookathil] # c + - [0x00F1C0, asm, libultra/xprintf] # c + - [0x00FEA0, hasm, libultra/unmaptlball] + - [0x00FEF0, asm, libultra/epidma] # c + - [0x00FF90, asm, libultra/string] # c + - [0x010030, hasm, libultra/invaldcache] + - [0x0100E0, hasm, libultra/invalicache] + - [0x010160, asm, libultra/createmesgqueue] # c + - [0x010190, asm, libultra/pfsrepairid] # c + - [0x0101F0, asm, libultra/timerintr] # c + - [0x010620, asm, libultra/sp] # c + - [0x010650, asm, libultra/si] # c + - [0x010680, asm, libultra/mtxident] # c + - [0x0106D0, asm, libultra/jammesg] # c + - [0x010820, asm, libultra/setthreadpri] # c + - [0x010900, asm, libultra/getthreadpri] # c + - [0x010920, asm, libultra/epirawread] # c + - [0x010A80, asm, libultra/viswapbuf] # c + - [0x010AD0, asm, libultra/position] # c + - [0x010CE0, asm, libultra/epirawdma] # c + - [0x010EC0, asm, libultra/sptaskyielded] # c + - [0x010F20, hasm, libultra/bcmp] + - [0x011040, asm, libultra/gettime] # c + - [0x0110D0, asm, libultra/rotate] # c + - [0x0112A0, asm, libultra/setglobalintmask] # c + - [0x0112F0, asm, libultra/aisetfreq] # c + - [0x011440, asm, boot/011440] + - [0x011460, asm, libultra/normalize] # c + - [0x0114C0, hasm, libultra/setcompare] + - [0x0114D0, asm, libultra/aigetstat] # c + - [0x0114E0, hasm, libultra/bcopy] + - [0x0117F0, asm, libultra/resetglobalintmask] # c + - [0x011850, asm, libultra/pfsdeletefile] # c + - [0x011AC0, asm, libultra/ortho] # c + - [0x011C80, asm, libultra/gbpakinit] # c + - [0x011EB0, asm, libultra/vi] # c + - [0x011FD0, asm, libultra/viswapcontext] # c + - [0x0122D0, hasm, libultra/interrupt] + - [0x012360, asm, libultra/pigetcmdq] # c + - [0x012390, asm, libultra/cosf] # c + - [0x012500, asm, boot/012500] + - [0x012550, asm, libultra/visetspecial] # c + - [0x0126B0, asm, libultra/coss] # c + - [0x0126E0, asm, libultra/flashwritearray] # c + - [0x012840, asm, libultra/flashallerase] # c + - [0x012980, asm, libultra/flashclearstatus] # c + - [0x0129D0, asm, libultra/visetevent] # c + - [0x012A30, asm, libultra/pfsisplug] # c + - [0x012D20, asm, libultra/flashwritebuffer] # c + - [0x012DB0, asm, libultra/pfsnumfiles] # c + - [0x012EE0, asm, libultra/cartrominit] # c + - [0x013040, asm, libultra/us2dex] # c + - [0x0131C0, asm, libultra/pfsselectbank] # c + - [0x013240, asm, libultra/contsetch] # c + - [0x0132A0, hasm, libultra/setfpccsr] + - [0x0132B0, hasm, libultra/getfpccsr] + - [0x0132C0, asm, libultra/pfsfilestate] # c + - [0x0134A0, asm, libultra/pfsinitpak] # c + - [0x0137B0, asm, libultra/pfschecker] # c + - [0x014160, asm, libultra/aigetlen] # c + - [0x014170, asm, boot/014170] + - [0x0141C0, hasm, libultra/maptlbrdb] + - [0x014220, asm, libultra/yieldthread] # c + - [0x014270, asm, boot/014270] + - [0x014280, asm, libultra/translate] # c + - [0x014350, hasm, libultra/getcause] + - [0x014360, asm, libultra/contramwrite] # c + - [0x0145B0, asm, libultra/contramread] # c + - [0x0147E0, asm, libultra/crc] # c + - [0x014950, asm, libultra/epirawwrite] # c + - [0x014AB0, asm, libultra/settimer] # c + - [0x014C40, asm, libultra/xldtob] # c + - [0x015750, asm, libultra/ldiv] # c + - [0x0158E0, asm, libultra/xlitob] # c + - [0x015B80, asm, boot/015B80] + # - [0x015B80, asm, libultra/sirawwrite] # ambiguous # c + # - [0x015B80, asm, libultra/sprawwrite] # ambiguous # c + - [0x015BD0, asm, libultra/spsetstat] # c + - [0x015BE0, asm, libultra/spgetstat] # c + - [0x015BF0, asm, boot/015BF0] + - [0x015C00, asm, libultra/vimgr] # c + - [0x015F10, asm, boot/015F10] + - [0x015F20, hasm, libultra/writebackdcacheall] + - [0x015F50, asm, boot/015F50] + - [0x015F60, asm, libultra/mtxf2l] # c + - [0x015FD0, asm, libultra/startthread] # c + - [0x016120, asm, libultra/llcvt] # c + - [0x016330, asm, libultra/visetyscale] # c + - [0x016380, asm, libultra/visetxscale] # c + - [0x016490, asm, libultra/conteepread] # c + - [0x0166F0, asm, libultra/conteepwrite] # c + - [0x016B10, asm, boot/016B10] + - [0x016B50, asm, libultra/spsetpc] # c + - [0x016B80, asm, libultra/flashreadarray] # c + - [0x016D20, asm, libultra/flashgetaddr] # c + - [0x016D50, hasm, libultra/setwatchlo] + + - [0x016D60, asm, boot/016D60] + + - [0x016DB0, asm, boot/016DB0] + - [0x016DE0, asm, boot/016DE0] + - [0x016E20, asm, boot/016E20] + - [0x016E60, asm, boot/016E60] + + - [0x016EF0, data, libultra/rsp/rspboot] + + - [0x016FC0, data, boot/016FC0] + + - [0x018580, rodata, boot/018580] + + - [0x0185B0, rodata, boot/0185B0] + - [0x0187F0, rodata, boot/0187F0] + - [0x018840, rodata, boot/018840] + - [0x019250, rodata, boot/019250] + - [0x019690, rodata, boot/019690] + - [0x0196B0, rodata, boot/0196B0] + - [0x0196C0, rodata, boot/0196C0] + - [0x019710, rodata, boot/019710] + - [0x0199D0, rodata, boot/0199D0] + - [0x019AA0, rodata, boot/019AA0] + - [0x019AF0, rodata, boot/019AF0] + - [0x019B00, rodata, boot/019B00] + - [0x019B30, rodata, boot/019B30] + - [0x019C30, rodata, boot/019C30] + - [0x019C80, rodata, boot/019C80] + - [0x019C90, rodata, boot/019C90] + - [0x019CF0, rodata, boot/019CF0] + + - { start: 0x019D40, type: bss, vram: 0x8003E940, name: boot/8003E940 } + + - name: dmadata + type: bin + start: 0x019D40 + vram: 0x80044690 + follows_vram: boot + + - type: bin + start: 0x027130 + + - name: code + type: code + start: 0x675720 + vram: 0x80051A80 + # follows_vram: entry + bss_size: 0x36C90 + subsegments: + - [0x675720, asm, code/675720] + - [0x678660, asm, code/678660] + - [0x6792F0, asm, code/6792F0] + - [0x67C6B0, asm, code/67C6B0] + - [0x67D890, asm, code/67D890] + - [0x67E840, asm, code/67E840] + - [0x683030, asm, code/683030] + - [0x688CE0, asm, code/688CE0] + - [0x68AAF0, asm, code/68AAF0] + - [0x68AB30, asm, code/68AB30] + - [0x68B0D0, asm, code/68B0D0] + - [0x69A7E0, asm, code/69A7E0] + - [0x69C6B0, asm, code/69C6B0] + - [0x69C770, asm, code/69C770] + - [0x69E2C0, asm, code/69E2C0] + - [0x6A0DE0, asm, code/6A0DE0] + - [0x6A5B00, asm, code/6A5B00] + - [0x6A6C40, asm, code/6A6C40] + - [0x6A6E80, asm, code/6A6E80] + - [0x6A7D20, asm, code/6A7D20] + - [0x6A8180, asm, code/6A8180] + - [0x6A83A0, asm, code/6A83A0] + - [0x6A8B70, asm, code/6A8B70] + - [0x6AB8D0, asm, code/6AB8D0] + - [0x6B3DC0, asm, code/6B3DC0] + - [0x6B6560, asm, code/6B6560] + - [0x6B81C0, asm, code/6B81C0] + - [0x6B8A70, asm, code/6B8A70] + - [0x6B8F20, asm, code/6B8F20] + - [0x6BA3B0, asm, code/6BA3B0] + - [0x6BA500, asm, code/6BA500] + - [0x6BD560, asm, code/6BD560] + - [0x6BEE80, asm, code/6BEE80] + - [0x6C05A0, asm, code/6C05A0] + - [0x6C0690, asm, code/6C0690] + - [0x6C0E90, asm, code/6C0E90] + - [0x6C92D0, asm, code/6C92D0] + - [0x6C97F0, asm, code/6C97F0] + - [0x6CA4B0, asm, code/6CA4B0] + - [0x6D2720, asm, code/6D2720] + - [0x6D4440, asm, code/6D4440] + - [0x6D44F0, asm, code/6D44F0] + - [0x6D4C60, asm, code/6D4C60] + - [0x6D9D80, asm, code/6D9D80] + - [0x6DA460, asm, code/6DA460] + - [0x6DB420, asm, code/6DB420] + - [0x6DE300, asm, code/6DE300] + - [0x6E0F50, asm, code/6E0F50] + - [0x6E2300, asm, code/6E2300] + - [0x6E30B0, asm, code/6E30B0] + - [0x6E7AD0, asm, code/6E7AD0] + - [0x6E80C0, asm, code/6E80C0] + - [0x6E9650, asm, code/6E9650] + - [0x6EAB20, asm, code/6EAB20] + - [0x6EC430, asm, code/6EC430] + - [0x6EC9E0, asm, code/6EC9E0] + - [0x6ECD90, asm, code/6ECD90] + - [0x6EDD10, asm, code/6EDD10] + - [0x6EE540, asm, code/6EE540] + - [0x6EFC20, asm, code/6EFC20] + - [0x6F12E0, asm, code/6F12E0] + - [0x6F2150, asm, code/6F2150] + - [0x6F5180, asm, code/6F5180] + - [0x6F5390, asm, code/6F5390] + - [0x6F5550, asm, code/6F5550] + - [0x6F6230, asm, code/6F6230] + - [0x6F68B0, asm, code/6F68B0] + - [0x6F6AA0, asm, code/6F6AA0] + - [0x6F73C0, asm, code/6F73C0] + - [0x6F7500, asm, code/6F7500] + - [0x6F7580, asm, code/6F7580] + - [0x6F8A60, asm, code/6F8A60] + - [0x6F9B10, asm, code/6F9B10] + - [0x6FA030, asm, code/6FA030] + - [0x6FA180, asm, code/6FA180] + - [0x6FA6B0, asm, code/6FA6B0] + - [0x6FB340, asm, code/6FB340] + - [0x6FC540, asm, code/6FC540] + - [0x6FD190, asm, code/6FD190] + - [0x6FD530, asm, code/6FD530] + - [0x6FD840, asm, code/6FD840] + - [0x703E70, asm, code/703E70] + - [0x706580, asm, code/706580] + - [0x7065F0, asm, code/7065F0] + - [0x7069C0, asm, code/7069C0] + - [0x70DC90, asm, code/70DC90] + - [0x711CC0, asm, code/711CC0] + - [0x713B90, asm, code/713B90] + - [0x7165D0, asm, code/7165D0] + - [0x71A100, asm, code/71A100] + - [0x71A140, asm, code/71A140] + - [0x71FA20, asm, code/71FA20] + - [0x7205C0, asm, code/7205C0] + - [0x7206E0, asm, code/7206E0] + - [0x720B20, asm, code/720B20] + - [0x720F70, asm, code/720F70] + - [0x721EC0, asm, code/721EC0] + - [0x7220C0, asm, code/7220C0] + - [0x722310, asm, code/722310] + - [0x722570, asm, code/722570] + - [0x722880, asm, code/722880] + - [0x722970, asm, code/722970] + - [0x722AB0, asm, code/722AB0] + - [0x723010, asm, code/723010] + + - [0x7248D0, data, code/7248D0] + + - [0x739DB0, rodata, code/739DB0] + - [0x739E00, rodata, code/739E00] + - [0x739E50, rodata, code/739E50] + - [0x739E90, rodata, code/739E90] + - [0x739EA0, rodata, code/739EA0] + - [0x739F20, rodata, code/739F20] + - [0x739F70, rodata, code/739F70] + - [0x73A080, rodata, code/73A080] + - [0x73A0F0, rodata, code/73A0F0] + - [0x73A110, rodata, code/73A110] + - [0x73A480, rodata, code/73A480] + - [0x73A4A0, rodata, code/73A4A0] + - [0x73A4D0, rodata, code/73A4D0] + - [0x73A6A0, rodata, code/73A6A0] + - [0x73A730, rodata, code/73A730] + - [0x73A9B0, rodata, code/73A9B0] + - [0x73A9C0, rodata, code/73A9C0] + - [0x73A9D0, rodata, code/73A9D0] + - [0x73A9E0, rodata, code/73A9E0] + - [0x73AA10, rodata, code/73AA10] + - [0x73AAE0, rodata, code/73AAE0] + - [0x73ABB0, rodata, code/73ABB0] + - [0x73ABD0, rodata, code/73ABD0] + - [0x73AC50, rodata, code/73AC50] + - [0x73AC60, rodata, code/73AC60] + - [0x73AD50, rodata, code/73AD50] + - [0x73AD70, rodata, code/73AD70] + - [0x73AD90, rodata, code/73AD90] + - [0x73AEE0, rodata, code/73AEE0] + - [0x73AEF0, rodata, code/73AEF0] + - [0x73AF40, rodata, code/73AF40] + - [0x73AF50, rodata, code/73AF50] + - [0x73B000, rodata, code/73B000] + - [0x73B020, rodata, code/73B020] + - [0x73B0F0, rodata, code/73B0F0] + - [0x73B130, rodata, code/73B130] + - [0x73B210, rodata, code/73B210] + - [0x73B250, rodata, code/73B250] + - [0x73B360, rodata, code/73B360] + - [0x73B3E0, rodata, code/73B3E0] + - [0x73B400, rodata, code/73B400] + - [0x73B580, rodata, code/73B580] + - [0x73B6D0, rodata, code/73B6D0] + - [0x73B710, rodata, code/73B710] + - [0x73B720, rodata, code/73B720] + - [0x73B740, rodata, code/73B740] + - [0x73B780, rodata, code/73B780] + - [0x73B7D0, rodata, code/73B7D0] + - [0x73B7E0, rodata, code/73B7E0] + - [0x73B830, rodata, code/73B830] + - [0x73B880, rodata, code/73B880] + - [0x73B890, rodata, code/73B890] + - [0x73B920, rodata, code/73B920] + - [0x73B960, rodata, code/73B960] + - [0x73B980, rodata, code/73B980] + - [0x73B9C0, rodata, code/73B9C0] + - [0x73BA50, rodata, code/73BA50] + - [0x73BA70, rodata, code/73BA70] + - [0x73BB10, rodata, code/73BB10] + - [0x73BCA0, rodata, code/73BCA0] + - [0x73BD20, rodata, code/73BD20] + - [0x73BD30, rodata, code/73BD30] + - [0x73BD50, rodata, code/73BD50] + - [0x73BD70, rodata, code/73BD70] + - [0x73BE00, rodata, code/73BE00] + - [0x73BE10, rodata, code/73BE10] + - [0x73BE40, rodata, code/73BE40] + - [0x73BE70, rodata, code/73BE70] + - [0x73BEA0, rodata, code/73BEA0] + - [0x73BEF0, rodata, code/73BEF0] + - [0x73BF60, rodata, code/73BF60] + - [0x73C0B0, rodata, code/73C0B0] + - [0x73C0D0, rodata, code/73C0D0] + - [0x73C120, rodata, code/73C120] + - [0x73C7C0, rodata, code/73C7C0] + - [0x73CEE0, rodata, code/73CEE0] + + - { start: 0x73F4D0, type: bss, vram: 0x8011B830, name: code/73F4D0 } + + - type: bin + start: 0x73F4D0 + + - [0x1914000] diff --git a/animalforest_uncompressed.jp.md5 b/animalforest_uncompressed.jp.md5 new file mode 100644 index 00000000..71dc81ff --- /dev/null +++ b/animalforest_uncompressed.jp.md5 @@ -0,0 +1 @@ +d7ae64f2f47a9fa3f87686a3c5ce09af build/animalforest_uncompressed.jp.z64 diff --git a/diff.py b/diff.py new file mode 120000 index 00000000..9f7d52b4 --- /dev/null +++ b/diff.py @@ -0,0 +1 @@ +tools/asm-differ/diff.py \ No newline at end of file diff --git a/diff_settings.py b/diff_settings.py new file mode 100644 index 00000000..df89baff --- /dev/null +++ b/diff_settings.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +from pathlib import Path + +def apply(config, args): + version = "jp" + + make_options = Path(".make_options") + if make_options.exists(): + with make_options.open() as f: + for line in f: + if "VERSION" in line and "=" in line: + version = line.split("=")[1].strip() + + config["baseimg"] = f"expected/build/animalforest_uncompressed.{version}.z64" + config["myimg"] = f"build/animalforest_uncompressed.{version}.z64" + config["mapfile"] = f"build/animalforest.{version}.map" + config["source_directories"] = ["./src", "./include", "./asm"] + config["objdump_flags"] = ["-Mreg-names=32"] + # config["objdump_flags"].append("-Mno-aliases") + config["makeflags"] = ["KEEP_MDEBUG=1", "WERROR=0", f"VERSION={version}"] diff --git a/include/alignment.h b/include/alignment.h new file mode 100644 index 00000000..9fb3b572 --- /dev/null +++ b/include/alignment.h @@ -0,0 +1,33 @@ +#ifndef ALIGNMENT_H +#define ALIGNMENT_H + +#include "attributes.h" + +#define ALIGN4(val) (((val) + 3) & ~3) +#define ALIGN8(val) (((val) + 7) & ~7) +#define ALIGN16(val) (((val) + 0xF) & ~0xF) +#define ALIGN32(val) (((val) + 0x1F) & ~0x1F) +#define ALIGN64(val) (((val) + 0x3F) & ~0x3F) +#define ALIGN128(val) (((val) + 0x7F) & ~0x7F) +#define ALIGN256(val) (((val) + 0xFF) & ~0xFF) + + +#ifndef ALIGNED8 +#define ALIGNED8 __attribute__ ((aligned (8))) +#endif + +#ifndef ALIGNOF +#ifdef __sgi /* IDO compiler */ +#define ALIGNOF(x) __builtin_alignof(x) +#elif (__STDC_VERSION__ >= 201112L) /* C11 */ +#define ALIGNOF(x) _Alignof(x) +#else /* __GNUC__ */ +#define ALIGNOF(x) __alignof__(x) +#endif +#endif + +#define ALIGN_MASK(n) (~((n) - 1)) + +#define ALIGNOF_MASK(x) ALIGN_MASK(ALIGNOF(x)) + +#endif diff --git a/include/attributes.h b/include/attributes.h new file mode 100644 index 00000000..c2045faa --- /dev/null +++ b/include/attributes.h @@ -0,0 +1,39 @@ +#ifndef ATTRIBUTES_H +#define ATTRIBUTES_H + + +#if (!defined(__GNUC__) && !defined(__clang__)) || defined(M2CTX) || defined(__sgi) + #ifndef __attribute__ + #define __attribute__(x) + #endif +#endif + + +#ifndef FALLTHROUGH + #if __STDC_VERSION__ >= 202000L + #define FALLTHROUGH [[fallthrough]] + #else + #define FALLTHROUGH __attribute__((fallthrough)) + #endif +#endif + +#ifndef NORETURN + #if __STDC_VERSION__ >= 202000L + #define NORETURN [[noreturn]] + #elif __STDC_VERSION__ >= 201112L + #define NORETURN _Noreturn + #else + #define NORETURN __attribute__((noreturn)) + #endif +#endif + +#ifndef UNUSED + #if __STDC_VERSION__ >= 202000L + #define UNUSED [[maybe_unused]] + #else + #define UNUSED __attribute__((unused)) + #endif +#endif + + +#endif diff --git a/include/global.h b/include/global.h new file mode 100644 index 00000000..6d84d8a8 --- /dev/null +++ b/include/global.h @@ -0,0 +1,19 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#include "ultra64.h" + +#include "libc/assert.h" +#include "libc/stdbool.h" +#include "libc/stddef.h" +#include "libc/stdint.h" + +#include "attributes.h" +#include "alignment.h" +#include "other_types.h" +#include "unk.h" +#include "unknown_structs.h" + +#include "macros.h" + +#endif diff --git a/include/libc/assert.h b/include/libc/assert.h new file mode 100644 index 00000000..a9ecef0e --- /dev/null +++ b/include/libc/assert.h @@ -0,0 +1,23 @@ +#ifndef LIBC_ASSERT_H +#define LIBC_ASSERT_H + +// Runtime assertions + +// TODO + +// Static/compile-time assertions + +#if __STDC_VERSION__ >= 201112L +# define static_assert(cond, msg) _Static_assert(cond, msg) +#else +# ifndef GLUE +# define GLUE(a, b) a##b +# endif +# ifndef GLUE2 +# define GLUE2(a, b) GLUE(a, b) +# endif + +# define static_assert(cond, msg) typedef char GLUE2(static_assertion_failed, __LINE__)[(cond) ? 1 : -1] +#endif + +#endif diff --git a/include/libc/stdbool.h b/include/libc/stdbool.h new file mode 100644 index 00000000..d3f951bd --- /dev/null +++ b/include/libc/stdbool.h @@ -0,0 +1,30 @@ +#ifndef LIBC_STDBOOL_H +#define LIBC_STDBOOL_H + +#ifndef __bool_true_false_are_defined +#define __bool_true_false_are_defined 1 +#endif + +#ifndef __cplusplus + +#if (__STDC_VERSION__ >= 199901L) && !defined(PERMUTER) +#define bool _Bool +#define false 0 +#define true 1 +#elif CC_CHECK +// A way to enforce bools to not be treated the same as s32 by the host compiler +// This has to be an ifdef because an enum-return-type doesn't match on `return (thing1) && (thing2);` patterns +typedef enum bool { + false, + true +} bool; +#else +typedef int bool; + +#define false 0 +#define true 1 +#endif + +#endif /* __cplusplus */ + +#endif /* STDBOOL */ diff --git a/include/libc/stddef.h b/include/libc/stddef.h new file mode 100644 index 00000000..8a48f559 --- /dev/null +++ b/include/libc/stddef.h @@ -0,0 +1,25 @@ +#ifndef LIBC_STDDEF_H +#define LIBC_STDDEF_H + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef _PTRDIFF_T + #define _PTRDIFF_T + #if (_MIPS_SZLONG == 32) + typedef int ptrdiff_t; + #else + typedef long ptrdiff_t; + #endif +#endif + +#ifndef offsetof +#ifdef __GNUC__ +#define offsetof(structure, member) __builtin_offsetof(structure, member) +#else +#define offsetof(structure, member) ((size_t)&(((structure*)0)->member)) +#endif +#endif + +#endif diff --git a/include/libc/stdint.h b/include/libc/stdint.h new file mode 100644 index 00000000..854fd254 --- /dev/null +++ b/include/libc/stdint.h @@ -0,0 +1,29 @@ +#ifndef LIBC_STDINT_H +#define LIBC_STDINT_H + +#include "PR/ultratypes.h" + +typedef s32 intptr_t; +typedef u32 uintptr_t; + +#define INT8_MIN (-0x80) +#define INT16_MIN (-0x8000) +#define INT32_MIN (-0x80000000) +#define INT64_MIN (-0x8000000000000000) + +#define INT8_MAX 0x7F +#define INT16_MAX 0x7FFF +#define INT32_MAX 0x7FFFFFFF +#define INT64_MAX 0x7FFFFFFFFFFFFFFF + +#define UINT8_MAX 0xFF +#define UINT16_MAX 0xFFFF +#define UINT32_MAX 0xFFFFFFFF +#define UINT64_MAX 0xFFFFFFFFFFFFFFFF + +#define INTPTR_MIN (-0x80000000) +#define INTPTR_MAX 0x7FFFFFFF +#define UINTPTR_MAX 0xFFFFFFFF + + +#endif /* STDINT_H */ diff --git a/include/macro.inc b/include/macro.inc new file mode 100644 index 00000000..1ee4aa4f --- /dev/null +++ b/include/macro.inc @@ -0,0 +1,87 @@ +.macro glabel label + .global \label + .type \label, @function + \label: +.endm + +.macro dlabel label + .global \label + \label: +.endm + +.macro jlabel label + .global \label + .type \label, @function + \label: +.endm + +# COP0 register aliases + +.set Index, $0 +.set Random, $1 +.set EntryLo0, $2 +.set EntryLo1, $3 +.set Context, $4 +.set PageMask, $5 +.set Wired, $6 +.set Reserved07, $7 +.set BadVaddr, $8 +.set Count, $9 +.set EntryHi, $10 +.set Compare, $11 +.set Status, $12 +.set Cause, $13 +.set EPC, $14 +.set PRevID, $15 +.set Config, $16 +.set LLAddr, $17 +.set WatchLo, $18 +.set WatchHi, $19 +.set XContext, $20 +.set Reserved21, $21 +.set Reserved22, $22 +.set Reserved23, $23 +.set Reserved24, $24 +.set Reserved25, $25 +.set PErr, $26 +.set CacheErr, $27 +.set TagLo, $28 +.set TagHi, $29 +.set ErrorEPC, $30 +.set Reserved31, $31 + + +# Float register aliases (o32 ABI, odd ones are rarely used) + +.set $fv0, $f0 +.set $fv0f, $f1 +.set $fv1, $f2 +.set $fv1f, $f3 +.set $ft0, $f4 +.set $ft0f, $f5 +.set $ft1, $f6 +.set $ft1f, $f7 +.set $ft2, $f8 +.set $ft2f, $f9 +.set $ft3, $f10 +.set $ft3f, $f11 +.set $fa0, $f12 +.set $fa0f, $f13 +.set $fa1, $f14 +.set $fa1f, $f15 +.set $ft4, $f16 +.set $ft4f, $f17 +.set $ft5, $f18 +.set $ft5f, $f19 +.set $fs0, $f20 +.set $fs0f, $f21 +.set $fs1, $f22 +.set $fs1f, $f23 +.set $fs2, $f24 +.set $fs2f, $f25 +.set $fs3, $f26 +.set $fs3f, $f27 +.set $fs4, $f28 +.set $fs4f, $f29 +.set $fs5, $f30 +.set $fs5f, $f31 diff --git a/include/macros.h b/include/macros.h new file mode 100644 index 00000000..53755ada --- /dev/null +++ b/include/macros.h @@ -0,0 +1,18 @@ +#ifndef MACROS_H +#define MACROS_H + +#if defined(__GNUC__) || defined(__clang__) +# define UNREACHABLE __builtin_unreachable() +#else +# define UNREACHABLE +#endif + +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 240 + + +#define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0])) +#define ARRAY_COUNTU(arr) (u32)(sizeof(arr) / sizeof(arr[0])) + + +#endif diff --git a/include/other_types.h b/include/other_types.h new file mode 100644 index 00000000..f699ccbd --- /dev/null +++ b/include/other_types.h @@ -0,0 +1,11 @@ +#ifndef OTHER_TYPES_H +#define OTHER_TYPES_H + +#include "ultra64.h" + +// Header for files that are well known, but don't have a proper header home yet + +typedef u32 romoffset_t; +typedef void* TexturePtr; + +#endif diff --git a/include/segment_symbols.h b/include/segment_symbols.h new file mode 100644 index 00000000..e2950c03 --- /dev/null +++ b/include/segment_symbols.h @@ -0,0 +1,66 @@ +#ifndef SEGMENT_SYMBOLS_H +#define SEGMENT_SYMBOLS_H + +#include "ultra64.h" +#include "libc/stdint.h" +#include "other_types.h" + + +#define DECLARE_VRAM_SEGMENT(name) \ + extern u32 name ## _VRAM[]; \ + extern u32 name ## _VRAM_END[] + +#define DECLARE_ROM_SEGMENT(name) \ + extern u32 name ## _ROM_START[]; \ + extern u32 name ## _ROM_END[] + +#define DECLARE_DATA_SEGMENT(name) \ + extern u32 name ## _DATA_START[]; \ + extern u32 name ## _DATA_END[]; \ + extern u32 name ## _DATA_SIZE[] + +#define DECLARE_BSS_SEGMENT(name) \ + extern u32 name ## _BSS_START[]; \ + extern u32 name ## _BSS_END[] + +#define DECLARE_SEGMENT(name) \ + DECLARE_VRAM_SEGMENT(name); \ + DECLARE_ROM_SEGMENT(name); \ + DECLARE_DATA_SEGMENT(name); \ + DECLARE_BSS_SEGMENT(name) + +#define SEGMENT_VRAM_START(segment) (segment ## _VRAM) +#define SEGMENT_VRAM_END(segment) (segment ## _VRAM_END) +#define SEGMENT_VRAM_SIZE(segment) ((uintptr_t)SEGMENT_VRAM_END(segment) - (uintptr_t)SEGMENT_VRAM_START(segment)) + +#define SEGMENT_ROM_START(segment) ((romoffset_t)segment ## _ROM_START) +#define SEGMENT_ROM_END(segment) ((romoffset_t)segment ## _ROM_END) +#define SEGMENT_ROM_SIZE(segment) (SEGMENT_ROM_END(segment) - SEGMENT_ROM_START(segment)) + +#define SEGMENT_DATA_SIZE_CONST(segment) ((romoffset_t)segment ## _DATA_SIZE) + +#define SEGMENT_BSS_START(segment) (segment ## _BSS_START) +#define SEGMENT_BSS_END(segment) (segment ## _BSS_END) +#define SEGMENT_BSS_SIZE(segment) ((uintptr_t)SEGMENT_BSS_END(segment) - (uintptr_t)SEGMENT_BSS_START(segment)) + + +DECLARE_SEGMENT(header); + +DECLARE_SEGMENT(ipl3); + +DECLARE_SEGMENT(entry); + +DECLARE_SEGMENT(boot); + +DECLARE_SEGMENT(dmadata); + +// DECLARE_SEGMENT(); + +DECLARE_SEGMENT(code); + + +// TODO: the rest of segments + + + +#endif diff --git a/include/stack.h b/include/stack.h new file mode 100644 index 00000000..eb127f32 --- /dev/null +++ b/include/stack.h @@ -0,0 +1,14 @@ +#ifndef STACK_H +#define STACK_H + +#include "alignment.h" +#include "ultra64.h" + + +#define STACK(stack, size) \ + u64 stack[ALIGN8(size) / sizeof(u64)] + +#define STACK_TOP(stack) \ + ((u64*)((u8*)(stack) + sizeof(stack))) + +#endif diff --git a/include/unk.h b/include/unk.h new file mode 100644 index 00000000..c65730e4 --- /dev/null +++ b/include/unk.h @@ -0,0 +1,19 @@ +#ifndef UNK_H +#define UNK_H + +#include "ultra64.h" + +#define UNK_TYPE s32 +#define UNK_TYPE1 s8 +#define UNK_TYPE2 s16 +#define UNK_TYPE4 s32 +#define UNK_TYPE8 s64 +#define UNK_PTR void* +#define UNK_RET UNK_TYPE +#define UNK_ARGS +#define UNK_FUN_ARG void(*)(void) +//#define UNK_FUN_PTR(name) void(*name)(void) +typedef UNK_RET (*UNK_FUN_PTR)(UNK_ARGS); +#define UNK_SIZE 1 + +#endif diff --git a/include/unknown_structs.h b/include/unknown_structs.h new file mode 100644 index 00000000..a10218f1 --- /dev/null +++ b/include/unknown_structs.h @@ -0,0 +1,10 @@ +#ifndef UNKNOWN_STRUCTS_H +#define UNKNOWN_STRUCTS_H + +#include "ultra64.h" +#include "libc/stdint.h" +#include "libc/stdbool.h" +#include "unk.h" + + +#endif diff --git a/lib/ultralib/.github/workflows/ci_egcs.txt b/lib/ultralib/.github/workflows/ci_egcs.txt new file mode 100644 index 00000000..f903a0a5 --- /dev/null +++ b/lib/ultralib/.github/workflows/ci_egcs.txt @@ -0,0 +1,42 @@ +# CI file for EGCS builds +# TODO: rename to `ci_egcs.yml` when the repo has EGCS / iQue support + +name: Build EGCS libultra + +# Build on every branch push, tag push, and pull request change: +on: [push, pull_request_target] + +jobs: + build_repo: + name: Build repo + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + version: [ique_v1.5] + suffix: [_rom] # [, _d, _rom] + + steps: + - name: Checkout reposistory + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Install package requirements + run: sudo apt-get install -y build-essential python3 + + - name: Get extra dependencies + uses: actions/checkout@v3 + with: + repository: ${{ secrets.SECRETREPO }} + token: ${{ secrets.SECRETTOKEN }} + path: deps_repo + - name: Get the dependency + run: cp deps_repo/libultra/${{ matrix.version }}/* . + + - name: Setup + run: make setup -j $(nproc) TARGET=libultra${{ matrix.suffix }} VERSION=${{ matrix.version }} + + - name: Build libultra${{ matrix.suffix }} ${{ matrix.version }} + run: make -j $(nproc) TARGET=libultra${{ matrix.suffix }} VERSION=${{ matrix.version }} diff --git a/lib/ultralib/.github/workflows/ci_gcc.yml b/lib/ultralib/.github/workflows/ci_gcc.yml new file mode 100644 index 00000000..1ea1413c --- /dev/null +++ b/lib/ultralib/.github/workflows/ci_gcc.yml @@ -0,0 +1,41 @@ +# CI file for GCC/KMC builds + +name: Build GCC libgultra + +# Build on every branch push, tag push, and pull request change: +on: [push, pull_request_target] + +jobs: + build_repo: + name: Build repo + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + version: [L] # [H, I, I_patch, J, K, L] + suffix: [_rom] # [, _d, _rom] + + steps: + - name: Checkout reposistory + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Install package requirements + run: sudo apt-get install -y build-essential python3 + + - name: Get extra dependencies + uses: actions/checkout@v3 + with: + repository: ${{ secrets.SECRETREPO }} + token: ${{ secrets.SECRETTOKEN }} + path: deps_repo + - name: Get the dependency + run: cp deps_repo/libultra/${{ matrix.version }}/* . + + - name: Setup + run: make setup -j $(nproc) TARGET=libgultra${{ matrix.suffix }} VERSION=${{ matrix.version }} + + - name: Build libgultra${{ matrix.suffix }} ${{ matrix.version }} + run: make -j $(nproc) TARGET=libgultra${{ matrix.suffix }} VERSION=${{ matrix.version }} diff --git a/lib/ultralib/.github/workflows/ci_ido.txt b/lib/ultralib/.github/workflows/ci_ido.txt new file mode 100644 index 00000000..36896a93 --- /dev/null +++ b/lib/ultralib/.github/workflows/ci_ido.txt @@ -0,0 +1,42 @@ +# CI file for IDO builds +# TODO: rename to `ci_ido.yml` when the repo has IDO support + +name: Build IDO libultra + +# Build on every branch push, tag push, and pull request change: +on: [push, pull_request_target] + +jobs: + build_repo: + name: Build repo + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + version: [L] # [E, F, G, H, I, I_patch, J, K, L] + suffix: [_rom] # [, _d, _rom] + + steps: + - name: Checkout reposistory + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Install package requirements + run: sudo apt-get install -y build-essential python3 + + - name: Get extra dependencies + uses: actions/checkout@v3 + with: + repository: ${{ secrets.SECRETREPO }} + token: ${{ secrets.SECRETTOKEN }} + path: deps_repo + - name: Get the dependency + run: cp deps_repo/libultra/${{ matrix.version }}/* . + + - name: Setup + run: make setup -j $(nproc) TARGET=libultra${{ matrix.suffix }} VERSION=${{ matrix.version }} + + - name: Build libultra${{ matrix.suffix }} ${{ matrix.version }} + run: make -j $(nproc) TARGET=libultra${{ matrix.suffix }} VERSION=${{ matrix.version }} diff --git a/lib/ultralib/.gitignore b/lib/ultralib/.gitignore new file mode 100644 index 00000000..669011d4 --- /dev/null +++ b/lib/ultralib/.gitignore @@ -0,0 +1,25 @@ +# Cache files +__pycache__/ +.pyc +.DS_Store + +# Text editor remnants +.vscode/ +.vs/ +.idea/ +CMakeLists.txt +cmake-build-debug +venv/ + +# Project-specific ignores +base_*/ +build/ +expected/ +notes/ +tools/gcc +*.elf +*.o +*.a + +# Tool artifacts +ctx.c diff --git a/lib/ultralib/.gitrepo b/lib/ultralib/.gitrepo new file mode 100644 index 00000000..8f49f289 --- /dev/null +++ b/lib/ultralib/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:decompals/ultralib.git + branch = main + commit = d03b2a3afbec0baabc2263b8e9087f50d22ef85c + parent = cbdbee54db4b971b070d3c78ec1361849150040d + method = merge + cmdver = 0.4.3 diff --git a/lib/ultralib/Makefile b/lib/ultralib/Makefile new file mode 100644 index 00000000..37006411 --- /dev/null +++ b/lib/ultralib/Makefile @@ -0,0 +1,161 @@ +NON_MATCHING ?= 0 + +TARGET := libgultra_rom +BASE_DIR := base_$(TARGET) +BASE_AR := $(TARGET).a +BUILD_DIR := build +BUILD_AR := $(BUILD_DIR)/$(TARGET).a + +WORKING_DIR := $(shell pwd) + +CPP := cpp -P +AR := ar +AS := tools/gcc/as +CC := tools/gcc/gcc +AR_OLD := tools/gcc/ar + +export COMPILER_PATH := $(WORKING_DIR)/tools/gcc + +CFLAGS := -w -nostdinc -c -G 0 -mgp32 -mfp32 -mips3 -D_LANGUAGE_C +ASFLAGS := -w -nostdinc -c -G 0 -mgp32 -mfp32 -mips3 -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_MIPS_SIM=1 -D_ULTRA64 -x assembler-with-cpp +GBIDEFINE := -DF3DEX_GBI_2 +CPPFLAGS = -D_MIPS_SZLONG=32 -D__USE_ISOC99 -I $(WORKING_DIR)/include -I $(WORKING_DIR)/include/gcc -I $(WORKING_DIR)/include/PR $(GBIDEFINE) + +ifeq ($(findstring _d,$(TARGET)),_d) +CPPFLAGS += -D_DEBUG +OPTFLAGS := -O0 +else +CPPFLAGS += -DNDEBUG -D_FINALROM +OPTFLAGS := -O3 +endif + +SRC_DIRS := $(shell find src -type d) +ASM_DIRS := $(shell find asm -type d -not -path "asm/non_matchings*") +C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) +S_FILES := $(foreach dir,$(SRC_DIRS) $(ASM_DIRS),$(wildcard $(dir)/*.s)) +O_FILES := $(foreach f,$(S_FILES:.s=.o),$(BUILD_DIR)/$f) \ + $(foreach f,$(C_FILES:.c=.o),$(BUILD_DIR)/$f) \ + $(foreach f,$(wildcard $(BASE_DIR)/*),$(BUILD_DIR)/$f) +# Because we patch the object file timestamps, we can't use them as the targets since they'll always be older than the C file +# Therefore instead we use marker files that have actual timestamps as the dependencies for the archive +MARKER_FILES := $(O_FILES:.o=.marker) + +ifneq ($(NON_MATCHING),1) +COMPARE_OBJ = cmp $(BASE_DIR)/$(@F:.marker=.o) $(@:.marker=.o) && echo "$(@:.marker=.o): OK" +COMPARE_AR = cmp $(BASE_AR) $@ && echo "$@: OK" +else +COMPARE_OBJ := +COMPARE_AR := +AR_OLD := $(AR) +endif + +BASE_OBJS := $(wildcard $(BASE_DIR)/*.o) +# Try to find a file corresponding to an archive file in any of src/ asm/ or the base directory, prioritizing src then asm then the original file +AR_ORDER = $(foreach f,$(shell $(AR) t $(BASE_AR)),$(shell find $(BUILD_DIR)/src $(BUILD_DIR)/asm $(BUILD_DIR)/$(BASE_DIR) -name $f -type f -print -quit)) +MATCHED_OBJS = $(filter-out $(BUILD_DIR)/$(BASE_DIR)/%,$(AR_ORDER)) +UNMATCHED_OBJS = $(filter-out $(MATCHED_OBJS),$(AR_ORDER)) +NUM_OBJS = $(words $(AR_ORDER)) +NUM_OBJS_MATCHED = $(words $(MATCHED_OBJS)) +NUM_OBJS_UNMATCHED = $(words $(UNMATCHED_OBJS)) + +$(shell mkdir -p asm $(BASE_DIR) src $(BUILD_DIR)/$(BASE_DIR) $(foreach dir,$(ASM_DIRS) $(SRC_DIRS),$(BUILD_DIR)/$(dir))) + +.PHONY: all clean distclean setup +all: $(BUILD_AR) + +$(BUILD_AR): $(MARKER_FILES) + $(AR_OLD) rcs $@ $(AR_ORDER) +ifneq ($(NON_MATCHING),1) +# patch archive creation time and individual files' ownership & permissions + dd bs=1 skip=24 seek=24 count=12 conv=notrunc if=$(BASE_AR) of=$@ status=none + python3 tools/patch_ar_meta.py $@ + @$(COMPARE_AR) + @echo "Matched: $(NUM_OBJS_MATCHED)/$(NUM_OBJS)" +endif + +clean: + $(RM) -rf $(BUILD_DIR) + +distclean: clean + $(MAKE) -C tools distclean + $(RM) -rf $(BASE_DIR) + +setup: + $(MAKE) -C tools + cd $(BASE_DIR) && $(AR) xo ../$(BASE_AR) + chmod -R +rw $(BASE_DIR) + +# KMC gcc has a custom flag, N64ALIGN, which forces 8 byte alignment on arrays. This can be used to match, but +# an explicit aligned(8) attribute can be used instead. We opted for the latter for better compatibilty with +# other versions of GCC that do not have this flag. +# export N64ALIGN := ON +export VR4300MUL := ON + +$(BUILD_DIR)/$(BASE_DIR)/%.marker: $(BASE_DIR)/%.o + cp $< $(@:.marker=.o) +ifneq ($(NON_MATCHING),1) +# @$(COMPARE_OBJ) +# change file timestamps to match original + @touch -r $(BASE_DIR)/$(@F:.marker=.o) $(@:.marker=.o) + @$(COMPARE_OBJ) + @touch $@ +endif + +ifeq ($(findstring _d,$(TARGET)),_d) +$(BUILD_DIR)/src/rmon/%.marker: OPTFLAGS := -O0 +endif + +STRIP = + +$(BUILD_DIR)/src/os/initialize_isv.marker: OPTFLAGS := -O2 +$(BUILD_DIR)/src/os/initialize_isv.marker: STRIP = && tools/gcc/strip-2.7 -N initialize_isv.c $(WORKING_DIR)/$(@:.marker=.o) $(WORKING_DIR)/$(@:.marker=.o) +$(BUILD_DIR)/src/os/assert.marker: OPTFLAGS := -O0 +$(BUILD_DIR)/src/os/ackramromread.marker: OPTFLAGS := -O0 +$(BUILD_DIR)/src/os/ackramromwrite.marker: OPTFLAGS := -O0 +$(BUILD_DIR)/src/os/exit.marker: OPTFLAGS := -O0 +$(BUILD_DIR)/src/os/seterrorhandler.marker: OPTFLAGS := -O0 +$(BUILD_DIR)/src/gu/us2dex_emu.marker: GBIDEFINE := -DF3DEX_GBI +$(BUILD_DIR)/src/sp/sprite.marker: GBIDEFINE := +$(BUILD_DIR)/src/sp/spriteex.marker: GBIDEFINE := +$(BUILD_DIR)/src/sp/spriteex2.marker: GBIDEFINE := +$(BUILD_DIR)/src/sp/spriteex2.marker: GBIDEFINE := +$(BUILD_DIR)/src/mgu/%.marker: export VR4300MUL := OFF +$(BUILD_DIR)/src/mgu/rotate.marker: export VR4300MUL := ON +$(BUILD_DIR)/src/os/%.marker: ASFLAGS += -P +$(BUILD_DIR)/src/gu/%.marker: ASFLAGS += -P +$(BUILD_DIR)/src/libc/%.marker: ASFLAGS += -P +$(BUILD_DIR)/src/rmon/%.marker: ASFLAGS += -P +$(BUILD_DIR)/src/voice/%.marker: OPTFLAGS += -DLANG_JAPANESE -I$(WORKING_DIR)/src -I$(WORKING_DIR)/src/voice +$(BUILD_DIR)/src/voice/%.marker: CC := tools/compile_sjis.py -D__CC=$(WORKING_DIR)/$(CC) + +$(BUILD_DIR)/%.marker: %.c + cd $( + +/* + * Segment base addresses and sizes + */ +#define KUBASE 0 +#define KUSIZE 0x80000000 +#define K0BASE 0x80000000 +#define K0SIZE 0x20000000 +#define K1BASE 0xA0000000 +#define K1SIZE 0x20000000 +#define K2BASE 0xC0000000 +#define K2SIZE 0x20000000 + +/* + * Exception vectors + */ +#define SIZE_EXCVEC 0x80 /* Size of an exc. vec */ +#define UT_VEC K0BASE /* utlbmiss vector */ +#define R_VEC (K1BASE+0x1fc00000) /* reset vector */ +#define XUT_VEC (K0BASE+0x80) /* extended address tlbmiss */ +#define ECC_VEC (K0BASE+0x100) /* Ecc exception vector */ +#define E_VEC (K0BASE+0x180) /* Gen. exception vector */ + +/* + * Address conversion macros + */ +#ifdef _LANGUAGE_ASSEMBLY + +#define K0_TO_K1(x) ((x)|0xA0000000) /* kseg0 to kseg1 */ +#define K1_TO_K0(x) ((x)&0x9FFFFFFF) /* kseg1 to kseg0 */ +#define K0_TO_PHYS(x) ((x)&0x1FFFFFFF) /* kseg0 to physical */ +#define K1_TO_PHYS(x) ((x)&0x1FFFFFFF) /* kseg1 to physical */ +#define KDM_TO_PHYS(x) ((x)&0x1FFFFFFF) /* direct mapped to physical */ +#define PHYS_TO_K0(x) ((x)|0x80000000) /* physical to kseg0 */ +#define PHYS_TO_K1(x) ((x)|0xA0000000) /* physical to kseg1 */ + +#else /* _LANGUAGE_C */ + +#define K0_TO_K1(x) ((u32)(x)|0xA0000000) /* kseg0 to kseg1 */ +#define K1_TO_K0(x) ((u32)(x)&0x9FFFFFFF) /* kseg1 to kseg0 */ +#define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */ +#define K1_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg1 to physical */ +#define KDM_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* direct mapped to physical */ +#define PHYS_TO_K0(x) ((u32)(x)|0x80000000) /* physical to kseg0 */ +#define PHYS_TO_K1(x) ((u32)(x)|0xA0000000) /* physical to kseg1 */ + +#endif /* _LANGUAGE_ASSEMBLY */ + +/* + * Address predicates + */ +#define IS_KSEG0(x) ((u32)(x) >= K0BASE && (u32)(x) < K1BASE) +#define IS_KSEG1(x) ((u32)(x) >= K1BASE && (u32)(x) < K2BASE) +#define IS_KSEGDM(x) ((u32)(x) >= K0BASE && (u32)(x) < K2BASE) +#define IS_KSEG2(x) ((u32)(x) >= K2BASE && (u32)(x) < KPTE_SHDUBASE) +#define IS_KPTESEG(x) ((u32)(x) >= KPTE_SHDUBASE) +#define IS_KUSEG(x) ((u32)(x) < K0BASE) + +/* + * TLB size constants + */ + +#define NTLBENTRIES 31 /* entry 31 is reserved by rdb */ + +#define TLBHI_VPN2MASK 0xffffe000 +#define TLBHI_VPN2SHIFT 13 +#define TLBHI_PIDMASK 0xff +#define TLBHI_PIDSHIFT 0 +#define TLBHI_NPID 255 /* 255 to fit in 8 bits */ + +#define TLBLO_PFNMASK 0x3fffffc0 +#define TLBLO_PFNSHIFT 6 +#define TLBLO_CACHMASK 0x38 /* cache coherency algorithm */ +#define TLBLO_CACHSHIFT 3 +#define TLBLO_UNCACHED 0x10 /* not cached */ +#define TLBLO_NONCOHRNT 0x18 /* Cacheable non-coherent */ +#define TLBLO_EXLWR 0x28 /* Exclusive write */ +#define TLBLO_D 0x4 /* writeable */ +#define TLBLO_V 0x2 /* valid bit */ +#define TLBLO_G 0x1 /* global access bit */ + +#define TLBINX_PROBE 0x80000000 +#define TLBINX_INXMASK 0x3f +#define TLBINX_INXSHIFT 0 + +#define TLBRAND_RANDMASK 0x3f +#define TLBRAND_RANDSHIFT 0 + +#define TLBWIRED_WIREDMASK 0x3f + +#define TLBCTXT_BASEMASK 0xff800000 +#define TLBCTXT_BASESHIFT 23 +#define TLBCTXT_BASEBITS 9 + +#define TLBCTXT_VPNMASK 0x7ffff0 +#define TLBCTXT_VPNSHIFT 4 + +#define TLBPGMASK_4K 0x0 +#define TLBPGMASK_16K 0x6000 +#define TLBPGMASK_64K 0x1e000 + +/* + * Status register + */ +#define SR_CUMASK 0xf0000000 /* coproc usable bits */ + +#define SR_CU3 0x80000000 /* Coprocessor 3 usable */ +#define SR_CU2 0x40000000 /* Coprocessor 2 usable */ +#define SR_CU1 0x20000000 /* Coprocessor 1 usable */ +#define SR_CU0 0x10000000 /* Coprocessor 0 usable */ +#define SR_RP 0x08000000 /* Reduced power (quarter speed) */ +#define SR_FR 0x04000000 /* MIPS III FP register mode */ +#define SR_RE 0x02000000 /* Reverse endian */ +#define SR_ITS 0x01000000 /* Instruction trace support */ +#define SR_BEV 0x00400000 /* Use boot exception vectors */ +#define SR_TS 0x00200000 /* TLB shutdown */ +#define SR_SR 0x00100000 /* Soft reset occured */ +#define SR_CH 0x00040000 /* Cache hit for last 'cache' op */ +#define SR_CE 0x00020000 /* Create ECC */ +#define SR_DE 0x00010000 /* ECC of parity does not cause error */ + +/* + * Interrupt enable bits + * (NOTE: bits set to 1 enable the corresponding level interrupt) + */ +#define SR_IMASK 0x0000ff00 /* Interrupt mask */ +#define SR_IMASK8 0x00000000 /* mask level 8 */ +#define SR_IMASK7 0x00008000 /* mask level 7 */ +#define SR_IMASK6 0x0000c000 /* mask level 6 */ +#define SR_IMASK5 0x0000e000 /* mask level 5 */ +#define SR_IMASK4 0x0000f000 /* mask level 4 */ +#define SR_IMASK3 0x0000f800 /* mask level 3 */ +#define SR_IMASK2 0x0000fc00 /* mask level 2 */ +#define SR_IMASK1 0x0000fe00 /* mask level 1 */ +#define SR_IMASK0 0x0000ff00 /* mask level 0 */ + +#define SR_IBIT8 0x00008000 /* bit level 8 */ +#define SR_IBIT7 0x00004000 /* bit level 7 */ +#define SR_IBIT6 0x00002000 /* bit level 6 */ +#define SR_IBIT5 0x00001000 /* bit level 5 */ +#define SR_IBIT4 0x00000800 /* bit level 4 */ +#define SR_IBIT3 0x00000400 /* bit level 3 */ +#define SR_IBIT2 0x00000200 /* bit level 2 */ +#define SR_IBIT1 0x00000100 /* bit level 1 */ + +#define SR_IMASKSHIFT 8 + +#define SR_KX 0x00000080 /* extended-addr TLB vec in kernel */ +#define SR_SX 0x00000040 /* xtended-addr TLB vec supervisor */ +#define SR_UX 0x00000020 /* xtended-addr TLB vec in user mode */ +#define SR_KSU_MASK 0x00000018 /* mode mask */ +#define SR_KSU_USR 0x00000010 /* user mode */ +#define SR_KSU_SUP 0x00000008 /* supervisor mode */ +#define SR_KSU_KER 0x00000000 /* kernel mode */ +#define SR_ERL 0x00000004 /* Error level, 1=>cache error */ +#define SR_EXL 0x00000002 /* Exception level, 1=>exception */ +#define SR_IE 0x00000001 /* interrupt enable, 1=>enable */ + +/* + * Cause Register + */ +#define CAUSE_BD 0x80000000 /* Branch delay slot */ +#define CAUSE_CEMASK 0x30000000 /* coprocessor error */ +#define CAUSE_CESHIFT 28 + +/* Interrupt pending bits */ +#define CAUSE_IP8 0x00008000 /* External level 8 pending - COMPARE */ +#define CAUSE_IP7 0x00004000 /* External level 7 pending - INT4 */ +#define CAUSE_IP6 0x00002000 /* External level 6 pending - INT3 */ +#define CAUSE_IP5 0x00001000 /* External level 5 pending - INT2 */ +#define CAUSE_IP4 0x00000800 /* External level 4 pending - INT1 */ +#define CAUSE_IP3 0x00000400 /* External level 3 pending - INT0 */ +#define CAUSE_SW2 0x00000200 /* Software level 2 pending */ +#define CAUSE_SW1 0x00000100 /* Software level 1 pending */ + +#define CAUSE_IPMASK 0x0000FF00 /* Pending interrupt mask */ +#define CAUSE_IPSHIFT 8 + +#define CAUSE_EXCMASK 0x0000007C /* Cause code bits */ + +#define CAUSE_EXCSHIFT 2 + +/* Cause register exception codes */ + +#define EXC_CODE(x) ((x)<<2) + +/* Hardware exception codes */ +#define EXC_INT EXC_CODE(0) /* interrupt */ +#define EXC_MOD EXC_CODE(1) /* TLB mod */ +#define EXC_RMISS EXC_CODE(2) /* Read TLB Miss */ +#define EXC_WMISS EXC_CODE(3) /* Write TLB Miss */ +#define EXC_RADE EXC_CODE(4) /* Read Address Error */ +#define EXC_WADE EXC_CODE(5) /* Write Address Error */ +#define EXC_IBE EXC_CODE(6) /* Instruction Bus Error */ +#define EXC_DBE EXC_CODE(7) /* Data Bus Error */ +#define EXC_SYSCALL EXC_CODE(8) /* SYSCALL */ +#define EXC_BREAK EXC_CODE(9) /* BREAKpoint */ +#define EXC_II EXC_CODE(10) /* Illegal Instruction */ +#define EXC_CPU EXC_CODE(11) /* CoProcessor Unusable */ +#define EXC_OV EXC_CODE(12) /* OVerflow */ +#define EXC_TRAP EXC_CODE(13) /* Trap exception */ +#define EXC_VCEI EXC_CODE(14) /* Virt. Coherency on Inst. fetch */ +#define EXC_FPE EXC_CODE(15) /* Floating Point Exception */ +#define EXC_WATCH EXC_CODE(23) /* Watchpoint reference */ +#define EXC_VCED EXC_CODE(31) /* Virt. Coherency on data read */ + +/* C0_PRID Defines */ +#define C0_IMPMASK 0xff00 +#define C0_IMPSHIFT 8 +#define C0_REVMASK 0xff +#define C0_MAJREVMASK 0xf0 +#define C0_MAJREVSHIFT 4 +#define C0_MINREVMASK 0xf + +/* + * Coprocessor 0 operations + */ +#define C0_READI 0x1 /* read ITLB entry addressed by C0_INDEX */ +#define C0_WRITEI 0x2 /* write ITLB entry addressed by C0_INDEX */ +#define C0_WRITER 0x6 /* write ITLB entry addressed by C0_RAND */ +#define C0_PROBE 0x8 /* probe for ITLB entry addressed by TLBHI */ +#define C0_RFE 0x10 /* restore for exception */ + +/* + * 'cache' instruction definitions + */ + +/* Target cache */ +#define CACH_PI 0x0 /* specifies primary inst. cache */ +#define CACH_PD 0x1 /* primary data cache */ +#define CACH_SI 0x2 /* secondary instruction cache */ +#define CACH_SD 0x3 /* secondary data cache */ + +/* Cache operations */ +#define C_IINV 0x0 /* index invalidate (inst, 2nd inst) */ +#define C_IWBINV 0x0 /* index writeback inval (d, sd) */ +#define C_ILT 0x4 /* index load tag (all) */ +#define C_IST 0x8 /* index store tag (all) */ +#define C_CDX 0xc /* create dirty exclusive (d, sd) */ +#define C_HINV 0x10 /* hit invalidate (all) */ +#define C_HWBINV 0x14 /* hit writeback inv. (d, sd) */ +#define C_FILL 0x14 /* fill (i) */ +#define C_HWB 0x18 /* hit writeback (i, d, sd) */ +#define C_HSV 0x1c /* hit set virt. (si, sd) */ + +/* + * Cache size definitions + */ +#define ICACHE_SIZE 0x4000 /* 16K */ +#define ICACHE_LINESIZE 32 /* 8 words */ +#define ICACHE_LINEMASK (ICACHE_LINESIZE-1) + +#define DCACHE_SIZE 0x2000 /* 8K */ +#define DCACHE_LINESIZE 16 /* 4 words */ +#define DCACHE_LINEMASK (DCACHE_LINESIZE-1) + +/* + * C0_CONFIG register definitions + */ +#define CONFIG_CM 0x80000000 /* 1 == Master-Checker enabled */ +#define CONFIG_EC 0x70000000 /* System Clock ratio */ +#define CONFIG_EC_1_1 0x6 /* System Clock ratio 1 :1 */ +#define CONFIG_EC_3_2 0x7 /* System Clock ratio 1.5 :1 */ +#define CONFIG_EC_2_1 0x0 /* System Clock ratio 2 :1 */ +#define CONFIG_EC_3_1 0x1 /* System Clock ratio 3 :1 */ +#define CONFIG_EP 0x0f000000 /* Transmit Data Pattern */ +#define CONFIG_SB 0x00c00000 /* Secondary cache block size */ + +#define CONFIG_SS 0x00200000 /* Split scache: 0 == I&D combined */ +#define CONFIG_SW 0x00100000 /* scache port: 0==128, 1==64 */ +#define CONFIG_EW 0x000c0000 /* System Port width: 0==64, 1==32 */ +#define CONFIG_SC 0x00020000 /* 0 -> 2nd cache present */ +#define CONFIG_SM 0x00010000 /* 0 -> Dirty Shared Coherency enabled*/ +#define CONFIG_BE 0x00008000 /* Endian-ness: 1 --> BE */ +#define CONFIG_EM 0x00004000 /* 1 -> ECC mode, 0 -> parity */ +#define CONFIG_EB 0x00002000 /* Block order:1->sequent,0->subblock */ + +#define CONFIG_IC 0x00000e00 /* Primary Icache size */ +#define CONFIG_DC 0x000001c0 /* Primary Dcache size */ +#define CONFIG_IB 0x00000020 /* Icache block size */ +#define CONFIG_DB 0x00000010 /* Dcache block size */ +#define CONFIG_CU 0x00000008 /* Update on Store-conditional */ +#define CONFIG_K0 0x00000007 /* K0SEG Coherency algorithm */ + +#define CONFIG_UNCACHED 0x00000002 /* K0 is uncached */ +#define CONFIG_NONCOHRNT 0x00000003 +#define CONFIG_COHRNT_EXLWR 0x00000005 +#define CONFIG_SB_SHFT 22 /* shift SB to bit position 0 */ +#define CONFIG_IC_SHFT 9 /* shift IC to bit position 0 */ +#define CONFIG_DC_SHFT 6 /* shift DC to bit position 0 */ +#define CONFIG_BE_SHFT 15 /* shift BE to bit position 0 */ + +/* + * C0_TAGLO definitions for setting/getting cache states and physaddr bits + */ +#define SADDRMASK 0xFFFFE000 /* 31..13 -> scache paddr bits 35..17 */ +#define SVINDEXMASK 0x00000380 /* 9..7: prim virt index bits 14..12 */ +#define SSTATEMASK 0x00001c00 /* bits 12..10 hold scache line state */ +#define SINVALID 0x00000000 /* invalid --> 000 == state 0 */ +#define SCLEANEXCL 0x00001000 /* clean exclusive --> 100 == state 4 */ +#define SDIRTYEXCL 0x00001400 /* dirty exclusive --> 101 == state 5 */ +#define SECC_MASK 0x0000007f /* low 7 bits are ecc for the tag */ +#define SADDR_SHIFT 4 /* shift STagLo (31..13) to 35..17 */ + +#define PADDRMASK 0xFFFFFF00 /* PTagLo31..8->prim paddr bits35..12 */ +#define PADDR_SHIFT 4 /* roll bits 35..12 down to 31..8 */ +#define PSTATEMASK 0x00C0 /* bits 7..6 hold primary line state */ +#define PINVALID 0x0000 /* invalid --> 000 == state 0 */ +#define PCLEANEXCL 0x0080 /* clean exclusive --> 10 == state 2 */ +#define PDIRTYEXCL 0x00C0 /* dirty exclusive --> 11 == state 3 */ +#define PPARITY_MASK 0x0001 /* low bit is parity bit (even). */ + +/* + * C0_CACHE_ERR definitions. + */ +#define CACHERR_ER 0x80000000 /* 0: inst ref, 1: data ref */ +#define CACHERR_EC 0x40000000 /* 0: primary, 1: secondary */ +#define CACHERR_ED 0x20000000 /* 1: data error */ +#define CACHERR_ET 0x10000000 /* 1: tag error */ +#define CACHERR_ES 0x08000000 /* 1: external ref, e.g. snoop*/ +#define CACHERR_EE 0x04000000 /* error on SysAD bus */ +#define CACHERR_EB 0x02000000 /* complicated, see spec. */ +#define CACHERR_EI 0x01000000 /* complicated, see spec. */ +#define CACHERR_SIDX_MASK 0x003ffff8 /* secondary cache index */ +#define CACHERR_PIDX_MASK 0x00000007 /* primary cache index */ +#define CACHERR_PIDX_SHIFT 12 /* bits 2..0 are paddr14..12 */ + +/* R4000 family supports hardware watchpoints: + * C0_WATCHLO: + * bits 31..3 are bits 31..3 of physaddr to watch + * bit 2: reserved; must be written as 0. + * bit 1: when set causes a watchpoint trap on load accesses to paddr. + * bit 0: when set traps on stores to paddr; + * C0_WATCHHI + * bits 31..4 are reserved and must be written as zeros. + * bits 3..0 are bits 35..32 of the physaddr to watch + */ +#define WATCHLO_WTRAP 0x00000001 +#define WATCHLO_RTRAP 0x00000002 +#define WATCHLO_ADDRMASK 0xfffffff8 +#define WATCHLO_VALIDMASK 0xfffffffb +#define WATCHHI_VALIDMASK 0x0000000f + +/* + * Coprocessor 0 registers + */ +#ifdef _LANGUAGE_ASSEMBLY +#define C0_INX $0 +#define C0_RAND $1 +#define C0_ENTRYLO0 $2 +#define C0_ENTRYLO1 $3 +#define C0_CONTEXT $4 +#define C0_PAGEMASK $5 /* page mask */ +#define C0_WIRED $6 /* # wired entries in tlb */ +#define C0_BADVADDR $8 +#define C0_COUNT $9 /* free-running counter */ +#define C0_ENTRYHI $10 +#define C0_SR $12 +#define C0_CAUSE $13 +#define C0_EPC $14 +#define C0_PRID $15 /* revision identifier */ +#define C0_COMPARE $11 /* counter comparison reg. */ +#define C0_CONFIG $16 /* hardware configuration */ +#define C0_LLADDR $17 /* load linked address */ +#define C0_WATCHLO $18 /* watchpoint */ +#define C0_WATCHHI $19 /* watchpoint */ +#define C0_ECC $26 /* S-cache ECC and primary parity */ +#define C0_CACHE_ERR $27 /* cache error status */ +#define C0_TAGLO $28 /* cache operations */ +#define C0_TAGHI $29 /* cache operations */ +#define C0_ERROR_EPC $30 /* ECC error prg. counter */ + +# else /* ! _LANGUAGE_ASSEMBLY */ + +#define C0_INX 0 +#define C0_RAND 1 +#define C0_ENTRYLO0 2 +#define C0_ENTRYLO1 3 +#define C0_CONTEXT 4 +#define C0_PAGEMASK 5 /* page mask */ +#define C0_WIRED 6 /* # wired entries in tlb */ +#define C0_BADVADDR 8 +#define C0_COUNT 9 /* free-running counter */ +#define C0_ENTRYHI 10 +#define C0_SR 12 +#define C0_CAUSE 13 +#define C0_EPC 14 +#define C0_PRID 15 /* revision identifier */ +#define C0_COMPARE 11 /* counter comparison reg. */ +#define C0_CONFIG 16 /* hardware configuration */ +#define C0_LLADDR 17 /* load linked address */ +#define C0_WATCHLO 18 /* watchpoint */ +#define C0_WATCHHI 19 /* watchpoint */ +#define C0_ECC 26 /* S-cache ECC and primary parity */ +#define C0_CACHE_ERR 27 /* cache error status */ +#define C0_TAGLO 28 /* cache operations */ +#define C0_TAGHI 29 /* cache operations */ +#define C0_ERROR_EPC 30 /* ECC error prg. counter */ + +#endif /* _LANGUAGE_ASSEMBLY */ + +/* + * floating-point status register + */ +#define FPCSR_FS 0x01000000 /* flush denorm to zero */ +#define FPCSR_C 0x00800000 /* condition bit */ +#define FPCSR_CE 0x00020000 /* cause: unimplemented operation */ +#define FPCSR_CV 0x00010000 /* cause: invalid operation */ +#define FPCSR_CZ 0x00008000 /* cause: division by zero */ +#define FPCSR_CO 0x00004000 /* cause: overflow */ +#define FPCSR_CU 0x00002000 /* cause: underflow */ +#define FPCSR_CI 0x00001000 /* cause: inexact operation */ +#define FPCSR_EV 0x00000800 /* enable: invalid operation */ +#define FPCSR_EZ 0x00000400 /* enable: division by zero */ +#define FPCSR_EO 0x00000200 /* enable: overflow */ +#define FPCSR_EU 0x00000100 /* enable: underflow */ +#define FPCSR_EI 0x00000080 /* enable: inexact operation */ +#define FPCSR_FV 0x00000040 /* flag: invalid operation */ +#define FPCSR_FZ 0x00000020 /* flag: division by zero */ +#define FPCSR_FO 0x00000010 /* flag: overflow */ +#define FPCSR_FU 0x00000008 /* flag: underflow */ +#define FPCSR_FI 0x00000004 /* flag: inexact operation */ +#define FPCSR_RM_MASK 0x00000003 /* rounding mode mask */ +#define FPCSR_RM_RN 0x00000000 /* round to nearest */ +#define FPCSR_RM_RZ 0x00000001 /* round to zero */ +#define FPCSR_RM_RP 0x00000002 /* round to positive infinity */ +#define FPCSR_RM_RM 0x00000003 /* round to negative infinity */ + +#endif /* __R4300_H */ diff --git a/lib/ultralib/include/PR/abi.h b/lib/ultralib/include/PR/abi.h new file mode 100644 index 00000000..e1215260 --- /dev/null +++ b/lib/ultralib/include/PR/abi.h @@ -0,0 +1,410 @@ +#ifndef _ABI_H_ +#define _ABI_H_ + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.32 $ + * $Date: 1997/02/11 08:16:37 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/abi.h,v $ + * + **************************************************************************/ + +/* + * Header file for the Audio Binary Interface. + * This is included in the Media Binary Interface file + * mbi.h. + * + * This file follows the framework used for graphics. + * + */ + +/* Audio commands: */ +#define A_SPNOOP 0 +#define A_ADPCM 1 +#define A_CLEARBUFF 2 +#define A_ENVMIXER 3 +#define A_LOADBUFF 4 +#define A_RESAMPLE 5 +#define A_SAVEBUFF 6 +#define A_SEGMENT 7 +#define A_SETBUFF 8 +#define A_SETVOL 9 +#define A_DMEMMOVE 10 +#define A_LOADADPCM 11 +#define A_MIXER 12 +#define A_INTERLEAVE 13 +#define A_POLEF 14 +#define A_SETLOOP 15 + +#define ACMD_SIZE 32 +/* + * Audio flags + */ + +#define A_INIT 0x01 +#define A_CONTINUE 0x00 +#define A_LOOP 0x02 +#define A_OUT 0x02 +#define A_LEFT 0x02 +#define A_RIGHT 0x00 +#define A_VOL 0x04 +#define A_RATE 0x00 +#define A_AUX 0x08 +#define A_NOAUX 0x00 +#define A_MAIN 0x00 +#define A_MIX 0x10 + +/* + * BEGIN C-specific section: (typedef's) + */ +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * Data Structures. + */ + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int gain:16; + unsigned int addr; +} Aadpcm; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int gain:16; + unsigned int addr; +} Apolef; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int pad1:16; + unsigned int addr; +} Aenvelope; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:8; + unsigned int dmem:16; + unsigned int pad2:16; + unsigned int count:16; +} Aclearbuff; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:8; + unsigned int pad2:16; + unsigned int inL:16; + unsigned int inR:16; +} Ainterleave; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:24; + unsigned int addr; +} Aloadbuff; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int pad1:16; + unsigned int addr; +} Aenvmixer; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int gain:16; + unsigned int dmemi:16; + unsigned int dmemo:16; +} Amixer; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int dmem2:16; + unsigned int addr; +} Apan; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int pitch:16; + unsigned int addr; +} Aresample; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int pad1:16; + unsigned int addr; +} Areverb; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:24; + unsigned int addr; +} Asavebuff; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:24; + unsigned int pad2:2; + unsigned int number:4; + unsigned int base:24; +} Asegment; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int dmemin:16; + unsigned int dmemout:16; + unsigned int count:16; +} Asetbuff; + +typedef struct { + unsigned int cmd:8; + unsigned int flags:8; + unsigned int vol:16; + unsigned int voltgt:16; + unsigned int volrate:16; +} Asetvol; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:8; + unsigned int dmemin:16; + unsigned int dmemout:16; + unsigned int count:16; +} Admemmove; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:8; + unsigned int count:16; + unsigned int addr; +} Aloadadpcm; + +typedef struct { + unsigned int cmd:8; + unsigned int pad1:8; + unsigned int pad2:16; + unsigned int addr; +} Asetloop; + +/* + * Generic Acmd Packet + */ + +typedef struct { + unsigned int w0; + unsigned int w1; +} Awords; + +typedef union { + Awords words; + Aadpcm adpcm; + Apolef polef; + Aclearbuff clearbuff; + Aenvelope envelope; + Ainterleave interleave; + Aloadbuff loadbuff; + Aenvmixer envmixer; + Aresample resample; + Areverb reverb; + Asavebuff savebuff; + Asegment segment; + Asetbuff setbuff; + Asetvol setvol; + Admemmove dmemmove; + Aloadadpcm loadadpcm; + Amixer mixer; + Asetloop setloop; + long long int force_union_align; /* dummy, force alignment */ +} Acmd; + +/* + * ADPCM State + */ +#define ADPCMVSIZE 8 +#define ADPCMFSIZE 16 +typedef short ADPCM_STATE[ADPCMFSIZE]; + +/* + * Pole filter state + */ +typedef short POLEF_STATE[4]; + +/* + * Resampler state + */ +typedef short RESAMPLE_STATE[16]; + +/* + * Resampler constants + */ +#define UNITY_PITCH 0x8000 +#define MAX_RATIO 1.99996 /* within .03 cents of +1 octave */ + +/* + * Enveloper/Mixer state + */ +typedef short ENVMIX_STATE[40]; + +/* + * Macros to assemble the audio command list + */ + +#define aADPCMdec(pkt, f, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_ADPCM, 24, 8) | _SHIFTL(f, 16, 8); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aPoleFilter(pkt, f, g, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_POLEF, 24, 8) | _SHIFTL(f, 16, 8) | \ + _SHIFTL(g, 0, 16)); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aClearBuffer(pkt, d, c) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_CLEARBUFF, 24, 8) | _SHIFTL(d, 0, 24); \ + _a->words.w1 = (unsigned int)(c); \ +} + +#define aEnvMixer(pkt, f, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_ENVMIXER, 24, 8) | _SHIFTL(f, 16, 8); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aInterleave(pkt, l, r) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_INTERLEAVE, 24, 8); \ + _a->words.w1 = _SHIFTL(l, 16, 16) | _SHIFTL(r, 0, 16); \ +} + +#define aLoadBuffer(pkt, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_LOADBUFF, 24, 8); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aMix(pkt, f, g, i, o) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_MIXER, 24, 8) | _SHIFTL(f, 16, 8) | \ + _SHIFTL(g, 0, 16)); \ + _a->words.w1 = _SHIFTL(i,16, 16) | _SHIFTL(o, 0, 16); \ +} + +#define aPan(pkt, f, d, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_PAN, 24, 8) | _SHIFTL(f, 16, 8) | \ + _SHIFTL(d, 0, 16)); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aResample(pkt, f, p, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_RESAMPLE, 24, 8) | _SHIFTL(f, 16, 8) |\ + _SHIFTL(p, 0, 16)); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aSaveBuffer(pkt, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_SAVEBUFF, 24, 8); \ + _a->words.w1 = (unsigned int)(s); \ +} + +#define aSegment(pkt, s, b) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_SEGMENT, 24, 8); \ + _a->words.w1 = _SHIFTL(s, 24, 8) | _SHIFTL(b, 0, 24); \ +} + +#define aSetBuffer(pkt, f, i, o, c) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_SETBUFF, 24, 8) | _SHIFTL(f, 16, 8) | \ + _SHIFTL(i, 0, 16)); \ + _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ +} + +#define aSetVolume(pkt, f, v, t, r) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_SETVOL, 24, 8) | _SHIFTL(f, 16, 16) | \ + _SHIFTL(v, 0, 16)); \ + _a->words.w1 = _SHIFTL(t, 16, 16) | _SHIFTL(r, 0, 16); \ +} + +#define aSetLoop(pkt, a) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + _a->words.w0 = _SHIFTL(A_SETLOOP, 24, 8); \ + _a->words.w1 = (unsigned int)(a); \ +} + +#define aDMEMMove(pkt, i, o, c) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_DMEMMOVE, 24, 8) | _SHIFTL(i, 0, 24); \ + _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ +} + +#define aLoadADPCM(pkt, c, d) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_LOADADPCM, 24, 8) | _SHIFTL(c, 0, 24); \ + _a->words.w1 = (unsigned int) d; \ +} + +#endif /* _LANGUAGE_C */ + +#endif /* !_ABI_H_ */ + + + diff --git a/lib/ultralib/include/PR/gbi.h b/lib/ultralib/include/PR/gbi.h new file mode 100644 index 00000000..80ba6023 --- /dev/null +++ b/lib/ultralib/include/PR/gbi.h @@ -0,0 +1,4572 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ +/************************************************************************** + * + * $Revision: 1.141 $ + * $Date: 1999/09/03 03:43:08 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/gbi.h,v $ + * + **************************************************************************/ + +#ifndef _GBI_H_ +#define _GBI_H_ + +#include + +/* + * To use the F3DEX ucodes, define F3DEX_GBI before include this file. + * + * #define F3DEX_GBI + * #include + * + * or + * + * cc -c -DF3DEX_GBI -I.... foo.c + * + */ + +/************************************************************************** + * + * Graphics Binary Interface + * + **************************************************************************/ + +/* + * Graphics Commands, 'xxx' parts may be generated from ucode + * + * The command format is + * + * |00xxxxxx| = DMA 0,..,127 + * |10xxxxxx| = Immediate Mode -65,..,-128 + * |11xxxxxx| = RDP cmds -1,..,-64 + * + * Note: in order for the RSP microcode to process RDP commands opaquely, + * we need to further identify those RDP commands that need DRAM address + * "fixup". To do this, we have the dummy command G_RDP_ADDR_FIXUP, and + * all |RDP commands| less than this are commands with embedded DRAM + * addresses. Further, the format of these commands should be similar so + * only one fixup routine is needed. + * + * Further explanation: + * The names of the commands are somewhat misleading. Here is clarification: + * + * - a 'DMA' type command has a pointer to additional data and + * causes a DMA transfer to bring that into DMEM. + * + * - an 'Immediate' type command isn't really 'immediate', in the + * traditional sense. This just means that the entire command fits + * in the 64-bit word, and the ucode can execute it 'immediately' + * without additional memory transfers. + * + * - an 'RDP' command is identified as such because the RDP + * commands can be passed-thru the RSP and sent to the RDP + * directly. One further confusing thing, is that some 'DP' + * macros below actually generate immediate commands, not + * not direct DP commands. + * + * IMPLEMENTATION NOTE: + * There is another group of RDP commands that includes the triangle commands + * generated by the RSP code. These are the raw commands the rasterizer + * hardware chews on, with slope info, etc. They will follow the RDP + * ordering... + * + * IMPLEMENTATION NOTE: + * The RDP hardware has some of these bit patterns wired up. If the hardware + * changes, we must adjust this table, likewise we can't change/add things + * once the hardware is frozen. (actually, the RDP hardware only looks at + * the lower 6 bits of the command byte) + * + */ + +#ifdef F3DEX_GBI_2 +# ifndef F3DEX_GBI +# define F3DEX_GBI +# endif +#define G_NOOP 0x00 +#define G_RDPHALF_2 0xf1 +#define G_SETOTHERMODE_H 0xe3 +#define G_SETOTHERMODE_L 0xe2 +#define G_RDPHALF_1 0xe1 +#define G_SPNOOP 0xe0 +#define G_ENDDL 0xdf +#define G_DL 0xde +#define G_LOAD_UCODE 0xdd +#define G_MOVEMEM 0xdc +#define G_MOVEWORD 0xdb +#define G_MTX 0xda +#define G_GEOMETRYMODE 0xd9 +#define G_POPMTX 0xd8 +#define G_TEXTURE 0xd7 +#define G_DMA_IO 0xd6 +#define G_SPECIAL_1 0xd5 +#define G_SPECIAL_2 0xd4 +#define G_SPECIAL_3 0xd3 + +#define G_VTX 0x01 +#define G_MODIFYVTX 0x02 +#define G_CULLDL 0x03 +#define G_BRANCH_Z 0x04 +#define G_TRI1 0x05 +#define G_TRI2 0x06 +#define G_QUAD 0x07 +#define G_LINE3D 0x08 +#else /* F3DEX_GBI_2 */ + +/* DMA commands: */ +#define G_SPNOOP 0 /* handle 0 gracefully */ +#define G_MTX 1 +#define G_RESERVED0 2 /* not implemeted */ +#define G_MOVEMEM 3 /* move a block of memory (up to 4 words) to dmem */ +#define G_VTX 4 +#define G_RESERVED1 5 /* not implemeted */ +#define G_DL 6 +#define G_RESERVED2 7 /* not implemeted */ +#define G_RESERVED3 8 /* not implemeted */ +#define G_SPRITE2D_BASE 9 /* sprite command */ + +/* IMMEDIATE commands: */ +#define G_IMMFIRST -65 +#define G_TRI1 (G_IMMFIRST-0) +#define G_CULLDL (G_IMMFIRST-1) +#define G_POPMTX (G_IMMFIRST-2) +#define G_MOVEWORD (G_IMMFIRST-3) +#define G_TEXTURE (G_IMMFIRST-4) +#define G_SETOTHERMODE_H (G_IMMFIRST-5) +#define G_SETOTHERMODE_L (G_IMMFIRST-6) +#define G_ENDDL (G_IMMFIRST-7) +#define G_SETGEOMETRYMODE (G_IMMFIRST-8) +#define G_CLEARGEOMETRYMODE (G_IMMFIRST-9) +#define G_LINE3D (G_IMMFIRST-10) +#define G_RDPHALF_1 (G_IMMFIRST-11) +#define G_RDPHALF_2 (G_IMMFIRST-12) +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +# define G_MODIFYVTX (G_IMMFIRST-13) +# define G_TRI2 (G_IMMFIRST-14) +# define G_BRANCH_Z (G_IMMFIRST-15) +# define G_LOAD_UCODE (G_IMMFIRST-16) +#else +# define G_RDPHALF_CONT (G_IMMFIRST-13) +#endif + +/* We are overloading 2 of the immediate commands + to keep the byte alignment of dmem the same */ + +#define G_SPRITE2D_SCALEFLIP (G_IMMFIRST-1) +#define G_SPRITE2D_DRAW (G_IMMFIRST-2) + +/* RDP commands: */ +#define G_NOOP 0xc0 /* 0 */ + +#endif /* F3DEX_GBI_2 */ + +/* RDP commands: */ +#define G_SETCIMG 0xff /* -1 */ +#define G_SETZIMG 0xfe /* -2 */ +#define G_SETTIMG 0xfd /* -3 */ +#define G_SETCOMBINE 0xfc /* -4 */ +#define G_SETENVCOLOR 0xfb /* -5 */ +#define G_SETPRIMCOLOR 0xfa /* -6 */ +#define G_SETBLENDCOLOR 0xf9 /* -7 */ +#define G_SETFOGCOLOR 0xf8 /* -8 */ +#define G_SETFILLCOLOR 0xf7 /* -9 */ +#define G_FILLRECT 0xf6 /* -10 */ +#define G_SETTILE 0xf5 /* -11 */ +#define G_LOADTILE 0xf4 /* -12 */ +#define G_LOADBLOCK 0xf3 /* -13 */ +#define G_SETTILESIZE 0xf2 /* -14 */ +#define G_LOADTLUT 0xf0 /* -16 */ +#define G_RDPSETOTHERMODE 0xef /* -17 */ +#define G_SETPRIMDEPTH 0xee /* -18 */ +#define G_SETSCISSOR 0xed /* -19 */ +#define G_SETCONVERT 0xec /* -20 */ +#define G_SETKEYR 0xeb /* -21 */ +#define G_SETKEYGB 0xea /* -22 */ +#define G_RDPFULLSYNC 0xe9 /* -23 */ +#define G_RDPTILESYNC 0xe8 /* -24 */ +#define G_RDPPIPESYNC 0xe7 /* -25 */ +#define G_RDPLOADSYNC 0xe6 /* -26 */ +#define G_TEXRECTFLIP 0xe5 /* -27 */ +#define G_TEXRECT 0xe4 /* -28 */ + + +/* + * The following commands are the "generated" RDP commands; the user + * never sees them, the RSP microcode generates them. + * + * The layout of the bits is magical, to save work in the ucode. + * These id's are -56, -52, -54, -50, -55, -51, -53, -49, ... + * edge, shade, texture, zbuff bits: estz + */ +#define G_TRI_FILL 0xc8 /* fill triangle: 11001000 */ +#define G_TRI_SHADE 0xcc /* shade triangle: 11001100 */ +#define G_TRI_TXTR 0xca /* texture triangle: 11001010 */ +#define G_TRI_SHADE_TXTR 0xce /* shade, texture triangle: 11001110 */ +#define G_TRI_FILL_ZBUFF 0xc9 /* fill, zbuff triangle: 11001001 */ +#define G_TRI_SHADE_ZBUFF 0xcd /* shade, zbuff triangle: 11001101 */ +#define G_TRI_TXTR_ZBUFF 0xcb /* texture, zbuff triangle: 11001011 */ +#define G_TRI_SHADE_TXTR_ZBUFF 0xcf /* shade, txtr, zbuff trngl: 11001111 */ + +/* + * A TRI_FILL triangle is just the edges. You need to set the DP + * to use primcolor, in order to see anything. (it is NOT a triangle + * that gets rendered in 'fill mode'. Triangles can't be rendered + * in 'fill mode') + * + * A TRI_SHADE is a gouraud triangle that has colors interpolated. + * Flat-shaded triangles (from the software) are still gouraud shaded, + * it's just the colors are all the same and the deltas are 0. + * + * Other triangle types, and combinations are more obvious. + */ + +/* masks to build RDP triangle commands: */ +#define G_RDP_TRI_FILL_MASK 0x08 +#define G_RDP_TRI_SHADE_MASK 0x04 +#define G_RDP_TRI_TXTR_MASK 0x02 +#define G_RDP_TRI_ZBUFF_MASK 0x01 + +/* + * HACK: + * This is a dreadful hack. For version 1.0 hardware, there are still + * some 'bowtie' hangs. This parameter can be increased to avoid + * the hangs. Every increase of 4 chops one scanline off of every + * triangle. Values of 4,8,12 should be sufficient to avoid any + * bowtie hang. + * + * Change this value, then recompile ALL of your program (including static + * display lists!) + * + * THIS WILL BE REMOVED FOR HARDWARE VERSION 2.0! + */ +#define BOWTIE_VAL 0 + + +/* gets added to RDP command, in order to test for addres fixup: */ +#define G_RDP_ADDR_FIXUP 3 /* |RDP cmds| <= this, do addr fixup */ +#ifdef _LANGUAGE_ASSEMBLY +#define G_RDP_TEXRECT_CHECK ((-1*G_TEXRECTFLIP)& 0xff) +#endif + +/* macros for command parsing: */ +#define GDMACMD(x) (x) +#define GIMMCMD(x) (G_IMMFIRST-(x)) +#define GRDPCMD(x) (0xff-(x)) + +#define G_DMACMDSIZ 128 +#define G_IMMCMDSIZ 64 +#define G_RDPCMDSIZ 64 + +/* + * Coordinate shift values, number of bits of fraction + */ +#define G_TEXTURE_IMAGE_FRAC 2 +#define G_TEXTURE_SCALE_FRAC 16 +#define G_SCALE_FRAC 8 +#define G_ROTATE_FRAC 16 + +/* + * Parameters to graphics commands + */ + +/* + * Data packing macros + */ + +/* + * Maximum z-buffer value, used to initialize the z-buffer. + * Note : this number is NOT the viewport z-scale constant. + * See the comment next to G_MAXZ for more info. + */ +#define G_MAXFBZ 0x3fff /* 3b exp, 11b mantissa */ + +#define GPACK_RGBA5551(r, g, b, a) ((((r)<<8) & 0xf800) | \ + (((g)<<3) & 0x7c0) | \ + (((b)>>2) & 0x3e) | ((a) & 0x1)) +#define GPACK_ZDZ(z, dz) ((z) << 2 | (dz)) + +/* + * G_MTX: parameter flags + */ +#ifdef F3DEX_GBI_2 +# define G_MTX_MODELVIEW 0x00 /* matrix types */ +# define G_MTX_PROJECTION 0x04 +# define G_MTX_MUL 0x00 /* concat or load */ +# define G_MTX_LOAD 0x02 +# define G_MTX_NOPUSH 0x00 /* push or not */ +# define G_MTX_PUSH 0x01 +#else /* F3DEX_GBI_2 */ +# define G_MTX_MODELVIEW 0x00 /* matrix types */ +# define G_MTX_PROJECTION 0x01 +# define G_MTX_MUL 0x00 /* concat or load */ +# define G_MTX_LOAD 0x02 +# define G_MTX_NOPUSH 0x00 /* push or not */ +# define G_MTX_PUSH 0x04 +#endif /* F3DEX_GBI_2 */ + +/* + * flags for G_SETGEOMETRYMODE + * (this rendering state is maintained in RSP) + * + * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: + * The weird bit-ordering is for the micro-code: the lower byte + * can be OR'd in with G_TRI_SHADE (11001100) to construct + * the triangle command directly. Don't break it... + * + * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: + * The high byte is OR'd with 0x703 to form the clip code mask. + * If it is set to 0x04, this will cause near clipping to occur. + * If it is zero, near clipping will not occur. + * + * Further explanation: + * G_SHADE is necessary in order to see the color that you passed + * down with the vertex. If G_SHADE isn't set, you need to set the DP + * appropriately and use primcolor to see anything. + * + * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. + * If it is not set, then do 'flat shading', where only one vertex color + * is used (and all 3 vertices are set to that same color by the ucode) + * See the man page for gSP1Triangle(). + * + */ +#define G_ZBUFFER 0x00000001 +#define G_SHADE 0x00000004 /* enable Gouraud interp */ +/* rest of low byte reserved for setup ucode */ +#ifdef F3DEX_GBI_2 +# define G_TEXTURE_ENABLE 0x00000000 /* Ignored */ +# define G_SHADING_SMOOTH 0x00200000 /* flat or smooth shaded */ +# define G_CULL_FRONT 0x00000200 +# define G_CULL_BACK 0x00000400 +# define G_CULL_BOTH 0x00000600 /* To make code cleaner */ +#else +# define G_TEXTURE_ENABLE 0x00000002 /* Microcode use only */ +# define G_SHADING_SMOOTH 0x00000200 /* flat or smooth shaded */ +# define G_CULL_FRONT 0x00001000 +# define G_CULL_BACK 0x00002000 +# define G_CULL_BOTH 0x00003000 /* To make code cleaner */ +#endif +#define G_FOG 0x00010000 +#define G_LIGHTING 0x00020000 +#define G_TEXTURE_GEN 0x00040000 +#define G_TEXTURE_GEN_LINEAR 0x00080000 +#define G_LOD 0x00100000 /* NOT IMPLEMENTED */ +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +# define G_CLIPPING 0x00800000 +#else +# define G_CLIPPING 0x00000000 +#endif + +#ifdef _LANGUAGE_ASSEMBLY +#define G_FOG_H (G_FOG/0x10000) +#define G_LIGHTING_H (G_LIGHTING/0x10000) +#define G_TEXTURE_GEN_H (G_TEXTURE_GEN/0x10000) +#define G_TEXTURE_GEN_LINEAR_H (G_TEXTURE_GEN_LINEAR/0x10000) +#define G_LOD_H (G_LOD/0x10000) /* NOT IMPLEMENTED */ +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +# define G_CLIPPING_H (G_CLIPPING/0x10000) +#endif +#endif + +/* Need these defined for Sprite Microcode */ +#ifdef _LANGUAGE_ASSEMBLY +#define G_TX_LOADTILE 7 +#define G_TX_RENDERTILE 0 + +#define G_TX_NOMIRROR 0 +#define G_TX_WRAP 0 +#define G_TX_MIRROR 0x1 +#define G_TX_CLAMP 0x2 +#define G_TX_NOMASK 0 +#define G_TX_NOLOD 0 +#endif + +/* + * G_SETIMG fmt: set image formats + */ +#define G_IM_FMT_RGBA 0 +#define G_IM_FMT_YUV 1 +#define G_IM_FMT_CI 2 +#define G_IM_FMT_IA 3 +#define G_IM_FMT_I 4 + +/* + * G_SETIMG siz: set image pixel size + */ +#define G_IM_SIZ_4b 0 +#define G_IM_SIZ_8b 1 +#define G_IM_SIZ_16b 2 +#define G_IM_SIZ_32b 3 +#define G_IM_SIZ_DD 5 + +#define G_IM_SIZ_4b_BYTES 0 +#define G_IM_SIZ_4b_TILE_BYTES G_IM_SIZ_4b_BYTES +#define G_IM_SIZ_4b_LINE_BYTES G_IM_SIZ_4b_BYTES + +#define G_IM_SIZ_8b_BYTES 1 +#define G_IM_SIZ_8b_TILE_BYTES G_IM_SIZ_8b_BYTES +#define G_IM_SIZ_8b_LINE_BYTES G_IM_SIZ_8b_BYTES + +#define G_IM_SIZ_16b_BYTES 2 +#define G_IM_SIZ_16b_TILE_BYTES G_IM_SIZ_16b_BYTES +#define G_IM_SIZ_16b_LINE_BYTES G_IM_SIZ_16b_BYTES + +#define G_IM_SIZ_32b_BYTES 4 +#define G_IM_SIZ_32b_TILE_BYTES 2 +#define G_IM_SIZ_32b_LINE_BYTES 2 + +#define G_IM_SIZ_4b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_8b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_16b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_32b_LOAD_BLOCK G_IM_SIZ_32b + +#define G_IM_SIZ_4b_SHIFT 2 +#define G_IM_SIZ_8b_SHIFT 1 +#define G_IM_SIZ_16b_SHIFT 0 +#define G_IM_SIZ_32b_SHIFT 0 + +#define G_IM_SIZ_4b_INCR 3 +#define G_IM_SIZ_8b_INCR 1 +#define G_IM_SIZ_16b_INCR 0 +#define G_IM_SIZ_32b_INCR 0 + +/* + * G_SETCOMBINE: color combine modes + */ +/* Color combiner constants: */ +#define G_CCMUX_COMBINED 0 +#define G_CCMUX_TEXEL0 1 +#define G_CCMUX_TEXEL1 2 +#define G_CCMUX_PRIMITIVE 3 +#define G_CCMUX_SHADE 4 +#define G_CCMUX_ENVIRONMENT 5 +#define G_CCMUX_CENTER 6 +#define G_CCMUX_SCALE 6 +#define G_CCMUX_COMBINED_ALPHA 7 +#define G_CCMUX_TEXEL0_ALPHA 8 +#define G_CCMUX_TEXEL1_ALPHA 9 +#define G_CCMUX_PRIMITIVE_ALPHA 10 +#define G_CCMUX_SHADE_ALPHA 11 +#define G_CCMUX_ENV_ALPHA 12 +#define G_CCMUX_LOD_FRACTION 13 +#define G_CCMUX_PRIM_LOD_FRAC 14 +#define G_CCMUX_NOISE 7 +#define G_CCMUX_K4 7 +#define G_CCMUX_K5 15 +#define G_CCMUX_1 6 +#define G_CCMUX_0 31 + +/* Alpha combiner constants: */ +#define G_ACMUX_COMBINED 0 +#define G_ACMUX_TEXEL0 1 +#define G_ACMUX_TEXEL1 2 +#define G_ACMUX_PRIMITIVE 3 +#define G_ACMUX_SHADE 4 +#define G_ACMUX_ENVIRONMENT 5 +#define G_ACMUX_LOD_FRACTION 0 +#define G_ACMUX_PRIM_LOD_FRAC 6 +#define G_ACMUX_1 6 +#define G_ACMUX_0 7 + +/* typical CC cycle 1 modes */ +#define G_CC_PRIMITIVE 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE +#define G_CC_SHADE 0, 0, 0, SHADE, 0, 0, 0, SHADE +#define G_CC_MODULATEI TEXEL0, 0, SHADE, 0, 0, 0, 0, SHADE +#define G_CC_MODULATEIA TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0 +#define G_CC_MODULATEIDECALA TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB G_CC_MODULATEI +#define G_CC_MODULATERGBA G_CC_MODULATEIA +#define G_CC_MODULATERGBDECALA G_CC_MODULATEIDECALA +#define G_CC_MODULATEI_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0 +#define G_CC_MODULATEIDECALA_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB_PRIM G_CC_MODULATEI_PRIM +#define G_CC_MODULATERGBA_PRIM G_CC_MODULATEIA_PRIM +#define G_CC_MODULATERGBDECALA_PRIM G_CC_MODULATEIDECALA_PRIM +#define G_CC_DECALRGB 0, 0, 0, TEXEL0, 0, 0, 0, SHADE +#define G_CC_DECALRGBA 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0 +#define G_CC_BLENDI ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDIA ENVIRONMENT, SHADE, TEXEL0, SHADE, TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDIDECALA ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_BLENDRGBA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDRGBDECALA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_ADDRGB 1, 0, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_ADDRGBDECALA 1, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_REFLECTRGB ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_REFLECTRGBDECALA ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_HILITERGB PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_HILITERGBA PRIMITIVE, SHADE, TEXEL0, SHADE, PRIMITIVE, SHADE, TEXEL0, SHADE +#define G_CC_HILITERGBDECALA PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_SHADEDECALA 0, 0, 0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_BLENDPE PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDPEDECALA PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, TEXEL0 + +/* oddball modes */ +#define _G_CC_BLENDPE ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, SHADE, 0 +#define _G_CC_BLENDPEDECALA ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, 0, 0, 0, TEXEL0 +#define _G_CC_TWOCOLORTEX PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +/* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */ +#define _G_CC_SPARSEST PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_TEMPLERP TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0 + +/* typical CC cycle 1 modes, usually followed by other cycle 2 modes */ +#define G_CC_TRILERP TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_INTERFERENCE TEXEL0, 0, TEXEL1, 0, TEXEL0, 0, TEXEL1, 0 + +/* + * One-cycle color convert operation + */ +#define G_CC_1CYUV2RGB TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE + +/* + * NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock. + * Therefore, CC looks for step1 results in TEXEL1 + */ +#define G_CC_YUV2RGB TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0 + +/* typical CC cycle 2 modes */ +#define G_CC_PASS2 0, 0, 0, COMBINED, 0, 0, 0, COMBINED +#define G_CC_MODULATEI2 COMBINED, 0, SHADE, 0, 0, 0, 0, SHADE +#define G_CC_MODULATEIA2 COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0 +#define G_CC_MODULATERGB2 G_CC_MODULATEI2 +#define G_CC_MODULATERGBA2 G_CC_MODULATEIA2 +#define G_CC_MODULATEI_PRIM2 COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM2 COMBINED, 0, PRIMITIVE, 0, COMBINED, 0, PRIMITIVE, 0 +#define G_CC_MODULATERGB_PRIM2 G_CC_MODULATEI_PRIM2 +#define G_CC_MODULATERGBA_PRIM2 G_CC_MODULATEIA_PRIM2 +#define G_CC_DECALRGB2 0, 0, 0, COMBINED, 0, 0, 0, SHADE +/* + * ? +#define G_CC_DECALRGBA2 COMBINED, SHADE, COMBINED_ALPHA, SHADE, 0, 0, 0, SHADE +*/ +#define G_CC_BLENDI2 ENVIRONMENT, SHADE, COMBINED, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDIA2 ENVIRONMENT, SHADE, COMBINED, SHADE, COMBINED, 0, SHADE, 0 +#define G_CC_CHROMA_KEY2 TEXEL0, CENTER, SCALE, 0, 0, 0, 0, 0 +#define G_CC_HILITERGB2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, SHADE +#define G_CC_HILITERGBA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, ENVIRONMENT, COMBINED, TEXEL0, COMBINED +#define G_CC_HILITERGBDECALA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, TEXEL0 +#define G_CC_HILITERGBPASSA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, COMBINED + +/* + * G_SETOTHERMODE_L sft: shift count + */ +#define G_MDSFT_ALPHACOMPARE 0 +#define G_MDSFT_ZSRCSEL 2 +#define G_MDSFT_RENDERMODE 3 +#define G_MDSFT_BLENDER 16 + +/* + * G_SETOTHERMODE_H sft: shift count + */ +#define G_MDSFT_BLENDMASK 0 /* unsupported */ +#define G_MDSFT_ALPHADITHER 4 +#define G_MDSFT_RGBDITHER 6 + +#define G_MDSFT_COMBKEY 8 +#define G_MDSFT_TEXTCONV 9 +#define G_MDSFT_TEXTFILT 12 +#define G_MDSFT_TEXTLUT 14 +#define G_MDSFT_TEXTLOD 16 +#define G_MDSFT_TEXTDETAIL 17 +#define G_MDSFT_TEXTPERSP 19 +#define G_MDSFT_CYCLETYPE 20 +#define G_MDSFT_COLORDITHER 22 /* unsupported in HW 2.0 */ +#define G_MDSFT_PIPELINE 23 + +/* G_SETOTHERMODE_H gPipelineMode */ +#define G_PM_1PRIMITIVE (1 << G_MDSFT_PIPELINE) +#define G_PM_NPRIMITIVE (0 << G_MDSFT_PIPELINE) + +/* G_SETOTHERMODE_H gSetCycleType */ +#define G_CYC_1CYCLE (0 << G_MDSFT_CYCLETYPE) +#define G_CYC_2CYCLE (1 << G_MDSFT_CYCLETYPE) +#define G_CYC_COPY (2 << G_MDSFT_CYCLETYPE) +#define G_CYC_FILL (3 << G_MDSFT_CYCLETYPE) + +/* G_SETOTHERMODE_H gSetTexturePersp */ +#define G_TP_NONE (0 << G_MDSFT_TEXTPERSP) +#define G_TP_PERSP (1 << G_MDSFT_TEXTPERSP) + +/* G_SETOTHERMODE_H gSetTextureDetail */ +#define G_TD_CLAMP (0 << G_MDSFT_TEXTDETAIL) +#define G_TD_SHARPEN (1 << G_MDSFT_TEXTDETAIL) +#define G_TD_DETAIL (2 << G_MDSFT_TEXTDETAIL) + +/* G_SETOTHERMODE_H gSetTextureLOD */ +#define G_TL_TILE (0 << G_MDSFT_TEXTLOD) +#define G_TL_LOD (1 << G_MDSFT_TEXTLOD) + +/* G_SETOTHERMODE_H gSetTextureLUT */ +#define G_TT_NONE (0 << G_MDSFT_TEXTLUT) +#define G_TT_RGBA16 (2 << G_MDSFT_TEXTLUT) +#define G_TT_IA16 (3 << G_MDSFT_TEXTLUT) + +/* G_SETOTHERMODE_H gSetTextureFilter */ +#define G_TF_POINT (0 << G_MDSFT_TEXTFILT) +#define G_TF_AVERAGE (3 << G_MDSFT_TEXTFILT) +#define G_TF_BILERP (2 << G_MDSFT_TEXTFILT) + +/* G_SETOTHERMODE_H gSetTextureConvert */ +#define G_TC_CONV (0 << G_MDSFT_TEXTCONV) +#define G_TC_FILTCONV (5 << G_MDSFT_TEXTCONV) +#define G_TC_FILT (6 << G_MDSFT_TEXTCONV) + +/* G_SETOTHERMODE_H gSetCombineKey */ +#define G_CK_NONE (0 << G_MDSFT_COMBKEY) +#define G_CK_KEY (1 << G_MDSFT_COMBKEY) + +/* G_SETOTHERMODE_H gSetColorDither */ +#define G_CD_MAGICSQ (0 << G_MDSFT_RGBDITHER) +#define G_CD_BAYER (1 << G_MDSFT_RGBDITHER) +#define G_CD_NOISE (2 << G_MDSFT_RGBDITHER) + +#ifndef _HW_VERSION_1 +#define G_CD_DISABLE (3 << G_MDSFT_RGBDITHER) +#define G_CD_ENABLE G_CD_NOISE /* HW 1.0 compatibility mode */ +#else +#define G_CD_ENABLE (1 << G_MDSFT_COLORDITHER) +#define G_CD_DISABLE (0 << G_MDSFT_COLORDITHER) +#endif + +/* G_SETOTHERMODE_H gSetAlphaDither */ +#define G_AD_PATTERN (0 << G_MDSFT_ALPHADITHER) +#define G_AD_NOTPATTERN (1 << G_MDSFT_ALPHADITHER) +#define G_AD_NOISE (2 << G_MDSFT_ALPHADITHER) +#define G_AD_DISABLE (3 << G_MDSFT_ALPHADITHER) + +/* G_SETOTHERMODE_L gSetAlphaCompare */ +#define G_AC_NONE (0 << G_MDSFT_ALPHACOMPARE) +#define G_AC_THRESHOLD (1 << G_MDSFT_ALPHACOMPARE) +#define G_AC_DITHER (3 << G_MDSFT_ALPHACOMPARE) + +/* G_SETOTHERMODE_L gSetDepthSource */ +#define G_ZS_PIXEL (0 << G_MDSFT_ZSRCSEL) +#define G_ZS_PRIM (1 << G_MDSFT_ZSRCSEL) + +/* G_SETOTHERMODE_L gSetRenderMode */ +#define AA_EN 0x8 +#define Z_CMP 0x10 +#define Z_UPD 0x20 +#define IM_RD 0x40 +#define CLR_ON_CVG 0x80 +#define CVG_DST_CLAMP 0 +#define CVG_DST_WRAP 0x100 +#define CVG_DST_FULL 0x200 +#define CVG_DST_SAVE 0x300 +#define ZMODE_OPA 0 +#define ZMODE_INTER 0x400 +#define ZMODE_XLU 0x800 +#define ZMODE_DEC 0xc00 +#define CVG_X_ALPHA 0x1000 +#define ALPHA_CVG_SEL 0x2000 +#define FORCE_BL 0x4000 +#define TEX_EDGE 0x0000 /* used to be 0x8000 */ + +#define G_BL_CLR_IN 0 +#define G_BL_CLR_MEM 1 +#define G_BL_CLR_BL 2 +#define G_BL_CLR_FOG 3 +#define G_BL_1MA 0 +#define G_BL_A_MEM 1 +#define G_BL_A_IN 0 +#define G_BL_A_FOG 1 +#define G_BL_A_SHADE 2 +#define G_BL_1 2 +#define G_BL_0 3 + +#define GBL_c1(m1a, m1b, m2a, m2b) \ + (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 +#define GBL_c2(m1a, m1b, m2a, m2b) \ + (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 + +#define RM_AA_ZB_OPA_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_SURF(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_DECAL(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | \ + ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_DECAL(clk) \ + AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \ + ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_DECAL(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + ALPHA_CVG_SEL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ + ALPHA_CVG_SEL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_INTER(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + FORCE_BL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_XLU_LINE(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_DEC_LINE(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_TEX_EDGE(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_TEX_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_SUB_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_PCL_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | G_AC_DITHER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_TEX_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_SUB_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + + +#define RM_AA_OPA_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_OPA_SURF(clk) \ + AA_EN | CVG_DST_CLAMP | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_XLU_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \ + ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_XLU_LINE(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_DEC_LINE(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \ + ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_TEX_EDGE(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_SUB_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_PCL_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | G_AC_DITHER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_OPA_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_TEX_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_SUB_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | \ + ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + + +#define RM_ZB_OPA_SURF(clk) \ + Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | \ + ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_ZB_XLU_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OPA_DECAL(clk) \ + Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_ZB_XLU_DECAL(clk) \ + Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_CLD_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OVL_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_PCL_SURF(clk) \ + Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \ + G_AC_DITHER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + + +#define RM_OPA_SURF(clk) \ + CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_XLU_SURF(clk) \ + IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_TEX_EDGE(clk) \ + CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL |\ + ZMODE_OPA | TEX_EDGE | AA_EN | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_CLD_SURF(clk) \ + IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_PCL_SURF(clk) \ + CVG_DST_FULL | FORCE_BL | ZMODE_OPA | \ + G_AC_DITHER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_ADD(clk) \ + IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) + +#define RM_NOOP(clk) \ + GBL_c##clk(0, 0, 0, 0) + +#define RM_VISCVG(clk) \ + IM_RD | FORCE_BL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) + +/* for rendering to an 8-bit framebuffer */ +#define RM_OPA_CI(clk) \ + CVG_DST_CLAMP | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + + + +#define G_RM_AA_ZB_OPA_SURF RM_AA_ZB_OPA_SURF(1) +#define G_RM_AA_ZB_OPA_SURF2 RM_AA_ZB_OPA_SURF(2) +#define G_RM_AA_ZB_XLU_SURF RM_AA_ZB_XLU_SURF(1) +#define G_RM_AA_ZB_XLU_SURF2 RM_AA_ZB_XLU_SURF(2) +#define G_RM_AA_ZB_OPA_DECAL RM_AA_ZB_OPA_DECAL(1) +#define G_RM_AA_ZB_OPA_DECAL2 RM_AA_ZB_OPA_DECAL(2) +#define G_RM_AA_ZB_XLU_DECAL RM_AA_ZB_XLU_DECAL(1) +#define G_RM_AA_ZB_XLU_DECAL2 RM_AA_ZB_XLU_DECAL(2) +#define G_RM_AA_ZB_OPA_INTER RM_AA_ZB_OPA_INTER(1) +#define G_RM_AA_ZB_OPA_INTER2 RM_AA_ZB_OPA_INTER(2) +#define G_RM_AA_ZB_XLU_INTER RM_AA_ZB_XLU_INTER(1) +#define G_RM_AA_ZB_XLU_INTER2 RM_AA_ZB_XLU_INTER(2) +#define G_RM_AA_ZB_XLU_LINE RM_AA_ZB_XLU_LINE(1) +#define G_RM_AA_ZB_XLU_LINE2 RM_AA_ZB_XLU_LINE(2) +#define G_RM_AA_ZB_DEC_LINE RM_AA_ZB_DEC_LINE(1) +#define G_RM_AA_ZB_DEC_LINE2 RM_AA_ZB_DEC_LINE(2) +#define G_RM_AA_ZB_TEX_EDGE RM_AA_ZB_TEX_EDGE(1) +#define G_RM_AA_ZB_TEX_EDGE2 RM_AA_ZB_TEX_EDGE(2) +#define G_RM_AA_ZB_TEX_INTER RM_AA_ZB_TEX_INTER(1) +#define G_RM_AA_ZB_TEX_INTER2 RM_AA_ZB_TEX_INTER(2) +#define G_RM_AA_ZB_SUB_SURF RM_AA_ZB_SUB_SURF(1) +#define G_RM_AA_ZB_SUB_SURF2 RM_AA_ZB_SUB_SURF(2) +#define G_RM_AA_ZB_PCL_SURF RM_AA_ZB_PCL_SURF(1) +#define G_RM_AA_ZB_PCL_SURF2 RM_AA_ZB_PCL_SURF(2) +#define G_RM_AA_ZB_OPA_TERR RM_AA_ZB_OPA_TERR(1) +#define G_RM_AA_ZB_OPA_TERR2 RM_AA_ZB_OPA_TERR(2) +#define G_RM_AA_ZB_TEX_TERR RM_AA_ZB_TEX_TERR(1) +#define G_RM_AA_ZB_TEX_TERR2 RM_AA_ZB_TEX_TERR(2) +#define G_RM_AA_ZB_SUB_TERR RM_AA_ZB_SUB_TERR(1) +#define G_RM_AA_ZB_SUB_TERR2 RM_AA_ZB_SUB_TERR(2) + +#define G_RM_RA_ZB_OPA_SURF RM_RA_ZB_OPA_SURF(1) +#define G_RM_RA_ZB_OPA_SURF2 RM_RA_ZB_OPA_SURF(2) +#define G_RM_RA_ZB_OPA_DECAL RM_RA_ZB_OPA_DECAL(1) +#define G_RM_RA_ZB_OPA_DECAL2 RM_RA_ZB_OPA_DECAL(2) +#define G_RM_RA_ZB_OPA_INTER RM_RA_ZB_OPA_INTER(1) +#define G_RM_RA_ZB_OPA_INTER2 RM_RA_ZB_OPA_INTER(2) + +#define G_RM_AA_OPA_SURF RM_AA_OPA_SURF(1) +#define G_RM_AA_OPA_SURF2 RM_AA_OPA_SURF(2) +#define G_RM_AA_XLU_SURF RM_AA_XLU_SURF(1) +#define G_RM_AA_XLU_SURF2 RM_AA_XLU_SURF(2) +#define G_RM_AA_XLU_LINE RM_AA_XLU_LINE(1) +#define G_RM_AA_XLU_LINE2 RM_AA_XLU_LINE(2) +#define G_RM_AA_DEC_LINE RM_AA_DEC_LINE(1) +#define G_RM_AA_DEC_LINE2 RM_AA_DEC_LINE(2) +#define G_RM_AA_TEX_EDGE RM_AA_TEX_EDGE(1) +#define G_RM_AA_TEX_EDGE2 RM_AA_TEX_EDGE(2) +#define G_RM_AA_SUB_SURF RM_AA_SUB_SURF(1) +#define G_RM_AA_SUB_SURF2 RM_AA_SUB_SURF(2) +#define G_RM_AA_PCL_SURF RM_AA_PCL_SURF(1) +#define G_RM_AA_PCL_SURF2 RM_AA_PCL_SURF(2) +#define G_RM_AA_OPA_TERR RM_AA_OPA_TERR(1) +#define G_RM_AA_OPA_TERR2 RM_AA_OPA_TERR(2) +#define G_RM_AA_TEX_TERR RM_AA_TEX_TERR(1) +#define G_RM_AA_TEX_TERR2 RM_AA_TEX_TERR(2) +#define G_RM_AA_SUB_TERR RM_AA_SUB_TERR(1) +#define G_RM_AA_SUB_TERR2 RM_AA_SUB_TERR(2) + +#define G_RM_RA_OPA_SURF RM_RA_OPA_SURF(1) +#define G_RM_RA_OPA_SURF2 RM_RA_OPA_SURF(2) + +#define G_RM_ZB_OPA_SURF RM_ZB_OPA_SURF(1) +#define G_RM_ZB_OPA_SURF2 RM_ZB_OPA_SURF(2) +#define G_RM_ZB_XLU_SURF RM_ZB_XLU_SURF(1) +#define G_RM_ZB_XLU_SURF2 RM_ZB_XLU_SURF(2) +#define G_RM_ZB_OPA_DECAL RM_ZB_OPA_DECAL(1) +#define G_RM_ZB_OPA_DECAL2 RM_ZB_OPA_DECAL(2) +#define G_RM_ZB_XLU_DECAL RM_ZB_XLU_DECAL(1) +#define G_RM_ZB_XLU_DECAL2 RM_ZB_XLU_DECAL(2) +#define G_RM_ZB_CLD_SURF RM_ZB_CLD_SURF(1) +#define G_RM_ZB_CLD_SURF2 RM_ZB_CLD_SURF(2) +#define G_RM_ZB_OVL_SURF RM_ZB_OVL_SURF(1) +#define G_RM_ZB_OVL_SURF2 RM_ZB_OVL_SURF(2) +#define G_RM_ZB_PCL_SURF RM_ZB_PCL_SURF(1) +#define G_RM_ZB_PCL_SURF2 RM_ZB_PCL_SURF(2) + +#define G_RM_OPA_SURF RM_OPA_SURF(1) +#define G_RM_OPA_SURF2 RM_OPA_SURF(2) +#define G_RM_XLU_SURF RM_XLU_SURF(1) +#define G_RM_XLU_SURF2 RM_XLU_SURF(2) +#define G_RM_CLD_SURF RM_CLD_SURF(1) +#define G_RM_CLD_SURF2 RM_CLD_SURF(2) +#define G_RM_TEX_EDGE RM_TEX_EDGE(1) +#define G_RM_TEX_EDGE2 RM_TEX_EDGE(2) +#define G_RM_PCL_SURF RM_PCL_SURF(1) +#define G_RM_PCL_SURF2 RM_PCL_SURF(2) +#define G_RM_ADD RM_ADD(1) +#define G_RM_ADD2 RM_ADD(2) +#define G_RM_NOOP RM_NOOP(1) +#define G_RM_NOOP2 RM_NOOP(2) +#define G_RM_VISCVG RM_VISCVG(1) +#define G_RM_VISCVG2 RM_VISCVG(2) +#define G_RM_OPA_CI RM_OPA_CI(1) +#define G_RM_OPA_CI2 RM_OPA_CI(2) + + +#define G_RM_FOG_SHADE_A GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA) +#define G_RM_FOG_PRIM_A GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA) +#define G_RM_PASS GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +/* + * G_SETCONVERT: K0-5 + */ +#define G_CV_K0 175 +#define G_CV_K1 -43 +#define G_CV_K2 -89 +#define G_CV_K3 222 +#define G_CV_K4 114 +#define G_CV_K5 42 + +/* + * G_SETSCISSOR: interlace mode + */ +#define G_SC_NON_INTERLACE 0 +#define G_SC_ODD_INTERLACE 3 +#define G_SC_EVEN_INTERLACE 2 + +/* flags to inhibit pushing of the display list (on branch) */ +#define G_DL_PUSH 0x00 +#define G_DL_NOPUSH 0x01 + +/* + * BEGIN C-specific section: (typedef's) + */ +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * Data Structures + * + * NOTE: + * The DMA transfer hardware requires 64-bit aligned, 64-bit multiple- + * sized transfers. This important hardware optimization is unfortunately + * reflected in the programming interface, with some structures + * padded and alignment enforced. + * + * Since structures are aligned to the boundary of the "worst-case" + * element, we can't depend on the C compiler to align things + * properly. + * + * 64-bit structure alignment is enforced by wrapping structures with + * unions that contain a dummy "long long int". Why this works is + * explained in the ANSI C Spec, or on page 186 of the second edition + * of K&R, "The C Programming Language". + * + * The price we pay for this is a little awkwardness referencing the + * structures through the union. There is no memory penalty, since + * all the structures are at least 64-bits the dummy alignment field + * does not increase the size of the union. + * + * Static initialization of these union structures works because + * the ANSI C spec states that static initialization for unions + * works by using the first union element. We put the dummy alignment + * field last for this reason. + * + * (it's possible a newer 64-bit compiler from MIPS might make this + * easier with a flag, but we can't wait for it...) + * + */ + +/* + * Vertex (set up for use with colors) + */ +typedef struct { + short ob[3]; /* x, y, z */ + unsigned short flag; + short tc[2]; /* texture coord */ + unsigned char cn[4]; /* color & alpha */ +} Vtx_t; + +/* + * Vertex (set up for use with normals) + */ +typedef struct { + short ob[3]; /* x, y, z */ + unsigned short flag; + short tc[2]; /* texture coord */ + signed char n[3]; /* normal */ + unsigned char a; /* alpha */ +} Vtx_tn; + +typedef union { + Vtx_t v; /* Use this one for colors */ + Vtx_tn n; /* Use this one for normals */ + long long int force_structure_alignment; +} Vtx; + +/* + * Sprite structure + */ + +typedef struct { + void *SourceImagePointer; + void *TlutPointer; + short Stride; + short SubImageWidth; + short SubImageHeight; + char SourceImageType; + char SourceImageBitSize; + short SourceImageOffsetS; + short SourceImageOffsetT; + /* 20 bytes for above */ + + /* padding to bring structure size to 64 bit allignment */ + char dummy[4]; + +} uSprite_t; + +typedef union { + uSprite_t s; + + /* Need to make sure this is 64 bit aligned */ + long long int force_structure_allignment[3]; +} uSprite; + +/* + * Triangle face + */ +typedef struct { + unsigned char flag; + unsigned char v[3]; +} Tri; + +/* + * 4x4 matrix, fixed point s15.16 format. + * First 8 words are integer portion of the 4x4 matrix + * Last 8 words are the fraction portion of the 4x4 matrix + */ +typedef long Mtx_t[4][4]; + +typedef union { + Mtx_t m; + long long int force_structure_alignment; +} Mtx; + +/* + * Viewport + */ + +/* + * + * This magic value is the maximum INTEGER z-range of the hardware + * (there are also 16-bits of fraction, which are introduced during + * any transformations). This is not just a good idea, it's the law. + * Feeding the hardware eventual z-coordinates (after any transforms + * or scaling) bigger than this, will not work. + * + * This number is DIFFERENT than G_MAXFBZ, which is the maximum value + * you want to use to initialize the z-buffer. + * + * The reason these are different is mildly interesting, but too long + * to explain here. It is basically the result of optimizations in the + * hardware. A more generic API might hide this detail from the users, + * but we don't have the ucode to do that... + * + */ +#define G_MAXZ 0x03ff /* 10 bits of integer screen-Z precision */ + +/* + * The viewport structure elements have 2 bits of fraction, necessary + * to accomodate the sub-pixel positioning scaling for the hardware. + * This can also be exploited to handle odd-sized viewports. + * + * Accounting for these fractional bits, using the default projection + * and viewing matrices, the viewport structure is initialized thusly: + * + * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, G_MAXZ, 0, + * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, 0, 0, + */ +typedef struct { + short vscale[4]; /* scale, 2 bits fraction */ + short vtrans[4]; /* translate, 2 bits fraction */ + /* both the above arrays are padded to 64-bit boundary */ +} Vp_t; + +typedef union { + Vp_t vp; + long long int force_structure_alignment; +} Vp; + +/* + * MOVEMEM indices + * + * Each of these indexes an entry in a dmem table + * which points to a 1-4 word block of dmem in + * which to store a 1-4 word DMA. + * + */ +#ifdef F3DEX_GBI_2 +/* 0,4 are reserved by G_MTX */ +# define G_MV_MMTX 2 +# define G_MV_PMTX 6 +# define G_MV_VIEWPORT 8 +# define G_MV_LIGHT 10 +# define G_MV_POINT 12 +# define G_MV_MATRIX 14 /* NOTE: this is in moveword table */ +# define G_MVO_LOOKATX (0*24) +# define G_MVO_LOOKATY (1*24) +# define G_MVO_L0 (2*24) +# define G_MVO_L1 (3*24) +# define G_MVO_L2 (4*24) +# define G_MVO_L3 (5*24) +# define G_MVO_L4 (6*24) +# define G_MVO_L5 (7*24) +# define G_MVO_L6 (8*24) +# define G_MVO_L7 (9*24) +#else /* F3DEX_GBI_2 */ +# define G_MV_VIEWPORT 0x80 +# define G_MV_LOOKATY 0x82 +# define G_MV_LOOKATX 0x84 +# define G_MV_L0 0x86 +# define G_MV_L1 0x88 +# define G_MV_L2 0x8a +# define G_MV_L3 0x8c +# define G_MV_L4 0x8e +# define G_MV_L5 0x90 +# define G_MV_L6 0x92 +# define G_MV_L7 0x94 +# define G_MV_TXTATT 0x96 +# define G_MV_MATRIX_1 0x9e /* NOTE: this is in moveword table */ +# define G_MV_MATRIX_2 0x98 +# define G_MV_MATRIX_3 0x9a +# define G_MV_MATRIX_4 0x9c +#endif /* F3DEX_GBI_2 */ + +/* + * MOVEWORD indices + * + * Each of these indexes an entry in a dmem table + * which points to a word in dmem in dmem where + * an immediate word will be stored. + * + */ +#define G_MW_MATRIX 0x00 /* NOTE: also used by movemem */ +#define G_MW_NUMLIGHT 0x02 +#define G_MW_CLIP 0x04 +#define G_MW_SEGMENT 0x06 +#define G_MW_FOG 0x08 +#define G_MW_LIGHTCOL 0x0a +#ifdef F3DEX_GBI_2 +# define G_MW_FORCEMTX 0x0c +#else /* F3DEX_GBI_2 */ +# define G_MW_POINTS 0x0c +#endif /* F3DEX_GBI_2 */ +#define G_MW_PERSPNORM 0x0e + +/* + * These are offsets from the address in the dmem table + */ +#define G_MWO_NUMLIGHT 0x00 +#define G_MWO_CLIP_RNX 0x04 +#define G_MWO_CLIP_RNY 0x0c +#define G_MWO_CLIP_RPX 0x14 +#define G_MWO_CLIP_RPY 0x1c +#define G_MWO_SEGMENT_0 0x00 +#define G_MWO_SEGMENT_1 0x01 +#define G_MWO_SEGMENT_2 0x02 +#define G_MWO_SEGMENT_3 0x03 +#define G_MWO_SEGMENT_4 0x04 +#define G_MWO_SEGMENT_5 0x05 +#define G_MWO_SEGMENT_6 0x06 +#define G_MWO_SEGMENT_7 0x07 +#define G_MWO_SEGMENT_8 0x08 +#define G_MWO_SEGMENT_9 0x09 +#define G_MWO_SEGMENT_A 0x0a +#define G_MWO_SEGMENT_B 0x0b +#define G_MWO_SEGMENT_C 0x0c +#define G_MWO_SEGMENT_D 0x0d +#define G_MWO_SEGMENT_E 0x0e +#define G_MWO_SEGMENT_F 0x0f +#define G_MWO_FOG 0x00 +#define G_MWO_aLIGHT_1 0x00 +#define G_MWO_bLIGHT_1 0x04 +#ifdef F3DEX_GBI_2 +#define G_MWO_aLIGHT_2 0x18 +#define G_MWO_bLIGHT_2 0x1c +#define G_MWO_aLIGHT_3 0x30 +#define G_MWO_bLIGHT_3 0x34 +#define G_MWO_aLIGHT_4 0x48 +#define G_MWO_bLIGHT_4 0x4c +#define G_MWO_aLIGHT_5 0x60 +#define G_MWO_bLIGHT_5 0x64 +#define G_MWO_aLIGHT_6 0x78 +#define G_MWO_bLIGHT_6 0x7c +#define G_MWO_aLIGHT_7 0x90 +#define G_MWO_bLIGHT_7 0x94 +#define G_MWO_aLIGHT_8 0xa8 +#define G_MWO_bLIGHT_8 0xac +#else +#define G_MWO_aLIGHT_2 0x20 +#define G_MWO_bLIGHT_2 0x24 +#define G_MWO_aLIGHT_3 0x40 +#define G_MWO_bLIGHT_3 0x44 +#define G_MWO_aLIGHT_4 0x60 +#define G_MWO_bLIGHT_4 0x64 +#define G_MWO_aLIGHT_5 0x80 +#define G_MWO_bLIGHT_5 0x84 +#define G_MWO_aLIGHT_6 0xa0 +#define G_MWO_bLIGHT_6 0xa4 +#define G_MWO_aLIGHT_7 0xc0 +#define G_MWO_bLIGHT_7 0xc4 +#define G_MWO_aLIGHT_8 0xe0 +#define G_MWO_bLIGHT_8 0xe4 +#endif +#define G_MWO_MATRIX_XX_XY_I 0x00 +#define G_MWO_MATRIX_XZ_XW_I 0x04 +#define G_MWO_MATRIX_YX_YY_I 0x08 +#define G_MWO_MATRIX_YZ_YW_I 0x0c +#define G_MWO_MATRIX_ZX_ZY_I 0x10 +#define G_MWO_MATRIX_ZZ_ZW_I 0x14 +#define G_MWO_MATRIX_WX_WY_I 0x18 +#define G_MWO_MATRIX_WZ_WW_I 0x1c +#define G_MWO_MATRIX_XX_XY_F 0x20 +#define G_MWO_MATRIX_XZ_XW_F 0x24 +#define G_MWO_MATRIX_YX_YY_F 0x28 +#define G_MWO_MATRIX_YZ_YW_F 0x2c +#define G_MWO_MATRIX_ZX_ZY_F 0x30 +#define G_MWO_MATRIX_ZZ_ZW_F 0x34 +#define G_MWO_MATRIX_WX_WY_F 0x38 +#define G_MWO_MATRIX_WZ_WW_F 0x3c +#define G_MWO_POINT_RGBA 0x10 +#define G_MWO_POINT_ST 0x14 +#define G_MWO_POINT_XYSCREEN 0x18 +#define G_MWO_POINT_ZSCREEN 0x1c + +/* + * Light structure. + * + * Note: only directional (infinite) lights are currently supported. + * + * Note: the weird order is for the DMEM alignment benefit of + * the microcode. + * + */ + +typedef struct { + unsigned char col[3]; /* diffuse light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of diffuse light value (rgba) */ + char pad2; + signed char dir[3]; /* direction of light (normalized) */ + char pad3; +} Light_t; + +typedef struct { + unsigned char col[3]; /* ambient light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of ambient light value (rgba) */ + char pad2; +} Ambient_t; + +typedef struct { + int x1,y1,x2,y2; /* texture offsets for highlight 1/2 */ +} Hilite_t; + +typedef union { + Light_t l; + long long int force_structure_alignment[2]; +} Light; + +typedef union { + Ambient_t l; + long long int force_structure_alignment[1]; +} Ambient; + +typedef struct { + Ambient a; + Light l[7]; +} Lightsn; + +typedef struct { + Ambient a; + Light l[1]; +} Lights0; + +typedef struct { + Ambient a; + Light l[1]; +} Lights1; + +typedef struct { + Ambient a; + Light l[2]; +} Lights2; + +typedef struct { + Ambient a; + Light l[3]; +} Lights3; + +typedef struct { + Ambient a; + Light l[4]; +} Lights4; + +typedef struct { + Ambient a; + Light l[5]; +} Lights5; + +typedef struct { + Ambient a; + Light l[6]; +} Lights6; + +typedef struct { + Ambient a; + Light l[7]; +} Lights7; + +typedef struct { + Light l[2]; +} LookAt; + +typedef union { + Hilite_t h; + long int force_structure_alignment[4]; +} Hilite; + +#define gdSPDefLights0(ar,ag,ab) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ { 0, 0, 0},0,{ 0, 0, 0},0,{ 0, 0, 0},0}}} } +#define gdSPDefLights1(ar,ag,ab,r1,g1,b1,x1,y1,z1) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}} } +#define gdSPDefLights2(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \ + {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}} } +#define gdSPDefLights3(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \ + {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \ + {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}} } +#define gdSPDefLights4(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \ + {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \ + {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \ + {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}} } +#define gdSPDefLights5(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4,r5,g5,b5,x5,y5,z5) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \ + {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \ + {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \ + {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}, \ + {{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}} } + + +#define gdSPDefLights6(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4,r5,g5,b5,x5,y5,z5,r6,g6,b6,x6,y6,z6) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \ + {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \ + {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \ + {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}, \ + {{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}, \ + {{ {r6,g6,b6},0,{r6,g6,b6},0,{x6,y6,z6},0}}} } + + +#define gdSPDefLights7(ar,ag,ab,r1,g1,b1,x1,y1,z1,r2,g2,b2,x2,y2,z2,r3,g3,b3,x3,y3,z3,r4,g4,b4,x4,y4,z4,r5,g5,b5,x5,y5,z5,r6,g6,b6,x6,y6,z6,r7,g7,b7,x7,y7,z7) \ + { {{ {ar,ag,ab},0,{ar,ag,ab},0}}, \ + {{{ {r1,g1,b1},0,{r1,g1,b1},0,{x1,y1,z1},0}}, \ + {{ {r2,g2,b2},0,{r2,g2,b2},0,{x2,y2,z2},0}}, \ + {{ {r3,g3,b3},0,{r3,g3,b3},0,{x3,y3,z3},0}}, \ + {{ {r4,g4,b4},0,{r4,g4,b4},0,{x4,y4,z4},0}}, \ + {{ {r5,g5,b5},0,{r5,g5,b5},0,{x5,y5,z5},0}}, \ + {{ {r6,g6,b6},0,{r6,g6,b6},0,{x6,y6,z6},0}}, \ + {{ {r7,g7,b7},0,{r7,g7,b7},0,{x7,y7,z7},0}}} } + + +#define gdSPDefLookAt(rightx,righty,rightz,upx,upy,upz) \ + { {{ {{0,0,0},0,{0,0,0},0,{rightx,righty,rightz},0}}, \ + { {{0,0x80,0},0,{0,0x80,0},0,{upx,upy,upz},0}}} } + +/* + * Graphics DMA Packet + */ +typedef struct { + int cmd:8; + unsigned int par:8; + unsigned int len:16; + unsigned int addr; +} Gdma; + +/* + * Graphics Immediate Mode Packet types + */ +typedef struct { + int cmd:8; + int pad:24; + Tri tri; +} Gtri; + +typedef struct { + int cmd:8; + int pad1:24; + int pad2:24; + unsigned char param:8; +} Gpopmtx; + +/* + * typedef struct { + * int cmd:8; + * int pad0:24; + * int pad1:4; + * int number:4; + * int base:24; + * } Gsegment; + */ +typedef struct { + int cmd:8; + int pad0:8; + int mw_index:8; + int number:8; + int pad1:8; + int base:24; +} Gsegment; + +typedef struct { + int cmd:8; + int pad0:8; + int sft:8; + int len:8; + unsigned int data:32; +} GsetothermodeL; + +typedef struct { + int cmd:8; + int pad0:8; + int sft:8; + int len:8; + unsigned int data:32; +} GsetothermodeH; + +typedef struct { + unsigned char cmd; + unsigned char lodscale; + unsigned char tile; + unsigned char on; + unsigned short s; + unsigned short t; +} Gtexture; + +typedef struct { + int cmd:8; + int pad:24; + Tri line; +} Gline3D; + +typedef struct { + int cmd:8; + int pad1:24; + short int pad2; + short int scale; +} Gperspnorm; + + +/* + * RDP Packet types + */ +typedef struct { + int cmd:8; + unsigned int fmt:3; + unsigned int siz:2; + unsigned int pad:7; + unsigned int wd:12; /* really only 10 bits, extra */ + unsigned int dram; /* to account for 1024 */ +} Gsetimg; + +typedef struct { + int cmd:8; + unsigned int muxs0:24; + unsigned int muxs1:32; +} Gsetcombine; + +typedef struct { + int cmd:8; + unsigned char pad; + unsigned char prim_min_level; + unsigned char prim_level; + unsigned long color; +} Gsetcolor; + +typedef struct { + int cmd:8; + int x0:10; + int x0frac:2; + int y0:10; + int y0frac:2; + unsigned int pad:8; + int x1:10; + int x1frac:2; + int y1:10; + int y1frac:2; +} Gfillrect; + +typedef struct { + int cmd:8; + unsigned int fmt:3; + unsigned int siz:2; + unsigned int pad0:1; + unsigned int line:9; + unsigned int tmem:9; + unsigned int pad1:5; + unsigned int tile:3; + unsigned int palette:4; + unsigned int ct:1; + unsigned int mt:1; + unsigned int maskt:4; + unsigned int shiftt:4; + unsigned int cs:1; + unsigned int ms:1; + unsigned int masks:4; + unsigned int shifts:4; +} Gsettile; + +typedef struct { + int cmd:8; + unsigned int sl:12; + unsigned int tl:12; + int pad:5; + unsigned int tile:3; + unsigned int sh:12; + unsigned int th:12; +} Gloadtile; + +typedef Gloadtile Gloadblock; + +typedef Gloadtile Gsettilesize; + +typedef Gloadtile Gloadtlut; + +typedef struct { + unsigned int cmd:8; /* command */ + unsigned int xl:12; /* X coordinate of upper left */ + unsigned int yl:12; /* Y coordinate of upper left */ + unsigned int pad1:5; /* Padding */ + unsigned int tile:3; /* Tile descriptor index */ + unsigned int xh:12; /* X coordinate of lower right */ + unsigned int yh:12; /* Y coordinate of lower right */ + unsigned int s:16; /* S texture coord at top left */ + unsigned int t:16; /* T texture coord at top left */ + unsigned int dsdx:16;/* Change in S per change in X */ + unsigned int dtdy:16;/* Change in T per change in Y */ +} Gtexrect; + +#define MakeTexRect(xh,yh,flip,tile,xl,yl,s,t,dsdx,dtdy) \ + G_TEXRECT, xh, yh, 0, flip, 0, tile, xl, yl, s, t, dsdx, dtdy + +/* + * Textured rectangles are 128 bits not 64 bits + */ +typedef struct { + unsigned long w0; + unsigned long w1; + unsigned long w2; + unsigned long w3; +} TexRect; + +/* + * Generic Gfx Packet + */ +typedef struct { + unsigned int w0; + unsigned int w1; +} Gwords; + +/* + * This union is the fundamental type of the display list. + * It is, by law, exactly 64 bits in size. + */ +typedef union { + Gwords words; + Gdma dma; + Gtri tri; + Gline3D line; + Gpopmtx popmtx; + Gsegment segment; + GsetothermodeH setothermodeH; + GsetothermodeL setothermodeL; + Gtexture texture; + Gperspnorm perspnorm; + Gsetimg setimg; + Gsetcombine setcombine; + Gsetcolor setcolor; + Gfillrect fillrect; /* use for setscissor also */ + Gsettile settile; + Gloadtile loadtile; /* use for loadblock also, th is dxt */ + Gsettilesize settilesize; + Gloadtlut loadtlut; + long long int force_structure_alignment; +} Gfx; + +/* + * Macros to assemble the graphics display list + */ + +/* + * DMA macros + */ +#define gDma0p(pkt, c, s, l) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \ + _g->words.w1 = (unsigned int)(s); \ +} + +#define gsDma0p(c, s, l) \ +{{ \ + _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (unsigned int)(s) \ +}} + +#define gDma1p(pkt, c, s, l, p) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \ + _SHIFTL((l), 0, 16)); \ + _g->words.w1 = (unsigned int)(s); \ +} + +#define gsDma1p(c, s, l, p) \ +{{ \ + (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \ + _SHIFTL((l), 0, 16)), \ + (unsigned int)(s) \ +}} + +#define gDma2p(pkt, c, adrs, len, idx, ofs) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \ + _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \ + _g->words.w1 = (unsigned int)(adrs); \ +} +#define gsDma2p(c, adrs, len, idx, ofs) \ +{{ \ + (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \ + _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \ + (unsigned int)(adrs) \ +}} + +#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0) +#define gsSPNoOp() gsDma0p(G_SPNOOP, 0, 0) + +#ifdef F3DEX_GBI_2 +# define gSPMatrix(pkt, m, p) \ + gDma2p((pkt),G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0) +# define gsSPMatrix(m, p) \ + gsDma2p( G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0) +#else /* F3DEX_GBI_2 */ +# define gSPMatrix(pkt, m, p) gDma1p(pkt, G_MTX, m, sizeof(Mtx), p) +# define gsSPMatrix(m, p) gsDma1p(G_MTX, m, sizeof(Mtx), p) +#endif /* F3DEX_GBI_2 */ + +#if defined(F3DEX_GBI_2) +/* + * F3DEX_GBI_2: G_VTX GBI format was changed. + * + * +--------+----+---+---+----+------+-+ + * G_VTX | cmd:8 |0000| n:8 |0000|v0+n:7|0| + * +-+---+--+----+---+---+----+------+-+ + * | |seg| address | + * +-+---+-----------------------------+ + */ +# define gSPVertex(pkt, v, n, v0) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = \ + _SHIFTL(G_VTX,24,8)|_SHIFTL((n),12,8)|_SHIFTL((v0)+(n),1,7); \ + _g->words.w1 = (unsigned int)(v); \ +} +# define gsSPVertex(v, n, v0) \ +{{ \ + (_SHIFTL(G_VTX,24,8)|_SHIFTL((n),12,8)|_SHIFTL((v0)+(n),1,7)), \ + (unsigned int)(v) \ +}} +#elif (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +/* + * F3DEX_GBI: G_VTX GBI format was changed to support 64 vertice. + * + * +--------+--------+------+----------+ + * G_VTX | cmd:8 | v0:8 | n:6 |length:10 | + * +-+---+--+--------+------+----------+ + * | |seg| address | + * +-+---+-----------------------------+ + */ +# define gSPVertex(pkt, v, n, v0) \ + gDma1p((pkt),G_VTX,(v),((n)<<10)|(sizeof(Vtx)*(n)-1),(v0)*2) +# define gsSPVertex(v, n, v0) \ + gsDma1p(G_VTX,(v),((n)<<10)|(sizeof(Vtx)*(n)-1),(v0)*2) +#else +# define gSPVertex(pkt, v, n, v0) \ + gDma1p(pkt, G_VTX, v, sizeof(Vtx)*(n),((n)-1)<<4|(v0)) +# define gsSPVertex(v, n, v0) \ + gsDma1p(G_VTX, v, sizeof(Vtx)*(n), ((n)-1)<<4|(v0)) +#endif + + +#ifdef F3DEX_GBI_2 +# define gSPViewport(pkt, v) \ + gDma2p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0) +# define gsSPViewport(v) \ + gsDma2p( G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0) +#else /* F3DEX_GBI_2 */ +# define gSPViewport(pkt,v) \ + gDma1p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT) +# define gsSPViewport(v) \ + gsDma1p( G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT) +#endif /* F3DEX_GBI_2 */ + +#define gSPDisplayList(pkt,dl) gDma1p(pkt,G_DL,dl,0,G_DL_PUSH) +#define gsSPDisplayList( dl) gsDma1p( G_DL,dl,0,G_DL_PUSH) + +#define gSPBranchList(pkt,dl) gDma1p(pkt,G_DL,dl,0,G_DL_NOPUSH) +#define gsSPBranchList( dl) gsDma1p( G_DL,dl,0,G_DL_NOPUSH) + +#define gSPSprite2DBase(pkt, s) gDma1p(pkt, G_SPRITE2D_BASE, s, sizeof(uSprite), 0) +#define gsSPSprite2DBase(s) gsDma1p(G_SPRITE2D_BASE, s, sizeof(uSprite), 0) + +/* + * RSP short command (no DMA required) macros + */ +#define gImmp0(pkt, c) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ +} + +#define gsImmp0(c) \ +{{ \ + _SHIFTL((c), 24, 8) \ +}} + +#define gImmp1(pkt, c, p0) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + _g->words.w1 = (unsigned int)(p0); \ +} + +#define gsImmp1(c, p0) \ +{{ \ + _SHIFTL((c), 24, 8), (unsigned int)(p0) \ +}} + +#define gImmp2(pkt, c, p0, p1) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + _g->words.w1 = _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8); \ +} + +#define gsImmp2(c, p0, p1) \ +{{ \ + _SHIFTL((c), 24, 8), _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8)\ +}} + +#define gImmp3(pkt, c, p0, p1, p2) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + _g->words.w1 = (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) | \ + _SHIFTL((p2), 0, 8)); \ +} + +#define gsImmp3(c, p0, p1, p2) \ +{{ \ + _SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) | \ + _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8))\ +}} + +#define gImmp21(pkt, c, p0, p1, dat) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \ + _SHIFTL((p1), 0, 8)); \ + _g->words.w1 = (unsigned int) (dat); \ +} + +#define gsImmp21(c, p0, p1, dat) \ +{{ \ + _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8),\ + (unsigned int) (dat) \ +}} + +#ifdef F3DEX_GBI_2 +#define gMoveWd(pkt, index, offset, data) \ + gDma1p((pkt), G_MOVEWORD, data, offset, index) +#define gsMoveWd( index, offset, data) \ + gsDma1p( G_MOVEWORD, data, offset, index) +#else /* F3DEX_GBI_2 */ +#define gMoveWd(pkt, index, offset, data) \ + gImmp21((pkt), G_MOVEWORD, offset, index, data) +#define gsMoveWd( index, offset, data) \ + gsImmp21( G_MOVEWORD, offset, index, data) +#endif /* F3DEX_GBI_2 */ + +/* Sprite immediate macros, there is also a sprite dma macro above */ + +#define gSPSprite2DScaleFlip(pkt, sx, sy, fx, fy) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | \ + _SHIFTL((fx), 8, 8) | \ + _SHIFTL((fy), 0, 8)); \ + _g->words.w1 = (_SHIFTL((sx), 16, 16) | \ + _SHIFTL((sy), 0, 16)); \ +} + +#define gsSPSprite2DScaleFlip(sx, sy, fx, fy) \ +{{ \ + (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | \ + _SHIFTL((fx), 8, 8) | \ + _SHIFTL((fy), 0, 8)), \ + (_SHIFTL((sx), 16, 16) | \ + _SHIFTL((sy), 0, 16)) \ +}} + +#define gSPSprite2DDraw(pkt, px, py) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)); \ + _g->words.w1 = (_SHIFTL((px), 16, 16) | \ + _SHIFTL((py), 0, 16)); \ +} + +#define gsSPSprite2DDraw(px, py) \ +{{ \ + (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)), \ + (_SHIFTL((px), 16, 16) | \ + _SHIFTL((py), 0, 16)) \ +}} + + +/* + * Note: the SP1Triangle() and line macros multiply the vertex indices + * by 10, this is an optimization for the microcode. + */ +#if (defined(F3DLP_GBI)||defined(F3DEX_GBI)) +# define __gsSP1Triangle_w1(v0, v1, v2) \ + (_SHIFTL((v0)*2,16,8)|_SHIFTL((v1)*2,8,8)|_SHIFTL((v2)*2,0,8)) +# define __gsSP1Triangle_w1f(v0, v1, v2, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2): \ + ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v0): \ + __gsSP1Triangle_w1(v2, v0, v1)) +# define __gsSPLine3D_w1(v0, v1, wd) \ + (_SHIFTL((v0)*2,16,8)|_SHIFT((v1)*2,8,8)|_SHIFT((wd),0,8)) +# define __gsSPLine3D_w1f(v0, v1, wd, flag) \ + (((flag) == 0) ? __gsSPLine3D_w1(v0, v1, wd): \ + __gsSPLine3D_w1(v1, v0, wd)) +# define __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2): \ + ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v3): \ + ((flag) == 2) ? __gsSP1Triangle_w1(v2, v3, v0): \ + __gsSP1Triangle_w1(v3, v0, v1)) +# define __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1(v0, v2, v3): \ + ((flag) == 1) ? __gsSP1Triangle_w1(v1, v3, v0): \ + ((flag) == 2) ? __gsSP1Triangle_w1(v2, v0, v1): \ + __gsSP1Triangle_w1(v3, v1, v2)) +#else +# define __gsSP1Triangle_w1f(v0, v1, v2, flag) \ + (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \ + _SHIFTL((v1)*10, 8,8)|_SHIFTL((v2)*10, 0,8)) +# define __gsSPLine3D_w1f(v0, v1, wd, flag) \ + (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \ + _SHIFTL((v1)*10, 8,8)|_SHIFTL((wd), 0,8)) +#endif + +#ifdef F3DEX_GBI_2 +/*** + *** 1 Triangle + ***/ +#define gSP1Triangle(pkt, v0, v1, v2, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_TRI1, 24, 8)| \ + __gsSP1Triangle_w1f(v0, v1, v2, flag); \ + _g->words.w1 = 0; \ +} +#define gsSP1Triangle(v0, v1, v2, flag) \ +{{ \ + _SHIFTL(G_TRI1, 24, 8)|__gsSP1Triangle_w1f(v0, v1, v2, flag), \ + 0 \ +}} + +/*** + *** Line + ***/ +#define gSPLine3D(pkt, v0, v1, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8)| \ + __gsSPLine3D_w1f(v0, v1, 0, flag); \ + _g->words.w1 = 0; \ +} +#define gsSPLine3D(v0, v1, flag) \ +{{ \ + _SHIFTL(G_LINE3D, 24, 8)|__gsSPLine3D_w1f(v0, v1, 0, flag), \ + 0 \ +}} + +/*** + *** LineW + ***/ +/* these macros are the same as SPLine3D, except they have an + * additional parameter for width. The width is added to the "minimum" + * thickness, which is 1.5 pixels. The units for width are in + * half-pixel units, so a width of 1 translates to (.5 + 1.5) or + * a 2.0 pixels wide line. + */ +#define gSPLineW3D(pkt, v0, v1, wd, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8)| \ + __gsSPLine3D_w1f(v0, v1, wd, flag); \ + _g->words.w1 = 0; \ +} +#define gsSPLineW3D(v0, v1, wd, flag) \ +{{ \ + _SHIFTL(G_LINE3D, 24, 8)|__gsSPLine3D_w1f(v0, v1, wd, flag), \ + 0 \ +}} + +/*** + *** 1 Quadrangle + ***/ +#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_QUAD, 24, 8)| \ + __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \ + _g->words.w1 = __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \ +} + +#define gsSP1Quadrangle(v0, v1, v2, v3, flag) \ +{{ \ + (_SHIFTL(G_QUAD, 24, 8)| \ + __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \ + __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \ +}} +#else /* F3DEX_GBI_2 */ + +/*** + *** 1 Triangle + ***/ +#define gSP1Triangle(pkt, v0, v1, v2, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_TRI1, 24, 8); \ + _g->words.w1 = __gsSP1Triangle_w1f(v0, v1, v2, flag); \ +} +#define gsSP1Triangle(v0, v1, v2, flag) \ +{{ \ + _SHIFTL(G_TRI1, 24, 8), \ + __gsSP1Triangle_w1f(v0, v1, v2, flag) \ +}} + +/*** + *** Line + ***/ +#define gSPLine3D(pkt, v0, v1, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8); \ + _g->words.w1 = __gsSPLine3D_w1f(v0, v1, 0, flag); \ +} +#define gsSPLine3D(v0, v1, flag) \ +{{ \ + _SHIFTL(G_LINE3D, 24, 8), \ + __gsSPLine3D_w1f(v0, v1, 0, flag) \ +}} + +/*** + *** LineW + ***/ +/* these macros are the same as SPLine3D, except they have an + * additional parameter for width. The width is added to the "minimum" + * thickness, which is 1.5 pixels. The units for width are in + * half-pixel units, so a width of 1 translates to (.5 + 1.5) or + * a 2.0 pixels wide line. + */ +#define gSPLineW3D(pkt, v0, v1, wd, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8); \ + _g->words.w1 = __gsSPLine3D_w1f(v0, v1, wd, flag); \ +} +#define gsSPLineW3D(v0, v1, wd, flag) \ +{{ \ + _SHIFTL(G_LINE3D, 24, 8), \ + __gsSPLine3D_w1f(v0, v1, wd, flag) \ +}} + +/*** + *** 1 Quadrangle + ***/ +#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)| \ + __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \ + _g->words.w1 = __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \ +} + +#define gsSP1Quadrangle(v0, v1, v2, v3, flag) \ +{{ \ + (_SHIFTL(G_TRI2, 24, 8)| \ + __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \ + __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \ +}} +#endif /* F3DEX_GBI_2 */ + +#if (defined(F3DLP_GBI)||defined(F3DEX_GBI)) +/*** + *** 2 Triangles + ***/ +#define gSP2Triangles(pkt, v00, v01, v02, flag0, v10, v11, v12, flag1) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8)| \ + __gsSP1Triangle_w1f(v00, v01, v02, flag0)); \ + _g->words.w1 = __gsSP1Triangle_w1f(v10, v11, v12, flag1); \ +} + +#define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1) \ +{{ \ + (_SHIFTL(G_TRI2, 24, 8)| \ + __gsSP1Triangle_w1f(v00, v01, v02, flag0)), \ + __gsSP1Triangle_w1f(v10, v11, v12, flag1) \ +}} + +#endif /* F3DEX_GBI/F3DLP_GBI */ + +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +#define gSPCullDisplayList(pkt,vstart,vend) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \ + _SHIFTL((vstart)*2, 0, 16); \ + _g->words.w1 = _SHIFTL((vend)*2, 0, 16); \ +} + +#define gsSPCullDisplayList(vstart,vend) \ +{{ \ + _SHIFTL(G_CULLDL, 24, 8) | _SHIFTL((vstart)*2, 0, 16), \ + _SHIFTL((vend)*2, 0, 16) \ +}} + +#else +#define gSPCullDisplayList(pkt,vstart,vend) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \ + ((0x0f & (vstart))*40); \ + _g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40); \ +} + +#define gsSPCullDisplayList(vstart,vend) \ +{{ \ + _SHIFTL(G_CULLDL, 24, 8) | ((0x0f & (vstart))*40), \ + ((0x0f & ((vend)+1))*40) \ +}} +#endif + +#define gSPSegment(pkt, segment, base) \ + gMoveWd(pkt, G_MW_SEGMENT, (segment)*4, base) +#define gsSPSegment(segment, base) \ + gsMoveWd( G_MW_SEGMENT, (segment)*4, base) + +/* + * Clipping Macros + */ +#define FR_NEG_FRUSTRATIO_1 0x00000001 +#define FR_POS_FRUSTRATIO_1 0x0000ffff +#define FR_NEG_FRUSTRATIO_2 0x00000002 +#define FR_POS_FRUSTRATIO_2 0x0000fffe +#define FR_NEG_FRUSTRATIO_3 0x00000003 +#define FR_POS_FRUSTRATIO_3 0x0000fffd +#define FR_NEG_FRUSTRATIO_4 0x00000004 +#define FR_POS_FRUSTRATIO_4 0x0000fffc +#define FR_NEG_FRUSTRATIO_5 0x00000005 +#define FR_POS_FRUSTRATIO_5 0x0000fffb +#define FR_NEG_FRUSTRATIO_6 0x00000006 +#define FR_POS_FRUSTRATIO_6 0x0000fffa +/* + * r should be one of: FRUSTRATIO_1, FRUSTRATIO_2, FRUSTRATIO_3, ... FRUSTRATIO_6 + */ +#define gSPClipRatio(pkt, r) \ +{ \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r); \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r); \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r); \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r); \ +} + +#define gsSPClipRatio(r) \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r) + +/* + * Insert values into Matrix + * + * where = element of matrix (byte offset) + * num = new element (32 bit value replacing 2 int or 2 frac matrix + * componants + */ +#ifdef F3DEX_GBI_2 +#define gSPInsertMatrix(pkt, where, num) \ + ERROR!! gSPInsertMatrix is no longer supported. +#define gsSPInsertMatrix(where, num) \ + ERROR!! gsSPInsertMatrix is no longer supported. +#else +#define gSPInsertMatrix(pkt, where, num) \ + gMoveWd(pkt, G_MW_MATRIX, where, num) +#define gsSPInsertMatrix(where, num) \ + gsMoveWd(G_MW_MATRIX, where, num) +#endif + +/* + * Load new matrix directly + * + * mptr = pointer to matrix + */ +#ifdef F3DEX_GBI_2 +#define gSPForceMatrix(pkt, mptr) \ +{ gDma2p((pkt),G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0); \ + gMoveWd((pkt), G_MW_FORCEMTX,0,0x00010000); \ +} +#define gsSPForceMatrix(mptr) \ + gsDma2p(G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0), \ + gsMoveWd(G_MW_FORCEMTX,0,0x00010000) + +#else /* F3DEX_GBI_2 */ +#define gSPForceMatrix(pkt, mptr) \ +{ \ + gDma1p(pkt, G_MOVEMEM, mptr, 16, G_MV_MATRIX_1); \ + gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2); \ + gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3); \ + gDma1p(pkt, G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4); \ +} +#define gsSPForceMatrix(mptr) \ + gsDma1p( G_MOVEMEM, mptr, 16, G_MV_MATRIX_1), \ + gsDma1p( G_MOVEMEM, (char *)(mptr)+16, 16, G_MV_MATRIX_2), \ + gsDma1p( G_MOVEMEM, (char *)(mptr)+32, 16, G_MV_MATRIX_3), \ + gsDma1p( G_MOVEMEM, (char *)(mptr)+48, 16, G_MV_MATRIX_4) +#endif /* F3DEX_GBI_2 */ + +/* + * Insert values into Points + * + * point = point number 0-15 + * where = which element of point to modify (byte offset into point) + * num = new value (32 bit) + */ +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +# define gSPModifyVertex(pkt, vtx, where, val) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL(G_MODIFYVTX,24,8)| \ + _SHIFTL((where),16,8)|_SHIFTL((vtx)*2,0,16)); \ + _g->words.w1 = (unsigned int)(val); \ +} +# define gsSPModifyVertex(vtx, where, val) \ +{{ \ + _SHIFTL(G_MODIFYVTX,24,8)| \ + _SHIFTL((where),16,8)|_SHIFTL((vtx)*2,0,16), \ + (unsigned int)(val) \ +}} +#else +# define gSPModifyVertex(pkt, vtx, where, val) \ + gMoveWd(pkt, G_MW_POINTS, (vtx)*40+(where), val) +# define gsSPModifyVertex(vtx, where, val) \ + gsMoveWd(G_MW_POINTS, (vtx)*40+(where), val) +#endif + +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)) +/* + * gSPBranchLessZ Branch DL if (vtx.z) less than or equal (zval). + * + * dl = DL branch to + * vtx = Vertex + * zval = Screen depth + * near = Near plane + * far = Far plane + * flag = G_BZ_PERSP or G_BZ_ORTHO + */ + +#define G_BZ_PERSP 0 +#define G_BZ_ORTHO 1 + +#define G_DEPTOZSrg(zval, near, far, flag, zmin, zmax) \ +(((unsigned int)FTOFIX32(((flag) == G_BZ_PERSP ? \ + (1.0f-(float)(near)/(float)(zval)) / \ + (1.0f-(float)(near)/(float)(far )) : \ + ((float)(zval) - (float)(near)) / \ + ((float)(far ) - (float)(near))))) * \ + (((int)((zmax) - (zmin)))&~1) + (int)FTOFIX32(zmin)) + +#define G_DEPTOZS(zval, near, far, flag) \ + G_DEPTOZSrg(zval, near, far, flag, 0, G_MAXZ) + +#define gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, zmin, zmax) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8); \ + _g->words.w1 = (unsigned int)(dl); \ + _g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL(G_BRANCH_Z,24,8)| \ + _SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12)); \ + _g->words.w1 = G_DEPTOZSrg(zval, near, far, flag, zmin, zmax); \ +} + +#define gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, zmin, zmax) \ +{{ _SHIFTL(G_RDPHALF_1,24,8), \ + (unsigned int)(dl), }}, \ +{{ _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\ + G_DEPTOZSrg(zval, near, far, flag, zmin, zmax), }} + +#define gSPBranchLessZ(pkt, dl, vtx, zval, near, far, flag) \ + gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, 0, G_MAXZ) +#define gsSPBranchLessZ(dl, vtx, zval, near, far, flag) \ + gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, 0, G_MAXZ) + +/* + * gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval). + * + * dl = DL branch to + * vtx = Vertex + * zval = Raw value of screen depth + */ +#define gSPBranchLessZraw(pkt, dl, vtx, zval) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8); \ + _g->words.w1 = (unsigned int)(dl); \ + _g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL(G_BRANCH_Z,24,8)| \ + _SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12)); \ + _g->words.w1 = (unsigned int)(zval); \ +} + +#define gsSPBranchLessZraw(dl, vtx, zval) \ +{{ _SHIFTL(G_RDPHALF_1,24,8), \ + (unsigned int)(dl), }}, \ +{{ _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\ + (unsigned int)(zval), }} + +/* + * gSPLoadUcode RSP loads specified ucode. + * + * uc_start = ucode text section start + * uc_dstart = ucode data section start + */ +#define gSPLoadUcodeEx(pkt, uc_start, uc_dstart, uc_dsize) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = _SHIFTL(G_RDPHALF_1,24,8); \ + _g->words.w1 = (unsigned int)(uc_dstart); \ + _g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL(G_LOAD_UCODE,24,8)| \ + _SHIFTL((int)(uc_dsize)-1,0,16)); \ + _g->words.w1 = (unsigned int)(uc_start); \ +} + +#define gsSPLoadUcodeEx(uc_start, uc_dstart, uc_dsize) \ +{{ _SHIFTL(G_RDPHALF_1,24,8), \ + (unsigned int)(uc_dstart), }}, \ +{{ _SHIFTL(G_LOAD_UCODE,24,8)| \ + _SHIFTL((int)(uc_dsize)-1,0,16), \ + (unsigned int)(uc_start), }} + +#define gSPLoadUcode(pkt, uc_start, uc_dstart) \ + gSPLoadUcodeEx((pkt), (uc_start), (uc_dstart), SP_UCODE_DATA_SIZE) +#define gsSPLoadUcode(uc_start, uc_dstart) \ + gsSPLoadUcodeEx((uc_start), (uc_dstart), SP_UCODE_DATA_SIZE) + +#define gSPLoadUcodeL(pkt, ucode) \ + gSPLoadUcode((pkt), OS_K0_TO_PHYSICAL(&##ucode##TextStart), \ + OS_K0_TO_PHYSICAL(&##ucode##DataStart)) +#define gsSPLoadUcodeL(ucode) \ + gsSPLoadUcode(OS_K0_TO_PHYSICAL(&##ucode##TextStart), \ + OS_K0_TO_PHYSICAL(&##ucode##DataStart)) +#endif + +#ifdef F3DEX_GBI_2 +/* + * gSPDma_io DMA to/from DMEM/IMEM for DEBUG. + */ +#define gSPDma_io(pkt, flag, dmem, dram, size) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = _SHIFTL(G_DMA_IO,24,8)|_SHIFTL((flag),23,1)| \ + _SHIFTL((dmem)/8,13,10)|_SHIFTL((size)-1,0,12); \ + _g->words.w1 = (unsigned int)(dram); \ +} + +#define gsSPDma_io(flag, dmem, dram, size) \ +{{ \ + _SHIFTL(G_DMA_IO,24,8)|_SHIFTL((flag),23,1)| \ + _SHIFTL((dmem)/8,13,10)|_SHIFTL((size)-1,0,12), \ + (unsigned int)(dram) \ +}} + +#define gSPDmaRead(pkt,dmem,dram,size) gSPDma_io((pkt),0,(dmem),(dram),(size)) +#define gsSPDmaRead(dmem,dram,size) gsSPDma_io(0,(dmem),(dram),(size)) +#define gSPDmaWrite(pkt,dmem,dram,size) gSPDma_io((pkt),1,(dmem),(dram),(size)) +#define gsSPDmaWrite(dmem,dram,size) gsSPDma_io(1,(dmem),(dram),(size)) +#endif + +/* + * Lighting Macros + */ +#ifdef F3DEX_GBI_2 +# define NUML(n) ((n)*24) +#else +# define NUML(n) (((n)+1)*32 + 0x80000000) +#endif +#define NUMLIGHTS_0 1 +#define NUMLIGHTS_1 1 +#define NUMLIGHTS_2 2 +#define NUMLIGHTS_3 3 +#define NUMLIGHTS_4 4 +#define NUMLIGHTS_5 5 +#define NUMLIGHTS_6 6 +#define NUMLIGHTS_7 7 +/* + * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7 + * NOTE: in addition to the number of directional lights specified, + * there is always 1 ambient light + */ +#define gSPNumLights(pkt, n) \ + gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n)) +#define gsSPNumLights(n) \ + gsMoveWd( G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n)) + +#define LIGHT_1 1 +#define LIGHT_2 2 +#define LIGHT_3 3 +#define LIGHT_4 4 +#define LIGHT_5 5 +#define LIGHT_6 6 +#define LIGHT_7 7 +#define LIGHT_8 8 +/* + * l should point to a Light struct + * n should be one of: LIGHT_1, LIGHT_2, ..., LIGHT_8 + * NOTE: the highest numbered light is always the ambient light (eg if there are + * 3 directional lights defined: gsSPNumLights(NUMLIGHTS_3), then lights + * LIGHT_1 through LIGHT_3 will be the directional lights and light + * LIGHT_4 will be the ambient light. + */ +#ifdef F3DEX_GBI_2 +# define gSPLight(pkt, l, n) \ + gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,(n)*24+24) +# define gsSPLight(l, n) \ + gsDma2p( G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,(n)*24+24) +#else /* F3DEX_GBI_2 */ +# define gSPLight(pkt, l, n) \ + gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0) +# define gsSPLight(l, n) \ + gsDma1p( G_MOVEMEM, l, sizeof(Light),((n)-1)*2+G_MV_L0) +#endif /* F3DEX_GBI_2 */ + +/* + * gSPLightColor changes color of light without recalculating light direction + * col is a 32 bit word with r,g,b,a (alpha is ignored) + * n should be one of LIGHT_1, LIGHT_2, ..., LIGHT_8 + */ +#define gSPLightColor(pkt, n, col) \ +{ \ + gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_a##n, col); \ + gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_b##n, col); \ +} +#define gsSPLightColor(n, col) \ + gsMoveWd(G_MW_LIGHTCOL, G_MWO_a##n, col), \ + gsMoveWd(G_MW_LIGHTCOL, G_MWO_b##n, col) + +/* These macros use a structure "name" which is init'd with the gdSPDefLights macros*/ + +#define gSPSetLights0(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_0); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.a,2); \ +} +#define gsSPSetLights0(name) \ + gsSPNumLights(NUMLIGHTS_0), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.a,2) + +#define gSPSetLights1(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_1); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.a,2); \ +} +#define gsSPSetLights1(name) \ + gsSPNumLights(NUMLIGHTS_1), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.a,2) + +#define gSPSetLights2(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_2); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.l[1],2); \ + gSPLight(pkt,&name.a,3); \ +} +#define gsSPSetLights2(name) \ + gsSPNumLights(NUMLIGHTS_2), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.l[1],2), \ + gsSPLight(&name.a,3) + +#define gSPSetLights3(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_3); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.l[1],2); \ + gSPLight(pkt,&name.l[2],3); \ + gSPLight(pkt,&name.a,4); \ +} +#define gsSPSetLights3(name) \ + gsSPNumLights(NUMLIGHTS_3), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.l[1],2), \ + gsSPLight(&name.l[2],3), \ + gsSPLight(&name.a,4) + +#define gSPSetLights4(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_4); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.l[1],2); \ + gSPLight(pkt,&name.l[2],3); \ + gSPLight(pkt,&name.l[3],4); \ + gSPLight(pkt,&name.a,5); \ +} +#define gsSPSetLights4(name) \ + gsSPNumLights(NUMLIGHTS_4), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.l[1],2), \ + gsSPLight(&name.l[2],3), \ + gsSPLight(&name.l[3],4), \ + gsSPLight(&name.a,5) + +#define gSPSetLights5(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_5); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.l[1],2); \ + gSPLight(pkt,&name.l[2],3); \ + gSPLight(pkt,&name.l[3],4); \ + gSPLight(pkt,&name.l[4],5); \ + gSPLight(pkt,&name.a,6); \ +} + +#define gsSPSetLights5(name) \ + gsSPNumLights(NUMLIGHTS_5), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.l[1],2), \ + gsSPLight(&name.l[2],3), \ + gsSPLight(&name.l[3],4), \ + gsSPLight(&name.l[4],5), \ + gsSPLight(&name.a,6) + +#define gSPSetLights6(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_6); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.l[1],2); \ + gSPLight(pkt,&name.l[2],3); \ + gSPLight(pkt,&name.l[3],4); \ + gSPLight(pkt,&name.l[4],5); \ + gSPLight(pkt,&name.l[5],6); \ + gSPLight(pkt,&name.a,7); \ +} + +#define gsSPSetLights6(name) \ + gsSPNumLights(NUMLIGHTS_6), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.l[1],2), \ + gsSPLight(&name.l[2],3), \ + gsSPLight(&name.l[3],4), \ + gsSPLight(&name.l[4],5), \ + gsSPLight(&name.l[5],6), \ + gsSPLight(&name.a,7) + +#define gSPSetLights7(pkt,name) \ +{ \ + gSPNumLights(pkt,NUMLIGHTS_7); \ + gSPLight(pkt,&name.l[0],1); \ + gSPLight(pkt,&name.l[1],2); \ + gSPLight(pkt,&name.l[2],3); \ + gSPLight(pkt,&name.l[3],4); \ + gSPLight(pkt,&name.l[4],5); \ + gSPLight(pkt,&name.l[5],6); \ + gSPLight(pkt,&name.l[6],7); \ + gSPLight(pkt,&name.a,8); \ +} + +#define gsSPSetLights7(name) \ + gsSPNumLights(NUMLIGHTS_7), \ + gsSPLight(&name.l[0],1), \ + gsSPLight(&name.l[1],2), \ + gsSPLight(&name.l[2],3), \ + gsSPLight(&name.l[3],4), \ + gsSPLight(&name.l[4],5), \ + gsSPLight(&name.l[5],6), \ + gsSPLight(&name.l[6],7), \ + gsSPLight(&name.a,8) + +/* + * Reflection/Hiliting Macros + */ +#ifdef F3DEX_GBI_2 +# define gSPLookAtX(pkt, l) \ + gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATX) +# define gsSPLookAtX(l) \ + gsDma2p( G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATX) +# define gSPLookAtY(pkt, l) \ + gDma2p((pkt),G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATY) +# define gsSPLookAtY(l) \ + gsDma2p( G_MOVEMEM,(l),sizeof(Light),G_MV_LIGHT,G_MVO_LOOKATY) +#else /* F3DEX_GBI_2 */ +# define gSPLookAtX(pkt, l) \ + gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX) +# define gsSPLookAtX(l) \ + gsDma1p( G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATX) +# define gSPLookAtY(pkt, l) \ + gDma1p(pkt, G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY) +# define gsSPLookAtY(l) \ + gsDma1p( G_MOVEMEM, l, sizeof(Light),G_MV_LOOKATY) +#endif /* F3DEX_GBI_2 */ + +#define gSPLookAt(pkt, la) \ +{ \ + gSPLookAtX(pkt,la) \ + gSPLookAtY(pkt,(char *)(la)+16) \ +} +#define gsSPLookAt(la) \ + gsSPLookAtX(la), \ + gsSPLookAtY((char *)(la)+16) + +#define gDPSetHilite1Tile(pkt, tile, hilite, width, height) \ + gDPSetTileSize(pkt, tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff, \ + ((((width)-1)*4)+(hilite)->h.x1) & 0xfff, ((((height)-1)*4)+(hilite)->h.y1) & 0xfff) + +#define gDPSetHilite2Tile(pkt, tile, hilite, width, height) \ + gDPSetTileSize(pkt, tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff, \ + ((((width)-1)*4)+(hilite)->h.x2) & 0xfff, ((((height)-1)*4)+(hilite)->h.y2) & 0xfff) + + +/* + * FOG macros + * fm = z multiplier + * fo = z offset + * FOG FORMULA: alpha(fog) = (eyespace z) * fm + fo CLAMPED 0 to 255 + * note: (eyespace z) ranges -1 to 1 + * + * Alternate method of setting fog: + * min, max: range 0 to 1000: 0=nearplane, 1000=farplane + * min is where fog begins (usually less than max and often 0) + * max is where fog is thickest (usually 1000) + * + */ +#define gSPFogFactor(pkt, fm, fo) \ + gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \ + (_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16))) + +#define gsSPFogFactor(fm, fo) \ + gsMoveWd(G_MW_FOG, G_MWO_FOG, \ + (_SHIFTL(fm,16,16) | _SHIFTL(fo,0,16))) + +#define gSPFogPosition(pkt, min, max) \ + gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \ + (_SHIFTL((128000/((max)-(min))),16,16) | \ + _SHIFTL(((500-(min))*256/((max)-(min))),0,16))) + +#define gsSPFogPosition(min, max) \ + gsMoveWd(G_MW_FOG, G_MWO_FOG, \ + (_SHIFTL((128000/((max)-(min))),16,16) | \ + _SHIFTL(((500-(min))*256/((max)-(min))),0,16))) + +#ifdef F3DEX_GBI_2 +/* + * Macros to turn texture on/off + */ +# define gSPTexture(pkt, s, t, level, tile, on) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8) | \ + _SHIFTL(BOWTIE_VAL,16,8) | \ + _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | \ + _SHIFTL((on),1,7)); \ + _g->words.w1 = (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)); \ +} +# define gsSPTexture(s, t, level, tile, on) \ +{{ \ + (_SHIFTL(G_TEXTURE,24,8) | _SHIFTL(BOWTIE_VAL,16,8) | \ + _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\ + (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)) \ +}} +/* + * Different version of SPTexture macro, has an additional parameter + * which is currently reserved in the microcode. + */ +# define gSPTextureL(pkt, s, t, level, xparam, tile, on) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8) | \ + _SHIFTL((xparam),16,8) | \ + _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | \ + _SHIFTL((on),1,7)); \ + _g->words.w1 = (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)); \ +} +# define gsSPTextureL(s, t, level, xparam, tile, on) \ +{{ \ + (_SHIFTL(G_TEXTURE,24,8) | _SHIFTL((xparam),16,8) | \ + _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\ + (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)) \ +}} +#else +/* + * Macros to turn texture on/off + */ +# define gSPTexture(pkt, s, t, level, tile, on) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL(BOWTIE_VAL,16,8)|\ + _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)| \ + _SHIFTL((on),0,8)); \ + _g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)); \ +} +# define gsSPTexture(s, t, level, tile, on) \ +{{ \ + (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL(BOWTIE_VAL,16,8)| \ + _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \ + (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)) \ +}} +/* + * Different version of SPTexture macro, has an additional parameter + * which is currently reserved in the microcode. + */ +# define gSPTextureL(pkt, s, t, level, xparam, tile, on) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)| \ + _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)| \ + _SHIFTL((on),0,8)); \ + _g->words.w1 = (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)); \ +} +# define gsSPTextureL(s, t, level, xparam, tile, on) \ +{{ \ + (_SHIFTL(G_TEXTURE,24,8)|_SHIFTL((xparam),16,8)| \ + _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \ + (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)) \ +}} +#endif + +#define gSPPerspNormalize(pkt, s) gMoveWd(pkt, G_MW_PERSPNORM, 0, (s)) +#define gsSPPerspNormalize(s) gsMoveWd( G_MW_PERSPNORM, 0, (s)) + +#ifdef F3DEX_GBI_2 +# define gSPPopMatrixN(pkt, n, num) gDma2p((pkt),G_POPMTX,(num)*64,64,2,0) +# define gsSPPopMatrixN(n, num) gsDma2p( G_POPMTX,(num)*64,64,2,0) +# define gSPPopMatrix(pkt, n) gSPPopMatrixN((pkt), (n), 1) +# define gsSPPopMatrix(n) gsSPPopMatrixN( (n), 1) +#else /* F3DEX_GBI_2 */ +# define gSPPopMatrix(pkt, n) gImmp1(pkt, G_POPMTX, n) +# define gsSPPopMatrix(n) gsImmp1( G_POPMTX, n) +#endif /* F3DEX_GBI_2 */ + +#define gSPEndDisplayList(pkt) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_ENDDL, 24, 8); \ + _g->words.w1 = 0; \ +} + +#define gsSPEndDisplayList() \ +{{ \ + _SHIFTL(G_ENDDL, 24, 8), 0 \ +}} + +#ifdef F3DEX_GBI_2 +/* + * One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs. + * + * gSPClearGeometryMode(pkt,c) + * gSPSetGeometryMode(pkt,s) + * + * gSPLoadGeometryMode(pkt, word) sets GeometryMode directly. + */ +#define gSPGeometryMode(pkt, c, s) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = _SHIFTL(G_GEOMETRYMODE,24,8)|_SHIFTL(~(u32)(c),0,24);\ + _g->words.w1 = (u32)(s); \ +} + +#define gsSPGeometryMode(c, s) \ +{{ \ + (_SHIFTL(G_GEOMETRYMODE,24,8)|_SHIFTL(~(u32)(c),0,24)),(u32)(s) \ +}} +#define gSPSetGeometryMode(pkt, word) gSPGeometryMode((pkt),0,(word)) +#define gsSPSetGeometryMode(word) gsSPGeometryMode(0,(word)) +#define gSPClearGeometryMode(pkt, word) gSPGeometryMode((pkt),(word),0) +#define gsSPClearGeometryMode(word) gsSPGeometryMode((word),0) +#define gSPLoadGeometryMode(pkt, word) gSPGeometryMode((pkt),-1,(word)) +#define gsSPLoadGeometryMode(word) gsSPGeometryMode(-1,(word)) + +#else /* F3DEX_GBI_2 */ +#define gSPSetGeometryMode(pkt, word) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \ + _g->words.w1 = (unsigned int)(word); \ +} + +#define gsSPSetGeometryMode(word) \ +{{ \ + _SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) \ +}} + +#define gSPClearGeometryMode(pkt, word) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \ + _g->words.w1 = (unsigned int)(word); \ +} + +#define gsSPClearGeometryMode(word) \ +{{ \ + _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word) \ +}} +#endif /* F3DEX_GBI_2 */ + +#ifdef F3DEX_GBI_2 +#define gSPSetOtherMode(pkt, cmd, sft, len, data) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + _g->words.w0 = (_SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)| \ + _SHIFTL((len)-1,0,8)); \ + _g->words.w1 = (unsigned int)(data); \ +} + +#define gsSPSetOtherMode(cmd, sft, len, data) \ +{{ \ + _SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)|_SHIFTL((len)-1,0,8), \ + (unsigned int)(data) \ +}} +#else +#define gSPSetOtherMode(pkt, cmd, sft, len, data) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \ + _SHIFTL(len, 0, 8)); \ + _g->words.w1 = (unsigned int)(data); \ +} + +#define gsSPSetOtherMode(cmd, sft, len, data) \ +{{ \ + _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \ + (unsigned int)(data) \ +}} +#endif + +/* + * RDP setothermode register commands - register shadowed in RSP + */ +#define gDPPipelineMode(pkt, mode) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode) +#define gsDPPipelineMode(mode) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode) + +#define gDPSetCycleType(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type) +#define gsDPSetCycleType(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type) + +#define gDPSetTexturePersp(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type) +#define gsDPSetTexturePersp(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type) + +#define gDPSetTextureDetail(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type) +#define gsDPSetTextureDetail(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type) + +#define gDPSetTextureLOD(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type) +#define gsDPSetTextureLOD(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type) + +#define gDPSetTextureLUT(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type) +#define gsDPSetTextureLUT(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type) + +#define gDPSetTextureFilter(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type) +#define gsDPSetTextureFilter(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type) + +#define gDPSetTextureConvert(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type) +#define gsDPSetTextureConvert(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type) + +#define gDPSetCombineKey(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type) +#define gsDPSetCombineKey(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type) + +#ifndef _HW_VERSION_1 +#define gDPSetColorDither(pkt, mode) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode) +#define gsDPSetColorDither(mode) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode) +#else +#define gDPSetColorDither(pkt, mode) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode) +#define gsDPSetColorDither(mode) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode) +#endif + +#ifndef _HW_VERSION_1 +#define gDPSetAlphaDither(pkt, mode) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode) +#define gsDPSetAlphaDither(mode) \ + gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode) +#endif + +/* 'blendmask' is not supported anymore. + * The bits are reserved for future use. + * Fri May 26 13:45:55 PDT 1995 + */ +#define gDPSetBlendMask(pkt, mask) gDPNoOp(pkt) +#define gsDPSetBlendMask(mask) gsDPNoOp() + +#define gDPSetAlphaCompare(pkt, type) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type) +#define gsDPSetAlphaCompare(type) \ + gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type) + +#define gDPSetDepthSource(pkt, src) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src) +#define gsDPSetDepthSource(src) \ + gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src) + +#define gDPSetRenderMode(pkt, c0, c1) \ + gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, \ + (c0) | (c1)) +#define gsDPSetRenderMode(c0, c1) \ + gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, \ + (c0) | (c1)) + +#define gSetImage(pkt, cmd, fmt, siz, width, i) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \ + _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \ + _g->words.w1 = (unsigned int)(i); \ +} + +#define gsSetImage(cmd, fmt, siz, width, i) \ +{{ \ + _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \ + _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \ + (unsigned int)(i) \ +}} + +#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i) +#define gsDPSetColorImage(f, s, w, i) gsSetImage(G_SETCIMG, f, s, w, i) + + +/* use these for new code */ +#define gDPSetDepthImage(pkt, i) gSetImage(pkt, G_SETZIMG, 0, 0, 1, i) +#define gsDPSetDepthImage(i) gsSetImage(G_SETZIMG, 0, 0, 1, i) +/* kept for compatibility */ +#define gDPSetMaskImage(pkt, i) gDPSetDepthImage(pkt, i) +#define gsDPSetMaskImage(i) gsDPSetDepthImage(i) + +#define gDPSetTextureImage(pkt, f, s, w, i) gSetImage(pkt, G_SETTIMG, f, s, w, i) +#define gsDPSetTextureImage(f, s, w, i) gsSetImage(G_SETTIMG, f, s, w, i) + +/* + * RDP macros + */ + +#define gDPSetCombine(pkt, muxs0, muxs1) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24);\ + _g->words.w1 = (unsigned int)(muxs1); \ +} + +#define gsDPSetCombine(muxs0, muxs1) \ +{{ \ + _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \ + (unsigned int)(muxs1) \ +}} + +#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \ + (_SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | \ + _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3)) + +#define GCCc1w0(saRGB1, mRGB1) \ + (_SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5)) + +#define GCCc0w1(sbRGB0, aRGB0, sbA0, aA0) \ + (_SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) | \ + _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3)) + +#define GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1) \ + (_SHIFTL((sbRGB1), 24, 4) | _SHIFTL((saA1), 21, 3) | \ + _SHIFTL((mA1), 18, 3) | _SHIFTL((aRGB1), 6, 3) | \ + _SHIFTL((sbA1), 3, 3) | _SHIFTL((aA1), 0, 3)) + +#define gDPSetCombineLERP(pkt, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ + a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | \ + _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0, \ + G_ACMUX_##Aa0, G_ACMUX_##Ac0) | \ + GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), \ + 0, 24); \ + _g->words.w1 = (unsigned int)(GCCc0w1(G_CCMUX_##b0, \ + G_CCMUX_##d0, \ + G_ACMUX_##Ab0, \ + G_ACMUX_##Ad0) | \ + GCCc1w1(G_CCMUX_##b1, \ + G_ACMUX_##Aa1, \ + G_ACMUX_##Ac1, \ + G_CCMUX_##d1, \ + G_ACMUX_##Ab1, \ + G_ACMUX_##Ad1)); \ +} + +#define gsDPSetCombineLERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ + a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ +{{ \ + _SHIFTL(G_SETCOMBINE, 24, 8) | \ + _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0, \ + G_ACMUX_##Aa0, G_ACMUX_##Ac0) | \ + GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), 0, 24), \ + (unsigned int)(GCCc0w1(G_CCMUX_##b0, G_CCMUX_##d0, \ + G_ACMUX_##Ab0, G_ACMUX_##Ad0) | \ + GCCc1w1(G_CCMUX_##b1, G_ACMUX_##Aa1, \ + G_ACMUX_##Ac1, G_CCMUX_##d1, \ + G_ACMUX_##Ab1, G_ACMUX_##Ad1)) \ +}} + +/* + * SetCombineMode macros are NOT redunant. It allow the C preprocessor + * to substitute single parameter which includes commas in the token and + * rescan for higher parameter count macro substitution. + * + * eg. gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into + * gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0, + * TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0) + */ + +#define gDPSetCombineMode(pkt, a, b) gDPSetCombineLERP(pkt, a, b) +#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b) + +#define gDPSetColor(pkt, c, d) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(c, 24, 8); \ + _g->words.w1 = (unsigned int)(d); \ +} + +#define gsDPSetColor(c, d) \ +{{ \ + _SHIFTL(c, 24, 8), (unsigned int)(d) \ +}} + +#define DPRGBColor(pkt, cmd, r, g, b, a) \ + gDPSetColor(pkt, cmd, \ + (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \ + _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8))) +#define sDPRGBColor(cmd, r, g, b, a) \ + gsDPSetColor(cmd, \ + (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \ + _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8))) + +#define gDPSetEnvColor(pkt, r, g, b, a) \ + DPRGBColor(pkt, G_SETENVCOLOR, r,g,b,a) +#define gsDPSetEnvColor(r, g, b, a) \ + sDPRGBColor(G_SETENVCOLOR, r,g,b,a) +#define gDPSetBlendColor(pkt, r, g, b, a) \ + DPRGBColor(pkt, G_SETBLENDCOLOR, r,g,b,a) +#define gsDPSetBlendColor(r, g, b, a) \ + sDPRGBColor(G_SETBLENDCOLOR, r,g,b,a) +#define gDPSetFogColor(pkt, r, g, b, a) \ + DPRGBColor(pkt, G_SETFOGCOLOR, r,g,b,a) +#define gsDPSetFogColor(r, g, b, a) \ + sDPRGBColor(G_SETFOGCOLOR, r,g,b,a) +#define gDPSetFillColor(pkt, d) \ + gDPSetColor(pkt, G_SETFILLCOLOR, (d)) +#define gsDPSetFillColor(d) \ + gsDPSetColor(G_SETFILLCOLOR, (d)) + +#define gDPSetPrimDepth(pkt, z, dz) \ + gDPSetColor(pkt, G_SETPRIMDEPTH, \ + _SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16)) +#define gsDPSetPrimDepth(z, dz) \ + gsDPSetColor(G_SETPRIMDEPTH, _SHIFTL(z, 16, 16) | \ + _SHIFTL(dz, 0, 16)) + +#define gDPSetPrimColor(pkt, m, l, r, g, b, a) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | \ + _SHIFTL(m, 8, 8) | _SHIFTL(l, 0, 8)); \ + _g->words.w1 = (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \ + _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)); \ +} + +#define gsDPSetPrimColor(m, l, r, g, b, a) \ +{{ \ + (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | _SHIFTL(m, 8, 8) | \ + _SHIFTL(l, 0, 8)), \ + (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | \ + _SHIFTL(a, 0, 8)) \ +}} + +/* + * gDPSetOtherMode (This is for expert user.) + * + * This command makes all othermode parameters set. + * Do not use this command in the same DL with another g*SPSetOtherMode DLs. + * + * [Usage] + * gDPSetOtherMode(pkt, modeA, modeB) + * + * 'modeA' is described all parameters of GroupA GBI command. + * 'modeB' is also described all parameters of GroupB GBI command. + * + * GroupA: + * gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp, + * gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT, + * gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey, + * gDPSetColorDither, gDPSetAlphaDither + * + * GroupB: + * gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode + * + * Use 'OR' operation to get modeA and modeB. + * + * modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_* + * G_TC_* | G_CK_* | G_CD_* | G_AD_*; + * + * modeB = G_AC_* | G_ZS_* | G_RM_* | G_RM_*2; + */ +#define gDPSetOtherMode(pkt, mode0, mode1) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24);\ + _g->words.w1 = (unsigned int)(mode1); \ +} + +#define gsDPSetOtherMode(mode0, mode1) \ +{{ \ + _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \ + (unsigned int)(mode1) \ +}} + +/* + * Texturing macros + */ + +/* These are also defined defined above for Sprite Microcode */ + +#define G_TX_LOADTILE 7 +#define G_TX_RENDERTILE 0 + +#define G_TX_NOMIRROR 0 +#define G_TX_WRAP 0 +#define G_TX_MIRROR 0x1 +#define G_TX_CLAMP 0x2 +#define G_TX_NOMASK 0 +#define G_TX_NOLOD 0 + + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +/* + * Dxt is the inverse of the number of 64-bit words in a line of + * the texture being loaded using the load_block command. If + * there are any 1's to the right of the 11th fractional bit, + * dxt should be rounded up. The following macros accomplish + * this. The 4b macros are a special case since 4-bit textures + * are loaded as 8-bit textures. Dxt is fixed point 1.11. RJM + */ +#define G_TX_DXT_FRAC 11 + +/* + * For RCP 2.0, the maximum number of texels that can be loaded + * using a load_block command is 2048. In order to load the total + * 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b, + * then change the tile to the proper texel size after the load. + * The g*DPLoadTextureBlock macros already do this, so this change + * will be transparent if you use these macros. If you use + * the g*DPLoadBlock macros directly, you will need to handle this + * tile manipulation yourself. RJM. + */ +#ifdef _HW_VERSION_1 +#define G_TX_LDBLK_MAX_TXL 4095 +#else +#define G_TX_LDBLK_MAX_TXL 2047 +#endif /* _HW_VERSION_1 */ + +#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8)) +#define CALC_DXT(width, b_txl) \ + (((1 << G_TX_DXT_FRAC) + TXL2WORDS(width, b_txl) - 1) / \ + TXL2WORDS(width, b_txl)) + +#define TXL2WORDS_4b(txls) MAX(1, ((txls)/16)) +#define CALC_DXT_4b(width) \ + (((1 << G_TX_DXT_FRAC) + TXL2WORDS_4b(width) - 1) / \ + TXL2WORDS_4b(width)) + +#define gDPLoadTileGeneric(pkt, c, tile, uls, ult, lrs, lrt) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | \ + _SHIFTL(ult, 0, 12); \ + _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | \ + _SHIFTL(lrt, 0, 12); \ +} + +#define gsDPLoadTileGeneric(c, tile, uls, ult, lrs, lrt) \ +{{ \ + _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12), \ + _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12)\ +}} + +#define gDPSetTileSize(pkt, t, uls, ult, lrs, lrt) \ + gDPLoadTileGeneric(pkt, G_SETTILESIZE, t, uls, ult, lrs, lrt) +#define gsDPSetTileSize(t, uls, ult, lrs, lrt) \ + gsDPLoadTileGeneric(G_SETTILESIZE, t, uls, ult, lrs, lrt) +#define gDPLoadTile(pkt, t, uls, ult, lrs, lrt) \ + gDPLoadTileGeneric(pkt, G_LOADTILE, t, uls, ult, lrs, lrt) +#define gsDPLoadTile(t, uls, ult, lrs, lrt) \ + gsDPLoadTileGeneric(G_LOADTILE, t, uls, ult, lrs, lrt) + +#define gDPSetTile(pkt, fmt, siz, line, tmem, tile, palette, cmt, \ + maskt, shiftt, cms, masks, shifts) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) |\ + _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | \ + _SHIFTL(tmem, 0, 9); \ + _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | \ + _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | \ + _SHIFTL(shiftt, 10, 4) |_SHIFTL(cms, 8, 2) | \ + _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4); \ +} + +#define gsDPSetTile(fmt, siz, line, tmem, tile, palette, cmt, \ + maskt, shiftt, cms, masks, shifts) \ +{{ \ + (_SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) | \ + _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | _SHIFTL(tmem, 0, 9)),\ + (_SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | \ + _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | \ + _SHIFTL(shiftt, 10, 4) | _SHIFTL(cms, 8, 2) | \ + _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4)) \ +}} + +/* + * For RCP 2.0, the maximum number of texels that can be loaded + * using a load_block command is 2048. In order to load the total + * 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b, + * then change the tile to the proper texel size after the load. + * The g*DPLoadTextureBlock macros already do this, so this change + * will be transparent if you use these macros. If you use + * the g*DPLoadBlock macros directly, you will need to handle this + * tile manipulation yourself. RJM. + */ +#define gDPLoadBlock(pkt, tile, uls, ult, lrs, dxt) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_LOADBLOCK, 24, 8) | \ + _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | \ + _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) |\ + _SHIFTL(dxt, 0, 12)); \ +} + +#define gsDPLoadBlock(tile, uls, ult, lrs, dxt) \ +{{ \ + (_SHIFTL(G_LOADBLOCK, 24, 8) | _SHIFTL(uls, 12, 12) | \ + _SHIFTL(ult, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | \ + _SHIFTL((MIN(lrs,G_TX_LDBLK_MAX_TXL)), 12, 12) | \ + _SHIFTL(dxt, 0, 12)) \ +}} + +#define gDPLoadTLUTCmd(pkt, tile, count) \ +{ \ + Gfx *_g = (Gfx *)pkt; \ + \ + _g->words.w0 = _SHIFTL(G_LOADTLUT, 24, 8); \ + _g->words.w1 = _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10);\ +} + +#define gsDPLoadTLUTCmd(tile, count) \ +{{ \ + _SHIFTL(G_LOADTLUT, 24, 8), \ + _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10) \ +}} + +#define gDPLoadTextureBlock(pkt, timg, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, \ + (((width) * siz##_LINE_BYTES)+7)>>3, 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +#define gDPLoadTextureBlockYuv(pkt, timg, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, \ + (((width) * 1)+7)>>3, 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* Load fix rww 27jun95 */ +/* The S at the end means odd lines are already word Swapped */ + +#define gDPLoadTextureBlockS(pkt, timg, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, \ + (((width) * siz##_LINE_BYTES)+7)>>3, 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* + * Allow tmem address and render tile to be specified. + * The S at the end means odd lines are already word Swapped + */ +#define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, \ + height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, \ + (((width) * siz##_LINE_BYTES)+7)>>3, tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + + +#define gDPLoadTextureBlockYuvS(pkt, timg, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1,0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, \ + (((width) * 1)+7)>>3, 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* + * allows tmem address to be specified + */ +#define _gDPLoadTextureBlock(pkt, timg, tmem, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \ + 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, \ + tmem, G_TX_RENDERTILE, pal, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* + * allows tmem address and render tile to be specified + */ +#define _gDPLoadTextureBlockTile(pkt, timg, tmem, rtile, fmt, siz, width, \ + height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,\ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, \ + tmem, rtile, pal, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* + * allows tmem address and render tile to be specified + */ +#define gDPLoadMultiBlock(pkt, timg, tmem, rtile, fmt, siz, width, \ + height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0,\ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width) * siz##_LINE_BYTES)+7)>>3, \ + tmem, rtile, pal, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +#define gsDPLoadTextureBlock(timg, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* Here is the static form of the pre-swapped texture block loading */ +/* See gDPLoadTextureBlockS() for reference. Basically, just don't + calculate DxT, use 0 */ + +#define gsDPLoadTextureBlockS(timg, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0 , \ + cmt, maskt,shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),\ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allow tmem address to be specified + */ +#define _gsDPLoadTextureBlock(timg, tmem, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, \ + ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + + +/* + * Allow tmem address and render_tile to be specified + */ +#define _gsDPLoadTextureBlockTile(timg, tmem, rtile, fmt, siz, width, \ + height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, \ + ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + + +/* + * Allow tmem address and render_tile to be specified, useful when loading + * mutilple tiles at a time. + */ +#define gsDPLoadMultiBlock(timg, tmem, rtile, fmt, siz, width, \ + height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, \ + 0 , cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, \ + ((((width) * siz##_LINE_BYTES)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allows tmem and render tile to be specified. Useful when loading + * several tiles at a time. + * + * Here is the static form of the pre-swapped texture block loading + * See gDPLoadTextureBlockS() for reference. Basically, just don't + * calculate DxT, use 0 + */ + +#define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0 , \ + cmt, maskt,shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, \ + (((width)*(height) + siz##_INCR) >> siz##_SHIFT)-1, 0 ),\ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width) * siz##_LINE_BYTES)+7)>>3), tmem,\ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + + +#define gDPLoadTextureBlock_4b(pkt, timg, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height)+3)>>2)-1, \ + CALC_DXT_4b(width)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* Load fix rww 27jun95 */ +/* The S at the end means odd lines are already word Swapped */ + +#define gDPLoadTextureBlock_4bS(pkt, timg, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height)+3)>>2)-1, 0 ); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* + * 4-bit load block. Useful when loading multiple tiles + */ +#define gDPLoadMultiBlock_4b(pkt, timg, tmem, rtile, fmt, width, height,\ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height)+3)>>2)-1, \ + CALC_DXT_4b(width)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +/* + * 4-bit load block. Allows tmem and render tile to be specified. Useful when + * loading multiple tiles. The S means odd lines are already word swapped. + */ +#define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height,\ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height)+3)>>2)-1, 0 ); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + + +#define _gDPLoadTextureBlock_4b(pkt, timg, tmem, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, \ + cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, \ + (((width)*(height)+3)>>2)-1, \ + CALC_DXT_4b(width)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ +} + +#define gsDPLoadTextureBlock_4b(timg, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1, \ + CALC_DXT_4b(width)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +#define gsDPLoadTextureBlock_4bS(timg, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0 , cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0),\ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * 4-bit load block. Allows tmem address and render tile to be specified. + * Useful when loading multiple tiles. + */ +#define gsDPLoadMultiBlock_4b(timg, tmem, rtile, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1, \ + CALC_DXT_4b(width)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + + +/* + * 4-bit load block. Allows tmem address and render tile to be specified. + * Useful when loading multiple tiles. S means odd lines are already swapped. + */ +#define gsDPLoadMultiBlock_4bS(timg, tmem, rtile, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1,0),\ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + + +/* + * Allows tmem address to be specified + */ +#define _gsDPLoadTextureBlock_4b(timg, tmem, fmt, width, height, \ + pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0 , cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width)*(height)+3)>>2)-1, \ + CALC_DXT_4b(width)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width)>>1)+7)>>3), tmem, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, \ + ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +#ifndef _HW_VERSION_1 + +#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height, \ + uls, ult, lrs, lrt, pal, \ + cms, cmt, masks, maskt, shifts, shiftt) \ +{ \ + gDPSetTextureImage(pkt, fmt, siz, width, timg); \ + gDPSetTile(pkt, fmt, siz, \ + (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile( pkt, G_TX_LOADTILE, \ + (uls)<>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, \ + (uls)<>3), tmem, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile( pkt, G_TX_LOADTILE, \ + (uls)<>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, rtile, \ + (uls)<>3), 0, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile( G_TX_LOADTILE, \ + (uls)<>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,\ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, \ + (uls)<>3), \ + tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile( G_TX_LOADTILE, \ + (uls)<>3), \ + tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, \ + (uls)<>1), timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_8b, \ + (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile( pkt, G_TX_LOADTILE, \ + (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (ult)<<(G_TEXTURE_IMAGE_FRAC), \ + (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (lrt)<<(G_TEXTURE_IMAGE_FRAC)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \ + (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, \ + (uls)<>1), timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_8b, \ + (((((lrs)-(uls)+1)>>1)+7)>>3), tmem, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile( pkt, G_TX_LOADTILE, \ + (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (ult)<<(G_TEXTURE_IMAGE_FRAC), \ + (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (lrt)<<(G_TEXTURE_IMAGE_FRAC)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \ + (((((lrs)-(uls)+1)>>1)+7)>>3), tmem, \ + rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, rtile, \ + (uls)<>1), timg), \ + gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \ + G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile( G_TX_LOADTILE, \ + (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (ult)<<(G_TEXTURE_IMAGE_FRAC), \ + (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (lrt)<<(G_TEXTURE_IMAGE_FRAC)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), 0, \ + G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, \ + (uls)<>1), timg), \ + gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs)-(uls)+1)>>1)+7)>>3), \ + tmem, G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile( G_TX_LOADTILE, \ + (uls)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (ult)<<(G_TEXTURE_IMAGE_FRAC), \ + (lrs)<<(G_TEXTURE_IMAGE_FRAC-1), \ + (lrt)<<(G_TEXTURE_IMAGE_FRAC)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs)-(uls)+1)>>1)+7)>>3), \ + tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, \ + (uls)<words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) | \ + _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(uly)*4.0F), 0, 12); \ + _g->words.w1 = _SHIFTL(mode, 24, 2) | \ + _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(lry)*4.0F), 0, 12); \ +} + + +#define gDPSetScissorFrac(pkt, mode, ulx, uly, lrx, lry) \ +{ \ + Gfx *_g = (Gfx *)pkt; \ + \ + _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) | \ + _SHIFTL((int)((ulx)), 12, 12) | \ + _SHIFTL((int)((uly)), 0, 12); \ + _g->words.w1 = _SHIFTL(mode, 24, 2) | \ + _SHIFTL((int)((lrx)), 12, 12) | \ + _SHIFTL((int)((lry)), 0, 12); \ +} + +#define gsDPSetScissor(mode, ulx, uly, lrx, lry) \ +{{ \ + _SHIFTL(G_SETSCISSOR, 24, 8) | \ + _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(uly)*4.0F), 0, 12), \ + _SHIFTL(mode, 24, 2) | \ + _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(lry)*4.0F), 0, 12) \ +}} + +#define gsDPSetScissorFrac(mode, ulx, uly, lrx, lry) \ +{{ \ + _SHIFTL(G_SETSCISSOR, 24, 8) | \ + _SHIFTL((int)((ulx)), 12, 12) | \ + _SHIFTL((int)((uly)), 0, 12), \ + _SHIFTL(mode, 24, 2) | \ + _SHIFTL((int)(lrx), 12, 12) | \ + _SHIFTL((int)(lry), 0, 12) \ +}} + +/* Fraction never used in fill */ +#define gDPFillRectangle(pkt, ulx, uly, lrx, lry) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | \ + _SHIFTL((lrx), 14, 10) | _SHIFTL((lry), 2, 10));\ + _g->words.w1 = (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10));\ +} + +#define gsDPFillRectangle(ulx, uly, lrx, lry) \ +{{ \ + (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 14, 10) | \ + _SHIFTL((lry), 2, 10)), \ + (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10)) \ +}} + +/* like gDPFillRectangle but accepts negative arguments */ +#define gDPScisFillRectangle(pkt, ulx, uly, lrx, lry) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | \ + _SHIFTL(MAX((lrx),0), 14, 10) | \ + _SHIFTL(MAX((lry),0), 2, 10)); \ + _g->words.w1 = (_SHIFTL(MAX((ulx),0), 14, 10) | \ + _SHIFTL(MAX((uly),0), 2, 10)); \ +} + +#define gDPSetConvert(pkt, k0, k1, k2, k3, k4, k5) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SETCONVERT, 24, 8) | \ + _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | \ + _SHIFTR(k2, 5, 4)); \ + _g->words.w1 = (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | \ + _SHIFTL(k4, 9, 9) | _SHIFTL(k5, 0, 9)); \ +} + +#define gsDPSetConvert(k0, k1, k2, k3, k4, k5) \ +{{ \ + (_SHIFTL(G_SETCONVERT, 24, 8) | \ + _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | _SHIFTR(k2, 5, 4)), \ + (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | _SHIFTL(k4, 9, 9) | \ + _SHIFTL(k5, 0, 9)) \ +}} + +#define gDPSetKeyR(pkt, cR, sR, wR) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETKEYR, 24, 8); \ + _g->words.w1 = (_SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | \ + _SHIFTL(sR, 0, 8)); \ +} + +#define gsDPSetKeyR(cR, sR, wR) \ +{{ \ + _SHIFTL(G_SETKEYR, 24, 8), \ + _SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | _SHIFTL(sR, 0, 8) \ +}} + +#define gDPSetKeyGB(pkt, cG, sG, wG, cB, sB, wB) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SETKEYGB, 24, 8) | \ + _SHIFTL(wG, 12, 12) | _SHIFTL(wB, 0, 12)); \ + _g->words.w1 = (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | \ + _SHIFTL(cB, 8, 8) | _SHIFTL(sB, 0, 8)); \ +} + +#define gsDPSetKeyGB(cG, sG, wG, cB, sB, wB) \ +{{ \ + (_SHIFTL(G_SETKEYGB, 24, 8) | _SHIFTL(wG, 12, 12) | \ + _SHIFTL(wB, 0, 12)), \ + (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | _SHIFTL(cB, 8, 8) | \ + _SHIFTL(sB, 0, 8)) \ +}} + +#define gDPNoParam(pkt, cmd) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(cmd, 24, 8); \ + _g->words.w1 = 0; \ +} + +#define gsDPNoParam(cmd) \ +{{ \ + _SHIFTL(cmd, 24, 8), 0 \ +}} + +#define gDPParam(pkt, cmd, param) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(cmd, 24, 8); \ + _g->words.w1 = (param); \ +} + +#define gsDPParam(cmd, param) \ +{{ \ + _SHIFTL(cmd, 24, 8), (param) \ +}} + +/* Notice that textured rectangles are 128-bit commands, therefore + * gsDPTextureRectangle() should not be used in display lists + * under normal circumstances (use gsSPTextureRectangle()). + * That is also why there is no gDPTextureRectangle() macros. + */ +#define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ +{{ \ + (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \ + _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \ +}}, \ +{{ \ + _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \ + _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \ +}} + +#define gDPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + if (pkt); \ + _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \ + _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \ + _SHIFTL(yl, 0, 12)); \ + _g ++; \ + _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \ + _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ +} + +#define gsDPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ +{{ \ + (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \ + _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \ +}}, \ +{{ \ + _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \ + _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \ +}} + +#define gDPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + if (pkt); \ + _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \ + _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \ + _SHIFTL(yl, 0, 12)); \ + _g ++; \ + _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \ + _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ +} + +#define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + {{(_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)),\ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12))}}, \ + gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \ + gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))) + +#define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)\ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | \ + _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \ + _SHIFTL(yl, 0, 12)); \ + gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \ + gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)));\ +} + +/* like gSPTextureRectangle but accepts negative position arguments */ +#define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | \ + _SHIFTL(MAX((s16)(xh),0), 12, 12) | \ + _SHIFTL(MAX((s16)(yh),0), 0, 12)); \ + _g->words.w1 = (_SHIFTL((tile), 24, 3) | \ + _SHIFTL(MAX((s16)(xl),0), 12, 12) | \ + _SHIFTL(MAX((s16)(yl),0), 0, 12)); \ + gImmp1(pkt, G_RDPHALF_1, \ + (_SHIFTL(((s) - \ + (((s16)(xl) < 0) ? \ + (((s16)(dsdx) < 0) ? \ + (MAX((((s16)(xl)*(s16)(dsdx))>>7),0)) : \ + (MIN((((s16)(xl)*(s16)(dsdx))>>7),0))) : 0)), \ + 16, 16) | \ + _SHIFTL(((t) - \ + (((yl) < 0) ? \ + (((s16)(dtdy) < 0) ? \ + (MAX((((s16)(yl)*(s16)(dtdy))>>7),0)) : \ + (MIN((((s16)(yl)*(s16)(dtdy))>>7),0))) : 0)), \ + 0, 16))); \ + gImmp1(pkt, G_RDPHALF_2, (_SHIFTL((dsdx), 16, 16) | \ + _SHIFTL((dtdy), 0, 16))); \ +} + +#define gsSPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + {{(_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | \ + _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12))}}, \ + gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \ + gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))) + +#define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) |\ + _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | \ + _SHIFTL(yl, 0, 12)); \ + gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \ + gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \ +} + +#define gsDPWord(wordhi, wordlo) \ + gsImmp1(G_RDPHALF_1, (unsigned int)(wordhi)), \ + gsImmp1(G_RDPHALF_2, (unsigned int)(wordlo)) + +#define gDPWord(pkt, wordhi, wordlo) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + gImmp1(pkt, G_RDPHALF_1, (unsigned int)(wordhi)); \ + gImmp1(pkt, G_RDPHALF_2, (unsigned int)(wordlo)); \ +} + +#define gDPFullSync(pkt) gDPNoParam(pkt, G_RDPFULLSYNC) +#define gsDPFullSync() gsDPNoParam(G_RDPFULLSYNC) +#define gDPTileSync(pkt) gDPNoParam(pkt, G_RDPTILESYNC) +#define gsDPTileSync() gsDPNoParam(G_RDPTILESYNC) +#define gDPPipeSync(pkt) gDPNoParam(pkt, G_RDPPIPESYNC) +#define gsDPPipeSync() gsDPNoParam(G_RDPPIPESYNC) +#define gDPLoadSync(pkt) gDPNoParam(pkt, G_RDPLOADSYNC) +#define gsDPLoadSync() gsDPNoParam(G_RDPLOADSYNC) +#define gDPNoOp(pkt) gDPNoParam(pkt, G_NOOP) +#define gsDPNoOp() gsDPNoParam(G_NOOP) +#define gDPNoOpTag(pkt, tag) gDPParam(pkt, G_NOOP, tag) +#define gsDPNoOpTag(tag) gsDPParam(G_NOOP, tag) + +#endif /* _LANGUAGE_C */ + + +#endif /* _GBI_H_ */ diff --git a/lib/ultralib/include/PR/gs2dex.h b/lib/ultralib/include/PR/gs2dex.h new file mode 100644 index 00000000..ced46855 --- /dev/null +++ b/lib/ultralib/include/PR/gs2dex.h @@ -0,0 +1,392 @@ +/*--------------------------------------------------------------------- + Copyright (C) 1997, Nintendo. + + File gs2dex.h + Coded by Yoshitaka Yasumoto. Jul 31, 1997. + Modified by + Comments Header file for S2DEX ucode. + + $Id: gs2dex.h,v 1.21 1998/05/28 00:14:49 has Exp $ + ---------------------------------------------------------------------*/ + +#ifndef _GS2DEX_H_ +#define _GS2DEX_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +/*===========================================================================* + * Macro + *===========================================================================*/ +#define GS_CALC_DXT(line) (((1<< G_TX_DXT_FRAC)-1)/(line)+1) +#define GS_PIX2TMEM(pix, siz) ((pix)>>(4-(siz))) +#define GS_PIX2DXT(pix, siz) GS_CALC_DXT(GS_PIX2TMEM((pix), (siz))) + +/*===========================================================================* + * Data structures for S2DEX microcode + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * Background + *---------------------------------------------------------------------------*/ +#define G_BGLT_LOADBLOCK 0x0033 +#define G_BGLT_LOADTILE 0xfff4 + +#define G_BG_FLAG_FLIPS 0x01 +#define G_BG_FLAG_FLIPT 0x10 + +/* Non scalable background plane */ +typedef struct { + u16 imageX; /* x-coordinate of upper-left position of texture (u10.5) */ + u16 imageW; /* width of the texture (u10.2) */ + s16 frameX; /* upper-left position of transferred frame (s10.2) */ + u16 frameW; /* width of transferred frame (u10.2) */ + + u16 imageY; /* y-coordinate of upper-left position of texture (u10.5) */ + u16 imageH; /* height of the texture (u10.2) */ + s16 frameY; /* upper-left position of transferred frame (s10.2) */ + u16 frameH; /* height of transferred frame (u10.2) */ + + u64 *imagePtr; /* texture source address on DRAM */ + u16 imageLoad; /* which to use, LoadBlock or LoadTile */ + u8 imageFmt; /* format of texel - G_IM_FMT_* */ + u8 imageSiz; /* size of texel - G_IM_SIZ_* */ + u16 imagePal; /* pallet number */ + u16 imageFlip; /* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */ + + /* The following is set in the initialization routine guS2DInitBg(). There is no need for the user to set it. */ + u16 tmemW; /* TMEM width and Word size of frame 1 line. + At LoadBlock, GS_PIX2TMEM(imageW/4,imageSiz) + At LoadTile GS_PIX2TMEM(frameW/4,imageSiz)+1 */ + u16 tmemH; /* height of TMEM loadable at a time (s13.2) 4 times value + When the normal texture, 512/tmemW*4 + When the CI texture, 256/tmemW*4 */ + u16 tmemLoadSH; /* SH value + At LoadBlock, tmemSize/2-1 + At LoadTile, tmemW*16-1 */ + u16 tmemLoadTH; /* TH value or Stride value + At LoadBlock, GS_CALC_DXT(tmemW) + At LoadTile, tmemH-1 */ + u16 tmemSizeW; /* skip value of imagePtr for image 1-line + At LoadBlock, tmemW*2 + At LoadTile, GS_PIX2TMEM(imageW/4,imageSiz)*2 */ + u16 tmemSize; /* skip value of imagePtr for 1-loading + = tmemSizeW*tmemH */ +} uObjBg_t; /* 40 bytes */ + +/* Scalable background plane */ +typedef struct { + u16 imageX; /* x-coordinate of upper-left position of texture (u10.5) */ + u16 imageW; /* width of texture (u10.2) */ + s16 frameX; /* upper-left position of transferred frame (s10.2) */ + u16 frameW; /* width of transferred frame (u10.2) */ + + u16 imageY; /* y-coordinate of upper-left position of texture (u10.5) */ + u16 imageH; /* height of texture (u10.2) */ + s16 frameY; /* upper-left position of transferred frame (s10.2) */ + u16 frameH; /* height of transferred frame (u10.2) */ + + u64 *imagePtr; /* texture source address on DRAM */ + u16 imageLoad; /* Which to use, LoadBlock or LoadTile? */ + u8 imageFmt; /* format of texel - G_IM_FMT_* */ + u8 imageSiz; /* size of texel - G_IM_SIZ_* */ + u16 imagePal; /* pallet number */ + u16 imageFlip; /* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */ + + u16 scaleW; /* scale value of X-direction (u5.10) */ + u16 scaleH; /* scale value of Y-direction (u5.10) */ + s32 imageYorig; /* start point of drawing on image (s20.5) */ + + u8 padding[4]; + +} uObjScaleBg_t; /* 40 bytes */ + +typedef union { + uObjBg_t b; + uObjScaleBg_t s; + long long int force_structure_alignment; +} uObjBg; + +/*---------------------------------------------------------------------------* + * 2D Objects + *---------------------------------------------------------------------------*/ +#define G_OBJ_FLAG_FLIPS 1<<0 /* inversion to S-direction */ +#define G_OBJ_FLAG_FLIPT 1<<4 /* nversion to T-direction */ + +typedef struct { + s16 objX; /* s10.2 OBJ x-coordinate of upper-left end */ + u16 scaleW; /* u5.10 Scaling of u5.10 width direction */ + u16 imageW; /* u10.5 width of u10.5 texture (length of S-direction) */ + u16 paddingX; /* Unused - Always 0 */ + s16 objY; /* s10.2 OBJ y-coordinate of s10.2 OBJ upper-left end */ + u16 scaleH; /* u5.10 Scaling of u5.10 height direction */ + u16 imageH; /* u10.5 height of u10.5 texture (length of T-direction) */ + u16 paddingY; /* Unused - Always 0 */ + u16 imageStride; /* folding width of texel (In units of 64bit word) */ + u16 imageAdrs; /* texture header position in TMEM (In units of 64bit word) */ + u8 imageFmt; /* format of texel - G_IM_FMT_* */ + u8 imageSiz; /* size of texel - G_IM_SIZ_* */ + u8 imagePal; /* pallet number (0-7) */ + u8 imageFlags; /* The display flag - G_OBJ_FLAG_FLIP* */ +} uObjSprite_t; /* 24 bytes */ + +typedef union { + uObjSprite_t s; + long long int force_structure_alignment; +} uObjSprite; + +/*---------------------------------------------------------------------------* + * 2D Matrix + *---------------------------------------------------------------------------*/ +typedef struct { + s32 A, B, C, D; /* s15.16 */ + s16 X, Y; /* s10.2 */ + u16 BaseScaleX; /* u5.10 */ + u16 BaseScaleY; /* u5.10 */ +} uObjMtx_t; /* 24 bytes */ + +typedef union { + uObjMtx_t m; + long long int force_structure_alignment; +} uObjMtx; + +typedef struct { + s16 X, Y; /* s10.2 */ + u16 BaseScaleX; /* u5.10 */ + u16 BaseScaleY; /* u5.10 */ +} uObjSubMtx_t; /* 8 bytes */ + +typedef union { + uObjSubMtx_t m; + long long int force_structure_alignment; +} uObjSubMtx; + +/*---------------------------------------------------------------------------* + * Loading into TMEM + *---------------------------------------------------------------------------*/ +#define G_OBJLT_TXTRBLOCK 0x00001033 +#define G_OBJLT_TXTRTILE 0x00fc1034 +#define G_OBJLT_TLUT 0x00000030 + +#define GS_TB_TSIZE(pix,siz) (GS_PIX2TMEM((pix),(siz))-1) +#define GS_TB_TLINE(pix,siz) (GS_CALC_DXT(GS_PIX2TMEM((pix),(siz)))) + +typedef struct { + u32 type; /* G_OBJLT_TXTRBLOCK divided into types */ + u64 *image; /* texture source address on DRAM */ + u16 tmem; /* loaded TMEM word address (8byteWORD) */ + u16 tsize; /* Texture size, Specified by macro GS_TB_TSIZE() */ + u16 tline; /* width of Texture 1-line, Specified by macro GS_TB_TLINE() */ + u16 sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12) */ + u32 flag; /* STATE flag */ + u32 mask; /* STATE mask */ +} uObjTxtrBlock_t; /* 24 bytes */ + +#define GS_TT_TWIDTH(pix,siz) ((GS_PIX2TMEM((pix), (siz))<<2)-1) +#define GS_TT_THEIGHT(pix,siz) (((pix)<<2)-1) + +typedef struct { + u32 type; /* G_OBJLT_TXTRTILE divided into types */ + u64 *image; /* texture source address on DRAM */ + u16 tmem; /* loaded TMEM word address (8byteWORD)*/ + u16 twidth; /* width of Texture (Specified by macro GS_TT_TWIDTH()) */ + u16 theight; /* height of Texture (Specified by macro GS_TT_THEIGHT()) */ + u16 sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12) */ + u32 flag; /* STATE flag */ + u32 mask; /* STATE mask */ +} uObjTxtrTile_t; /* 24 bytes */ + +#define GS_PAL_HEAD(head) ((head)+256) +#define GS_PAL_NUM(num) ((num)-1) + +typedef struct { + u32 type; /* G_OBJLT_TLUT divided into types */ + u64 *image; /* texture source address on DRAM */ + u16 phead; /* pallet number of load header (Between 256 and 511) */ + u16 pnum; /* loading pallet number -1 */ + u16 zero; /* Assign 0 all the time */ + u16 sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12)*/ + u32 flag; /* STATE flag */ + u32 mask; /* STATE mask */ +} uObjTxtrTLUT_t; /* 24 bytes */ + +typedef union { + uObjTxtrBlock_t block; + uObjTxtrTile_t tile; + uObjTxtrTLUT_t tlut; + long long int force_structure_alignment; +} uObjTxtr; + +/*---------------------------------------------------------------------------* + * Loading into TMEM & 2D Objects + *---------------------------------------------------------------------------*/ +typedef struct { + uObjTxtr txtr; + uObjSprite sprite; +} uObjTxSprite; /* 48 bytes */ + +/*===========================================================================* + * GBI Commands for S2DEX microcode + *===========================================================================*/ +/* GBI Header */ +#ifdef F3DEX_GBI_2 +#define G_OBJ_RECTANGLE_R 0xda +#define G_OBJ_MOVEMEM 0xdc +#define G_RDPHALF_0 0xe4 +#define G_OBJ_RECTANGLE 0x01 +#define G_OBJ_SPRITE 0x02 +#define G_SELECT_DL 0x04 +#define G_OBJ_LOADTXTR 0x05 +#define G_OBJ_LDTX_SPRITE 0x06 +#define G_OBJ_LDTX_RECT 0x07 +#define G_OBJ_LDTX_RECT_R 0x08 +#define G_BG_1CYC 0x09 +#define G_BG_COPY 0x0a +#define G_OBJ_RENDERMODE 0x0b +#else +#define G_BG_1CYC 0x01 +#define G_BG_COPY 0x02 +#define G_OBJ_RECTANGLE 0x03 +#define G_OBJ_SPRITE 0x04 +#define G_OBJ_MOVEMEM 0x05 +#define G_SELECT_DL 0xb0 +#define G_OBJ_RENDERMODE 0xb1 +#define G_OBJ_RECTANGLE_R 0xb2 +#define G_OBJ_LOADTXTR 0xc1 +#define G_OBJ_LDTX_SPRITE 0xc2 +#define G_OBJ_LDTX_RECT 0xc3 +#define G_OBJ_LDTX_RECT_R 0xc4 +#define G_RDPHALF_0 0xe4 +#endif + +/*---------------------------------------------------------------------------* + * Background wrapped screen + *---------------------------------------------------------------------------*/ +#define gSPBgRectangle(pkt, m, mptr) gDma0p((pkt),(m),(mptr),0) +#define gsSPBgRectangle(m, mptr) gsDma0p( (m),(mptr),0) +#define gSPBgRectCopy(pkt, mptr) gSPBgRectangle((pkt), G_BG_COPY, (mptr)) +#define gsSPBgRectCopy(mptr) gsSPBgRectangle( G_BG_COPY, (mptr)) +#define gSPBgRect1Cyc(pkt, mptr) gSPBgRectangle((pkt), G_BG_1CYC, (mptr)) +#define gsSPBgRect1Cyc(mptr) gsSPBgRectangle( G_BG_1CYC, (mptr)) + +/*---------------------------------------------------------------------------* + * 2D Objects + *---------------------------------------------------------------------------*/ +#define gSPObjSprite(pkt, mptr) gDma0p((pkt),G_OBJ_SPRITE, (mptr),0) +#define gsSPObjSprite(mptr) gsDma0p( G_OBJ_SPRITE, (mptr),0) +#define gSPObjRectangle(pkt, mptr) gDma0p((pkt),G_OBJ_RECTANGLE, (mptr),0) +#define gsSPObjRectangle(mptr) gsDma0p( G_OBJ_RECTANGLE, (mptr),0) +#define gSPObjRectangleR(pkt, mptr) gDma0p((pkt),G_OBJ_RECTANGLE_R,(mptr),0) +#define gsSPObjRectangleR(mptr) gsDma0p( G_OBJ_RECTANGLE_R,(mptr),0) + +/*---------------------------------------------------------------------------* + * 2D Matrix + *---------------------------------------------------------------------------*/ +#define gSPObjMatrix(pkt, mptr) gDma1p((pkt),G_OBJ_MOVEMEM,(mptr),0,23) +#define gsSPObjMatrix(mptr) gsDma1p( G_OBJ_MOVEMEM,(mptr),0,23) +#define gSPObjSubMatrix(pkt, mptr) gDma1p((pkt),G_OBJ_MOVEMEM,(mptr),2, 7) +#define gsSPObjSubMatrix(mptr) gsDma1p( G_OBJ_MOVEMEM,(mptr),2, 7) + +/*---------------------------------------------------------------------------* + * Loading into TMEM + *---------------------------------------------------------------------------*/ +#define gSPObjLoadTxtr(pkt, tptr) gDma0p((pkt),G_OBJ_LOADTXTR, (tptr),23) +#define gsSPObjLoadTxtr(tptr) gsDma0p( G_OBJ_LOADTXTR, (tptr),23) +#define gSPObjLoadTxSprite(pkt, tptr) gDma0p((pkt),G_OBJ_LDTX_SPRITE,(tptr),47) +#define gsSPObjLoadTxSprite(tptr) gsDma0p( G_OBJ_LDTX_SPRITE,(tptr),47) +#define gSPObjLoadTxRect(pkt, tptr) gDma0p((pkt),G_OBJ_LDTX_RECT, (tptr),47) +#define gsSPObjLoadTxRect(tptr) gsDma0p( G_OBJ_LDTX_RECT, (tptr),47) +#define gSPObjLoadTxRectR(pkt, tptr) gDma0p((pkt),G_OBJ_LDTX_RECT_R,(tptr),47) +#define gsSPObjLoadTxRectR(tptr) gsDma0p( G_OBJ_LDTX_RECT_R,(tptr),47) + +/*---------------------------------------------------------------------------* + * Select Display List + *---------------------------------------------------------------------------*/ +#define gSPSelectDL(pkt, mptr, sid, flag, mask) \ +{ gDma1p((pkt), G_RDPHALF_0, (flag), (u32)(mptr) & 0xffff, (sid)); \ + gDma1p((pkt), G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_PUSH); } +#define gsSPSelectDL(mptr, sid, flag, mask) \ +{ gsDma1p(G_RDPHALF_0, (flag), (u32)(mptr) & 0xffff, (sid)); \ + gsDma1p(G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_PUSH); } +#define gSPSelectBranchDL(pkt, mptr, sid, flag, mask) \ +{ gDma1p((pkt), G_RDPHALF_0, (flag), (u32)(mptr) & 0xffff, (sid)); \ + gDma1p((pkt), G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_NOPUSH); } +#define gsSPSelectBranchDL(mptr, sid, flag, mask) \ +{ gsDma1p(G_RDPHALF_0, (flag), (u32)(mptr) & 0xffff, (sid)); \ + gsDma1p(G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_NOPUSH); } + +/*---------------------------------------------------------------------------* + * Set general status + *---------------------------------------------------------------------------*/ +#define G_MW_GENSTAT 0x08 /* Note that it is the same value of G_MW_FOG */ + +#define gSPSetStatus(pkt, sid, val) \ + gMoveWd((pkt), G_MW_GENSTAT, (sid), (val)) +#define gsSPSetStatus(sid, val) \ + gsMoveWd( G_MW_GENSTAT, (sid), (val)) + +/*---------------------------------------------------------------------------* + * Set Object Render Mode + *---------------------------------------------------------------------------*/ +#define G_OBJRM_NOTXCLAMP 0x01 +#define G_OBJRM_XLU 0x02 /* Ignored */ +#define G_OBJRM_ANTIALIAS 0x04 /* Ignored */ +#define G_OBJRM_BILERP 0x08 +#define G_OBJRM_SHRINKSIZE_1 0x10 +#define G_OBJRM_SHRINKSIZE_2 0x20 +#define G_OBJRM_WIDEN 0x40 + +#define gSPObjRenderMode(pkt, mode) gImmp1((pkt),G_OBJ_RENDERMODE,(mode)) +#define gsSPObjRenderMode(mode) gsImmp1( G_OBJ_RENDERMODE,(mode)) + +/*===========================================================================* + * Render Mode Macro + *===========================================================================*/ +#define RM_RA_SPRITE(clk) \ + AA_EN | CVG_DST_CLAMP | \ + CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define G_RM_SPRITE G_RM_OPA_SURF +#define G_RM_SPRITE2 G_RM_OPA_SURF2 +#define G_RM_RA_SPRITE RM_RA_SPRITE(1) +#define G_RM_RA_SPRITE2 RM_RA_SPRITE(2) +#define G_RM_AA_SPRITE G_RM_AA_TEX_TERR +#define G_RM_AA_SPRITE2 G_RM_AA_TEX_TERR2 +#define G_RM_XLU_SPRITE G_RM_XLU_SURF +#define G_RM_XLU_SPRITE2 G_RM_XLU_SURF2 +#define G_RM_AA_XLU_SPRITE G_RM_AA_XLU_SURF +#define G_RM_AA_XLU_SPRITE2 G_RM_AA_XLU_SURF2 + +/*===========================================================================* + * External functions + *===========================================================================*/ +extern u64 gspS2DEX_fifoTextStart[], gspS2DEX_fifoTextEnd[]; +extern u64 gspS2DEX_fifoDataStart[], gspS2DEX_fifoDataEnd[]; +extern u64 gspS2DEX_fifo_dTextStart[], gspS2DEX_fifo_dTextEnd[]; +extern u64 gspS2DEX_fifo_dDataStart[], gspS2DEX_fifo_dDataEnd[]; +extern u64 gspS2DEX2_fifoTextStart[], gspS2DEX2_fifoTextEnd[]; +extern u64 gspS2DEX2_fifoDataStart[], gspS2DEX2_fifoDataEnd[]; +extern u64 gspS2DEX2_xbusTextStart[], gspS2DEX2_xbusTextEnd[]; +extern u64 gspS2DEX2_xbusDataStart[], gspS2DEX2_xbusDataEnd[]; +extern void guS2DInitBg(uObjBg *); + +#ifdef F3DEX_GBI_2 +# define guS2DEmuBgRect1Cyc guS2D2EmuBgRect1Cyc /*Wrapper*/ +# define guS2DEmuSetScissor guS2D2EmuSetScissor /*Wrapper*/ + extern void guS2D2EmuSetScissor(u32, u32, u32, u32, u8); + extern void guS2D2EmuBgRect1Cyc(Gfx **, uObjBg *); +#else + extern void guS2DEmuSetScissor(u32, u32, u32, u32, u8); + extern void guS2DEmuBgRect1Cyc(Gfx **, uObjBg *); +#endif + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif +#endif /* _GS2DEX_H_ */ + +/*======== End of gs2dex.h ========*/ diff --git a/lib/ultralib/include/PR/gt.h b/lib/ultralib/include/PR/gt.h new file mode 100644 index 00000000..09b6ba2d --- /dev/null +++ b/lib/ultralib/include/PR/gt.h @@ -0,0 +1,365 @@ + +/* + * 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.h + * Creator: hsa@sgi.com + * Create Date: Thu Oct 12 15:48:14 PDT 1995 + * + * This file defines the GBI for the TURBO 3D graphics microcode. + * The turbo microcode is a special FEATURE-LIMITED microcode designed + * for specific applications. It is not for general use. + * + * (see XXX for more information) + * + */ + +/************************************************************************** + * + * $Revision: 1.16 $ + * $Date: 1998/05/28 00:14:50 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/gt.h,v $ + * + **************************************************************************/ + +#ifndef _GT_H_ +#define _GT_H_ + +/* this file should be #included AFTER gbi.h */ + +#include "sptask.h" + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif /* _LANGUAGE_C_PLUS_PLUS */ + +#include + +/* the following #defines seem out of order, but we need them + * for the microcode. + */ + +/* + * object state field: rendState + * + * This flag word is built up out of the bits from a + * subset of the G_SETGEOMETRYMODE flags from gbi.h. + * + * When each of these bits is '1', the comments below explain + * the effect on the triangles. + */ +#define GT_ZBUFFER G_ZBUFFER +#define GT_TEXTURE G_TEXTURE_ENABLE /* texture ON */ +#define GT_CULL_BACK G_CULL_BACK /* reject backfaces */ +#define GT_SHADING_SMOOTH G_SHADING_SMOOTH /* smooth shade ON */ + +/* + * object state field: textureState + * + * The lower 3 bits of this flag word contain the texture tile number + * to be used. All triangles of an object are rendered with the same + * texture tile. + */ + +/* + * object state field: flag + * + * This is a group of what would be pad bits. We use them for some + * flag bits. + */ +#define GT_FLAG_NOMTX 0x01 /* don't load the matrix */ +#define GT_FLAG_NO_XFM 0x02 /* load vtx, use verbatim */ +#define GT_FLAG_XFM_ONLY 0x04 /* xform vtx, write to *TriN */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* turbo 3D ucode: */ +extern long long int gspTurbo3DTextStart[], gspTurbo3DTextEnd[]; +extern long long int gspTurbo3DDataStart[], gspTurbo3DDataEnd[]; +extern long long int gspTurbo3D_dramTextStart[], gspTurbo3D_dramTextEnd[]; +extern long long int gspTurbo3D_dramDataStart[], gspTurbo3D_dramDataEnd[]; +extern long long int gspTurbo3D_fifoTextStart[], gspTurbo3D_fifoTextEnd[]; +extern long long int gspTurbo3D_fifoDataStart[], gspTurbo3D_fifoDataEnd[]; + +/* + * This is the global state structure. It's definition carefully + * matches the ucode, so if this structure changes, you must also change + * the ucode. + */ +typedef struct { + u16 perspNorm; /* persp normalization */ + u16 pad0; + u32 flag; + Gfx rdpOthermode; + u32 segBases[16]; /* table of segment base addrs (SEE NOTE!) */ + Vp viewport; /* the viewport to use */ + Gfx *rdpCmds; /* block of RDP data, process if !NULL + * block terminated by gDPEndDisplayList() + * (This is a segment address) + */ +} gtGlobState_t; + +/* NOTE: + * Although there are 16 segment table entries, the first one (segment 0) + * is reserved for physical memory mapping. You should not segment 0 + * to anything other than 0x0. + */ + +typedef union { + gtGlobState_t sp; + long long int force_structure_alignment; +} gtGlobState; + + +/* + * This is the 'state' structure associated with each object + * to be rendered. It's definition carefully matches the + * ucode, so if this structure changes, you must also change + * the gtoff.c tool and the ucode. + */ +typedef struct { + u32 renderState; /* render state */ + u32 textureState; /* texture state */ + u8 vtxCount; /* how many verts? */ + u8 vtxV0; /* where to load verts? */ + u8 triCount; /* how many tris? */ + u8 flag; + Gfx *rdpCmds; /* ptr (segment address) to RDP DL */ + Gfx rdpOthermode; + Mtx transform; /* the transform matrix to use */ +} gtState_t; + +typedef union { + gtState_t sp; + long long int force_structure_alignment; +} gtState; + +/* gtStateLite : same as gtState, but no matrix (see flags below) */ +/* this structure must be identical to gtState! (bad) */ +typedef struct { + u32 renderState; /* render state */ + u32 textureState; /* texture state */ + u8 vtxCount; /* how many verts? */ + u8 vtxV0; /* where to load verts? */ + u8 triCount; /* how many tris? */ + u8 flag; + Gfx *rdpCmds; /* ptr (segment address) to RDP DL */ + Gfx rdpOthermode; +} gtStateL_t; + +typedef union { + gtStateL_t sp; + long long int force_structure_alignment; +} gtStateL; + +/* + * The vertex list for the turbo display list uses the + * Vtx struct in gbi.h + * + */ + + +/* + * This structure represents a single triangle, part of the + * triangle list of the object to be rendered. + * + * NOTE: The triangle list MUST be aligned to an 8-byte boundary. + * Since this structure is only 4 bytes, we are REQUIRING that + * this structure only be used as an array of triangles, and we + * depend on the MIPS C compiler (which always aligns arrays to + * 8-byte boundaries). THIS IS DANGEROUS!!!! + * + */ +typedef struct { + u8 v0, v1, v2, flag; /* flag is which one for flat shade */ +} gtTriN; + + +/* + * This structure represents the transformed points. It is the format + * of the points written out when GT_FLAG_XFM_ONLY is set, as well as + * the format expected when GT_FLAG_NO_XFM is used. + * + * NOTE: The size and layout of these points is very similar to Vtx, + * except the screen coordinates overwrite the x,y,z,pad fields. + * (we could consider adding to the Vtx union, but we want to keep + * turbo stuff out of gbi.h) + * + * NOTE: The z is a special format. It can be used to compare vertices + * for sorting, but it should not be used for other purposes. If modified, + * the z-buffer hardware might not understand the data. + * + */ +typedef struct { + short int xscrn; /* x,y screen coordinates are SSSS10.2 */ + short int yscrn; + int zscrn; /* z screen is S15.16 */ + + short int s; /* transformed texture coord, S10.5 */ + short int t; + + u8 r; /* color (or normal) */ + u8 g; + u8 b; + u8 a; +} gtVtxOut_t; + +/* see "Data Structure" comment in gbi.h for information about why + * we use this union. + */ +typedef union { + gtVtxOut_t v; + long long int force_structure_alignment; +} gtVtxOut; + + + +/* + * state field: rdpOthermode + * + * This is one of the trickier state fields. The turbo interface + * requires the RDP othermode command to be cached by the host, + * therefore we provide a different interface in libultra to help cache + * this in the gt state (this word is just bits, you could pack them + * on your own). + * + * gtStateSetOthermode() accomplishs this, taking as arguments + * the state, one of the following mode enums, and a piece of data + * (othermode parameters from gbi.h). + * + * By definition, the othermode word from the gt state structure is sent + * to the RDP *before* any RDP commands from the rdpCmds[] field. The + * othermode is *always* sent. + * + * Stated another way, NONE of the gbi RDP othermode commands equivalent + * to those listed here are allowed in the rdpCmd[] field of the + * gt state structure. + * + * Notice also that many of these commands do not make sense for + * the turbo ucode (they control features not supported, like mip-mapping). + * They are only included here for completeness. + * + */ +typedef enum { + GT_CLEAR, /* special gt mode, clears othermode state */ + GT_ALPHACOMPARE, + GT_ZSRCSEL, + GT_RENDERMODE, + GT_ALPHADITHER, + GT_RGBDITHER, + GT_COMBKEY, + GT_TEXTCONV, + GT_TEXTFILT, + GT_TEXTLUT, + GT_TEXTLOD, + GT_TEXTDETAIL, + GT_TEXTPERSP, + GT_CYCLETYPE, + GT_PIPELINE +} gtStateOthermode_t; + +/* + * This call builds up an othermode command word. The 'mode' is one of + * the above modes, the 'data' field comes from gbi.h, it is the data + * field for the equivalent gbi setothermode macro. + */ +extern void gtStateSetOthermode(Gfx *om, gtStateOthermode_t mode, int data); + +/* + * This call dumps a turbo display list for use with gbi2mem and RSPSIM + */ +#define GT_DUMPTURBO_HANGAFTER 64 +#define GT_DUMPTURBO_NOTEXTURES 128 +extern void gtDumpTurbo(OSTask *tp,u8 flags); + +/* + * Special macros to init othermode words to all 0's, a good default + * value. + */ +#define gDPClearOtherMode(pkt) \ +{ \ + Gfx *_g = (Gfx *)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE, 24, 8); \ + _g->words.w1 = 0x0; \ +} + +#define gsDPClearOtherMode() \ +{ \ + _SHIFTL(G_RDPSETOTHERMODE, 24, 8), 0x0 \ +} + +/* + * Special macros to end DP blocks (see above). These commands + * generate all 0's, which the turbo ucode looks for. They *aren't* + * real DP commands! + */ +#define gDPEndDisplayList(pkt) gSPNoOp(pkt) +#define gsDPEndDisplayList() gsSPNoOp() + +/* + * This structure is a turbo 'object', the turbo display list is + * simply a list of these. + * + * NOTE: All pointers are segment addresses + * + * NOTE: If (statep->flag & GT_FLAG_XFM_ONLY), the trip field is + * interpreted as a pointer to gtVtxOut[] that can be used to store + * the transformed points. (statep->triCount should be 0, else bad + * things could happen...) + * + * NOTE: If (statep->flag & GT_FLAG_NO_XFM), the vtxp field is + * interpreted as a pointer to gtVtxOut[] that can be used to load + * pre-transformed points. + * + */ +typedef struct { + gtGlobState *gstatep; /* global state, usually NULL */ + gtState *statep; /* if this is NULL, end object processing */ + Vtx *vtxp; /* if this is NULL, use points in buffer */ + gtTriN *trip; /* if this is NULL, use tris in buffer */ +} gtGfx_t; + +typedef union { + gtGfx_t obj; + long long int force_structure_alignment; +} gtGfx; + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_ASSEMBLY +#include +#endif /* _LANGUAGE_ASSEMBLY */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif /* _LANGUAGE_C_PLUS_PLUS */ + +#ifdef _LANGUAGE_MAKEROM +#endif /* _LANGUAGE_MAKEROM */ + +#endif /* _GT_H_ */ diff --git a/lib/ultralib/include/PR/gu.h b/lib/ultralib/include/PR/gu.h new file mode 100644 index 00000000..aa83ba08 --- /dev/null +++ b/lib/ultralib/include/PR/gu.h @@ -0,0 +1,269 @@ +#ifndef _GU_H_ +#define _GU_H_ + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.48 $ + * $Date: 1999/07/13 08:00:20 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/gu.h,v $ + * + **************************************************************************/ + +#include +#include +#include + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#define M_PI 3.14159265358979323846 +#define M_DTOR (3.14159265358979323846/180.0) + +#define FTOFIX32(x) (long)((x) * (float)0x00010000) +#define FIX32TOF(x) ((float)(x) * (1.0f / (float)0x00010000)) +#define FTOFRAC8(x) ((int) MIN(((x) * (128.0f)), 127.0f) & 0xff) + +#define FILTER_WRAP 0 +#define FILTER_CLAMP 1 + +#define RAND(x) (guRandom()%x) /* random number between 0 to x */ + +/* + * Data Structures + */ +typedef struct { + unsigned char *base; + int fmt, siz; + int xsize, ysize; + int lsize; + /* current tile info */ + int addr; + int w, h; + int s, t; +} Image; + +typedef struct { + float col[3]; + float pos[3]; + float a1, a2; /* actual color = col/(a1*dist + a2) */ +} PositionalLight; + + +/* + * Function Prototypes + */ + +extern int guLoadTextureBlockMipMap(Gfx **glist, 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); + +extern int guGetDPLoadTextureTileSz (int ult, int lrt); +extern void guDPLoadTextureTile (Gfx *glistp, 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); + + +/* + * matrix operations: + * + * The 'F' version is floating point, in case the application wants + * to do matrix manipulations and convert to fixed-point at the last + * minute. + */ +extern void guMtxIdent(Mtx *m); +extern void guMtxIdentF(float mf[4][4]); +extern void guOrtho(Mtx *m, float l, float r, float b, float t, + float n, float f, float scale); +extern void guOrthoF(float mf[4][4], float l, float r, float b, float t, + float n, float f, float scale); +extern void guFrustum(Mtx *m, float l, float r, float b, float t, + float n, float f, float scale); +extern void guFrustumF(float mf[4][4], float l, float r, float b, float t, + float n, float f, float scale); +extern void guPerspective(Mtx *m, u16 *perspNorm, float fovy, + float aspect, float near, float far, float scale); +extern void guPerspectiveF(float mf[4][4], u16 *perspNorm, float fovy, + float aspect, float near, float far, float scale); +extern void guLookAt(Mtx *m, + float xEye, float yEye, float zEye, + float xAt, float yAt, float zAt, + float xUp, float yUp, float zUp); +extern void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye, + float xAt, float yAt, float zAt, + float xUp, float yUp, float zUp); +extern void guLookAtReflect(Mtx *m, LookAt *l, + float xEye, float yEye, float zEye, + float xAt, float yAt, float zAt, + float xUp, float yUp, float zUp); +extern 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); +extern 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, + float xl2, float yl2, float zl2, + int twidth, int theight); +extern 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, + float xl2, float yl2, float zl2, + int twidth, int theight); +extern void guLookAtStereo(Mtx *m, + float xEye, float yEye, float zEye, + float xAt, float yAt, float zAt, + float xUp, float yUp, float zUp, + float eyedist); +extern 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); +extern void guRotate(Mtx *m, float a, float x, float y, float z); +extern void guRotateF(float mf[4][4], float a, float x, float y, float z); +extern void guRotateRPY(Mtx *m, float r, float p, float y); +extern void guRotateRPYF(float mf[4][4], float r, float p, float h); +extern void guAlign(Mtx *m, float a, float x, float y, float z); +extern void guAlignF(float mf[4][4], float a, float x, float y, float z); +extern void guScale(Mtx *m, float x, float y, float z); +extern void guScaleF(float mf[4][4], float x, float y, float z); +extern void guTranslate(Mtx *m, float x, float y, float z); +extern void guTranslateF(float mf[4][4], float x, float y, float z); +extern void guPosition(Mtx *m, float r, float p, float h, float s, + float x, float y, float z); +extern void guPositionF(float mf[4][4], float r, float p, float h, float s, + float x, float y, float z); +extern void guMtxF2L(float mf[4][4], Mtx *m); +extern void guMtxL2F(float mf[4][4], Mtx *m); +extern void guMtxCatF(float m[4][4], float n[4][4], float r[4][4]); +extern void guMtxCatL(Mtx *m, Mtx *n, Mtx *res); +extern void guMtxXFMF(float mf[4][4], float x, float y, float z, + float *ox, float *oy, float *oz); +extern void guMtxXFML(Mtx *m, float x, float y, float z, + float *ox, float *oy, float *oz); + +/* vector utility: */ +extern void guNormalize(float *x, float *y, float *z); + +/* light utilities: */ +void guPosLight(PositionalLight *pl, Light *l, + float xOb, float yOb, float zOb); +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); +extern int guRandom(void); + +/* + * Math functions + */ +extern float sinf(float angle); +extern float cosf(float angle); +extern signed short sins (unsigned short angle); +extern signed short coss (unsigned short angle); +extern float sqrtf(float value); +#ifdef __sgi +#pragma intrinsic(sqrtf); +#endif + +/* + * Dump routines for low-level display lists + */ +/* flag values for guParseRdpDL() */ +#define GU_PARSERDP_VERBOSE 1 +#define GU_PARSERDP_PRAREA 2 +#define GU_PARSERDP_PRHISTO 4 +#define GU_PARSERDP_DUMPONLY 32 /* doesn't need to be same as */ + /* GU_PARSEGBI_DUMPOLNY, but this */ + /* allows app to use interchangeably */ + +extern void guParseRdpDL(u64 *rdp_dl, u64 nbytes, u8 flags); +extern void guParseString(char *StringPointer, u64 nbytes); + +/* + * NO LONGER SUPPORTED, + * use guParseRdpDL with GU_PARSERDP_DUMPONLY flags + */ +/* extern void guDumpRawRdpDL(u64 *rdp_dl, u64 nbytes); */ + +/* flag values for guBlinkRdpDL() */ +#define GU_BLINKRDP_HILITE 1 +#define GU_BLINKRDP_EXTRACT 2 + +extern void +guBlinkRdpDL(u64 *rdp_dl_in, u64 nbytes_in, + u64 *rdp_dl_out, u64 *nbytes_out, + u32 x, u32 y, u32 radius, + u8 red, u8 green, u8 blue, + u8 flags); + +/* flag values for guParseGbiDL() */ +#define GU_PARSEGBI_ROWMAJOR 1 +#define GU_PARSEGBI_NONEST 2 +#define GU_PARSEGBI_FLTMTX 4 +#define GU_PARSEGBI_SHOWDMA 8 +#define GU_PARSEGBI_ALLMTX 16 +#define GU_PARSEGBI_DUMPONLY 32 +/* +#define GU_PARSEGBI_HANGAFTER 64 +#define GU_PARSEGBI_NOTEXTURES 128 +*/ +extern void guParseGbiDL(u64 *gbi_dl, u32 nbytes, u8 flags); +extern void guDumpGbiDL(OSTask *tp,u8 flags); + +#define GU_PARSE_GBI_TYPE 1 +#define GU_PARSE_RDP_TYPE 2 +#define GU_PARSE_READY 3 +#define GU_PARSE_MEM_BLOCK 4 +#define GU_PARSE_ABI_TYPE 5 +#define GU_PARSE_STRING_TYPE 6 + +typedef struct { + int dataSize; + int dlType; + int flags; + u32 paddr; +} guDLPrintCB; + +void guSprite2DInit(uSprite *SpritePointer, + void *SourceImagePointer, + void *TlutPointer, + int Stride, + int SubImageWidth, + int SubImageHeight, + int SourceImageType, + int SourceImageBitSize, + int SourceImageOffsetS, + int SourceImageOffsetT); + +#endif /* !_GU_H_ */ diff --git a/lib/ultralib/include/PR/libaudio.h b/lib/ultralib/include/PR/libaudio.h new file mode 100644 index 00000000..33017b72 --- /dev/null +++ b/lib/ultralib/include/PR/libaudio.h @@ -0,0 +1,947 @@ +/*==================================================================== + * libaudio.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. + *====================================================================*/ + +/************************************************************************** + * + * $Revision: 1.173 $ + * $Date: 1997/12/01 12:42:21 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/libaudio.h,v $ + * + **************************************************************************/ + +#ifndef __LIB_AUDIO__ +#define __LIB_AUDIO__ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include + +/*********************************************************************** + * misc defines + ***********************************************************************/ +#ifndef _EMULATOR +# ifdef AUD_PROFILE + +#define PROFILE_AUD(num, cnt, max, min) \ +{ \ + u32 currCnt = osGetCount(); \ + currCnt -= lastCnt[cnt_index]; \ + cnt_index--; \ + cnt += currCnt; \ + num++; \ + \ + if ( currCnt > max ) max = currCnt; \ + if ( currCnt < min ) min = currCnt; \ +} + +# endif /* AUD_PROFILE */ +#endif /* EMULATOR */ + +#ifndef NULL +#define NULL 0 +#endif + +#define AL_FX_BUFFER_SIZE 8192 +#define AL_FRAME_INIT -1 +#define AL_USEC_PER_FRAME 16000 +#define AL_MAX_PRIORITY 127 +#define AL_GAIN_CHANGE_TIME 1000 + +typedef s32 ALMicroTime; +typedef u8 ALPan; + +#define AL_PAN_CENTER 64 +#define AL_PAN_LEFT 0 +#define AL_PAN_RIGHT 127 +#define AL_VOL_FULL 127 +#define AL_KEY_MIN 0 +#define AL_KEY_MAX 127 +#define AL_DEFAULT_FXMIX 0 +#define AL_SUSTAIN 63 + +/*********************************************************************** + * Error handling + ***********************************************************************/ + +#ifdef _DEBUG +#define ALFailIf(condition, error) \ + if (condition) { \ + __osError(error, 0); \ + return; } + +#else +#define ALFailIf(condition, error) \ + if (condition) { \ + return; } +#endif + +#ifdef _DEBUG +#define ALFlagFailIf(condition, flag, error) \ + if (condition) { \ + if(flag) __osError(error, 0); \ + return; } + +#else +#define ALFlagFailIf(condition, flag, error) \ + if (condition) { \ + return; } +#endif + +/*********************************************************************** + * Audio Library global routines + ***********************************************************************/ +typedef struct ALLink_s { + struct ALLink_s *next; + struct ALLink_s *prev; +} ALLink; + +void alUnlink(ALLink *element); +void alLink(ALLink *element, ALLink *after); + +typedef s32 (*ALDMAproc)(s32 addr, s32 len, void *state); +typedef ALDMAproc (*ALDMANew)(void *state); + +void alCopy(void *src, void *dest, s32 len); + +typedef struct { + u8 *base; + u8 *cur; + s32 len; + s32 count; +} ALHeap; + +#define AL_HEAP_DEBUG 1 +#define AL_HEAP_MAGIC 0x20736a73 +#define AL_HEAP_INIT 0 + +void alHeapInit(ALHeap *hp, u8 *base, s32 len); +void *alHeapDBAlloc(u8 *file, s32 line, ALHeap *hp, s32 num, s32 size); +s32 alHeapCheck(ALHeap *hp); + +#ifdef _DEBUG +#define alHeapAlloc(hp, elem ,size) alHeapDBAlloc((u8 *) __FILE__,__LINE__,(hp),(elem),(size)) +#else +#define alHeapAlloc(hp, elem ,size) alHeapDBAlloc(0, 0,(hp),(elem),(size)) +#endif + +/*********************************************************************** + * FX Stuff + ***********************************************************************/ +#define AL_FX_NONE 0 +#define AL_FX_SMALLROOM 1 +#define AL_FX_BIGROOM 2 +#define AL_FX_CHORUS 3 +#define AL_FX_FLANGE 4 +#define AL_FX_ECHO 5 +#define AL_FX_CUSTOM 6 + +typedef u8 ALFxId; +typedef void *ALFxRef; + +/*********************************************************************** + * data structures for sound banks + ***********************************************************************/ + +#define AL_BANK_VERSION 0x4231 /* 'B1' */ + +/* Possible wavetable types */ +enum {AL_ADPCM_WAVE = 0, + AL_RAW16_WAVE}; + +typedef struct { + s32 order; + s32 npredictors; + s16 book[1]; /* Actually variable size. Must be 8-byte aligned */ +} ALADPCMBook; + +typedef struct { + u32 start; + u32 end; + u32 count; + ADPCM_STATE state; +} ALADPCMloop; + +typedef struct { + u32 start; + u32 end; + u32 count; +} ALRawLoop; + +typedef struct { + ALMicroTime attackTime; + ALMicroTime decayTime; + ALMicroTime releaseTime; + u8 attackVolume; + u8 decayVolume; +} ALEnvelope; + +typedef struct { + u8 velocityMin; + u8 velocityMax; + u8 keyMin; + u8 keyMax; + u8 keyBase; + s8 detune; +} ALKeyMap; + +typedef struct { + ALADPCMloop *loop; + ALADPCMBook *book; +} ALADPCMWaveInfo; + +typedef struct { + ALRawLoop *loop; +} ALRAWWaveInfo; + +typedef struct ALWaveTable_s { + u8 *base; /* ptr to start of wave data */ + s32 len; /* length of data in bytes */ + u8 type; /* compression type */ + u8 flags; /* offset/address flags */ + union { + ALADPCMWaveInfo adpcmWave; + ALRAWWaveInfo rawWave; + } waveInfo; +} ALWaveTable; + +typedef struct ALSound_s { + ALEnvelope *envelope; + ALKeyMap *keyMap; + ALWaveTable *wavetable; /* offset to wavetable struct */ + ALPan samplePan; + u8 sampleVolume; + u8 flags; +} ALSound; + +typedef struct { + u8 volume; /* overall volume for this instrument */ + ALPan pan; /* 0 = hard left, 127 = hard right */ + u8 priority; /* voice priority for this instrument */ + u8 flags; + u8 tremType; /* the type of tremelo osc. to use */ + u8 tremRate; /* the rate of the tremelo osc. */ + u8 tremDepth; /* the depth of the tremelo osc */ + u8 tremDelay; /* the delay for the tremelo osc */ + u8 vibType; /* the type of tremelo osc. to use */ + u8 vibRate; /* the rate of the tremelo osc. */ + u8 vibDepth; /* the depth of the tremelo osc */ + u8 vibDelay; /* the delay for the tremelo osc */ + s16 bendRange; /* pitch bend range in cents */ + s16 soundCount; /* number of sounds in this array */ + ALSound *soundArray[1]; +} ALInstrument; + +typedef struct ALBank_s { + s16 instCount; /* number of programs in this bank */ + u8 flags; + u8 pad; + s32 sampleRate; /* e.g. 44100, 22050, etc... */ + ALInstrument *percussion; /* default percussion for GM */ + ALInstrument *instArray[1]; /* ARRAY of instruments */ +} ALBank; + +typedef struct { /* Note: sizeof won't be correct */ + s16 revision; /* format revision of this file */ + s16 bankCount; /* number of banks */ + ALBank *bankArray[1]; /* ARRAY of bank offsets */ +} ALBankFile; + +void alBnkfNew(ALBankFile *f, u8 *table); + +/*********************************************************************** + * Sequence Files + ***********************************************************************/ +#define AL_SEQBANK_VERSION 'S1' + +typedef struct { + u8 *offset; + s32 len; +} ALSeqData; + +typedef struct { /* Note: sizeof won't be correct */ + s16 revision; /* format revision of this file */ + s16 seqCount; /* number of sequences */ + ALSeqData seqArray[1]; /* ARRAY of sequence info */ +} ALSeqFile; + +void alSeqFileNew(ALSeqFile *f, u8 *base); + +/*********************************************************************** + * Synthesis driver stuff + ***********************************************************************/ +typedef ALMicroTime (*ALVoiceHandler)(void *); + +typedef struct { + s32 maxVVoices; /* obsolete */ + s32 maxPVoices; + s32 maxUpdates; + s32 maxFXbusses; + void *dmaproc; + ALHeap *heap; + s32 outputRate; /* output sample rate */ + ALFxId fxType; + s32 *params; +} ALSynConfig; + +typedef struct ALPlayer_s { + struct ALPlayer_s *next; + void *clientData; /* storage for client callback */ + ALVoiceHandler handler; /* voice handler for player */ + ALMicroTime callTime; /* usec requested callback */ + s32 samplesLeft; /* usec remaining to callback */ +} ALPlayer; + +typedef struct ALVoice_s { + ALLink node; + struct PVoice_s *pvoice; + ALWaveTable *table; + void *clientPrivate; + s16 state; + s16 priority; + s16 fxBus; + s16 unityPitch; +} ALVoice; + +typedef struct ALVoiceConfig_s { + s16 priority; /* voice priority */ + s16 fxBus; /* bus assignment */ + u8 unityPitch; /* unity pitch flag */ +} ALVoiceConfig; + +typedef struct { + ALPlayer *head; /* client list head */ + ALLink pFreeList; /* list of free physical voices */ + ALLink pAllocList; /* list of allocated physical voices */ + ALLink pLameList; /* list of voices ready to be freed */ + s32 paramSamples; + s32 curSamples; /* samples from start of game */ + ALDMANew dma; + ALHeap *heap; + + struct ALParam_s *paramList; + + struct ALMainBus_s *mainBus; + struct ALAuxBus_s *auxBus; /* ptr to array of aux bus structs */ + struct ALFilter_s *outputFilter; /* last filter in the filter chain */ + + s32 numPVoices; + s32 maxAuxBusses; + s32 outputRate; /* output sample rate */ + s32 maxOutSamples; /* Maximum samples rsp can generate + at one time at output rate */ +} ALSynth; + +void alSynNew(ALSynth *s, ALSynConfig *config); +void alSynDelete(ALSynth *s); + +void alSynAddPlayer(ALSynth *s, ALPlayer *client); +void alSynRemovePlayer(ALSynth *s, ALPlayer *client); + +s32 alSynAllocVoice(ALSynth *s, ALVoice *v, ALVoiceConfig *vc); +void alSynFreeVoice(ALSynth *s, ALVoice *voice); + +void alSynStartVoice(ALSynth *s, ALVoice *voice, ALWaveTable *w); +void alSynStartVoiceParams(ALSynth *s, ALVoice *voice, ALWaveTable *w, + f32 pitch, s16 vol, ALPan pan, u8 fxmix, + ALMicroTime t); +void alSynStopVoice(ALSynth *s, ALVoice *voice); + +void alSynSetVol(ALSynth *s, ALVoice *v, s16 vol, ALMicroTime delta); +void alSynSetPitch(ALSynth *s, ALVoice *voice, f32 ratio); +void alSynSetPan(ALSynth *s, ALVoice *voice, ALPan pan); +void alSynSetFXMix(ALSynth *s, ALVoice *voice, u8 fxmix); +void alSynSetPriority(ALSynth *s, ALVoice *voice, s16 priority); +s16 alSynGetPriority(ALSynth *s, ALVoice *voice); + +ALFxRef *alSynAllocFX(ALSynth *s, s16 bus, ALSynConfig *c, ALHeap *hp); +ALFxRef alSynGetFXRef(ALSynth *s, s16 bus, s16 index); +void alSynFreeFX(ALSynth *s, ALFxRef *fx); +void alSynSetFXParam(ALSynth *s, ALFxRef fx, s16 paramID, void *param); + +/*********************************************************************** + * Audio Library (AL) stuff + ***********************************************************************/ +typedef struct { + ALSynth drvr; +} ALGlobals; + +extern ALGlobals *alGlobals; + +void alInit(ALGlobals *glob, ALSynConfig *c); +void alClose(ALGlobals *glob); + +Acmd *alAudioFrame(Acmd *cmdList, s32 *cmdLen, s16 *outBuf, s32 outLen); + +/*********************************************************************** + * Sequence Player stuff + ***********************************************************************/ + +/* + * Play states + */ +#define AL_STOPPED 0 +#define AL_PLAYING 1 +#define AL_STOPPING 2 + +#define AL_DEFAULT_PRIORITY 5 +#define AL_DEFAULT_VOICE 0 +#define AL_MAX_CHANNELS 16 + +/* + * Audio Library event type definitions + */ +enum ALMsg { + AL_SEQ_REF_EVT, /* Reference to a pending event in the sequence. */ + AL_SEQ_MIDI_EVT, + AL_SEQP_MIDI_EVT, + AL_TEMPO_EVT, + AL_SEQ_END_EVT, + AL_NOTE_END_EVT, + AL_SEQP_ENV_EVT, + AL_SEQP_META_EVT, + AL_SEQP_PROG_EVT, + AL_SEQP_API_EVT, + AL_SEQP_VOL_EVT, + AL_SEQP_LOOP_EVT, + AL_SEQP_PRIORITY_EVT, + AL_SEQP_SEQ_EVT, + AL_SEQP_BANK_EVT, + AL_SEQP_PLAY_EVT, + AL_SEQP_STOP_EVT, + AL_SEQP_STOPPING_EVT, + AL_TRACK_END, + AL_CSP_LOOPSTART, + AL_CSP_LOOPEND, + AL_CSP_NOTEOFF_EVT, + AL_TREM_OSC_EVT, + AL_VIB_OSC_EVT +}; + +/* + * Midi event definitions + */ +#define AL_EVTQ_END 0x7fffffff + +enum AL_MIDIstatus { + /* For distinguishing channel number from status */ + AL_MIDI_ChannelMask = 0x0F, + AL_MIDI_StatusMask = 0xF0, + + /* Channel voice messages */ + AL_MIDI_ChannelVoice = 0x80, + AL_MIDI_NoteOff = 0x80, + AL_MIDI_NoteOn = 0x90, + AL_MIDI_PolyKeyPressure = 0xA0, + AL_MIDI_ControlChange = 0xB0, + AL_MIDI_ChannelModeSelect = 0xB0, + AL_MIDI_ProgramChange = 0xC0, + AL_MIDI_ChannelPressure = 0xD0, + AL_MIDI_PitchBendChange = 0xE0, + + /* System messages */ + AL_MIDI_SysEx = 0xF0, /* System Exclusive */ + + /* System common */ + AL_MIDI_SystemCommon = 0xF1, + AL_MIDI_TimeCodeQuarterFrame = 0xF1, + AL_MIDI_SongPositionPointer = 0xF2, + AL_MIDI_SongSelect = 0xF3, + AL_MIDI_Undefined1 = 0xF4, + AL_MIDI_Undefined2 = 0xF5, + AL_MIDI_TuneRequest = 0xF6, + AL_MIDI_EOX = 0xF7, /* End of System Exclusive */ + + /* System real time */ + AL_MIDI_SystemRealTime = 0xF8, + AL_MIDI_TimingClock = 0xF8, + AL_MIDI_Undefined3 = 0xF9, + AL_MIDI_Start = 0xFA, + AL_MIDI_Continue = 0xFB, + AL_MIDI_Stop = 0xFC, + AL_MIDI_Undefined4 = 0xFD, + AL_MIDI_ActiveSensing = 0xFE, + AL_MIDI_SystemReset = 0xFF, + AL_MIDI_Meta = 0xFF /* MIDI Files only */ +}; + +enum AL_MIDIctrl { + AL_MIDI_VOLUME_CTRL = 0x07, + AL_MIDI_PAN_CTRL = 0x0A, + AL_MIDI_PRIORITY_CTRL = 0x10, /* use general purpose controller for priority */ + AL_MIDI_FX_CTRL_0 = 0x14, + AL_MIDI_FX_CTRL_1 = 0x15, + AL_MIDI_FX_CTRL_2 = 0x16, + AL_MIDI_FX_CTRL_3 = 0x17, + AL_MIDI_FX_CTRL_4 = 0x18, + AL_MIDI_FX_CTRL_5 = 0x19, + AL_MIDI_FX_CTRL_6 = 0x1A, + AL_MIDI_FX_CTRL_7 = 0x1B, + AL_MIDI_FX_CTRL_8 = 0x1C, + AL_MIDI_FX_CTRL_9 = 0x1D, + AL_MIDI_SUSTAIN_CTRL = 0x40, + AL_MIDI_FX1_CTRL = 0x5B, + AL_MIDI_FX3_CTRL = 0x5D +}; + +enum AL_MIDImeta { + AL_MIDI_META_TEMPO = 0x51, + AL_MIDI_META_EOT = 0x2f +}; + + +#define AL_CMIDI_BLOCK_CODE 0xFE +#define AL_CMIDI_LOOPSTART_CODE 0x2E +#define AL_CMIDI_LOOPEND_CODE 0x2D +#define AL_CMIDI_CNTRL_LOOPSTART 102 +#define AL_CMIDI_CNTRL_LOOPEND 103 +#define AL_CMIDI_CNTRL_LOOPCOUNT_SM 104 +#define AL_CMIDI_CNTRL_LOOPCOUNT_BIG 105 + +typedef struct { + u8 *curPtr; /* ptr to the next event */ + s32 lastTicks; /* sequence clock ticks (used by alSeqSetLoc) */ + s32 curTicks; /* sequence clock ticks of next event (used by loop end test) */ + s16 lastStatus; /* the last status msg */ +} ALSeqMarker; + +typedef struct { + s32 ticks; /* MIDI, Tempo and End events must start with ticks */ + u8 status; + u8 byte1; + u8 byte2; + u32 duration; +} ALMIDIEvent; + +typedef struct { + s32 ticks; + u8 status; + u8 type; + u8 len; + u8 byte1; + u8 byte2; + u8 byte3; +} ALTempoEvent; + +typedef struct { + s32 ticks; + u8 status; + u8 type; + u8 len; +} ALEndEvent; + +typedef struct { + struct ALVoice_s *voice; +} ALNoteEvent; + +typedef struct { + struct ALVoice_s *voice; + ALMicroTime delta; + u8 vol; +} ALVolumeEvent; + +typedef struct { + s16 vol; +} ALSeqpVolEvent; + +typedef struct { + ALSeqMarker *start; + ALSeqMarker *end; + s32 count; +} ALSeqpLoopEvent; + +typedef struct { + u8 chan; + u8 priority; +} ALSeqpPriorityEvent; + +typedef struct { + void *seq; /* pointer to a seq (could be an ALSeq or an ALCSeq). */ +} ALSeqpSeqEvent; + +typedef struct { + ALBank *bank; +} ALSeqpBankEvent; + +typedef struct { + struct ALVoiceState_s *vs; + void *oscState; + u8 chan; +} ALOscEvent; + +typedef struct { + s16 type; + union { + ALMIDIEvent midi; + ALTempoEvent tempo; + ALEndEvent end; + ALNoteEvent note; + ALVolumeEvent vol; + ALSeqpLoopEvent loop; + ALSeqpVolEvent spvol; + ALSeqpPriorityEvent sppriority; + ALSeqpSeqEvent spseq; + ALSeqpBankEvent spbank; + ALOscEvent osc; + } msg; +} ALEvent; + +typedef struct { + ALLink node; + ALMicroTime delta; + ALEvent evt; +} ALEventListItem; + +typedef struct { + ALLink freeList; + ALLink allocList; + s32 eventCount; +} ALEventQueue; + +void alEvtqNew(ALEventQueue *evtq, ALEventListItem *items, + s32 itemCount); +ALMicroTime alEvtqNextEvent(ALEventQueue *evtq, ALEvent *evt); +void alEvtqPostEvent(ALEventQueue *evtq, ALEvent *evt, + ALMicroTime delta); +void alEvtqFlush(ALEventQueue *evtq); +void alEvtqFlushType(ALEventQueue *evtq, s16 type); + + +#define AL_PHASE_ATTACK 0 +#define AL_PHASE_NOTEON 0 +#define AL_PHASE_DECAY 1 +#define AL_PHASE_SUSTAIN 2 +#define AL_PHASE_RELEASE 3 +#define AL_PHASE_SUSTREL 4 + +typedef struct ALVoiceState_s { + struct ALVoiceState_s *next;/* MUST be first */ + ALVoice voice; + ALSound *sound; + ALMicroTime envEndTime; /* time of envelope segment end */ + f32 pitch; /* currect pitch ratio */ + f32 vibrato; /* current value of the vibrato */ + u8 envGain; /* current envelope gain */ + u8 channel; /* channel assignment */ + u8 key; /* note on key number */ + u8 velocity; /* note on velocity */ + u8 envPhase; /* what envelope phase */ + u8 phase; + u8 tremelo; /* current value of the tremelo */ + u8 flags; /* bit 0 tremelo flag + bit 1 vibrato flag */ +} ALVoiceState; + +typedef struct { + ALInstrument *instrument; /* instrument assigned to this chan */ + s16 bendRange; /* pitch bend range in cents */ + ALFxId fxId; /* type of fx assigned to this chan */ + ALPan pan; /* overall pan for this chan */ + u8 priority; /* priority for this chan */ + u8 vol; /* current volume for this chan */ + u8 fxmix; /* current fx mix for this chan */ + u8 sustain; /* current sustain pedal state */ + f32 pitchBend; /* current pitch bend val in cents */ +} ALChanState; + +typedef struct ALSeq_s { + u8 *base; /* ptr to start of sequence file */ + u8 *trackStart; /* ptr to first MIDI event */ + u8 *curPtr; /* ptr to next event to read */ + s32 lastTicks; /* MIDI ticks for last event */ + s32 len; /* length of sequence in bytes */ + f32 qnpt; /* qrter notes / tick (1/division) */ + s16 division; /* ticks per quarter note */ + s16 lastStatus; /* for running status */ +} ALSeq; + +typedef struct { + u32 trackOffset[16]; + u32 division; +} ALCMidiHdr; + +typedef struct ALCSeq_s { + ALCMidiHdr *base; /* ptr to start of sequence file */ + u32 validTracks; /* set of flags, showing valid tracks */ + f32 qnpt; /* qrter notes / tick (1/division) */ + u32 lastTicks; /* keep track of ticks incase app wants */ + u32 lastDeltaTicks; /* number of delta ticks of last event */ + u32 deltaFlag; /* flag: set if delta's not subtracted */ + u8 *curLoc[16]; /* ptr to current track location, */ + /* may point to next event, or may point */ + /* to a backup code */ + u8 *curBUPtr[16]; /* ptr to next event if in backup mode */ + u8 curBULen[16]; /* if > 0, then in backup mode */ + u8 lastStatus[16]; /* for running status */ + u32 evtDeltaTicks[16]; /* delta time to next event */ +} ALCSeq; + +typedef struct { + u32 validTracks; + s32 lastTicks; + u32 lastDeltaTicks; + u8 *curLoc[16]; + u8 *curBUPtr[16]; + u8 curBULen[16]; + u8 lastStatus[16]; + u32 evtDeltaTicks[16]; +} ALCSeqMarker; + +#define NO_SOUND_ERR_MASK 0x01 +#define NOTE_OFF_ERR_MASK 0x02 +#define NO_VOICE_ERR_MASK 0x04 + +typedef struct { + s32 maxVoices; /* max number of voices to alloc */ + s32 maxEvents; /* max internal events to support */ + u8 maxChannels; /* max MIDI channels to support (16)*/ + u8 debugFlags; /* control which error get reported */ + ALHeap *heap; /* ptr to initialized heap */ + void *initOsc; + void *updateOsc; + void *stopOsc; +} ALSeqpConfig; + +typedef ALMicroTime (*ALOscInit)(void **oscState,f32 *initVal, u8 oscType, + u8 oscRate, u8 oscDepth, u8 oscDelay); +typedef ALMicroTime (*ALOscUpdate)(void *oscState, f32 *updateVal); +typedef void (*ALOscStop)(void *oscState); + +typedef struct { + ALPlayer node; /* note: must be first in structure */ + ALSynth *drvr; /* reference to the client driver */ + ALSeq *target; /* current sequence */ + ALMicroTime curTime; + ALBank *bank; /* current ALBank */ + s32 uspt; /* microseconds per tick */ + s32 nextDelta; /* microseconds to next callback */ + s32 state; + u16 chanMask; /* active channels */ + s16 vol; /* overall sequence volume */ + u8 maxChannels; /* number of MIDI channels */ + u8 debugFlags; /* control which error get reported */ + ALEvent nextEvent; + ALEventQueue evtq; + ALMicroTime frameTime; + ALChanState *chanState; /* 16 channels for MIDI */ + ALVoiceState *vAllocHead; /* list head for allocated voices */ + ALVoiceState *vAllocTail; /* list tail for allocated voices */ + ALVoiceState *vFreeList; /* list of free voice state structs */ + ALOscInit initOsc; + ALOscUpdate updateOsc; + ALOscStop stopOsc; + ALSeqMarker *loopStart; + ALSeqMarker *loopEnd; + s32 loopCount; /* -1 = loop forever, 0 = no loop */ +} ALSeqPlayer; + +typedef struct { + ALPlayer node; /* note: must be first in structure */ + ALSynth *drvr; /* reference to the client driver */ + ALCSeq *target; /* current sequence */ + ALMicroTime curTime; + ALBank *bank; /* current ALBank */ + s32 uspt; /* microseconds per tick */ + s32 nextDelta; /* microseconds to next callback */ + s32 state; + u16 chanMask; /* active channels */ + s16 vol; /* overall sequence volume */ + u8 maxChannels; /* number of MIDI channels */ + u8 debugFlags; /* control which error get reported */ + ALEvent nextEvent; + ALEventQueue evtq; + ALMicroTime frameTime; + ALChanState *chanState; /* 16 channels for MIDI */ + ALVoiceState *vAllocHead; /* list head for allocated voices */ + ALVoiceState *vAllocTail; /* list tail for allocated voices */ + ALVoiceState *vFreeList; /* list of free voice state structs */ + ALOscInit initOsc; + ALOscUpdate updateOsc; + ALOscStop stopOsc; +} ALCSPlayer; + +/* + * Sequence data representation routines + */ +void alSeqNew(ALSeq *seq, u8 *ptr, s32 len); +void alSeqNextEvent(ALSeq *seq, ALEvent *event); +s32 alSeqGetTicks(ALSeq *seq); +f32 alSeqTicksToSec(ALSeq *seq, s32 ticks, u32 tempo); +u32 alSeqSecToTicks(ALSeq *seq, f32 sec, u32 tempo); +void alSeqNewMarker(ALSeq *seq, ALSeqMarker *m, u32 ticks); +void alSeqSetLoc(ALSeq *seq, ALSeqMarker *marker); +void alSeqGetLoc(ALSeq *seq, ALSeqMarker *marker); +/* + * Compact Sequence data representation routines + */ +void alCSeqNew(ALCSeq *seq, u8 *ptr); +void alCSeqNextEvent(ALCSeq *seq,ALEvent *evt); +s32 alCSeqGetTicks(ALCSeq *seq); +f32 alCSeqTicksToSec(ALCSeq *seq, s32 ticks, u32 tempo); +u32 alCSeqSecToTicks(ALCSeq *seq, f32 sec, u32 tempo); +void alCSeqNewMarker(ALCSeq *seq, ALCSeqMarker *m, u32 ticks); +void alCSeqSetLoc(ALCSeq *seq, ALCSeqMarker *marker); +void alCSeqGetLoc(ALCSeq *seq, ALCSeqMarker *marker); + +/* + * Sequence Player routines + */ +f32 alCents2Ratio(s32 cents); + +void alSeqpNew(ALSeqPlayer *seqp, ALSeqpConfig *config); +void alSeqpDelete(ALSeqPlayer *seqp); +void alSeqpSetSeq(ALSeqPlayer *seqp, ALSeq *seq); +ALSeq *alSeqpGetSeq(ALSeqPlayer *seqp); +void alSeqpPlay(ALSeqPlayer *seqp); +void alSeqpStop(ALSeqPlayer *seqp); +s32 alSeqpGetState(ALSeqPlayer *seqp); +void alSeqpSetBank(ALSeqPlayer *seqp, ALBank *b); +void alSeqpSetTempo(ALSeqPlayer *seqp, s32 tempo); +s32 alSeqpGetTempo(ALSeqPlayer *seqp); +s16 alSeqpGetVol(ALSeqPlayer *seqp); /* Master volume control */ +void alSeqpSetVol(ALSeqPlayer *seqp, s16 vol); +void alSeqpLoop(ALSeqPlayer *seqp, ALSeqMarker *start, ALSeqMarker *end, s32 count); + +void alSeqpSetChlProgram(ALSeqPlayer *seqp, u8 chan, u8 prog); +s32 alSeqpGetChlProgram(ALSeqPlayer *seqp, u8 chan); +void alSeqpSetChlFXMix(ALSeqPlayer *seqp, u8 chan, u8 fxmix); +u8 alSeqpGetChlFXMix(ALSeqPlayer *seqp, u8 chan); +void alSeqpSetChlVol(ALSeqPlayer *seqp, u8 chan, u8 vol); +u8 alSeqpGetChlVol(ALSeqPlayer *seqp, u8 chan); +void alSeqpSetChlPan(ALSeqPlayer *seqp, u8 chan, ALPan pan); +ALPan alSeqpGetChlPan(ALSeqPlayer *seqp, u8 chan); +void alSeqpSetChlPriority(ALSeqPlayer *seqp, u8 chan, u8 priority); +u8 alSeqpGetChlPriority(ALSeqPlayer *seqp, u8 chan); +void alSeqpSendMidi(ALSeqPlayer *seqp, s32 ticks, u8 status, u8 byte1, u8 byte2); + + +/* Maintain backwards compatibility with old routine names. */ +#define alSeqpSetProgram alSeqpSetChlProgram +#define alSeqpGetProgram alSeqpGetChlProgram +#define alSeqpSetFXMix alSeqpSetChlFXMix +#define alSeqpGetFXMix alSeqpGetChlFXMix +#define alSeqpSetPan alSeqpSetChlPan +#define alSeqpGetPan alSeqpGetChlPan +#define alSeqpSetChannelPriority alSeqpSetChlPriority +#define alSeqpGetChannelPriority alSeqpGetChlPriority + + + +/* + * Compressed Sequence Player routines + */ +void alCSPNew(ALCSPlayer *seqp, ALSeqpConfig *config); +void alCSPDelete(ALCSPlayer *seqp); +void alCSPSetSeq(ALCSPlayer *seqp, ALCSeq *seq); +ALCSeq *alCSPGetSeq(ALCSPlayer *seqp); +void alCSPPlay(ALCSPlayer *seqp); +void alCSPStop(ALCSPlayer *seqp); +s32 alCSPGetState(ALCSPlayer *seqp); +void alCSPSetBank(ALCSPlayer *seqp, ALBank *b); +void alCSPSetTempo(ALCSPlayer *seqp, s32 tempo); +s32 alCSPGetTempo(ALCSPlayer *seqp); +s16 alCSPGetVol(ALCSPlayer *seqp); +void alCSPSetVol(ALCSPlayer *seqp, s16 vol); + +void alCSPSetChlProgram(ALCSPlayer *seqp, u8 chan, u8 prog); +s32 alCSPGetChlProgram(ALCSPlayer *seqp, u8 chan); +void alCSPSetChlFXMix(ALCSPlayer *seqp, u8 chan, u8 fxmix); +u8 alCSPGetChlFXMix(ALCSPlayer *seqp, u8 chan); +void alCSPSetChlPan(ALCSPlayer *seqp, u8 chan, ALPan pan); +ALPan alCSPGetChlPan(ALCSPlayer *seqp, u8 chan); +void alCSPSetChlVol(ALCSPlayer *seqp, u8 chan, u8 vol); +u8 alCSPGetChlVol(ALCSPlayer *seqp, u8 chan); +void alCSPSetChlPriority(ALCSPlayer *seqp, u8 chan, u8 priority); +u8 alCSPGetChlPriority(ALCSPlayer *seqp, u8 chan); +void alCSPSendMidi(ALCSPlayer *seqp, s32 ticks, u8 status, + u8 byte1, u8 byte2); + + +/* Maintain backwards compatibility with old routine names. */ +#define alCSPSetProgram alCSPSetChlProgram +#define alCSPGetProgram alCSPGetChlProgram +#define alCSPSetFXMix alCSPSetChlFXMix +#define alCSPGetFXMix alCSPGetChlFXMix +#define alCSPSetPan alCSPSetChlPan +#define alCSPGetPan alCSPGetChlPan +#define alCSPSetChannelPriority alCSPSetChlPriority +#define alCSPGetChannelPriority alCSPGetChlPriority + + + +/*********************************************************************** + * Sound Player stuff + ***********************************************************************/ + +typedef struct { + s32 maxSounds; + s32 maxEvents; + ALHeap *heap; +} ALSndpConfig; + +typedef struct { + ALPlayer node; /* note: must be first in structure */ + ALEventQueue evtq; + ALEvent nextEvent; + ALSynth *drvr; /* reference to the client driver */ + s32 target; + void *sndState; + s32 maxSounds; + ALMicroTime frameTime; + ALMicroTime nextDelta; /* microseconds to next callback */ + ALMicroTime curTime; +} ALSndPlayer; + +typedef s16 ALSndId; + +void alSndpNew(ALSndPlayer *sndp, ALSndpConfig *c); +void alSndpDelete(ALSndPlayer *sndp); + +ALSndId alSndpAllocate(ALSndPlayer *sndp, ALSound *sound); +void alSndpDeallocate(ALSndPlayer *sndp, ALSndId id); + +void alSndpSetSound(ALSndPlayer *sndp, ALSndId id); +ALSndId alSndpGetSound(ALSndPlayer *sndp); + +void alSndpPlay(ALSndPlayer *sndp); +void alSndpPlayAt(ALSndPlayer *sndp, ALMicroTime delta); +void alSndpStop(ALSndPlayer *sndp); + +void alSndpSetVol(ALSndPlayer *sndp, s16 vol); +void alSndpSetPitch(ALSndPlayer *sndp, f32 pitch); +void alSndpSetPan(ALSndPlayer *sndp, ALPan pan); +void alSndpSetPriority(ALSndPlayer *sndp, ALSndId id, u8 priority); + +void alSndpSetFXMix(ALSndPlayer *sndp, u8 mix); +s32 alSndpGetState(ALSndPlayer *sndp); + +#ifndef _FINALROM +void alParseAbiCL(Acmd *cmdList, u32 nbytes); +#endif +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !__LIB_AUDIO__ */ + + + diff --git a/lib/ultralib/include/PR/mbi.h b/lib/ultralib/include/PR/mbi.h new file mode 100644 index 00000000..ac900a54 --- /dev/null +++ b/lib/ultralib/include/PR/mbi.h @@ -0,0 +1,100 @@ +#ifndef _MBI_H_ +#define _MBI_H_ + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.136 $ + * $Date: 1999/01/05 13:04:00 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/mbi.h,v $ + * + **************************************************************************/ + +/* + * Header file for the Media Binary Interface + * + * NOTE: This file is included by the RSP microcode, so any C-specific + * constructs must be bracketed by #ifdef _LANGUAGE_C + * + */ + + +/* + * the SHIFT macros are used to build display list commands, inserting + * bit-fields into a 32-bit word. They take a value, a shift amount, + * and a width. + * + * For the left shift, the lower bits of the value are masked, + * then shifted left. + * + * For the right shift, the value is shifted right, then the lower bits + * are masked. + * + * (NOTE: _SHIFTL(v, 0, 32) won't work, just use an assignment) + * + */ +#define _SHIFTL(v, s, w) \ + ((unsigned int) (((unsigned int)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) \ + ((unsigned int)(((unsigned int)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#define _SHIFT _SHIFTL /* old, for compatibility only */ + +#define G_ON (1) +#define G_OFF (0) + +/************************************************************************** + * + * Graphics Binary Interface + * + **************************************************************************/ + +#include + +/************************************************************************** + * + * Audio Binary Interface + * + **************************************************************************/ + +#include + +/************************************************************************** + * + * Task list + * + **************************************************************************/ + +#define M_GFXTASK 1 +#define M_AUDTASK 2 +#define M_VIDTASK 3 +#define M_HVQTASK 6 +#define M_HVQMTASK 7 + +/************************************************************************** + * + * Segment macros and definitions + * + **************************************************************************/ + +#define NUM_SEGMENTS (16) +#define SEGMENT_OFFSET(a) ((unsigned int)(a) & 0x00ffffff) +#define SEGMENT_NUMBER(a) (((unsigned int)(a) << 4) >> 28) +#define SEGMENT_ADDR(num, off) (((num) << 24) + (off)) + +#ifndef NULL +#define NULL 0 +#endif + +#endif /* !_MBI_H_ */ diff --git a/lib/ultralib/include/PR/os.h b/lib/ultralib/include/PR/os.h new file mode 100644 index 00000000..4b52dfb2 --- /dev/null +++ b/lib/ultralib/include/PR/os.h @@ -0,0 +1,108 @@ + +/*==================================================================== + * os.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os.h,v $ + $Revision: 1.168 $ + $Date: 2000/06/15 06:24:52 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_H_ +#define _OS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +/************************************************************************** + * + * Global definitions + * + */ + +/* + * Stack size for I/O device managers: PIM (PI Manager), VIM (VI Manager), + * SIM (SI Manager) + * + */ +#define OS_PIM_STACKSIZE 4096 +#define OS_VIM_STACKSIZE 4096 +#define OS_SIM_STACKSIZE 4096 + +#define OS_MIN_STACKSIZE 72 + +/* + * Leo Disk + */ + +/* transfer mode */ + +#define LEO_BLOCK_MODE 1 +#define LEO_TRACK_MODE 2 +#define LEO_SECTOR_MODE 3 + +/* + * Boot addresses + */ +#define BOOT_ADDRESS_ULTRA 0x80000400 +#define BOOT_ADDRESS_COSIM 0x80002000 +#define BOOT_ADDRESS_EMU 0x20010000 +#define BOOT_ADDRESS_INDY 0x88100000 + + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_H */ diff --git a/lib/ultralib/include/PR/os_ai.h b/lib/ultralib/include/PR/os_ai.h new file mode 100644 index 00000000..f89d87cf --- /dev/null +++ b/lib/ultralib/include/PR/os_ai.h @@ -0,0 +1,92 @@ + +/*==================================================================== + * os_ai.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_ai.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:04 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_AI_H_ +#define _OS_AI_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Audio interface (Ai) */ +extern u32 osAiGetStatus(void); +extern u32 osAiGetLength(void); +extern s32 osAiSetFrequency(u32); +extern s32 osAiSetNextBuffer(void *, u32); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_AI_H_ */ diff --git a/lib/ultralib/include/PR/os_cache.h b/lib/ultralib/include/PR/os_cache.h new file mode 100644 index 00000000..54ed9230 --- /dev/null +++ b/lib/ultralib/include/PR/os_cache.h @@ -0,0 +1,96 @@ + +/*==================================================================== + * os_cache.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_cache.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:04 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_CACHE_H_ +#define _OS_CACHE_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + +#define OS_DCACHE_ROUNDUP_ADDR(x) (void *)(((((u32)(x)+0xf)/0x10)*0x10)) +#define OS_DCACHE_ROUNDUP_SIZE(x) (u32)(((((u32)(x)+0xf)/0x10)*0x10)) + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Cache operations and macros */ + +extern void osInvalDCache(void *, s32); +extern void osInvalICache(void *, s32); +extern void osWritebackDCache(void *, s32); +extern void osWritebackDCacheAll(void); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_CACHE_H_ */ diff --git a/lib/ultralib/include/PR/os_cont.h b/lib/ultralib/include/PR/os_cont.h new file mode 100644 index 00000000..2b69330f --- /dev/null +++ b/lib/ultralib/include/PR/os_cont.h @@ -0,0 +1,208 @@ + +/*==================================================================== + * os_cont.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_cont.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:05 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_CONT_H_ +#define _OS_CONT_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_message.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Structure for controllers + */ + +typedef struct { + u16 type; /* Controller Type */ + u8 status; /* Controller status */ + u8 errno; +}OSContStatus; + +typedef struct { + u16 button; + s8 stick_x; /* -80 <= stick_x <= 80 */ + s8 stick_y; /* -80 <= stick_y <= 80 */ + u8 errno; +} OSContPad; + +typedef struct { + void *address; /* Ram pad Address: 11 bits */ + u8 databuffer[32]; /* address of the data buffer */ + u8 addressCrc; /* CRC code for address */ + u8 dataCrc; /* CRC code for data */ + u8 errno; +} OSContRamIo; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* + * Controllers number + */ + +#ifndef _HW_VERSION_1 +#define MAXCONTROLLERS 4 +#else +#define MAXCONTROLLERS 6 +#endif + +/* controller errors */ +#define CONT_NO_RESPONSE_ERROR 0x8 +#define CONT_OVERRUN_ERROR 0x4 +#define CONT_RANGE_ERROR -1 +#ifdef _HW_VERSION_1 +#define CONT_FRAME_ERROR 0x2 +#define CONT_COLLISION_ERROR 0x1 +#endif + +/* Controller type */ + +#define CONT_ABSOLUTE 0x0001 +#define CONT_RELATIVE 0x0002 +#define CONT_JOYPORT 0x0004 +#define CONT_EEPROM 0x8000 +#define CONT_EEP16K 0x4000 +#define CONT_TYPE_MASK 0x1f07 +#define CONT_TYPE_NORMAL 0x0005 +#define CONT_TYPE_MOUSE 0x0002 +#define CONT_TYPE_VOICE 0x0100 + +/* Controller status */ + +#define CONT_CARD_ON 0x01 +#define CONT_CARD_PULL 0x02 +#define CONT_ADDR_CRC_ER 0x04 +#define CONT_EEPROM_BUSY 0x80 + +/* Buttons */ + +#define CONT_A 0x8000 +#define CONT_B 0x4000 +#define CONT_G 0x2000 +#define CONT_START 0x1000 +#define CONT_UP 0x0800 +#define CONT_DOWN 0x0400 +#define CONT_LEFT 0x0200 +#define CONT_RIGHT 0x0100 +#define CONT_L 0x0020 +#define CONT_R 0x0010 +#define CONT_E 0x0008 +#define CONT_D 0x0004 +#define CONT_C 0x0002 +#define CONT_F 0x0001 + +/* Nintendo's official button names */ + +#define A_BUTTON CONT_A +#define B_BUTTON CONT_B +#define L_TRIG CONT_L +#define R_TRIG CONT_R +#define Z_TRIG CONT_G +#define START_BUTTON CONT_START +#define U_JPAD CONT_UP +#define L_JPAD CONT_LEFT +#define R_JPAD CONT_RIGHT +#define D_JPAD CONT_DOWN +#define U_CBUTTONS CONT_E +#define L_CBUTTONS CONT_C +#define R_CBUTTONS CONT_F +#define D_CBUTTONS CONT_D + +/* Controller error number */ + +#define CONT_ERR_NO_CONTROLLER PFS_ERR_NOPACK /* 1 */ +#define CONT_ERR_CONTRFAIL CONT_OVERRUN_ERROR /* 4 */ +#define CONT_ERR_INVALID PFS_ERR_INVALID /* 5 */ +#define CONT_ERR_DEVICE PFS_ERR_DEVICE /* 11 */ +#define CONT_ERR_NOT_READY 12 +#define CONT_ERR_VOICE_MEMORY 13 +#define CONT_ERR_VOICE_WORD 14 +#define CONT_ERR_VOICE_NO_RESPONSE 15 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Controller interface */ + +extern s32 osContInit(OSMesgQueue *, u8 *, OSContStatus *); +extern s32 osContReset(OSMesgQueue *, OSContStatus *); +extern s32 osContStartQuery(OSMesgQueue *); +extern s32 osContStartReadData(OSMesgQueue *); +#ifndef _HW_VERSION_1 +extern s32 osContSetCh(u8); +#endif +extern void osContGetQuery(OSContStatus *); +extern void osContGetReadData(OSContPad *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_CONT_H_ */ diff --git a/lib/ultralib/include/PR/os_convert.h b/lib/ultralib/include/PR/os_convert.h new file mode 100644 index 00000000..0a5da10a --- /dev/null +++ b/lib/ultralib/include/PR/os_convert.h @@ -0,0 +1,111 @@ + +/*==================================================================== + * os_convert.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_convert.h,v $ + $Revision: 1.2 $ + $Date: 1999/04/21 02:53:11 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_CONVERT_H_ +#define _OS_CONVERT_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +#define OS_CLOCK_RATE 62500000LL +#define OS_CPU_COUNTER (OS_CLOCK_RATE*3/4) + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + +#define OS_NSEC_TO_CYCLES(n) (((u64)(n)*(OS_CPU_COUNTER/15625000LL))/(1000000000LL/15625000LL)) +#define OS_USEC_TO_CYCLES(n) (((u64)(n)*(OS_CPU_COUNTER/15625LL))/(1000000LL/15625LL)) +#define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL)) +#define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL)) + +/* OS_K?_TO_PHYSICAL macro bug fix for CodeWarrior */ +#ifndef __MWERKS__ +#define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000)) +#define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000)) +#else +#define OS_K0_TO_PHYSICAL(x) ((char *)(x)-0x80000000) +#define OS_K1_TO_PHYSICAL(x) ((char *)(x)-0xa0000000) +#endif + +#define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000)) +#define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000)) + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Address translation routines and macros */ + +extern u32 osVirtualToPhysical(void *); +extern void * osPhysicalToVirtual(u32); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_CONVERT_H_ */ diff --git a/lib/ultralib/include/PR/os_debug.h b/lib/ultralib/include/PR/os_debug.h new file mode 100644 index 00000000..f8f5a89a --- /dev/null +++ b/lib/ultralib/include/PR/os_debug.h @@ -0,0 +1,117 @@ + +/*==================================================================== + * os_debug.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_debug.h,v $ + $Revision: 1.4 $ + $Date: 1999/06/30 03:04:08 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_DEBUG_H_ +#define _OS_DEBUG_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Structure for Profiler + */ +typedef struct { + u16 *histo_base; /* histogram base */ + u32 histo_size; /* histogram size */ + u32 *text_start; /* start of text segment */ + u32 *text_end; /* end of text segment */ +} OSProf; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* + * Profiler constants + */ +#define PROF_MIN_INTERVAL 50 /* microseconds */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Profiler Interface */ + +extern void osProfileInit(OSProf *, u32 profcnt); +extern void osProfileStart(u32); +extern void osProfileFlush(void); +extern void osProfileStop(void); + +/* Thread Profiler Interface */ +extern void osThreadProfileClear(OSId); +extern void osThreadProfileInit(void); +extern void osThreadProfileStart(void); +extern void osThreadProfileStop(void); +extern u32 osThreadProfileReadCount(OSId); +extern u32 osThreadProfileReadCountTh(OSThread*); +extern OSTime osThreadProfileReadTime(OSId); +extern OSTime osThreadProfileReadTimeTh(OSThread*); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_DEBUG_H_ */ diff --git a/lib/ultralib/include/PR/os_eeprom.h b/lib/ultralib/include/PR/os_eeprom.h new file mode 100644 index 00000000..b3bca814 --- /dev/null +++ b/lib/ultralib/include/PR/os_eeprom.h @@ -0,0 +1,107 @@ + +/*==================================================================== + * os_eeprom.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_eeprom.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:06 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_EEPROM_H_ +#define _OS_EEPROM_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_message.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* EEPROM TYPE */ + +#define EEPROM_TYPE_4K 0x01 +#define EEPROM_TYPE_16K 0x02 + +/* definition for EEPROM */ + +#define EEPROM_MAXBLOCKS 64 +#define EEP16K_MAXBLOCKS 256 +#define EEPROM_BLOCK_SIZE 8 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* EEPROM interface */ + +extern s32 osEepromProbe(OSMesgQueue *); +extern s32 osEepromRead(OSMesgQueue *, u8, u8 *); +extern s32 osEepromWrite(OSMesgQueue *, u8, u8 *); +extern s32 osEepromLongRead(OSMesgQueue *, u8, u8 *, int); +extern s32 osEepromLongWrite(OSMesgQueue *, u8, u8 *, int); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_EEPROM_H_ */ diff --git a/lib/ultralib/include/PR/os_error.h b/lib/ultralib/include/PR/os_error.h new file mode 100644 index 00000000..f4c3b83c --- /dev/null +++ b/lib/ultralib/include/PR/os_error.h @@ -0,0 +1,86 @@ + +/*==================================================================== + * os_error.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_error.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:06 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_ERROR_H_ +#define _OS_ERROR_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_ERROR_H_ */ diff --git a/lib/ultralib/include/PR/os_exception.h b/lib/ultralib/include/PR/os_exception.h new file mode 100644 index 00000000..2457bdea --- /dev/null +++ b/lib/ultralib/include/PR/os_exception.h @@ -0,0 +1,86 @@ + +/*==================================================================== + * os_exception.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_exception.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:07 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_EXCEPTION_H_ +#define _OS_EXCEPTION_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +typedef u32 OSIntMask; +typedef u32 OSHWIntr; + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/* Flags for debugging purpose */ + +#define OS_FLAG_CPU_BREAK 1 /* Break exception has occurred */ +#define OS_FLAG_FAULT 2 /* CPU fault has occurred */ + +/* Interrupt masks */ + +#define OS_IM_NONE 0x00000001 +#define OS_IM_RCP 0x00000401 +#define OS_IM_SW1 0x00000501 +#define OS_IM_SW2 0x00000601 +#define OS_IM_CART 0x00000c01 +#define OS_IM_PRENMI 0x00001401 +#define OS_IM_RDBWRITE 0x00002401 +#define OS_IM_RDBREAD 0x00004401 +#define OS_IM_COUNTER 0x00008401 +#define OS_IM_CPU 0x0000ff01 +#define OS_IM_SP 0x00010401 +#define OS_IM_SI 0x00020401 +#define OS_IM_AI 0x00040401 +#define OS_IM_VI 0x00080401 +#define OS_IM_PI 0x00100401 +#define OS_IM_DP 0x00200401 +#define OS_IM_ALL 0x003fff01 +#define RCP_IMASK 0x003f0000 +#define RCP_IMASKSHIFT 16 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Interrupt operations */ + +extern OSIntMask osGetIntMask(void); +extern OSIntMask osSetIntMask(OSIntMask); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_EXCEPTION_H_ */ diff --git a/lib/ultralib/include/PR/os_flash.h b/lib/ultralib/include/PR/os_flash.h new file mode 100644 index 00000000..9eb0bf7f --- /dev/null +++ b/lib/ultralib/include/PR/os_flash.h @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. + + $RCSfile: os_flash.h,v $ + $Revision: 1.1 $ + $Date: 2000/06/15 06:24:55 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_FLASH_H_ +#define _OS_FLASH_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_pi.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * defines for FLASH + */ +#define FLASH_START_ADDR 0x08000000 + +#define FLASH_SIZE 0x20000 + +#define FLASH_LATENCY 0x5 +#define FLASH_PULSE 0x0c +#define FLASH_PAGE_SIZE 0xf +#define FLASH_REL_DURATION 0x2 +#define DEVICE_TYPE_FLASH 8 + +#define FLASH_VERSION_MX_PROTO_A 0x00c20000 +#define FLASH_VERSION_MX_A 0x00c20001 +#define FLASH_VERSION_MX_C 0x00c2001e +#define FLASH_VERSION_MX_B_AND_D 0x00c2001d +#define FLASH_VERSION_MEI 0x003200f1 + +/* OLD_FLASH is MX_PROTO_A, MX_A and MX_C */ +#define OLD_FLASH 0 +/* NEW_FLASH is MX_B_AND_D and MATSUSHITA flash */ +#define NEW_FLASH 1 + +#define FLASH_STATUS_ERASE_BUSY 2 +#define FLASH_STATUS_ERASE_OK 0 +#define FLASH_STATUS_ERASE_ERROR -1 + +#define FLASH_STATUS_WRITE_BUSY 1 +#define FLASH_STATUS_WRITE_OK 0 +#define FLASH_STATUS_WRITE_ERROR -1 + +extern OSPiHandle *osFlashReInit(u8 latency, u8 pulse, + u8 page_size, u8 rel_duration, u32 start); +extern OSPiHandle *osFlashInit(void); +extern void osFlashReadStatus(u8 *flash_status); +extern void osFlashReadId(u32 *flash_type, u32 *flash_maker); +extern void osFlashClearStatus(void); +extern s32 osFlashAllErase(void); +extern s32 osFlashSectorErase(u32 page_num); +extern s32 osFlashWriteBuffer(OSIoMesg *mb, s32 priority, + void *dramAddr, OSMesgQueue *mq); +extern s32 osFlashWriteArray(u32 page_num); +extern s32 osFlashReadArray(OSIoMesg *mb, s32 priority, u32 page_num, + void *dramAddr, u32 n_pages, OSMesgQueue *mq); +extern void osFlashChange(u32 flash_num); +extern void osFlashAllEraseThrough(void); +extern void osFlashSectorEraseThrough(u32 page_num); +extern s32 osFlashCheckEraseEnd(void); + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_FLASH_H_ */ diff --git a/lib/ultralib/include/PR/os_gbpak.h b/lib/ultralib/include/PR/os_gbpak.h new file mode 100644 index 00000000..0a999945 --- /dev/null +++ b/lib/ultralib/include/PR/os_gbpak.h @@ -0,0 +1,107 @@ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. + + $RCSfile: os_gbpak.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:07 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_GBPAK_H_ +#define _OS_GBPAK_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_message.h" +#include "os_pfs.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +typedef struct { + u16 fixed1; + u16 start_address; + u8 nintendo_chr[0x30]; + u8 game_title[16]; + u16 company_code; + u8 body_code; + u8 cart_type; + u8 rom_size; + u8 ram_size; + u8 country_code; + u8 fixed2; + u8 version; + u8 isum; + u16 sum; +} OSGbpakId; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* definition for 64GB-PAK */ + +#define OS_GBPAK_POWER 0x01 +#define OS_GBPAK_RSTB_DETECTION 0x04 +#define OS_GBPAK_RSTB_STATUS 0x08 +#define OS_GBPAK_GBCART_PULL 0x40 +#define OS_GBPAK_GBCART_ON 0x80 + +#define OS_GBPAK_POWER_OFF 0x00 /* power of 64GB-PAK */ +#define OS_GBPAK_POWER_ON 0x01 + +#define OS_GBPAK_ROM_ID_SIZE 0x50 /* ID size of GB cartridge */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* 64GB-PAK */ +extern s32 osGbpakInit(OSMesgQueue *, OSPfs *, int); +extern s32 osGbpakPower(OSPfs *, s32); +extern s32 osGbpakGetStatus(OSPfs *, u8 *); +extern s32 osGbpakReadWrite(OSPfs *, u16, u16, u8 *, u16); +extern s32 osGbpakReadId(OSPfs *, OSGbpakId *, u8 *); +extern s32 osGbpakCheckConnector(OSPfs *, u8 *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_GBPAK_H_ */ diff --git a/lib/ultralib/include/PR/os_gio.h b/lib/ultralib/include/PR/os_gio.h new file mode 100644 index 00000000..ad3c020f --- /dev/null +++ b/lib/ultralib/include/PR/os_gio.h @@ -0,0 +1,86 @@ + +/*==================================================================== + * os_gio.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_gio.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:08 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_GIO_H_ +#define _OS_GIO_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_GIO_H_ */ diff --git a/lib/ultralib/include/PR/os_host.h b/lib/ultralib/include/PR/os_host.h new file mode 100644 index 00000000..0cc1ae5b --- /dev/null +++ b/lib/ultralib/include/PR/os_host.h @@ -0,0 +1,161 @@ + +/*==================================================================== + * os_host.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_host.h,v $ + $Revision: 1.3 $ + $Date: 1999/06/24 09:23:06 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_HOST_H_ +#define _OS_HOST_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + +extern void __osInitialize_common(void); + +#if defined(_FINALROM) + +#define osInitialize() __osInitialize_common() + +#else + +/* PARTNER-N64 */ +#if defined(PTN64) +extern void __osInitialize_kmc(void); +#define osReadHost osReadHost_pt +#define osWriteHost osWriteHost_pt +#define osInitialize() \ +{ \ + __osInitialize_common(); \ + __osInitialize_kmc(); \ +} + +/* MONEGI SMART PACK A */ +#elif defined(MWN64) +extern void __osInitialize_msp(void); +#define osReadHost osReadHost_pt +#define osWriteHost osWriteHost_pt +#define osInitialize() \ +{ \ + __osInitialize_common(); \ + __osInitialize_msp(); \ +} + +/* IS-Viewer(for Debugger) */ +#elif defined(ISV64) +extern void __osInitialize_isv(void); +#define osInitialize() \ +{ \ + __osInitialize_common(); \ + __osInitialize_isv(); \ +} + +/* Emulation board for INDY */ +#elif defined(EMU64) +extern void __osInitialize_emu(void); +#define osInitialize() \ +{ \ + __osInitialize_common(); \ + __osInitialize_emu(); \ +} + +#else +/* Default (auto detect) */ +extern void __osInitialize_autodetect(void); +extern void __osInitialize_msp(void); +extern void __osInitialize_kmc(void); +extern void __osInitialize_isv(void); +extern void __osInitialize_emu(void); +#define osInitialize() \ +{ \ + __osInitialize_common(); \ + __osInitialize_autodetect(); \ +} +#endif + +#endif /* _FINAL_ROM */ + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Game <> Host data transfer functions */ + +extern s32 osTestHost(void); +extern void osReadHost(void *, u32); +extern void osWriteHost(void *, u32); +extern void osAckRamromRead(void); +extern void osAckRamromWrite(void); + +/* RDB port operations */ + +extern void osInitRdb(u8 *sendBuf, u32 sendSize); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_HOST_H_ */ diff --git a/lib/ultralib/include/PR/os_internal.h b/lib/ultralib/include/PR/os_internal.h new file mode 100644 index 00000000..d094a577 --- /dev/null +++ b/lib/ultralib/include/PR/os_internal.h @@ -0,0 +1,50 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal.h,v $ + $Revision: 1.20 $ + $Date: 1998/10/09 08:01:09 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_H_ +#define _OS_INTERNAL_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +#include "os_internal_reg.h" +#include "os_internal_exception.h" +#include "os_internal_tlb.h" +#include "os_internal_si.h" +#include "os_internal_rsp.h" +#include "os_internal_error.h" +#include "os_internal_gio.h" +#include "os_internal_thread.h" +#include "os_internal_debug.h" +#include "os_internal_host.h" +#include "os_internal_flash.h" + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_H */ diff --git a/lib/ultralib/include/PR/os_internal_debug.h b/lib/ultralib/include/PR/os_internal_debug.h new file mode 100644 index 00000000..7b307d6e --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_debug.h @@ -0,0 +1,43 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_debug.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:09 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_DEBUG_H_ +#define _OS_INTERNAL_DEBUG_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Debug port */ +extern void __osSyncPutChars(int, int, const char *); +extern int __osAtomicDec(unsigned int *p); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_DEBUG_H */ diff --git a/lib/ultralib/include/PR/os_internal_error.h b/lib/ultralib/include/PR/os_internal_error.h new file mode 100644 index 00000000..de188d23 --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_error.h @@ -0,0 +1,45 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_error.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:10 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_ERROR_H_ +#define _OS_INTERNAL_ERROR_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Error handling */ + +extern void __osError(s16, s16, ...); +extern OSThread * __osGetCurrFaultedThread(void); +extern OSThread * __osGetNextFaultedThread(OSThread *); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_ERROR_H */ diff --git a/lib/ultralib/include/PR/os_internal_exception.h b/lib/ultralib/include/PR/os_internal_exception.h new file mode 100644 index 00000000..2484903a --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_exception.h @@ -0,0 +1,49 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_exception.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:10 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_EXCEPTION_H_ +#define _OS_INTERNAL_EXCEPTION_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "os.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Routine for HW interrupt "handler" */ +extern void __osSetHWIntrRoutine(OSHWIntr interrupt, + s32 (*handler)(void), void *stackEnd); +extern void __osGetHWIntrRoutine(OSHWIntr interrupt, + s32 (**handler)(void), void **stackEnd); + +/* Routine for global interrupt mask */ +extern void __osSetGlobalIntMask(OSHWIntr); +extern void __osResetGlobalIntMask(OSHWIntr); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_EXCEPTION_H */ diff --git a/lib/ultralib/include/PR/os_internal_flash.h b/lib/ultralib/include/PR/os_internal_flash.h new file mode 100644 index 00000000..d8681d7a --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_flash.h @@ -0,0 +1,40 @@ +#ifndef _OS_INTERNAL_FLASH_H_ +#define _OS_INTERNAL_FLASH_H_ + +#include "os_message.h" +#include "os_flash.h" + +#define FLASH_BLOCK_SIZE 128 + +/** + * Flash commands + */ +#define FLASH_CMD_REG 0x10000 + +/* set whole chip erase mode */ +#define FLASH_CMD_CHIP_ERASE 0x3C000000 +/* set sector erase mode */ +#define FLASH_CMD_SECTOR_ERASE 0x4B000000 +/* do erasure */ +#define FLASH_CMD_EXECUTE_ERASE 0x78000000 +/* program selected page */ +#define FLASH_CMD_PROGRAM_PAGE 0xA5000000 +/* set page program mode */ +#define FLASH_CMD_PAGE_PROGRAM 0xB4000000 +/* set status mode */ +#define FLASH_CMD_STATUS 0xD2000000 +/* set silicon id mode */ +#define FLASH_CMD_ID 0xE1000000 +/* set read mode */ +#define FLASH_CMD_READ_ARRAY 0xF0000000 + +extern s32 __osFlashVersion; +extern OSPiHandle __osFlashHandler; +extern OSMesgQueue __osFlashMessageQ; +extern OSMesg __osFlashMsgBuf[1]; +extern OSIoMesg __osFlashMsg; +extern u32 __osFlashID[4]; + +u32 __osFlashGetAddr(u32 page_num); + +#endif diff --git a/lib/ultralib/include/PR/os_internal_gio.h b/lib/ultralib/include/PR/os_internal_gio.h new file mode 100644 index 00000000..ff133850 --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_gio.h @@ -0,0 +1,45 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_gio.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:11 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_GIO_H_ +#define _OS_INTERNAL_GIO_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Development board functions */ + +extern void __osGIOInit(s32); +extern void __osGIOInterrupt(s32); +extern void __osGIORawInterrupt(s32); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_GIO_H */ diff --git a/lib/ultralib/include/PR/os_internal_host.h b/lib/ultralib/include/PR/os_internal_host.h new file mode 100644 index 00000000..b6d19513 --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_host.h @@ -0,0 +1,42 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_host.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:11 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_HOST_H_ +#define _OS_INTERNAL_HOST_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* routine for rdb port */ +extern u32 __osRdbSend(u8 *buf, u32 size, u32 type); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_HOST_H */ diff --git a/lib/ultralib/include/PR/os_internal_reg.h b/lib/ultralib/include/PR/os_internal_reg.h new file mode 100644 index 00000000..206b721c --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_reg.h @@ -0,0 +1,57 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_reg.h,v $ + $Revision: 1.2 $ + $Date: 1999/03/10 12:19:14 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_REG_H_ +#define _OS_INTERNAL_REG_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "os.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Routines to get/fetch coprocessor 0 registers */ +extern u32 __osGetCause(void); +extern void __osSetCause(u32); +extern u32 __osGetCompare(void); +extern void __osSetCompare(u32); +extern u32 __osGetConfig(void); +extern void __osSetConfig(u32); +extern void __osSetCount(u32); +extern u32 __osGetSR(void); +extern void __osSetSR(u32); +extern u32 __osDisableInt(void); +extern void __osRestoreInt(u32); +extern u32 __osGetWatchLo(void); +extern void __osSetWatchLo(u32); + +/* Routines to get/set floating-point control and status register */ +extern u32 __osSetFpcCsr(u32); +extern u32 __osGetFpcCsr(void); + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_REG_H */ diff --git a/lib/ultralib/include/PR/os_internal_rsp.h b/lib/ultralib/include/PR/os_internal_rsp.h new file mode 100644 index 00000000..646e6679 --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_rsp.h @@ -0,0 +1,48 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_rsp.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:12 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_RSP_H_ +#define _OS_INTERNAL_RSP_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Signal processor interface (Sp) */ + +extern u32 __osSpGetStatus(void); +extern void __osSpSetStatus(u32); +extern s32 __osSpSetPc(u32); +extern s32 __osSpRawWriteIo(u32, u32); +extern s32 __osSpRawReadIo(u32, u32 *); +extern s32 __osSpRawStartDma(s32, u32, void *, u32); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_RSP_H */ diff --git a/lib/ultralib/include/PR/os_internal_si.h b/lib/ultralib/include/PR/os_internal_si.h new file mode 100644 index 00000000..d0eeedcc --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_si.h @@ -0,0 +1,46 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_si.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:13 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_SI_H_ +#define _OS_INTERNAL_SI_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Serial interface (Si) */ + +extern u32 __osSiGetStatus(void); +extern s32 __osSiRawWriteIo(u32, u32); +extern s32 __osSiRawReadIo(u32, u32 *); +extern s32 __osSiRawStartDma(s32, void *); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_SI_H */ diff --git a/lib/ultralib/include/PR/os_internal_thread.h b/lib/ultralib/include/PR/os_internal_thread.h new file mode 100644 index 00000000..1305eb58 --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_thread.h @@ -0,0 +1,43 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_thread.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:13 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_THREAD_H_ +#define _OS_INTERNAL_THREAD_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* For debugger use */ + +extern OSThread * __osGetActiveQueue(void); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_THREAD_H */ diff --git a/lib/ultralib/include/PR/os_internal_tlb.h b/lib/ultralib/include/PR/os_internal_tlb.h new file mode 100644 index 00000000..b92918ff --- /dev/null +++ b/lib/ultralib/include/PR/os_internal_tlb.h @@ -0,0 +1,47 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_internal_tlb.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:14 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_INTERNAL_TLB_H_ +#define _OS_INTERNAL_TLB_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Routines for fetch TLB info */ + +extern u32 __osGetTLBASID(void); +extern u32 __osGetTLBPageMask(s32); +extern u32 __osGetTLBHi(s32); +extern u32 __osGetTLBLo0(s32); +extern u32 __osGetTLBLo1(s32); + + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_INTERNAL_TLB_H */ diff --git a/lib/ultralib/include/PR/os_libc.h b/lib/ultralib/include/PR/os_libc.h new file mode 100644 index 00000000..35d0e8e6 --- /dev/null +++ b/lib/ultralib/include/PR/os_libc.h @@ -0,0 +1,100 @@ + +/*==================================================================== + * os_libc.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_libc.h,v $ + $Revision: 1.3 $ + $Date: 1999/07/13 01:43:47 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_LIBC_H_ +#define _OS_LIBC_H_ + +#include "os_pfs.h" + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* byte string operations */ + + +extern void bcopy(const void *, void *, int); +extern int bcmp(const void *, const void *, int); +extern void bzero(void *, int); + +/* Printf */ + +extern int sprintf(char *s, const char *fmt, ...); +extern void osSyncPrintf(const char *fmt, ...); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_LIBC_H_ */ diff --git a/lib/ultralib/include/PR/os_message.h b/lib/ultralib/include/PR/os_message.h new file mode 100644 index 00000000..606c5cb0 --- /dev/null +++ b/lib/ultralib/include/PR/os_message.h @@ -0,0 +1,162 @@ + +/*==================================================================== + * os_message.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_message.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:15 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_MESSAGE_H_ +#define _OS_MESSAGE_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_thread.h" + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +typedef u32 OSEvent; + +/* + * Structure for message + */ +typedef void *OSMesg; + +/* + * Structure for message queue + */ +typedef struct OSMesgQueue_s { + OSThread *mtqueue; /* Queue to store threads blocked on empty mailboxes (receive) */ + OSThread *fullqueue; /* Queue to store threads blocked on full mailboxes (send) */ + s32 validCount; /* Contains number of valid message */ + s32 first; /* Points to first valid message */ + s32 msgCount; /* Contains total # of messages */ + OSMesg *msg; /* Points to message buffer array */ +} OSMesgQueue; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* Events */ +#ifdef _FINALROM +#define OS_NUM_EVENTS 15 +#else +#define OS_NUM_EVENTS 23 +#endif + +#define OS_EVENT_SW1 0 /* CPU SW1 interrupt */ +#define OS_EVENT_SW2 1 /* CPU SW2 interrupt */ +#define OS_EVENT_CART 2 /* Cartridge interrupt: used by rmon */ +#define OS_EVENT_COUNTER 3 /* Counter int: used by VI/Timer Mgr */ +#define OS_EVENT_SP 4 /* SP task done interrupt */ +#define OS_EVENT_SI 5 /* SI (controller) interrupt */ +#define OS_EVENT_AI 6 /* AI interrupt */ +#define OS_EVENT_VI 7 /* VI interrupt: used by VI/Timer Mgr */ +#define OS_EVENT_PI 8 /* PI interrupt: used by PI Manager */ +#define OS_EVENT_DP 9 /* DP full sync interrupt */ +#define OS_EVENT_CPU_BREAK 10 /* CPU breakpoint: used by rmon */ +#define OS_EVENT_SP_BREAK 11 /* SP breakpoint: used by rmon */ +#define OS_EVENT_FAULT 12 /* CPU fault event: used by rmon */ +#define OS_EVENT_THREADSTATUS 13 /* CPU thread status: used by rmon */ +#define OS_EVENT_PRENMI 14 /* Pre NMI interrupt */ +#ifndef _FINALROM +#define OS_EVENT_RDB_READ_DONE 15 /* RDB read ok event: used by rmon */ +#define OS_EVENT_RDB_LOG_DONE 16 /* read of log data complete */ +#define OS_EVENT_RDB_DATA_DONE 17 /* read of hostio data complete */ +#define OS_EVENT_RDB_REQ_RAMROM 18 /* host needs ramrom access */ +#define OS_EVENT_RDB_FREE_RAMROM 19 /* host is done with ramrom access */ +#define OS_EVENT_RDB_DBG_DONE 20 +#define OS_EVENT_RDB_FLUSH_PROF 21 +#define OS_EVENT_RDB_ACK_PROF 22 +#endif + +/* Flags to turn blocking on/off when sending/receiving message */ + +#define OS_MESG_NOBLOCK 0 +#define OS_MESG_BLOCK 1 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + +/* Get count of valid messages in queue */ +#define MQ_GET_COUNT(mq) ((mq)->validCount) + +/* Figure out if message queue is empty or full */ +#define MQ_IS_EMPTY(mq) (MQ_GET_COUNT(mq) == 0) +#define MQ_IS_FULL(mq) (MQ_GET_COUNT(mq) >= (mq)->msgCount) + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Message operations */ + +extern void osCreateMesgQueue(OSMesgQueue *, OSMesg *, s32); +extern s32 osSendMesg(OSMesgQueue *, OSMesg, s32); +extern s32 osJamMesg(OSMesgQueue *, OSMesg, s32); +extern s32 osRecvMesg(OSMesgQueue *, OSMesg *, s32); + +/* Event operations */ + +extern void osSetEventMesg(OSEvent, OSMesgQueue *, OSMesg); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_MESSAGE_H_ */ diff --git a/lib/ultralib/include/PR/os_motor.h b/lib/ultralib/include/PR/os_motor.h new file mode 100644 index 00000000..f8dcbd5a --- /dev/null +++ b/lib/ultralib/include/PR/os_motor.h @@ -0,0 +1,83 @@ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. + + $RCSfile: os_motor.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:15 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_MOTOR_H_ +#define _OS_MOTOR_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_message.h" +#include "os_pfs.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Rumble PAK interface */ + +extern s32 osMotorInit(OSMesgQueue *, OSPfs *, int); +#if 1 +#define MOTOR_START 1 +#define MOTOR_STOP 0 +#define osMotorStart(x) __osMotorAccess((x), MOTOR_START) +#define osMotorStop(x) __osMotorAccess((x), MOTOR_STOP) +extern s32 __osMotorAccess(OSPfs *, s32); +#else +extern s32 osMotorStop(OSPfs *); +extern s32 osMotorStart(OSPfs *); +#endif + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_MOTOR_H_ */ diff --git a/lib/ultralib/include/PR/os_pfs.h b/lib/ultralib/include/PR/os_pfs.h new file mode 100644 index 00000000..9c86e238 --- /dev/null +++ b/lib/ultralib/include/PR/os_pfs.h @@ -0,0 +1,200 @@ + +/*==================================================================== + * os_pfs.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_pfs.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:16 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_PFS_H_ +#define _OS_PFS_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_message.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Structure for file system + */ +typedef struct { + int status; + OSMesgQueue *queue; + int channel; + u8 id[32]; + u8 label[32]; + int version; + int dir_size; + int inode_table; /* block location */ + int minode_table; /* mirrioring inode_table */ + int dir_table; /* block location */ + int inode_start_page; /* page # */ + u8 banks; + u8 activebank; +} OSPfs; + +typedef struct { + u32 file_size; /* bytes */ + u32 game_code; + u16 company_code; + char ext_name[4]; + char game_name[16]; +} OSPfsState; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +/* File System size */ +#define OS_PFS_VERSION 0x0200 +#define OS_PFS_VERSION_HI (OS_PFS_VERSION >> 8) +#define OS_PFS_VERSION_LO (OS_PFS_VERSION & 255) + +#define PFS_INODE_SIZE_PER_PAGE 128 +#define PFS_FILE_NAME_LEN 16 +#define PFS_FILE_EXT_LEN 4 +#define BLOCKSIZE 32 /* bytes */ +#define PFS_ONE_PAGE 8 /* blocks */ +#define PFS_MAX_BANKS 62 + +/* File System flag */ + +#define PFS_READ 0 +#define PFS_WRITE 1 +#define PFS_CREATE 2 + +/* File System status */ +#define PFS_INITIALIZED 0x1 +#define PFS_CORRUPTED 0x2 +#define PFS_ID_BROKEN 0x4 +#define PFS_MOTOR_INITIALIZED 0x8 +#define PFS_GBPAK_INITIALIZED 0x10 + +/* Definition for page usage */ +#define PFS_EOF 1 +#define PFS_PAGE_NOT_EXIST 2 +#define PFS_PAGE_NOT_USED 3 + +/* File System error number */ + +#define PFS_ERR_NOPACK 1 /* no memory card is plugged or */ +#define PFS_ERR_NEW_PACK 2 /* ram pack has been changed to a different one */ +#define PFS_ERR_INCONSISTENT 3 /* need to run Pfschecker*/ +#define PFS_ERR_CONTRFAIL CONT_OVERRUN_ERROR +#define PFS_ERR_INVALID 5 /* invalid parameter or file not exist*/ +#define PFS_ERR_BAD_DATA 6 /* the data read from pack are bad*/ +#define PFS_DATA_FULL 7 /* no free pages on ram pack*/ +#define PFS_DIR_FULL 8 /* no free directories on ram pack*/ +#define PFS_ERR_EXIST 9 /* file exists*/ +#define PFS_ERR_ID_FATAL 10 /* dead ram pack */ +#define PFS_ERR_DEVICE 11 /* wrong device type*/ +#define PFS_ERR_NO_GBCART 12 /* no gb cartridge (64GB-PAK) */ +#define PFS_ERR_NEW_GBCART 13 /* gb cartridge may be changed */ + +/* Definition for bank */ +#define PFS_ID_BANK_256K 0 +#define PFS_ID_BANK_1M 4 +#define PFS_BANKS_256K 1 + +#define PFS_WRITTEN 2 +#define DEF_DIR_PAGES 2 + +#define PFS_ID_0AREA 1 +#define PFS_ID_1AREA 3 +#define PFS_ID_2AREA 4 +#define PFS_ID_3AREA 6 +#define PFS_LABEL_AREA 7 +#define PFS_ID_PAGE PFS_ONE_PAGE * 0 + +#define PFS_BANK_LAPPED_BY 8 /* => u8 */ +#define PFS_SECTOR_PER_BANK 32 +#define PFS_INODE_DIST_MAP (PFS_BANK_LAPPED_BY * PFS_SECTOR_PER_BANK) +#define PFS_SECTOR_SIZE (PFS_INODE_SIZE_PER_PAGE/PFS_SECTOR_PER_BANK) + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* file system interface */ + +extern s32 osPfsInitPak(OSMesgQueue *, OSPfs *, int); +extern s32 osPfsRepairId(OSPfs *); +extern s32 osPfsInit(OSMesgQueue *, OSPfs *, int); +extern s32 osPfsReFormat(OSPfs *, OSMesgQueue *, int); +extern s32 osPfsChecker(OSPfs *); +extern s32 osPfsAllocateFile(OSPfs *, u16, u32, u8 *, u8 *, int, s32 *); +extern s32 osPfsFindFile(OSPfs *, u16, u32, u8 *, u8 *, s32 *); +extern s32 osPfsDeleteFile(OSPfs *, u16, u32, u8 *, u8 *); +extern s32 osPfsReadWriteFile(OSPfs *, s32, u8, int, int, u8 *); +extern s32 osPfsFileState(OSPfs *, s32, OSPfsState *); +extern s32 osPfsGetLabel(OSPfs *, u8 *, int *); +extern s32 osPfsSetLabel(OSPfs *, u8 *); +extern s32 osPfsIsPlug(OSMesgQueue *, u8 *); +extern s32 osPfsFreeBlocks(OSPfs *, s32 *); +extern s32 osPfsNumFiles(OSPfs *, s32 *, s32 *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_PFS_H_ */ diff --git a/lib/ultralib/include/PR/os_pi.h b/lib/ultralib/include/PR/os_pi.h new file mode 100644 index 00000000..f408d6ce --- /dev/null +++ b/lib/ultralib/include/PR/os_pi.h @@ -0,0 +1,221 @@ + +/*==================================================================== + * os_pi.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_pi.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:16 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_PI_H_ +#define _OS_PI_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" +#include "os_thread.h" +#include "os_message.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Structure for Enhanced PI interface + */ + +/* + * OSTranxInfo is set up for Leo Disk DMA. This info will be maintained + * by exception handler. This is how the PIMGR and the ISR communicate. + */ + +typedef struct { + u32 errStatus; /* error status */ + void *dramAddr; /* RDRAM buffer address (DMA) */ + void *C2Addr; /* C2 buffer address */ + u32 sectorSize; /* size of transfering sector */ + u32 C1ErrNum; /* total # of C1 errors */ + u32 C1ErrSector[4]; /* error sectors */ +} __OSBlockInfo; + +typedef struct { + u32 cmdType; /* for disk only */ + u16 transferMode; /* Block, Track, or sector? */ + u16 blockNum; /* which block is transfering */ + s32 sectorNum; /* which sector is transfering */ + u32 devAddr; /* Device buffer address */ + u32 bmCtlShadow; /* asic bm_ctl(510) register shadow ram */ + u32 seqCtlShadow; /* asic seq_ctl(518) register shadow ram */ + __OSBlockInfo block[2]; /* bolck transfer info */ +} __OSTranxInfo; + + +typedef struct OSPiHandle_s { + struct OSPiHandle_s *next; /* point to next handle on the table */ + u8 type; /* DEVICE_TYPE_BULK for disk */ + u8 latency; /* domain latency */ + u8 pageSize; /* domain page size */ + u8 relDuration; /* domain release duration */ + u8 pulse; /* domain pulse width */ + u8 domain; /* which domain */ + u32 baseAddress; /* Domain address */ + u32 speed; /* for roms only */ + /* The following are "private" elements" */ + __OSTranxInfo transferInfo; /* for disk only */ +} OSPiHandle; + +typedef struct { + u8 type; + u32 address; +} OSPiInfo; + +/* + * Structure for I/O message block + */ +typedef struct { + u16 type; /* Message type */ + u8 pri; /* Message priority (High or Normal) */ + u8 status; /* Return status */ + OSMesgQueue *retQueue; /* Return message queue to notify I/O completion */ +} OSIoMesgHdr; + +typedef struct { + OSIoMesgHdr hdr; /* Message header */ + void *dramAddr; /* RDRAM buffer address (DMA) */ + u32 devAddr; /* Device buffer address (DMA) */ + u32 size; /* DMA transfer size in bytes */ + OSPiHandle *piHandle; /* PI device handle */ +} OSIoMesg; + +/* + * Structure for device manager block + */ +typedef struct { + s32 active; /* Status flag */ + OSThread *thread; /* Calling thread */ + OSMesgQueue *cmdQueue; /* Command queue */ + OSMesgQueue *evtQueue; /* Event queue */ + OSMesgQueue *acsQueue; /* Access queue */ + /* Raw DMA routine */ + s32 (*dma)(s32, u32, void *, u32); + s32 (*edma)(OSPiHandle *, s32, u32, void *, u32); +} OSDevMgr; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* Flags to indicate direction of data transfer */ + +#define OS_READ 0 /* device -> RDRAM */ +#define OS_WRITE 1 /* device <- RDRAM */ +#define OS_OTHERS 2 /* for Leo disk only */ + +/* + * I/O message types + */ +#define OS_MESG_TYPE_BASE (10) +#define OS_MESG_TYPE_LOOPBACK (OS_MESG_TYPE_BASE + 0) +#define OS_MESG_TYPE_DMAREAD (OS_MESG_TYPE_BASE + 1) +#define OS_MESG_TYPE_DMAWRITE (OS_MESG_TYPE_BASE + 2) +#define OS_MESG_TYPE_VRETRACE (OS_MESG_TYPE_BASE + 3) +#define OS_MESG_TYPE_COUNTER (OS_MESG_TYPE_BASE + 4) +#define OS_MESG_TYPE_EDMAREAD (OS_MESG_TYPE_BASE + 5) +#define OS_MESG_TYPE_EDMAWRITE (OS_MESG_TYPE_BASE + 6) + +/* + * I/O message priority + */ +#define OS_MESG_PRI_NORMAL 0 +#define OS_MESG_PRI_HIGH 1 + +/* + * PI/EPI + */ +#define PI_DOMAIN1 0 +#define PI_DOMAIN2 1 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + +extern OSPiHandle *__osPiTable; /* The head of OSPiHandle link list */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +extern u32 osPiGetStatus(void); +extern s32 osPiGetDeviceType(void); +extern s32 osPiWriteIo(u32, u32); +extern s32 osPiReadIo(u32, u32 *); +extern s32 osPiStartDma(OSIoMesg *, s32, s32, u32, void *, u32, OSMesgQueue *); +extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32); + +/* Enhanced PI interface */ + +extern OSPiHandle *osCartRomInit(void); +extern OSPiHandle *osLeoDiskInit(void); +extern OSPiHandle *osDriveRomInit(void); + +extern s32 osEPiDeviceType(OSPiHandle *, OSPiInfo *); +extern s32 osEPiWriteIo(OSPiHandle *, u32 , u32 ); +extern s32 osEPiReadIo(OSPiHandle *, u32 , u32 *); +extern s32 osEPiStartDma(OSPiHandle *, OSIoMesg *, s32); +extern s32 osEPiLinkHandle(OSPiHandle *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_PI_H_ */ diff --git a/lib/ultralib/include/PR/os_rdp.h b/lib/ultralib/include/PR/os_rdp.h new file mode 100644 index 00000000..6b3d288c --- /dev/null +++ b/lib/ultralib/include/PR/os_rdp.h @@ -0,0 +1,92 @@ + +/*==================================================================== + * os_rdp.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_rdp.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:16 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_RDP_H_ +#define _OS_RDP_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Display processor interface (Dp) */ +extern u32 osDpGetStatus(void); +extern void osDpSetStatus(u32); +extern void osDpGetCounters(u32 *); +extern s32 osDpSetNextBuffer(void *, u64); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_RDP_H_ */ diff --git a/lib/ultralib/include/PR/os_reg.h b/lib/ultralib/include/PR/os_reg.h new file mode 100644 index 00000000..50aa2188 --- /dev/null +++ b/lib/ultralib/include/PR/os_reg.h @@ -0,0 +1,90 @@ + +/*==================================================================== + * os_reg.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_reg.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:17 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_REG_H_ +#define _OS_REG_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Miscellaneous operations */ + +extern u32 osGetCount(void); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_REG_H_ */ diff --git a/lib/ultralib/include/PR/os_rsp.h b/lib/ultralib/include/PR/os_rsp.h new file mode 100644 index 00000000..12116053 --- /dev/null +++ b/lib/ultralib/include/PR/os_rsp.h @@ -0,0 +1,86 @@ + +/*==================================================================== + * os_rsp.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_rsp.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:17 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_RSP_H_ +#define _OS_RSP_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_RSP_H_ */ diff --git a/lib/ultralib/include/PR/os_si.h b/lib/ultralib/include/PR/os_si.h new file mode 100644 index 00000000..23b07c07 --- /dev/null +++ b/lib/ultralib/include/PR/os_si.h @@ -0,0 +1,86 @@ + +/*==================================================================== + * os_si.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_si.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:18 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_SI_H_ +#define _OS_SI_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_SI_H_ */ diff --git a/lib/ultralib/include/PR/os_system.h b/lib/ultralib/include/PR/os_system.h new file mode 100644 index 00000000..682c9cff --- /dev/null +++ b/lib/ultralib/include/PR/os_system.h @@ -0,0 +1,118 @@ + +/*==================================================================== + * os_system.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_system.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:18 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_SYSTEM_H_ +#define _OS_SYSTEM_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* + * Values for osTvType + */ +#define OS_TV_PAL 0 +#define OS_TV_NTSC 1 +#define OS_TV_MPAL 2 + +/* + * Size of buffer the retains contents after NMI + */ +#define OS_APP_NMI_BUFSIZE 64 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + +extern s32 osRomType; /* Bulk or cartridge ROM. 0=cartridge 1=bulk */ +extern void *osRomBase; /* Rom base address of the game image */ +extern s32 osTvType; /* 0 = PAL, 1 = NTSC, 2 = MPAL */ +extern s32 osResetType; /* 0 = cold reset, 1 = NMI */ +extern s32 osCicId; +extern s32 osVersion; +extern u32 osMemSize; /* Memory Size */ +extern s32 osAppNMIBuffer[]; + +extern u64 osClockRate; + +extern OSIntMask __OSGlobalIntMask; /* global interrupt mask */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +extern void osInitialize(void); +extern void osExit(void); +extern u32 osGetMemSize(void); + +/* pre-NMI */ +extern s32 osAfterPreNMI(void); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_SYSTEM_H_ */ diff --git a/lib/ultralib/include/PR/os_thread.h b/lib/ultralib/include/PR/os_thread.h new file mode 100644 index 00000000..68c8e74f --- /dev/null +++ b/lib/ultralib/include/PR/os_thread.h @@ -0,0 +1,161 @@ + +/*==================================================================== + * os_thread.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_thread.h,v $ + $Revision: 1.3 $ + $Date: 1999/06/15 12:39:40 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_THREAD_H_ +#define _OS_THREAD_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +typedef s32 OSPri; +typedef s32 OSId; + +typedef union { + struct { + f32 f_odd; + f32 f_even; + } f; + f64 d; +} __OSfp; + +typedef struct { + u64 at, v0, v1, a0, a1, a2, a3; + u64 t0, t1, t2, t3, t4, t5, t6, t7; + u64 s0, s1, s2, s3, s4, s5, s6, s7; + u64 t8, t9; + u64 gp, sp, s8, ra; + u64 lo, hi; + u32 sr, pc, cause, badvaddr, rcp; + u32 fpcsr; + __OSfp fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14; + __OSfp fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30; +} __OSThreadContext; + +typedef struct { + u32 flag; + u32 count; + u64 time; +} __OSThreadprofile_s; + +typedef struct OSThread_s { + struct OSThread_s *next; /* run/mesg queue link */ + OSPri priority; /* run/mesg queue priority */ + struct OSThread_s **queue; /* queue thread is on */ + struct OSThread_s *tlnext; /* all threads queue link */ + u16 state; /* OS_STATE_* */ + u16 flags; /* flags for rmon */ + OSId id; /* id for debugging */ + int fp; /* thread has used fp unit */ + __OSThreadprofile_s *thprof; /* workarea for thread profiler */ + __OSThreadContext context; /* register/interrupt mask */ +} OSThread; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* Thread states */ + +#define OS_STATE_STOPPED (1 << 0) +#define OS_STATE_RUNNABLE (1 << 1) +#define OS_STATE_RUNNING (1 << 2) +#define OS_STATE_WAITING (1 << 3) + +/* Recommended thread priorities for the system threads */ + +#define OS_PRIORITY_MAX 255 +#define OS_PRIORITY_VIMGR 254 +#define OS_PRIORITY_RMON 250 +#define OS_PRIORITY_RMONSPIN 200 +#define OS_PRIORITY_PIMGR 150 +#define OS_PRIORITY_SIMGR 140 +#define OS_PRIORITY_APPMAX 127 +#define OS_PRIORITY_IDLE 0 /* Must be 0 */ + +/* For thread profiler */ +#define THPROF_IDMAX 64 +#define THPROF_STACKSIZE 256 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Thread operations */ + +extern void osCreateThread(OSThread *, OSId, void (*)(void *), void *, void *, OSPri); +extern void osDestroyThread(OSThread *); +extern void osYieldThread(void); +extern void osStartThread(OSThread *); +extern void osStopThread(OSThread *); +extern OSId osGetThreadId(OSThread *); +extern void osSetThreadPri(OSThread *, OSPri); +extern OSPri osGetThreadPri(OSThread *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_THREAD_H_ */ diff --git a/lib/ultralib/include/PR/os_time.h b/lib/ultralib/include/PR/os_time.h new file mode 100644 index 00000000..deaec659 --- /dev/null +++ b/lib/ultralib/include/PR/os_time.h @@ -0,0 +1,114 @@ + +/*==================================================================== + * os_time.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_time.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:19 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_TIME_H_ +#define _OS_TIME_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_message.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Structure for time value + */ +typedef u64 OSTime; + +/* + * Structure for interval timer + */ +typedef struct OSTimer_s { + struct OSTimer_s *next; /* point to next timer in list */ + struct OSTimer_s *prev; /* point to previous timer in list */ + OSTime interval; /* duration set by user */ + OSTime value; /* time remaining before */ + /* timer fires */ + OSMesgQueue *mq; /* Message Queue */ + OSMesg msg; /* Message to send */ +} OSTimer; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Timer interface */ + +extern OSTime osGetTime(void); +extern void osSetTime(OSTime); +extern int osSetTimer(OSTimer *, OSTime, OSTime, + OSMesgQueue *, OSMesg); +extern int osStopTimer(OSTimer *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_TIME_H_ */ diff --git a/lib/ultralib/include/PR/os_tlb.h b/lib/ultralib/include/PR/os_tlb.h new file mode 100644 index 00000000..2cdd5c9c --- /dev/null +++ b/lib/ultralib/include/PR/os_tlb.h @@ -0,0 +1,107 @@ + +/*==================================================================== + * os_tlb.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_tlb.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:20 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_TLB_H_ +#define _OS_TLB_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +typedef u32 OSPageMask; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* + * Page size argument for TLB routines + */ +#define OS_PM_4K 0x0000000 +#define OS_PM_16K 0x0006000 +#define OS_PM_64K 0x001e000 +#define OS_PM_256K 0x007e000 +#define OS_PM_1M 0x01fe000 +#define OS_PM_4M 0x07fe000 +#define OS_PM_16M 0x1ffe000 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* TLB management routines */ + +extern void osMapTLB(s32, OSPageMask, void *, u32, u32, s32); +extern void osMapTLBRdb(void); +extern void osUnmapTLB(s32); +extern void osUnmapTLBAll(void); +extern void osSetTLBASID(s32); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_TLB_H_ */ diff --git a/lib/ultralib/include/PR/os_version.h b/lib/ultralib/include/PR/os_version.h new file mode 100644 index 00000000..c485a438 --- /dev/null +++ b/lib/ultralib/include/PR/os_version.h @@ -0,0 +1,16 @@ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. + + $RCSfile: os_version.h,v $ + $Revision: 1.2 $ + $Date: 1999/06/17 01:33:01 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_VERSION_H_ +#define _OS_VERSION_H_ + +#define OS_MAJOR_VERSION "2.0K" /* major version */ +#define OS_MINOR_VERSION 0 /* patch level */ + +#endif /* !_OS_VERSION_H_ */ diff --git a/lib/ultralib/include/PR/os_vi.h b/lib/ultralib/include/PR/os_vi.h new file mode 100644 index 00000000..5a17f258 --- /dev/null +++ b/lib/ultralib/include/PR/os_vi.h @@ -0,0 +1,298 @@ + +/*==================================================================== + * os_vi.h + * + * 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. + *====================================================================*/ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. (Originated by SGI) + + $RCSfile: os_vi.h,v $ + $Revision: 1.1 $ + $Date: 1998/10/09 08:01:20 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_VI_H_ +#define _OS_VI_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include "os_thread.h" +#include "os_message.h" + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Structure to store VI register values that remain the same between 2 fields + */ +typedef struct { + u32 ctrl; + u32 width; + u32 burst; + u32 vSync; + u32 hSync; + u32 leap; + u32 hStart; + u32 xScale; + u32 vCurrent; +} OSViCommonRegs; + + +/* + * Structure to store VI register values that change between fields + */ +typedef struct { + u32 origin; + u32 yScale; + u32 vStart; + u32 vBurst; + u32 vIntr; +} OSViFieldRegs; + + +/* + * Structure for VI mode + */ +typedef struct { + u8 type; /* Mode type */ + OSViCommonRegs comRegs; /* Common registers for both fields */ + OSViFieldRegs fldRegs[2]; /* Registers for Field 1 & 2 */ +} OSViMode; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* + * Video Interface (VI) mode type + */ +#define OS_VI_NTSC_LPN1 0 /* NTSC */ +#define OS_VI_NTSC_LPF1 1 +#define OS_VI_NTSC_LAN1 2 +#define OS_VI_NTSC_LAF1 3 +#define OS_VI_NTSC_LPN2 4 +#define OS_VI_NTSC_LPF2 5 +#define OS_VI_NTSC_LAN2 6 +#define OS_VI_NTSC_LAF2 7 +#define OS_VI_NTSC_HPN1 8 +#define OS_VI_NTSC_HPF1 9 +#define OS_VI_NTSC_HAN1 10 +#define OS_VI_NTSC_HAF1 11 +#define OS_VI_NTSC_HPN2 12 +#define OS_VI_NTSC_HPF2 13 + +#define OS_VI_PAL_LPN1 14 /* PAL */ +#define OS_VI_PAL_LPF1 15 +#define OS_VI_PAL_LAN1 16 +#define OS_VI_PAL_LAF1 17 +#define OS_VI_PAL_LPN2 18 +#define OS_VI_PAL_LPF2 19 +#define OS_VI_PAL_LAN2 20 +#define OS_VI_PAL_LAF2 21 +#define OS_VI_PAL_HPN1 22 +#define OS_VI_PAL_HPF1 23 +#define OS_VI_PAL_HAN1 24 +#define OS_VI_PAL_HAF1 25 +#define OS_VI_PAL_HPN2 26 +#define OS_VI_PAL_HPF2 27 + +#define OS_VI_MPAL_LPN1 28 /* MPAL - mainly Brazil */ +#define OS_VI_MPAL_LPF1 29 +#define OS_VI_MPAL_LAN1 30 +#define OS_VI_MPAL_LAF1 31 +#define OS_VI_MPAL_LPN2 32 +#define OS_VI_MPAL_LPF2 33 +#define OS_VI_MPAL_LAN2 34 +#define OS_VI_MPAL_LAF2 35 +#define OS_VI_MPAL_HPN1 36 +#define OS_VI_MPAL_HPF1 37 +#define OS_VI_MPAL_HAN1 38 +#define OS_VI_MPAL_HAF1 39 +#define OS_VI_MPAL_HPN2 40 +#define OS_VI_MPAL_HPF2 41 + +#define OS_VI_FPAL_LPN1 42 /* FPAL - Full screen PAL */ +#define OS_VI_FPAL_LPF1 43 +#define OS_VI_FPAL_LAN1 44 +#define OS_VI_FPAL_LAF1 45 +#define OS_VI_FPAL_LPN2 46 +#define OS_VI_FPAL_LPF2 47 +#define OS_VI_FPAL_LAN2 48 +#define OS_VI_FPAL_LAF2 49 +#define OS_VI_FPAL_HPN1 50 +#define OS_VI_FPAL_HPF1 51 +#define OS_VI_FPAL_HAN1 52 +#define OS_VI_FPAL_HAF1 53 +#define OS_VI_FPAL_HPN2 54 +#define OS_VI_FPAL_HPF2 55 + +/* + * Video Interface (VI) special features + */ +#define OS_VI_GAMMA_ON 0x0001 +#define OS_VI_GAMMA_OFF 0x0002 +#define OS_VI_GAMMA_DITHER_ON 0x0004 +#define OS_VI_GAMMA_DITHER_OFF 0x0008 +#define OS_VI_DIVOT_ON 0x0010 +#define OS_VI_DIVOT_OFF 0x0020 +#define OS_VI_DITHER_FILTER_ON 0x0040 +#define OS_VI_DITHER_FILTER_OFF 0x0080 + +/* + * Video Interface (VI) mode attribute bit + */ +#define OS_VI_BIT_NONINTERLACE 0x0001 /* lo-res */ +#define OS_VI_BIT_INTERLACE 0x0002 /* lo-res */ +#define OS_VI_BIT_NORMALINTERLACE 0x0004 /* hi-res */ +#define OS_VI_BIT_DEFLICKINTERLACE 0x0008 /* hi-res */ +#define OS_VI_BIT_ANTIALIAS 0x0010 +#define OS_VI_BIT_POINTSAMPLE 0x0020 +#define OS_VI_BIT_16PIXEL 0x0040 +#define OS_VI_BIT_32PIXEL 0x0080 +#define OS_VI_BIT_LORES 0x0100 +#define OS_VI_BIT_HIRES 0x0200 +#define OS_VI_BIT_NTSC 0x0400 +#define OS_VI_BIT_PAL 0x0800 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + +extern OSViMode osViModeTable[]; /* Global VI mode table */ + +extern OSViMode osViModeNtscLpn1; /* Individual VI NTSC modes */ +extern OSViMode osViModeNtscLpf1; +extern OSViMode osViModeNtscLan1; +extern OSViMode osViModeNtscLaf1; +extern OSViMode osViModeNtscLpn2; +extern OSViMode osViModeNtscLpf2; +extern OSViMode osViModeNtscLan2; +extern OSViMode osViModeNtscLaf2; +extern OSViMode osViModeNtscHpn1; +extern OSViMode osViModeNtscHpf1; +extern OSViMode osViModeNtscHan1; +extern OSViMode osViModeNtscHaf1; +extern OSViMode osViModeNtscHpn2; +extern OSViMode osViModeNtscHpf2; + +extern OSViMode osViModePalLpn1; /* Individual VI PAL modes */ +extern OSViMode osViModePalLpf1; +extern OSViMode osViModePalLan1; +extern OSViMode osViModePalLaf1; +extern OSViMode osViModePalLpn2; +extern OSViMode osViModePalLpf2; +extern OSViMode osViModePalLan2; +extern OSViMode osViModePalLaf2; +extern OSViMode osViModePalHpn1; +extern OSViMode osViModePalHpf1; +extern OSViMode osViModePalHan1; +extern OSViMode osViModePalHaf1; +extern OSViMode osViModePalHpn2; +extern OSViMode osViModePalHpf2; + +extern OSViMode osViModeMpalLpn1; /* Individual VI MPAL modes */ +extern OSViMode osViModeMpalLpf1; +extern OSViMode osViModeMpalLan1; +extern OSViMode osViModeMpalLaf1; +extern OSViMode osViModeMpalLpn2; +extern OSViMode osViModeMpalLpf2; +extern OSViMode osViModeMpalLan2; +extern OSViMode osViModeMpalLaf2; +extern OSViMode osViModeMpalHpn1; +extern OSViMode osViModeMpalHpf1; +extern OSViMode osViModeMpalHan1; +extern OSViMode osViModeMpalHaf1; +extern OSViMode osViModeMpalHpn2; +extern OSViMode osViModeMpalHpf2; + +extern OSViMode osViModeFpalLpn1; /* Individual VI FPAL modes */ +extern OSViMode osViModeFpalLpf1; +extern OSViMode osViModeFpalLan1; +extern OSViMode osViModeFpalLaf1; +extern OSViMode osViModeFpalLpn2; +extern OSViMode osViModeFpalLpf2; +extern OSViMode osViModeFpalLan2; +extern OSViMode osViModeFpalLaf2; +extern OSViMode osViModeFpalHpn1; +extern OSViMode osViModeFpalHpf1; +extern OSViMode osViModeFpalHan1; +extern OSViMode osViModeFpalHaf1; +extern OSViMode osViModeFpalHpn2; +extern OSViMode osViModeFpalHpf2; + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Video interface (Vi) */ +extern u32 osViGetStatus(void); +extern u32 osViGetCurrentMode(void); +extern u32 osViGetCurrentLine(void); +extern u32 osViGetCurrentField(void); +extern void *osViGetCurrentFramebuffer(void); +extern void *osViGetNextFramebuffer(void); +extern void osViSetXScale(f32); +extern void osViSetYScale(f32); +extern void osViExtendVStart(u32); +extern void osViSetSpecialFeatures(u32); +extern void osViSetMode(OSViMode *); +extern void osViSetEvent(OSMesgQueue *, OSMesg, u32); +extern void osViSwapBuffer(void *); +extern void osViBlack(u8); +extern void osViFade(u8, u16); +extern void osViRepeatLine(u8); +extern void osCreateViManager(OSPri); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_VI_H_ */ diff --git a/lib/ultralib/include/PR/os_voice.h b/lib/ultralib/include/PR/os_voice.h new file mode 100644 index 00000000..4e3cf6ec --- /dev/null +++ b/lib/ultralib/include/PR/os_voice.h @@ -0,0 +1,108 @@ + +/*---------------------------------------------------------------------* + Copyright (C) 1998 Nintendo. + + $RCSfile: os_voice.h,v $ + $Revision: 1.2 $ + $Date: 1999/07/13 08:36:42 $ + *---------------------------------------------------------------------*/ + +#ifndef _OS_VOICE_H_ +#define _OS_VOICE_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +typedef struct { /* Voice Recognition System */ + OSMesgQueue *__mq; /* SI Message Queue */ + int __channel; /* Controller Port # */ + s32 __mode; + u8 cmd_status; /* Command Status */ +} OSVoiceHandle; + +typedef struct { /* Voice Recognition System */ + u16 warning; + u16 answer_num; /* 0...5 */ + u16 voice_level; + u16 voice_sn; + u16 voice_time; + u16 answer[5]; + u16 distance[5]; +} OSVoiceData; + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +/************************************************************************** + * + * Global definitions + * + */ + +/* definition for Voice Recognition System */ + +#define VOICE_WARN_TOO_SMALL 0x0400 +#define VOICE_WARN_TOO_LARGE 0x0800 +#define VOICE_WARN_NOT_FIT 0x4000 +#define VOICE_WARN_TOO_NOISY 0x8000 + +#define VOICE_STATUS_READY 0 +#define VOICE_STATUS_START 1 +#define VOICE_STATUS_CANCEL 3 +#define VOICE_STATUS_BUSY 5 +#define VOICE_STATUS_END 7 + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* Voice Recognition System */ +extern s32 osVoiceInit(OSMesgQueue *, OSVoiceHandle *, int); +extern s32 osVoiceCheckWord(u8 *data); +extern s32 osVoiceClearDictionary(OSVoiceHandle *, u8); +extern s32 osVoiceControlGain(OSVoiceHandle *, s32, s32); +extern s32 osVoiceSetWord(OSVoiceHandle *, u8 *); +extern s32 osVoiceStartReadData(OSVoiceHandle *); +extern s32 osVoiceStopReadData(OSVoiceHandle *); +extern s32 osVoiceGetReadData(OSVoiceHandle *, OSVoiceData *); +extern s32 osVoiceMaskDictionary(OSVoiceHandle *, u8 *, int); +extern void osVoiceCountSyllables(u8 *, u32 *); + + +#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_VOICE_H_ */ diff --git a/lib/ultralib/include/PR/ramrom.h b/lib/ultralib/include/PR/ramrom.h new file mode 100644 index 00000000..42e5c2d5 --- /dev/null +++ b/lib/ultralib/include/PR/ramrom.h @@ -0,0 +1,113 @@ +#ifndef _RAMROM_H +#define _RAMROM_H + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.20 $ + * $Date: 1997/02/11 08:26:47 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/ramrom.h,v $ + * + **************************************************************************/ + +/* + * Defines for the GIO card in the Nintendo Development Station + * + * The RAM on the GIO card acts as ROM for the game + * Interrupts available between the game and the Indy host + * + * The last part of the ramrom is used for communication between + * game and host. There are 6 4K buffers defined: + * log, printf, rmon to indy, rmon from indy, app to indy, app from indy + * The last 8 bytes of the buffer are used in the emulator environment + */ + +#define RAMROM_SIZE (0x1000000) + +#define RAMROM_BUF_SIZE (4096) +#define RAMROM_MSG_SIZE (RAMROM_BUF_SIZE*6) +#define RAMROM_MSG_ADDR (RAMROM_SIZE - RAMROM_MSG_SIZE) +#define RAMROM_MSG_HDR_SIZE (3*sizeof(long)) +#define RAMROM_USER_DATA_SIZE (RAMROM_MSG_SIZE-RAMROM_MSG_HDR_SIZE) + +#define RAMROM_APP_READ_ADDR (RAMROM_MSG_ADDR + (0*RAMROM_BUF_SIZE)) +#define RAMROM_APP_WRITE_ADDR (RAMROM_MSG_ADDR + (1*RAMROM_BUF_SIZE)) +#define RAMROM_RMON_READ_ADDR (RAMROM_MSG_ADDR + (2*RAMROM_BUF_SIZE)) +#define RAMROM_RMON_WRITE_ADDR (RAMROM_MSG_ADDR + (3*RAMROM_BUF_SIZE)) +#define RAMROM_PRINTF_ADDR (RAMROM_MSG_ADDR + (4*RAMROM_BUF_SIZE)) +#define RAMROM_LOG_ADDR (RAMROM_MSG_ADDR + (5*RAMROM_BUF_SIZE)) + +/*#define RAMROM_GIO_INTERRUPT (RAMROM_MSG_ADDR + RAMROM_MSG_SIZE - 4)*/ + +/* + * For the initial round of PIF bringup, we will load in a bootstrap loader + * 0x400 bytes into the ramrom, and the rom will be loaded at 0x2000 + */ +#ifndef _HW_VERSION_1 +#define RAMROM_BOOTSTRAP_OFFSET 0x40 +#define RAMROM_GAME_OFFSET 0x1000 +#define RAMROM_FONTDATA_OFFSET 0xb70 +#define RAMROM_FONTDATA_SIZE 1152 +#else +#define RAMROM_BOOTSTRAP_OFFSET 0x400 +#define RAMROM_GAME_OFFSET 0x2000 +#endif +#define RAMROM_CLOCKRATE_OFFSET 0x4 +#define RAMROM_CLOCKRATE_MASK 0xfffffff0 +#define RAMROM_BOOTADDR_OFFSET 0x8 +#define RAMROM_RELEASE_OFFSET 0xc +/* + * Second version of the PIF jumps to location 0x1000, and we'll put a jump to + * location 0x400 into the ramrom (for backwards compatibility). + */ +#define RAMROM_PIF2BOOTSTRAP_OFFSET 0x1000 + +typedef struct { + long type; + long length; /* in bytes of userdata */ + long magic; + char userdata[RAMROM_USER_DATA_SIZE]; +} RamRomBuffer; + +/* + * Interrupt values (must fit in 6 bits!) + * values are used for both request & response + * Transactions initiated by the host start with HOST + * and those initiated by the target start with GAME. + */ + +#define HOST_PIACCESS_REQ 1 +#define HOST_DBG_CMD_READY 2 +#define GAME_DBG_DATA_SEND 3 +#define HOST_DBG_DATA_ACK 4 +#define GAME_PRINTF_SEND 5 +#define HOST_PRINTF_ACK 6 +#define GAME_LOG_SEND 7 +#define HOST_LOG_ACK 8 +#define HOST_APP_CMD_READY 9 +#define GAME_APP_DATA_READY 10 +#define HOST_PROF_REQ 11 +#define GAME_PROF_SEND 12 +#define HOST_PROF_ACK 13 +#define GAME_FAULT_SEND 14 +#define HOST_FAULT_ACK 15 +#define GAME_EXIT 16 +#define HOST_DATA_ACK 17 + +#ifdef _EMULATOR +void __RamRomInit(int key, void *romaddr); +void __RamRomDestroy(int key); +#endif /* _EMULATOR */ + +#endif /* !_RAMROM_H */ diff --git a/lib/ultralib/include/PR/rcp.h b/lib/ultralib/include/PR/rcp.h new file mode 100644 index 00000000..56cb2369 --- /dev/null +++ b/lib/ultralib/include/PR/rcp.h @@ -0,0 +1,848 @@ +#ifndef _RCP_H_ +#define _RCP_H_ + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * File: rcp.h + * + * This file contains register and bit definitions for RCP memory map. + * $Revision: 1.22 $ + * $Date: 1999/05/20 03:01:49 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/rcp.h,v $ + * + **************************************************************************/ + +#include "R4300.h" +#include "ultratypes.h" + +/** + * RCP memory map overview: + * + * 0x0000_0000 .. 0x03ef_ffff RDRAM memory + * 0x03f0_0000 .. 0x03ff_ffff RDRAM registers + * + * 0x0400_0000 .. 0x0400_2000 SP memory + * 0x0404_0000 .. 0x040f_ffff SP registers + * 0x0410_0000 .. 0x041f_ffff DP command registers + * 0x0420_0000 .. 0x042f_ffff DP span registers + * 0x0430_0000 .. 0x043f_ffff MI registers + * 0x0440_0000 .. 0x044f_ffff VI registers + * 0x0450_0000 .. 0x045f_ffff AI registers + * 0x0460_0000 .. 0x046f_ffff PI registers + * 0x0470_0000 .. 0x047f_ffff RI registers + * 0x0480_0000 .. 0x048f_ffff SI registers + * 0x0490_0000 .. 0x04ff_ffff unused + * + * 0x0500_0000 .. 0x05ff_ffff cartridge domain 2 + * 0x0600_0000 .. 0x07ff_ffff cartridge domain 1 + * 0x0800_0000 .. 0x0fff_ffff cartridge domain 2 + * 0x1000_0000 .. 0x1fbf_ffff cartridge domain 1 + * + * 0x1fc0_0000 .. 0x1fc0_07bf PIF Boot Rom (1984 bytes) + * 0x1fc0_07c0 .. 0x1fc0_07ff PIF (JoyChannel) RAM (64 bytes) + * 0x1fc0_0800 .. 0x1fcf_ffff Reserved + * 0x1fd0_0000 .. 0x7fff_ffff cartridge domain 1 + * 0x8000_0000 .. 0xffff_ffff external SysAD device + */ + +/** + * RDRAM memory + */ + +#define RDRAM_0_START 0x00000000 +#define RDRAM_0_END 0x001FFFFF +#define RDRAM_1_START 0x00200000 +#define RDRAM_1_END 0x003FFFFF + +#define RDRAM_START RDRAM_0_START +#define RDRAM_END RDRAM_1_END + +/** + * RDRAM registers + */ +#define RDRAM_BASE_REG 0x03F00000 + +#define RDRAM_CONFIG_REG (RDRAM_BASE_REG + 0x00) +#define RDRAM_DEVICE_TYPE_REG (RDRAM_BASE_REG + 0x00) +#define RDRAM_DEVICE_ID_REG (RDRAM_BASE_REG + 0x04) +#define RDRAM_DELAY_REG (RDRAM_BASE_REG + 0x08) +#define RDRAM_MODE_REG (RDRAM_BASE_REG + 0x0c) +#define RDRAM_REF_INTERVAL_REG (RDRAM_BASE_REG + 0x10) +#define RDRAM_REF_ROW_REG (RDRAM_BASE_REG + 0x14) +#define RDRAM_RAS_INTERVAL_REG (RDRAM_BASE_REG + 0x18) +#define RDRAM_MIN_INTERVAL_REG (RDRAM_BASE_REG + 0x1c) +#define RDRAM_ADDR_SELECT_REG (RDRAM_BASE_REG + 0x20) +#define RDRAM_DEVICE_MANUF_REG (RDRAM_BASE_REG + 0x24) + +#define RDRAM_0_DEVICE_ID 0 +#define RDRAM_1_DEVICE_ID 1 + +#define RDRAM_RESET_MODE 0 +#define RDRAM_ACTIVE_MODE 1 +#define RDRAM_STANDBY_MODE 2 + +#define RDRAM_LENGTH (2 * 512 * 2048) +#define RDRAM_0_BASE_ADDRESS (RDRAM_0_DEVICE_ID * RDRAM_LENGTH) +#define RDRAM_1_BASE_ADDRESS (RDRAM_1_DEVICE_ID * RDRAM_LENGTH) + +#define RDRAM_0_CONFIG 0x00000 +#define RDRAM_1_CONFIG 0x00400 +#define RDRAM_GLOBAL_CONFIG 0x80000 + +/** + * PIF Physical memory map (total size = 2 KB) + * + * Size Description Mode + * 1FC007FF +-------+-----------------+-----+ + * | 64 B | JoyChannel RAM | R/W | + * 1FC007C0 +-------+-----------------+-----+ + * |1984 B | Boot ROM | * | * = Reserved + * 1FC00000 +-------+-----------------+-----+ + */ +#define PIF_ROM_START 0x1FC00000 +#define PIF_ROM_END 0x1FC007BF +#define PIF_RAM_START 0x1FC007C0 +#define PIF_RAM_END 0x1FC007FF + + +/** + * Controller channel + * Each game controller channel has 4 error bits that are defined in bit 6-7 of + * the Rx and Tx data size area bytes. Programmers need to clear these bits + * when setting the Tx/Rx size area values for a channel + */ +#define CHNL_ERR_NORESP 0x80 /* Bit 7 (Rx): No response error */ +#define CHNL_ERR_OVERRUN 0x40 /* Bit 6 (Rx): Overrun error */ +#define CHNL_ERR_FRAME 0x80 /* Bit 7 (Tx): Frame error */ +#define CHNL_ERR_COLLISION 0x40 /* Bit 6 (Tx): Collision error */ + +#define CHNL_ERR_MASK 0xC0 /* Bit 6-7: channel errors */ + + +/** + * External device info + */ +#define DEVICE_TYPE_CART 0 /* ROM cartridge */ +#define DEVICE_TYPE_BULK 1 /* ROM bulk */ +#define DEVICE_TYPE_64DD 2 /* 64 Disk Drive */ +#define DEVICE_TYPE_SRAM 3 /* SRAM */ +/* 4-6 are reserved */ +#define DEVICE_TYPE_INIT 7 /* initial value */ +/* 8-14 are reserved */ + +/** + * Signal Processor (SP) Memory + */ +#define SP_DMEM_START 0x04000000 +#define SP_DMEM_END 0x04000FFF +#define SP_IMEM_START 0x04001000 +#define SP_IMEM_END 0x04001FFF + +/** + * Signal Processor (SP) CP0 Registers + */ + +#define SP_BASE_REG 0x04040000 + +//! SP memory address (R/W): [11:0] DMEM/IMEM address, [12] 0=DMEM,1=IMEM +#define SP_MEM_ADDR_REG (SP_BASE_REG + 0x00) + +//! SP DRAM DMA address (R/W): [23:0] RDRAM address +#define SP_DRAM_ADDR_REG (SP_BASE_REG + 0x04) + +//! SP read DMA length (R/W): [11:0] length, [19:12] count, [31:20] skip; RDRAM -> I/DMEM +#define SP_RD_LEN_REG (SP_BASE_REG + 0x08) + +//! SP write DMA length (R/W): [11:0] length, [19:12] count, [31:20] skip; I/DMEM -> RDRAM +#define SP_WR_LEN_REG (SP_BASE_REG + 0x0C) + +//! SP status (R/W): [14:0] valid bits; see below for write/read mode +#define SP_STATUS_REG (SP_BASE_REG + 0x10) + +//! SP DMA full (R): [0] dma full +#define SP_DMA_FULL_REG (SP_BASE_REG + 0x14) + +//! SP DMA busy (R): [0] dma busy +#define SP_DMA_BUSY_REG (SP_BASE_REG + 0x18) + +//! SP semaphore (R/W): Read: [0] acquire semaphore; Write: [] release semaphore +#define SP_SEMAPHORE_REG (SP_BASE_REG + 0x1C) + +//! SP PC (R/W): [11:0] program counter +#define SP_PC_REG 0x04080000 + +/** + * SP_MEM_ADDR_REG: bit 12 + */ +#define SP_DMA_DMEM (0 << 12) +#define SP_DMA_IMEM (1 << 12) + +/** + * SP_STATUS_REG: write bits + */ +#define SP_CLR_HALT (1 << 0) // clear halt +#define SP_SET_HALT (1 << 1) // set halt +#define SP_CLR_BROKE (1 << 2) // clear broke +#define SP_CLR_INTR (1 << 3) // clear interrupt +#define SP_SET_INTR (1 << 4) // set interrupt +#define SP_CLR_SSTEP (1 << 5) // clear sstep +#define SP_SET_SSTEP (1 << 6) // set sstep +#define SP_CLR_INTR_BREAK (1 << 7) // clear interrupt on break +#define SP_SET_INTR_BREAK (1 << 8) // set interrupt on break +#define SP_CLR_SIG0 (1 << 9) // clear signal 0 +#define SP_SET_SIG0 (1 << 10) // set signal 0 +#define SP_CLR_SIG1 (1 << 11) // clear signal 1 +#define SP_SET_SIG1 (1 << 12) // set signal 1 +#define SP_CLR_SIG2 (1 << 13) // clear signal 2 +#define SP_SET_SIG2 (1 << 14) // set signal 2 +#define SP_CLR_SIG3 (1 << 15) // clear signal 3 +#define SP_SET_SIG3 (1 << 16) // set signal 3 +#define SP_CLR_SIG4 (1 << 17) // clear signal 4 +#define SP_SET_SIG4 (1 << 18) // set signal 4 +#define SP_CLR_SIG5 (1 << 19) // clear signal 5 +#define SP_SET_SIG5 (1 << 20) // set signal 5 +#define SP_CLR_SIG6 (1 << 21) // clear signal 6 +#define SP_SET_SIG6 (1 << 22) // set signal 6 +#define SP_CLR_SIG7 (1 << 23) // clear signal 7 +#define SP_SET_SIG7 (1 << 24) // set signal 7 + +/* + * SP_STATUS_REG: read bits + */ +#define SP_STATUS_HALT (1 << 0) +#define SP_STATUS_BROKE (1 << 1) +#define SP_STATUS_DMA_BUSY (1 << 2) +#define SP_STATUS_DMA_FULL (1 << 3) +#define SP_STATUS_IO_FULL (1 << 4) +#define SP_STATUS_SSTEP (1 << 5) +#define SP_STATUS_INTR_BREAK (1 << 6) +#define SP_STATUS_SIG0 (1 << 7) +#define SP_STATUS_SIG1 (1 << 8) +#define SP_STATUS_SIG2 (1 << 9) +#define SP_STATUS_SIG3 (1 << 10) +#define SP_STATUS_SIG4 (1 << 11) +#define SP_STATUS_SIG5 (1 << 12) +#define SP_STATUS_SIG6 (1 << 13) +#define SP_STATUS_SIG7 (1 << 14) + +/* + * SP_STATUS_REG: use of SIG bits + */ +#define SP_CLR_YIELD SP_CLR_SIG0 +#define SP_SET_YIELD SP_SET_SIG0 +#define SP_STATUS_YIELD SP_STATUS_SIG0 +#define SP_CLR_YIELDED SP_CLR_SIG1 +#define SP_SET_YIELDED SP_SET_SIG1 +#define SP_STATUS_YIELDED SP_STATUS_SIG1 +#define SP_CLR_TASKDONE SP_CLR_SIG2 +#define SP_SET_TASKDONE SP_SET_SIG2 +#define SP_STATUS_TASKDONE SP_STATUS_SIG2 +#define SP_CLR_RSPSIGNAL SP_CLR_SIG3 +#define SP_SET_RSPSIGNAL SP_SET_SIG3 +#define SP_STATUS_RSPSIGNAL SP_STATUS_SIG3 +#define SP_CLR_CPUSIGNAL SP_CLR_SIG4 +#define SP_SET_CPUSIGNAL SP_SET_SIG4 +#define SP_STATUS_CPUSIGNAL SP_STATUS_SIG4 + +/* + * SP IMEM BIST REG (R/W): [6:0] BIST status bits; see below for detail + */ +#define SP_IBIST_REG 0x04080004 + +/* + * SP_IBIST_REG: write bits + */ +#define SP_IBIST_CHECK (1 << 0) // BIST check +#define SP_IBIST_GO (1 << 1) // BIST go +#define SP_IBIST_CLEAR (1 << 2) // BIST clear + +/* + * SP_BIST_REG: read bits + * First 2 bits are same as in write mode + */ +#define SP_IBIST_DONE (1 << 2) +#define SP_IBIST_FAILED 0x78 // bits [6:3], BIST fail + +/** + * Display Processor Command (DPC) Registers + */ +#define DPC_BASE_REG 0x04100000 + +//! DP CMD DMA start (R/W): [23:0] DMEM/RDRAM start address +#define DPC_START_REG (DPC_BASE_REG + 0x00) + +//! DP CMD DMA end (R/W): [23:0] DMEM/RDRAM end address +#define DPC_END_REG (DPC_BASE_REG + 0x04) + +//! DP CMD DMA end (R): [23:0] DMEM/RDRAM current address +#define DPC_CURRENT_REG (DPC_BASE_REG + 0x08) + +//! DP CMD status (R/W): [9:0] valid bits - see below for definitions +#define DPC_STATUS_REG (DPC_BASE_REG + 0x0C) + +//! DP clock counter (R): [23:0] clock counter +#define DPC_CLOCK_REG (DPC_BASE_REG + 0x10) + +//! DP buffer busy counter (R): [23:0] clock counter +#define DPC_BUFBUSY_REG (DPC_BASE_REG + 0x14) + +//! DP pipe busy counter (R): [23:0] clock counter +#define DPC_PIPEBUSY_REG (DPC_BASE_REG + 0x18) + +//! DP TMEM load counter (R): [23:0] clock counter +#define DPC_TMEM_REG (DPC_BASE_REG + 0x1C) + +/** + * DPC_STATUS_REG: write bits + */ +#define DPC_CLR_XBUS_DMEM_DMA (1 << 0) +#define DPC_SET_XBUS_DMEM_DMA (1 << 1) +#define DPC_CLR_FREEZE (1 << 2) +#define DPC_SET_FREEZE (1 << 3) +#define DPC_CLR_FLUSH (1 << 4) +#define DPC_SET_FLUSH (1 << 5) +#define DPC_CLR_TMEM_CTR (1 << 6) +#define DPC_CLR_PIPE_CTR (1 << 7) +#define DPC_CLR_CMD_CTR (1 << 8) +#define DPC_CLR_CLOCK_CTR (1 << 9) + +/** + * DPC_STATUS_REG: read bits + */ +#define DPC_STATUS_XBUS_DMEM_DMA (1 << 0) +#define DPC_STATUS_FREEZE (1 << 1) +#define DPC_STATUS_FLUSH (1 << 2) +#define DPC_STATUS_START_GCLK (1 << 3) +#define DPC_STATUS_TMEM_BUSY (1 << 4) +#define DPC_STATUS_PIPE_BUSY (1 << 5) +#define DPC_STATUS_CMD_BUSY (1 << 6) +#define DPC_STATUS_CBUF_READY (1 << 7) +#define DPC_STATUS_DMA_BUSY (1 << 8) +#define DPC_STATUS_END_VALID (1 << 9) +#define DPC_STATUS_START_VALID (1 << 10) + +/** + * Display Processor Span (DPS) Registers + */ +#define DPS_BASE_REG 0x04200000 + +//! DP tmem built-in self-test (R/W): [10:0] BIST status bits +#define DPS_TBIST_REG (DPS_BASE_REG + 0x00) + +//! DP span test mode (R/W): [0] Span buffer test access enable +#define DPS_TEST_MODE_REG (DPS_BASE_REG + 0x04) + +//! DP span buffer test address (R/W): [6:0] bits +#define DPS_BUFTEST_ADDR_REG (DPS_BASE_REG + 0x08) + +//! DP span buffer test data (R/W): [31:0] span buffer data +#define DPS_BUFTEST_DATA_REG (DPS_BASE_REG + 0x0C) + +/* + * DPS_TMEM_BIST_REG: write bits + */ +#define DPS_TBIST_CHECK (1 << 0) +#define DPS_TBIST_GO (1 << 1) +#define DPS_TBIST_CLEAR (1 << 2) + +/* + * DPS_TMEM_BIST_REG: read bits + * First 2 bits are same as in write mode + */ +#define DPS_TBIST_DONE (1 << 2) +#define DPS_TBIST_FAILED 0x7F8 // bits [10:3], BIST fail + +/** + * MIPS Interface (MI) Registers + */ +#define MI_BASE_REG 0x04300000 + +/* + * MI init mode (W): [6:0] init length, [7] clear init mode, [8] set init mode + * [9/10] clear/set ebus test mode, [11] clear DP interrupt + * (R): [6:0] init length, [7] init mode, [8] ebus test mode + */ +#define MI_INIT_MODE_REG (MI_BASE_REG + 0x00) +#define MI_MODE_REG MI_INIT_MODE_REG + +/* + * MI_MODE_REG: write bits + */ +#define MI_CLR_INIT (1 << 7) /* clear init mode */ +#define MI_SET_INIT (1 << 8) /* set init mode */ +#define MI_CLR_EBUS (1 << 9) /* clear ebus test */ +#define MI_SET_EBUS (1 << 10) /* set ebus test mode */ +#define MI_CLR_DP_INTR (1 << 11) /* clear dp interrupt */ +#define MI_CLR_RDRAM (1 << 12) /* clear RDRAM reg */ +#define MI_SET_RDRAM (1 << 13) /* set RDRAM reg mode */ + +/* + * MI_MODE_REG: read bits + */ +#define MI_MODE_INIT (1 << 7) /* init mode */ +#define MI_MODE_EBUS (1 << 8) /* ebus test mode */ +#define MI_MODE_RDRAM (1 << 9) /* RDRAM reg mode */ + +//! MI version (R): [7:0] io, [15:8] rac, [23:16] rdp, [31:24] rsp +#define MI_VERSION_REG (MI_BASE_REG + 0x04) +#define MI_NOOP_REG MI_VERSION_REG + +//! MI interrupt (R): [5:0] valid bits - see below for bit patterns +#define MI_INTR_REG (MI_BASE_REG + 0x08) + +/* + * MI interrupt mask (W): [11:0] valid bits - see below for bit patterns + * (R): [5:0] valid bits - see below for bit patterns + */ +#define MI_INTR_MASK_REG (MI_BASE_REG + 0x0C) + +/* + * MI_INTR_REG: read bits + */ +#define MI_INTR_SP (1 << 0) /* SP intr */ +#define MI_INTR_SI (1 << 1) /* SI intr */ +#define MI_INTR_AI (1 << 2) /* AI intr */ +#define MI_INTR_VI (1 << 3) /* VI intr */ +#define MI_INTR_PI (1 << 4) /* PI intr */ +#define MI_INTR_DP (1 << 5) /* DP intr */ + +/* + * MI_INTR_MASK_REG: write bits + */ +#define MI_INTR_MASK_CLR_SP (1 << 0) /* clear SP mask */ +#define MI_INTR_MASK_SET_SP (1 << 1) /* set SP mask */ +#define MI_INTR_MASK_CLR_SI (1 << 2) /* clear SI mask */ +#define MI_INTR_MASK_SET_SI (1 << 3) /* set SI mask */ +#define MI_INTR_MASK_CLR_AI (1 << 4) /* clear AI mask */ +#define MI_INTR_MASK_SET_AI (1 << 5) /* set AI mask */ +#define MI_INTR_MASK_CLR_VI (1 << 6) /* clear VI mask */ +#define MI_INTR_MASK_SET_VI (1 << 7) /* set VI mask */ +#define MI_INTR_MASK_CLR_PI (1 << 8) /* clear PI mask */ +#define MI_INTR_MASK_SET_PI (1 << 9) /* set PI mask */ +#define MI_INTR_MASK_CLR_DP (1 << 10) /* clear DP mask */ +#define MI_INTR_MASK_SET_DP (1 << 11) /* set DP mask */ + +/* + * MI_INTR_MASK_REG: read bits + */ +#define MI_INTR_MASK_SP (1 << 0) /* SP intr mask */ +#define MI_INTR_MASK_SI (1 << 1) /* SI intr mask */ +#define MI_INTR_MASK_AI (1 << 2) /* AI intr mask */ +#define MI_INTR_MASK_VI (1 << 3) /* VI intr mask */ +#define MI_INTR_MASK_PI (1 << 4) /* PI intr mask */ +#define MI_INTR_MASK_DP (1 << 5) /* DP intr mask */ + +/** + * Video Interface (VI) Registers + */ +#define VI_BASE_REG 0x04400000 + +/* VI status/control (R/W): [15-0] valid bits: + * [1:0] = type[1:0] (pixel size) + * 0: blank (no data, no sync) + * 1: reserved + * 2: 5/5/5/3 ("16" bit) + * 3: 8/8/8/8 (32 bit) + * [2] = gamma_dither_enable (normally on, unless "special effect") + * [3] = gamma_enable (normally on, unless MPEG/JPEG) + * [4] = divot_enable (normally on if antialiased, unless decal lines) + * [5] = reserved - always off + * [6] = serrate (always on if interlaced, off if not) + * [7] = reserved - diagnostics only + * [9:8] = anti-alias (aa) mode[1:0] + * 0: aa & resamp (always fetch extra lines) + * 1: aa & resamp (fetch extra lines if needed) + * 2: resamp only (treat as all fully covered) + * 3: neither (replicate pixels, no interpolate) + * [11] = reserved - diagnostics only + * [15:12] = reserved + * + */ +#define VI_CONTROL_REG (VI_BASE_REG + 0x00) +#define VI_STATUS_REG VI_CONTROL_REG + +/* VI origin (R/W): [23:0] frame buffer origin in bytes */ +#define VI_ORIGIN_REG (VI_BASE_REG + 0x04) +#define VI_DRAM_ADDR_REG VI_ORIGIN_REG + +/* VI width (R/W): [11:0] frame buffer line width in pixels */ +#define VI_WIDTH_REG (VI_BASE_REG + 0x08) +#define VI_H_WIDTH_REG VI_WIDTH_REG + +/* VI vertical intr (R/W): [9:0] interrupt when current half-line = V_INTR */ +#define VI_INTR_REG (VI_BASE_REG + 0x0C) +#define VI_V_INTR_REG VI_INTR_REG + +/* + * VI current vertical line (R/W): [9:0] current half line, sampled once per + * line (the lsb of V_CURRENT is constant within a field, and in + * interlaced modes gives the field number - which is constant for non- + * interlaced modes) + * - Any write to this register will clear interrupt line + */ +#define VI_CURRENT_REG (VI_BASE_REG + 0x10) +#define VI_V_CURRENT_LINE_REG VI_CURRENT_REG + +/* + * VI video timing (R/W): [ 7: 0] horizontal sync width in pixels, + * [15: 8] color burst width in pixels, + * [19:16] vertical sync width in half lines, + * [29:20] start of color burst in pixels from h-sync + */ +#define VI_BURST_REG (VI_BASE_REG + 0x14) +#define VI_TIMING_REG VI_BURST_REG + +/* VI vertical sync (R/W): [9:0] number of half-lines per field */ +#define VI_V_SYNC_REG (VI_BASE_REG + 0x18) + +/* VI horizontal sync (R/W): [11: 0] total duration of a line in 1/4 pixel + * [20:16] a 5-bit leap pattern used for PAL only + * (h_sync_period) + */ +#define VI_H_SYNC_REG (VI_BASE_REG + 0x1C) + +/* + * VI horizontal sync leap (R/W): [11: 0] identical to h_sync_period + * [27:16] identical to h_sync_period + */ +#define VI_LEAP_REG (VI_BASE_REG + 0x20) +#define VI_H_SYNC_LEAP_REG VI_LEAP_REG + +/* + * VI horizontal video (R/W): [ 9: 0] end of active video in screen pixels + * : [25:16] start of active video in screen pixels + */ +#define VI_H_START_REG (VI_BASE_REG + 0x24) +#define VI_H_VIDEO_REG VI_H_START_REG + +/* + * VI vertical video (R/W): [ 9: 0] end of active video in screen half-lines + * : [25:16] start of active video in screen half-lines + */ +#define VI_V_START_REG (VI_BASE_REG + 0x28) +#define VI_V_VIDEO_REG VI_V_START_REG + +/* + * VI vertical burst (R/W): [ 9: 0] end of color burst enable in half-lines + * : [25:16] start of color burst enable in half-lines + */ +#define VI_V_BURST_REG (VI_BASE_REG + 0x2C) + +/* VI x-scale (R/W): [11: 0] 1/horizontal scale up factor (2.10 format) + * [27:16] horizontal subpixel offset (2.10 format) + */ +#define VI_X_SCALE_REG (VI_BASE_REG + 0x30) + +/* VI y-scale (R/W): [11: 0] 1/vertical scale up factor (2.10 format) + * [27:16] vertical subpixel offset (2.10 format) + */ +#define VI_Y_SCALE_REG (VI_BASE_REG + 0x34) + +/* + * Patterns to interpret VI_CONTROL_REG + */ +#define VI_CTRL_TYPE_16 0x00002 /* [1:0] pixel size: 16 bit */ +#define VI_CTRL_TYPE_32 0x00003 /* [1:0] pixel size: 32 bit */ +#define VI_CTRL_GAMMA_DITHER_ON 0x00004 /* 2: default = on */ +#define VI_CTRL_GAMMA_ON 0x00008 /* 3: default = on */ +#define VI_CTRL_DIVOT_ON 0x00010 /* 4: default = on */ +#define VI_CTRL_SERRATE_ON 0x00040 /* 6: on if interlaced */ +#define VI_CTRL_ANTIALIAS_MASK 0x00300 /* [9:8] anti-alias mode */ +#define VI_CTRL_ANTIALIAS_MODE_1 0x00100 /* Bit [9:8] anti-alias mode */ +#define VI_CTRL_ANTIALIAS_MODE_2 0x00200 /* Bit [9:8] anti-alias mode */ +#define VI_CTRL_ANTIALIAS_MODE_3 0x00300 /* Bit [9:8] anti-alias mode */ +#define VI_CTRL_PIXEL_ADV_MASK 0x01000 /* [15:12] pixel advance mode? */ +#define VI_CTRL_PIXEL_ADV_1 0x01000 /* Bit [15:12] pixel advance mode? */ +#define VI_CTRL_PIXEL_ADV_2 0x02000 /* Bit [15:12] pixel advance mode? */ +#define VI_CTRL_PIXEL_ADV_3 0x03000 /* Bit [15:12] pixel advance mode? */ +#define VI_CTRL_DITHER_FILTER_ON 0x10000 /* 16: dither-filter mode */ + +/* + * Possible video clocks (NTSC or PAL) + */ +#define VI_NTSC_CLOCK 48681812 /* Hz = 48.681812 MHz */ +#define VI_PAL_CLOCK 49656530 /* Hz = 49.656530 MHz */ +#define VI_MPAL_CLOCK 48628316 /* Hz = 48.628316 MHz */ + +/** + * The address and length registers are double buffered; that is, they + * can be written twice before becoming full. + * The address must be written before the length. + */ + +/** + * Audio Interface (AI) Registers + */ +#define AI_BASE_REG 0x04500000 + +/* AI DRAM address (W): [23:0] starting RDRAM address (8B-aligned) */ +#define AI_DRAM_ADDR_REG (AI_BASE_REG + 0x00) /* R0: DRAM address */ + +/* AI length (R/W): [14:0] transfer length (v1.0) - Bottom 3 bits are ignored */ +/* [17:0] transfer length (v2.0) - Bottom 3 bits are ignored */ +#define AI_LEN_REG (AI_BASE_REG + 0x04) /* R1: Length */ + +/* AI control (W): [0] DMA enable - if LSB == 1, DMA is enabled */ +#define AI_CONTROL_REG (AI_BASE_REG + 0x08) /* R2: DMA Control */ + +/* Value for control register */ +#define AI_CONTROL_DMA_ON 1 /* LSB = 1: DMA enable*/ +#define AI_CONTROL_DMA_OFF 0 /* LSB = 1: DMA enable*/ + +/* + * AI status (R): [31]/[0] ai_full (addr & len buffer full), [30] ai_busy + * Note that a 1->0 transition in ai_full will set interrupt + * (W): clear audio interrupt + */ +#define AI_STATUS_REG (AI_BASE_REG + 0x0C) /* R3: Status */ + +/* Value for status register */ +#define AI_STATUS_FIFO_FULL (1 << 31) +#define AI_STATUS_DMA_BUSY (1 << 30) + +/* + * AI DAC sample period register (W): [13:0] dac rate + * - vid_clock/(dperiod + 1) is the DAC sample rate + * - (dperiod + 1) >= 66 * (aclockhp + 1) must be true + */ +#define AI_DACRATE_REG (AI_BASE_REG + 0x10) /* R4: DAC rate 14-lsb*/ + +/* DAC rate = video clock / audio frequency + * - DAC rate >= (66 * Bit rate) must be true + */ +#define AI_MAX_DAC_RATE 16384 /* 14-bit+1 */ +#define AI_MIN_DAC_RATE 132 + +/* + * AI bit rate (W): [3:0] bit rate (abus clock half period register - aclockhp) + * - vid_clock/(2 * (aclockhp + 1)) is the DAC clock rate + * - The abus clock stops if aclockhp is zero + */ +#define AI_BITRATE_REG (AI_BASE_REG + 0x14) /* R5: Bit rate 4-lsb */ + +/* Bit rate <= (DAC rate / 66) */ +#define AI_MAX_BIT_RATE 16 /* 4-bit+1 */ +#define AI_MIN_BIT_RATE 2 + +/* + * Maximum and minimum values for audio frequency based on video clocks + * max frequency = (video clock / min dac rate) + * min frequency = (video clock / max dac rate) + */ +#define AI_NTSC_MAX_FREQ 368000 /* 368 KHz */ +#define AI_NTSC_MIN_FREQ 3000 /* 3 KHz ~ 2971 Hz */ + +#define AI_PAL_MAX_FREQ 376000 /* 376 KHz */ +#define AI_PAL_MIN_FREQ 3050 /* 3 KHz ~ 3031 Hz */ + +#define AI_MPAL_MAX_FREQ 368000 /* 368 KHz */ +#define AI_MPAL_MIN_FREQ 3000 /* 3 KHz ~ 2968 Hz */ + +/** + * Peripheral Interface (PI) Registers + */ +#define PI_BASE_REG 0x04600000 + +/* PI DRAM address (R/W): [23:0] starting RDRAM address */ +#define PI_DRAM_ADDR_REG (PI_BASE_REG + 0x00) /* DRAM address */ + +/* PI pbus (cartridge) address (R/W): [31:0] starting AD16 address */ +#define PI_CART_ADDR_REG (PI_BASE_REG + 0x04) + +/* PI read length (R/W): [23:0] read data length */ +#define PI_RD_LEN_REG (PI_BASE_REG + 0x08) + +/* PI write length (R/W): [23:0] write data length */ +#define PI_WR_LEN_REG (PI_BASE_REG + 0x0C) + +/* + * PI status (R): [0] DMA busy, [1] IO busy, [2], error + * (W): [0] reset controller (and abort current op), [1] clear intr + */ +#define PI_STATUS_REG (PI_BASE_REG + 0x10) + +/* PI dom1 latency (R/W): [7:0] domain 1 device latency */ +#define PI_BSD_DOM1_LAT_REG (PI_BASE_REG + 0x14) + +/* PI dom1 pulse width (R/W): [7:0] domain 1 device R/W strobe pulse width */ +#define PI_BSD_DOM1_PWD_REG (PI_BASE_REG + 0x18) + +/* PI dom1 page size (R/W): [3:0] domain 1 device page size */ +#define PI_BSD_DOM1_PGS_REG (PI_BASE_REG + 0x1C) /* page size */ + +/* PI dom1 release (R/W): [1:0] domain 1 device R/W release duration */ +#define PI_BSD_DOM1_RLS_REG (PI_BASE_REG + 0x20) + +/* PI dom2 latency (R/W): [7:0] domain 2 device latency */ +#define PI_BSD_DOM2_LAT_REG (PI_BASE_REG + 0x24) /* Domain 2 latency */ + +/* PI dom2 pulse width (R/W): [7:0] domain 2 device R/W strobe pulse width */ +#define PI_BSD_DOM2_PWD_REG (PI_BASE_REG + 0x28) /* pulse width */ + +/* PI dom2 page size (R/W): [3:0] domain 2 device page size */ +#define PI_BSD_DOM2_PGS_REG (PI_BASE_REG + 0x2C) /* page size */ + +/* PI dom2 release (R/W): [1:0] domain 2 device R/W release duration */ +#define PI_BSD_DOM2_RLS_REG (PI_BASE_REG + 0x30) /* release duration */ + +#define PI_DOMAIN1_REG PI_BSD_DOM1_LAT_REG +#define PI_DOMAIN2_REG PI_BSD_DOM2_LAT_REG + +#define PI_DOM_LAT_OFS 0x00 +#define PI_DOM_PWD_OFS 0x04 +#define PI_DOM_PGS_OFS 0x08 +#define PI_DOM_RLS_OFS 0x0C + +/* + * PI status register has 3 bits active when read from (PI_STATUS_REG - read) + * Bit 0: DMA busy - set when DMA is in progress + * Bit 1: IO busy - set when IO is in progress + * Bit 2: Error - set when CPU issues IO request while DMA is busy + */ +#define PI_STATUS_DMA_BUSY (1 << 0) +#define PI_STATUS_IO_BUSY (1 << 1) +#define PI_STATUS_ERROR (1 << 2) + +/* PI status register has 2 bits active when written to: + * Bit 0: When set, reset PIC + * Bit 1: When set, clear interrupt flag + * The values of the two bits can be ORed together to both reset PIC and + * clear interrupt at the same time. + * + * Note: + * - The PIC does generate an interrupt at the end of each DMA. CPU + * needs to clear the interrupt flag explicitly (from an interrupt + * handler) by writing into the STATUS register with bit 1 set. + * + * - When a DMA completes, the interrupt flag is set. CPU can issue + * another request even while the interrupt flag is set (as long as + * PIC is idle). However, it is the CPU's responsibility for + * maintaining accurate correspondence between DMA completions and + * interrupts. + * + * - When PIC is reset, if PIC happens to be busy, an interrupt will + * be generated as PIC returns to idle. Otherwise, no interrupt will + * be generated and PIC remains idle. + */ + +/* + * PI_STATUS_REG: write bits + */ +#define PI_STATUS_RESET (1 << 0) +#define PI_SET_RESET PI_STATUS_RESET + +#define PI_STATUS_CLR_INTR (1 << 1) +#define PI_CLR_INTR PI_STATUS_CLR_INTR + +#define PI_DMA_BUFFER_SIZE 128 + +#define PI_DOM1_ADDR1 0x06000000 /* to 0x07FFFFFF */ +#define PI_DOM1_ADDR2 0x10000000 /* to 0x1FBFFFFF */ +#define PI_DOM1_ADDR3 0x1FD00000 /* to 0x7FFFFFFF */ +#define PI_DOM2_ADDR1 0x05000000 /* to 0x05FFFFFF */ +#define PI_DOM2_ADDR2 0x08000000 /* to 0x0FFFFFFF */ + +/** + * RDRAM Interface (RI) Registers + */ +#define RI_BASE_REG 0x04700000 + +/* RI mode (R/W): [1:0] operating mode, [2] stop T active, [3] stop R active */ +#define RI_MODE_REG (RI_BASE_REG + 0x00) + +/* RI config (R/W): [5:0] current control input, [6] current control enable */ +#define RI_CONFIG_REG (RI_BASE_REG + 0x04) + +/* RI current load (W): [] any write updates current control register */ +#define RI_CURRENT_LOAD_REG (RI_BASE_REG + 0x08) + +/* RI select (R/W): [2:0] receive select, [2:0] transmit select */ +#define RI_SELECT_REG (RI_BASE_REG + 0x0C) + +/* RI refresh (R/W): [7:0] clean refresh delay, [15:8] dirty refresh delay, + * [16] refresh bank, [17] refresh enable + * [18] refresh optimize + */ +#define RI_REFRESH_REG (RI_BASE_REG + 0x10) +#define RI_COUNT_REG RI_REFRESH_REG + +/* RI latency (R/W): [3:0] DMA latency/overlap */ +#define RI_LATENCY_REG (RI_BASE_REG + 0x14) + +/* RI error (R): [0] nack error, [1] ack error */ +#define RI_RERROR_REG (RI_BASE_REG + 0x18) + +/* RI error (W): [] any write clears all error bits */ +#define RI_WERROR_REG (RI_BASE_REG + 0x1C) + +/** + * Serial Interface (SI) Registers + */ +#define SI_BASE_REG 0x04800000 + +//! SI DRAM address (R/W): [23:0] starting RDRAM address +#define SI_DRAM_ADDR_REG (SI_BASE_REG + 0x00) + +//! SI address read 64B (W): [] write begins a 64B DMA write PIF RAM -> RDRAM +#define SI_PIF_ADDR_RD64B_REG (SI_BASE_REG + 0x04) + +//! Address SI_BASE_REG + (0x08, 0x0C, 0x14) are reserved + +//! SI address write 64B (W): [] write begins a 64B DMA read RDRAM -> PIF RAM */ +#define SI_PIF_ADDR_WR64B_REG (SI_BASE_REG + 0x10) + +//! SI status (R/W): [] any write clears interrupt +#define SI_STATUS_REG (SI_BASE_REG + 0x18) + +/* + * SI_STATUS_REG: read bits + */ +#define SI_STATUS_DMA_BUSY (1 << 0) // DMA in progress +#define SI_STATUS_RD_BUSY (1 << 1) // IO access in progress +#define SI_STATUS_DMA_ERROR (1 << 3) // Overlapping DMA requests +#define SI_STATUS_INTERRUPT (1 << 12) // Interrupt is set + +/** + * Development Board GIO Control Registers + */ + +#define GIO_BASE_REG 0x18000000 + +/* Game to Host Interrupt */ +#define GIO_GIO_INTR_REG (GIO_BASE_REG+0x000) + +/* Game to Host SYNC */ +#define GIO_GIO_SYNC_REG (GIO_BASE_REG+0x400) + +/* Host to Game Interrupt */ +#define GIO_CART_INTR_REG (GIO_BASE_REG+0x800) + +/** + * Common macros + */ +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) +#define IO_READ(addr) (*(vu32*)PHYS_TO_K1(addr)) +#define IO_WRITE(addr,data) (*(vu32*)PHYS_TO_K1(addr)=(u32)(data)) +#define RCP_STAT_PRINT \ + rmonPrintf("current=%x start=%x end=%x dpstat=%x spstat=%x\n", \ + IO_READ(DPC_CURRENT_REG), \ + IO_READ(DPC_START_REG), \ + IO_READ(DPC_END_REG), \ + IO_READ(DPC_STATUS_REG), \ + IO_READ(SP_STATUS_REG)) + +#endif + +#endif /* _RCP_H_ */ diff --git a/lib/ultralib/include/PR/rdb.h b/lib/ultralib/include/PR/rdb.h new file mode 100644 index 00000000..e0897493 --- /dev/null +++ b/lib/ultralib/include/PR/rdb.h @@ -0,0 +1,93 @@ + +/************************************************************************** + * + * $Revision: 1.6 $ + * $Date: 1997/02/11 08:29:31 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/rdb.h,v $ + * + **************************************************************************/ + +#ifndef _RDB_H +#define _RDB_H + +/* U64 side address */ +#define RDB_BASE_REG 0xc0000000 +#define RDB_WRITE_INTR_REG (RDB_BASE_REG + 0x8) +#define RDB_READ_INTR_REG (RDB_BASE_REG + 0xc) +#define RDB_BASE_VIRTUAL_ADDR 0x80000000 + +/* packet type Have six bits, so can have up to 63 types */ +#define RDB_TYPE_INVALID 0 +#define RDB_TYPE_GtoH_PRINT 1 +#define RDB_TYPE_GtoH_FAULT 2 +#define RDB_TYPE_GtoH_LOG_CT 3 +#define RDB_TYPE_GtoH_LOG 4 +#define RDB_TYPE_GtoH_READY_FOR_DATA 5 +#define RDB_TYPE_GtoH_DATA_CT 6 +#define RDB_TYPE_GtoH_DATA 7 +#define RDB_TYPE_GtoH_DEBUG 8 +#define RDB_TYPE_GtoH_RAMROM 9 +#define RDB_TYPE_GtoH_DEBUG_DONE 10 +#define RDB_TYPE_GtoH_DEBUG_READY 11 +#define RDB_TYPE_GtoH_KDEBUG 12 +#define RDB_TYPE_GtoH_PROF_DATA 22 + + +#define RDB_TYPE_HtoG_LOG_DONE 13 +#define RDB_TYPE_HtoG_DEBUG 14 +#define RDB_TYPE_HtoG_DEBUG_CT 15 +#define RDB_TYPE_HtoG_DATA 16 +#define RDB_TYPE_HtoG_DATA_DONE 17 +#define RDB_TYPE_HtoG_REQ_RAMROM 18 +#define RDB_TYPE_HtoG_FREE_RAMROM 19 +#define RDB_TYPE_HtoG_KDEBUG 20 +#define RDB_TYPE_HtoG_PROF_SIGNAL 21 + + +#define RDB_PROF_ACK_SIG 1 +#define RDB_PROF_FLUSH_SIG 2 +#define PROF_BLOCK_SIZE 2048 + +#define RDB_LOG_MAX_BLOCK_SIZE 0x8000 +#define RDB_DATA_MAX_BLOCK_SIZE 0x8000 + + +/* GIO side address */ +#define GIO_RDB_BASE_REG 0xbf480000 +#define GIO_RDB_WRITE_INTR_REG (GIO_RDB_BASE_REG + 0x8) +#define GIO_RDB_READ_INTR_REG (GIO_RDB_BASE_REG + 0xc) + +/* minor device number */ +#define GIO_RDB_PRINT_MINOR 1 +#define GIO_RDB_DEBUG_MINOR 2 + +/* interrupt bit */ +#define GIO_RDB_WRITE_INTR_BIT 0x80000000 +#define GIO_RDB_READ_INTR_BIT 0x40000000 + +/* debug command */ +#define DEBUG_COMMAND_NULL 0 +#define DEBUG_COMMAND_MEMORY 1 +#define DEBUG_COMMAND_REGISTER 2 +#define DEBUG_COMMAND_INVALID 255 + +/* debug state */ +#define DEBUG_STATE_NULL 0 +#define DEBUG_STATE_RECEIVE 1 +#define DEBUG_STATE_INVALID 255 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* Structure for debug port */ +typedef struct { + unsigned type : 6; /* 0: invalid, 1: print, 2: debug */ + unsigned length : 2; /* 1, 2, or 3 */ + char buf[3]; /* character buffer */ +} rdbPacket; + +extern unsigned int __osRdbWriteOK; +extern unsigned int __osRdbSendMessage; + +#endif /* _LANGUAGE_C */ + +#endif /* !_RDB_H */ diff --git a/lib/ultralib/include/PR/region.h b/lib/ultralib/include/PR/region.h new file mode 100755 index 00000000..0ac8a253 --- /dev/null +++ b/lib/ultralib/include/PR/region.h @@ -0,0 +1,123 @@ + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * Module: region.h + * + * $Revision: 1.8 $ + * $Date: 1997/11/26 00:30:56 $ + * $Author: mitu $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/region.h,v $ + * + * Description: + * This file contains macros and structure definitions for the region + * library. + * + **************************************************************************/ + + +#ifndef _REGION_H_ +#define _REGION_H_ + + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + + +/*************************************** + * + * Global defines + * + */ + /* Alignment sizes */ +#define ALIGNSZ (sizeof(long long)) /* 8 bytes */ +#define ALIGNOFFST (ALIGNSZ-1) + + /* size for storing index to free buffer */ +#define BUF_CTRL_SIZE ALIGNSZ + + /* Max bufcount = 32K */ +#define MAX_BUFCOUNT 0x8000 + /* code for last free buffer */ +#define BUF_FREE_WO_NEXT 0x8000 + +/* + * Global defines for alignment size (default is 8-byte alignment) + */ +#define OS_RG_ALIGN_2B 2 /* 2 bytes = 16-bit alignment */ +#define OS_RG_ALIGN_4B 4 /* 4 bytes = 32-bit alignment */ +#define OS_RG_ALIGN_8B 8 /* 8 bytes = 64-bit alignment */ +#define OS_RG_ALIGN_16B 16 /* 16 bytes = 128-bit alignment */ + +#define OS_RG_ALIGN_DEFAULT OS_RG_ALIGN_8B + + +/*************************************** + * + * Macro definitions + * + */ + +/* Perform alignment on input 's' */ +#define ALIGN(s, align) (((u32)(s) + ((align)-1)) & ~((align)-1)) + + +/*************************************** + * + * Typedefs & structure definitions + * + */ +/* + * Structure for region header/control area + */ +typedef struct _Region_s { + u8 *r_startBufferAddress; /* start address to data buffer */ + u8 *r_endAddress; /* end address of region */ + s32 r_bufferSize; /* size of buffers for this region */ + s32 r_bufferCount; /* up to 32K entries; MSB is used for + setting end-of-list/used */ + u16 r_freeList; /* point to array index of first + available memory buffer */ + u16 r_alignSize; /* alignment size (# of bytes) */ +} OSRegion; + +/* + * Macro to simplify accessing region header structure + */ +#define RP(x) rp->r_##x + + +/*************************************** + * + * Function prototypes + * + */ +extern void *osCreateRegion(void *, u32, u32, u32); +extern void *osMalloc(void *); +extern void osFree(void *, void *); +extern s32 osGetRegionBufCount(void *); +extern s32 osGetRegionBufSize(void *); + + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + + +#endif /* _REGION_H_ */ + + diff --git a/lib/ultralib/include/PR/rmon.h b/lib/ultralib/include/PR/rmon.h new file mode 100644 index 00000000..199e5699 --- /dev/null +++ b/lib/ultralib/include/PR/rmon.h @@ -0,0 +1,39 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.6 $ + * $Date: 1997/02/11 08:30:08 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/rmon.h,v $ + * + **************************************************************************/ + +#ifndef _RMON_H_ +#define _RMON_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#define RMON_DBG_BUF_SIZE 2048 +#define RMON_STACKSIZE 0x1000 + +extern void rmonMain( void * ); +extern void rmonPrintf( const char *, ... ); + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_OS_H */ diff --git a/lib/ultralib/include/PR/sched.h b/lib/ultralib/include/PR/sched.h new file mode 100644 index 00000000..2d305a2e --- /dev/null +++ b/lib/ultralib/include/PR/sched.h @@ -0,0 +1,115 @@ +/*==================================================================== + * sched.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. + *====================================================================*/ + +/************************************************************************** + * + * $Revision: 1.7 $ + * $Date: 1997/02/11 08:32:02 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/sched.h,v $ + * + **************************************************************************/ + +#ifndef __sched__ +#define __sched__ + +#include + +#define OS_SC_STACKSIZE 0x2000 + +#define OS_SC_RETRACE_MSG 1 +#define OS_SC_DONE_MSG 2 +#define OS_SC_RDP_DONE_MSG 3 +#define OS_SC_PRE_NMI_MSG 4 +#define OS_SC_LAST_MSG 4 /* this should have highest number */ +#define OS_SC_MAX_MESGS 8 + +typedef struct { + short type; + char misc[30]; +} OSScMsg; + +typedef struct OSScTask_s { + struct OSScTask_s *next; /* note: this must be first */ + u32 state; + u32 flags; + void *framebuffer; /* used by graphics tasks */ + + OSTask list; + OSMesgQueue *msgQ; + OSMesg msg; +#ifndef _FINALROM /* all #ifdef items should */ + OSTime startTime; /* remain at the end!!, or */ + OSTime totalTime; /* possible conflict if */ +#endif /* FINALROM library used with */ +} OSScTask; /* non FINALROM code */ + +/* + * OSScTask flags: + */ +#define OS_SC_NEEDS_RDP 0x0001 /* uses the RDP */ +#define OS_SC_NEEDS_RSP 0x0002 /* uses the RSP */ +#define OS_SC_DRAM_DLIST 0x0004 /* SP & DP communicate through DRAM */ +#define OS_SC_PARALLEL_TASK 0x0010 /* must be first gfx task on list */ +#define OS_SC_LAST_TASK 0x0020 /* last task in queue for frame */ +#define OS_SC_SWAPBUFFER 0x0040 /* swapbuffers when gfx task done */ + +#define OS_SC_RCP_MASK 0x0003 /* mask for needs bits */ +#define OS_SC_TYPE_MASK 0x0007 /* complete type mask */ +/* + * OSScClient: + * + * Data structure used by threads that wish to communicate to the + * scheduling thread + * + */ +typedef struct SCClient_s { + struct SCClient_s *next; /* next client in the list */ + OSMesgQueue *msgQ; /* where to send the frame msg */ +} OSScClient; + +typedef struct { + OSScMsg retraceMsg; + OSScMsg prenmiMsg; + OSMesgQueue interruptQ; + OSMesg intBuf[OS_SC_MAX_MESGS]; + OSMesgQueue cmdQ; + OSMesg cmdMsgBuf[OS_SC_MAX_MESGS]; + OSThread thread; + OSScClient *clientList; + OSScTask *audioListHead; + OSScTask *gfxListHead; + OSScTask *audioListTail; + OSScTask *gfxListTail; + OSScTask *curRSPTask; + OSScTask *curRDPTask; + u32 frameCount; + s32 doAudio; +} OSSched; + +void osCreateScheduler(OSSched *s, void *stack, OSPri priority, + u8 mode, u8 numFields); +void osScAddClient(OSSched *s, OSScClient *c, OSMesgQueue *msgQ); +void osScRemoveClient(OSSched *s, OSScClient *c); +OSMesgQueue *osScGetCmdQ(OSSched *s); + +#endif + diff --git a/lib/ultralib/include/PR/sp.h b/lib/ultralib/include/PR/sp.h new file mode 100644 index 00000000..8167ca23 --- /dev/null +++ b/lib/ultralib/include/PR/sp.h @@ -0,0 +1,196 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * Sprite library include file + * + * $Revision: 1.16 $ + * $Date: 1998/04/17 05:03:46 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/sp.h,v $ + * + **************************************************************************/ + +#ifndef _SP_H_ +#define _SP_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include +#include + +struct bitmap { + s16 width; /* Size across to draw in texels */ + /* Done if width = 0 */ + + s16 width_img; /* Size across of bitmap in texels */ + /* Done if width = 0 */ + + s16 s; /* Horizontal offset into bitmap */ + /* if (s > width), then load only! */ + + s16 t; /* Vertical offset into base */ + + void *buf; /* Pointer to bitmap data */ + /* Don't re-load if new buf */ + /* is the same as the old one */ + /* Skip if NULL */ + + s16 actualHeight; /* True Height of this bitmap piece */ + + s16 LUToffset; /* LUT base index */ +}; + +typedef struct bitmap Bitmap; + +struct sprite { + s16 x,y; /* Target position */ + + s16 width, height; /* Target size */ + + f32 scalex, scaley; /* Texel to Pixel scale factor */ + + s16 expx, expy; /* Explosion spacing */ + + u16 attr; /* Attribute Flags */ + s16 zdepth; /* Z Depth */ + + u8 red; /* Red component */ + u8 green; /* Green component */ + u8 blue; /* Blue component */ + u8 alpha; /* Alpha component */ + + s16 startTLUT; /* Lookup Table Entry Starting index */ + s16 nTLUT; /* Total number of Lookup Table Entries */ + + int *LUT; /* Pointer to Lookup Table */ + + s16 istart; /* Starting bitmap index */ + s16 istep; /* Bitmaps index step (see SP_INCY) */ + /* if 0, then variable width bitmaps */ + + s16 nbitmaps; /* Total number of bitmaps */ + s16 ndisplist; /* Total number of display-list words */ + + s16 bmheight; /* Bitmap Texel height (Used) */ + s16 bmHreal; /* Bitmap Texel height (Real) */ + u8 bmfmt; /* Bitmap Format */ + u8 bmsiz; /* Bitmap Texel Size */ + + Bitmap *bitmap; /* Pointer to first bitmap */ + + Gfx *rsp_dl; /* Pointer to RSP display list */ + + Gfx *rsp_dl_next; /* Pointer to next RSP display entry */ + + s16 frac_s, /* Fractional Texture offsets */ + frac_t; /* These have 5 fraction bits */ +}; + +typedef struct sprite Sprite; + +/* + * DANGER! + * This is bad programming. Where the *heck* do these numbers come + * from? + * + * They are obviously 'maximums' from the sprite library, but since + * the sprite library is built on top of gbi.h, which includes macros + * that decode into multiple macros, etc., it is nearly impossible to + * know what these maximums should be. + * + * Worse, there are some gbi macros (texture alignment mostly) that + * decode into *many* macros, so if we choose that as a maximum, we + * are wasting TONS of space... + * + * These numbers work for "reasonable" sprite library usage, and + * there is an assert() in the library to detect when they aren't + * enough. (use the debug version) + */ +#define DL_BM_OVERHEAD (12) +#define DL_SPRITE_OVERHEAD (24) + +#define NUM_DL(nb) ((nb)*DL_BM_OVERHEAD +DL_SPRITE_OVERHEAD) + +/* + * Misc constants + */ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * For sprite->attr + */ + +#define SP_TRANSPARENT 0x00000001 +#define SP_CUTOUT 0x00000002 +#define SP_HIDDEN 0x00000004 +#define SP_Z 0x00000008 +#define SP_SCALE 0x00000010 +#define SP_FASTCOPY 0x00000020 +#define SP_OVERLAP 0x00000040 +#define SP_TEXSHIFT 0x00000080 +#define SP_FRACPOS 0x00000100 +#define SP_TEXSHUF 0x00000200 +#define SP_EXTERN 0x00000400 + +/* + * Function wrapper + */ +#if defined(F3DEX_GBI_2) +#define spMove spX2Move +#define spSetZ spX2SetZ +#define spScissor spX2Scissor +#define spDraw spX2Draw +#define spInit spX2Init +#define spFinish spX2Finish +#elif defined(F3DEX_GBI) +#define spMove spXMove +#define spSetZ spXSetZ +#define spScissor spXScissor +#define spDraw spXDraw +#define spInit spXInit +#define spFinish spXFinish +#endif + +/* + * Function prototypes + */ + +void spSetAttribute (Sprite *sp, s32 attr); +void spClearAttribute (Sprite *sp, s32 attr); +void spMove (Sprite *sp, s32 x, s32 y); +void spScale (Sprite *sp, f32 sx, f32 sy); +void spSetZ (Sprite *sp, s32 z ); +void spColor (Sprite *sp, u8 red, u8 green, u8 blue, u8 alpha); +Gfx *spDraw (Sprite *sp); +void spInit( Gfx **glistp ); +void spScissor( s32 xmin, s32 xmax, s32 ymin, s32 ymax ); +void spFinish( Gfx **glistp ); + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* _SP_H_ */ diff --git a/lib/ultralib/include/PR/sptask.h b/lib/ultralib/include/PR/sptask.h new file mode 100644 index 00000000..960cab9b --- /dev/null +++ b/lib/ultralib/include/PR/sptask.h @@ -0,0 +1,201 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.9 $ + * $Date: 1998/03/05 06:40:29 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/sptask.h,v $ + * + **************************************************************************/ + +#ifndef _SPTASK_H_ +#define _SPTASK_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Type definitions + * + */ + +/* + * Task List Structure. + * + * Things an app might pass to the SP via the task list. + * Not every task ucode would need/use every field, but + * + * - type (audio, gfx, video, ...) + * - flags + * - wait for DP to drain before running new task + * - SEE BIT DEFINITIONS UNDER "Task Flags field" + * - pointer to boot ucode + * - size of boot ucode + * - pointer to ucode + * - size of ucode + * - pointer to initial DMEM data + * - size of initial DMEM data + * - pointer to DRAM stack + * - size of DRAM stack (max) + * - pointer to output buffer + * - pointer to store output buffer length + * - generic data pointer (for display list, etc.) + * - generic data length (for display list, etc.) + * - pointer to buffer where to store saved DMEM (in yield case) + * - size of buffer to store saved DMEM. + * + * IMPORTANT!!! Watch alignment issues. + * + * IMPORTANT!!! Watch data cache issues. The RCP may write data into the + * dram_stack, output_buff, output_buff_size, and the yield_data_ptr areas. + * These buffers should be cache aligned and use the entire line (16 bytes) to + * avoid corruption by writebacks by the CPU (cache tearing). + * + * IMPORTANT!!! all addresses are virtual addresses. Library does + * any necessary translation. + * + */ +typedef struct { + u32 type; + u32 flags; + + u64 *ucode_boot; + u32 ucode_boot_size; + + u64 *ucode; + u32 ucode_size; + + u64 *ucode_data; + u32 ucode_data_size; + + u64 *dram_stack; + u32 dram_stack_size; + + u64 *output_buff; + u64 *output_buff_size; + + u64 *data_ptr; + u32 data_size; + + u64 *yield_data_ptr; + u32 yield_data_size; + +} OSTask_t; + +typedef union { + OSTask_t t; + long long int force_structure_alignment; +} OSTask; + +typedef u32 OSYieldResult; + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_ASSEMBLY + +/* + * For the RSP ucode: + * offsets into the task structure + */ + +#include + +#endif + +/* + * Task Flags field + */ +#define OS_TASK_YIELDED 0x0001 +#define OS_TASK_DP_WAIT 0x0002 +#define OS_TASK_LOADABLE 0x0004 +#define OS_TASK_SP_ONLY 0x0008 +#define OS_TASK_USR0 0x0010 +#define OS_TASK_USR1 0x0020 +#define OS_TASK_USR2 0x0040 +#define OS_TASK_USR3 0x0080 + +/* + * Size of Yield buffer. The taskHdrPtr->t.yield_data_ptr must point to a + * buffer of this size. (The size is in bytes). ONLY If the task will NEVER + * yield it may be a null pointer. The buffer must be aligned to a 64 bit + * boundary. The taskHdrPtr->t.yield_data_ptr must be set to point to the + * buffer BEFORE the task is started. + */ +#if (defined(F3DEX_GBI)||defined(F3DLP_GBI)||defined(F3DEX_GBI_2)) +#define OS_YIELD_DATA_SIZE 0xc00 +#else +#define OS_YIELD_DATA_SIZE 0x900 +#endif +#define OS_YIELD_AUDIO_SIZE 0x400 + +/************************************************************************** + * + * Global definitions + * + */ + + + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + +/* + * this macro simulates atomic action. + */ +#define osSpTaskStart(tp) \ + { \ + osSpTaskLoad((tp)); \ + osSpTaskStartGo((tp)); \ + } + + +/************************************************************************** + * + * Extern variables + * + */ + + +/************************************************************************** + * + * Function prototypes + * + */ + +/* + * break this up into two steps for debugging. + */ +extern void osSpTaskLoad(OSTask *tp); +extern void osSpTaskStartGo(OSTask *tp); + +extern void osSpTaskYield(void); +extern OSYieldResult osSpTaskYielded(OSTask *tp); + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_SPTASK_H */ diff --git a/lib/ultralib/include/PR/ucode.h b/lib/ultralib/include/PR/ucode.h new file mode 100644 index 00000000..e43f52ae --- /dev/null +++ b/lib/ultralib/include/PR/ucode.h @@ -0,0 +1,192 @@ +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.15 $ + * $Date: 1998/03/31 07:58:57 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/ucode.h,v $ + * + **************************************************************************/ + +#ifndef _UCODE_H_ +#define _UCODE_H_ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/************************************************************************** + * + * Macro definitions + * + */ + +/* + * This is the recommended size of the SP DRAM stack area, used + * by the graphics ucode. This stack is used primarily for the + * matrix stack, so it needs to be AT LEAST (10 * 64bytes) in size. + */ +#define SP_DRAM_STACK_SIZE8 (1024) +#define SP_DRAM_STACK_SIZE64 (SP_DRAM_STACK_SIZE8 >> 3) + +/* + * This is the size of the IMEM, which is also the size of the + * graphics microcode. (other ucode might be less) + * This value is used in apps to tell the OS how much ucode to + * load. + */ +#define SP_UCODE_SIZE 4096 + +/* + * This is 1/2 the size of DMEM, which is the maximum amount of + * initialized DMEM data any of the ucode tasks need to start up. + * This value is dependent on all of the task ucodes, and is therefore + * fixed per release. + */ +#define SP_UCODE_DATA_SIZE 2048 + + +/************************************************************************** + * + * Extern variables + * + */ + +/* + * Symbols generated by "rsp2elf", included by "makerom" that indicate + * the location and size of the SP microcode objects. The ucode objects + * are loaded as part of the codesegment (arbitrary, could do other + * ways) + * + */ + +/* standard boot ucode: */ +extern long long int rspbootTextStart[], rspbootTextEnd[]; + +/* standard 3D ucode: */ +extern long long int gspFast3DTextStart[], gspFast3DTextEnd[]; +extern long long int gspFast3DDataStart[], gspFast3DDataEnd[]; + +/* 3D ucode with output to DRAM: */ +extern long long int gspFast3D_dramTextStart[], gspFast3D_dramTextEnd[]; +extern long long int gspFast3D_dramDataStart[], gspFast3D_dramDataEnd[]; + +/* 3D ucode with output through DRAM FIFO to RDP: */ +extern long long int gspFast3D_fifoTextStart[], gspFast3D_fifoTextEnd[]; +extern long long int gspFast3D_fifoDataStart[], gspFast3D_fifoDataEnd[]; + +/* 3D ucode without nearclip: */ +extern long long int gspF3DNoNTextStart[], gspF3DNoNTextEnd[]; +extern long long int gspF3DNoNDataStart[], gspF3DNoNDataEnd[]; + +/* 3D ucode without nearclip with output to DRAM: */ +extern long long int gspF3DNoN_dramTextStart[]; +extern long long int gspF3DNoN_dramTextEnd[]; +extern long long int gspF3DNoN_dramDataStart[]; +extern long long int gspF3DNoN_dramDataEnd[]; + +/* 3D ucode without nearclip with output through DRAM FIFO to RDP: */ +extern long long int gspF3DNoN_fifoTextStart[]; +extern long long int gspF3DNoN_fifoTextEnd[]; +extern long long int gspF3DNoN_fifoDataStart[]; +extern long long int gspF3DNoN_fifoDataEnd[]; + +/* 3D line ucode: */ +extern long long int gspLine3DTextStart[], gspLine3DTextEnd[]; +extern long long int gspLine3DDataStart[], gspLine3DDataEnd[]; + +/* 3D line ucode with output to DRAM: */ +extern long long int gspLine3D_dramTextStart[], gspLine3D_dramTextEnd[]; +extern long long int gspLine3D_dramDataStart[], gspLine3D_dramDataEnd[]; + +/* 3D line ucode with output through DRAM FIFO to RDP: */ +extern long long int gspLine3D_fifoTextStart[], gspLine3D_fifoTextEnd[]; +extern long long int gspLine3D_fifoDataStart[], gspLine3D_fifoDataEnd[]; + +/* 2D sprite ucode: */ +extern long long int gspSprite2DTextStart[], gspSprite2DTextEnd[]; +extern long long int gspSprite2DDataStart[], gspSprite2DDataEnd[]; + +/* 2D sprite ucode with output to DRAM: */ +extern long long int gspSprite2D_dramTextStart[], gspSprite2D_dramTextEnd[]; +extern long long int gspSprite2D_dramDataStart[], gspSprite2D_dramDataEnd[]; + +/* 2D sprite ucode with output through DRAM FIFO to RDP: */ +extern long long int gspSprite2D_fifoTextStart[], gspSprite2D_fifoTextEnd[]; +extern long long int gspSprite2D_fifoDataStart[], gspSprite2D_fifoDataEnd[]; + +/* basic audio ucode: */ +extern long long int aspMainTextStart[], aspMainTextEnd[]; +extern long long int aspMainDataStart[], aspMainDataEnd[]; + +/*========== F3DEX/F3DLX/F3DLP/L3DEX ==========*/ +/* FIFO version only */ +extern long long int gspF3DEX_fifoTextStart[], gspF3DEX_fifoTextEnd[]; +extern long long int gspF3DEX_fifoDataStart[], gspF3DEX_fifoDataEnd[]; +extern long long int gspF3DEX_NoN_fifoTextStart[], gspF3DEX_NoN_fifoTextEnd[]; +extern long long int gspF3DEX_NoN_fifoDataStart[], gspF3DEX_NoN_fifoDataEnd[]; + +extern long long int gspF3DLX_fifoTextStart[], gspF3DLX_fifoTextEnd[]; +extern long long int gspF3DLX_fifoDataStart[], gspF3DLX_fifoDataEnd[]; +extern long long int gspF3DLX_NoN_fifoTextStart[], gspF3DLX_NoN_fifoTextEnd[]; +extern long long int gspF3DLX_NoN_fifoDataStart[], gspF3DLX_NoN_fifoDataEnd[]; +extern long long int gspF3DLX_Rej_fifoTextStart[], gspF3DLX_Rej_fifoTextEnd[]; +extern long long int gspF3DLX_Rej_fifoDataStart[], gspF3DLX_Rej_fifoDataEnd[]; + +extern long long int gspF3DLP_Rej_fifoTextStart[], gspF3DLP_Rej_fifoTextEnd[]; +extern long long int gspF3DLP_Rej_fifoDataStart[], gspF3DLP_Rej_fifoDataEnd[]; +extern long long int gspL3DEX_fifoTextStart[], gspL3DEX_fifoTextEnd[]; +extern long long int gspL3DEX_fifoDataStart[], gspL3DEX_fifoDataEnd[]; + +/*========== F3DEX2/F3DLX2/F3DLP2/L3DEX2 ==========*/ +/* FIFO version */ +extern long long int gspF3DEX2_fifoTextStart[], gspF3DEX2_fifoTextEnd[]; +extern long long int gspF3DEX2_fifoDataStart[], gspF3DEX2_fifoDataEnd[]; +extern long long int gspF3DEX2_NoN_fifoTextStart[],gspF3DEX2_NoN_fifoTextEnd[]; +extern long long int gspF3DEX2_NoN_fifoDataStart[],gspF3DEX2_NoN_fifoDataEnd[]; +extern long long int gspF3DEX2_Rej_fifoTextStart[],gspF3DEX2_Rej_fifoTextEnd[]; +extern long long int gspF3DEX2_Rej_fifoDataStart[],gspF3DEX2_Rej_fifoDataEnd[]; +extern long long int gspF3DLX2_Rej_fifoTextStart[],gspF3DLX2_Rej_fifoTextEnd[]; +extern long long int gspF3DLX2_Rej_fifoDataStart[],gspF3DLX2_Rej_fifoDataEnd[]; +extern long long int gspL3DEX2_fifoTextStart[], gspL3DEX2_fifoTextEnd[]; +extern long long int gspL3DEX2_fifoDataStart[], gspL3DEX2_fifoDataEnd[]; + +/* XBUS version */ +extern long long int gspF3DEX2_xbusTextStart[], gspF3DEX2_xbusTextEnd[]; +extern long long int gspF3DEX2_xbusDataStart[], gspF3DEX2_xbusDataEnd[]; +extern long long int gspF3DEX2_NoN_xbusTextStart[],gspF3DEX2_NoN_xbusTextEnd[]; +extern long long int gspF3DEX2_NoN_xbusDataStart[],gspF3DEX2_NoN_xbusDataEnd[]; +extern long long int gspF3DEX2_Rej_xbusTextStart[],gspF3DEX2_Rej_xbusTextEnd[]; +extern long long int gspF3DEX2_Rej_xbusDataStart[],gspF3DEX2_Rej_xbusDataEnd[]; +extern long long int gspF3DLX2_Rej_xbusTextStart[],gspF3DLX2_Rej_xbusTextEnd[]; +extern long long int gspF3DLX2_Rej_xbusDataStart[],gspF3DLX2_Rej_xbusDataEnd[]; +extern long long int gspL3DEX2_xbusTextStart[], gspL3DEX2_xbusTextEnd[]; +extern long long int gspL3DEX2_xbusDataStart[], gspL3DEX2_xbusDataEnd[]; + +/************************************************************************** + * + * Function prototypes + * + */ + +#endif /* _LANGUAGE_C */ + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* !_UCODE_H */ diff --git a/lib/ultralib/include/PR/ultraerror.h b/lib/ultralib/include/PR/ultraerror.h new file mode 100644 index 00000000..ebaf59aa --- /dev/null +++ b/lib/ultralib/include/PR/ultraerror.h @@ -0,0 +1,165 @@ +/*==================================================================== + * ultraerror.h + * + * 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. + *====================================================================*/ + +/************************************************************************** + * + * $Revision: 1.27 $ + * $Date: 1999/07/14 02:44:00 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/ultraerror.h,v $ + * + **************************************************************************/ + +#ifndef __ULTRAERROR_H__ +#define __ULTRAERROR_H__ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include "ultratypes.h" + +#define OS_ERROR_FMT "/usr/lib/PR/error.fmt" +#define OS_ERROR_MAGIC 0x6b617479 + +/* OS error codes */ + +#define ERR_OSCREATETHREAD_SP 1 +#define ERR_OSCREATETHREAD_PRI 2 +#define ERR_OSSTARTTHREAD 3 +#define ERR_OSSETTHREADPRI 4 +#define ERR_OSCREATEMESGQUEUE 5 +#define ERR_OSSENDMESG 6 +#define ERR_OSJAMMESG 7 +#define ERR_OSRECVMESG 8 +#define ERR_OSSETEVENTMESG 9 +#define ERR_OSMAPTLB_INDEX 10 +#define ERR_OSMAPTLB_ASID 11 +#define ERR_OSUNMAPTLB 12 +#define ERR_OSSETTLBASID 13 +#define ERR_OSAISETFREQUENCY 14 +#define ERR_OSAISETNEXTBUFFER_ADDR 15 +#define ERR_OSAISETNEXTBUFFER_SIZE 16 +#define ERR_OSDPSETNEXTBUFFER_ADDR 17 +#define ERR_OSDPSETNEXTBUFFER_SIZE 18 +#define ERR_OSPIRAWREADIO 19 +#define ERR_OSPIRAWWRITEIO 20 +#define ERR_OSPIRAWSTARTDMA_DIR 21 +#define ERR_OSPIRAWSTARTDMA_DEVADDR 22 +#define ERR_OSPIRAWSTARTDMA_ADDR 23 +#define ERR_OSPIRAWSTARTDMA_SIZE 24 +#define ERR_OSPIRAWSTARTDMA_RANGE 25 +#define ERR_OSPIREADIO 26 +#define ERR_OSPIWRITEIO 27 +#define ERR_OSPISTARTDMA_PIMGR 28 +#define ERR_OSPISTARTDMA_PRI 29 +#define ERR_OSPISTARTDMA_DIR 30 +#define ERR_OSPISTARTDMA_DEVADDR 31 +#define ERR_OSPISTARTDMA_ADDR 32 +#define ERR_OSPISTARTDMA_SIZE 33 +#define ERR_OSPISTARTDMA_RANGE 34 +#define ERR_OSCREATEPIMANAGER 35 +#define ERR_OSVIGETCURRENTMODE 36 +#define ERR_OSVIGETCURRENTFRAMEBUFFER 37 +#define ERR_OSVIGETNEXTFRAMEBUFFER 38 +#define ERR_OSVISETXSCALE_VALUE 39 +#define ERR_OSVISETXSCALE_VIMGR 40 +#define ERR_OSVISETYSCALE_VALUE 41 +#define ERR_OSVISETYSCALE_VIMGR 42 +#define ERR_OSVISETSPECIAL_VALUE 43 +#define ERR_OSVISETSPECIAL_VIMGR 44 +#define ERR_OSVISETMODE 45 +#define ERR_OSVISETEVENT 46 +#define ERR_OSVISWAPBUFFER_ADDR 47 +#define ERR_OSVISWAPBUFFER_VIMGR 48 +#define ERR_OSCREATEVIMANAGER 49 +#define ERR_OSCREATEREGION_ALIGN 50 +#define ERR_OSCREATEREGION_SIZE 51 +#define ERR_OSMALLOC 52 +#define ERR_OSFREE_REGION 53 +#define ERR_OSFREE_ADDR 54 +#define ERR_OSGETREGIONBUFCOUNT 55 +#define ERR_OSGETREGIONBUFSIZE 56 +#define ERR_OSSPTASKLOAD_DRAM 57 +#define ERR_OSSPTASKLOAD_OUT 58 +#define ERR_OSSPTASKLOAD_OUTSIZE 59 +#define ERR_OSSPTASKLOAD_YIELD 60 +#define ERR_OSPROFILEINIT_STR 61 +#define ERR_OSPROFILEINIT_CNT 62 +#define ERR_OSPROFILEINIT_ALN 63 +#define ERR_OSPROFILEINIT_ORD 64 +#define ERR_OSPROFILEINIT_SIZ 65 +#define ERR_OSPROFILESTART_TIME 66 +#define ERR_OSPROFILESTART_FLAG 67 +#define ERR_OSPROFILESTOP_FLAG 68 +#define ERR_OSPROFILESTOP_TIMER 69 +#define ERR_OSREADHOST_ADDR 70 +#define ERR_OSREADHOST_SIZE 71 +#define ERR_OSWRITEHOST_ADDR 72 +#define ERR_OSWRITEHOST_SIZE 73 +#define ERR_OSGETTIME 74 +#define ERR_OSSETTIME 75 +#define ERR_OSSETTIMER 76 +#define ERR_OSSTOPTIMER 77 +#define ERR_ALSEQP_NO_SOUND 100 +#define ERR_ALSEQP_NO_VOICE 101 +#define ERR_ALSEQP_MAP_VOICE 102 +#define ERR_ALSEQP_OFF_VOICE 103 +#define ERR_ALSEQP_POLY_VOICE 104 +#define ERR_ALSNDP_NO_VOICE 105 +#define ERR_ALSYN_NO_UPDATE 106 +#define ERR_ALSNDPDEALLOCATE 107 +#define ERR_ALSNDPDELETE 108 +#define ERR_ALSNDPPLAY 109 +#define ERR_ALSNDPSETSOUND 110 +#define ERR_ALSNDPSETPRIORITY 111 +#define ERR_ALSNDPSETPAR 112 +#define ERR_ALBNKFNEW 113 +#define ERR_ALSEQNOTMIDI 114 +#define ERR_ALSEQNOTMIDI0 115 +#define ERR_ALSEQNUMTRACKS 116 +#define ERR_ALSEQTIME 117 +#define ERR_ALSEQTRACKHDR 118 +#define ERR_ALSEQSYSEX 119 +#define ERR_ALSEQMETA 120 +#define ERR_ALSEQPINVALIDPROG 121 +#define ERR_ALSEQPUNKNOWNMIDI 122 +#define ERR_ALSEQPUNMAP 123 +#define ERR_ALEVENTNOFREE 124 +#define ERR_ALHEAPNOFREE 125 +#define ERR_ALHEAPCORRUPT 126 +#define ERR_ALHEAPFIRSTBLOCK 127 +#define ERR_ALCSEQZEROSTATUS 128 +#define ERR_ALCSEQZEROVEL 129 +#define ERR_ALCSPVNOTFREE 130 +#define ERR_ALSEQOVERRUN 131 +#define ERR_OSAISETNEXTBUFFER_ENDADDR 132 +#define ERR_ALMODDELAYOVERFLOW 133 + +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) +typedef void (*OSErrorHandler)(s16, s16, ...); + +OSErrorHandler osSetErrorHandler(OSErrorHandler); +#endif + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif /* __ULTRAERROR_H__ */ diff --git a/lib/ultralib/include/PR/ultralog.h b/lib/ultralib/include/PR/ultralog.h new file mode 100644 index 00000000..48b84b97 --- /dev/null +++ b/lib/ultralib/include/PR/ultralog.h @@ -0,0 +1,74 @@ +/*==================================================================== + * ultralog.h + * + * 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. + *====================================================================*/ + +/************************************************************************** + * + * $Revision: 1.6 $ + * $Date: 1997/02/11 08:39:05 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/ultralog.h,v $ + * + **************************************************************************/ + +#ifndef __log__ +#define __log__ + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +#include + +#define OS_LOG_MAX_ARGS 16 +#define OS_LOG_MAGIC 0x20736a73 +#define OS_LOG_FLOAT(x) (*(int *) &(x)) +#define OS_LOG_VERSION 1 + +typedef struct { + u32 magic; /* log identifier */ + u32 len; /* length of log data + log structure */ + u32 *base; /* starting addr array */ + s32 startCount; /* read offset from dataBase */ + s32 writeOffset; /* write offset from dataBase */ +} OSLog; + +typedef struct { + u32 magic; + u32 timeStamp; + u16 argCount; + u16 eventID; +} OSLogItem; + +typedef struct { + u32 magic; /* log identifier */ + u32 version; /* 1 */ +} OSLogFileHdr; + +void osCreateLog(OSLog *log, u32 *base, s32 len); +void osLogEvent(OSLog *log, s16 code, s16 numArgs, ...); +void osFlushLog(OSLog *log); +u32 osLogFloat(f32); + +extern void osDelay(int count); + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif + +#endif diff --git a/lib/ultralib/include/PR/ultratypes.h b/lib/ultralib/include/PR/ultratypes.h new file mode 100644 index 00000000..235cc739 --- /dev/null +++ b/lib/ultralib/include/PR/ultratypes.h @@ -0,0 +1,85 @@ +#ifndef _ULTRATYPES_H_ +#define _ULTRATYPES_H_ + + +/************************************************************************** + * * + * 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. * + * * + **************************************************************************/ + + +/************************************************************************* + * + * File: ultratypes.h + * + * This file contains various types used in Ultra64 interfaces. + * + * $Revision: 1.6 $ + * $Date: 1997/12/17 04:02:06 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/ultratypes.h,v $ + * + **************************************************************************/ + + + +/********************************************************************** + * General data types for R4300 + */ +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +typedef unsigned char u8; /* unsigned 8-bit */ +typedef unsigned short u16; /* unsigned 16-bit */ +typedef unsigned long u32; /* unsigned 32-bit */ +typedef unsigned long long u64; /* unsigned 64-bit */ + +typedef signed char s8; /* signed 8-bit */ +typedef short s16; /* signed 16-bit */ +typedef long s32; /* signed 32-bit */ +typedef long long s64; /* signed 64-bit */ + +typedef volatile unsigned char vu8; /* unsigned 8-bit */ +typedef volatile unsigned short vu16; /* unsigned 16-bit */ +typedef volatile unsigned long vu32; /* unsigned 32-bit */ +typedef volatile unsigned long long vu64; /* unsigned 64-bit */ + +typedef volatile signed char vs8; /* signed 8-bit */ +typedef volatile short vs16; /* signed 16-bit */ +typedef volatile long vs32; /* signed 32-bit */ +typedef volatile long long vs64; /* signed 64-bit */ + +typedef float f32; /* single prec floating point */ +typedef double f64; /* double prec floating point */ + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEF) +#define _SIZE_T +#define _SIZE_T_DEF /* exeGCC size_t define label */ +#if (_MIPS_SZLONG == 32) +typedef unsigned int size_t; +#endif +#if (_MIPS_SZLONG == 64) +typedef unsigned long size_t; +#endif +#endif + +#endif /* _LANGUAGE_C */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif /* _ULTRATYPES_H_ */ diff --git a/lib/ultralib/include/assert.h b/lib/ultralib/include/assert.h new file mode 100644 index 00000000..7f1989ad --- /dev/null +++ b/lib/ultralib/include/assert.h @@ -0,0 +1,12 @@ +#ifndef __ASSERT_H__ +#define __ASSERT_H__ + +#ifdef NDEBUG +#undef assert +#define assert(EX) ((void)0) +#else +extern void __assert(const char *, const char *, int); +#define assert(EX) ((EX)?((void)0):__assert( # EX , __FILE__, __LINE__)) +#endif /* NDEBUG */ + +#endif /* !__ASSERT_H__ */ diff --git a/lib/ultralib/include/dbgdefs.h b/lib/ultralib/include/dbgdefs.h new file mode 100644 index 00000000..f7ead714 --- /dev/null +++ b/lib/ultralib/include/dbgdefs.h @@ -0,0 +1,8 @@ +#ifndef _DBGDEFS_H__ +#define _DBGDEFS_H__ + +typedef int TVid; +typedef unsigned short TVushort; +typedef char TVuchar; + +#endif diff --git a/lib/ultralib/include/dbgproto.h b/lib/ultralib/include/dbgproto.h new file mode 100644 index 00000000..2eabf9a8 --- /dev/null +++ b/lib/ultralib/include/dbgproto.h @@ -0,0 +1,402 @@ +#ifndef _DBGPROTO_H__ +#define _DBGPROTO_H__ + +#include "dbgdefs.h" + +#define KK_REV 2 + +#define KK_CODE_THREAD_STATUS 4 + +#define KK_TYPE_REQUEST 0 +#define KK_TYPE_REPLY 1 +#define KK_TYPE_EXCEPTION 2 +#define KK_TYPE_THREAD_EXIT 3 +#define KK_TYPE_PROCESS_EXIT 4 +#define KK_TYPE_CONSOLE 5 + +#define TV_ERROR_NO_ERROR 0 +#define TV_ERROR_ILLEGAL_CALL -1 +#define TV_ERROR_INVALID_ID -2 +#define TV_ERROR_INVALID_TYPE -3 +#define TV_ERROR_OPERATIONS_PROTECTED -4 +#define TV_ERROR_INVALID_ADDRESS -5 +#define TV_ERROR_INVALID_PRIORITY -6 +#define TV_ERROR_INVALID_FLAGS -7 +#define TV_ERROR_INVALID_CAPABILITY -8 +#define TV_ERROR_NO_HANDLER -9 +#define TV_ERROR_NO_MORE_IDS -10 +#define TV_ERROR_NO_MORE_MESSAGES -11 +#define TV_ERROR_NO_MORE_PROCESSES -12 +#define TV_ERROR_NO_MORE_THREADS -13 +#define TV_ERROR_NO_MORE_REGIONS -14 +#define TV_ERROR_NO_MORE_TIMERS -15 +#define TV_ERROR_NO_MORE_LOCKS -16 +#define TV_ERROR_NO_MORE_QUEUES -17 +#define TV_ERROR_NO_MORE_SETS -18 +#define TV_ERROR_NO_MORE_MEMORY -19 +#define TV_ERROR_NOT_LOCKED -20 + +typedef struct __KKTimeStruct { + long seconds; + long nanoseconds; +} KKTimeStruct; + +typedef struct __KKObjsStruct { + TVushort number; + TVid objects[1]; +} KKObjs; + +typedef struct __KKFaultInfoStruct { + unsigned int addr; + short major; + short minor; +} KKFaultInfo; + +typedef struct __KKThreadStatusStruct { + int flags; + short why; + short what; + TVid tid; + TVid pid; + unsigned int instr; + KKFaultInfo info; + int priority; + int start; + int rv; + unsigned int args[6]; +} KKThreadStatus; + +#define KK_RUN_SSTEP (1 << 0) +#define KK_RUN_SETPC (1 << 1) + +typedef struct __KKRunStruct { + int flags; + unsigned int vaddr; +} KKRun; + +typedef struct __KKFaultStruct { + short majorMask; + short minorMask; +} KKFault; + +typedef struct __KKRegionStruct { + unsigned int vaddr; + unsigned int size; + short flags; + unsigned int paddr; +} KKRegion; + +typedef struct __KKGregSetStruct { + unsigned int gregs[37]; +} KKGregSet; + +typedef struct __KKFPregSetStruct { + union { + double dregs[16]; + float fregs[32]; + unsigned int regs[32]; + } fpregs; + unsigned int fpcsr; + unsigned int fppad; +} KKFPregSet; + +typedef struct __KKRegisterContextStruct { + KKGregSet gregs; + KKFPregSet fpregs; +} KKRegisterContext; + +typedef struct __KKCpScalarSetStruct { + unsigned int sregs[40]; +} KKCpScalarRegSet; + +typedef struct __KKCpVectorSetStruct { + unsigned int vregs[128]; +} KKCpVectorRegSet; + +typedef struct __KKCpRegisterContextStruct { + KKCpScalarRegSet sregs; + KKCpVectorRegSet vregs; +} KKCpRegisterContext; + +typedef struct __KKUsageStruct { + KKTimeStruct tstamp; + KKTimeStruct created; + KKTimeStruct states[10]; +} KKUsage; + +typedef struct __KKLogEventSetStruct { + int from; + int to; +} KKLogEventSet; + +typedef struct __KKLogStatusStruct { + int bufferType; + int bufferSize; + int dataSize; + int logState; + int flushLimit; +} KKLogStatus; + +typedef struct __KKProcUsageStruct { + TVid pid; + KKTimeStruct states[10]; +} KKProcUsage; + +typedef struct __KKHeaderStruct { + int length; + char code; + char type; + short error; + char rev; + char method; + short notused2; +} KKHeader; + +typedef struct __KKGetFrameRequestStruct { + KKHeader header; + int height; + int width; + int which; +} KKGetFrameRequest; + +typedef struct __KKLoadExecutableRequestStruct { + KKHeader header; + char str[1]; +} KKLoadExecutableRequest; + +typedef struct __KKObjectRequestStruct { + KKHeader header; + TVid object; +} KKObjectRequest; + +typedef struct __KKRunThreadRequestStruct { + KKHeader header; + TVid tid; + KKRun actions; +} KKRunThreadRequest; + +typedef struct __KKFaultRequestStruct { + KKHeader header; + TVid tid; + KKFault fault; + TVuchar stopAllThreads; +} KKFaultRequest; + +typedef struct __KKGRegsetRequestStruct { + KKHeader header; + TVid tid; + KKGregSet registers; +} KKGRegsetRequest; + +typedef struct __KKFPRegsetRequestStruct { + KKHeader header; + TVid tid; + KKFPregSet registers; +} KKFPRegsetRequest; + +typedef struct __KKCpScalarRegsetRequestStruct { + KKHeader header; + TVid tid; + KKCpScalarRegSet registers; +} KKCpScalarRegsetRequest; + +typedef struct __KKCpVectorRegsetRequestStruct { + KKHeader header; + TVid tid; + KKCpVectorRegSet registers; +} KKCpVectorRegsetRequest; + +typedef struct __KKReadRequestStruct { + KKHeader header; + TVid object; + unsigned int addr; + unsigned int nbytes; +} KKReadRequest; + +typedef struct __KKWriteHeaderStruct { + KKHeader header; + TVid object; + unsigned int addr; + unsigned int nbytes; +} KKWriteHeader; + +typedef struct __KKWriteRequestStruct { + KKWriteHeader writeHeader; + char buffer[1]; +} KKWriteRequest; + +typedef struct __KKSetBkptRequestStruct { + KKHeader header; + TVid object; + unsigned int addr; +} KKSetBkptRequest; + +typedef struct __KKClrBkptRequestStruct { + KKHeader header; + TVid object; + TVid bp; +} KKClrBkptRequest; + +typedef struct __KKWatchRequestStruct { + KKHeader header; + TVid object; + unsigned int number; + KKRegion wp[1]; +} KKWatchRequest; + +typedef struct __KKSetCommRequestStruct { + KKHeader header; + unsigned int how; + unsigned int addr; +} KKSetCommRequest; + +typedef struct __KKSysCallSetStruct { + unsigned int word[8]; +} KKSysCallSet; + +typedef struct __KKSysCallRequestStruct { + KKHeader header; + TVid pid; + KKSysCallSet syscallset; +} KKSysCallRequest; + +typedef struct __KKLogEventRequestStruct { + KKHeader header; + unsigned int numSet; + KKLogEventSet set[1]; +} KKLogEventRequest; + +typedef struct __KKNewLogRequestStruct { + KKHeader header; + char str[1]; +} KKNewLogRequest; + +typedef struct __KKRemoteRequestStruct { + KKHeader header; + int len; + char buf[16]; +} KKRemoteRequest; + +typedef struct __KKFlushLogRequestStruct { + KKHeader header; + int no_block; +} KKFlushLogRequest; + +typedef struct __KKLogControlRequestStruct { + KKHeader header; + int command; + int arg; +} KKLogControlRequest; + +typedef struct __KKSetTrptRequestStruct { + KKSetBkptRequest bpRequest; + unsigned short code; +} KKSetTrptRequest; + +typedef KKClrBkptRequest KKClrTrptRequest; + +typedef struct __KKObjectEventStruct { + KKHeader header; + TVid object; +} KKObjectEvent; + +typedef struct __KKObjsEventStruct { + KKHeader header; + TVid object; + KKObjs objs; +} KKObjsEvent; + +typedef struct __KKBufferEventStruct { + KKHeader header; + TVid object; + char buffer[1]; +} KKBufferEvent; + +typedef struct __KKStatusEventStruct { + KKHeader header; + KKThreadStatus status; +} KKStatusEvent; + +typedef struct __KKFaultEventStruct { + KKHeader header; + TVid tid; + KKFault fault; + TVuchar stopAllThreads; +} KKFaultEvent; + +typedef struct __KKNumberEventStruct { + KKHeader header; + TVid object; + unsigned int number; +} KKNumberEvent; + +typedef struct __KKRegionEventStruct { + KKHeader header; + TVid object; + unsigned int number; + KKRegion regions[1]; +} KKRegionEvent; + +typedef struct __KKGregEventStruct { + KKHeader header; + TVid tid; + KKGregSet registers; +} KKGregEvent; + +typedef struct __KKFPregEventStruct { + KKHeader header; + TVid tid; + KKFPregSet registers; +} KKFPregEvent; + +typedef struct __KKCpSregEventStruct { + KKHeader header; + TVid tid; + KKCpScalarRegSet registers; +} KKCpSregEvent; + +typedef struct __KKCpVregEventStruct { + KKHeader header; + TVid tid; + KKCpVectorRegSet registers; +} KKCpVregEvent; + +typedef struct __KKBkptEventStruct { + KKHeader header; + TVid object; + TVid bp; + unsigned int instruction; +} KKBkptEvent; + +typedef struct __KKUsageEventStruct { + KKHeader header; + TVid tid; + KKUsage usage; +} KKUsageEvent; + +typedef struct __KKFlushEventStruct { + KKHeader header; + int bufferType; + char buffer[1]; +} KKFlushEvent; + +typedef struct __KKLogStatusEventStruct { + KKHeader header; + KKLogStatus status; +} KKLogStatusEvent; + +typedef struct __KKSysUsageEventStruct { + KKHeader header; + KKTimeStruct tstamp; + int numProc; + KKProcUsage usage[1]; +} KKSysUsageEvent; + +typedef struct __KKStringEventStruct { + KKHeader header; + char str[1]; +} KKStringEvent; + +typedef KKSysCallRequest KKSysCallEvent; + +#endif diff --git a/lib/ultralib/include/gcc/math.h b/lib/ultralib/include/gcc/math.h new file mode 100644 index 00000000..3e93ceb1 --- /dev/null +++ b/lib/ultralib/include/gcc/math.h @@ -0,0 +1 @@ +// Nothing needed here diff --git a/lib/ultralib/include/gcc/memory.h b/lib/ultralib/include/gcc/memory.h new file mode 100644 index 00000000..edfff5e7 --- /dev/null +++ b/lib/ultralib/include/gcc/memory.h @@ -0,0 +1,23 @@ +#ifndef _MEMORY_H +#define _MEMORY_H +/* + memory.h +*/ + +#ifndef _SIZE_T_DEF +#define _SIZE_T_DEF +typedef unsigned size_t; +#endif + +void *memccpy(void *,void *,int,size_t); +void *memchr(void *,int,size_t); +int memcmp(const void *,const void *,size_t); +void *memcpy(void *,const void *,size_t); +int memicmp(void *,void *,size_t); +void *memmove(void *,void *,size_t); +void *memset(void *,int,size_t); + +void movmem(void *,void *,unsigned); +void setmem(void *,unsigned,int); + +#endif diff --git a/lib/ultralib/include/gcc/stdarg.h b/lib/ultralib/include/gcc/stdarg.h new file mode 100755 index 00000000..af337f66 --- /dev/null +++ b/lib/ultralib/include/gcc/stdarg.h @@ -0,0 +1,121 @@ +#ifndef _STDARG_H +#define _STDARG_H +/* ---------------------------------------- */ +/* VARARGS for MIPS/GNU CC */ +/* */ +/* */ +/* */ +/* */ +/* ---------------------------------------- */ + +/* These macros implement varargs for GNU C--either traditional or ANSU. */ + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef char * __gnuc_va_list; +#endif /* not __GNUC_VA_LIST */ + +/* If this is for internal libc use, don't define anything but + __gnuc_va_list. */ +#if defined (_STDARG_H) || defined (_VARARGS_H) + +/* In GCC version 2, we want an ellipsis at the end of the declaration + of the argument list. GCC version 1 can't parse it. */ + +#if __GNUC__ > 1 +#define __va_ellipsis ... +#else +#define __va_ellipsis +#endif + +#if __mips>=3 +#define __va_rounded_size(__TYPE) \ + (((sizeof (__TYPE) + 8 - 1) / 8) * 8) +#else +#define __va_rounded_size(__TYPE) \ + (((sizeof (__TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) +#endif + +/* Get definitions for _MIPS_SIM_ABI64 etc. */ +#ifdef _MIPS_SIM +#include +#endif + +#ifdef _STDARG_H +#if defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64) +#define va_start(__AP, __LASTARG) \ + (__AP = __builtin_next_arg (__LASTARG) - 64 \ + + (__builtin_args_info (2) > 8 ? 64 : __builtin_args_info(2) * 8)) +#else +#define va_start(__AP, __LASTARG) \ + (__AP = (__gnuc_va_list) __builtin_next_arg (__LASTARG)) +#endif + +#else +#define va_alist __builtin_va_alist +#if __mips>=3 +/* This assumes that `long long int' is always a 64 bit type. */ +#define va_dcl long long int __builtin_va_alist; __va_ellipsis +#else +#define va_dcl int __builtin_va_alist; __va_ellipsis +#endif +/* Need alternate code for _MIPS_SIM_ABI64, but don't use that symbol + because it may not be defined. */ +#if defined(_MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64) +#define va_start(__AP) \ + (__AP = __builtin_next_arg () - 64 \ + + (__builtin_args_info (2) > 8 ? 64 : __builtin_args_info(2) * 8)) +#else +#define va_start(__AP) __AP = (char *) &__builtin_va_alist +#endif +#endif + +#ifndef va_end +void va_end (__gnuc_va_list); /* Defined in libgcc.a */ +#endif +#define va_end(__AP) ((void)0) + +/* We cast to void * and then to TYPE * because this avoids + a warning about increasing the alignment requirement. */ +/* The __mips>=3 cases are reversed from the 32 bit cases, because the standard + 32 bit calling convention left-aligns all parameters smaller than a word, + whereas the __mips>=3 calling convention does not (and hence they are + right aligned). */ +#if __mips>=3 +#ifdef __MIPSEB__ +#define va_arg(__AP, __type) \ + ((__type *) (void *) (__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \ + + __va_rounded_size (__type))))[-1] +#else +#define va_arg(__AP, __type) \ + ((__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \ + + __va_rounded_size (__type))), \ + *(__type *) (void *) (__AP - __va_rounded_size (__type))) +#endif + +#else /* not __mips>=3 */ + +#ifdef __MIPSEB__ +/* For big-endian machines. */ +#define va_arg(__AP, __type) \ + ((__AP = (char *) ((__alignof__ (__type) > 4 \ + ? ((int)__AP + 8 - 1) & -8 \ + : ((int)__AP + 4 - 1) & -4) \ + + __va_rounded_size (__type))), \ + *(__type *) (void *) (__AP - __va_rounded_size (__type))) +#else +/* For little-endian machines. */ +#define va_arg(__AP, __type) \ + ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4 \ + ? ((int)__AP + 8 - 1) & -8 \ + : ((int)__AP + 4 - 1) & -4) \ + + __va_rounded_size(__type))))[-1] +#endif +#endif + +typedef __gnuc_va_list va_list; + +#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */ +#endif diff --git a/lib/ultralib/include/gcc/stdio.h b/lib/ultralib/include/gcc/stdio.h new file mode 100644 index 00000000..3e93ceb1 --- /dev/null +++ b/lib/ultralib/include/gcc/stdio.h @@ -0,0 +1 @@ +// Nothing needed here diff --git a/lib/ultralib/include/gcc/stdlib.h b/lib/ultralib/include/gcc/stdlib.h new file mode 100644 index 00000000..98f8a2e1 --- /dev/null +++ b/lib/ultralib/include/gcc/stdlib.h @@ -0,0 +1,81 @@ +#ifndef _STDLIB_H +#define _STDLIB_H +/* + stdlib.h +*/ + +#ifndef _SIZE_T_DEF +#define _SIZE_T_DEF +typedef unsigned size_t; +#endif + +#ifndef _DIV_T_DEF +#define _DIV_T_DEF +typedef struct DIV_T { + int quot; + int rem; +} div_t; +#endif + +#ifndef _LDIV_T_DEF +#define _LDIV_T_DEF +typedef struct LDIV_T { + long quot; + long rem; +} ldiv_t; +#endif + +#ifndef _LLDIV_T_DEF +#define _LLDIV_T_DEF +typedef struct lldiv_t +{ + long long quot; + long long rem; +} lldiv_t; +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define _max(a,b) (((a) > (b)) ? (a) : (b)) +#define _min(a,b) (((a) < (b)) ? (a) : (b)) + +#define RAND_MAX 32767 + +int rand(void); +void srand(unsigned); + +int abs(int); +long labs(long); + +div_t div(int,int); +ldiv_t ldiv(long,long); +lldiv_t lldiv(long long, long long); + +int atoi(const char *); +long atol(const char *); + +long strtol(const char *,char **,int); +unsigned long strtoul(const char *,char **,int); + +char *itoa(int,char *,int); +char *ltoa(long,char *,int); +char *ultoa(unsigned long,char *,int); + +double atof(const char *); +double strtod(const char *,char **); + +void qsort(void *,size_t,size_t,int (*)(const void *,const void *)); +void *bsearch(const void *,const void *,size_t,size_t,int (*)(const void *,const void *)); + +void *malloc(size_t); +void *calloc(size_t,size_t); +void *realloc(void *,size_t); +void free(void *); + +void exit(int); + +void abort(void); + +#endif diff --git a/lib/ultralib/include/gcc/string.h b/lib/ultralib/include/gcc/string.h new file mode 100755 index 00000000..d82e1f10 --- /dev/null +++ b/lib/ultralib/include/gcc/string.h @@ -0,0 +1,42 @@ +#ifndef _STRING_H +#define _STRING_H +/* + string.h +*/ + +#ifndef _SIZE_T_DEF +#define _SIZE_T_DEF +typedef unsigned size_t; +#endif + +#include "memory.h" + +char *stpcpy(char *,const char *); +char *strcat(char *,const char *); +char *strchr(const char *,int); +int strcmp(const char *,const char *); +char *strcpy(char *,const char *); +size_t strcspn(const char *,const char *); +char *strdup(const char *); +char *strerror(int); +int stricmp(const char *,const char *); +size_t strlen(const char *); +char *strlwr(char *); +char *strncat(char *,const char *,size_t); +int strncmp(const char *,const char *,size_t); +char *strncpy(char *,const char *,size_t); +int strnicmp(const char *,const char *,size_t); +char *strnset(char *,int,size_t); +char *strpbrk(const char *,const char *); +char *strrchr(const char *,int); +char *strrev(char *); +char *strset(char *,int); +size_t strspn(const char *,const char *); +char *strstr(const char *,const char *); +char *strtok(char *,const char *); +char *strupr(char *); + +#define strcmpi(s1,s2) stricmp(s1,s2) +#define strncmpi(s1,s2,n) strnicmp(s1,s2,n) + +#endif diff --git a/lib/ultralib/include/macros.h b/lib/ultralib/include/macros.h new file mode 100644 index 00000000..f7266598 --- /dev/null +++ b/lib/ultralib/include/macros.h @@ -0,0 +1,16 @@ +#ifndef __MACROS_H__ +#define __MACROS_H__ + +#define ALIGNED(x) __attribute__((aligned(x))) + +#define ARRLEN(x) ((s32)(sizeof(x) / sizeof(x[0]))) + +#define STUBBED_PRINTF(x) + +#define UNUSED __attribute__((unused)) + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +#endif diff --git a/lib/ultralib/include/sys/asm.h b/lib/ultralib/include/sys/asm.h new file mode 100644 index 00000000..445a2bf3 --- /dev/null +++ b/lib/ultralib/include/sys/asm.h @@ -0,0 +1,72 @@ +/************************************************************************ + 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 XLEAF(x) \ + .global x; + +#define END(proc) \ + .end proc + +#define ABS(x, y) \ + .globl x; \ + x = y + +#define EXPORT(x) \ + .globl x; \ +x: +/* +#define WEAK(x, y) \ + .weak x; \ + .set x,y; +*/ + +#define WEAK(x, y) + +#define STAY1(stmnt) .set noreorder; stmnt; .set reorder; +#define STAY2(stmnt, arg1) .set noreorder; stmnt, arg1; .set reorder; +#define STAY3(stmnt, arg1, arg2) .set noreorder; stmnt, arg1, arg2; .set reorder; +#define NOP .set noreorder; nop; .set reorder; +#define CACHE(op, reg) .set noreorder; cache op, reg; .set reorder; + +#ifdef __cplusplus +} +#endif + +#endif /* !__ASM_H__ */ diff --git a/lib/ultralib/include/sys/regdef.h b/lib/ultralib/include/sys/regdef.h new file mode 100644 index 00000000..ac9c109a --- /dev/null +++ b/lib/ultralib/include/sys/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/include/ultra64.h b/lib/ultralib/include/ultra64.h new file mode 100644 index 00000000..053db38e --- /dev/null +++ b/lib/ultralib/include/ultra64.h @@ -0,0 +1,40 @@ + +/************************************************************************** + * * + * 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. * + * * + *************************************************************************/ + +/************************************************************************** + * + * $Revision: 1.10 $ + * $Date: 1997/02/11 08:37:33 $ + * $Source: /exdisk2/cvs/N64OS/Master/cvsmdev2/PR/include/ultra64.h,v $ + * + **************************************************************************/ + +#ifndef _ULTRA64_H_ +#define _ULTRA64_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/lib/ultralib/include/ultrahost.h b/lib/ultralib/include/ultrahost.h new file mode 100644 index 00000000..2c50b95d --- /dev/null +++ b/lib/ultralib/include/ultrahost.h @@ -0,0 +1,59 @@ +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 1999/07/05 02:16:07 $ + * + **************************************************************************/ + +#ifndef _ULTRAHOST_H_ +#define _ULTRAHOST_H_ + +#ifdef WIN32 /* { */ + +int __stdcall uhOpenGame(char *); +int __stdcall uhCloseGame(int); +int __stdcall uhReadGame(int hfd,void *buf,int count); +int __stdcall uhWriteGame(int hfd,void *buf,int count); +int __stdcall uhReadRamrom(int hfd,void *ramrom_adr,void *buf,int count); +int __stdcall uhWriteRamrom(int hfd,void *ramrom_adr,void *buf,int count); +int __stdcall uhPartnerInit(int hfd); +int __stdcall uhPartnerCmd(int hfd,char *ptcmd); +int __stdcall uhGload(int hfd,char *loadfile); + +#else /* }{ */ +#ifdef PTN64 /* { */ + +#define execl execl_pt + +#define uhOpenGame uhOpenGame_pt +#define uhCloseGame uhCloseGame_pt + +#define uhReadGame uhReadGame_pt +#define uhWriteGame uhWriteGame_pt +#define uhReadRamrom uhReadRamrom_pt +#define uhWriteRamrom uhWriteRamrom_pt +#define uhPartnerCmd uhPartnerCmd_pt +#define uhGload uhGload_pt + +int uhPartnerCmd(int,char *); +int uhGload(int,char *); + +#endif /* } */ + +#ifdef __cplusplus +extern "C" { +#endif +int uhOpenGame(const char *); +int uhCloseGame(int); + +int uhReadGame(int, void *, int); +int uhWriteGame(int, void *, int); +int uhWriteRamrom(int, void *, void*, int); +int uhReadRamrom(int, void *, void*, int); + +#ifdef __cplusplus +} +#endif +#endif /* } */ + +#endif /* ULTRAHOST */ diff --git a/lib/ultralib/src/audio/Makefile b/lib/ultralib/src/audio/Makefile new file mode 100644 index 00000000..d8fdce4e --- /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 00000000..471ba41e --- /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 +#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 00000000..dfd312fa --- /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 +#include +#include + +/* + * ### 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 00000000..55cd2a3c --- /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 + +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 00000000..e80a8dfb --- /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 + +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 00000000..9c4b8bd1 --- /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 +#include +#include +#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 00000000..0342398f --- /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 00000000..bb72541d --- /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 00000000..063c5430 --- /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 + +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 00000000..23d256ee --- /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 + +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 00000000..c67e033c --- /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 + +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 00000000..5c0e322a --- /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 + +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 00000000..ac38cae4 --- /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 + +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 00000000..382616f3 --- /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 + +s32 alCSPGetChlProgram(ALCSPlayer *seqp, u8 chan) + +{ + s32 i; + ALBank *b = seqp->bank; + ALInstrument *inst; + ALChanState s; + + s = seqp->chanState[chan]; + for (i=0; iinstCount; 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 00000000..85d25454 --- /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 + +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 00000000..9be79371 --- /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 + +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 00000000..ed3dfe23 --- /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 + +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 00000000..5353228d --- /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 + +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 00000000..621ce02e --- /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 +#include +#include +#include +#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 00000000..e34914c2 --- /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 +#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 00000000..3d03c9b8 --- /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 + +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 00000000..63292b4b --- /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 + +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 00000000..28e62bba --- /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 + +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 00000000..f099297e --- /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 + +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 00000000..c0dab00c --- /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 + +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 00000000..b449b826 --- /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 + +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 00000000..2b19e63d --- /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 + +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 00000000..4b6718e9 --- /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 + +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 00000000..b085b454 --- /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 + +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 00000000..6782f330 --- /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 + +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 00000000..99298204 --- /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 + +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 00000000..ef9e27f2 --- /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 +#include "synthInternals.h" +#include +#include +#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; isection_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 00000000..bc7369a1 --- /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 +#include "synthInternals.h" +#include +#include +#include +#include + +// 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<>= 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 00000000..3112c99d --- /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 +#include +#include + + +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 00000000..d88460bf --- /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 +#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 00000000..8a378084 --- /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 +#include +#include + +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 00000000..baae6437 --- /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 +#include +#include + +#ifdef AUD_PROFILE +#include +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 00000000..9053375c --- /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 + +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 00000000..704e1f4a --- /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 00000000..af070756 --- /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 +#include "synthInternals.h" +#include +#include + +#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<memin + nbytes - ((s32) f->table->base + f->table->len); + if (overFlow < 0) + overFlow = 0; + nOver = (overFlow/ADPCMFBYTES)< 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 00000000..d5c8eca6 --- /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 +#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 00000000..f1fd37d3 --- /dev/null +++ b/lib/ultralib/src/audio/parse_abi.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#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 00000000..2baf26f2 --- /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 +#include "synthInternals.h" +#include +#include + +// 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 00000000..292ed0f3 --- /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 +#include +#include "synthInternals.h" +#include +#include +#include +#include +#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 00000000..bc15294e --- /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 +#include "synthInternals.h" +#include +#include + +// 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 00000000..5da5b119 --- /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 +#include +#include +#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 00000000..479b3396 --- /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 00000000..c9ab02ba --- /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 00000000..b4f11fd4 --- /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 +#include + +// 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 00000000..e2056517 --- /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 + +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 00000000..5d7ee3f7 --- /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 + +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 00000000..23f10678 --- /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 + +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 00000000..e6f77a4e --- /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 + +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 00000000..d421cdec --- /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 + +s32 alSeqpGetChlProgram(ALSeqPlayer *seqp, u8 chan) + +{ + s32 i; + ALBank *b = seqp->bank; + ALInstrument *inst; + ALChanState s; + + s = seqp->chanState[chan]; + for (i=0; iinstCount; 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 00000000..d35ea199 --- /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 + +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 00000000..8d36b498 --- /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 + +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 00000000..41cd4b4a --- /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 + +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 00000000..43a3bb80 --- /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 + +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 00000000..3b83257b --- /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 +#include +#include +#include +#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 00000000..9bbaf5f9 --- /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 + +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 00000000..8e655042 --- /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 +#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 00000000..56a9510d --- /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 + +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 00000000..1c00e8b2 --- /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 + +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 00000000..9b48803c --- /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 + +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 00000000..93979635 --- /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 + +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 00000000..85d07d9e --- /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 + +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 00000000..09107263 --- /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 + +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 00000000..dfd6d942 --- /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 + +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 00000000..3fe81757 --- /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 + +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 00000000..592320aa --- /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 + +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 00000000..b698a406 --- /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 + +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 00000000..abec7812 --- /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 + +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 00000000..d1849722 --- /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 + +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 00000000..17d70151 --- /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 + +#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 00000000..0629ac79 --- /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 00000000..7c18b56b --- /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 +#include + +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 00000000..5cfb4f74 --- /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 +#include + +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; imaxSounds; 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 00000000..90889823 --- /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 00000000..882b4a3f --- /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 00000000..391e6acf --- /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 +#include +#include + +// 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 00000000..ff5d123a --- /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 +#include + +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 00000000..b37f796f --- /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 00000000..147c956d --- /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 +#include + +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 00000000..5f98648d --- /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 +#include + +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 00000000..0ee174c2 --- /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 +#include + +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 00000000..0d0fbc01 --- /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 +#include + +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 00000000..3d341ecb --- /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 +#include + +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 00000000..ad79f5fd --- /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 +#include + +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 00000000..69aead6a --- /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 00000000..77efb293 --- /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 + +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 00000000..e0e7f268 --- /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 00000000..73d608d5 --- /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 +#include +#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 00000000..900fe76c --- /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 00000000..be436ea5 --- /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 00000000..eaa71ace --- /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 +#include +#include "synthInternals.h" + +#include + +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 00000000..b0fa5778 --- /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 00000000..68de3651 --- /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 00000000..0248a7e3 --- /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 + +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 00000000..8c156ab5 --- /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 +#include + +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 00000000..b3991f64 --- /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 00000000..0d68538a --- /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 +#include + +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 00000000..0bfb7ba8 --- /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 +#include + +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 00000000..c680bccd --- /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 + +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 00000000..181c96f2 --- /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 +#include + +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 00000000..9ad1d890 --- /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 +#include + +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 00000000..dbede0f2 --- /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 +#include +#include + +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 00000000..69c09d87 --- /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 +#include + + +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 00000000..07c08bcb --- /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 + +/* + * 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 00000000..d42a21aa --- /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 + +// TODO: this comes from a header +#ident "$Revision: 1.17 $" + +#ifdef AUD_PROFILE +#include +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= ¶ms[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 00000000..b4930351 --- /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 00000000..e3837732 --- /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 00000000..42788f86 --- /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 00000000..7fef229b --- /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 00000000..c12d313c --- /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 00000000..c5c4ccaa --- /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 00000000..0891ad7f --- /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 00000000..666d7cd3 --- /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 00000000..c66dbd6d --- /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 00000000..9e52b972 --- /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 00000000..e667668e --- /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 00000000..47faf5c3 --- /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 00000000..7622f9cb --- /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 00000000..3fe2e37f --- /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 00000000..9b51a253 --- /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 00000000..6134d339 --- /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 00000000..7c8a2c03 --- /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 00000000..6bb582b7 --- /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 00000000..deb6070e --- /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 00000000..fcccc6ed --- /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 00000000..52097e1a --- /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 00000000..555f1df5 --- /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 00000000..8cbd0c97 --- /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 00000000..3abc04fd --- /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 00000000..64652d36 --- /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 00000000..b0868fdd --- /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 00000000..095c8a49 --- /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 +#include + +#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 00000000..bf99e858 --- /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 00000000..31ddd7cc --- /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 00000000..ad6e2faf --- /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 00000000..9be7b4a4 --- /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 00000000..5a66c1b3 --- /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 00000000..0d955303 --- /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 00000000..a5e5e128 --- /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= 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; it.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 00000000..4af9c5d2 --- /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 00000000..c3206dd5 --- /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 00000000..e16e2503 --- /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 00000000..b88ad985 --- /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 00000000..786f64a4 --- /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 +#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; hh; h++) + { + flip = (h & 1) << 2; /*shift does not depend on txlsize*/ + for (b=0; b> 4); + } + /* add last aligned nibble */ + if (!endUnAligned) *(taddr+((b-1)^flip)) &= (0xf0); + /* pickup trailing bytes */ + for (b=im_bytes; blsize; + taddr += tr_bytes; + } + } + else /* if start aligned */ + { + for (h=0; hh; h++) + { + flip = (h & 1) << 2; /*shift does not depend on txlsize*/ + for (b=0; blsize; + 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) 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) 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 <> (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 00000000..1fadc17f --- /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 00000000..a848688b --- /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 00000000..3cd3b65d --- /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 00000000..b60ca089 --- /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 00000000..11f43a1a --- /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 00000000..25105587 --- /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 00000000..9e52cb36 --- /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 00000000..21cf9c31 --- /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 +#include +#include + +#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 00000000..c17c978f --- /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 +#include +#include + +/* 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 00000000..71a58a89 --- /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 +#include +#include + +/* 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 00000000..be571d40 --- /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 + +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 00000000..52cdd963 --- /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 00000000..389a04d7 --- /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 (al.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 00000000..259fe8c6 --- /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 (al.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 (al.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)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 00000000..32cfde3a --- /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 00000000..114174ed --- /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 00000000..eceb096b --- /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 00000000..c239d210 --- /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 00000000..f4bb1ad6 --- /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 00000000..b24851f7 --- /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 00000000..b5e1a45a --- /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 00000000..475a827a --- /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 00000000..cf977f95 --- /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 +#include + +/* + * 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 00000000..cc321792 --- /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 00000000..e79ff7b7 --- /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 +#include + +#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 00000000..a10ed344 --- /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 00000000..9e6fbd67 --- /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 00000000..5cc19748 --- /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 00000000..92e95871 --- /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 00000000..5e345dc7 --- /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 00000000..6b836823 --- /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 00000000..c7a3cf7f --- /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 00000000..52cd8c37 --- /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 00000000..d4295d3e --- /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 00000000..9cd16173 --- /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 00000000..d209ffc9 --- /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 00000000..15af27ca --- /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 00000000..ea924319 --- /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 00000000..d24ff06b --- /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 00000000..887ada6d --- /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 00000000..aa351fd8 --- /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 00000000..51214267 --- /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 00000000..d042ecf7 --- /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 00000000..0afa93a5 --- /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 00000000..14784800 --- /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 00000000..60b94936 --- /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 00000000..ab30a477 --- /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 00000000..db9b7693 --- /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 00000000..efce970c --- /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 00000000..db98bd48 --- /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 00000000..7223d060 --- /dev/null +++ b/lib/ultralib/src/io/controller_voice.h @@ -0,0 +1,59 @@ +#ifndef CONTROLLER_VOICE_H +#define CONTROLLER_VOICE_H + +#include + +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 00000000..eff63a6f --- /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 00000000..e2661529 --- /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 00000000..2d227746 --- /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 00000000..e4d02545 --- /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 00000000..0c2164bb --- /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 00000000..af3cceee --- /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 00000000..fa9a0d4b --- /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 00000000..5b538670 --- /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 00000000..d1227919 --- /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 00000000..ef749ea8 --- /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 00000000..8785bdb1 --- /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 00000000..63ad6cf3 --- /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 00000000..7871f56b --- /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 00000000..5cc17523 --- /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 00000000..3918c5f8 --- /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 00000000..1a4c4626 --- /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 00000000..7fbef18c --- /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 00000000..622e707d --- /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 00000000..d17d15c6 --- /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 00000000..604bafae --- /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 00000000..c0b78cb3 --- /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 00000000..d0cf4673 --- /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 00000000..5fac5ce3 --- /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 00000000..134cad88 --- /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 00000000..df36414d --- /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 00000000..84ef32fe --- /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 00000000..ee718302 --- /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 00000000..6ca88eb9 --- /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 00000000..7f5cb8b4 --- /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 00000000..a1fd8488 --- /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 00000000..960bd302 --- /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 00000000..6640728e --- /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 00000000..e290cdae --- /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 00000000..927636f2 --- /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 00000000..71a18d9b --- /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 00000000..e4480bdc --- /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 00000000..14a6e456 --- /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 00000000..cbd4b6ab --- /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 00000000..f29590a7 --- /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 00000000..04a4155c --- /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 00000000..fb0ab489 --- /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 00000000..a0584cf7 --- /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 00000000..1c350c54 --- /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 00000000..03ab11e6 --- /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 00000000..077f13a6 --- /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 00000000..809cdb2a --- /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 00000000..43e9a271 --- /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 00000000..f918306d --- /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 00000000..734fdde1 --- /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 00000000..c757532b --- /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 00000000..d7660641 --- /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 00000000..8531d171 --- /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 00000000..5e9d7c5c --- /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 00000000..2fed7a62 --- /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 00000000..99353313 --- /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 00000000..f97691b6 --- /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 00000000..f515c490 --- /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 00000000..02254454 --- /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 00000000..636a87ff --- /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 00000000..e27ff101 --- /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 00000000..5381cf19 --- /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 00000000..9967c1d5 --- /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 00000000..95d5b202 --- /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 00000000..0cdfda69 --- /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 00000000..41239b1c --- /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 00000000..affc78bb --- /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 00000000..f6451ae2 --- /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 00000000..dce0b5d2 --- /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 00000000..2ab47e08 --- /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 00000000..13d6f003 --- /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 00000000..78bacaee --- /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 00000000..6c18c219 --- /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 00000000..bffed927 --- /dev/null +++ b/lib/ultralib/src/io/vi.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#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 00000000..7e8ea819 --- /dev/null +++ b/lib/ultralib/src/io/viblack.c @@ -0,0 +1,17 @@ +#include +#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 00000000..8fa8074e --- /dev/null +++ b/lib/ultralib/src/io/viextendvstart.c @@ -0,0 +1,6 @@ +#include +#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 00000000..2812860a --- /dev/null +++ b/lib/ultralib/src/io/vifade.c @@ -0,0 +1,18 @@ +#include +#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 00000000..729d9023 --- /dev/null +++ b/lib/ultralib/src/io/vigetcurrcontext.c @@ -0,0 +1,9 @@ +#include +#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 00000000..987e86be --- /dev/null +++ b/lib/ultralib/src/io/vigetcurrframebuf.c @@ -0,0 +1,10 @@ +#include +#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 00000000..395e9122 --- /dev/null +++ b/lib/ultralib/src/io/vigetfield.c @@ -0,0 +1,6 @@ +#include +#include + +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 00000000..1eed3cd2 --- /dev/null +++ b/lib/ultralib/src/io/vigetline.c @@ -0,0 +1,6 @@ +#include +#include + +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 00000000..bb3fcd00 --- /dev/null +++ b/lib/ultralib/src/io/vigetmode.c @@ -0,0 +1,10 @@ +#include +#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 00000000..56928902 --- /dev/null +++ b/lib/ultralib/src/io/vigetnextcontext.c @@ -0,0 +1,6 @@ +#include +#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 00000000..91582812 --- /dev/null +++ b/lib/ultralib/src/io/vigetnextframebuf.c @@ -0,0 +1,10 @@ +#include +#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 00000000..eea94a73 --- /dev/null +++ b/lib/ultralib/src/io/vigetstat.c @@ -0,0 +1,6 @@ +#include +#include + +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 00000000..3ae94c89 --- /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 00000000..d4766b50 --- /dev/null +++ b/lib/ultralib/src/io/vimgr.c @@ -0,0 +1,110 @@ +#include +#include +#include +#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 00000000..905538ef --- /dev/null +++ b/lib/ultralib/src/io/virepeatline.c @@ -0,0 +1,17 @@ +#include +#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 00000000..589647ac --- /dev/null +++ b/lib/ultralib/src/io/visetevent.c @@ -0,0 +1,14 @@ +#include +#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 00000000..655cba60 --- /dev/null +++ b/lib/ultralib/src/io/visetmode.c @@ -0,0 +1,14 @@ +#include +#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 00000000..e8f90b88 --- /dev/null +++ b/lib/ultralib/src/io/visetspecial.c @@ -0,0 +1,48 @@ +#include +#include +#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 00000000..328987c2 --- /dev/null +++ b/lib/ultralib/src/io/visetxscale.c @@ -0,0 +1,16 @@ +#include +#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 00000000..525e0ebb --- /dev/null +++ b/lib/ultralib/src/io/visetyscale.c @@ -0,0 +1,13 @@ +#include +#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 00000000..327ed606 --- /dev/null +++ b/lib/ultralib/src/io/viswapbuf.c @@ -0,0 +1,13 @@ +#include +#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 00000000..3095d51e --- /dev/null +++ b/lib/ultralib/src/io/viswapcontext.c @@ -0,0 +1,72 @@ +#include +#include +#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 00000000..89e57e76 --- /dev/null +++ b/lib/ultralib/src/io/vitbl.c @@ -0,0 +1,1742 @@ +#include +#include +#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 00000000..f6fcc8bd --- /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 00000000..9bf1583e --- /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 00000000..13dcfa2f --- /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 00000000..59644e92 --- /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 00000000..71582bff --- /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 00000000..73d60566 --- /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 00000000..2c423dd8 --- /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 00000000..8d619f58 --- /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 00000000..c9a2b977 --- /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 00000000..f2e758c3 --- /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 00000000..b032e575 --- /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 00000000..f297df4d --- /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 00000000..d9f1003b --- /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 00000000..bd70de8a --- /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 00000000..52c29f69 --- /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 00000000..0c417fae --- /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 00000000..4b96124b --- /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 +#include + +/* + * 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 00000000..86a978aa --- /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 +#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 00000000..43bbe7eb --- /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 +#include + +/* + * 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 00000000..a9ec4913 --- /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 +#include + +/* + * 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 00000000..a6aa7793 --- /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 +#include + +/* + * 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 00000000..897acfbe --- /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 +#include + +/* + * 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 00000000..58c6772e --- /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 00000000..1dfa871f --- /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 00000000..58b90931 --- /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 +#include + +/* + * 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 00000000..ac9c109a --- /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 00000000..fec2443f --- /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 00000000..01bc290b --- /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 +#include + +/* + * 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 00000000..b27d1e33 --- /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 +#include + +/* + * 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 00000000..472fd8cf --- /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 +#include + +/* + 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 00000000..47d14bd6 --- /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 +#include + +/* + * 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 00000000..4aea8636 --- /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 00000000..34fe2ad7 --- /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 00000000..03b5b24a --- /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 00000000..d076a24d --- /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 00000000..f96bb634 --- /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 00000000..4e71cba4 --- /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 00000000..1ae9f0b3 --- /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 00000000..43d24363 --- /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 00000000..48c1234c --- /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 00000000..5a0bdcf5 --- /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 00000000..d5e60eb6 --- /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 00000000..4175e7d6 --- /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 00000000..873464f0 --- /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 00000000..99c17584 --- /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 00000000..81651785 --- /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 00000000..28d5a79f --- /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 00000000..7500928f --- /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 00000000..05bb19d5 --- /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 00000000..3a0e136b --- /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 00000000..deaccb66 --- /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 00000000..44fbc19a --- /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 00000000..9add6dd5 --- /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 00000000..bc9c767c --- /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 00000000..9aac16d5 --- /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 00000000..a1e9ce25 --- /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 00000000..aee799ae --- /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 00000000..a0702ea6 --- /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 00000000..04c03e90 --- /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 00000000..3b2c2ec8 --- /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 00000000..a24baef7 --- /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 00000000..de9954a7 --- /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 00000000..4eee9ee0 --- /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 00000000..ecc001ed --- /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 00000000..5b68da55 --- /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 00000000..cd648216 --- /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 00000000..c09b1fae --- /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 00000000..d0deeadb --- /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 00000000..a332c298 --- /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 00000000..8fac4817 --- /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 00000000..24cfb1cd --- /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 00000000..aeaf200a --- /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 00000000..289d850d --- /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 00000000..85dc1725 --- /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 00000000..d02e3fdc --- /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 00000000..c004362b --- /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 00000000..7a4c0cd0 --- /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 00000000..ce6ebb5d --- /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 00000000..a0c1baeb --- /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 00000000..237db23b --- /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 00000000..b561d999 --- /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 00000000..f7f0e63f --- /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 00000000..780da7cb --- /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 00000000..4d48d086 --- /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 00000000..52e49505 --- /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 00000000..dec29a23 --- /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 00000000..4f062bdd --- /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 00000000..f94f1d29 --- /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 00000000..4e839e88 --- /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 00000000..dd2ad991 --- /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 00000000..f96ab33a --- /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 00000000..1d82b6e1 --- /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 00000000..0fc9d30d --- /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 00000000..f19ed171 --- /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 00000000..ddc3f2f3 --- /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 00000000..c2eb1d72 --- /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 00000000..ab6b23ee --- /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 00000000..5bae2a24 --- /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 00000000..0b78f271 --- /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 00000000..efaed5e9 --- /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 00000000..2f645a78 --- /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 00000000..dfd7f1cc --- /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 00000000..d276b3bf --- /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 00000000..e9e07af3 --- /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 00000000..9095a042 --- /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 00000000..70514eb9 --- /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 00000000..767c4cf3 --- /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 00000000..c5a73dab --- /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 00000000..0f09d1f0 --- /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 00000000..280a42ee --- /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 00000000..6d4b2646 --- /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 00000000..5cf9e86f --- /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 00000000..5f5b4858 --- /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 00000000..ee8df884 --- /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 00000000..f4ed7c58 --- /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 00000000..0229b2c5 --- /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 00000000..4f615210 --- /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 00000000..6bd4b2a6 --- /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 00000000..4b264319 --- /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 00000000..181f52fe --- /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 00000000..ccae395b --- /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 00000000..a2bee99b --- /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 00000000..350b779f --- /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 00000000..6e2ee6d9 --- /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 00000000..3a8a3abf --- /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 00000000..0f9c4cde --- /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 00000000..8ac91a5f --- /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 00000000..2128c9ae --- /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 00000000..d1e3af25 --- /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 00000000..ffeca175 --- /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 00000000..87283745 --- /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 00000000..d4cd6590 --- /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 00000000..7cf59dd7 --- /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 +#include +#include + +// 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 00000000..50e042d5 --- /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 00000000..7807431c --- /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 00000000..e5faf167 --- /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 + +/* + * 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 00000000..a5abc859 --- /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 + +/* + * 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 00000000..6223c2cc --- /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 + +/* + * 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 00000000..887df089 --- /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 + +/* + * 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 00000000..dc0db543 --- /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 + +/* + * 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 00000000..0779f1fa --- /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 +#include + +// 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 = > + + 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 00000000..772036f8 --- /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 00000000..2ef12217 --- /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 00000000..4f1bd92e --- /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 + +/* + * 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 00000000..86e0f806 --- /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 00000000..857c4931 --- /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 00000000..366ed785 --- /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 00000000..76eaa135 --- /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 00000000..416e63e7 --- /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 00000000..3f3f1654 --- /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 00000000..bc86c990 --- /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 00000000..8233460e --- /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 00000000..30532a06 --- /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 00000000..76ddf136 --- /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 00000000..d743345c --- /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 00000000..04b4c6c6 --- /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 00000000..634d984c --- /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 00000000..cc1627a6 --- /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 00000000..0c3d605b --- /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 00000000..0566ccc3 --- /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 00000000..3aa2b6b9 --- /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 00000000..128ca150 --- /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 00000000..d589ad96 --- /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 00000000..57f43cd5 --- /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 00000000..2d726e7c --- /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 00000000..8eac1184 --- /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 00000000..2a4f73a5 --- /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 00000000..2ff5fad8 --- /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 00000000..d89f113b --- /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 00000000..2e5386b4 --- /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 00000000..420d5e6b --- /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 00000000..81957906 --- /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 00000000..071b3300 --- /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 00000000..279bb83a --- /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 00000000..5ad8c2bd --- /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 00000000..b9720a57 --- /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 00000000..ae8c0a9f --- /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 00000000..5c73d69f --- /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 00000000..31ff70b7 --- /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 00000000..fd15f404 --- /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 00000000..9a052bee --- /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 00000000..fa66af4a --- /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 00000000..dd146b98 --- /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 00000000..6cda2a14 --- /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 00000000..ff6172c7 --- /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 00000000..63409813 --- /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 00000000..791a918c --- /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 00000000..947a0c1c --- /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 00000000..6c9e9155 --- /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 00000000..62d162eb --- /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 00000000..a06efac6 --- /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 00000000..0ed9dfca --- /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 00000000..1a434892 --- /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 00000000..89bd8a22 --- /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 00000000..3dd00bed --- /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 00000000..bc5a2702 --- /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 00000000..50828ce4 --- /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 00000000..da2fead2 --- /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 00000000..e27e74bf --- /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 00000000..76fa04d0 --- /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 00000000..6f615e17 --- /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 00000000..25c51fac --- /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 00000000..ef6388f2 --- /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 00000000..ae4b07b6 --- /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 00000000..a3c80a42 --- /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 00000000..ffb833c6 --- /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 00000000..3842e3c4 --- /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 00000000..c2af86db --- /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 00000000..89b4c634 --- /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 00000000..95741e68 --- /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 00000000..5627846a --- /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 00000000..8d33f31a --- /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 00000000..a60f943c --- /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 00000000..899c1501 --- /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 00000000..a017e3d3 --- /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 00000000..2287c0d4 --- /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 00000000..9a7ed6fe --- /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 00000000..0f9fc73f --- /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 00000000..e5b97ca4 --- /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 diff --git a/lib/ultralib/tools/Makefile b/lib/ultralib/tools/Makefile new file mode 100644 index 00000000..f7bff848 --- /dev/null +++ b/lib/ultralib/tools/Makefile @@ -0,0 +1,30 @@ + +.PHONY: all clean distclean +GCC_DIR := gcc +AR := $(GCC_DIR)/ar +GCC-2.7.2 := $(GCC_DIR)/gcc +STRIP-2.7 := $(GCC_DIR)/strip-2.7 + +all: $(AR) $(GCC-2.7.2) $(STRIP-2.7) + +$(AR): | $(GCC_DIR) + wget https://github.com/decompals/mips-binutils-2.6/releases/download/main/binutils-2.6-linux.tar.gz + tar xf binutils-2.6-linux.tar.gz -C $(GCC_DIR) + $(RM) binutils-2.6-linux.tar.gz + +$(GCC-2.7.2): | $(GCC_DIR) + wget https://github.com/decompals/mips-gcc-2.7.2/releases/download/main/gcc-2.7.2-linux.tar.gz + tar xf gcc-2.7.2-linux.tar.gz -C $(GCC_DIR) + $(RM) gcc-2.7.2-linux.tar.gz + +$(STRIP-2.7): | $(GCC_DIR) + wget https://github.com/decompals/mips-binutils-2.7/releases/download/release/binutils-2.7.tar.gz + tar xf binutils-2.7.tar.gz -C $(GCC_DIR) + $(RM) binutils-2.7.tar.gz + +$(GCC_DIR): + mkdir -p $@ + +clean: +distclean: clean + $(RM) -rf $(GCC_DIR) diff --git a/lib/ultralib/tools/asm_differ/.gitignore b/lib/ultralib/tools/asm_differ/.gitignore new file mode 100644 index 00000000..eb176dc5 --- /dev/null +++ b/lib/ultralib/tools/asm_differ/.gitignore @@ -0,0 +1,2 @@ +.mypy_cache/ +__pycache__/ diff --git a/lib/ultralib/tools/asm_differ/.gitrepo b/lib/ultralib/tools/asm_differ/.gitrepo new file mode 100644 index 00000000..2e999c85 --- /dev/null +++ b/lib/ultralib/tools/asm_differ/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = https://github.com/simonlindholm/asm-differ + branch = main + commit = 4b38c884c1efdc3bfa8b14f13015a69368a8d3a2 + parent = 32a1a8061de197c4f10d4904cd72a22dd7cf905c + method = merge + cmdver = 0.4.3 diff --git a/lib/ultralib/tools/asm_differ/.pre-commit-config.yaml b/lib/ultralib/tools/asm_differ/.pre-commit-config.yaml new file mode 100644 index 00000000..6695f71a --- /dev/null +++ b/lib/ultralib/tools/asm_differ/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +repos: +- repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + language_version: python3.6 diff --git a/lib/ultralib/tools/asm_differ/LICENSE b/lib/ultralib/tools/asm_differ/LICENSE new file mode 100644 index 00000000..cf1ab25d --- /dev/null +++ b/lib/ultralib/tools/asm_differ/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/lib/ultralib/tools/asm_differ/README.md b/lib/ultralib/tools/asm_differ/README.md new file mode 100644 index 00000000..4a7f329b --- /dev/null +++ b/lib/ultralib/tools/asm_differ/README.md @@ -0,0 +1,56 @@ +# asm-differ + +Nice differ for assembly code. Currently supports MIPS, PPC, AArch64, and ARM32; should be easy to hack to support other instruction sets. + +![](screenshot.png) + +## Dependencies + +- Python >= 3.6 +- `python3 -m pip install --user colorama watchdog python-Levenshtein` (also `dataclasses` if on 3.6) + +## Usage + +Create a file `diff_settings.sh` in some directory (see the one in this repo for an example). Then from that directory, run + +```bash +/path/to/diff.sh [flags] (function|rom addr) +``` + +Recommended flags are `-mwo` (automatically run `make` on source file changes, and include symbols in diff). See `--help` for more details. + +### Tab completion + +[argcomplete](https://kislyuk.github.io/argcomplete/) can be optionally installed (with `python3 -m pip install argcomplete`) to enable tab completion in a bash shell, completing options and symbol names using the linker map. It also requires a bit more setup: + +If invoking the script **exactly** as `./diff.py`, the following should be added to the `.bashrc` according to argcomplete's instructions: + +```bash +eval "$(register-python-argcomplete ./diff.py)" +``` + +If that doesn't work, run `register-python-argcomplete ./diff.py` in your terminal and copy the output to `.bashrc`. + +If setup correctly (don't forget to restart the shell), `complete | grep ./diff.py` should output: + +```bash +complete -o bashdefault -o default -o nospace -F _python_argcomplete ./diff.py +``` + +Note for developers or for general troubleshooting: run `export _ARC_DEBUG=` to enable debug output during tab-completion, it may show otherwise silenced errors. Use `unset _ARC_DEBUG` or restart the terminal to disable. + +### Contributing + +Contributions are very welcome! Some notes on workflow: + +`black` is used for code formatting. You can either run `black diff.py` manually, or set up a pre-commit hook: +```bash +pip install pre-commit black +pre-commit install +``` + +Type annotations are used for all Python code. `mypy` should pass without any errors. + +PRs that skip the above are still welcome, however. + +The targeted Python version is 3.6. There are currently no tests. diff --git a/lib/ultralib/tools/asm_differ/diff-stylesheet.css b/lib/ultralib/tools/asm_differ/diff-stylesheet.css new file mode 100644 index 00000000..79da120d --- /dev/null +++ b/lib/ultralib/tools/asm_differ/diff-stylesheet.css @@ -0,0 +1,67 @@ +table.diff { + border: none; + font-family: Monospace; + white-space: pre; +} +tr.data-ref { + background-color: gray; +} +.immediate { + color: lightblue; +} +.stack { + color: yellow; +} +.register { + color: yellow; +} +.delay-slot { + font-weight: bold; + color: gray; +} +.diff-change { + color: lightblue; +} +.diff-add { + color: green; +} +.diff-remove { + color: red; +} +.source-filename { + font-weight: bold; +} +.source-function { + font-weight: bold; + text-decoration: underline; +} +.source-other { + font-style: italic; +} +.rotation-0 { + color: magenta; +} +.rotation-1 { + color: cyan; +} +.rotation-2 { + color: green; +} +.rotation-3 { + color: red; +} +.rotation-4 { + color: yellow; +} +.rotation-5 { + color: pink; +} +.rotation-6 { + color: blue; +} +.rotation-7 { + color: lime; +} +.rotation-8 { + color: gray; +} diff --git a/lib/ultralib/tools/asm_differ/diff.py b/lib/ultralib/tools/asm_differ/diff.py new file mode 100755 index 00000000..8ed764f9 --- /dev/null +++ b/lib/ultralib/tools/asm_differ/diff.py @@ -0,0 +1,2923 @@ +#!/usr/bin/env python3 +# PYTHON_ARGCOMPLETE_OK +import argparse +import sys +from typing import ( + Any, + Callable, + Dict, + Iterator, + List, + Match, + NoReturn, + Optional, + Pattern, + Set, + Tuple, + Type, + Union, +) + + +def fail(msg: str) -> NoReturn: + print(msg, file=sys.stderr) + sys.exit(1) + + +def static_assert_unreachable(x: NoReturn) -> NoReturn: + raise Exception("Unreachable! " + repr(x)) + + +# ==== COMMAND-LINE ==== + +if __name__ == "__main__": + # Prefer to use diff_settings.py from the current working directory + sys.path.insert(0, ".") + try: + import diff_settings + except ModuleNotFoundError: + fail("Unable to find diff_settings.py in the same directory.") + sys.path.pop(0) + + try: + import argcomplete + except ModuleNotFoundError: + argcomplete = None + + parser = argparse.ArgumentParser( + description="Diff MIPS, PPC, AArch64, or ARM32 assembly." + ) + + start_argument = parser.add_argument( + "start", + help="Function name or address to start diffing from.", + ) + + if argcomplete: + + def complete_symbol( + prefix: str, parsed_args: argparse.Namespace, **kwargs: object + ) -> List[str]: + if not prefix or prefix.startswith("-"): + # skip reading the map file, which would + # result in a lot of useless completions + return [] + config: Dict[str, Any] = {} + diff_settings.apply(config, parsed_args) # type: ignore + mapfile = config.get("mapfile") + if not mapfile: + return [] + completes = [] + with open(mapfile) as f: + data = f.read() + # assume symbols are prefixed by a space character + search = f" {prefix}" + pos = data.find(search) + while pos != -1: + # skip the space character in the search string + pos += 1 + # assume symbols are suffixed by either a space + # character or a (unix-style) line return + spacePos = data.find(" ", pos) + lineReturnPos = data.find("\n", pos) + if lineReturnPos == -1: + endPos = spacePos + elif spacePos == -1: + endPos = lineReturnPos + else: + endPos = min(spacePos, lineReturnPos) + if endPos == -1: + match = data[pos:] + pos = -1 + else: + match = data[pos:endPos] + pos = data.find(search, endPos) + completes.append(match) + return completes + + setattr(start_argument, "completer", complete_symbol) + + parser.add_argument( + "end", + nargs="?", + help="Address to end diff at.", + ) + parser.add_argument( + "-o", + dest="diff_obj", + action="store_true", + help="""Diff .o files rather than a whole binary. This makes it possible to + see symbol names. (Recommended)""", + ) + parser.add_argument( + "-e", + "--elf", + dest="diff_elf_symbol", + metavar="SYMBOL", + help="""Diff a given function in two ELFs, one being stripped and the other + one non-stripped. Requires objdump from binutils 2.33+.""", + ) + parser.add_argument( + "-c", + "--source", + dest="show_source", + action="store_true", + help="Show source code (if possible). Only works with -o or -e.", + ) + parser.add_argument( + "-C", + "--source-old-binutils", + dest="source_old_binutils", + action="store_true", + help="""Tweak --source handling to make it work with binutils < 2.33. + Implies --source.""", + ) + parser.add_argument( + "-j", + "--section", + dest="diff_section", + default=".text", + metavar="SECTION", + help="Diff restricted to a given output section.", + ) + parser.add_argument( + "-L", + "--line-numbers", + dest="show_line_numbers", + action="store_const", + const=True, + help="""Show source line numbers in output, when available. May be enabled by + default depending on diff_settings.py.""", + ) + parser.add_argument( + "--no-line-numbers", + dest="show_line_numbers", + action="store_const", + const=False, + help="Hide source line numbers in output.", + ) + parser.add_argument( + "--inlines", + dest="inlines", + action="store_true", + help="Show inline function calls (if possible). Only works with -o or -e.", + ) + parser.add_argument( + "--base-asm", + dest="base_asm", + metavar="FILE", + help="Read assembly from given file instead of configured base img.", + ) + parser.add_argument( + "--write-asm", + dest="write_asm", + metavar="FILE", + help="Write the current assembly output to file, e.g. for use with --base-asm.", + ) + parser.add_argument( + "-m", + "--make", + dest="make", + action="store_true", + help="Automatically run 'make' on the .o file or binary before diffing.", + ) + parser.add_argument( + "-l", + "--skip-lines", + dest="skip_lines", + metavar="LINES", + type=int, + default=0, + help="Skip the first LINES lines of output.", + ) + parser.add_argument( + "-s", + "--stop-jr-ra", + dest="stop_jrra", + action="store_true", + help="""Stop disassembling at the first 'jr ra'. Some functions have + multiple return points, so use with care!""", + ) + parser.add_argument( + "-i", + "--ignore-large-imms", + dest="ignore_large_imms", + action="store_true", + help="Pretend all large enough immediates are the same.", + ) + parser.add_argument( + "-I", + "--ignore-addr-diffs", + dest="ignore_addr_diffs", + action="store_true", + help="Ignore address differences. Currently only affects AArch64 and ARM32.", + ) + parser.add_argument( + "-B", + "--no-show-branches", + dest="show_branches", + action="store_false", + help="Don't visualize branches/branch targets.", + ) + parser.add_argument( + "-S", + "--base-shift", + dest="base_shift", + metavar="N", + type=str, + default="0", + help="""Diff position N in our img against position N + shift in the base img. + Arithmetic is allowed, so e.g. |-S "0x1234 - 0x4321"| is a reasonable + flag to pass if it is known that position 0x1234 in the base img syncs + up with position 0x4321 in our img. Not supported together with -o.""", + ) + parser.add_argument( + "-w", + "--watch", + dest="watch", + action="store_true", + help="""Automatically update when source/object files change. + Recommended in combination with -m.""", + ) + parser.add_argument( + "-3", + "--threeway=prev", + dest="threeway", + action="store_const", + const="prev", + help="""Show a three-way diff between target asm, current asm, and asm + prior to -w rebuild. Requires -w.""", + ) + parser.add_argument( + "-b", + "--threeway=base", + dest="threeway", + action="store_const", + const="base", + help="""Show a three-way diff between target asm, current asm, and asm + when diff.py was started. Requires -w.""", + ) + parser.add_argument( + "--width", + dest="column_width", + metavar="COLS", + type=int, + default=50, + help="Sets the width of the left and right view column.", + ) + parser.add_argument( + "--algorithm", + dest="algorithm", + default="levenshtein", + choices=["levenshtein", "difflib"], + help="""Diff algorithm to use. Levenshtein gives the minimum diff, while difflib + aims for long sections of equal opcodes. Defaults to %(default)s.""", + ) + parser.add_argument( + "--max-size", + "--max-lines", + metavar="LINES", + dest="max_lines", + type=int, + default=1024, + help="The maximum length of the diff, in lines.", + ) + parser.add_argument( + "--no-pager", + dest="no_pager", + action="store_true", + help="""Disable the pager; write output directly to stdout, then exit. + Incompatible with --watch.""", + ) + parser.add_argument( + "--format", + choices=("color", "plain", "html", "json"), + default="color", + help="Output format, default is color. --format=html or json implies --no-pager.", + ) + parser.add_argument( + "-U", + "--compress-matching", + metavar="N", + dest="compress_matching", + type=int, + help="""Compress streaks of matching lines, leaving N lines of context + around non-matching parts.""", + ) + parser.add_argument( + "-V", + "--compress-sameinstr", + metavar="N", + dest="compress_sameinstr", + type=int, + help="""Compress streaks of lines with same instructions (but possibly + different regalloc), leaving N lines of context around other parts.""", + ) + + # Project-specific flags, e.g. different versions/make arguments. + add_custom_arguments_fn = getattr(diff_settings, "add_custom_arguments", None) + if add_custom_arguments_fn: + add_custom_arguments_fn(parser) + + if argcomplete: + argcomplete.autocomplete(parser) + +# ==== IMPORTS ==== + +# (We do imports late to optimize auto-complete performance.) + +import abc +import ast +from collections import Counter, defaultdict +from dataclasses import asdict, dataclass, field, replace +import difflib +import enum +import html +import itertools +import json +import os +import queue +import re +import string +import struct +import subprocess +import threading +import time +import traceback + + +MISSING_PREREQUISITES = ( + "Missing prerequisite python module {}. " + "Run `python3 -m pip install --user colorama watchdog python-Levenshtein cxxfilt` to install prerequisites (cxxfilt only needed with --source)." +) + +try: + from colorama import Back, Fore, Style + import watchdog +except ModuleNotFoundError as e: + fail(MISSING_PREREQUISITES.format(e.name)) + +# ==== CONFIG ==== + + +@dataclass +class ProjectSettings: + arch_str: str + objdump_executable: str + build_command: List[str] + map_format: str + mw_build_dir: str + baseimg: Optional[str] + myimg: Optional[str] + mapfile: Optional[str] + source_directories: Optional[List[str]] + source_extensions: List[str] + show_line_numbers_default: bool + disassemble_all: bool + + +@dataclass +class Compress: + context: int + same_instr: bool + + +@dataclass +class Config: + arch: "ArchSettings" + + # Build/objdump options + diff_obj: bool + make: bool + source_old_binutils: bool + diff_section: str + inlines: bool + max_function_size_lines: int + max_function_size_bytes: int + + # Display options + formatter: "Formatter" + threeway: Optional[str] + base_shift: int + skip_lines: int + compress: Optional[Compress] + show_branches: bool + show_line_numbers: bool + show_source: bool + stop_jrra: bool + ignore_large_imms: bool + ignore_addr_diffs: bool + algorithm: str + + # Score options + score_stack_differences = True + penalty_stackdiff = 1 + penalty_regalloc = 5 + penalty_reordering = 60 + penalty_insertion = 100 + penalty_deletion = 100 + + +def create_project_settings(settings: Dict[str, Any]) -> ProjectSettings: + return ProjectSettings( + arch_str=settings.get("arch", "mips"), + baseimg=settings.get("baseimg"), + myimg=settings.get("myimg"), + mapfile=settings.get("mapfile"), + build_command=settings.get( + "make_command", ["make", *settings.get("makeflags", [])] + ), + source_directories=settings.get("source_directories"), + source_extensions=settings.get( + "source_extensions", [".c", ".h", ".cpp", ".hpp", ".s"] + ), + objdump_executable=get_objdump_executable(settings.get("objdump_executable")), + map_format=settings.get("map_format", "gnu"), + mw_build_dir=settings.get("mw_build_dir", "build/"), + show_line_numbers_default=settings.get("show_line_numbers_default", True), + disassemble_all=settings.get("disassemble_all", False) + ) + + +def create_config(args: argparse.Namespace, project: ProjectSettings) -> Config: + arch = get_arch(project.arch_str) + + formatter: Formatter + if args.format == "plain": + formatter = PlainFormatter(column_width=args.column_width) + elif args.format == "color": + formatter = AnsiFormatter(column_width=args.column_width) + elif args.format == "html": + formatter = HtmlFormatter() + elif args.format == "json": + formatter = JsonFormatter(arch_str=arch.name) + else: + raise ValueError(f"Unsupported --format: {args.format}") + + compress = None + if args.compress_matching is not None: + compress = Compress(args.compress_matching, False) + if args.compress_sameinstr is not None: + if compress is not None: + raise ValueError( + "Cannot pass both --compress-matching and --compress-sameinstr" + ) + compress = Compress(args.compress_sameinstr, True) + + show_line_numbers = args.show_line_numbers + if show_line_numbers is None: + show_line_numbers = project.show_line_numbers_default + + return Config( + arch=arch, + # Build/objdump options + diff_obj=args.diff_obj, + make=args.make, + source_old_binutils=args.source_old_binutils, + diff_section=args.diff_section, + inlines=args.inlines, + max_function_size_lines=args.max_lines, + max_function_size_bytes=args.max_lines * 4, + # Display options + formatter=formatter, + threeway=args.threeway, + base_shift=eval_int( + args.base_shift, "Failed to parse --base-shift (-S) argument as an integer." + ), + skip_lines=args.skip_lines, + compress=compress, + show_branches=args.show_branches, + show_line_numbers=show_line_numbers, + show_source=args.show_source or args.source_old_binutils, + stop_jrra=args.stop_jrra, + ignore_large_imms=args.ignore_large_imms, + ignore_addr_diffs=args.ignore_addr_diffs, + algorithm=args.algorithm, + ) + + +def get_objdump_executable(objdump_executable: Optional[str]) -> str: + if objdump_executable is not None: + return objdump_executable + + objdump_candidates = [ + "mips-linux-gnu-objdump", + "mips64-elf-objdump", + "mips-elf-objdump", + ] + for objdump_cand in objdump_candidates: + try: + subprocess.check_call( + [objdump_cand, "--version"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + return objdump_cand + except subprocess.CalledProcessError: + pass + except FileNotFoundError: + pass + + return fail( + f"Missing binutils; please ensure {' or '.join(objdump_candidates)} exists, or configure objdump_executable." + ) + + +def get_arch(arch_str: str) -> "ArchSettings": + for settings in ARCH_SETTINGS: + if arch_str == settings.name: + return settings + raise ValueError(f"Unknown architecture: {arch_str}") + + +BUFFER_CMD: List[str] = ["tail", "-c", str(10 ** 9)] + +# -S truncates long lines instead of wrapping them +# -R interprets color escape sequences +# -i ignores case when searching +# -c something about how the screen gets redrawn; I don't remember the purpose +# -#6 makes left/right arrow keys scroll by 6 characters +LESS_CMD: List[str] = ["less", "-SRic", "-#6"] + +DEBOUNCE_DELAY: float = 0.1 + +# ==== FORMATTING ==== + + +@enum.unique +class BasicFormat(enum.Enum): + NONE = enum.auto() + IMMEDIATE = enum.auto() + STACK = enum.auto() + REGISTER = enum.auto() + DELAY_SLOT = enum.auto() + DIFF_CHANGE = enum.auto() + DIFF_ADD = enum.auto() + DIFF_REMOVE = enum.auto() + SOURCE_FILENAME = enum.auto() + SOURCE_FUNCTION = enum.auto() + SOURCE_LINE_NUM = enum.auto() + SOURCE_OTHER = enum.auto() + + +@dataclass(frozen=True) +class RotationFormat: + group: str + index: int + key: str + + +Format = Union[BasicFormat, RotationFormat] +FormatFunction = Callable[[str], Format] + + +class Text: + segments: List[Tuple[str, Format]] + + def __init__(self, line: str = "", f: Format = BasicFormat.NONE) -> None: + self.segments = [(line, f)] if line else [] + + def reformat(self, f: Format) -> "Text": + return Text(self.plain(), f) + + def plain(self) -> str: + return "".join(s for s, f in self.segments) + + def __repr__(self) -> str: + return f"" + + def __bool__(self) -> bool: + return any(s for s, f in self.segments) + + def __str__(self) -> str: + # Use Formatter.apply(...) instead + return NotImplemented + + def __eq__(self, other: object) -> bool: + return NotImplemented + + def __add__(self, other: Union["Text", str]) -> "Text": + if isinstance(other, str): + other = Text(other) + result = Text() + # If two adjacent segments have the same format, merge their lines + if ( + self.segments + and other.segments + and self.segments[-1][1] == other.segments[0][1] + ): + result.segments = ( + self.segments[:-1] + + [(self.segments[-1][0] + other.segments[0][0], self.segments[-1][1])] + + other.segments[1:] + ) + else: + result.segments = self.segments + other.segments + return result + + def __radd__(self, other: Union["Text", str]) -> "Text": + if isinstance(other, str): + other = Text(other) + return other + self + + def finditer(self, pat: Pattern[str]) -> Iterator[Match[str]]: + """Replacement for `pat.finditer(text)` that operates on the inner text, + and returns the exact same matches as `Text.sub(pat, ...)`.""" + for chunk, f in self.segments: + for match in pat.finditer(chunk): + yield match + + def sub(self, pat: Pattern[str], sub_fn: Callable[[Match[str]], "Text"]) -> "Text": + result = Text() + for chunk, f in self.segments: + i = 0 + for match in pat.finditer(chunk): + start, end = match.start(), match.end() + assert i <= start <= end <= len(chunk) + sub = sub_fn(match) + if i != start: + result.segments.append((chunk[i:start], f)) + result.segments.extend(sub.segments) + i = end + if chunk[i:]: + result.segments.append((chunk[i:], f)) + return result + + def ljust(self, column_width: int) -> "Text": + length = sum(len(x) for x, _ in self.segments) + return self + " " * max(column_width - length, 0) + + +@dataclass +class TableMetadata: + headers: Tuple[Text, ...] + current_score: int + max_score: int + previous_score: Optional[int] + + +class Formatter(abc.ABC): + @abc.abstractmethod + def apply_format(self, chunk: str, f: Format) -> str: + """Apply the formatting `f` to `chunk` and escape the contents.""" + ... + + @abc.abstractmethod + def table(self, meta: TableMetadata, lines: List[Tuple["OutputLine", ...]]) -> str: + """Format a multi-column table with metadata""" + ... + + def apply(self, text: Text) -> str: + return "".join(self.apply_format(chunk, f) for chunk, f in text.segments) + + @staticmethod + def outputline_texts(lines: Tuple["OutputLine", ...]) -> Tuple[Text, ...]: + return tuple([lines[0].base or Text()] + [line.fmt2 for line in lines[1:]]) + + +@dataclass +class PlainFormatter(Formatter): + column_width: int + + def apply_format(self, chunk: str, f: Format) -> str: + return chunk + + def table(self, meta: TableMetadata, lines: List[Tuple["OutputLine", ...]]) -> str: + rows = [meta.headers] + [self.outputline_texts(ls) for ls in lines] + return "\n".join( + "".join(self.apply(x.ljust(self.column_width)) for x in row) for row in rows + ) + + +@dataclass +class AnsiFormatter(Formatter): + # Additional ansi escape codes not in colorama. See: + # https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters + STYLE_UNDERLINE = "\x1b[4m" + STYLE_NO_UNDERLINE = "\x1b[24m" + STYLE_INVERT = "\x1b[7m" + + BASIC_ANSI_CODES = { + BasicFormat.NONE: "", + BasicFormat.IMMEDIATE: Fore.LIGHTBLUE_EX, + BasicFormat.STACK: Fore.YELLOW, + BasicFormat.REGISTER: Fore.YELLOW, + BasicFormat.DELAY_SLOT: Fore.LIGHTBLACK_EX, + BasicFormat.DIFF_CHANGE: Fore.LIGHTBLUE_EX, + BasicFormat.DIFF_ADD: Fore.GREEN, + BasicFormat.DIFF_REMOVE: Fore.RED, + BasicFormat.SOURCE_FILENAME: Style.DIM + Style.BRIGHT, + BasicFormat.SOURCE_FUNCTION: Style.DIM + Style.BRIGHT + STYLE_UNDERLINE, + BasicFormat.SOURCE_LINE_NUM: Fore.LIGHTBLACK_EX, + BasicFormat.SOURCE_OTHER: Style.DIM, + } + + BASIC_ANSI_CODES_UNDO = { + BasicFormat.NONE: "", + BasicFormat.SOURCE_FILENAME: Style.NORMAL, + BasicFormat.SOURCE_FUNCTION: Style.NORMAL + STYLE_NO_UNDERLINE, + BasicFormat.SOURCE_OTHER: Style.NORMAL, + } + + ROTATION_ANSI_COLORS = [ + Fore.MAGENTA, + Fore.CYAN, + Fore.GREEN, + Fore.RED, + Fore.LIGHTYELLOW_EX, + Fore.LIGHTMAGENTA_EX, + Fore.LIGHTCYAN_EX, + Fore.LIGHTGREEN_EX, + Fore.LIGHTBLACK_EX, + ] + + column_width: int + + def apply_format(self, chunk: str, f: Format) -> str: + if f == BasicFormat.NONE: + return chunk + undo_ansi_code = Fore.RESET + if isinstance(f, BasicFormat): + ansi_code = self.BASIC_ANSI_CODES[f] + undo_ansi_code = self.BASIC_ANSI_CODES_UNDO.get(f, undo_ansi_code) + elif isinstance(f, RotationFormat): + ansi_code = self.ROTATION_ANSI_COLORS[ + f.index % len(self.ROTATION_ANSI_COLORS) + ] + else: + static_assert_unreachable(f) + return f"{ansi_code}{chunk}{undo_ansi_code}" + + def table(self, meta: TableMetadata, lines: List[Tuple["OutputLine", ...]]) -> str: + rows = [(meta.headers, False)] + [ + (self.outputline_texts(line), line[1].is_data_ref) for line in lines + ] + return "\n".join( + "".join( + (self.STYLE_INVERT if is_data_ref else "") + + self.apply(x.ljust(self.column_width)) + for x in row + ) + for (row, is_data_ref) in rows + ) + + +@dataclass +class HtmlFormatter(Formatter): + rotation_formats: int = 9 + + def apply_format(self, chunk: str, f: Format) -> str: + chunk = html.escape(chunk) + if f == BasicFormat.NONE: + return chunk + if isinstance(f, BasicFormat): + class_name = f.name.lower().replace("_", "-") + data_attr = "" + elif isinstance(f, RotationFormat): + class_name = f"rotation-{f.index % self.rotation_formats}" + rotation_key = html.escape(f"{f.group};{f.key}", quote=True) + data_attr = f'data-rotation="{rotation_key}"' + else: + static_assert_unreachable(f) + return f"{chunk}" + + def table(self, meta: TableMetadata, lines: List[Tuple["OutputLine", ...]]) -> str: + def table_row(line: Tuple[Text, ...], is_data_ref: bool, cell_el: str) -> str: + tr_attrs = " class='data-ref'" if is_data_ref else "" + output_row = f" " + for cell in line: + cell_html = self.apply(cell) + output_row += f"<{cell_el}>{cell_html}" + output_row += "\n" + return output_row + + output = "\n" + output += " \n" + output += table_row(meta.headers, False, "th") + output += " \n" + output += " \n" + output += "".join( + table_row(self.outputline_texts(line), line[1].is_data_ref, "td") + for line in lines + ) + output += " \n" + output += "
\n" + return output + + +@dataclass +class JsonFormatter(Formatter): + arch_str: str + + def apply_format(self, chunk: str, f: Format) -> str: + # This method is unused by this formatter + return NotImplemented + + def table(self, meta: TableMetadata, rows: List[Tuple["OutputLine", ...]]) -> str: + def serialize_format(s: str, f: Format) -> Dict[str, Any]: + if f == BasicFormat.NONE: + return {"text": s} + elif isinstance(f, BasicFormat): + return {"text": s, "format": f.name.lower()} + elif isinstance(f, RotationFormat): + attrs = asdict(f) + attrs.update( + { + "text": s, + "format": "rotation", + } + ) + return attrs + else: + static_assert_unreachable(f) + + def serialize(text: Optional[Text]) -> List[Dict[str, Any]]: + if text is None: + return [] + return [serialize_format(s, f) for s, f in text.segments] + + is_threeway = len(meta.headers) == 3 + + output: Dict[str, Any] = {} + output["arch_str"] = self.arch_str + output["header"] = { + name: serialize(h) + for h, name in zip(meta.headers, ("base", "current", "previous")) + } + output["current_score"] = meta.current_score + output["max_score"] = meta.max_score + if meta.previous_score is not None: + output["previous_score"] = meta.previous_score + output_rows: List[Dict[str, Any]] = [] + for row in rows: + output_row: Dict[str, Any] = {} + output_row["key"] = row[0].key2 + output_row["is_data_ref"] = row[1].is_data_ref + iters = [ + ("base", row[0].base, row[0].line1), + ("current", row[1].fmt2, row[1].line2), + ] + if is_threeway: + iters.append(("previous", row[2].fmt2, row[2].line2)) + if all(line is None for _, _, line in iters): + # Skip rows that were only for displaying source code + continue + for column_name, text, line in iters: + column: Dict[str, Any] = {} + column["text"] = serialize(text) + if line: + if line.line_num is not None: + column["line"] = line.line_num + if line.branch_target is not None: + column["branch"] = line.branch_target + if line.source_lines: + column["src"] = line.source_lines + if line.comment is not None: + column["src_comment"] = line.comment + if line.source_line_num is not None: + column["src_line"] = line.source_line_num + if line or column["text"]: + output_row[column_name] = column + output_rows.append(output_row) + output["rows"] = output_rows + return json.dumps(output) + + +def format_fields( + pat: Pattern[str], + out1: Text, + out2: Text, + color1: FormatFunction, + color2: Optional[FormatFunction] = None, +) -> Tuple[Text, Text]: + diffs = [ + of.group() != nf.group() + for (of, nf) in zip(out1.finditer(pat), out2.finditer(pat)) + ] + + it = iter(diffs) + + def maybe_color(color: FormatFunction, s: str) -> Text: + return Text(s, color(s)) if next(it, False) else Text(s) + + out1 = out1.sub(pat, lambda m: maybe_color(color1, m.group())) + it = iter(diffs) + out2 = out2.sub(pat, lambda m: maybe_color(color2 or color1, m.group())) + + return out1, out2 + + +def symbol_formatter(group: str, base_index: int) -> FormatFunction: + symbol_formats: Dict[str, Format] = {} + + def symbol_format(s: str) -> Format: + # TODO: it would be nice to use a unique Format for each symbol, so we could + # add extra UI elements in the HTML version + f = symbol_formats.get(s) + if f is None: + index = len(symbol_formats) + base_index + f = RotationFormat(key=s, index=index, group=group) + symbol_formats[s] = f + return f + + return symbol_format + + +# ==== LOGIC ==== + +ObjdumpCommand = Tuple[List[str], str, Optional[str]] + + +def maybe_eval_int(expr: str) -> Optional[int]: + try: + ret = ast.literal_eval(expr) + if not isinstance(ret, int): + raise Exception("not an integer") + return ret + except Exception: + return None + + +def eval_int(expr: str, emsg: str) -> int: + ret = maybe_eval_int(expr) + if ret is None: + fail(emsg) + return ret + + +def eval_line_num(expr: str) -> Optional[int]: + expr = expr.strip().replace(":", "") + if expr == "": + return None + return int(expr, 16) + + +def run_make(target: str, project: ProjectSettings) -> None: + subprocess.check_call(project.build_command + [target]) + + +def run_make_capture_output( + target: str, project: ProjectSettings +) -> "subprocess.CompletedProcess[bytes]": + return subprocess.run( + project.build_command + [target], + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + +def restrict_to_function(dump: str, fn_name: str) -> str: + try: + ind = dump.index("\n", dump.index(f"<{fn_name}>:")) + return dump[ind + 1 :] + except ValueError: + return "" + + +def serialize_data_references(references: List[Tuple[int, int, str]]) -> str: + return "".join( + f"DATAREF {text_offset} {from_offset} {from_section}\n" + for (text_offset, from_offset, from_section) in references + ) + + +def maybe_get_objdump_source_flags(config: Config) -> List[str]: + flags = [] + + if config.show_line_numbers or config.show_source: + flags.append("--line-numbers") + + if config.show_source: + flags.append("--source") + + if not config.source_old_binutils: + flags.append("--source-comment=│ ") + + if config.inlines: + flags.append("--inlines") + + return flags + + +def run_objdump(cmd: ObjdumpCommand, config: Config, project: ProjectSettings) -> str: + flags, target, restrict = cmd + try: + out = subprocess.run( + [project.objdump_executable] + config.arch.arch_flags + flags + [target], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ).stdout + except subprocess.CalledProcessError as e: + print(e.stdout) + print(e.stderr) + if "unrecognized option '--source-comment" in e.stderr: + fail("** Try using --source-old-binutils instead of --source **") + raise e + + obj_data: Optional[bytes] = None + if config.diff_obj: + with open(target, "rb") as f: + obj_data = f.read() + + return preprocess_objdump_out(restrict, obj_data, out, config) + + +def preprocess_objdump_out( + restrict: Optional[str], obj_data: Optional[bytes], objdump_out: str, config: Config +) -> str: + """ + Preprocess the output of objdump into a format that `process()` expects. + This format is suitable for saving to disk with `--write-asm`. + + - Optionally filter the output to a single function (`restrict`) + - Otherwise, strip objdump header (7 lines) + - Prepend .data references ("DATAREF" lines) when working with object files + """ + out = objdump_out + + if restrict is not None: + out = restrict_to_function(out, restrict) + else: + for i in range(7): + out = out[out.find("\n") + 1 :] + out = out.rstrip("\n") + + if obj_data: + out = serialize_data_references(parse_elf_data_references(obj_data, config)) + out + + return out + + +def search_map_file( + fn_name: str, project: ProjectSettings, config: Config +) -> Tuple[Optional[str], Optional[int]]: + if not project.mapfile: + fail(f"No map file configured; cannot find function {fn_name}.") + + try: + with open(project.mapfile) as f: + contents = f.read() + except Exception: + fail(f"Failed to open map file {project.mapfile} for reading.") + + if project.map_format == "gnu": + lines = contents.split("\n") + + try: + cur_objfile = None + ram_to_rom = None + cands = [] + last_line = "" + for line in lines: + if line.startswith(" " + config.diff_section): + cur_objfile = line.split()[3] + if "load address" in line: + tokens = last_line.split() + line.split() + ram = int(tokens[1], 0) + rom = int(tokens[5], 0) + ram_to_rom = rom - ram + if line.endswith(" " + fn_name): + ram = int(line.split()[0], 0) + if cur_objfile is not None and ram_to_rom is not None: + cands.append((cur_objfile, ram + ram_to_rom)) + last_line = line + except Exception as e: + traceback.print_exc() + fail(f"Internal error while parsing map file") + + if len(cands) > 1: + fail(f"Found multiple occurrences of function {fn_name} in map file.") + if len(cands) == 1: + return cands[0] + elif project.map_format == "mw": + section_pattern = re.escape(config.diff_section) + find = re.findall( + re.compile( + # ram elf rom + r" \S+ \S+ (\S+) (\S+) . " + + fn_name + # object name + + r"(?: \(entry of " + section_pattern + r"\))? \t(\S+)" + ), + contents, + ) + if len(find) > 1: + fail(f"Found multiple occurrences of function {fn_name} in map file.") + if len(find) == 1: + rom = int(find[0][1], 16) + objname = find[0][2] + # The metrowerks linker map format does not contain the full object path, + # so we must complete it manually. + objfiles = [ + os.path.join(dirpath, f) + for dirpath, _, filenames in os.walk(project.mw_build_dir) + for f in filenames + if f == objname + ] + if len(objfiles) > 1: + all_objects = "\n".join(objfiles) + fail( + f"Found multiple objects of the same name {objname} in {project.mw_build_dir}, " + f"cannot determine which to diff against: \n{all_objects}" + ) + if len(objfiles) == 1: + objfile = objfiles[0] + # TODO Currently the ram-rom conversion only works for diffing ELF + # executables, but it would likely be more convenient to diff DOLs. + # At this time it is recommended to always use -o when running the diff + # script as this mode does not make use of the ram-rom conversion. + return objfile, rom + else: + fail(f"Linker map format {project.map_format} unrecognised.") + return None, None + + +def parse_elf_data_references(data: bytes, config: Config) -> List[Tuple[int, int, str]]: + e_ident = data[:16] + if e_ident[:4] != b"\x7FELF": + return [] + + SHT_SYMTAB = 2 + SHT_REL = 9 + SHT_RELA = 4 + + is_32bit = e_ident[4] == 1 + is_little_endian = e_ident[5] == 1 + str_end = "<" if is_little_endian else ">" + str_off = "I" if is_32bit else "Q" + sym_size = {"B": 1, "H": 2, "I": 4, "Q": 8} + + def read(spec: str, offset: int) -> Tuple[int, ...]: + spec = spec.replace("P", str_off) + size = struct.calcsize(spec) + return struct.unpack(str_end + spec, data[offset : offset + size]) + + ( + e_type, + e_machine, + e_version, + e_entry, + e_phoff, + e_shoff, + e_flags, + e_ehsize, + e_phentsize, + e_phnum, + e_shentsize, + e_shnum, + e_shstrndx, + ) = read("HHIPPPIHHHHHH", 16) + if e_type != 1: # relocatable + return [] + assert e_shoff != 0 + assert e_shnum != 0 # don't support > 0xFF00 sections + assert e_shstrndx != 0 + + @dataclass + class Section: + sh_name: int + sh_type: int + sh_flags: int + sh_addr: int + sh_offset: int + sh_size: int + sh_link: int + sh_info: int + sh_addralign: int + sh_entsize: int + + sections = [ + Section(*read("IIPPPPIIPP", e_shoff + i * e_shentsize)) for i in range(e_shnum) + ] + shstr = sections[e_shstrndx] + sec_name_offs = [shstr.sh_offset + s.sh_name for s in sections] + sec_names = [data[offset : data.index(b"\0", offset)] for offset in sec_name_offs] + + symtab_sections = [i for i in range(e_shnum) if sections[i].sh_type == SHT_SYMTAB] + assert len(symtab_sections) == 1 + symtab = sections[symtab_sections[0]] + + section_name = config.diff_section.encode("utf-8") + text_sections = [i for i in range(e_shnum) if sec_names[i] == section_name and sections[i].sh_size != 0] + if len(text_sections) != 1: + return [] + text_section = text_sections[0] + + ret: List[Tuple[int, int, str]] = [] + for s in sections: + if s.sh_type == SHT_REL or s.sh_type == SHT_RELA: + if s.sh_info == text_section: + # Skip section_name -> section_name references + continue + sec_name = sec_names[s.sh_info].decode("latin1") + if sec_name == ".mwcats.text": + # Skip Metrowerks CATS Utility section + continue + sec_base = sections[s.sh_info].sh_offset + for i in range(0, s.sh_size, s.sh_entsize): + if s.sh_type == SHT_REL: + r_offset, r_info = read("PP", s.sh_offset + i) + else: + r_offset, r_info, r_addend = read("PPP", s.sh_offset + i) + + if is_32bit: + r_sym = r_info >> 8 + r_type = r_info & 0xFF + sym_offset = symtab.sh_offset + symtab.sh_entsize * r_sym + st_name, st_value, st_size, st_info, st_other, st_shndx = read( + "IIIBBH", sym_offset + ) + else: + r_sym = r_info >> 32 + r_type = r_info & 0xFFFFFFFF + sym_offset = symtab.sh_offset + symtab.sh_entsize * r_sym + st_name, st_info, st_other, st_shndx, st_value, st_size = read( + "IBBHQQ", sym_offset + ) + if st_shndx == text_section: + if s.sh_type == SHT_REL: + if e_machine == 8 and r_type == 2: # R_MIPS_32 + (r_addend,) = read("I", sec_base + r_offset) + else: + continue + text_offset = (st_value + r_addend) & 0xFFFFFFFF + ret.append((text_offset, r_offset, sec_name)) + return ret + + +def dump_elf( + start: str, + end: Optional[str], + diff_elf_symbol: str, + config: Config, + project: ProjectSettings, +) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: + if not project.baseimg or not project.myimg: + fail("Missing myimg/baseimg in config.") + if config.base_shift: + fail("--base-shift not compatible with -e") + + start_addr = eval_int(start, "Start address must be an integer expression.") + + if end is not None: + end_addr = eval_int(end, "End address must be an integer expression.") + else: + end_addr = start_addr + config.max_function_size_bytes + + flags1 = [ + f"--start-address={start_addr}", + f"--stop-address={end_addr}", + ] + + if project.disassemble_all: + disassemble_flag = "-D" + else: + disassemble_flag = "-d" + + flags2 = [ + f"--disassemble={diff_elf_symbol}", + ] + + objdump_flags = [disassemble_flag, "-rz", "-j", config.diff_section] + return ( + project.myimg, + (objdump_flags + flags1, project.baseimg, None), + ( + objdump_flags + flags2 + maybe_get_objdump_source_flags(config), + project.myimg, + None, + ), + ) + + +def dump_objfile( + start: str, end: Optional[str], config: Config, project: ProjectSettings +) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: + if config.base_shift: + fail("--base-shift not compatible with -o") + if end is not None: + fail("end address not supported together with -o") + if start.startswith("0"): + fail("numerical start address not supported with -o; pass a function name") + + objfile, _ = search_map_file(start, project, config) + if not objfile: + fail("Not able to find .o file for function.") + + if config.make: + run_make(objfile, project) + + if not os.path.isfile(objfile): + fail(f"Not able to find .o file for function: {objfile} is not a file.") + + refobjfile = "expected/" + objfile + if not os.path.isfile(refobjfile): + fail(f'Please ensure an OK .o file exists at "{refobjfile}".') + + if project.disassemble_all: + disassemble_flag = "-D" + else: + disassemble_flag = "-d" + + objdump_flags = [disassemble_flag, "-rz", "-j", config.diff_section] + return ( + objfile, + (objdump_flags, refobjfile, start), + (objdump_flags + maybe_get_objdump_source_flags(config), objfile, start), + ) + + +def dump_binary( + start: str, end: Optional[str], config: Config, project: ProjectSettings +) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: + if not project.baseimg or not project.myimg: + fail("Missing myimg/baseimg in config.") + if config.make: + run_make(project.myimg, project) + start_addr = maybe_eval_int(start) + if start_addr is None: + _, start_addr = search_map_file(start, project, config) + if start_addr is None: + fail("Not able to find function in map file.") + if end is not None: + end_addr = eval_int(end, "End address must be an integer expression.") + else: + end_addr = start_addr + config.max_function_size_bytes + objdump_flags = ["-Dz", "-bbinary"] + ["-EB" if config.arch.big_endian else "-EL"] + flags1 = [ + f"--start-address={start_addr + config.base_shift}", + f"--stop-address={end_addr + config.base_shift}", + ] + flags2 = [f"--start-address={start_addr}", f"--stop-address={end_addr}"] + return ( + project.myimg, + (objdump_flags + flags1, project.baseimg, None), + (objdump_flags + flags2, project.myimg, None), + ) + +# Example: "ldr r4, [pc, #56] ; (4c )" +ARM32_LOAD_POOL_PATTERN = r"(ldr\s+r([0-9]|1[0-3]),\s+\[pc,.*;\s*)(\([a-fA-F0-9]+.*\))" + + +# The base class is a no-op. +class AsmProcessor: + def __init__(self, config: Config) -> None: + self.config = config + + def process_reloc(self, row: str, prev: str) -> str: + return prev + + def normalize(self, mnemonic: str, row: str) -> str: + """This should be called exactly once for each line.""" + arch = self.config.arch + row = self._normalize_arch_specific(mnemonic, row) + if self.config.ignore_large_imms and mnemonic not in arch.branch_instructions: + row = re.sub(self.config.arch.re_large_imm, "", row) + return row + + def _normalize_arch_specific(self, mnemonic: str, row: str) -> str: + return row + + def post_process(self, lines: List["Line"]) -> None: + return + + +class AsmProcessorMIPS(AsmProcessor): + def process_reloc(self, row: str, prev: str) -> str: + arch = self.config.arch + if "R_MIPS_NONE" in row: + # GNU as emits no-op relocations immediately after real ones when + # assembling with -mabi=64. Return without trying to parse 'imm' as an + # integer. + return prev + before, imm, after = parse_relocated_line(prev) + repl = row.split()[-1] + if imm != "0": + # MIPS uses relocations with addends embedded in the code as immediates. + # If there is an immediate, show it as part of the relocation. Ideally + # we'd show this addend in both %lo/%hi, but annoyingly objdump's output + # doesn't include enough information to pair up %lo's and %hi's... + # TODO: handle unambiguous cases where all addends for a symbol are the + # same, or show "+???". + mnemonic = prev.split()[0] + if ( + mnemonic in arch.instructions_with_address_immediates + and not imm.startswith("0x") + ): + imm = "0x" + imm + repl += "+" + imm if int(imm, 0) > 0 else imm + if "R_MIPS_LO16" in row: + repl = f"%lo({repl})" + elif "R_MIPS_HI16" in row: + # Ideally we'd pair up R_MIPS_LO16 and R_MIPS_HI16 to generate a + # correct addend for each, but objdump doesn't give us the order of + # the relocations, so we can't find the right LO16. :( + repl = f"%hi({repl})" + elif "R_MIPS_26" in row: + # Function calls + pass + elif "R_MIPS_PC16" in row: + # Branch to glabel. This gives confusing output, but there's not much + # we can do here. + pass + elif "R_MIPS_GPREL16" in row: + repl = f"%gp_rel({repl})" + else: + assert False, f"unknown relocation type '{row}' for line '{prev}'" + return before + repl + after + + +class AsmProcessorPPC(AsmProcessor): + def process_reloc(self, row: str, prev: str) -> str: + arch = self.config.arch + assert any( + r in row for r in ["R_PPC_REL24", "R_PPC_ADDR16", "R_PPC_EMB_SDA21"] + ), f"unknown relocation type '{row}' for line '{prev}'" + before, imm, after = parse_relocated_line(prev) + repl = row.split()[-1] + if "R_PPC_REL24" in row: + # function calls + pass + elif "R_PPC_ADDR16_HI" in row: + # absolute hi of addr + repl = f"{repl}@h" + elif "R_PPC_ADDR16_HA" in row: + # adjusted hi of addr + repl = f"{repl}@ha" + elif "R_PPC_ADDR16_LO" in row: + # lo of addr + repl = f"{repl}@l" + elif "R_PPC_ADDR16" in row: + # 16-bit absolute addr + if "+0x7" in repl: + # remove the very large addends as they are an artifact of (label-_SDA(2)_BASE_) + # computations and are unimportant in a diff setting. + if int(repl.split("+")[1], 16) > 0x70000000: + repl = repl.split("+")[0] + elif "R_PPC_EMB_SDA21" in row: + # small data area + pass + return before + repl + after + + +class AsmProcessorARM32(AsmProcessor): + def process_reloc(self, row: str, prev: str) -> str: + arch = self.config.arch + before, imm, after = parse_relocated_line(prev) + repl = row.split()[-1] + return before + repl + after + + def _normalize_arch_specific(self, mnemonic: str, row: str) -> str: + if self.config.ignore_addr_diffs: + row = self._normalize_bl(mnemonic, row) + row = self._normalize_data_pool(row) + return row + + def _normalize_bl(self, mnemonic: str, row: str) -> str: + if mnemonic != "bl": + return row + + row, _ = split_off_address(row) + return row + "" + + def _normalize_data_pool(self, row: str) -> str: + pool_match = re.search(ARM32_LOAD_POOL_PATTERN, row) + return pool_match.group(1) if pool_match else row + + def post_process(self, lines: List["Line"]) -> None: + lines_by_line_number = {} + for line in lines: + lines_by_line_number[line.line_num] = line + for line in lines: + if line.data_pool_addr is None: + continue + + # Add data symbol and its address to the line. + line_original = lines_by_line_number[line.data_pool_addr].original + value = line_original.split()[1] + addr = "{:x}".format(line.data_pool_addr) + line.original = line.normalized_original + f"={value} ({addr})" + + +class AsmProcessorAArch64(AsmProcessor): + def __init__(self, config: Config) -> None: + super().__init__(config) + self._adrp_pair_registers: Set[str] = set() + + def _normalize_arch_specific(self, mnemonic: str, row: str) -> str: + if self.config.ignore_addr_diffs: + row = self._normalize_adrp_differences(mnemonic, row) + row = self._normalize_bl(mnemonic, row) + return row + + def _normalize_bl(self, mnemonic: str, row: str) -> str: + if mnemonic != "bl": + return row + + row, _ = split_off_address(row) + return row + "" + + def _normalize_adrp_differences(self, mnemonic: str, row: str) -> str: + """Identifies ADRP + LDR/ADD pairs that are used to access the GOT and + suppresses any immediate differences. + + Whenever an ADRP is seen, the destination register is added to the set of registers + that are part of an ADRP + LDR/ADD pair. Registers are removed from the set as soon + as they are used for an LDR or ADD instruction which completes the pair. + + This method is somewhat crude but should manage to detect most such pairs. + """ + row_parts = row.split("\t", 1) + if mnemonic == "adrp": + self._adrp_pair_registers.add(row_parts[1].strip().split(",")[0]) + row, _ = split_off_address(row) + return row + "" + elif mnemonic == "ldr": + for reg in self._adrp_pair_registers: + # ldr xxx, [reg] + # ldr xxx, [reg, ] + if f", [{reg}" in row_parts[1]: + self._adrp_pair_registers.remove(reg) + return normalize_imms(row, AARCH64_SETTINGS) + elif mnemonic == "add": + for reg in self._adrp_pair_registers: + # add reg, reg, + if row_parts[1].startswith(f"{reg}, {reg}, "): + self._adrp_pair_registers.remove(reg) + return normalize_imms(row, AARCH64_SETTINGS) + + return row + + +@dataclass +class ArchSettings: + name: str + re_int: Pattern[str] + re_comment: Pattern[str] + re_reg: Pattern[str] + re_sprel: Pattern[str] + re_large_imm: Pattern[str] + re_imm: Pattern[str] + re_reloc: Pattern[str] + branch_instructions: Set[str] + instructions_with_address_immediates: Set[str] + forbidden: Set[str] = field(default_factory=lambda: set(string.ascii_letters + "_")) + arch_flags: List[str] = field(default_factory=list) + branch_likely_instructions: Set[str] = field(default_factory=set) + proc: Type[AsmProcessor] = AsmProcessor + big_endian: Optional[bool] = True + delay_slot_instructions: Set[str] = field(default_factory=set) + +MIPS_BRANCH_LIKELY_INSTRUCTIONS = { + "beql", + "bnel", + "beqzl", + "bnezl", + "bgezl", + "bgtzl", + "blezl", + "bltzl", + "bc1tl", + "bc1fl", +} +MIPS_BRANCH_INSTRUCTIONS = MIPS_BRANCH_LIKELY_INSTRUCTIONS.union( + { + "b", + "beq", + "bne", + "beqz", + "bnez", + "bgez", + "bgtz", + "blez", + "bltz", + "bc1t", + "bc1f", + } +) + +ARM32_PREFIXES = {"b", "bl"} +ARM32_CONDS = { + "", + "eq", + "ne", + "cs", + "cc", + "mi", + "pl", + "vs", + "vc", + "hi", + "ls", + "ge", + "lt", + "gt", + "le", + "al", +} +ARM32_SUFFIXES = {"", ".n", ".w"} +ARM32_BRANCH_INSTRUCTIONS = { + f"{prefix}{cond}{suffix}" + for prefix in ARM32_PREFIXES + for cond in ARM32_CONDS + for suffix in ARM32_SUFFIXES +} + +AARCH64_BRANCH_INSTRUCTIONS = { + "b", + "b.eq", + "b.ne", + "b.cs", + "b.hs", + "b.cc", + "b.lo", + "b.mi", + "b.pl", + "b.vs", + "b.vc", + "b.hi", + "b.ls", + "b.ge", + "b.lt", + "b.gt", + "b.le", + "cbz", + "cbnz", + "tbz", + "tbnz", +} + +PPC_BRANCH_INSTRUCTIONS = { + "b", + "beq", + "beq+", + "beq-", + "bne", + "bne+", + "bne-", + "blt", + "blt+", + "blt-", + "ble", + "ble+", + "ble-", + "bdnz", + "bdnz+", + "bdnz-", + "bge", + "bge+", + "bge-", + "bgt", + "bgt+", + "bgt-", +} + +MIPS_SETTINGS = ArchSettings( + name="mips", + re_int=re.compile(r"[0-9]+"), + re_comment=re.compile(r"<.*?>"), + re_reg=re.compile( + r"\$?\b(a[0-7]|t[0-9]|s[0-8]|at|v[01]|f[12]?[0-9]|f3[01]|kt?[01]|fp|ra|zero)\b" + ), + re_sprel=re.compile(r"(?<=,)([0-9]+|0x[0-9a-f]+)\(sp\)"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile(r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(sp)|%(lo|hi)\([^)]*\)"), + re_reloc=re.compile(r"R_MIPS_"), + arch_flags=["-m", "mips:4300"], + branch_likely_instructions=MIPS_BRANCH_LIKELY_INSTRUCTIONS, + branch_instructions=MIPS_BRANCH_INSTRUCTIONS, + instructions_with_address_immediates=MIPS_BRANCH_INSTRUCTIONS.union({"jal", "j"}), + delay_slot_instructions=MIPS_BRANCH_INSTRUCTIONS.union({"j", "jal", "jr", "jalr"}), + proc=AsmProcessorMIPS, +) + +MIPSEL_SETTINGS = replace(MIPS_SETTINGS, name="mipsel", big_endian=False) + +ARM32_SETTINGS = ArchSettings( + name="arm32", + re_int=re.compile(r"[0-9]+"), + re_comment=re.compile(r"(<.*?>|//.*$)"), + # Includes: + # - General purpose registers: r0..13 + # - Frame pointer registers: lr (r14), pc (r15) + # - VFP/NEON registers: s0..31, d0..31, q0..15, fpscr, fpexc, fpsid + # SP should not be in this list. + re_reg=re.compile( + r"\$?\b([rq][0-9]|[rq]1[0-5]|pc|lr|[ds][12]?[0-9]|[ds]3[01]|fp(scr|exc|sid))\b" + ), + re_sprel=re.compile(r"sp, #-?(0x[0-9a-fA-F]+|[0-9]+)\b"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile(r"(?|//.*$)"), + # GPRs and FP registers: X0-X30, W0-W30, [BHSDVQ]0..31 + # (FP registers may be followed by data width and number of elements, e.g. V0.4S) + # The zero registers and SP should not be in this list. + re_reg=re.compile(r"\$?\b([bhsdvq]([12]?[0-9]|3[01])(\.\d\d?[bhsdvq])?|[xw][12]?[0-9]|[xw]30)\b"), + re_sprel=re.compile(r"sp, #-?(0x[0-9a-fA-F]+|[0-9]+)\b"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile(r"(?|//.*$)"), + re_reg=re.compile(r"\$?\b([rf][0-9]+)\b"), + re_sprel=re.compile(r"(?<=,)(-?[0-9]+|-?0x[0-9a-f]+)\(r1\)"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile(r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(r1)|[^@]*@(ha|h|lo)"), + re_reloc=re.compile(r"R_PPC_"), + branch_instructions=PPC_BRANCH_INSTRUCTIONS, + instructions_with_address_immediates=PPC_BRANCH_INSTRUCTIONS.union({"bl"}), + proc=AsmProcessorPPC, +) + +ARCH_SETTINGS = [ + MIPS_SETTINGS, + MIPSEL_SETTINGS, + ARM32_SETTINGS, + ARMEL_SETTINGS, + AARCH64_SETTINGS, + PPC_SETTINGS, +] + + +def hexify_int(row: str, pat: Match[str], arch: ArchSettings) -> str: + full = pat.group(0) + if len(full) <= 1: + # leave one-digit ints alone + return full + start, end = pat.span() + if start and row[start - 1] in arch.forbidden: + return full + if end < len(row) and row[end] in arch.forbidden: + return full + return hex(int(full)) + + +def parse_relocated_line(line: str) -> Tuple[str, str, str]: + for c in ",\t ": + if c in line: + ind2 = line.rindex(c) + break + else: + raise Exception(f"failed to parse relocated line: {line}") + before = line[: ind2 + 1] + after = line[ind2 + 1 :] + ind2 = after.find("(") + if ind2 == -1: + imm, after = after, "" + else: + imm, after = after[:ind2], after[ind2:] + if imm == "0x0": + imm = "0" + return before, imm, after + + +def pad_mnemonic(line: str) -> str: + if "\t" not in line: + return line + mn, args = line.split("\t", 1) + return f"{mn:<7s} {args}" + + +@dataclass +class Line: + mnemonic: str + diff_row: str + original: str + normalized_original: str + scorable_line: str + line_num: Optional[int] = None + branch_target: Optional[int] = None + data_pool_addr: Optional[int] = None + source_filename: Optional[str] = None + source_line_num: Optional[int] = None + source_lines: List[str] = field(default_factory=list) + comment: Optional[str] = None + + +def process(dump: str, config: Config) -> List[Line]: + arch = config.arch + processor = arch.proc(config) + skip_next = False + source_lines = [] + source_filename = None + source_line_num = None + + i = 0 + num_instr = 0 + data_refs: Dict[int, Dict[str, List[int]]] = defaultdict(lambda: defaultdict(list)) + output: List[Line] = [] + stop_after_delay_slot = False + lines = dump.split("\n") + while i < len(lines): + row = lines[i] + i += 1 + + if not row: + continue + + if re.match(r"^[0-9a-f]+ <.*>:$", row): + continue + + if row.startswith("DATAREF"): + parts = row.split(" ", 3) + text_offset = int(parts[1]) + from_offset = int(parts[2]) + from_section = parts[3] + data_refs[text_offset][from_section].append(from_offset) + continue + + if config.diff_obj and num_instr >= config.max_function_size_lines: + output.append( + Line( + mnemonic="...", + diff_row="...", + original="...", + normalized_original="...", + scorable_line="...", + ) + ) + break + + if not re.match(r"^\s+[0-9a-f]+:\s+", row): + # This regex is conservative, and assumes the file path does not contain "weird" + # characters like colons, tabs, or angle brackets. + if re.match( + r"^[^ \t<>:][^\t<>:]*:[0-9]+( \(discriminator [0-9]+\))?$", row + ): + source_filename, _, tail = row.rpartition(":") + source_line_num = int(tail.partition(" ")[0]) + source_lines.append(row) + continue + + # If the instructions loads a data pool symbol, extract the address of + # the symbol. + data_pool_addr = None + pool_match = re.search(ARM32_LOAD_POOL_PATTERN, row) + if pool_match: + offset = pool_match.group(3).split(" ")[0][1:] + data_pool_addr = int(offset, 16) + + m_comment = re.search(arch.re_comment, row) + comment = m_comment[0] if m_comment else None + row = re.sub(arch.re_comment, "", row) + line_num_str = row.split(":")[0] + row = row.rstrip() + tabs = row.split("\t") + row = "\t".join(tabs[2:]) + line_num = eval_line_num(line_num_str.strip()) + + if line_num in data_refs: + refs = data_refs[line_num] + ref_str = "; ".join( + section_name + "+" + ",".join(hex(off) for off in offs) + for section_name, offs in refs.items() + ) + output.append( + Line( + mnemonic="", + diff_row="", + original=ref_str, + normalized_original=ref_str, + scorable_line="", + ) + ) + + if "\t" in row: + row_parts = row.split("\t", 1) + else: + # powerpc-eabi-objdump doesn't use tabs + row_parts = [part.lstrip() for part in row.split(" ", 1)] + mnemonic = row_parts[0].strip() + + if mnemonic not in arch.instructions_with_address_immediates: + row = re.sub(arch.re_int, lambda m: hexify_int(row, m, arch), row) + + # Let 'original' be 'row' with relocations applied, while we continue + # transforming 'row' into a coarser version that ignores registers and + # immediates. + original = row + + while i < len(lines): + reloc_row = lines[i] + if re.search(arch.re_reloc, reloc_row): + original = processor.process_reloc(reloc_row, original) + else: + break + i += 1 + + normalized_original = processor.normalize(mnemonic, original) + + scorable_line = normalized_original + if not config.score_stack_differences: + scorable_line = re.sub(arch.re_sprel, "addr(sp)", scorable_line) + if mnemonic in arch.branch_instructions: + # Replace the final argument with "" + scorable_line = re.sub(r"[^, \t]+$", "", scorable_line) + + if skip_next: + skip_next = False + row = "" + mnemonic = "" + scorable_line = "" + if mnemonic in arch.branch_likely_instructions: + skip_next = True + + row = re.sub(arch.re_reg, "", row) + row = re.sub(arch.re_sprel, "addr(sp)", row) + row_with_imm = row + if mnemonic in arch.instructions_with_address_immediates: + row = row.strip() + row, _ = split_off_address(row) + row += "" + else: + row = normalize_imms(row, arch) + + branch_target = None + if mnemonic in arch.branch_instructions: + branch_target = int(row_parts[1].strip().split(",")[-1], 16) + if mnemonic in arch.branch_likely_instructions: + branch_target -= 4 + + output.append( + Line( + mnemonic=mnemonic, + diff_row=row, + original=original, + normalized_original=normalized_original, + scorable_line=scorable_line, + line_num=line_num, + branch_target=branch_target, + data_pool_addr=data_pool_addr, + source_filename=source_filename, + source_line_num=source_line_num, + source_lines=source_lines, + comment=comment, + ) + ) + num_instr += 1 + source_lines = [] + + if config.stop_jrra and mnemonic == "jr" and row_parts[1].strip() == "ra": + stop_after_delay_slot = True + elif stop_after_delay_slot: + break + + processor.post_process(output) + return output + + +def normalize_imms(row: str, arch: ArchSettings) -> str: + return re.sub(arch.re_imm, "", row) + + +def normalize_stack(row: str, arch: ArchSettings) -> str: + return re.sub(arch.re_sprel, "addr(sp)", row) + + +def imm_matches_everything(row: str, arch: ArchSettings) -> bool: + # (this should probably be arch-specific) + return "(." in row + + +def split_off_address(line: str) -> Tuple[str, str]: + """Split e.g. 'beqz $r0,1f0' into 'beqz $r0,' and '1f0'.""" + parts = line.split(",") + if len(parts) < 2: + parts = line.split(None, 1) + off = len(line) - len(parts[-1]) + return line[:off], line[off:] + + +def diff_sequences_difflib( + seq1: List[str], seq2: List[str] +) -> List[Tuple[str, int, int, int, int]]: + differ = difflib.SequenceMatcher(a=seq1, b=seq2, autojunk=False) + return differ.get_opcodes() + + +def diff_sequences( + seq1: List[str], seq2: List[str], algorithm: str +) -> List[Tuple[str, int, int, int, int]]: + if ( + algorithm != "levenshtein" + or len(seq1) * len(seq2) > 4 * 10 ** 8 + or len(seq1) + len(seq2) >= 0x110000 + ): + return diff_sequences_difflib(seq1, seq2) + + # The Levenshtein library assumes that we compare strings, not lists. Convert. + # (Per the check above we know we have fewer than 0x110000 unique elements, so chr() works.) + remapping: Dict[str, str] = {} + + def remap(seq: List[str]) -> str: + seq = seq[:] + for i in range(len(seq)): + val = remapping.get(seq[i]) + if val is None: + val = chr(len(remapping)) + remapping[seq[i]] = val + seq[i] = val + return "".join(seq) + + rem1 = remap(seq1) + rem2 = remap(seq2) + import Levenshtein + + ret: List[Tuple[str, int, int, int, int]] = Levenshtein.opcodes(rem1, rem2) + return ret + + +def diff_lines( + lines1: List[Line], + lines2: List[Line], + algorithm: str, +) -> List[Tuple[Optional[Line], Optional[Line]]]: + ret = [] + for (tag, i1, i2, j1, j2) in diff_sequences( + [line.mnemonic for line in lines1], + [line.mnemonic for line in lines2], + algorithm, + ): + for line1, line2 in itertools.zip_longest(lines1[i1:i2], lines2[j1:j2]): + if tag == "replace": + if line1 is None: + tag = "insert" + elif line2 is None: + tag = "delete" + elif tag == "insert": + assert line1 is None + elif tag == "delete": + assert line2 is None + ret.append((line1, line2)) + + return ret + + +def score_diff_lines( + lines: List[Tuple[Optional[Line], Optional[Line]]], config: Config +) -> int: + # This logic is copied from `scorer.py` from the decomp permuter project + # https://github.com/simonlindholm/decomp-permuter/blob/main/src/scorer.py + score = 0 + deletions = [] + insertions = [] + + def lo_hi_match(old: str, new: str) -> bool: + # TODO: Make this arch-independent, like `imm_matches_everything()` + old_lo = old.find("%lo") + old_hi = old.find("%hi") + new_lo = new.find("%lo") + new_hi = new.find("%hi") + + if old_lo != -1 and new_lo != -1: + old_idx = old_lo + new_idx = new_lo + elif old_hi != -1 and new_hi != -1: + old_idx = old_hi + new_idx = new_hi + else: + return False + + if old[:old_idx] != new[:new_idx]: + return False + + old_inner = old[old_idx + 4 : -1] + new_inner = new[new_idx + 4 : -1] + return old_inner.startswith(".") or new_inner.startswith(".") + + def diff_sameline(old: str, new: str) -> None: + nonlocal score + if old == new: + return + + if lo_hi_match(old, new): + return + + ignore_last_field = False + if config.score_stack_differences: + oldsp = re.search(config.arch.re_sprel, old) + newsp = re.search(config.arch.re_sprel, new) + if oldsp and newsp: + oldrel = int(oldsp.group(1) or "0", 0) + newrel = int(newsp.group(1) or "0", 0) + score += abs(oldrel - newrel) * config.penalty_stackdiff + ignore_last_field = True + + # Probably regalloc difference, or signed vs unsigned + + # Compare each field in order + newfields, oldfields = new.split(","), old.split(",") + if ignore_last_field: + newfields = newfields[:-1] + oldfields = oldfields[:-1] + for nf, of in zip(newfields, oldfields): + if nf != of: + score += config.penalty_regalloc + # Penalize any extra fields + score += abs(len(newfields) - len(oldfields)) * config.penalty_regalloc + + def diff_insert(line: str) -> None: + # Reordering or totally different codegen. + # Defer this until later when we can tell. + insertions.append(line) + + def diff_delete(line: str) -> None: + deletions.append(line) + + # Find the end of the last long streak of matching mnemonics, if it looks + # like the objdump output was truncated. This is used to skip scoring + # misaligned lines at the end of the diff. + last_mismatch = -1 + max_index = None + lines_were_truncated = False + for index, (line1, line2) in enumerate(lines): + if (line1 and line1.original == "...") or (line2 and line2.original == "..."): + lines_were_truncated = True + if line1 and line2 and line1.mnemonic == line2.mnemonic: + if index - last_mismatch >= 50: + max_index = index + else: + last_mismatch = index + if not lines_were_truncated: + max_index = None + + for index, (line1, line2) in enumerate(lines): + if max_index is not None and index > max_index: + break + if line1 and line2 and line1.mnemonic == line2.mnemonic: + diff_sameline(line1.scorable_line, line2.scorable_line) + else: + if line1: + diff_delete(line1.scorable_line) + if line2: + diff_insert(line2.scorable_line) + + insertions_co = Counter(insertions) + deletions_co = Counter(deletions) + for item in insertions_co + deletions_co: + ins = insertions_co[item] + dels = deletions_co[item] + common = min(ins, dels) + score += ( + (ins - common) * config.penalty_insertion + + (dels - common) * config.penalty_deletion + + config.penalty_reordering * common + ) + + return score + + +@dataclass(frozen=True) +class OutputLine: + base: Optional[Text] = field(compare=False) + fmt2: Text = field(compare=False) + key2: Optional[str] + boring: bool = field(compare=False) + is_data_ref: bool = field(compare=False) + line1: Optional[Line] = field(compare=False) + line2: Optional[Line] = field(compare=False) + + +@dataclass(frozen=True) +class Diff: + lines: List[OutputLine] + score: int + max_score: int + + +def trim_nops(lines: List[Line], arch: ArchSettings) -> List[Line]: + lines = lines[:] + while lines and lines[-1].mnemonic == "nop" and (len(lines) == 1 or lines[-2].mnemonic not in arch.delay_slot_instructions): + lines.pop() + return lines + +def do_diff(lines1: List[Line], lines2: List[Line], config: Config) -> Diff: + if config.show_source: + import cxxfilt + arch = config.arch + fmt = config.formatter + output: List[OutputLine] = [] + + sc1 = symbol_formatter("base-reg", 0) + sc2 = symbol_formatter("my-reg", 0) + sc3 = symbol_formatter("base-stack", 4) + sc4 = symbol_formatter("my-stack", 4) + sc5 = symbol_formatter("base-branch", 0) + sc6 = symbol_formatter("my-branch", 0) + bts1: Set[int] = set() + bts2: Set[int] = set() + + if config.show_branches: + for (lines, btset, sc) in [ + (lines1, bts1, sc5), + (lines2, bts2, sc6), + ]: + for line in lines: + bt = line.branch_target + if bt is not None: + btset.add(bt) + sc(str(bt)) + + lines1 = trim_nops(lines1, arch) + lines2 = trim_nops(lines2, arch) + + diffed_lines = diff_lines(lines1, lines2, config.algorithm) + score = score_diff_lines(diffed_lines, config) + max_score = len(lines1) * config.penalty_deletion + + line_num_base = -1 + line_num_offset = 0 + line_num_2to1 = {} + for (line1, line2) in diffed_lines: + if line1 is not None and line1.line_num is not None: + line_num_base = line1.line_num + line_num_offset = 0 + else: + line_num_offset += 1 + if line2 is not None and line2.line_num is not None: + line_num_2to1[line2.line_num] = (line_num_base, line_num_offset) + + for (line1, line2) in diffed_lines: + line_color1 = line_color2 = sym_color = BasicFormat.NONE + line_prefix = " " + is_data_ref = False + out1 = Text() if not line1 else Text(pad_mnemonic(line1.original)) + out2 = Text() if not line2 else Text(pad_mnemonic(line2.original)) + if line1 and line2 and line1.diff_row == line2.diff_row: + if line1.diff_row == "": + if line1.normalized_original != line2.normalized_original: + line_prefix = "i" + sym_color = BasicFormat.DIFF_CHANGE + out1 = out1.reformat(sym_color) + out2 = out2.reformat(sym_color) + is_data_ref = True + elif ( + line1.normalized_original == line2.normalized_original + and line2.branch_target is None + ): + # Fast path: no coloring needed. We don't include branch instructions + # in this case because we need to check that their targets line up in + # the diff, and don't just happen to have the are the same address + # by accident. + pass + elif line1.diff_row == "": + # Don't draw attention to differing branch-likely delay slots: they + # typically mirror the branch destination - 1 so the real difference + # is elsewhere. Still, do mark them as different to avoid confusion. + # No need to consider branches because delay slots can't branch. + out1 = out1.reformat(BasicFormat.DELAY_SLOT) + out2 = out2.reformat(BasicFormat.DELAY_SLOT) + else: + mnemonic = line1.original.split()[0] + branchless1, address1 = out1.plain(), "" + branchless2, address2 = out2.plain(), "" + if mnemonic in arch.instructions_with_address_immediates: + branchless1, address1 = split_off_address(branchless1) + branchless2, address2 = split_off_address(branchless2) + + out1 = Text(branchless1) + out2 = Text(branchless2) + out1, out2 = format_fields( + arch.re_imm, out1, out2, lambda _: BasicFormat.IMMEDIATE + ) + + if line2.branch_target is not None: + target = line2.branch_target + line2_target = line_num_2to1.get(line2.branch_target) + if line2_target is None: + # If the target is outside the disassembly, extrapolate. + # This only matters near the bottom. + assert line2.line_num is not None + line2_line = line_num_2to1[line2.line_num] + line2_target = (line2_line[0] + (target - line2.line_num), 0) + + # Set the key for three-way diffing to a normalized version. + norm2, norm_branch2 = split_off_address(line2.normalized_original) + if norm_branch2 != "": + line2.normalized_original = norm2 + str(line2_target) + same_target = line2_target == (line1.branch_target, 0) + else: + # Do a naive comparison for non-branches (e.g. function calls). + same_target = address1 == address2 + + if normalize_imms(branchless1, arch) == normalize_imms( + branchless2, arch + ): + if imm_matches_everything(branchless2, arch): + # ignore differences due to %lo(.rodata + ...) vs symbol + out1 = out1.reformat(BasicFormat.NONE) + out2 = out2.reformat(BasicFormat.NONE) + elif line2.branch_target is not None and same_target: + # same-target branch, don't color + pass + else: + # must have an imm difference (or else we would have hit the + # fast path) + sym_color = BasicFormat.IMMEDIATE + line_prefix = "i" + else: + out1, out2 = format_fields(arch.re_sprel, out1, out2, sc3, sc4) + if normalize_stack(branchless1, arch) == normalize_stack( + branchless2, arch + ): + # only stack differences (luckily stack and imm + # differences can't be combined in MIPS, so we + # don't have to think about that case) + sym_color = BasicFormat.STACK + line_prefix = "s" + else: + # reg differences and maybe imm as well + out1, out2 = format_fields(arch.re_reg, out1, out2, sc1, sc2) + line_color1 = line_color2 = sym_color = BasicFormat.REGISTER + line_prefix = "r" + + if same_target: + address_imm_fmt = BasicFormat.NONE + else: + address_imm_fmt = BasicFormat.IMMEDIATE + out1 += Text(address1, address_imm_fmt) + out2 += Text(address2, address_imm_fmt) + elif line1 and line2: + line_prefix = "|" + line_color1 = line_color2 = sym_color = BasicFormat.DIFF_CHANGE + out1 = out1.reformat(line_color1) + out2 = out2.reformat(line_color2) + elif line1: + line_prefix = "<" + line_color1 = sym_color = BasicFormat.DIFF_REMOVE + out1 = out1.reformat(line_color1) + out2 = Text() + elif line2: + line_prefix = ">" + line_color2 = sym_color = BasicFormat.DIFF_ADD + out1 = Text() + out2 = out2.reformat(line_color2) + + if config.show_source and line2 and line2.comment: + out2 += f" {line2.comment}" + + def format_part( + out: Text, + line: Optional[Line], + line_color: Format, + btset: Set[int], + sc: FormatFunction, + ) -> Optional[Text]: + if line is None: + return None + if line.line_num is None: + return out + in_arrow = Text(" ") + out_arrow = Text() + if config.show_branches: + if line.line_num in btset: + in_arrow = Text("~>", sc(str(line.line_num))) + if line.branch_target is not None: + out_arrow = " " + Text("~>", sc(str(line.branch_target))) + formatted_line_num = Text(hex(line.line_num)[2:] + ":", line_color) + return formatted_line_num + " " + in_arrow + " " + out + out_arrow + + part1 = format_part(out1, line1, line_color1, bts1, sc5) + part2 = format_part(out2, line2, line_color2, bts2, sc6) + + if config.show_source and line2: + for source_line in line2.source_lines: + line_format = BasicFormat.SOURCE_OTHER + if config.source_old_binutils: + if source_line and re.fullmatch(".*\.c(?:pp)?:\d+", source_line): + line_format = BasicFormat.SOURCE_FILENAME + elif source_line and source_line.endswith("():"): + line_format = BasicFormat.SOURCE_FUNCTION + try: + source_line = cxxfilt.demangle( + source_line[:-3], external_only=False + ) + except: + pass + else: + # File names and function names + if source_line and source_line[0] != "│": + line_format = BasicFormat.SOURCE_FILENAME + # Function names + if source_line.endswith("():"): + line_format = BasicFormat.SOURCE_FUNCTION + try: + source_line = cxxfilt.demangle( + source_line[:-3], external_only=False + ) + except: + pass + padding = " " * 7 if config.show_line_numbers else " " * 2 + output.append( + OutputLine( + base=None, + fmt2=padding + Text(source_line, line_format), + key2=source_line, + boring=True, + is_data_ref=False, + line1=None, + line2=None, + ) + ) + + key2 = line2.normalized_original if line2 else None + boring = False + if line_prefix == " ": + boring = True + elif config.compress and config.compress.same_instr and line_prefix in "irs": + boring = True + + if config.show_line_numbers: + if line2 and line2.source_line_num is not None: + num_color = ( + BasicFormat.SOURCE_LINE_NUM + if sym_color == BasicFormat.NONE + else sym_color + ) + num2 = Text(f"{line2.source_line_num:5}", num_color) + else: + num2 = Text(" " * 5) + else: + num2 = Text() + + fmt2 = Text(line_prefix, sym_color) + num2 + " " + (part2 or Text()) + + output.append( + OutputLine( + base=part1, + fmt2=fmt2, + key2=key2, + boring=boring, + is_data_ref=is_data_ref, + line1=line1, + line2=line2, + ) + ) + + output = output[config.skip_lines :] + return Diff(lines=output, score=score, max_score=max_score) + + +def chunk_diff_lines( + diff: List[OutputLine], +) -> List[Union[List[OutputLine], OutputLine]]: + """Chunk a diff into an alternating list like A B A B ... A, where: + * A is a List[OutputLine] of insertions, + * B is a single non-insertion OutputLine, with .base != None.""" + cur_right: List[OutputLine] = [] + chunks: List[Union[List[OutputLine], OutputLine]] = [] + for output_line in diff: + if output_line.base is not None: + chunks.append(cur_right) + chunks.append(output_line) + cur_right = [] + else: + cur_right.append(output_line) + chunks.append(cur_right) + return chunks + + +def compress_matching( + li: List[Tuple[OutputLine, ...]], context: int +) -> List[Tuple[OutputLine, ...]]: + ret: List[Tuple[OutputLine, ...]] = [] + matching_streak: List[Tuple[OutputLine, ...]] = [] + context = max(context, 0) + + def flush_matching() -> None: + if len(matching_streak) <= 2 * context + 1: + ret.extend(matching_streak) + else: + ret.extend(matching_streak[:context]) + skipped = len(matching_streak) - 2 * context + filler = OutputLine( + base=Text(f"<{skipped} lines>", BasicFormat.SOURCE_OTHER), + fmt2=Text(), + key2=None, + boring=False, + is_data_ref=False, + line1=None, + line2=None, + ) + columns = len(matching_streak[0]) + ret.append(tuple([filler] * columns)) + if context > 0: + ret.extend(matching_streak[-context:]) + matching_streak.clear() + + for line in li: + if line[0].boring: + matching_streak.append(line) + else: + flush_matching() + ret.append(line) + + flush_matching() + return ret + + +def align_diffs( + old_diff: Diff, new_diff: Diff, config: Config +) -> Tuple[TableMetadata, List[Tuple[OutputLine, ...]]]: + meta: TableMetadata + diff_lines: List[Tuple[OutputLine, ...]] + padding = " " * 7 if config.show_line_numbers else " " * 2 + + if config.threeway: + meta = TableMetadata( + headers=( + Text("TARGET"), + Text(f"{padding}CURRENT ({new_diff.score})"), + Text(f"{padding}PREVIOUS ({old_diff.score})"), + ), + current_score=new_diff.score, + max_score=new_diff.max_score, + previous_score=old_diff.score, + ) + old_chunks = chunk_diff_lines(old_diff.lines) + new_chunks = chunk_diff_lines(new_diff.lines) + diff_lines = [] + empty = OutputLine(Text(), Text(), None, True, False, None, None) + assert len(old_chunks) == len(new_chunks), "same target" + for old_chunk, new_chunk in zip(old_chunks, new_chunks): + if isinstance(old_chunk, list): + assert isinstance(new_chunk, list) + if not old_chunk and not new_chunk: + # Most of the time lines sync up without insertions/deletions, + # and there's no interdiffing to be done. + continue + differ = difflib.SequenceMatcher( + a=old_chunk, b=new_chunk, autojunk=False + ) + for (tag, i1, i2, j1, j2) in differ.get_opcodes(): + if tag in ["equal", "replace"]: + for i, j in zip(range(i1, i2), range(j1, j2)): + diff_lines.append((empty, new_chunk[j], old_chunk[i])) + if tag in ["insert", "replace"]: + for j in range(j1 + i2 - i1, j2): + diff_lines.append((empty, new_chunk[j], empty)) + if tag in ["delete", "replace"]: + for i in range(i1 + j2 - j1, i2): + diff_lines.append((empty, empty, old_chunk[i])) + else: + assert isinstance(new_chunk, OutputLine) + # old_chunk.base and new_chunk.base have the same text since + # both diffs are based on the same target, but they might + # differ in color. Use the new version. + diff_lines.append((new_chunk, new_chunk, old_chunk)) + diff_lines = [ + (base, new, old if old != new else empty) for base, new, old in diff_lines + ] + else: + meta = TableMetadata( + headers=( + Text("TARGET"), + Text(f"{padding}CURRENT ({new_diff.score})"), + ), + current_score=new_diff.score, + max_score=new_diff.max_score, + previous_score=None, + ) + diff_lines = [(line, line) for line in new_diff.lines] + if config.compress: + diff_lines = compress_matching(diff_lines, config.compress.context) + return meta, diff_lines + + +def debounced_fs_watch( + targets: List[str], + outq: "queue.Queue[Optional[float]]", + config: Config, + project: ProjectSettings, +) -> None: + import watchdog.events + import watchdog.observers + + class WatchEventHandler(watchdog.events.FileSystemEventHandler): + def __init__( + self, queue: "queue.Queue[float]", file_targets: List[str] + ) -> None: + self.queue = queue + self.file_targets = file_targets + + def on_modified(self, ev: object) -> None: + if isinstance(ev, watchdog.events.FileModifiedEvent): + self.changed(ev.src_path) + + def on_moved(self, ev: object) -> None: + if isinstance(ev, watchdog.events.FileMovedEvent): + self.changed(ev.dest_path) + + def should_notify(self, path: str) -> bool: + for target in self.file_targets: + if os.path.normpath(path) == target: + return True + if config.make and any( + path.endswith(suffix) for suffix in project.source_extensions + ): + return True + return False + + def changed(self, path: str) -> None: + if self.should_notify(path): + self.queue.put(time.time()) + + def debounce_thread() -> NoReturn: + listenq: "queue.Queue[float]" = queue.Queue() + file_targets: List[str] = [] + event_handler = WatchEventHandler(listenq, file_targets) + observer = watchdog.observers.Observer() + observed = set() + for target in targets: + if os.path.isdir(target): + observer.schedule(event_handler, target, recursive=True) + else: + file_targets.append(os.path.normpath(target)) + target = os.path.dirname(target) or "." + if target not in observed: + observed.add(target) + observer.schedule(event_handler, target) + observer.start() + while True: + t = listenq.get() + more = True + while more: + delay = t + DEBOUNCE_DELAY - time.time() + if delay > 0: + time.sleep(delay) + # consume entire queue + more = False + try: + while True: + t = listenq.get(block=False) + more = True + except queue.Empty: + pass + outq.put(t) + + th = threading.Thread(target=debounce_thread, daemon=True) + th.start() + + +class Display: + basedump: str + mydump: str + last_refresh_key: object + config: Config + emsg: Optional[str] + last_diff_output: Optional[Diff] + pending_update: Optional[str] + ready_queue: "queue.Queue[None]" + watch_queue: "queue.Queue[Optional[float]]" + less_proc: "Optional[subprocess.Popen[bytes]]" + + def __init__(self, basedump: str, mydump: str, config: Config) -> None: + self.config = config + self.base_lines = process(basedump, config) + self.mydump = mydump + self.emsg = None + self.last_refresh_key = None + self.last_diff_output = None + + def run_diff(self) -> Tuple[str, object]: + if self.emsg is not None: + return (self.emsg, self.emsg) + + my_lines = process(self.mydump, self.config) + diff_output = do_diff(self.base_lines, my_lines, self.config) + last_diff_output = self.last_diff_output or diff_output + if self.config.threeway != "base" or not self.last_diff_output: + self.last_diff_output = diff_output + + meta, diff_lines = align_diffs(last_diff_output, diff_output, self.config) + output = self.config.formatter.table(meta, diff_lines) + refresh_key = ( + [line.key2 for line in diff_output.lines], + diff_output.score, + ) + return (output, refresh_key) + + def run_less( + self, output: str + ) -> "Tuple[subprocess.Popen[bytes], subprocess.Popen[bytes]]": + # Pipe the output through 'tail' and only then to less, to ensure the + # write call doesn't block. ('tail' has to buffer all its input before + # it starts writing.) This also means we don't have to deal with pipe + # closure errors. + buffer_proc = subprocess.Popen( + BUFFER_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) + less_proc = subprocess.Popen(LESS_CMD, stdin=buffer_proc.stdout) + assert buffer_proc.stdin + assert buffer_proc.stdout + buffer_proc.stdin.write(output.encode()) + buffer_proc.stdin.close() + buffer_proc.stdout.close() + return (buffer_proc, less_proc) + + def run_sync(self) -> None: + output, _ = self.run_diff() + proca, procb = self.run_less(output) + procb.wait() + proca.wait() + + def run_async(self, watch_queue: "queue.Queue[Optional[float]]") -> None: + self.watch_queue = watch_queue + self.ready_queue = queue.Queue() + self.pending_update = None + output, refresh_key = self.run_diff() + self.last_refresh_key = refresh_key + dthread = threading.Thread(target=self.display_thread, args=(output,)) + dthread.start() + self.ready_queue.get() + + def display_thread(self, initial_output: str) -> None: + proca, procb = self.run_less(initial_output) + self.less_proc = procb + self.ready_queue.put(None) + while True: + ret = procb.wait() + proca.wait() + self.less_proc = None + if ret != 0: + # fix the terminal + os.system("tput reset") + if ret != 0 and self.pending_update is not None: + # killed by program with the intent to refresh + output = self.pending_update + self.pending_update = None + proca, procb = self.run_less(output) + self.less_proc = procb + self.ready_queue.put(None) + else: + # terminated by user, or killed + self.watch_queue.put(None) + self.ready_queue.put(None) + break + + def progress(self, msg: str) -> None: + # Write message to top-left corner + sys.stdout.write("\x1b7\x1b[1;1f{}\x1b8".format(msg + " ")) + sys.stdout.flush() + + def update(self, text: str, error: bool) -> None: + if not error and not self.emsg and text == self.mydump: + self.progress("Unchanged. ") + return + if not error: + self.mydump = text + self.emsg = None + else: + self.emsg = text + output, refresh_key = self.run_diff() + if refresh_key == self.last_refresh_key: + self.progress("Unchanged. ") + return + self.last_refresh_key = refresh_key + self.pending_update = output + if not self.less_proc: + return + self.less_proc.kill() + self.ready_queue.get() + + def terminate(self) -> None: + if not self.less_proc: + return + self.less_proc.kill() + self.ready_queue.get() + + +def main() -> None: + args = parser.parse_args() + + # Apply project-specific configuration. + settings: Dict[str, Any] = {} + diff_settings.apply(settings, args) # type: ignore + project = create_project_settings(settings) + + try: + config = create_config(args, project) + except ValueError as e: + fail(str(e)) + + if config.algorithm == "levenshtein": + try: + import Levenshtein + except ModuleNotFoundError as e: + fail(MISSING_PREREQUISITES.format(e.name)) + + if config.show_source: + try: + import cxxfilt + except ModuleNotFoundError as e: + fail(MISSING_PREREQUISITES.format(e.name)) + + if config.threeway and not args.watch: + fail("Threeway diffing requires -w.") + + if args.diff_elf_symbol: + make_target, basecmd, mycmd = dump_elf( + args.start, args.end, args.diff_elf_symbol, config, project + ) + elif config.diff_obj: + make_target, basecmd, mycmd = dump_objfile( + args.start, args.end, config, project + ) + else: + make_target, basecmd, mycmd = dump_binary(args.start, args.end, config, project) + + map_build_target_fn = getattr(diff_settings, "map_build_target", None) + if map_build_target_fn: + make_target = map_build_target_fn(make_target=make_target) + + if args.write_asm is not None: + mydump = run_objdump(mycmd, config, project) + with open(args.write_asm, "w") as f: + f.write(mydump) + print(f"Wrote assembly to {args.write_asm}.") + sys.exit(0) + + if args.base_asm is not None: + with open(args.base_asm) as f: + basedump = f.read() + else: + basedump = run_objdump(basecmd, config, project) + + mydump = run_objdump(mycmd, config, project) + + display = Display(basedump, mydump, config) + + if args.no_pager or args.format in ("html", "json"): + print(display.run_diff()[0]) + elif not args.watch: + display.run_sync() + else: + if not args.make: + yn = input( + "Warning: watch-mode (-w) enabled without auto-make (-m). " + "You will have to run make manually. Ok? (Y/n) " + ) + if yn.lower() == "n": + return + if args.make: + watch_sources = None + watch_sources_for_target_fn = getattr( + diff_settings, "watch_sources_for_target", None + ) + if watch_sources_for_target_fn: + watch_sources = watch_sources_for_target_fn(make_target) + watch_sources = watch_sources or project.source_directories + if not watch_sources: + fail("Missing source_directories config, don't know what to watch.") + else: + watch_sources = [make_target] + q: "queue.Queue[Optional[float]]" = queue.Queue() + debounced_fs_watch(watch_sources, q, config, project) + display.run_async(q) + last_build = 0.0 + try: + while True: + t = q.get() + if t is None: + break + if t < last_build: + continue + last_build = time.time() + if args.make: + display.progress("Building...") + ret = run_make_capture_output(make_target, project) + if ret.returncode != 0: + display.update( + ret.stderr.decode("utf-8-sig", "replace") + or ret.stdout.decode("utf-8-sig", "replace"), + error=True, + ) + continue + mydump = run_objdump(mycmd, config, project) + display.update(mydump, error=False) + except KeyboardInterrupt: + display.terminate() + + +if __name__ == "__main__": + main() diff --git a/lib/ultralib/tools/asm_differ/diff_settings.py b/lib/ultralib/tools/asm_differ/diff_settings.py new file mode 100644 index 00000000..183b96b7 --- /dev/null +++ b/lib/ultralib/tools/asm_differ/diff_settings.py @@ -0,0 +1,11 @@ +def apply(config, args): + config["baseimg"] = "target.bin" + config["myimg"] = "source.bin" + config["mapfile"] = "build.map" + config["source_directories"] = ["."] + # config["show_line_numbers_default"] = True + # config["arch"] = "mips" + # config["map_format"] = "gnu" # gnu or mw + # config["mw_build_dir"] = "build/" # only needed for mw map format + # config["makeflags"] = [] + # config["objdump_executable"] = "" diff --git a/lib/ultralib/tools/asm_differ/mypy.ini b/lib/ultralib/tools/asm_differ/mypy.ini new file mode 100644 index 00000000..138b9393 --- /dev/null +++ b/lib/ultralib/tools/asm_differ/mypy.ini @@ -0,0 +1,17 @@ +[mypy] +check_untyped_defs = True +disallow_any_generics = True +disallow_incomplete_defs = True +disallow_untyped_calls = True +disallow_untyped_decorators = True +disallow_untyped_defs = True +no_implicit_optional = True +warn_redundant_casts = True +warn_return_any = True +warn_unused_ignores = True +ignore_missing_imports = True +python_version = 3.6 +files = diff.py + +[mypy-diff_settings] +ignore_errors = True diff --git a/lib/ultralib/tools/asm_differ/screenshot.png b/lib/ultralib/tools/asm_differ/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3230555328cd9acdf388ce1626415ceb78760535 GIT binary patch literal 99842 zcmd431yG#Zx~@w?g1b9Gg1b8j?(Ul4?yezdaCdiicXxMpXxtjt+nIC8T?|I+RzvN^@;bCxKz`(%Z#l?gaz`)*jgWgV15TGr};=9eDAJ8^p z>h@q@2))1G@8YNtaKXSnfr$%!RdPu^S#woWo_ig*yyF8fki`5Th6sk)PK;JWNis|Z zsu^+aDCNg#=!G|=0-dGpsRFN!*d=R5V@HWtjq$!zFb{tE^mFtRRO-tUcq%diOwffV zZ^T4S^`iOdq5b%}ds!X2tgI|Lksp!(6cH8H*o@VW-y=UH*`6J5CQL_(Z*_qu*{tga7bR<#a{)OOf4fWVsTgfN-|O~^HU_AgLGLcgL@F$H4n zWr;G-r0}(Es%!V>?c=6wf1ONQ`%w_<1L{LxpY?I@Q-aQ`neWb-rQz3gs#AUH&UsU< zY)xdWjZP#W(P)lq3pRdOxv<-GjZ?%dMuI)7(gO+PE$QRg!DbZbrc6Ovt=^Fq766-5)c zGoJ(ITpZQBar&%xo?I~-vuyJnJBZ*?jigQ@u}@?ogV3@)qEfx%#l}N|r64mG?-`8F zC|c7jt0s+N&^*JzapP;uL>btv30uhMTA6lvAKR9Z$Y&$&h6d2+Y>bJ=mZsGoa5s;2HN!v8s<;Ip1Pf~_@MNjk&d(l7Sf(N7P_`YCW+gYaKmom&3px9qBtjw3|*?;4C zWYSRGs%><_9@!+@vPfgbZQ1gw9dAhe97l8AtHUX3V!}u0`Y2W}g)=yRVqpgc^@(8# zyTX-TaYA|I>_d|(sgQU~Dt+Q^E9jyoI)Is(F}N?#8#r6M#|}oXTZaGM8>l!KbYZx+ zWFc2-%4&qLqa(Fjac)$@qY-EyBh#wN){174%ry zAqm9t3_bi5842voGw*BplO2k@d(jWyeuN{uoyPw$4`s@$wLCykf6TeBCMWjPzM z%;z6e7*CsAvzNXpNt)f;I+bb;H+x3iZG0TgDY@m+4`3xfTljS^I7TWLRB1HU(Z zcp=R2bPm{VtswGqVfo{lV~W`6#Hw<|7CWS}pz0RHc)XngJ_zMzS9$roDh95$b*p|w zq)2{m^ou2Tw9Oy(K1l~rqilZCk-}CTnLCkx8!9EaE=xK^^?Fm6<1LCdA&rsbu6}vZ$nN3VBk^*_{vTVn6%)|Ofsb!l z-*oP1^F5~!k3DN19EQGb@0und49n(;=)6EeiR zlh&o_FGPZ(o|0;5UT~(mr&Fkd)XGI0nJ|x)-?~F^KIEw+NSN(%%0NP(pkay0O>$;W z2XFC3WM6#KN9QK&m-571d0|efRqK`yQuxeijWy)jBR(EtCmZvZzC4o6}C?EOp=3f`~j66SNK z#;z<<$zn6Qs?!WPyIE2h0xrRMcWcJ|H3KjBP(j@yx?3CDj;;G`S;^`WMZdxlosn?rLJheNxys8Q zPKs6=j$^7Jcn6;C7;TxGO38>&4YAW9A*H3?*-)p=Q1gG6$fkec4&SV4pq(Gije6=GAa zLLusT?mQz}LF+S#H+lJY5*k(8Id^*^zRg;|9^GOICQy+X2xWW+ zJU5l{#Xfg}3w-33rRTArnXJ3Y^4UYkR-B!#82O^HkS?XWikPq>%aF!rIAl(BsmVW< zb}Pm>&}s*-W403IT%z$kHco1EFXov=AD(~Xj6HvGXG{KLS{pMVy{Y@gRZY0p5O>Ur z>+Z}KqTZN)%+r-wyVKZKacHABdkz z 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 literal 0 HcmV?d00001 diff --git a/lib/ultralib/tools/compile_sjis.py b/lib/ultralib/tools/compile_sjis.py new file mode 100755 index 00000000..19057452 --- /dev/null +++ b/lib/ultralib/tools/compile_sjis.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import sys, os +from shiftjis_conv import sjis_process + +os.chdir("../../") +WORKING_DIR = os.getcwd() + +fb = [] +original_c_file = [i for i in sys.argv if ".c" in i][0] +CC = [i for i in sys.argv if "-D__CC=" in i][0][7:] + +output_c_file = original_c_file + +sys.argv[sys.argv.index(original_c_file)] = output_c_file + +original_c_file = "src/voice/" + original_c_file + +with open(original_c_file) as f: + fb = f.read() + +os.chdir("build/src/voice") + +with open(output_c_file, "w+") as outf: + sjis_process(fb, outf) + +os.system("%s %s" % (CC, " ".join(sys.argv[1:]))) diff --git a/lib/ultralib/tools/disassemble_elf.py b/lib/ultralib/tools/disassemble_elf.py new file mode 100755 index 00000000..1fa58a81 --- /dev/null +++ b/lib/ultralib/tools/disassemble_elf.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python3 +# +# ELF disassembler that attempts to be matching +# + +import argparse, struct, sys + +from libelf import * +from mdebug import * +from mips_isa import * +from util import * + +def debug_log(msg): + print(msg, file=sys.stderr) + +class MipsDisasm: + """ + """ + + def __init__(self, elf_file) -> None: + self.elf_file = elf_file + mdebug_section = elf_file.find_section_by_type(SHT_MIPS_DEBUG) + if mdebug_section is not None: + self.mdebug = mdebug_section + self.has_mdebug = True + else: + self.has_mdebug = False + self.cur_file = None + self.comment_section_pos = 1 + self.section_local_labels = {} + + def add_section_local_label(self, section, offset): + if section not in self.section_local_labels: + self.section_local_labels.update({section : set()}) + self.section_local_labels[section].add(offset) + + def advance_file(self): + seen_cur_file = False + for sym in self.elf_file.symtab.symbol_entries: + if sym.type == ST_FILE: + if seen_cur_file or self.cur_file is None: + self.cur_file = sym + break + elif self.cur_file == sym: + seen_cur_file = True + return self.cur_file is not None + + def disassemble_all_sections(self): + print(MipsDisasm.asm_prelude()) + + # debug_log("Name Type Addr Off Size ES Flg Lk Inf Al") + for section in self.elf_file.sections: + local_labels = self.section_local_labels.get(section.name, None) + # debug_log(section) + if section.name in ['', '.strtab', '.shstrtab', '.symtab', '.reginfo', '.comment', '.note', '.options', '.mdebug', '.gptab.data', '.gptab.bss'] or \ + (section.sh_type == SHT_REL or section.sh_type == SHT_RELA): + continue + if section.sh_size == 0: + continue + print("") + print(MipsDisasm.begin_section(section)) + if section.is_executable(): + self.disassemble_exec(section) + elif section.sh_type == SHT_PROGBITS: + # TODO kmc as doesn't support incbin, byte array this + # print(f".incbin \"libultra.a\", 0x{section.sh_offset:08X}, 0x{section.sh_size:X}") + first = True + for i,b in enumerate(section.data): + if local_labels is not None and i in local_labels: + if not first: + print("") + print(f".{section.name[1].upper()}_{i:08X}:") + print(" .byte ", end='') + first = True + elif first: + print(" .byte ", end='') + if not first: + print(", ", end='') + print(f"0x{int(b):02X}", end='') + first = False + print("") + elif section.sh_type == SHT_NOBITS: + print(f".skip 0x{section.sh_size:X}") + else: + assert False, f"Unhandled section: {section.name}" + # debug_log("/// UNHANDLED ///") + + def pass_section(self, section): + pass + + @staticmethod + def asm_prelude(): + return f""".include "macro.inc" +#include "regdef.h" + +// assembler directives +.set noat // allow manual use of $at +.set noreorder // don't insert nops after branches""" + + @staticmethod + def begin_section(section): + section_flags = section.flags_str().lower().replace(' ', '') + if section_flags != "": + section_flags = f", \"{section_flags}\"" + section_type = "" + if section.sh_type == SHT_PROGBITS: + section_type = ", @progbits" + elif section.sh_type == SHT_NOBITS: + section_type = ", @nobits" + if section_type != "" and section_flags == "": + section_flags = ", \"\"" + + return f""".section {section.name}{section_flags}{section_type} +.balign {section.sh_addralign} +""" + + def get_label_name(self, addr, pdr=None, optional=False): + if pdr is not None: + sym = pdr.lookup_sym(addr, EcoffSt.LABEL) + if sym is not None: + return sym.name + if not optional: + return f".L{addr:08X}" + else: + return None + + def get_comment_string(self, start): + comment_section = self.elf_file.find_section_by_name(".comment") + end = comment_section.data.find(b'\0', start) + if end == -1: + return None, None + comment = comment_section.data[start:end].decode("ASCII") + return comment, end + 1 + + def print_end(self, vaddr, eof): + ends = eof.get(vaddr, None) + if ends is not None: + for sym in ends: + print(f" .type {sym.name}, @{'function' if sym.type == ST_FUNC else 'object'}") + if sym.st_size != 0: + print(f" .size {sym.name}, . - {sym.name}") + print(f" .end {sym.name}\n") + + def disassemble_exec(self, section): + raw_insns = as_word_list(section.data) + insns = [decode_insn(raw, section.sh_addr + j * 4) for j,raw in enumerate(raw_insns)] + + # enumerate branch labels + branch_labels = set() + + for i,insn in enumerate(insns): + if insn.id in MIPS_BRANCH_INSNS or insn.id == MIPS_INS_J: + branch_labels.add(insn.target if insn.id == MIPS_INS_J else insn.offset) + + eof = {} # vaddr : name + def add_end(vaddr, sym): + if vaddr not in eof: + eof[vaddr] = set() + eof[vaddr].add(sym) + + cur_fdr = None + cur_pdr = None + for i,insn in enumerate(insns): + mnemonic = insn.mnemonic + op_str = insn.op_str + + # Update mdebug info + src_inf = "" + if self.has_mdebug: + # Get new fdr if there is one + fdr = self.mdebug.fdr_foraddr(i * 4, extensions=('.c', '.s')) + if fdr is not None: + # debug_log(fdr.name) + cur_fdr = fdr + + # Get new pdr if there is one + if cur_fdr is not None: + pdr = cur_fdr.pdr_foraddr(i * 4) + if pdr is not None: + # debug_log(pdr) + cur_pdr = pdr + + # Line numbers + if cur_pdr is not None: + asm_line = i - cur_pdr.addr//4 + if asm_line < len(cur_pdr.lines): + src_inf = f" {cur_pdr.lines[asm_line]:4}" + else: + src_inf = " PADDING" + + # Symbols for this address + syms = section.get_sym(i * 4) + # if len(syms) != 0: + # debug_log("\n".join([str(sym) for sym in syms])) + + # Print end + self.print_end(insn.vaddr, eof) + + # Print symbol + for sym in syms: + if sym.name == "gcc2_compiled.": + print(f"// compiler generated") + if self.cur_file is None: + print(f".version \"01.01\"") + if self.advance_file(): + print(f".file 1 \"{self.cur_file.name}\"") + + comment_string = None + while comment_string != "\"GCC: (GNU) 2.7.2\"": + comment_string, self.comment_section_pos = self.get_comment_string(self.comment_section_pos) + if comment_string is None: + break + print(f".ident \"{comment_string}\"") + + if sym.bind == SB_GLOBAL: + print(f"glabel {sym.name}") + else: + print(f"{sym.name}:") + + if sym.st_size != 0: + print(f" .ent {sym.name}") + add_end(insn.vaddr + sym.st_size, sym) + else: + print(f" .type {sym.name}, @{'function' if sym.type == ST_FUNC else 'object'}\n") + + # Print branch labels + lbl = self.get_label_name(insn.vaddr, pdr=cur_pdr, optional=not insn.vaddr in branch_labels) + if lbl is not None: + print(f"{lbl}:") + + # Relocations for this address + rels = section.get_rel(i * 4) + assert len(rels) < 2 # There should never be more than 1 relocation for a single address, right? + # if len(rels) != 0: + # debug_log("\n".join([str(rel) for rel in rels])) + + # Apply relocation + if len(rels) != 0: + rel = rels[0] + if rel.rel_type == R_MIPS_26: + if insn.id == MIPS_INS_JAL: + op_str = rel.relocated_symbol.name + if op_str == ".text" and cur_fdr is not None: + pdr = cur_fdr.pdr_foraddr(insn.target) + if pdr is not None: + op_str = pdr.name + elif insn.id != MIPS_INS_J: # Branch labels for j instructions are also R_MIPS_26 relocations + assert False , f"Got unexpected R_MIPS_26 relocation {insn.id}" + elif rel.rel_type == R_MIPS_HI16: + assert insn.id in [MIPS_INS_LUI] + rel_name = rel.relocated_symbol.name + if rel.relocated_symbol.type == ST_SECTION: + rel_name = f".{rel_name[1].upper()}_00000000" + if cur_fdr is not None: + pass + + op_str = f"{insn.abi.gpr_names[insn.rt]}, %hi({rel_name})" + elif rel.rel_type == R_MIPS_LO16: + # Ideally this should be in the elf code so the relocations don't look identical + addend = insn.imm + rel_name = rel.relocated_symbol.name + if rel.relocated_symbol.type == ST_SECTION: + rel_name = f".{rel_name[1].upper()}_{addend:08X}" + self.add_section_local_label(rel.relocated_symbol.name, addend) + addend = 0 + addend_str = f" + 0x{addend:X}" if addend != 0 else "" + + if insn.id == MIPS_INS_ADDIU: + op_str = f"{insn.abi.gpr_names[insn.rt]}, {insn.abi.gpr_names[insn.rs]}, %lo({rel_name}{addend_str})" + elif insn.id in MIPS_LOAD_STORE_INSNS: + if insn.id in MIPS_FP_LOAD_STORE_INSNS: + op_str = f"{insn.abi.cop1_names[insn.ft]}, " + else: + op_str = f"{insn.abi.gpr_names[insn.rt]}, " + op_str += f"%lo({rel_name}{addend_str})({insn.abi.gpr_names[insn.base]})" + else: + assert False + else: + assert False + + # Apply branch labels + if insn.id in MIPS_BRANCH_INSNS: + op_str_parts = [] + for field in insn.fields: + if field == 'offset': + op_str_parts.append(self.get_label_name(insn.offset, cur_pdr)) + else: + op_str_parts.append(insn.format_field(field)) + op_str = ", ".join(op_str_parts) + elif insn.id == MIPS_INS_J: + op_str = self.get_label_name(insn.target, cur_pdr) + + print(f"/* {section.sh_offset + i * 4:06X} {insn.vaddr:08X} {insn.raw:08X}{src_inf} */ {mnemonic:12}{op_str:35}".rstrip()) + self.print_end(section.sh_addr + section.sh_size, eof) + +def main(): + parser = argparse.ArgumentParser(description="Disassemble relocatable ELF object.") + parser.add_argument("filepath", help="path to the ELF file") + # TODO unimplemented optionals + parser.add_argument("--compiler", help="original compiler that produced the ELF (IDO or GCC, IDO default)", default="IDO") + parser.add_argument("--strenc", help="string encoding, default is EUC-JP for IDO and SJIS for GCC") + args = parser.parse_args() + + elf_file = None + with open(args.filepath, "rb") as elf: + elf_file = ElfFile(bytearray(elf.read())) + + disassembler = MipsDisasm(elf_file) + disassembler.disassemble_all_sections() + +if __name__ == '__main__': + main() diff --git a/lib/ultralib/tools/fix_objfile.py b/lib/ultralib/tools/fix_objfile.py new file mode 100755 index 00000000..52a79bcd --- /dev/null +++ b/lib/ultralib/tools/fix_objfile.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# +# Fixes garbage data between sections and optionally rodata section flags +# + +import argparse +from libelf import * + +def fix_section_flags(elf): + for section in elf.sections: + # Unset Alloc flag in .rodata section + if section.name == ".rodata": + section.sh_flags &= ~SHF_ALLOC + +def fix_garbage(elf, original): + # Begin with the original data, and paste header and section data over it + result = original + if len(original) < len(elf.data): + result.extend([0]*(len(elf.data) - len(original))) + else: + result = result[:len(elf.data)] + + # NOTE: This only supports the elf header, program headers, section headers and section data at this time + + # emplace elf header + hdr = elf.elf_header.to_bin() + result[0:len(hdr)] = hdr + + # emplace program headers + for i,proghdr in enumerate(elf.progheaders): + offset = elf.elf_header.e_phoff + i * elf.elf_header.e_phentsize + result[offset:offset+elf.elf_header.e_phentsize] = proghdr.to_bin() + + # emplace section headers and section data + for i,section in enumerate(elf.sections): + offset = elf.elf_header.e_shoff + i * elf.elf_header.e_shentsize + section_header, section_data = section.to_bin() + result[offset:offset+elf.elf_header.e_shentsize] = section_header + if section_data is not None: + result[section.sh_offset:section.sh_offset+section.sh_size] = section_data + + return result + +def main(): + parser = argparse.ArgumentParser(description="Disassemble relocatable ELF object.") + parser.add_argument("compiled", help="path to the compiled ELF file") + parser.add_argument("original", help="path to the original ELF file") + parser.add_argument("--fix-section-flags", help="", action="store_true") + args = parser.parse_args() + + elf = None + with open(args.compiled, "rb") as elf_file: + elf = ElfFile(bytearray(elf_file.read())) + + original = None + with open(args.original, "rb") as original_file: + original = bytearray(original_file.read()) + + if args.fix_section_flags: + fix_section_flags(elf) + + result_data = fix_garbage(elf, original) + + with open(args.compiled, "wb") as elf_file: + elf_file.write(result_data) + +if __name__ == '__main__': + main() diff --git a/lib/ultralib/tools/libdiff.py b/lib/ultralib/tools/libdiff.py new file mode 100755 index 00000000..ac6b1391 --- /dev/null +++ b/lib/ultralib/tools/libdiff.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +from typing import Any, Dict, Optional +import json +import logging +import subprocess +import tempfile +import pathlib +import sys +import queue + +import asm_differ.diff as asm_differ + +MAX_FUNC_SIZE_LINES = 5000 + +class AsmDifferWrapper: + @staticmethod + def create_config(arch: asm_differ.ArchSettings) -> asm_differ.Config: + return asm_differ.Config( + arch=arch, + # Build/objdump options + diff_obj=True, + make=False, + source_old_binutils=True, + diff_section=".text", + inlines=False, + max_function_size_lines=MAX_FUNC_SIZE_LINES, + max_function_size_bytes=MAX_FUNC_SIZE_LINES * 4, + # Display options + formatter=asm_differ.AnsiFormatter(column_width=50), + threeway=None, + base_shift=0, + skip_lines=0, + compress=None, + show_branches=True, + show_line_numbers=False, + show_source=False, + stop_jrra=False, + ignore_large_imms=False, + ignore_addr_diffs=False, + algorithm="levenshtein", + ) + + @staticmethod + def run_objdump(target_data: bytes, config: asm_differ.Config, label: Optional[str]) -> Optional[str]: + flags = [ + "--disassemble", + "--disassemble-zeroes", + "--line-numbers", + "--reloc", + ] + + with tempfile.TemporaryDirectory() as tempdir: + target_path = pathlib.Path(tempdir) / "out.s" + target_path.write_bytes(target_data) + + start_addr = 0 + + if label: + nm_command = "mips-linux-gnu-nm" + + if nm_command: + try: + nm_proc = subprocess.run( + [nm_command] + [target_path], + capture_output=True, + universal_newlines=True + ) + except subprocess.CalledProcessError as e: + logger.error(f"Error running nm: {e}") + logger.error(e.stderr) + + if nm_proc.stdout: + for line in nm_proc.stdout.splitlines(): + if label in line: + start_addr = int(line.split()[0], 16) + break + else: + # logger.error(f"No nm command for {platform}") + return None + + flags.append(f"--start-address={start_addr}") + + objdump_command = "mips-linux-gnu-objdump" + cmds = [objdump_command] + config.arch.arch_flags + flags + [target_path] + + try: + objdump_proc = subprocess.run( + [objdump_command] + config.arch.arch_flags + flags + [target_path], + capture_output=True, + universal_newlines=True + ) + except subprocess.CalledProcessError as e: + # logger.error(e) + # logger.error(e.stderr) + return None + + out = objdump_proc.stdout + return out + + @staticmethod + def diff(target_elf: bytes, compiled_elf: bytes, diff_label:Optional[str]) -> Dict[str, Any]: + arch = asm_differ.get_arch("mips") + + config = AsmDifferWrapper.create_config(arch) + + # Base + if len(target_elf) == 0: + print("Base asm empty") + return + + basedump = AsmDifferWrapper.run_objdump(target_elf, config, diff_label) + if not basedump: + print("Error running asm-differ on basedump") + return + + if len(compiled_elf) == 0: + print("Creation of compilation elf_object failed") + return + + mydump = AsmDifferWrapper.run_objdump(compiled_elf, config, diff_label) + if not mydump: + print("Error running asm-differ") + return + + # Preprocess the dumps + basedump = asm_differ.preprocess_objdump_out(None, target_elf, basedump, config) + mydump = asm_differ.preprocess_objdump_out(None, compiled_elf, mydump, config) + + try: + display = asm_differ.Display(basedump, mydump, config) + except Exception: + print("Error running asm-differ") + return + + # Print the output + display.run_sync() + +if __name__ == "__main__": + if len(sys.argv) != 3 and len(sys.argv) != 4: + print(f"Usage: {sys.argv[0]} [path/to/target.o] [path/to/compiled.o] [function name (optional)]") + sys.exit(0) + target = pathlib.Path(sys.argv[1]) + compiled = pathlib.Path(sys.argv[2]) + if len(sys.argv) == 4: + label = sys.argv[3] + else: + label = None + target_bytes = target.read_bytes() + compiled_bytes = compiled.read_bytes() + AsmDifferWrapper.diff(target_bytes, compiled_bytes, label) diff --git a/lib/ultralib/tools/libelf.py b/lib/ultralib/tools/libelf.py new file mode 100755 index 00000000..0c9cc3ad --- /dev/null +++ b/lib/ultralib/tools/libelf.py @@ -0,0 +1,1180 @@ +#!/usr/bin/env python3 +# +# MIPS ELF library +# + +import struct + +from mdebug import EcoffHDRR, EcoffFdr, EcoffPdr, EcoffLiner, EcoffSymr + +# ===================================================================================================== +# Utility +# ===================================================================================================== + +def align_as(value, align): + if align == 0: + return value + while (value % align != 0): + value += 1 + return value + +# ===================================================================================================== +# ELF Identity +# ===================================================================================================== + +# Offsets into e_ident +EI_MAG0 = 0x00 # Magic char 0 , 0x7F +EI_MAG1 = 0x01 # Magic char 1 , 0x45 +EI_MAG2 = 0x02 # Magic char 2 , 0x4C +EI_MAG3 = 0x03 # Magic char 3 , 0x46 +EI_CLASS = 0x04 # +EI_DATA = 0x05 # +EI_VERSION = 0x06 # +EI_OSABI = 0x07 # +EI_ABIVERSION = 0x08 # +EI_PAD = 0x09 # +EI_NIDENT = 0x10 # + +# Values for e_ident[EI_DATA] +EI_DATA_LE = 1 # little endian +EI_DATA_BE = 2 # big endian + +EI_DATA_V = { + EI_DATA_LE : 'Little Endian', + EI_DATA_BE : 'Big Endian' +} + +# Values for e_ident[EI_CLASS] +EI_CLASS_32 = 1 # 32-bit +EI_CLASS_64 = 2 # 64-bit + +EI_CLASS_V = { + EI_CLASS_32 : 'ELF32', + EI_CLASS_64 : 'ELF64' +} + +# Values for e_ident[EI_OSABI] +EI_OSABI_V = { + 0x00 : 'UNIX / System V', + 0x01 : 'HP-UX', + 0x02 : 'NetBSD', + 0x03 : 'Linux', + 0x04 : 'GNU Hurd', + 0x06 : 'Solaris', + 0x07 : 'AIX', + 0x08 : 'IRIX', + 0x09 : 'FreeBSD', + 0x0A : 'Tru64', + 0x0B : 'Novell Modesto', + 0x0C : 'OpenBSD', + 0x0D : 'OpenVMS', + 0x0E : 'NonStop Kernel', + 0x0F : 'AROS', + 0x10 : 'Fenix OS', + 0x11 : 'CloudABI', + 0x12 : 'Stratus Technologies OpenVOS' +} + +# ===================================================================================================== +# ELF Types +# ===================================================================================================== + +ET_NONE = 0x0000 # +ET_REL = 0x0001 # relocatable +ET_EXEC = 0x0002 # +ET_DYN = 0x0003 # +ET_CORE = 0x0004 # +ET_LOOS = 0xFE00 # +ET_HIOS = 0xFEFF # +ET_LOPROC = 0xFF00 # +ET_HIPROC = 0xFFFF # + +E_TYPE = { + ET_NONE : 'ET_NONE', + ET_REL : 'ET_REL', + ET_EXEC : 'ET_EXEC', + ET_DYN : 'ET_DYN', + ET_CORE : 'ET_CORE', + ET_LOOS : 'ET_LOOS', + ET_HIOS : 'ET_HIOS', + ET_LOPROC : 'ET_LOPROC', + ET_HIPROC : 'ET_HIPROC' +} + +# ===================================================================================================== +# ELF Machines +# ===================================================================================================== + +EM_UNSPECIFIED = 0x00 +EM_ATNT_WE_32100 = 0x01 +EM_SPARC = 0x02 +EM_X86 = 0x03 +EM_MOTOROLA_68000 = 0x04 +EM_MOTOROLA_88000 = 0x05 +EM_INTEL_MCU = 0x06 +EM_INTEL_80860 = 0x07 +EM_MIPS = 0x08 +EM_IBM_SYSTEM_370 = 0x09 +EM_MIPS_RS3000_LE = 0x0A +EM_RESERVED_xB = 0x0B +EM_RESERVED_xC = 0x0C +EM_RESERVED_xD = 0x0D +EM_HEWLETT_PACKARD = 0x0E +EM_RESERVED_xF = 0x0F +EM_INTEL_80960 = 0x13 +EM_POWERPC = 0x14 +EM_POWERPC_64 = 0x15 +EM_5390 = 0x16 +EM_ARM = 0x28 +EM_SUPERH = 0x2A +EM_IA64 = 0x32 +EM_AMD64 = 0x3E +EM_TMS320C6000 = 0x8C +EM_ARM64 = 0xB7 +EM_RISC_V = 0xF3 + +E_MACHINE = { + EM_UNSPECIFIED : 'Unspecified', + EM_ATNT_WE_32100 : 'AT&T WE 32100', + EM_SPARC : 'SPARC', + EM_X86 : 'x86', + EM_MOTOROLA_68000 : 'Motorola 68000 (M68K)', + EM_MOTOROLA_88000 : 'Motorola 88000 (M88K)', + EM_INTEL_MCU : 'Intel MCU', + EM_INTEL_80860 : 'Intel 80860', + EM_MIPS : 'MIPS', + EM_IBM_SYSTEM_370 : 'IBM_System/370', + EM_MIPS_RS3000_LE : 'MIPS RS3000 Little-endian', + EM_RESERVED_xB : 'Reserved', + EM_RESERVED_xC : 'Reserved', + EM_RESERVED_xD : 'Reserved', + EM_HEWLETT_PACKARD : 'Hewlett-Packard PA-RISC', + EM_RESERVED_xF : 'Reserved', + EM_INTEL_80960 : 'Intel 80960', + EM_POWERPC : 'PowerPC', + EM_POWERPC_64 : 'PowerPC (64-bit)', + EM_5390 : 'S390, including S390x', + EM_ARM : 'ARM (up to ARMv7/Aarch32)', + EM_IA64 : 'SuperH', + EM_IA64 : 'IA-64', + EM_AMD64 : 'amd64', + EM_TMS320C6000 : 'TMS320C6000 Family', + EM_ARM64 : 'ARM 64-bits (ARMv8/Aarch64)', + EM_RISC_V : 'RISC-V' +} + +# ===================================================================================================== +# Program Types +# ===================================================================================================== + +PT_NULL = 0x00000000 # Program header table entry unused +PT_LOAD = 0x00000001 # Loadable segment +PT_DYNAMIC = 0x00000002 # Dynamic linking information +PT_INTERP = 0x00000003 # Interpreter information +PT_NOTE = 0x00000004 # Auxiliary information +PT_SHLIB = 0x00000005 # Reserved +PT_PHDR = 0x00000006 # Segment containing the program header table itself +PT_TLS = 0x00000007 # Thread-Local storage template +PT_LOOS = 0x60000000 # Inclusive reserved range for processor-specific semantics +PT_HIOS = 0x6FFFFFFF # ^ +PT_LOPROC = 0x70000000 # Inclusive reserved range for processor-specific semantics +PT_HIPROC = 0x7FFFFFFF # ^ + +P_TYPE = { + PT_NULL : 'PT_NULL' , + PT_LOAD : 'PT_LOAD' , + PT_DYNAMIC : 'PT_DYNAMIC', + PT_INTERP : 'PT_INTERP' , + PT_NOTE : 'PT_NOTE' , + PT_SHLIB : 'PT_SHLIB' , + PT_PHDR : 'PT_PHDR' , + PT_TLS : 'PT_TLS' , + PT_LOOS : 'PT_LOOS' , + PT_HIOS : 'PT_HIOS' , + PT_LOPROC : 'PT_LOPROC' , + PT_HIPROC : 'PT_HIPROC' +} + +# ===================================================================================================== +# Program Flags ( May be platform specific ! ) +# ===================================================================================================== + +PF_E = 1 << 0 # Execute +PF_W = 1 << 1 # Write +PF_R = 1 << 2 # Read + +# ===================================================================================================== +# Symbol Info +# ===================================================================================================== + +# Symbol Types + +ST_NOTYPE = 0 +ST_OBJECT = 1 +ST_FUNC = 2 +ST_SECTION = 3 +ST_FILE = 4 + +SYM_TYPE = { + ST_NOTYPE : 'NOTYPE', + ST_OBJECT : 'OBJECT', + ST_FUNC : 'FUNC', + ST_SECTION : 'SECTION', + ST_FILE : 'FILE' +} + +# Symbol Bind + +SB_LOCAL = 0 +SB_GLOBAL = 1 +SB_WEAK = 2 + +SYM_BIND = { + SB_LOCAL : 'LOCAL', + SB_GLOBAL : 'GLOBAL', + SB_WEAK : 'WEAK' +} + +# Symbol Visibility + +SV_DEFAULT = 0 + +SYM_VIS = { + SV_DEFAULT : 'DEFAULT' +} + +# NDX + +SHN_UND = 0x0000 +SHN_ABS = 0xFFF1 +SHN_COMMON = 0xFFF2 +SHN_XINDEX = 0xFFFF +SHN_LORESERVE = 0xFF00 + +SYM_NDX = { + SHN_UND : 'UND', + SHN_ABS : 'ABS', + SHN_COMMON : 'COMMON', + SHN_XINDEX : 'XINDEX', + SHN_LORESERVE : 'LORESERVE' +} + +# ===================================================================================================== +# Relocation Type +# ===================================================================================================== + +# EM_MIPS +R_MIPS_32 = 2 # Write the 32 bit address of the symbol +R_MIPS_26 = 4 # Write the 26 bit address of the symbol divided by four (for relocating branch instructions). Fail if address won't fit +R_MIPS_HI16 = 5 # Write the high 16 bits of the address of the symbol +R_MIPS_LO16 = 6 # Write the low 16 bits of the address of the symbol + +# EM_POWERPC +R_PPC_NONE = 0 # Do nothing. Skip this entry +R_PPC_ADDR32 = 1 # Write the 32 bit address of the symbol +R_PPC_ADDR24 = 2 # Write the 24 bit address of the symbol divided by four shifted up 2 bits to the 32 bit value (for relocating branch instructions). Fail if address won't fit +R_PPC_ADDR16 = 3 # Write the 16 bit address of the symbol. Fail if address more than 16 bits +R_PPC_ADDR16_LO = 4 # Write the low 16 bits of the address of the symbol +R_PPC_ADDR16_HI = 5 # Write the high 16 bits of the address of the symbol +R_PPC_ADDR16_HA = 6 # Write the high 16 bits of the address of the symbol plus 0x8000 +R_PPC_ADDR14 = 7 # Write the 14 bits of the address of the symbol divided by four shifted up 2 bits to the 32 bit value (for relocating conditional branch instructions). Fail if address won't fit +R_PPC_REL24 = 10 # Write the 24 bit address of the symbol minus the address of the relocation divided by four shifted up 2 bits to the 32 bit value (for relocating relative branch instructions). Fail if address won't fit +R_PPC_REL14 = 11 # Write the 14 bit address of the symbol minus the address of the relocation divided by four shifted up 2 bits to the 32 bit value (for relocating conditional relative branch instructions). Fail if address won't fit +R_PPC_EMB_SDA21 = 109 # Small Data Area + +# Gamecube/Wii custom relocations +R_DOLPHIN_NOP = 201 # Do nothing. Skip this entry. Carry the address of the symbol to the next entry +R_DOLPHIN_SECTION = 202 # Change which section relocations are being applied to. Set the offset into the section to 0 +R_DOLPHIN_END = 203 # Stop parsing the relocation table +R_DOLPHIN_MRKREF = 204 # Unknown + +RELOC_TYPE = { + EM_MIPS : { + R_MIPS_32 : 'R_MIPS_32', + R_MIPS_26 : 'R_MIPS_26', + R_MIPS_HI16 : 'R_MIPS_HI16', + R_MIPS_LO16 : 'R_MIPS_LO16' + }, + EM_POWERPC : { + R_PPC_NONE : 'R_PPC_NONE', + R_PPC_ADDR32 : 'R_PPC_ADDR32', + R_PPC_ADDR24 : 'R_PPC_ADDR24', + R_PPC_ADDR16 : 'R_PPC_ADDR16', + R_PPC_ADDR16_LO : 'R_PPC_ADDR16_LO', + R_PPC_ADDR16_HI : 'R_PPC_ADDR16_HI', + R_PPC_ADDR16_HA : 'R_PPC_ADDR16_HA', + R_PPC_ADDR14 : 'R_PPC_ADDR14', + 8 : 'R_PPC_ADDR14', + 9 : 'R_PPC_ADDR14', + R_PPC_REL24 : 'R_PPC_REL24', + R_PPC_REL14 : 'R_PPC_REL14', + 12 : 'R_PPC_REL14', + 13 : 'R_PPC_REL14', + R_PPC_EMB_SDA21 : 'R_PPC_EMB_SDA21', + R_DOLPHIN_NOP : 'R_DOLPHIN_NOP', + R_DOLPHIN_SECTION : 'R_DOLPHIN_SECTION', + R_DOLPHIN_END : 'R_DOLPHIN_END', + R_DOLPHIN_MRKREF : 'R_DOLPHIN_MRKREF' + } +} + +# ===================================================================================================== +# Section Types +# ===================================================================================================== + +SHT_NULL = 0x00000000 # Section header table entry unused +SHT_PROGBITS = 0x00000001 # Program data +SHT_SYMTAB = 0x00000002 # Symbol table +SHT_STRTAB = 0x00000003 # String table +SHT_RELA = 0x00000004 # Relocation entries with addends +SHT_HASH = 0x00000005 # Symbol hash table +SHT_DYNAMIC = 0x00000006 # Dynamic linking information +SHT_NOTE = 0x00000007 # Notes +SHT_NOBITS = 0x00000008 # Program space with no data (bss) +SHT_REL = 0x00000009 # Relocation entries, no addends +SHT_SHLIB = 0x0000000A # Reserved +SHT_DYNSYM = 0x0000000B # Dynamic linker symbol table +SHT_INIT_ARRAY = 0x0000000E # Array of constructors +SHT_FINI_ARRAY = 0x0000000F # Array of destructors +SHT_PREINIT_ARRAY = 0x00000010 # Array of pre-constructors +SHT_GROUP = 0x00000011 # Section group +SHT_SYMTAB_SHNDX = 0x00000012 # Extended section indices +SHT_NUM = 0x00000013 # Number of defined types. +SHT_LOOS = 0x60000000 # Start OS-specific. + +# MIPS specific +SHT_MIPS_DEBUG = 0x70000005 # .mdebug +SHT_MIPS_REGINFO = 0x70000006 # .reginfo +SHT_MIPS_OPTIONS = 0x7000000D # .options + +SH_TYPE = { + SHT_NULL : 'SHT_NULL', + SHT_PROGBITS : 'SHT_PROGBITS', + SHT_SYMTAB : 'SHT_SYMTAB', + SHT_STRTAB : 'SHT_STRTAB', + SHT_RELA : 'SHT_RELA', + SHT_HASH : 'SHT_HASH', + SHT_DYNAMIC : 'SHT_DYNAMIC', + SHT_NOTE : 'SHT_NOTE', + SHT_NOBITS : 'SHT_NOBITS', + SHT_REL : 'SHT_REL', + SHT_SHLIB : 'SHT_SHLIB', + SHT_DYNSYM : 'SHT_DYNSYM', + SHT_INIT_ARRAY : 'SHT_INIT_ARRAY', + SHT_FINI_ARRAY : 'SHT_FINI_ARRAY', + SHT_PREINIT_ARRAY : 'SHT_PREINIT_ARRAY', + SHT_GROUP : 'SHT_GROUP', + SHT_SYMTAB_SHNDX : 'SHT_SYMTAB_SHNDX', + SHT_NUM : 'SHT_NUM', + SHT_LOOS : 'SHT_LOOS', + + SHT_MIPS_DEBUG : 'SHT_MIPS_DEBUG', + SHT_MIPS_REGINFO : 'SHT_MIPS_REGINFO', + SHT_MIPS_OPTIONS : 'SHT_MIPS_OPTIONS', +} + +# ===================================================================================================== +# Section Flags +# ===================================================================================================== + +SHF_WRITE = 1 << 0 # Writable +SHF_ALLOC = 1 << 1 # Occupies memory during execution +SHF_EXECINSTR = 1 << 2 # Executable +SHF_MERGE = 1 << 4 # Might be merged +SHF_STRINGS = 1 << 5 # Contains null-terminated strings +SHF_INFO_LINK = 1 << 6 # 'sh_info' contains SHT index +SHF_LINK_ORDER = 1 << 7 # Preserve order after combining +SHF_OS_NONCONFORMING = 1 << 8 # Non-standard OS specific handling required +SHF_GROUP = 1 << 9 # Section is member of a group +SHF_TLS = 1 << 10 # Section hold thread-local data + +SHF_MASKOS = 0x0ff00000 # OS-specific +SHF_MASKPROC = 0xf0000000 # Processor-specific +SHF_ORDERED = 0x04000000 # Special ordering requirement (Solaris) +SHF_EXCLUDE = 0x08000000 # Section is excluded unless referenced or allocated (Solaris) + +SH_FLAG = { + SHF_WRITE : 'SHF_WRITE', + SHF_ALLOC : 'SHF_ALLOC', + SHF_EXECINSTR : 'SHF_EXECINSTR', + SHF_MERGE : 'SHF_MERGE', + SHF_STRINGS : 'SHF_STRINGS', + SHF_INFO_LINK : 'SHF_INFO_LINK', + SHF_LINK_ORDER : 'SHF_LINK_ORDER', + SHF_OS_NONCONFORMING : 'SHF_OS_NONCONFORMING', + SHF_GROUP : 'SHF_GROUP', + SHF_TLS : 'SHF_TLS', + SHF_MASKOS : 'SHF_MASKOS', + SHF_MASKPROC : 'SHF_MASKPROC', + SHF_ORDERED : 'SHF_ORDERED', + SHF_EXCLUDE : 'SHF_EXCLUDE' +} + +# ===================================================================================================== +# ELF Header +# ===================================================================================================== + +ELF32_BIG_STRUCT = '>HHIIIIIHHHHHH' +ELF32_LITTLE_STRUCT = 'IIIBBH', data) + assert self.st_shndx != SHN_XINDEX, "too many sections (SHN_XINDEX not supported)" + self.bind = st_info >> 4 + self.type = st_info & 0xF + self.visibility = self.st_other & 3 + self.parent_section = elf_file.sections[self.st_shndx] if self.st_shndx < SHN_LORESERVE else None + + self.name = name + if self.type == ST_SECTION: + self.name = elf_file.shstrtab.lookup_str(self.parent_section.sh_name) + if self.name == None: + self.name = elf_file.symtab.strtab.lookup_str(self.st_name) + + @staticmethod + def from_parts(st_name, st_value, st_size, st_info, st_other, st_shndx, strtab, name): + header = struct.pack('>IIIBBH', st_name, st_value, st_size, st_info, st_other, st_shndx) + return Symbol(header, strtab, name) + + def to_bin(self): + st_info = (self.bind << 4) | self.type + return struct.pack('>IIIBBH', self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx) + + def section_offset(self): + return self.st_value - self.parent_section.sh_addr + + def padded_size_n(self, n): + return align_as(self.st_size, n) + + def padded_size(self): + return self.padded_size_n(self.parent_section.sh_addralign) + + def __str__(self): + # Num: Value Size Type Bind Vis Ndx Name + ndx = ' ' + (SYM_NDX[self.st_shndx] if self.st_shndx in SYM_NDX.keys() else self.parent_section.name) + out = f"{self.st_value:08X} {self.st_size:06X} {SYM_TYPE[self.type]:7} {SYM_BIND[self.bind]:6} {SYM_VIS[self.visibility]:7} {ndx:12} {self.name}" + return out + +# ===================================================================================================== +# Relocation +# ===================================================================================================== + +class Relocation: + """ + typedef struct { + Elf32_Word r_offset; + struct { + Elf32_Word sym_index : 24; + Elf32_Word rel_type : 8; + } r_info; + Elf32_Word r_addend; + } Elf32_Reloc; + """ + + def __init__(self, data, elf_file, target_section, sh_type): + self.sh_type = sh_type + if sh_type == SHT_REL: + self.r_offset, self.r_info = struct.unpack('>II', data) + self.r_addend = 0 + else: + self.r_offset, self.r_info, self.r_addend = struct.unpack('>III', data) + self.sym_index = self.r_info >> 8 + self.rel_type = self.r_info & 0xff + self.relocated_symbol = elf_file.symtab.symbol_entries[self.sym_index] + self.elf_machine = elf_file.elf_header.e_machine + self.target_section = target_section + # TODO obtain the addend if the target section is executable + + def to_bin(self): + self.r_info = (self.sym_index << 8) | self.rel_type + if self.sh_type == SHT_REL: + return struct.pack('>II', self.r_offset, self.r_info) + else: + return struct.pack('>III', self.r_offset, self.r_info, self.r_addend) + + def relocated_symbol_in_section(self, symtab, section): + return symtab.lookup_symbol_in_section(symtab.symbol_entries[self.sym_index].st_value, section) + + def __str__(self): + relocated_symbol = self.relocated_symbol + # Offset Info Type Sym.Value Sym. Name + Addend + # 80135560 00091201 R_MY_RELOC_TYPE 800f39e0 ...data.0 + 0 + out = f"{self.r_offset:08X} {self.r_info:08X} {RELOC_TYPE[self.elf_machine][self.rel_type]:17} {relocated_symbol.st_value:08X} {relocated_symbol.name} + 0x{self.r_addend:X}" + return out + +# ===================================================================================================== +# Section +# ===================================================================================================== + +class Section: + """ + Describes a section + + typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; + } Elf32_Shdr; + +x00 x00 4 4 sh_name Offset to string in the .shstrtab section representing this section's name + +x04 x04 4 4 sh_type See SH_TYPE + +x08 x08 4 8 sh_flags See SH_FLAG + +x0C x10 4 8 sh_addr Virtual address of the section in memory (for loaded sections) + +x10 x18 4 8 sh_offset Offset of the section in the file image + +x14 x20 4 8 sh_size Size in bytes of the section in the file image + +x18 x28 4 4 sh_link Contains the section index of an associated section. This field is used for several purposes depending on section type + +x1C x2C 4 4 sh_info Contains extra information about the section. This field is used for several purposes, depending on section type + +x20 x30 4 8 sh_addralign Contains the required alignment of the section. This field must be a power of two + +x24 x38 4 8 sh_entsize Contains the size, in bytes, of each entry, for sections that contain fixed-size entries. Zero otherwise + +x28 x40 END + """ + + def __init__(self, header, elf_file, index): + self.late_init_done = False + self.sh_name, self.sh_type, \ + self.sh_flags, self.sh_addr, \ + self.sh_offset, self.sh_size, \ + self.sh_link, self.sh_info, \ + self.sh_addralign, self.sh_entsize = struct.unpack('>IIIIIIIIII', header) + assert not self.sh_flags & SHF_LINK_ORDER + if self.sh_entsize != 0: + assert self.sh_size % self.sh_entsize == 0 + if self.sh_type in [SHT_NULL, SHT_NOBITS]: + self.data = None + else: + self.data = elf_file.data[self.sh_offset:][:self.sh_size] + self.index = index + self.relocated_by = [] + self.elf_file = elf_file + + def late_init(self): + self.late_init_done = True + + @staticmethod + def from_parts(sh_name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, sh_addr, sh_offset, data, index): + header = struct.pack('>IIIIIIIIII', sh_name, sh_type, sh_flags, sh_addr, sh_offset, \ + len(data), sh_link, sh_info, sh_addralign, sh_entsize) + return Section(header, data, index) + + def to_bin(self): + if self.sh_type not in [SHT_NULL, SHT_NOBITS]: + self.sh_size = len(self.data) + header = struct.pack('>IIIIIIIIII', self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize) + return header, self.data + + def get_rel(self, addr): + relocs = [] + for reloc_section in self.relocated_by: + reloc = reloc_section.find_reloc(addr) + if reloc is not None: + relocs.append(reloc) + return relocs + + def get_sym(self, addr): + symtab = self.elf_file.symtab + symbols = [] + for symbol in symtab.symbol_entries: + if symbol.st_value == addr and symbol.st_shndx == self.index and symbol.type != ST_SECTION: + symbols.append(symbol) + return symbols + + def is_rel(self): + return self.sh_type == SHT_REL or self.sh_type == SHT_RELA + + def is_allocable(self): + return (self.sh_flags & SHF_ALLOC) == SHF_ALLOC + + def is_executable(self): + return (self.sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR + + def is_writable(self): + return (self.sh_flags & SHF_WRITE) == SHF_WRITE + + def padded_size(self): + return align_as(self.sh_size, self.sh_addralign) + + def padded_size_4(self): + return align_as(self.sh_size, 4) + + def flags_str(self): + flags = "" + flags += "W" if self.is_writable() else " " + flags += "A" if self.is_allocable() else " " + flags += "X" if self.is_executable() else " " + return flags + + def __str__(self): + s_type = SH_TYPE[self.sh_type].replace('SHT_','') if self.sh_type in SH_TYPE.keys() else str(self.sh_type) + out = f"{self.name:12}{s_type:12} " + out += f"{self.sh_addr:08X} " + out += f"{self.sh_offset:06X} " + out += f"{self.sh_size:06X} " + out += f"{self.sh_entsize:2X} " + out += f"{self.flags_str():3} " + out += f"{self.sh_link:2} " + out += f"{self.sh_info:3} " + out += f"{self.sh_addralign:5X} " + return out + +class SymtabSection(Section): + """ + Symbol Table Section + """ + + def __init__(self, header, elf_file, index): + super().__init__(header, elf_file, index) + assert self.sh_entsize == 16 + + def late_init(self): + if self.late_init_done: + return + super().late_init() + self.strtab = self.elf_file.sections[self.sh_link] + self.symbol_entries = [] + for i in range(0, self.sh_size, self.sh_entsize): + self.symbol_entries.append(Symbol(self.data[i:i+self.sh_entsize], self.elf_file)) + + def to_bin(self): + header, _ = super().to_bin() + data = bytearray() + for sym in self.symbol_entries: + data.extend(sym.to_bin()) + return header, data + + def find_symbol(self, name): + for s in self.symbol_entries: + if s.name == name: + return (s.st_shndx, s.st_value) + return None + + def lookup_symbol(self, vaddr): + found = [] + for s in self.symbol_entries: + if s.st_value == vaddr and s.type != ST_SECTION: + found.append(s) + if len(found) != 0: + found.sort(reverse=True, key=(lambda s : s.type)) + return found[0] + return None + + def lookup_symbol_for_section(self, vaddr, shndx): + found = [] + for s in self.symbol_entries: + if s.st_value == vaddr and s.type != ST_SECTION and s.st_shndx == shndx: + found.append(s) + if len(found) != 0: + found.sort(reverse=True, key=(lambda s : s.type)) + return found[0] + return None + + def lookup_symbol_in_section(self, vaddr, section): + found = [] + for s in self.symbol_entries: + if s.st_value == vaddr and s.type != ST_SECTION and s.st_shndx == section.index: + found.append(s) + if len(found) != 0: + found.sort(reverse=True, key=(lambda s : s.type)) + return found[0] + return None + + def find_symbol_in_section(self, name, section): + pos = self.find_symbol(name) + assert pos is not None + assert pos[0] == section.index + return pos[1] + + def local_symbols(self): + return self.symbol_entries[:self.sh_info] + + def global_symbols(self): + return self.symbol_entries[self.sh_info:] + +class StrtabSection(Section): + """ + String Table Section + """ + def __init__(self, header, data, index): + super().__init__(header, data, index) + + def lookup_str(self, index): + to = self.data.find(b'\0', index) + assert to != -1 + return self.data[index:to].decode('latin1') + +class RelocationSection(Section): + """ + Relocation Section + """ + def __init__(self, header, data, index): + super().__init__(header, data, index) + + def late_init(self): + if self.late_init_done: + return + super().late_init() + self.rel_target = self.elf_file.sections[self.sh_info] + self.rel_target.relocated_by.append(self) + self.relocations = [] + for i in range(0, self.sh_size, self.sh_entsize): + self.relocations.append(Relocation(self.data[i:][:self.sh_entsize], self.elf_file, self.rel_target, self.sh_type)) + + def to_bin(self): + header, _ = super().to_bin() + data = bytearray() + for rel in self.relocations: + data.extend(rel.to_bin()) + return header, data + + def lookup_reloc(self, vaddr): + for r in self.relocations: + if r.r_offset - r.r_offset % 4 == vaddr: + return r + return None + + def find_reloc(self, vaddr): + for r in self.relocations: + if r.r_offset == vaddr: + return r + return None + + def lookup_jtbl_reloc(self, vaddr, symtab): + for r in self.relocations: + r_sym = r.relocated_symbol(symtab) + if r_sym.st_value + r.r_addend == vaddr: + return r + return None + +class MdebugSection(Section): + """ + MIPS Debugging Section + """ + def __init__(self, header, elf_file, index): + super().__init__(header, elf_file, index) + self.parent = self.elf_file + self.hdrr = EcoffHDRR(self.data) + + self.fdrs = [] + for i in range(self.hdrr.ifdMax): + fdr = EcoffFdr.from_binary(self, i) + self.fdrs.append(fdr) + + def late_init(self): + if self.late_init_done: + return + super().late_init() + for fdr in self.fdrs: + fdr.late_init() + + def fdr_forname(self, filename): + for fdr in self.fdrs: + # remove path and file ext + normalized_name = ".".join(fdr.name.split("/")[-1].split(".")[:-1]) + + if normalized_name == filename: + return fdr + return None + + def fdr_foraddr(self, addr, extensions=('.c')): + for fdr in self.fdrs: + if fdr.adr == addr and any((fdr.name.endswith(ext) for ext in extensions)): + return fdr + return None + + def read_string(self, index): + to = self.elf_file.data.find(b'\0', self.hdrr.cbSsOffset + index) + assert to != -1 + return self.elf_file.data[self.hdrr.cbSsOffset + index:to].decode("ASCII") + + def read_ext_string(self, index): + to = self.elf_file.data.find(b'\0', self.hdrr.cbSsExtOffset + index) + assert to != -1 + return self.elf_file.data[self.hdrr.cbSsExtOffset + index:to].decode("ASCII") + +class ReginfoSection(Section): + """ + MIPS Register Information Section + """ + def __init__(self, header, elf_file, index): + super().__init__(header, elf_file, index) + +# ===================================================================================================== +# Elf File +# ===================================================================================================== + +class ElfFile: + def __init__(self, data): + def init_section(i): + offset = self.elf_header.e_shoff + i * self.elf_header.e_shentsize + section_type = struct.unpack(">I", data[offset + 4:][:4])[0] + header_data = data[offset:][:self.elf_header.e_shentsize] + + if section_type == SHT_REL or section_type == SHT_RELA: + return RelocationSection(header_data, self, i) + elif section_type == SHT_SYMTAB: + return SymtabSection(header_data, self, i) + elif section_type == SHT_STRTAB: + return StrtabSection(header_data, self, i) + elif section_type == SHT_MIPS_DEBUG: + return MdebugSection(header_data, self, i) + elif section_type == SHT_MIPS_REGINFO: + return ReginfoSection(header_data, self, i) + else: + return Section(header_data, self, i) + + self.data = data + self.elf_header = ElfHeader(data[0:52]) + + num_progheaders = self.elf_header.e_phnum + num_sections = self.elf_header.e_shnum + + # Init program headers + self.progheaders = [] + for i in range(num_progheaders): + offset = self.elf_header.e_phoff + i * self.elf_header.e_phentsize + self.progheaders.append(ProgramHeader(data[offset:][:self.elf_header.e_phentsize], self.elf_header.e_ident[EI_CLASS])) + + # Init sections + self.sections = [] + for i in range(num_sections): + self.sections.append(init_section(i)) + + # Init shstrtab and name sections + self.shstrtab = self.sections[self.elf_header.e_shstrndx] + assert isinstance(self.shstrtab, StrtabSection) + + for s in self.sections: + s.name = self.shstrtab.lookup_str(s.sh_name) + + # Init symtab + symtab = None + for s in self.sections: + if s.sh_type == SHT_SYMTAB: + assert not symtab , "Found more than one symtab section?" + symtab = s + assert symtab is not None , "Could not find symtab" + self.symtab = symtab + self.symtab.late_init() + + # Late Init sections + for s in self.sections: + s.late_init() + + def find_section_by_name(self, name): + for s in self.sections: + if s.name == name: + return s + return None + + def find_section_by_type(self, type): + for s in self.sections: + if s.sh_type == type: + return s + return None + +### Tests + +if __name__ == "__main__": + import sys + + elf_file = None + + with open(sys.argv[1], "rb") as elf: + elf_file = ElfFile(bytearray(elf.read())) + + # Header Info Test + print(elf_file.elf_header) + # Program Headers Info Test + print("") + print("Program Headers:") + print(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align") + for phdr in elf_file.progheaders: + print(phdr) + # Section Headers Info Test + print("") + print("Section Headers:") + print(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al") + for i,s in enumerate(elf_file.sections,0): + print(f" [{i:2}] {s}") + # Symbols Info Test + print("") + print(f"Symbol table '{elf_file.symtab.name}' contains {len(elf_file.symtab.symbol_entries)} entries") + print(" Num: Value Size Type Bind Vis Ndx Name") + for i,sym in enumerate(elf_file.symtab.symbol_entries,0): + print(f"{i:6}: {sym}") + # Relocations Info Test + print("") + for s in elf_file.sections: + if s.is_rel(): + print(f"\nRelocation section '{s.name}' at offset 0x{s.sh_offset:06X} contains {len(s.relocations)} entries:") + print(" Offset Info Type Sym.Value Sym.Name + Addend") + for reloc in s.relocations: + print(f"{reloc}") + # mdebug Info Test + print("") + mdebug_section = elf_file.find_section_by_type(SHT_MIPS_DEBUG) + if mdebug_section is not None: + """ + for fdr in mdebug_section.fdrs: + print(fdr) + for symr in fdr.symrs: + print(symr) + for pdr in fdr.pdrs: + print(pdr) + for symr in pdr.symrs: + print(symr) + for liner in pdr.lines: + print(liner) + """ + for fdr in mdebug_section.fdrs: + print(fdr.c_str()) diff --git a/lib/ultralib/tools/mdebug.py b/lib/ultralib/tools/mdebug.py new file mode 100644 index 00000000..6f061ecc --- /dev/null +++ b/lib/ultralib/tools/mdebug.py @@ -0,0 +1,938 @@ +#!/usr/bin/env python3 +# +# .mdebug section +# + +""" +References: +https://www.cs.unibo.it/~solmi/teaching/arch_2002-2003/AssemblyLanguageProgDoc.pdf +https://web.archive.org/web/20010628021622/http://reality.sgi.com/davea/objectinfo.html +https://github.com/astrelsky/ghidra_mdebug +https://github.com/Rozelette/print-mdebug/blob/master/print_mdebug.py +https://opensource.apple.com/source/gcc_legacy/gcc_legacy-938/gcc/mips-tdump.c.auto.html +https://github.com/uhhpctools/openuh/blob/master/osprey-gcc-4.2.0/gcc/mips-tdump.c +https://github.com/bminor/binutils-gdb/blob/master/gdb/mdebugread.c + +(stabs docs): +https://sourceware.org/gdb/current/onlinedocs/stabs.html + +(ecoff docs): +https://web.archive.org/web/20160305114748/http://h41361.www4.hp.com/docs/base_doc/DOCUMENTATION/V50A_ACRO_SUP/OBJSPEC.PDF +https://chromium.googlesource.com/native_client/nacl-toolchain/+/refs/tags/gcc-4.4.3/binutils/gas/ecoff.c +https://kernel.googlesource.com/pub/scm/linux/kernel/git/hjl/binutils/+/hjl/secondary/include/coff/sym.h +https://kernel.googlesource.com/pub/scm/linux/kernel/git/hjl/binutils/+/hjl/secondary/include/coff/symconst.h +""" + +from enum import IntEnum +import struct + +class EcoffBt(IntEnum): # Basic Type + NIL = 0 # + ADR = 1 # pointer-sized integer type + CHAR = 2 # char + UCHAR = 3 # unsigned char + SHORT = 4 # short + USHORT = 5 # unsigned short + INT = 6 # int + UINT = 7 # unsigned int + LONG = 8 # long + ULONG = 9 # unsigned long + FLOAT = 10 # float + DOUBLE = 11 # double + STRUCT = 12 # struct + UNION = 13 # union + ENUM = 14 # enum + TYPEDEF = 15 # type definition + RANGE = 16 # subrange of int + SET = 17 # pascal set + COMPLEX = 18 # FORTRAN complex + DCOMPLEX = 19 # FORTRAN double com[plex + INDIRECT = 20 # forward or unnamed typedef + FIXEDDEC = 21 # Fixed point decimal + FLOATDEC = 22 # Floating point decimal + STRING = 23 # Varying length character string + BIT = 24 # Aligned bit tring + PICTURE = 25 # picture + VOID = 26 # void + LONGLONG = 27 # long long int + ULONGLONG = 28 # unsigned long long int + LONG64 = 30 # + ULONG64 = 31 # + LONGLONG64 = 32 # + ULONGLONG64 = 33 # + ADR64 = 34 # + INT64 = 35 # + UINT64 = 36 # + + AGGREGATE = 63 # not a basic type + MAX = 64 # + +class EcoffSc(IntEnum): + NIL = 0 + TEXT = 1 # .text symbol + DATA = 2 # .data symbol + BSS = 3 # .bss symbol + REGISTER = 4 # value of symbol is register number + ABS = 5 # value of symbol is absolute + UNDEFINED = 6 # value of symbol is undefined + CDBLOCAL = 7 # variable value is in se->va.?? + BITS = 8 # variable is a bit field + CDBSYSTEM = 9 # variable value is in cdb address space + REGIMAGE = 10 # register value is saved on stack + INFO = 11 # symbol contains debugger information + USERSTRUCT = 12 # address in struct user for current process + SDATA = 13 # load time only small data + SBSS = 14 # load time only small common + RDATA = 15 # load time only read-only data + VAR = 16 # var parameter (FORTRAN, Pascal) + COMMON = 17 # common variable + SCOMMON = 18 # small common + VARREGISTER = 19 # var parameter in a register + VARIANT = 20 # variant record + SUNDEFINED = 21 # small undefined (external) data + INIT = 22 # .init section symbol + BASEDVAR = 23 # FORTRAN or PL/1 ptr based var + XDATA = 24 # exception handling data + PDATA = 25 # procedure section + FINI = 26 # .fini section + RCONST = 27 # .rconst section + MAX = 32 # + +class EcoffSt(IntEnum): + NIL = 0 # + GLOBAL = 1 # external symbol + STATIC = 2 # static symbol + PARAM = 3 # procedure argument + LOCAL = 4 # local variable + LABEL = 5 # label + PROC = 6 # procedure + BLOCK = 7 # beginning of block + END = 8 # end of something + MEMBER = 9 # member of struct/union/enum/.. + TYPEDEF = 10 # type definition + FILE = 11 # filename + REGRELOC = 12 # register relocation + FORWARD = 13 # forwarding address + STATICPROC = 14 # load time only static procedures + # (CONSTANT and STAPARAM are in different orders between different sources...) + CONSTANT = 15 # constant + STAPARAM = 16 # FORTRAN static parameters + STRUCT = 26 # structure + UNION = 27 # union + ENUM = 28 # enum + INDIRECT = 34 # + +class EcoffTq(IntEnum): # Type qualifier + NIL = 0 # + PTR = 1 # pointer + PROC = 2 # procedure + ARRAY = 3 # array + FAR = 4 # longer addressing + VOL = 5 # volatile + CONST = 6 # constant + MAX = 8 # + + UNK7 = 7 # invalid + UNK9 = 9 # invalid + UNK10 = 10 # invalid + UNK11 = 11 # invalid + UNK12 = 12 # invalid + UNK13 = 13 # invalid + UNK14 = 14 # invalid + UNK = 15 # invalid + +class EcoffLanguageCode(IntEnum): + C = 0 + PASCAL = 1 + FORTRAN = 2 + ASM = 3 + MACHINE = 4 + NIL = 5 + ADA = 6 + PL1 = 7 + COBOL = 8 + STDC = 9 + CPLUSPLUSV2 = 10 + MAX = 11 + +def get_bitrange(value, start, length): + return (value >> start) & ((1 << length) - 1) + +def sign_extend_16(value): + return (value & 0x7FFF) - (value & 0x8000) + +def sign_extend_4(value): + return (value & 0x7) - (value & 0x8) + +class EcoffLiner: + """ + ECOFF Line Numbers Mapping + + typedef struct sLINER { + s32 count : 4; + s32 delta : 4; + } tLINER, *pLINER; + """ + + def __init__(self, data) -> None: + self.count = get_bitrange(data[0], 0, 4) + 1 + self.delta = get_bitrange(data[0], 4, 4) + + if self.delta == 8: + self.is_extended = True + self.delta = sign_extend_16((data[1] << 8) | data[2]) + self.data = data[:3] + else: + self.is_extended = False + self.delta = sign_extend_4(self.delta) + self.data = data[:1] + + def __str__(self) -> str: + return f"""= EcoffLiner ============= +delta = {self.delta} +count = {self.count} +extended = {self.is_extended}""" + +class EcoffTir: + """ + ECOFF Type Information Record + + typedef struct { +#ifdef LITTLE_ENDIAN + u32 tq3 : 4; + u32 tq2 : 4; + u32 tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + u32 tq0 : 4; + /* ---- 16 bit boundary ---- */ + u32 tq5 : 4; + u32 tq4 : 4; + u32 bt : 6; /* basic type */ + u32 continued : 1; /* indicates additional TQ info in next AUX */ + u32 fBitfield : 1; /* set if bit width is specified */ +#else + u32 fBitfield : 1; /* set if bit width is specified */ + u32 continued : 1; /* indicates additional TQ info in next AUX */ + u32 bt : 6; /* basic type */ + u32 tq4 : 4; + u32 tq5 : 4; + /* ---- 16 bit boundary ---- */ + u32 tq0 : 4; + u32 tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + u32 tq2 : 4; + u32 tq3 : 4; +#endif + } TIR, *pTIR; // size = 4 + """ + SIZE = 4 + + def __init__(self, data, endian) -> None: + if endian == 1: + self.tq3 = EcoffTq(get_bitrange(data, 0, 4)) + self.tq2 = EcoffTq(get_bitrange(data, 4, 4)) + self.tq1 = EcoffTq(get_bitrange(data, 8, 4)) + self.tq0 = EcoffTq(get_bitrange(data, 12, 4)) + self.tq5 = EcoffTq(get_bitrange(data, 16, 4)) + self.tq4 = EcoffTq(get_bitrange(data, 20, 4)) + self.bt = EcoffBt(get_bitrange(data, 24, 6)) + self.continued = get_bitrange(data, 30, 1) + self.fBitfield = get_bitrange(data, 31, 1) + else: + self.fBitfield = get_bitrange(data, 0, 1) + self.continued = get_bitrange(data, 1, 1) + self.bt = EcoffBt(get_bitrange(data, 2, 6)) + self.tq4 = EcoffTq(get_bitrange(data, 8, 4)) + self.tq5 = EcoffTq(get_bitrange(data, 12, 4)) + self.tq0 = EcoffTq(get_bitrange(data, 16, 4)) + self.tq1 = EcoffTq(get_bitrange(data, 20, 4)) + self.tq2 = EcoffTq(get_bitrange(data, 24, 4)) + self.tq3 = EcoffTq(get_bitrange(data, 28, 4)) + self.tqs = (self.tq0, self.tq1, self.tq2, self.tq3, self.tq4, self.tq5) + + def __str__(self) -> str: + return f"""= EcoffTIR ============== +fBitfield = {self.fBitfield} +continued = {self.continued} +bt = {self.bt.name} +tq4 = {self.tq4} +tq5 = {self.tq5} +tq0 = {self.tq0} +tq1 = {self.tq1} +tq2 = {self.tq2} +tq3 = {self.tq3}""" + +class EcoffRNDXR: + """ + typedef struct { +#ifdef LITTLE_ENDIAN + u32 index : 20; /* index int sym/aux/iss tables */ + u32 rfd : 12; /* index into the file indirect table */ +#else + u32 rfd : 12; /* index into the file indirect table */ + u32 index : 20; /* index int sym/aux/iss tables */ +#endif + } RNDXR, *pRNDXR; // size = 4 + """ + SIZE = 4 + + def __init__(self, data, endian) -> None: + if endian == 1: + self.index = get_bitrange(data, 0, 20) + self.rfd = get_bitrange(data, 20, 12) + else: + self.rfd = get_bitrange(data, 0, 12) + self.index = get_bitrange(data, 12, 20) + + def __str__(self) -> str: + return f"""= EcoffRNDXR ============== +index = {self.index} +rfd = {self.rfd}""" + +class EcoffAux: + """ + typedef union __sgi_auxu_u { + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + long_i dnLow; /* low dimension of array */ + long_i dnHigh; /* high dimension of array */ + long_i isym; /* symbol table index (end of proc) */ + long_i iss; /* index into string space (not used) */ + long_i width; /* width for non-default sized struct fields */ + long_i count; /* count of ranges for variant arm */ + } AUXU, *pAUXU; // size = 4 + """ + SIZE = 4 + + def __init__(self, fdr, data, endian) -> None: + data = struct.unpack((">" if endian == 1 else "<") + "I", data)[0] + self.ti = EcoffTir(data, endian) + self.rndx = EcoffRNDXR(data, endian) + self.dnLow = self.dnHigh = self.isym = self.iss = self.width = self.count = data + self.fdr = fdr + + def __str__(self) -> str: + return f"""= EcoffAux ============== +ti = {{ +{self.ti} +}} +rndx = {{ +{self.rndx} +}} +dnLow = {self.dnLow:04X} +dnHigh = {self.dnHigh:04X} +isym = {self.isym:04X} +iss = {self.iss:04X} +width = {self.width:04X} +count = {self.count:04X}""" + +class EcoffSymr: + """ + ECOFF Local Symbol + + typedef struct sSymr { + s32 iss; /* index into String Space of name */ + s32 value; /* symbol value */ + /* value can be an address, size or frame offset depending on symbol type */ + EcoffSt st : 6; /* symbol type */ + EcoffSc sc : 5; /* storage class - text, data, etc */ + s32 _reserved : 1; /* reserved bit */ + s32 index : 20; /* index into sym/aux table */ + } tSymr, *pSymr; // size = 0xC + """ + SIZE = 0xC + + def __init__(self, parent, idx, data): + self.idx = idx + self.parent = parent # can be either Fdr or Pdr + self.pdr = parent if type(parent) == EcoffPdr else None + self.fdr = self.pdr.parent if self.pdr is not None else parent + + self.data = data[:EcoffSymr.SIZE] + + self.iss, self.value, bits = struct.unpack(">III", self.data) + self.st = EcoffSt(get_bitrange(bits, 26, 6)) + self.sc = EcoffSc(get_bitrange(bits, 21, 5)) + self._reserved = get_bitrange(bits, 20, 1) + self.index = get_bitrange(bits, 0, 20) + + self.name = self.fdr.read_string(self.iss) + self.type_name = None + + self.c_repr = None + + assert self._reserved == 0 # Sanity check + + def link_syms(self): + if self.st == EcoffSt.END: + self.start_sym = self.fdr.symrs[self.index] + elif self.st in [EcoffSt.BLOCK, EcoffSt.FILE, EcoffSt.STRUCT, EcoffSt.UNION, EcoffSt.ENUM]: + self.end_sym = self.fdr.symrs[self.index - 1] + elif self.st in [EcoffSt.PROC, EcoffSt.STATICPROC]: + aux = self.fdr.auxs[self.index] + self.end_sym = self.fdr.symrs[aux.isym - 1] + elif self.st in [EcoffSt.GLOBAL, EcoffSt.STATIC, EcoffSt.PARAM, EcoffSt.LOCAL, EcoffSt.MEMBER, EcoffSt.TYPEDEF, EcoffSt.FORWARD]: + pass + + def late_init(self): + if self.st == EcoffSt.END: + """ + END symbols index the associated begin symbol + """ + self.start_sym = self.fdr.symrs[self.index] + if self.start_sym.st == EcoffSt.BLOCK: + self.c_repr = "}" + elif self.start_sym.st == EcoffSt.FILE: + self.c_repr = f"// end of file: \"{self.start_sym.name}\"" + elif self.start_sym.st in [EcoffSt.STRUCT, EcoffSt.UNION, EcoffSt.ENUM]: + self.c_repr = "}" + if len(self.start_sym.type_name) != 0: + self.c_repr += " " + self.start_sym.type_name + self.c_repr += f";" + elif self.st in [EcoffSt.BLOCK, EcoffSt.FILE, EcoffSt.STRUCT, EcoffSt.UNION, EcoffSt.ENUM]: + """ + These symbols index the first symbol after their associated END symbol + """ + self.end_sym = self.fdr.symrs[self.index - 1] + if self.st == EcoffSt.BLOCK: + self.c_repr = "{" + elif self.st == EcoffSt.FILE: + self.c_repr = f"#line 1 \"{self.name}\"" + elif self.st in [EcoffSt.STRUCT, EcoffSt.UNION, EcoffSt.ENUM]: + keyword = "" + self.type_name = "" + next_sym = self.fdr.symrs[self.index] + if next_sym.st == EcoffSt.TYPEDEF: + # possible typedef struct/union/enum + # TODO check this by ensuring the typedef symbol references this symbol + keyword += "typedef " + self.type_name = next_sym.name + + if self.st == EcoffSt.UNION: + keyword += "union" + elif self.st == EcoffSt.ENUM: + keyword += "enum" + else: + keyword += "struct" + + name = self.name + if len(name) != 0: + name = ' ' + name + + self.c_repr = f"{keyword}{name} {{" + elif self.st in [EcoffSt.PROC, EcoffSt.STATICPROC]: + aux1 = self.fdr.auxs[self.index] + self.end_sym = self.fdr.symrs[aux1.isym - 1] + + self.c_repr = "" + if self.st == EcoffSt.STATICPROC: + self.c_repr += "static " + + self.return_type, _ = self.process_type_information(1) + self.c_repr += self.return_type + if len(self.return_type) != 0: + self.c_repr += " " + self.c_repr += self.name + self.c_repr += "()" + elif self.st in [EcoffSt.GLOBAL, EcoffSt.STATIC, EcoffSt.PARAM, EcoffSt.LOCAL, EcoffSt.MEMBER, EcoffSt.FORWARD]: + self.c_repr = "" + if self.st == EcoffSt.MEMBER: + # value of a stMember is the offset in bits + self.c_repr += f"/* 0x{self.value//8:X} */ " + + type_str, bitwidth = self.process_type_information(0) + self.c_repr += type_str + if len(self.c_repr) != 0: + self.c_repr += " " + self.c_repr += f"{self.name}{f' : {bitwidth}' if bitwidth is not None else ''};" + elif self.st == EcoffSt.TYPEDEF: + # TODO the typedef may already be absorbed into a struct or similar, check before emitting + type_str, _ = self.process_type_information(0) + self.c_repr = f"typedef {type_str} {self.name};" + elif self.st == EcoffSt.LABEL: + self.c_repr = f"{self.name}:" + + def process_type_information(self, ind): + c_bt_names = { + EcoffBt.NIL : None, + EcoffBt.ADR : None, + EcoffBt.CHAR : "signed char", + EcoffBt.UCHAR : "char", + EcoffBt.SHORT : "short", + EcoffBt.USHORT : "unsigned short", + EcoffBt.INT : "int", + EcoffBt.UINT : "unsigned int", + EcoffBt.LONG : "long", + EcoffBt.ULONG : "unsigned long", + EcoffBt.FLOAT : "float", + EcoffBt.DOUBLE : "double", + EcoffBt.STRUCT : "struct", + EcoffBt.UNION : "union", + EcoffBt.ENUM : "enum", + EcoffBt.TYPEDEF : "typedef", + EcoffBt.RANGE : None, + EcoffBt.SET : None, + EcoffBt.COMPLEX : "complex", + EcoffBt.DCOMPLEX : "double complex", + EcoffBt.INDIRECT : None, + EcoffBt.FIXEDDEC : None, + EcoffBt.FLOATDEC : None, + EcoffBt.STRING : "const char*", + EcoffBt.BIT : None, + EcoffBt.PICTURE : None, + EcoffBt.VOID : "void", + EcoffBt.LONGLONG : "long long", + EcoffBt.ULONGLONG : "unsigned long long", + EcoffBt.LONG64 : "long", + EcoffBt.ULONG64 : "unsigned long", + EcoffBt.LONGLONG64 : "long long", + EcoffBt.ULONGLONG64 : "unsigned long long", + EcoffBt.ADR64 : None, + EcoffBt.INT64 : None, + EcoffBt.UINT64 : None, + } + c_tq_str = { + EcoffTq.NIL : "", + EcoffTq.PTR : "*", + EcoffTq.PROC : "()", + EcoffTq.ARRAY : "[]", + EcoffTq.FAR : "/* FAR */", + EcoffTq.VOL : "volatile", + EcoffTq.CONST : "const", + } + + if self.index == 0xFFFFF: + # no type info + return "", None + + aux = self.fdr.auxs[self.index + ind] + ind += 1 + type_str = "" + + bit_width = None + if aux.ti.fBitfield == 1: + bit_width = self.fdr.auxs[self.index + ind].isym + ind += 1 + + if aux.ti.bt in [EcoffBt.STRUCT, EcoffBt.UNION, EcoffBt.ENUM, EcoffBt.TYPEDEF]: + type_ref_aux = self.fdr.auxs[self.index + ind] + ind += 1 + + fd_ref_idx = type_ref_aux.rndx.rfd + if fd_ref_idx == 4095: + fd_ref_idx = self.fdr.auxs[self.index + ind].isym + ind += 1 + + fdr_ref = self.fdr.parent.fdrs[fd_ref_idx] + sym_ref = fdr_ref.symrs[type_ref_aux.rndx.index] + # now we have the reference to the stStruct, stUnion, stEnum, or stTypeDef + type_str += f"{sym_ref.type_name if sym_ref.type_name is not None else sym_ref.name}" + else: + type_str += f"{c_bt_names[aux.ti.bt]}" + + # TODO improve emitting qualified types + tqs = "" + for tq in aux.ti.tqs: + if tq == EcoffTq.NIL: + continue + if tq == EcoffTq.ARRAY: + ind += 2 # skips over some info such as the type of index (always int for C) + array_low_aux = self.fdr.auxs[self.index + ind] + array_high_aux = self.fdr.auxs[self.index + ind + 1] + stride_aux = self.fdr.auxs[self.index + ind + 2] + ind += 3 + tqs += "[" + if array_high_aux.dnHigh != 0xFFFFFFFF: + tqs += '%d' % (array_high_aux.dnHigh + 1) + tqs += "]" + else: + tqs += c_tq_str[tq] + tqs += " " + tqs = tqs.strip() + if len(tqs) != 0: + type_str += " " + tqs + + return type_str, bit_width + + def __str__(self) -> str: + return f"""= EcoffSymr ============== {self.idx} +iss = 0x{self.iss:08X} +value = 0x{self.value:08X} +st = st{self.st.name} +sc = sc{self.sc.name} +_reserved = {self._reserved} +index = 0x{self.index:05X} +name = {self.name}""" + +class EcoffPdr: + """ + ECOFF Procedure Descriptor + + typedef struct sPDR { + s32 addr; /* memory address of start of procedure */ + s32 isym; /* start of local symbol entries */ + s32 iline; /* start of line number entries */ + s32 regmask; /* save register mask */ + s32 regoffset; /* save register offset */ + s32 iopt; /* start of optimization symbol entries */ + s32 fregmask; /* save floating point register mask */ + s32 fregoffset; /* save floating point register offset */ + s32 frameoffset; /* frame size */ + u16 framereg; /* frame pointer register */ + u16 pcreg; /* offset or reg of return pc */ + s32 lnLow; /* lowest line in the procedure */ + s32 lnHigh; /* highest line in the procedure */ + s32 cbLineOffset; /* byte offset for this procedure from the fd base */ +#ifdef 64_BIT + // TODO there's a bitfield in here + s32 gpPrologue; /* byte size of GP prologue */ + s32 gpUsed; /* true if the procedure uses GP */ + s32 regFrame; /* true if register frame procedure */ + s32 prof; /* true if compiled with -pg */ + s32 localOffset; /* offset of local variables from vfp */ +#endif + } tPDR, *pPDR; // size = 0x34 + """ + SIZE = 0x34 + + def __init__(self, fdr, data) -> None: + self.parent = fdr + self.data = data[:EcoffPdr.SIZE] + + self.addr, self.isym, self.iline, self.regmask, \ + self.regoffset, self.iopt, self.fregmask, self.fregoffset, \ + self.frameoffset, self.framereg, self.pcreg, self.lnLow, \ + self.lnHigh, self.cbLineOffset = struct.unpack(">IIIIIIIIIHHIII", self.data) + + self.symrs = [] + + i = self.isym + symr = self.parent.symrs[i] + assert symr.st == EcoffSt.PROC or symr.st == EcoffSt.STATICPROC + # Inherit procedure name from procedure symbol + self.name = symr.name + + self.symrs.append(symr) + while not (symr.st == EcoffSt.END and symr.name == self.symrs[0].name): + i += 1 + symr = self.parent.symrs[i] + self.symrs.append(symr) + + assert symr.st == EcoffSt.END and symr.sc == EcoffSc.TEXT + self.size = symr.value # value field of an stEND and scTEXT symbol is the procedure size + assert self.size % 4 == 0 + + # indexed by asm word offset from proc start + self.lines = [] + + # ilineMax = self.parent.parent.hdrr.ilineMax + # cbLine = self.parent.parent.hdrr.cbLine + # cbLineOffset = self.parent.parent.hdrr.cbLineOffset + # ilineBase = self.parent.ilineBase + # cline = self.parent.cline + # cbLineOffset = self.parent.cbLineOffset + # cbLine = self.parent.cbLine + # lnLow = self.lnLow + # lnHigh = self.lnHigh + # iline = self.iline + + elf_data = self.parent.parent.parent.data + + line_no = self.lnLow # first line in the procedure + line_data = self.parent.parent.hdrr.cbLineOffset + self.parent.cbLineOffset + self.cbLineOffset + # line_end = self.parent.parent.hdrr.cbLineOffset + self.parent.cbLineOffset + self.parent.cbLine + + # print(self) + # print(f"{self.name} [{self.lnLow}:{self.lnHigh}]") + # print(self.size//4) + while len(self.lines) < self.size//4: + # assert line_data < line_end , "Overflow in line numbers table" + + liner = EcoffLiner(elf_data[line_data:]) + line_no += liner.delta + # if line_no < self.lnLow or line_no > self.lnHigh: + # break + + # print(liner) + for i in range(liner.count): + # print(f"[{len(self.lines)}] {line_no}") + self.lines.append(line_no) + + line_data += len(liner.data) + + def lookup_sym(self, value, type=-1): + for sym in self.symrs: + if sym.value == value and (type == -1 or type == sym.st): + return sym + return None + + def __str__(self) -> str: + return f"""= EcoffPdr =============== +addr = 0x{self.addr:08X} +isym = 0x{self.isym:08X} +iline = 0x{self.iline:08X} +regmask = 0b{self.regmask:032b} +regoffset = 0x{self.regoffset:08X} +iopt = 0x{self.iopt:08X} +fregmask = 0b{self.fregmask:032b} +fregoffset = 0x{self.fregoffset:08X} +frameoffset = 0x{self.frameoffset:08X} +framereg = ${self.framereg} +pcreg = ${self.pcreg} +lnLow = {self.lnLow} +lnHigh = {self.lnHigh} +cbLineOffset = 0x{self.cbLineOffset:08X} +name = {self.name}""" + +class EcoffFdr: + """ + ECOFF File Descriptor + + typedef struct sFDR { + u32 adr; /* memory address of beginning of file */ + s32 rss; /* file name (of source, if known) */ + s32 issBase; /* file's string space */ + s32 cbSs; /* number of bytes in the ss */ + s32 isymBase; /* beginning of symbols */ + s32 csym; /* count file's of symbols */ + s32 ilineBase; /* file's line symbols */ + s32 cline; /* count of file's line symbols */ + s32 ioptBase; /* file's optimization entries */ + s32 copt; /* count of file's optimization entries */ + u16 ipdFirst; /* start of procedures for this file */ + u16 cpd; /* count of procedures for this file */ + s32 iauxBase; /* file's auxiliary entries */ + s32 caux; /* count of file's auxiliary entries */ + s32 rfdBase; /* index into the file indirect table */ + s32 crfd; /* count file indirect entries */ + EcoffLanguageCode lang : 5; /* language for this file */ + u32 fMerge : 1; /* whether this file can be merged */ + u32 fReadin : 1; /* true if it was read in (not just created) */ + u32 fBigEndian : 1; /* true if AUXU's are big endian */ + u32 glevel : 2; /* level this file was compiled with */ + u32 _reserved : 20; /* reserved bits */ + s32 cbLineOffset; /* byte offset from header for this file ln's */ + s32 cbLine; /* size of lines for this file */ + } tFDR, *pFDR; // size = 0x48 + """ + SIZE = 0x48 + + @staticmethod + def from_binary(mdebug, i): + # Init + if 'init' not in EcoffFdr.from_binary.__dict__: + EcoffFdr.from_binary.cache = {} + EcoffFdr.from_binary.init = True + # Parent Init + if mdebug not in EcoffFdr.from_binary.cache: + EcoffFdr.from_binary.cache[mdebug] = {} + # Cache hit + if i in EcoffFdr.from_binary.cache[mdebug]: + return EcoffFdr.from_binary.cache[mdebug][i] + # Cache miss + cbFdOffset = mdebug.hdrr.cbFdOffset + elf_data = mdebug.parent.data + EcoffFdr.from_binary.cache[mdebug][i] = EcoffFdr(mdebug, elf_data[cbFdOffset+i*EcoffFdr.SIZE:cbFdOffset+(i+1)*EcoffFdr.SIZE]) + return EcoffFdr.from_binary.cache[mdebug][i] + + def __init__(self, mdebug, data) -> None: + self.parent = mdebug + self.data = data[:EcoffFdr.SIZE] + + self.adr, self.rss, self.issBase, self.cbSs, \ + self.isymBase, self.csym, self.ilineBase, self.cline, \ + self.ioptBase, self.copt, self.ipdFirst, self.cpd, \ + self.iauxBase, self.caux, self.rfdBase, self.crfd, \ + bits, self.cbLineOffset, self.cbLine = struct.unpack(">IIIIIIIIIIHHIIIIIII", self.data) + + self.lang = EcoffLanguageCode(get_bitrange(bits, 27, 5)) + self.fMerge = get_bitrange(bits, 26, 1) + self.fReadin = get_bitrange(bits, 25, 1) + self.fBigEndian = get_bitrange(bits, 24, 1) + self.glevel = get_bitrange(bits, 22, 2) + self._reserved = get_bitrange(bits, 2, 20) + + self.name = self.parent.read_string(self.issBase + self.rss) + + # print(self) + + hdrr = self.parent.hdrr + elf_data = self.parent.parent.data + + # Aux Symbols + self.auxs = [] + for i in range(self.caux): + i += self.iauxBase + assert i < hdrr.iauxMax , "Out of bounds in Auxiliary Symbol Table" + aux = EcoffAux(self, elf_data[hdrr.cbAuxOffset+i*EcoffAux.SIZE:][:EcoffAux.SIZE], self.fBigEndian) + self.auxs.append(aux) + + # Symbols + self.symrs = [] + for i in range(self.csym): + j = i + self.isymBase + assert j < hdrr.isymMax , "Out of bounds in Local Symbol Table" + symr = EcoffSymr(self, i, elf_data[hdrr.cbSymOffset+j*EcoffSymr.SIZE:hdrr.cbSymOffset+(j+1)*EcoffSymr.SIZE]) + self.symrs.append(symr) + for symr in self.symrs: + symr.link_syms() + + # PDRs + self.pdrs = [] + for i in range(self.cpd): + i += self.ipdFirst + assert i < hdrr.ipdMax , "Out of bounds in Procedure Descriptor Table" + pdr = EcoffPdr(self, elf_data[hdrr.cbPdOffset+i*EcoffPdr.SIZE:hdrr.cbPdOffset+(i+1)*EcoffPdr.SIZE]) + self.pdrs.append(pdr) + + self.size = sum([pdr.size for pdr in self.pdrs]) + + def late_init(self): + for symr in self.symrs: + symr.late_init() + + def pdr_forname(self, procedure_name): + for pdr in self.pdrs: + if pdr.name == procedure_name: + return pdr + return None + + def pdr_foranyaddr(self, addr): + for pdr in self.pdrs: + if pdr.addr <= addr and pdr.addr + pdr.size > addr: + return pdr + return None + + def pdr_foraddr(self, addr): + for pdr in self.pdrs: + if pdr.addr == addr: + return pdr + return None + + def read_string(self, index): + return self.parent.read_string(self.issBase + index) + + def c_str(self) -> str: + """ + C prettyprint file + """ + def print_symbol(symr): + return f"{symr.st.name} :: {symr.c_repr}" + + indent = 0 + out = f"File: {self.name}\n" + + for symr in self.symrs: + if symr.st in [EcoffSt.END]: + indent -= 2 + + out += " " * indent + out += print_symbol(symr) + out += "\n" + + if symr.st in [EcoffSt.FILE, EcoffSt.STRUCT, EcoffSt.UNION, EcoffSt.PROC, EcoffSt.STATICPROC, EcoffSt.BLOCK]: + indent += 2 + + return out + + def __str__(self) -> str: + return f"""= EcoffFdr =============== +adr = 0x{self.adr:08X} +rss = 0x{self.rss:08X} +issBase = 0x{self.issBase:08X} +cbSs = 0x{self.cbSs:08X} +isymBase = 0x{self.isymBase:08X} +csym = 0x{self.csym:08X} +ilineBase = 0x{self.ilineBase:08X} +cline = 0x{self.cline:08X} +ioptBase = 0x{self.ioptBase:08X} +copt = 0x{self.copt:08X} +ipdFirst = 0x{self.ipdFirst:08X} +cpd = 0x{self.cpd:08X} +iauxBase = 0x{self.iauxBase:08X} +caux = 0x{self.caux:08X} +rfdBase = 0x{self.rfdBase:08X} +crfd = 0x{self.crfd:08X} +lang = {self.lang.name} +fMerge = {bool(self.fMerge)} +fReadin = {bool(self.fReadin)} +fBigEndian = {bool(self.fBigEndian)} +glevel = {self.glevel} +_reserved = {self._reserved} +cbLineOffset = 0x{self.cbLineOffset:08X} +cbLine = 0x{self.cbLine:08X} +name = {self.name}""" + +class EcoffHDRR: + """ + Symbolic Header + + typedef struct sHDRR { + u16 magic; /* 0x7009 */ + u16 vstamp; /* version stamp */ + s32 ilineMax; /* number of line number entries */ + s32 cbLine; /* number of bytes for line number entries */ + s32 cbLineOffset; /* offset to start of line number entries */ + s32 idnMax; /* max index into dense number table */ + s32 cbDnOffset; /* offset to start dense number table */ + s32 ipdMax; /* number of procedures */ + s32 cbPdOffset; /* offset to procedure descriptor table */ + s32 isymMax; /* number of local symbols */ + s32 cbSymOffset; /* offset to start of local symbols */ + s32 ioptMax; /* max index into optimization symbol entries */ + s32 cbOptOffset; /* offset to optimization symbol entries */ + s32 iauxMax; /* number of auxillary symbol entries */ + s32 cbAuxOffset; /* offset to start of auxillary symbol entries */ + s32 issMax; /* max index into local strings */ + s32 cbSsOffset; /* offset to start of local strings */ + s32 issExtMax; /* max index into external strings */ + s32 cbSsExtOffset; /* offset to start of external strings */ + s32 ifdMax; /* number of file descriptor entries */ + s32 cbFdOffset; /* offset to file descriptor table */ + s32 crfd; /* number of relative file descriptor entries */ + s32 cbRfdOffset; /* offset to relative file descriptor table */ + s32 iextMax; /* max index into external symbols */ + s32 cbExtOffset; /* offset to start of external symbol entries */ + } tHDRR, *pHDRR; // size = 0x60 + """ + HDRR_MAGIC = 0x7009 + SIZE = 0x60 + + def __init__(self, data) -> None: + self.data = data[:EcoffHDRR.SIZE] + + self.magic, self.vstamp, self.ilineMax, self.cbLine, \ + self.cbLineOffset, self.idnMax, self.cbDnOffset, self.ipdMax, \ + self.cbPdOffset, self.isymMax, self.cbSymOffset, self.ioptMax, \ + self.cbOptOffset, self.iauxMax, self.cbAuxOffset, self.issMax, \ + self.cbSsOffset, self.issExtMax, self.cbSsExtOffset, self.ifdMax, \ + self.cbFdOffset, self.crfd, self.cbRfdOffset, self.iextMax, \ + self.cbExtOffset = struct.unpack(">HHIIIIIIIIIIIIIIIIIIIIIII", self.data) + + assert self.magic == EcoffHDRR.HDRR_MAGIC , f"Symbolic Header magic value is incorrect. Got 0x{self.magic:04X}, expected 0x{EcoffHDRR.HDRR_MAGIC:04X}" + + def __str__(self) -> str: + return f"""= EcoffHDRR ============== +magic = 0x{self.magic:04X} +vstamp = 0x{self.vstamp:04X} +ilineMax = 0x{self.ilineMax:08X} +cbLine = 0x{self.cbLine:08X} +cbLineOffset = 0x{self.cbLineOffset:08X} +idnMax = 0x{self.idnMax:08X} +cbDnOffset = 0x{self.cbDnOffset:08X} +ipdMax = 0x{self.ipdMax:08X} +cbPdOffset = 0x{self.cbPdOffset:08X} +isymMax = 0x{self.isymMax:08X} +cbSymOffset = 0x{self.cbSymOffset:08X} +ioptMax = 0x{self.ioptMax:08X} +cbOptOffset = 0x{self.cbOptOffset:08X} +iauxMax = 0x{self.iauxMax:08X} +cbAuxOffset = 0x{self.cbAuxOffset:08X} +issMax = 0x{self.issMax:08X} +cbSsOffset = 0x{self.cbSsOffset:08X} +issExtMax = 0x{self.issExtMax:08X} +cbSsExtOffset = 0x{self.cbSsExtOffset:08X} +ifdMax = 0x{self.ifdMax:08X} +cbFdOffset = 0x{self.cbFdOffset:08X} +crfd = 0x{self.crfd:08X} +cbRfdOffset = 0x{self.cbRfdOffset:08X} +iextMax = 0x{self.iextMax:08X} +cbExtOffset = 0x{self.cbExtOffset:08X}""" diff --git a/lib/ultralib/tools/mips_isa.py b/lib/ultralib/tools/mips_isa.py new file mode 100644 index 00000000..d99dcdaa --- /dev/null +++ b/lib/ultralib/tools/mips_isa.py @@ -0,0 +1,1309 @@ +# TODO enum these constants +from enum import IntEnum, auto + +# Register IDs +class MipsGPReg(IntEnum): + R0 = 0 # 0 + AT = auto() # 1 + V0 = auto() # 2 + V1 = auto() # 3 + A0 = auto() # 4 + A1 = auto() # 5 + A2 = auto() # 6 + A3 = auto() # 7 + T0 = auto() # 8 + T1 = auto() # 9 + T2 = auto() # 10 + T3 = auto() # 11 + T4 = auto() # 12 + T5 = auto() # 13 + T6 = auto() # 14 + T7 = auto() # 15 + S0 = auto() # 16 + S1 = auto() # 17 + S2 = auto() # 18 + S3 = auto() # 19 + S4 = auto() # 20 + S5 = auto() # 21 + S6 = auto() # 22 + S7 = auto() # 23 + T8 = auto() # 24 + T9 = auto() # 25 + K0 = auto() # 26 + K1 = auto() # 27 + GP = auto() # 28 + SP = auto() # 29 + FP = auto() # 30 + RA = auto() # 31 + +class MipsFPReg(IntEnum): + F0 = 0 # 0 + F1 = auto() # 1 + F2 = auto() # 2 + F3 = auto() # 3 + F4 = auto() # 4 + F5 = auto() # 5 + F6 = auto() # 6 + F7 = auto() # 7 + F8 = auto() # 8 + F9 = auto() # 9 + F10 = auto() # 10 + F11 = auto() # 11 + F12 = auto() # 12 + F13 = auto() # 13 + F14 = auto() # 14 + F15 = auto() # 15 + F16 = auto() # 16 + F17 = auto() # 17 + F18 = auto() # 18 + F19 = auto() # 19 + F20 = auto() # 20 + F21 = auto() # 21 + F22 = auto() # 22 + F23 = auto() # 23 + F24 = auto() # 24 + F25 = auto() # 25 + F26 = auto() # 26 + F27 = auto() # 27 + F28 = auto() # 28 + F29 = auto() # 29 + F30 = auto() # 30 + F31 = auto() # 31 + +# Instruction Unique IDs +MIPS_INS_SLL = 0 +MIPS_INS_SRL = 1 +MIPS_INS_SRA = 2 +MIPS_INS_SLLV = 3 +MIPS_INS_SRLV = 4 +MIPS_INS_SRAV = 5 +MIPS_INS_JR = 6 +MIPS_INS_JALR = 7 +MIPS_INS_SYSCALL = 8 +MIPS_INS_BREAK = 9 +MIPS_INS_SYNC = 10 +MIPS_INS_MFHI = 11 +MIPS_INS_MTHI = 12 +MIPS_INS_MFLO = 13 +MIPS_INS_MTLO = 14 +MIPS_INS_DSLLV = 15 +MIPS_INS_DSRLV = 16 +MIPS_INS_DSRAV = 17 +MIPS_INS_MULT = 18 +MIPS_INS_MULTU = 19 +MIPS_INS_DIV = 20 +MIPS_INS_DIVU = 21 +MIPS_INS_DMULT = 22 +MIPS_INS_DMULTU = 23 +MIPS_INS_DDIV = 24 +MIPS_INS_DDIVU = 25 +MIPS_INS_ADD = 26 +MIPS_INS_ADDU = 27 +MIPS_INS_SUB = 28 +MIPS_INS_SUBU = 29 +MIPS_INS_AND = 30 +MIPS_INS_OR = 31 +MIPS_INS_XOR = 32 +MIPS_INS_NOR = 33 +MIPS_INS_SLT = 34 +MIPS_INS_SLTU = 35 +MIPS_INS_DADD = 36 +MIPS_INS_DADDU = 37 +MIPS_INS_DSUB = 38 +MIPS_INS_DSUBU = 39 +MIPS_INS_TGE = 40 +MIPS_INS_TGEU = 41 +MIPS_INS_TLT = 42 +MIPS_INS_TLTU = 43 +MIPS_INS_TEQ = 44 +MIPS_INS_TNE = 45 +MIPS_INS_DSLL = 46 +MIPS_INS_DSRL = 47 +MIPS_INS_DSRA = 48 +MIPS_INS_DSLL32 = 49 +MIPS_INS_DSRL32 = 50 +MIPS_INS_DSRA32 = 51 +MIPS_INS_BLTZ = 52 +MIPS_INS_BGEZ = 53 +MIPS_INS_BLTZL = 54 +MIPS_INS_BGEZL = 55 +MIPS_INS_TGEI = 56 +MIPS_INS_TGEIU = 57 +MIPS_INS_TLTI = 58 +MIPS_INS_TLTIU = 59 +MIPS_INS_TEQI = 60 +MIPS_INS_TNEI = 61 +MIPS_INS_BLTZAL = 62 +MIPS_INS_BGEZAL = 63 +MIPS_INS_BLTZALL = 64 +MIPS_INS_BGEZALL = 65 +MIPS_INS_J = 66 +MIPS_INS_JAL = 67 +MIPS_INS_BEQ = 68 +MIPS_INS_BNE = 69 +MIPS_INS_BLEZ = 70 +MIPS_INS_BGTZ = 71 +MIPS_INS_ADDI = 72 +MIPS_INS_ADDIU = 73 +MIPS_INS_SLTI = 74 +MIPS_INS_SLTIU = 75 +MIPS_INS_ANDI = 76 +MIPS_INS_ORI = 77 +MIPS_INS_XORI = 78 +MIPS_INS_LUI = 79 +MIPS_INS_MFC0 = 80 +MIPS_INS_MTC0 = 81 +MIPS_INS_TLBR = 82 +MIPS_INS_TLBWI = 83 +MIPS_INS_TLBWR = 84 +MIPS_INS_TLBP = 85 +MIPS_INS_ERET = 86 +MIPS_INS_MFC1 = 87 +MIPS_INS_DMFC1 = 88 +MIPS_INS_CFC1 = 89 +MIPS_INS_MTC1 = 90 +MIPS_INS_DMTC1 = 91 +MIPS_INS_CTC1 = 92 +MIPS_INS_BC1F = 93 +MIPS_INS_BC1T = 94 +MIPS_INS_BC1FL = 95 +MIPS_INS_BC1TL = 96 +MIPS_INS_ADD_S = 97 +MIPS_INS_SUB_S = 98 +MIPS_INS_MUL_S = 99 +MIPS_INS_DIV_S = 100 +MIPS_INS_SQRT_S = 101 +MIPS_INS_ABS_S = 102 +MIPS_INS_MOV_S = 103 +MIPS_INS_NEG_S = 104 +MIPS_INS_ROUND_L_S = 105 +MIPS_INS_TRUNC_L_S = 106 +MIPS_INS_CEIL_L_S = 107 +MIPS_INS_FLOOR_L_S = 108 +MIPS_INS_ROUND_W_S = 109 +MIPS_INS_TRUNC_W_S = 110 +MIPS_INS_CEIL_W_S = 111 +MIPS_INS_FLOOR_W_S = 112 +MIPS_INS_CVT_D_S = 113 +MIPS_INS_CVT_W_S = 114 +MIPS_INS_CVT_L_S = 115 +MIPS_INS_C_F_S = 116 +MIPS_INS_C_UN_S = 117 +MIPS_INS_C_EQ_S = 118 +MIPS_INS_C_UEQ_S = 119 +MIPS_INS_C_OLT_S = 120 +MIPS_INS_C_ULT_S = 121 +MIPS_INS_C_OLE_S = 122 +MIPS_INS_C_ULE_S = 123 +MIPS_INS_C_SF_S = 124 +MIPS_INS_C_NGLE_S = 125 +MIPS_INS_C_SEQ_S = 126 +MIPS_INS_C_NGL_S = 127 +MIPS_INS_C_LT_S = 128 +MIPS_INS_C_NGE_S = 129 +MIPS_INS_C_LE_S = 130 +MIPS_INS_C_NGT_S = 131 +MIPS_INS_ADD_D = 132 +MIPS_INS_SUB_D = 133 +MIPS_INS_MUL_D = 134 +MIPS_INS_DIV_D = 135 +MIPS_INS_SQRT_D = 136 +MIPS_INS_ABS_D = 137 +MIPS_INS_MOV_D = 138 +MIPS_INS_NEG_D = 139 +MIPS_INS_ROUND_L_D = 140 +MIPS_INS_TRUNC_L_D = 141 +MIPS_INS_CEIL_L_D = 142 +MIPS_INS_FLOOR_L_D = 143 +MIPS_INS_ROUND_W_D = 144 +MIPS_INS_TRUNC_W_D = 145 +MIPS_INS_CEIL_W_D = 146 +MIPS_INS_FLOOR_W_D = 147 +MIPS_INS_CVT_S_D = 148 +MIPS_INS_CVT_W_D = 149 +MIPS_INS_CVT_L_D = 150 +MIPS_INS_C_F_D = 151 +MIPS_INS_C_UN_D = 152 +MIPS_INS_C_EQ_D = 153 +MIPS_INS_C_UEQ_D = 154 +MIPS_INS_C_OLT_D = 155 +MIPS_INS_C_ULT_D = 156 +MIPS_INS_C_OLE_D = 157 +MIPS_INS_C_ULE_D = 158 +MIPS_INS_C_SF_D = 159 +MIPS_INS_C_NGLE_D = 160 +MIPS_INS_C_SEQ_D = 161 +MIPS_INS_C_NGL_D = 162 +MIPS_INS_C_LT_D = 163 +MIPS_INS_C_NGE_D = 164 +MIPS_INS_C_LE_D = 165 +MIPS_INS_C_NGT_D = 166 +MIPS_INS_CVT_S_W = 167 +MIPS_INS_CVT_D_W = 168 +MIPS_INS_CVT_S_L = 169 +MIPS_INS_CVT_D_L = 170 +MIPS_INS_BEQL = 171 +MIPS_INS_BNEL = 172 +MIPS_INS_BLEZL = 173 +MIPS_INS_BGTZL = 174 +MIPS_INS_DADDI = 175 +MIPS_INS_DADDIU = 176 +MIPS_INS_LDL = 177 +MIPS_INS_LDR = 178 +MIPS_INS_LB = 179 +MIPS_INS_LH = 180 +MIPS_INS_LWL = 181 +MIPS_INS_LW = 182 +MIPS_INS_LBU = 183 +MIPS_INS_LHU = 184 +MIPS_INS_LWR = 185 +MIPS_INS_LWU = 186 +MIPS_INS_SB = 187 +MIPS_INS_SH = 188 +MIPS_INS_SWL = 189 +MIPS_INS_SW = 190 +MIPS_INS_SDL = 191 +MIPS_INS_SDR = 192 +MIPS_INS_SWR = 193 +MIPS_INS_CACHE = 194 +MIPS_INS_LL = 195 +MIPS_INS_LWC1 = 196 +MIPS_INS_LWC2 = 197 +MIPS_INS_LLD = 198 +MIPS_INS_LDC1 = 199 +MIPS_INS_LDC2 = 200 +MIPS_INS_LD = 201 +MIPS_INS_SC = 202 +MIPS_INS_SWC1 = 203 +MIPS_INS_SWC2 = 204 +MIPS_INS_SCD = 205 +MIPS_INS_SDC1 = 206 +MIPS_INS_SDC2 = 207 +MIPS_INS_SD = 208 + +# RSP COP2 +MIPS_INS_VMULF = 209 +MIPS_INS_VMULU = 210 +MIPS_INS_VRNDP = 211 +MIPS_INS_VMULQ = 212 +MIPS_INS_VMUDL = 213 +MIPS_INS_VMUDM = 214 +MIPS_INS_VMUDN = 215 +MIPS_INS_VMUDH = 216 +MIPS_INS_VMACF = 217 +MIPS_INS_VMACU = 218 +MIPS_INS_VRNDN = 219 +MIPS_INS_VMACQ = 220 +MIPS_INS_VMADL = 221 +MIPS_INS_VMADM = 222 +MIPS_INS_VMADN = 223 +MIPS_INS_VMADH = 224 +MIPS_INS_VADD = 225 +MIPS_INS_VSUB = 226 +MIPS_INS_VABS = 227 +MIPS_INS_VADDC = 228 +MIPS_INS_VSUBC = 229 +MIPS_INS_VSAR = 230 +MIPS_INS_VLT = 231 +MIPS_INS_VEQ = 232 +MIPS_INS_VNE = 233 +MIPS_INS_VGE = 234 +MIPS_INS_VCL = 235 +MIPS_INS_VCH = 236 +MIPS_INS_VCR = 237 +MIPS_INS_VMRG = 238 +MIPS_INS_VAND = 239 +MIPS_INS_VNAND = 240 +MIPS_INS_VOR = 241 +MIPS_INS_VNOR = 242 +MIPS_INS_VXOR = 243 +MIPS_INS_VNXOR = 244 +MIPS_INS_VRCP = 245 +MIPS_INS_VRCPL = 246 +MIPS_INS_VRCPH = 247 +MIPS_INS_VMOV = 248 +MIPS_INS_VRSQ = 249 +MIPS_INS_VRSQL = 250 +MIPS_INS_VRSQH = 251 +MIPS_INS_VNOP = 252 +MIPS_INS_LBV = 253 +MIPS_INS_LSV = 254 +MIPS_INS_LLV = 255 +MIPS_INS_LDV = 256 +MIPS_INS_LQV = 257 +MIPS_INS_LRV = 258 +MIPS_INS_LPV = 259 +MIPS_INS_LUV = 260 +MIPS_INS_LHV = 261 +MIPS_INS_LFV = 262 +MIPS_INS_LTV = 263 +MIPS_INS_SBV = 264 +MIPS_INS_SSV = 265 +MIPS_INS_SLV = 266 +MIPS_INS_SDV = 267 +MIPS_INS_SQV = 268 +MIPS_INS_SRV = 269 +MIPS_INS_SPV = 270 +MIPS_INS_SUV = 271 +MIPS_INS_SHV = 272 +MIPS_INS_SFV = 273 +MIPS_INS_SWV = 274 +MIPS_INS_STV = 275 +MIPS_INS_MFC2 = 276 +MIPS_INS_MTC2 = 277 +MIPS_INS_CFC2 = 278 +MIPS_INS_CTC2 = 279 + +# Pseudo-Instruction Unique IDs +MIPS_INS_BEQZ = 280 +MIPS_INS_BNEZ = 281 +MIPS_INS_B = 282 +MIPS_INS_NOP = 283 +MIPS_INS_MOVE = 284 +MIPS_INS_NEGU = 285 +MIPS_INS_NOT = 286 + +# Invalid Instruction Unique ID +MIPS_INS_INVALID = -1 + +# Op IDs +# MIPS_OP_RS = 0 +# MIPS_OP_RT = 0 +# MIPS_OP_RD = 0 +# MIPS_OP_IMM = 0 + +# Instruction Groups + +MIPS_BRANCH_LIKELY_INSNS = [ + MIPS_INS_BEQL, MIPS_INS_BGEZALL, + MIPS_INS_BGEZL, MIPS_INS_BGTZL, + MIPS_INS_BLEZL, MIPS_INS_BLTZALL, + MIPS_INS_BLTZL, MIPS_INS_BNEL, + MIPS_INS_BC1TL, MIPS_INS_BC1FL, +] + +MIPS_BRANCH_INSNS = [ + *MIPS_BRANCH_LIKELY_INSNS, + + MIPS_INS_BEQ, + MIPS_INS_BGEZ, MIPS_INS_BGEZAL, + MIPS_INS_BGTZ, + MIPS_INS_BNE, + MIPS_INS_BLTZ, MIPS_INS_BLTZAL, + MIPS_INS_BLEZ, + MIPS_INS_BC1T, MIPS_INS_BC1F, + + MIPS_INS_BEQZ, + MIPS_INS_BNEZ, + MIPS_INS_B, +] + +MIPS_JUMP_INSNS = [ + MIPS_INS_JAL, MIPS_INS_JALR, MIPS_INS_J, MIPS_INS_JR +] + +MIPS_DELAY_SLOT_INSNS = [ + *MIPS_BRANCH_INSNS, *MIPS_JUMP_INSNS +] + +MIPS_FP_LOAD_INSNS = [ + MIPS_INS_LWC1, MIPS_INS_LDC1 +] + +MIPS_LOAD_INSNS = [ + MIPS_INS_LB, MIPS_INS_LBU, + MIPS_INS_LH, MIPS_INS_LHU, + MIPS_INS_LW, MIPS_INS_LWL, MIPS_INS_LWR, MIPS_INS_LWU, + MIPS_INS_LD, MIPS_INS_LDL, MIPS_INS_LDR, + MIPS_INS_LL, MIPS_INS_LLD, + *MIPS_FP_LOAD_INSNS +] + +MIPS_FP_STORE_INSNS = [ + MIPS_INS_SWC1, MIPS_INS_SDC1 +] + +MIPS_STORE_INSNS = [ + MIPS_INS_SB, + MIPS_INS_SH, + MIPS_INS_SW, MIPS_INS_SWL, MIPS_INS_SWR, + MIPS_INS_SD, MIPS_INS_SDL, MIPS_INS_SDR, + MIPS_INS_SC, MIPS_INS_SCD, + *MIPS_FP_STORE_INSNS +] + +MIPS_LOAD_STORE_INSNS = [ + *MIPS_LOAD_INSNS, + *MIPS_STORE_INSNS, +] + +MIPS_FP_LOAD_STORE_INSNS = [ + *MIPS_FP_LOAD_INSNS, *MIPS_FP_STORE_INSNS +] + +RSP_VECTOR_LOAD_STORES = [ + MIPS_INS_LBV, MIPS_INS_LSV, MIPS_INS_LLV, MIPS_INS_LDV, + MIPS_INS_LQV, MIPS_INS_LRV, MIPS_INS_LPV, MIPS_INS_LUV, + MIPS_INS_LHV, MIPS_INS_LFV, MIPS_INS_LTV, + + MIPS_INS_SBV, MIPS_INS_SSV, MIPS_INS_SLV, MIPS_INS_SDV, + MIPS_INS_SQV, MIPS_INS_SRV, MIPS_INS_SPV, MIPS_INS_SUV, + MIPS_INS_SHV, MIPS_INS_SFV, MIPS_INS_SWV, MIPS_INS_STV, +] + +# Labels + +# These labels can be referenced from pointers/loads/stores/etc. +LABEL_TYPE_FUNC = 0 +LABEL_TYPE_JTBL = 1 +LABEL_TYPE_DATA = 2 +LABEL_TYPE_BRANCH = 3 + +# Unknown +LABEL_TYPE_UNK = 20 + +class MipsLabel: + """ + Label + """ + + def __init__(self, vaddr, name=None, lbl_type=LABEL_TYPE_UNK, is_global=None) -> None: + self.name = name + self.vaddr = vaddr + self.lbl_type = lbl_type + self.is_global = is_global or (False if (lbl_type == LABEL_TYPE_BRANCH) else True) + + def __str__(self): + if self.name is not None: + return self.name + + if self.lbl_type == LABEL_TYPE_FUNC: + return f"func_{self.vaddr:08X}" + elif self.lbl_type == LABEL_TYPE_JTBL: + return f"jtbl_{self.vaddr:08X}" + elif self.lbl_type == LABEL_TYPE_BRANCH: + return f".L{self.vaddr:08X}" + elif (self.lbl_type == LABEL_TYPE_DATA or self.lbl_type == LABEL_TYPE_UNK): + return f"D_{self.vaddr:08X}" + assert False , f"Unimplemented default name for label type {self.lbl_type}" + +# Register Names + +mips_gpr_names = ( + "$zero", + "$at", + "$v0", "$v1", + "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", + "$k0", "$k1", + "$gp", + "$sp", + "$fp", + "$ra", +) + +rsp_gpr_names = ( + "$zero", + "$1", "$2", "$3", "$4", "$5", "$6", + "$7", "$8", "$9", "$10", "$11", "$12", + "$13", "$14", "$15", "$16", "$17", "$18", + "$19", "$20", "$21", "$22", "$23", "$24", + "$25", "$26", "$27", "$28", "$29", "$30", + "$ra", +) + +mips_cop0_names = ( + "Index" , "Random" , "EntryLo0" , "EntryLo1" , + "Context" , "PageMask" , "Wired" , "Reserved07", + "BadVaddr" , "Count" , "EntryHi" , "Compare" , + "Status" , "Cause" , "EPC" , "PRevID" , + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , + "XContext" , "Reserved21", "Reserved22", "Reserved23", + "Reserved24", "Reserved25", "PErr" , "CacheErr" , + "TagLo" , "TagHi" , "ErrorEPC" , "Reserved31", +) + +rsp_cop0_names = ( + "SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN" , "SP_WR_LEN" , + "SP_STATUS" , "SP_DMA_FULL" , "SP_DMA_BUSY" , "SP_SEMAPHORE", + "DPC_START" , "DPC_END" , "DPC_CURRENT" , "DPC_STATUS" , + "DPC_CLOCK" , "DPC_BUFBUSY" , "DPC_PIPEBUSY", "DPC_TMEM" , +) + +mips_cop1_names = ( + "$f0", "$f1", "$f2", "$f3", + "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", + "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", + "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", + # Status register + "FpCsr", +) + +rsp_cop2_names = ( + "$v0", "$v1", "$v2", "$v3", "$v4", "$v5", "$v6", "$v7", + "$v8", "$v9", "$v10", "$v11", "$v12", "$v13", "$v14", "$v15", + "$v16", "$v17", "$v18", "$v19", "$v20", "$v21", "$v22", "$v23", + "$v24", "$v25", "$v26", "$v27", "$v28", "$v29", "$v30", "$v31", +) + +rsp_cop2_ctrl_names = ( + '$vco', '$vcc', '$vce' +) + +# Instruction sets + +class MipsAbi: + def __init__(self, name, gpr_names, cop0_names, cop1_names, cop2_names): + self.name = name + self.gpr_names, self.cop0_names, self.cop1_names, self.cop2_names = \ + gpr_names, cop0_names, cop1_names, cop2_names + +ABI_VR4300 = MipsAbi("VR4300", mips_gpr_names, mips_cop0_names, mips_cop1_names, None ) +ABI_RSP = MipsAbi("RSP", rsp_gpr_names, rsp_cop0_names, None, rsp_cop2_names) + +# Instruction field fetching + +def sign_extend_6(value): + if value & (1 << (6 - 1)): + return value - (1 << 6) + return value + +def sign_extend_16(value): + return (value & 0x7FFF) - (value & 0x8000) + +def mask_shift(v, s, w): + return (v >> s) & ((1 << w) - 1) + +mips_get_field = lambda raw,vaddr : mask_shift(raw, 26, 6) +mips_get_special = lambda raw,vaddr : mask_shift(raw, 0, 6) +mips_get_cop0 = lambda raw,vaddr : mask_shift(raw, 21, 5) +mips_get_cop1 = lambda raw,vaddr : mask_shift(raw, 21, 5) +mips_get_cop2 = lambda raw,vaddr : mask_shift(raw, 21, 4) +mips_get_regimm = lambda raw,vaddr : mask_shift(raw, 16, 5) +mips_get_tlb = lambda raw,vaddr : mask_shift(raw, 0, 5) +mips_get_function = lambda raw,vaddr : mask_shift(raw, 0, 6) + +mips_get_cond = lambda raw,vaddr : mask_shift(raw, 0, 4) +mips_get_fd = lambda raw,vaddr : MipsFPReg(mask_shift(raw, 6, 5)) +mips_get_fs = lambda raw,vaddr : MipsFPReg(mask_shift(raw, 11, 5)) +mips_get_ft = lambda raw,vaddr : MipsFPReg(mask_shift(raw, 16, 5)) +mips_get_fmt = lambda raw,vaddr : mask_shift(raw, 21, 5) +mips_get_ndtf = lambda raw,vaddr : mask_shift(raw, 16, 2) + +mips_get_target = lambda raw,vaddr : ((vaddr & 0xFC000000) | (mask_shift(raw, 0, 26) << 2)) +mips_get_offset = lambda raw,vaddr : vaddr + 4 + sign_extend_16(mask_shift(raw, 0, 16)) * 4 +mips_get_imm = lambda raw,vaddr : mask_shift(raw, 0, 16) + +mips_get_base = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 21, 5)) + +mips_get_cd = lambda raw,vaddr : mask_shift(raw, 11, 5) + +mips_get_code = lambda raw,vaddr : (mask_shift(raw, 6, 20) << 6) >> 16 +mips_get_op = lambda raw,vaddr : mask_shift(raw, 16, 5) + +mips_get_sa = lambda raw,vaddr : mask_shift(raw, 6, 5) + +mips_get_rd = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 11, 5)) +mips_get_rs = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 21, 5)) +mips_get_rt = lambda raw,vaddr : MipsGPReg(mask_shift(raw, 16, 5)) + +rsp_load_store_multiplier = { + 0b00000 : 0x01, # lbv, sbv + 0b00001 : 0x02, # lsv, ssv + 0b00010 : 0x04, # llv, slv + 0b00011 : 0x08, # ldv, sdv + 0b00100 : 0x10, # lqv, sqv + 0b00101 : 0x10, # lrv, srv + 0b00110 : 0x08, # lpv, spv + 0b00111 : 0x08, # luv, suv + + 0b01000 : 0x02, # lhv, shv + 0b01001 : 0x04, # lfv, sfv + 0b01010 : 0x10, # swv + 0b01011 : 0x10, # ltv, stv +} + +mips_get_vc = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_vd = lambda raw,vaddr : mask_shift(raw, 6, 5) +mips_get_vs = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_vt = lambda raw,vaddr : mask_shift(raw, 16, 5) +mips_get_elem = lambda raw,vaddr : mask_shift(raw, 21, 4) +mips_get_elemd = lambda raw,vaddr : mask_shift(raw, 7, 4) +mips_get_cop2_func = lambda raw,vaddr : mask_shift(raw, 25, 1) +mips_get_lwc2 = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_swc2 = lambda raw,vaddr : mask_shift(raw, 11, 5) +mips_get_voffset = lambda raw,vaddr : sign_extend_6(mask_shift(raw, 0, 6)) * rsp_load_store_multiplier[mips_get_lwc2(raw,vaddr)] + +# Formatting + +def resolve_pseudo_insn(insn): + # move varies between assemblers + # IDO + move_insn = MIPS_INS_OR + # GCC + # move_insn = MIPS_INS_ADDU + + if insn.id == MIPS_INS_SLL and insn.rd == MipsGPReg.R0 and insn.rt == MipsGPReg.R0 and insn.sa == 0: + return MIPS_INS_NOP, "nop", (), () + elif insn.id == MIPS_INS_BEQ and insn.rs == MipsGPReg.R0 and insn.rt == MipsGPReg.R0: + return MIPS_INS_B, "b", ("offset",), (False,) + elif insn.id == move_insn and insn.rt == MipsGPReg.R0: + return MIPS_INS_MOVE, "move", ("rd","rs"), (True,False) + elif insn.id == MIPS_INS_BEQ and insn.rt == MipsGPReg.R0: + return MIPS_INS_BEQZ, "beqz", ("rs","offset"), (False,False) + elif insn.id == MIPS_INS_BNE and insn.rt == MipsGPReg.R0: + return MIPS_INS_BNEZ, "bnez", ("rs","offset"), (False,False) + elif insn.id == MIPS_INS_SUBU and insn.rs == MipsGPReg.R0: + return MIPS_INS_NEGU, "negu", ("rd","rt"), (True,False) + elif insn.id == MIPS_INS_NOR and insn.rt == MipsGPReg.R0: + return MIPS_INS_NOT, "not", ("rd","rs"), (True,False) + else: + return insn.id, insn.mnemonic, insn.fields, insn.writes + +def format_hex(v, signed, zeros, no_zero): + if abs(v) < 10: + if v == 0 and no_zero: + return "" + return f"{v}" + elif not signed: + return f"0x{v:{f'0{zeros}' if zeros > 0 else ''}x}" + else: + return f"{v:#x}" + +def format_vector_elem(insn, elem): + if insn.id in RSP_VECTOR_LOAD_STORES: + return f"[{elem}]" + elif (elem & 8) == 8: + return f"[{elem & 7}]" + elif (elem & 0xC) == 4: + return f"[{elem & 3}h]" + elif (elem & 0xE) == 2: + return f"[{elem & 1}q]" + else: + return "" + +mips_field_formatters = { + 'code' : (lambda insn : f'{insn.code}' if insn.code != 0 else ''), + 'cd' : (lambda insn : insn.abi.cop0_names[insn.cd]), + 'rd' : (lambda insn : insn.abi.gpr_names[insn.rd]), + 'rs' : (lambda insn : insn.abi.gpr_names[insn.rs]), + 'rt' : (lambda insn : insn.abi.gpr_names[insn.rt]), + 'fd' : (lambda insn : insn.abi.cop1_names[insn.fd]), + 'fs' : (lambda insn : insn.abi.cop1_names[insn.fs]), + 'ft' : (lambda insn : insn.abi.cop1_names[insn.ft]), + 'sa' : (lambda insn : format_hex(insn.sa, True, 0, False)), + 'op' : (lambda insn : format_hex(insn.op, False, 0, False)), + 'imm' : (lambda insn : format_hex(insn.imm, True, 0, False)), + 'offset(base)' : (lambda insn : f'{format_hex(insn.imm, True, 0, True)}({insn.abi.gpr_names[insn.base]})'), + 'offset' : (lambda insn : f'{format_hex(insn.offset, True, 0, False)}'), + 'target' : (lambda insn : f'{format_hex(insn.target, False, 0, False)}'), + 'vd' : (lambda insn : insn.abi.cop2_names[insn.vd]), + 'vs' : (lambda insn : insn.abi.cop2_names[insn.vs]), + 'vt' : (lambda insn : insn.abi.cop2_names[insn.vt]), + 'vt[e]' : (lambda insn : f"{insn.abi.cop2_names[insn.vt]}{format_vector_elem(insn, insn.elem)}"), + 'vt[ed]' : (lambda insn : f"{insn.abi.cop2_names[insn.vt]}{format_vector_elem(insn, insn.elemd)}"), + 'vd[e]' : (lambda insn : f"{insn.abi.cop2_names[insn.vd]}{format_vector_elem(insn, insn.elem)}"), + 'vd[ed]' : (lambda insn : f"{insn.abi.cop2_names[insn.vd]}{format_vector_elem(insn, insn.elemd)}"), + 'voffset' : (lambda insn : f'{format_hex(insn.voffset, True, 0, False)}'), + 'voffset(base)' : (lambda insn : f'{format_hex(insn.voffset, True, 0, True)}({insn.abi.gpr_names[insn.base]})'), + 'vc' : (lambda insn : rsp_cop2_ctrl_names[insn.vc]) +} + +class MipsInsn: + + def __init__(self, abi, raw, vaddr, values): + self.abi = abi + self.raw = raw + self.vaddr = vaddr + + if values is None: + values = MIPS_INS_INVALID, f"/* Invalid Instruction */ .4byte 0x{raw:08X}", (), () + + self.id, self.mnemonic, self.fields, self.writes = values + + # self.code = self.sa = self.op = self.cd = self.rd = self.rs = self.rt = self.fd = self.fs = self.ft = self.imm = self.offset = self.base = self.target = None + + for field in self.fields: + self.set_value(field) + + self.id, self.mnemonic, self.fields, self.writes = resolve_pseudo_insn(self) + + self.op_str = self.format_insn() + + def read_fields(self): + return [field for i,field in enumerate(self.fields) if self.writes[i] == False] + + def write_fields(self): + return [field for i,field in enumerate(self.fields) if self.writes[i] == True] + + def has_field(self, field): + return field in self.fields + + def format_field(self, field): + return mips_field_formatters[field](self) + + def format_insn(self): + return ", ".join([self.format_field(field) for field in self.fields]) + + def __str__(self): + return f"{self.mnemonic:12}{self.op_str}" + + # Field setters + + def set_code(self): + self.code = mips_get_code(self.raw, self.vaddr) + + def set_sa(self): + self.sa = mips_get_sa(self.raw, self.vaddr) + + def set_op(self): + self.op = mips_get_op(self.raw, self.vaddr) + + def set_cd(self): + self.cd = mips_get_cd(self.raw, self.vaddr) + + def set_rd(self): + self.rd = mips_get_rd(self.raw, self.vaddr) + + def set_rs(self): + self.rs = mips_get_rs(self.raw, self.vaddr) + + def set_rt(self): + self.rt = mips_get_rt(self.raw, self.vaddr) + + def set_fd(self): + self.fd = mips_get_fd(self.raw, self.vaddr) + + def set_fs(self): + self.fs = mips_get_fs(self.raw, self.vaddr) + + def set_ft(self): + self.ft = mips_get_ft(self.raw, self.vaddr) + + do_sign_extend = [ + MIPS_INS_ADDIU, MIPS_INS_SLTI, MIPS_INS_ADDI, MIPS_INS_DADDIU, + MIPS_INS_LB, MIPS_INS_LBU, + MIPS_INS_LH, MIPS_INS_LHU, + MIPS_INS_LW, MIPS_INS_LWL, MIPS_INS_LWR, MIPS_INS_LWU, + MIPS_INS_LWC1, + MIPS_INS_LD, MIPS_INS_LDL, MIPS_INS_LDR, + MIPS_INS_LDC1, + MIPS_INS_LL, MIPS_INS_LLD, + MIPS_INS_SB, + MIPS_INS_SH, + MIPS_INS_SW, MIPS_INS_SWL, MIPS_INS_SWR, + MIPS_INS_SWC1, + MIPS_INS_SD, MIPS_INS_SDL, MIPS_INS_SDR, + MIPS_INS_SDC1, + MIPS_INS_SC, MIPS_INS_SCD, + ] + + def set_imm(self): + self.imm = mips_get_imm(self.raw, self.vaddr) + if self.id in MipsInsn.do_sign_extend: # sign extended immediates + self.imm = sign_extend_16(self.imm) + + def set_offset(self): + self.offset = mips_get_offset(self.raw, self.vaddr) + + def set_base(self): + self.base = mips_get_base(self.raw, self.vaddr) + + def set_offset_base(self): + self.set_imm() + self.set_base() + + def set_target(self): + self.target = mips_get_target(self.raw, self.vaddr) + + def set_vd(self): + self.vd = mips_get_vd(self.raw, self.vaddr) + + def set_vs(self): + self.vs = mips_get_vs(self.raw, self.vaddr) + + def set_vt(self): + self.vt = mips_get_vt(self.raw, self.vaddr) + + def set_e(self): + self.elem = mips_get_elem(self.raw, self.vaddr) + + def set_ed(self): + self.elemd = mips_get_elemd(self.raw, self.vaddr) + + def set_vd_e(self): + self.set_vd() + self.set_e() + + def set_vt_ed(self): + self.set_vt() + self.set_ed() + + def set_vt_e(self): + self.set_vt() + self.set_e() + + def set_vd_ed(self): + self.set_vd() + self.set_ed() + + def set_voffset(self): + self.voffset = mips_get_voffset(self.raw, self.vaddr) + + def set_voffset_base(self): + self.set_voffset() + self.set_base() + + def set_vc(self): + self.vc = mips_get_vc(self.raw, self.vaddr) + + field_setters = { + 'code' : set_code, + 'sa' : set_sa, + 'op' : set_op, + 'cd' : set_cd, + 'rd' : set_rd, + 'rs' : set_rs, + 'rt' : set_rt, + 'fd' : set_fd, + 'fs' : set_fs, + 'ft' : set_ft, + 'imm' : set_imm, + 'offset' : set_offset, + 'base' : set_base, + 'offset(base)' : set_offset_base, + 'target' : set_target, + 'vd' : set_vd, + 'vs' : set_vs, + 'vt' : set_vt, + 'vt[e]' : set_vt_e, + 'vt[ed]' : set_vt_ed, + 'vd[e]' : set_vd_e, + 'vd[ed]' : set_vd_ed, + 'voffset' : set_voffset, + 'voffset(base)' : set_voffset_base, + 'vc' : set_vc + } + + def set_value(self, name): + MipsInsn.field_setters[name](self) + + # Field getters + + field_getters = { + 'code' : (lambda insn: insn.code), + 'sa' : (lambda insn: insn.sa), + 'op' : (lambda insn: insn.op), + 'cd' : (lambda insn: insn.cd), + 'rd' : (lambda insn: insn.rd), + 'rs' : (lambda insn: insn.rs), + 'rt' : (lambda insn: insn.rt), + 'fd' : (lambda insn: insn.fd), + 'fs' : (lambda insn: insn.fs), + 'ft' : (lambda insn: insn.ft), + 'imm' : (lambda insn: insn.imm), + 'offset' : (lambda insn: insn.offset), + 'base' : (lambda insn: insn.base), + 'offset(base)' : (lambda insn: (insn.offset, insn.base)), + 'target' : (lambda insn: insn.target), + 'vd' : (lambda insn: insn.vd), + 'vs' : (lambda insn: insn.vs), + 'vt' : (lambda insn: insn.vt), + 'vt[e]' : (lambda insn: (insn.vt, insn.elem)), + 'vt[ed]' : (lambda insn: (insn.vt, insn.elemd)), + 'vd[e]' : (lambda insn: (insn.vd, insn.elem)), + 'vd[ed]' : (lambda insn: (insn.vd, insn.elemd)), + 'voffset' : (lambda insn: insn.voffset), + 'voffset(base)' : (lambda insn: (insn.voffset, insn.base)), + 'vc' : (lambda insn: insn.vc), + } + + def value_forname(self, name): + return MipsInsn.field_getters[name](self) + +def fetch_insn(raw, vaddr, insn_set, func): + insn = insn_set.get(func(raw, vaddr), None) # default none for invalid instruction encoding + + if insn is not None and type(insn[1]) == dict: # extra decoding required + insn = fetch_insn(raw, vaddr, insn[1], insn[0]) + return insn + +def decode_insn(raw, vaddr): + return MipsInsn(ABI_VR4300, raw, vaddr, fetch_insn(raw, vaddr, mips_insns, mips_get_field)) + +def decode_rsp_insn(raw, vaddr): + return MipsInsn(ABI_RSP, raw, vaddr, fetch_insn(raw, vaddr, rsp_insns, mips_get_field)) + +mips_insns = { + 0b000000: (mips_get_special, { + # opcode id mnemonic fields field is written to + 0b000000: (MIPS_INS_SLL, "sll", ("rd","rt","sa"), (True , False, False)), + 0b000010: (MIPS_INS_SRL, "srl", ("rd","rt","sa"), (True , False, False)), + 0b000011: (MIPS_INS_SRA, "sra", ("rd","rt","sa"), (True , False, False)), + 0b000100: (MIPS_INS_SLLV, "sllv", ("rd","rt","rs"), (True , False, False)), + 0b000110: (MIPS_INS_SRLV, "srlv", ("rd","rt","rs"), (True , False, False)), + 0b000111: (MIPS_INS_SRAV, "srav", ("rd","rt","rs"), (True , False, False)), + 0b001000: (MIPS_INS_JR, "jr", ("rs", ), (False, )), + 0b001001: (MIPS_INS_JALR, "jalr", ("rs", ), (False, )), # technically also rd but it's always $ra + 0b001100: (MIPS_INS_SYSCALL, "syscall", ( ), ( )), + 0b001101: (MIPS_INS_BREAK, "break", ("code", ), (False, )), + 0b001111: (MIPS_INS_SYNC, "sync", ( ), ( )), + 0b010000: (MIPS_INS_MFHI, "mfhi", ("rd", ), (True , )), + 0b010001: (MIPS_INS_MTHI, "mthi", ("rs", ), (False, )), + 0b010010: (MIPS_INS_MFLO, "mflo", ("rd", ), (True , )), + 0b010011: (MIPS_INS_MTLO, "mtlo", ("rs", ), (False, )), + 0b010100: (MIPS_INS_DSLLV, "dsllv", ("rd","rt","rs"), (True , False, False)), + 0b010110: (MIPS_INS_DSRLV, "dsrlv", ("rd","rt","rs"), (True , False, False)), + 0b010111: (MIPS_INS_DSRAV, "dsrav", ("rd","rt","rs"), (True , False, False)), + 0b011000: (MIPS_INS_MULT, "mult", ("rs","rt" ), (False, False )), + 0b011001: (MIPS_INS_MULTU, "multu", ("rs","rt" ), (False, False )), + 0b011010: (MIPS_INS_DIV, "div", ("rd","rs","rt"), (False, False, False)), # for some reason gas hates div instructions + 0b011011: (MIPS_INS_DIVU, "divu", ("rd","rs","rt"), (False, False, False)), # with the correct number of operands + 0b011100: (MIPS_INS_DMULT, "dmult", ("rs","rt" ), (False, False )), + 0b011101: (MIPS_INS_DMULTU, "dmultu", ("rs","rt" ), (False, False )), + 0b011110: (MIPS_INS_DDIV, "ddiv", ("rd","rs","rt"), (False, False, False)), + 0b011111: (MIPS_INS_DDIVU, "ddivu", ("rd","rs","rt"), (False, False, False)), + 0b100000: (MIPS_INS_ADD, "add", ("rd","rs","rt"), (True , False, False)), + 0b100001: (MIPS_INS_ADDU, "addu", ("rd","rs","rt"), (True , False, False)), + 0b100010: (MIPS_INS_SUB, "sub", ("rd","rs","rt"), (True , False, False)), + 0b100011: (MIPS_INS_SUBU, "subu", ("rd","rs","rt"), (True , False, False)), + 0b100100: (MIPS_INS_AND, "and", ("rd","rs","rt"), (True , False, False)), + 0b100101: (MIPS_INS_OR, "or", ("rd","rs","rt"), (True , False, False)), + 0b100110: (MIPS_INS_XOR, "xor", ("rd","rs","rt"), (True , False, False)), + 0b100111: (MIPS_INS_NOR, "nor", ("rd","rs","rt"), (True , False, False)), + 0b101010: (MIPS_INS_SLT, "slt", ("rd","rs","rt"), (True , False, False)), + 0b101011: (MIPS_INS_SLTU, "sltu", ("rd","rs","rt"), (True , False, False)), + 0b101100: (MIPS_INS_DADD, "dadd", ("rd","rs","rt"), (True , False, False)), + 0b101101: (MIPS_INS_DADDU, "daddu", ("rd","rs","rt"), (True , False, False)), + 0b101110: (MIPS_INS_DSUB, "dsub", ("rd","rs","rt"), (True , False, False)), + 0b101111: (MIPS_INS_DSUBU, "dsubu", ("rd","rs","rt"), (True , False, False)), + 0b110000: (MIPS_INS_TGE, "tge", ("rs","rt" ), (False, False )), + 0b110001: (MIPS_INS_TGEU, "tgeu", ("rs","rt" ), (False, False )), + 0b110010: (MIPS_INS_TLT, "tlt", ("rs","rt" ), (False, False )), + 0b110011: (MIPS_INS_TLTU, "tltu", ("rs","rt" ), (False, False )), + 0b110100: (MIPS_INS_TEQ, "teq", ("rs","rt" ), (False, False )), + 0b110110: (MIPS_INS_TNE, "tne", ("rs","rt" ), (False, False )), + 0b111000: (MIPS_INS_DSLL, "dsll", ("rd","rt","sa"), (True , False, False)), + 0b111010: (MIPS_INS_DSRL, "dsrl", ("rd","rt","sa"), (True , False, False)), + 0b111011: (MIPS_INS_DSRA, "dsra", ("rd","rt","sa"), (True , False, False)), + 0b111100: (MIPS_INS_DSLL32, "dsll32", ("rd","rt","sa"), (True , False, False)), + 0b111110: (MIPS_INS_DSRL32, "dsrl32", ("rd","rt","sa"), (True , False, False)), + 0b111111: (MIPS_INS_DSRA32, "dsra32", ("rd","rt","sa"), (True , False, False)), + }), + 0b000001: (mips_get_regimm, { + 0b00000: (MIPS_INS_BLTZ, "bltz", ("rs","offset"), (False, False)), + 0b00001: (MIPS_INS_BGEZ, "bgez", ("rs","offset"), (False, False)), + 0b00010: (MIPS_INS_BLTZL, "bltzl", ("rs","offset"), (False, False)), + 0b00011: (MIPS_INS_BGEZL, "bgezl", ("rs","offset"), (False, False)), + 0b01000: (MIPS_INS_TGEI, "tgei", ("rs","imm" ), (False, False)), + 0b01001: (MIPS_INS_TGEIU, "tgeiu", ("rs","imm" ), (False, False)), + 0b01010: (MIPS_INS_TLTI, "tlti", ("rs","imm" ), (False, False)), + 0b01011: (MIPS_INS_TLTIU, "tltiu", ("rs","imm" ), (False, False)), + 0b01100: (MIPS_INS_TEQI, "teqi", ("rs","imm" ), (False, False)), + 0b01110: (MIPS_INS_TNEI, "tnei", ("rs","imm" ), (False, False)), + 0b10000: (MIPS_INS_BLTZAL, "bltzal", ("rs","offset"), (False, False)), + 0b10001: (MIPS_INS_BGEZAL, "bgezal", ("rs","offset"), (False, False)), + 0b10010: (MIPS_INS_BLTZALL, "bltzall", ("rs","offset"), (False, False)), + 0b10011: (MIPS_INS_BGEZALL, "bgezall", ("rs","offset"), (False, False)), + }), + 0b000010: (MIPS_INS_J, "j", ("target", ), (False, )), + 0b000011: (MIPS_INS_JAL, "jal", ("target", ), (False, )), + 0b000100: (MIPS_INS_BEQ, "beq", ("rs","rt","offset"), (False, False, False)), + 0b000101: (MIPS_INS_BNE, "bne", ("rs","rt","offset"), (False, False, False)), + 0b000110: (MIPS_INS_BLEZ, "blez", ("rs","offset" ), (False, False, )), + 0b000111: (MIPS_INS_BGTZ, "bgtz", ("rs","offset" ), (False, False, )), + 0b001000: (MIPS_INS_ADDI, "addi", ("rt","rs","imm" ), (True , False, False)), + 0b001001: (MIPS_INS_ADDIU, "addiu", ("rt","rs","imm" ), (True , False, False)), + 0b001010: (MIPS_INS_SLTI, "slti", ("rt","rs","imm" ), (True , False, False)), + 0b001011: (MIPS_INS_SLTIU, "sltiu", ("rt","rs","imm" ), (True , False, False)), + 0b001100: (MIPS_INS_ANDI, "andi", ("rt","rs","imm" ), (True , False, False)), + 0b001101: (MIPS_INS_ORI, "ori", ("rt","rs","imm" ), (True , False, False)), + 0b001110: (MIPS_INS_XORI, "xori", ("rt","rs","imm" ), (True , False, False)), + 0b001111: (MIPS_INS_LUI, "lui", ("rt","imm" ), (True , False )), + 0b010000: (mips_get_cop0, { + 0b00000: (MIPS_INS_MFC0, "mfc0", ("rt","cd"), (True , False)), + 0b00100: (MIPS_INS_MTC0, "mtc0", ("rt","cd"), (False, True )), + 0b10000: (mips_get_tlb, { + 0b000001: (MIPS_INS_TLBR, "tlbr", (), ()), + 0b000010: (MIPS_INS_TLBWI, "tlbwi", (), ()), + 0b000110: (MIPS_INS_TLBWR, "tlbwr", (), ()), + 0b001000: (MIPS_INS_TLBP, "tlbp", (), ()), + 0b011000: (MIPS_INS_ERET, "eret", (), ()), + }), + }), + 0b010001: (mips_get_cop1, { + 0b00000: (MIPS_INS_MFC1, "mfc1", ("rt","fs"), (True , False)), + 0b00001: (MIPS_INS_DMFC1, "dmfc1", ("rt","fs"), (True , False)), + 0b00010: (MIPS_INS_CFC1, "cfc1", ("rt","fs"), (True , False)), + 0b00100: (MIPS_INS_MTC1, "mtc1", ("rt","fs"), (False, True )), + 0b00101: (MIPS_INS_DMTC1, "dmtc1", ("rt","fs"), (False, True )), + 0b00110: (MIPS_INS_CTC1, "ctc1", ("rt","fs"), (False, True )), + 0b01000: (mips_get_ndtf, { + 0b00: (MIPS_INS_BC1F, "bc1f", ("offset",), (False,)), + 0b01: (MIPS_INS_BC1T, "bc1t", ("offset",), (False,)), + 0b10: (MIPS_INS_BC1FL, "bc1fl", ("offset",), (False,)), + 0b11: (MIPS_INS_BC1TL, "bc1tl", ("offset",), (False,)), + }), + 0b010000: (mips_get_function, { + 0b000000: (MIPS_INS_ADD_S, "add.s", ("fd","fs","ft"), (True , False, False)), + 0b000001: (MIPS_INS_SUB_S, "sub.s", ("fd","fs","ft"), (True , False, False)), + 0b000010: (MIPS_INS_MUL_S, "mul.s", ("fd","fs","ft"), (True , False, False)), + 0b000011: (MIPS_INS_DIV_S, "div.s", ("fd","fs","ft"), (True , False, False)), + 0b000100: (MIPS_INS_SQRT_S, "sqrt.s", ("fd","fs" ), (True , False )), + 0b000101: (MIPS_INS_ABS_S, "abs.s", ("fd","fs" ), (True , False )), + 0b000110: (MIPS_INS_MOV_S, "mov.s", ("fd","fs" ), (True , False )), + 0b000111: (MIPS_INS_NEG_S, "neg.s", ("fd","fs" ), (True , False )), + 0b001000: (MIPS_INS_ROUND_L_S, "round.l.s", ("fd","fs" ), (True , False )), + 0b001001: (MIPS_INS_TRUNC_L_S, "trunc.l.s", ("fd","fs" ), (True , False )), + 0b001010: (MIPS_INS_CEIL_L_S, "ceil.l.s", ("fd","fs" ), (True , False )), + 0b001011: (MIPS_INS_FLOOR_L_S, "floor.l.s", ("fd","fs" ), (True , False )), + 0b001100: (MIPS_INS_ROUND_W_S, "round.w.s", ("fd","fs" ), (True , False )), + 0b001101: (MIPS_INS_TRUNC_W_S, "trunc.w.s", ("fd","fs" ), (True , False )), + 0b001110: (MIPS_INS_CEIL_W_S, "ceil.w.s", ("fd","fs" ), (True , False )), + 0b001111: (MIPS_INS_FLOOR_W_S, "floor.w.s", ("fd","fs" ), (True , False )), + 0b100001: (MIPS_INS_CVT_D_S, "cvt.d.s", ("fd","fs" ), (True , False )), + 0b100100: (MIPS_INS_CVT_W_S, "cvt.w.s", ("fd","fs" ), (True , False )), + 0b100101: (MIPS_INS_CVT_L_S, "cvt.l.s", ("fd","fs" ), (True , False )), + 0b110000: (MIPS_INS_C_F_S, "c.f.s", ("fs","ft" ), (False, False )), + 0b110001: (MIPS_INS_C_UN_S, "c.un.s", ("fs","ft" ), (False, False )), + 0b110010: (MIPS_INS_C_EQ_S, "c.eq.s", ("fs","ft" ), (False, False )), + 0b110011: (MIPS_INS_C_UEQ_S, "c.ueq.s", ("fs","ft" ), (False, False )), + 0b110100: (MIPS_INS_C_OLT_S, "c.olt.s", ("fs","ft" ), (False, False )), + 0b110101: (MIPS_INS_C_ULT_S, "c.ult.s", ("fs","ft" ), (False, False )), + 0b110110: (MIPS_INS_C_OLE_S, "c.ole.s", ("fs","ft" ), (False, False )), + 0b110111: (MIPS_INS_C_ULE_S, "c.ule.s", ("fs","ft" ), (False, False )), + 0b111000: (MIPS_INS_C_SF_S, "c.sf.s", ("fs","ft" ), (False, False )), + 0b111001: (MIPS_INS_C_NGLE_S, "c.ngle.s", ("fs","ft" ), (False, False )), + 0b111010: (MIPS_INS_C_SEQ_S, "c.seq.s", ("fs","ft" ), (False, False )), + 0b111011: (MIPS_INS_C_NGL_S, "c.ngl.s", ("fs","ft" ), (False, False )), + 0b111100: (MIPS_INS_C_LT_S, "c.lt.s", ("fs","ft" ), (False, False )), + 0b111101: (MIPS_INS_C_NGE_S, "c.nge.s", ("fs","ft" ), (False, False )), + 0b111110: (MIPS_INS_C_LE_S, "c.le.s", ("fs","ft" ), (False, False )), + 0b111111: (MIPS_INS_C_NGT_S, "c.ngt.s", ("fs","ft" ), (False, False )), + }), + 0b010001: (mips_get_function, { + 0b000000: (MIPS_INS_ADD_D, "add.d", ("fd","fs","ft"), (True , False, False)), + 0b000001: (MIPS_INS_SUB_D, "sub.d", ("fd","fs","ft"), (True , False, False)), + 0b000010: (MIPS_INS_MUL_D, "mul.d", ("fd","fs","ft"), (True , False, False)), + 0b000011: (MIPS_INS_DIV_D, "div.d", ("fd","fs","ft"), (True , False, False)), + 0b000100: (MIPS_INS_SQRT_D, "sqrt.d", ("fd","fs" ), (True , False )), + 0b000101: (MIPS_INS_ABS_D, "abs.d", ("fd","fs" ), (True , False )), + 0b000110: (MIPS_INS_MOV_D, "mov.d", ("fd","fs" ), (True , False )), + 0b000111: (MIPS_INS_NEG_D, "neg.d", ("fd","fs" ), (True , False )), + 0b001000: (MIPS_INS_ROUND_L_D, "round.l.d", ("fd","fs" ), (True , False )), + 0b001001: (MIPS_INS_TRUNC_L_D, "trunc.l.d", ("fd","fs" ), (True , False )), + 0b001010: (MIPS_INS_CEIL_L_D, "ceil.l.d", ("fd","fs" ), (True , False )), + 0b001011: (MIPS_INS_FLOOR_L_D, "floor.l.d", ("fd","fs" ), (True , False )), + 0b001100: (MIPS_INS_ROUND_W_D, "round.w.d", ("fd","fs" ), (True , False )), + 0b001101: (MIPS_INS_TRUNC_W_D, "trunc.w.d", ("fd","fs" ), (True , False )), + 0b001110: (MIPS_INS_CEIL_W_D, "ceil.w.d", ("fd","fs" ), (True , False )), + 0b001111: (MIPS_INS_FLOOR_W_D, "floor.w.d", ("fd","fs" ), (True , False )), + 0b100000: (MIPS_INS_CVT_S_D, "cvt.s.d", ("fd","fs" ), (True , False )), + 0b100100: (MIPS_INS_CVT_W_D, "cvt.w.d", ("fd","fs" ), (True , False )), + 0b100101: (MIPS_INS_CVT_L_D, "cvt.l.d", ("fd","fs" ), (True , False )), + 0b110000: (MIPS_INS_C_F_D, "c.f.d", ("fs","ft" ), (False, False )), + 0b110001: (MIPS_INS_C_UN_D, "c.un.d", ("fs","ft" ), (False, False )), + 0b110010: (MIPS_INS_C_EQ_D, "c.eq.d", ("fs","ft" ), (False, False )), + 0b110011: (MIPS_INS_C_UEQ_D, "c.ueq.d", ("fs","ft" ), (False, False )), + 0b110100: (MIPS_INS_C_OLT_D, "c.olt.d", ("fs","ft" ), (False, False )), + 0b110101: (MIPS_INS_C_ULT_D, "c.ult.d", ("fs","ft" ), (False, False )), + 0b110110: (MIPS_INS_C_OLE_D, "c.ole.d", ("fs","ft" ), (False, False )), + 0b110111: (MIPS_INS_C_ULE_D, "c.ule.d", ("fs","ft" ), (False, False )), + 0b111000: (MIPS_INS_C_SF_D, "c.sf.d", ("fs","ft" ), (False, False )), + 0b111001: (MIPS_INS_C_NGLE_D, "c.ngle.d", ("fs","ft" ), (False, False )), + 0b111010: (MIPS_INS_C_SEQ_D, "c.seq.d", ("fs","ft" ), (False, False )), + 0b111011: (MIPS_INS_C_NGL_D, "c.ngl.d", ("fs","ft" ), (False, False )), + 0b111100: (MIPS_INS_C_LT_D, "c.lt.d", ("fs","ft" ), (False, False )), + 0b111101: (MIPS_INS_C_NGE_D, "c.nge.d", ("fs","ft" ), (False, False )), + 0b111110: (MIPS_INS_C_LE_D, "c.le.d", ("fs","ft" ), (False, False )), + 0b111111: (MIPS_INS_C_NGT_D, "c.ngt.d", ("fs","ft" ), (False, False )), + }), + 0b010100: (mips_get_function, { + 0b100000: (MIPS_INS_CVT_S_W, "cvt.s.w", ("fd","fs"), (True , False)), + 0b100001: (MIPS_INS_CVT_D_W, "cvt.d.w", ("fd","fs"), (True , False)), + }), + 0b010101: (mips_get_function, { + 0b100000: (MIPS_INS_CVT_S_L, "cvt.s.l", ("fd","fs"), (True , False)), + 0b100001: (MIPS_INS_CVT_D_L, "cvt.d.l", ("fd","fs"), (True , False)), + }), + }), + 0b010100: (MIPS_INS_BEQL, "beql", ("rs","rt","offset" ), (False, False, False)), + 0b010101: (MIPS_INS_BNEL, "bnel", ("rs","rt","offset" ), (False, False, False)), + 0b010110: (MIPS_INS_BLEZL, "blezl", ("rs","offset" ), (False, False )), + 0b010111: (MIPS_INS_BGTZL, "bgtzl", ("rs","offset" ), (False, False )), + 0b011000: (MIPS_INS_DADDI, "daddi", ("rt","rs","imm" ), (True , False, False)), + 0b011001: (MIPS_INS_DADDIU, "daddiu", ("rt","rs","imm" ), (True , False, False)), + 0b011010: (MIPS_INS_LDL, "ldl", ("rt","offset(base)"), (True , False )), + 0b011011: (MIPS_INS_LDR, "ldr", ("rt","offset(base)"), (True , False )), + 0b100000: (MIPS_INS_LB, "lb", ("rt","offset(base)"), (True , False )), + 0b100001: (MIPS_INS_LH, "lh", ("rt","offset(base)"), (True , False )), + 0b100010: (MIPS_INS_LWL, "lwl", ("rt","offset(base)"), (True , False )), + 0b100011: (MIPS_INS_LW, "lw", ("rt","offset(base)"), (True , False )), + 0b100100: (MIPS_INS_LBU, "lbu", ("rt","offset(base)"), (True , False )), + 0b100101: (MIPS_INS_LHU, "lhu", ("rt","offset(base)"), (True , False )), + 0b100110: (MIPS_INS_LWR, "lwr", ("rt","offset(base)"), (True , False )), + 0b100111: (MIPS_INS_LWU, "lwu", ("rt","offset(base)"), (True , False )), + 0b101000: (MIPS_INS_SB, "sb", ("rt","offset(base)"), (False, False )), + 0b101001: (MIPS_INS_SH, "sh", ("rt","offset(base)"), (False, False )), + 0b101010: (MIPS_INS_SWL, "swl", ("rt","offset(base)"), (False, False )), + 0b101011: (MIPS_INS_SW, "sw", ("rt","offset(base)"), (False, False )), + 0b101100: (MIPS_INS_SDL, "sdl", ("rt","offset(base)"), (False, False )), + 0b101101: (MIPS_INS_SDR, "sdr", ("rt","offset(base)"), (False, False )), + 0b101110: (MIPS_INS_SWR, "swr", ("rt","offset(base)"), (False, False )), + 0b101111: (MIPS_INS_CACHE, "cache", ("op","offset(base)"), (False, False, False)), + 0b110000: (MIPS_INS_LL, "ll", ("rt","offset(base)"), (True , False )), + 0b110001: (MIPS_INS_LWC1, "lwc1", ("ft","offset(base)"), (True , False )), + # lwc2 + 0b110100: (MIPS_INS_LLD, "lld", ("rt","offset(base)"), (True , False )), + 0b110101: (MIPS_INS_LDC1, "ldc1", ("ft","offset(base)"), (True , False )), + # ldc2 + 0b110111: (MIPS_INS_LD, "ld", ("rt","offset(base)"), (True , False )), + 0b111000: (MIPS_INS_SC, "sc", ("rt","offset(base)"), (False, False )), + 0b111001: (MIPS_INS_SWC1, "swc1", ("ft","offset(base)"), (False, False )), + # lwc2 + 0b111100: (MIPS_INS_SCD, "scd", ("rt","offset(base)"), (False, False )), + 0b111101: (MIPS_INS_SDC1, "sdc1", ("ft","offset(base)"), (False, False )), + # sdc2 + 0b111111: (MIPS_INS_SD, "sd", ("rt","offset(base)"), (False, False )), +} + +rsp_insns = { + 0b000000: (mips_get_special, { + # opcode id mnemonic fields field is written to + 0b000000: (MIPS_INS_SLL, "sll", ("rd","rt","sa"), (True , False, False)), + 0b000010: (MIPS_INS_SRL, "srl", ("rd","rt","sa"), (True , False, False)), + 0b000011: (MIPS_INS_SRA, "sra", ("rd","rt","sa"), (True , False, False)), + 0b000100: (MIPS_INS_SLLV, "sllv", ("rd","rt","rs"), (True , False, False)), + 0b000110: (MIPS_INS_SRLV, "srlv", ("rd","rt","rs"), (True , False, False)), + 0b000111: (MIPS_INS_SRAV, "srav", ("rd","rt","rs"), (True , False, False)), + 0b001000: (MIPS_INS_JR, "jr", ("rs", ), (False, )), + 0b001001: (MIPS_INS_JALR, "jalr", ("rs", ), (False, )), # technically also rd but it's always $ra + 0b001101: (MIPS_INS_BREAK, "break", ("code", ), (False, )), + 0b100000: (MIPS_INS_ADD, "add", ("rd","rs","rt"), (True , False, False)), + 0b100001: (MIPS_INS_ADDU, "addu", ("rd","rs","rt"), (True , False, False)), + 0b100010: (MIPS_INS_SUB, "sub", ("rd","rs","rt"), (True , False, False)), + 0b100011: (MIPS_INS_SUBU, "subu", ("rd","rs","rt"), (True , False, False)), + 0b100100: (MIPS_INS_AND, "and", ("rd","rs","rt"), (True , False, False)), + 0b100101: (MIPS_INS_OR, "or", ("rd","rs","rt"), (True , False, False)), + 0b100110: (MIPS_INS_XOR, "xor", ("rd","rs","rt"), (True , False, False)), + 0b100111: (MIPS_INS_NOR, "nor", ("rd","rs","rt"), (True , False, False)), + 0b101010: (MIPS_INS_SLT, "slt", ("rd","rs","rt"), (True , False, False)), + 0b101011: (MIPS_INS_SLTU, "sltu", ("rd","rs","rt"), (True , False, False)), + }), + 0b000001: (mips_get_regimm, { + 0b00000: (MIPS_INS_BLTZ, "bltz", ("rs","offset"), (False, False)), + 0b00001: (MIPS_INS_BGEZ, "bgez", ("rs","offset"), (False, False)), + 0b10000: (MIPS_INS_BLTZAL, "bltzal", ("rs","offset"), (False, False)), + 0b10001: (MIPS_INS_BGEZAL, "bgezal", ("rs","offset"), (False, False)), + }), + 0b000010: (MIPS_INS_J, "j", ("target", ), (False, )), + 0b000011: (MIPS_INS_JAL, "jal", ("target", ), (False, )), + 0b000100: (MIPS_INS_BEQ, "beq", ("rs","rt","offset"), (False, False, False)), + 0b000101: (MIPS_INS_BNE, "bne", ("rs","rt","offset"), (False, False, False)), + 0b000110: (MIPS_INS_BLEZ, "blez", ("rs","offset" ), (False, False )), + 0b000111: (MIPS_INS_BGTZ, "bgtz", ("rs","offset" ), (False, False )), + 0b001000: (MIPS_INS_ADDI, "addi", ("rt","rs","imm" ), (True , False, False)), + 0b001001: (MIPS_INS_ADDIU, "addiu", ("rt","rs","imm" ), (True , False, False)), + 0b001010: (MIPS_INS_SLTI, "slti", ("rt","rs","imm" ), (True , False, False)), + 0b001011: (MIPS_INS_SLTIU, "sltiu", ("rt","rs","imm" ), (True , False, False)), + 0b001100: (MIPS_INS_ANDI, "andi", ("rt","rs","imm" ), (True , False, False)), + 0b001101: (MIPS_INS_ORI, "ori", ("rt","rs","imm" ), (True , False, False)), + 0b001110: (MIPS_INS_XORI, "xori", ("rt","rs","imm" ), (True , False, False)), + 0b001111: (MIPS_INS_LUI, "lui", ("rt","imm" ), (True , False )), + 0b010000: (mips_get_cop0, { + 0b00000: (MIPS_INS_MFC0, "mfc0", ("rt","cd"), (True , False)), + 0b00100: (MIPS_INS_MTC0, "mtc0", ("rt","cd"), (False, True )), + }), + 0b010010: (mips_get_cop2_func, { # TODO this encoding got ugly, move to a mask matcher like gnu objdump + 0b0: (mips_get_cop2, { + 0b0000: (MIPS_INS_MFC2, "mfc2", ("rt", "vd[e]"), (True , False)), + 0b0100: (MIPS_INS_MTC2, "mtc2", ("rt", "vd[e]"), (False, True )), + 0b0010: (MIPS_INS_CFC2, "cfc2", ("rt", "vc" ), (True , False)), + 0b0110: (MIPS_INS_CTC2, "ctc2", ("rt", "vc" ), (False, True )), + }), + 0b1: (mips_get_function, { + 0b000000: (MIPS_INS_VMULF, "vmulf", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000001: (MIPS_INS_VMULU, "vmulu", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000010: (MIPS_INS_VRNDP, "vrndp", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000011: (MIPS_INS_VMULQ, "vmulq", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000100: (MIPS_INS_VMUDL, "vmudl", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000101: (MIPS_INS_VMUDM, "vmudm", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000110: (MIPS_INS_VMUDN, "vmudn", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b000111: (MIPS_INS_VMUDH, "vmudh", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001000: (MIPS_INS_VMACF, "vmacf", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001001: (MIPS_INS_VMACU, "vmacu", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001010: (MIPS_INS_VRNDN, "vrndn", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001011: (MIPS_INS_VMACQ, "vmacq", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001100: (MIPS_INS_VMADL, "vmadl", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001101: (MIPS_INS_VMADM, "vmadm", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001110: (MIPS_INS_VMADN, "vmadn", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b001111: (MIPS_INS_VMADH, "vmadh", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010000: (MIPS_INS_VADD, "vadd", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010001: (MIPS_INS_VSUB, "vsub", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010011: (MIPS_INS_VABS, "vabs", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010100: (MIPS_INS_VADDC, "vaddc", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b010101: (MIPS_INS_VSUBC, "vsubc", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b011101: (MIPS_INS_VSAR, "vsar", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100000: (MIPS_INS_VLT, "vlt", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100001: (MIPS_INS_VEQ, "veq", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100010: (MIPS_INS_VNE, "vne", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100011: (MIPS_INS_VGE, "vge", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100100: (MIPS_INS_VCL, "vcl", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100101: (MIPS_INS_VCH, "vch", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100110: (MIPS_INS_VCR, "vcr", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b100111: (MIPS_INS_VMRG, "vmrg", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101000: (MIPS_INS_VAND, "vand", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101001: (MIPS_INS_VNAND, "vnand", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101010: (MIPS_INS_VOR, "vor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101011: (MIPS_INS_VNOR, "vnor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101100: (MIPS_INS_VXOR, "vxor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b101101: (MIPS_INS_VNXOR, "vnxor", ("vd", "vs", "vt[e]"), (True , False, False)), + 0b110000: (MIPS_INS_VRCP, "vrcp", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110001: (MIPS_INS_VRCPL, "vrcpl", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110010: (MIPS_INS_VRCPH, "vrcph", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110011: (MIPS_INS_VMOV, "vmov", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110100: (MIPS_INS_VRSQ, "vrsq", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110101: (MIPS_INS_VRSQL, "vrsql", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110110: (MIPS_INS_VRSQH, "vrsqh", ("vd[ed]", "vt[e]" ), (True , False)), + 0b110111: (MIPS_INS_VNOP, "vnop", ( ), ()), + }), + }), + 0b100000: (MIPS_INS_LB, "lb", ("rt","offset(base)"), (True , False)), + 0b100001: (MIPS_INS_LH, "lh", ("rt","offset(base)"), (True , False)), + 0b100011: (MIPS_INS_LW, "lw", ("rt","offset(base)"), (True , False)), + 0b100100: (MIPS_INS_LBU, "lbu", ("rt","offset(base)"), (True , False)), + 0b100101: (MIPS_INS_LHU, "lhu", ("rt","offset(base)"), (True , False)), + 0b101000: (MIPS_INS_SB, "sb", ("rt","offset(base)"), (False, False)), + 0b101001: (MIPS_INS_SH, "sh", ("rt","offset(base)"), (False, False)), + 0b101011: (MIPS_INS_SW, "sw", ("rt","offset(base)"), (False, False)), + 0b110010: (mips_get_lwc2, { + 0b00000: (MIPS_INS_LBV, "lbv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00001: (MIPS_INS_LSV, "lsv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00010: (MIPS_INS_LLV, "llv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00011: (MIPS_INS_LDV, "ldv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00100: (MIPS_INS_LQV, "lqv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00101: (MIPS_INS_LRV, "lrv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00110: (MIPS_INS_LPV, "lpv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b00111: (MIPS_INS_LUV, "luv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b01000: (MIPS_INS_LHV, "lhv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b01001: (MIPS_INS_LFV, "lfv", ("vt[ed]", "voffset(base)"), (True , False)), + 0b01011: (MIPS_INS_LTV, "ltv", ("vt[ed]", "voffset(base)"), (True , False)), + }), + 0b111010: (mips_get_swc2, { + 0b00000: (MIPS_INS_SBV, "sbv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00001: (MIPS_INS_SSV, "ssv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00010: (MIPS_INS_SLV, "slv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00011: (MIPS_INS_SDV, "sdv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00100: (MIPS_INS_SQV, "sqv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00101: (MIPS_INS_SRV, "srv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00110: (MIPS_INS_SPV, "spv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b00111: (MIPS_INS_SUV, "suv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01000: (MIPS_INS_SHV, "shv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01001: (MIPS_INS_SFV, "sfv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01010: (MIPS_INS_SWV, "swv", ("vt[ed]", "voffset(base)"), (False, False)), + 0b01011: (MIPS_INS_STV, "stv", ("vt[ed]", "voffset(base)"), (False, False)), + }), +} diff --git a/lib/ultralib/tools/patch_ar_meta.py b/lib/ultralib/tools/patch_ar_meta.py new file mode 100755 index 00000000..98d11f8c --- /dev/null +++ b/lib/ultralib/tools/patch_ar_meta.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# +# Patch metadata in .ar files +# + +import argparse + +def ar_patch(ar, new_uid, new_gid, new_filemode): + """ + AR file headers + + Offset Length Name Format + 0 16 File identifier ASCII + 16 12 File modification timestamp (in seconds) Decimal + 28 6 Owner ID Decimal + 34 6 Group ID Decimal + 40 8 File mode (type and permission) Octal + 48 10 File size in bytes Decimal + 58 2 Ending characters 0x60 0x0A + """ + assert len(ar) > 0x24 , "Got empty archive?" + + i = 8 + while i < len(ar): + file_name = ar[i:][0:][:16].decode("ASCII") + file_size = int(ar[i:][48:][:10].decode("ASCII").strip()) + end = ar[i:][58:][:2].decode("ASCII") + + assert end == "`\n" + + if file_name.strip() not in ["/", "//"]: # Skip armap + ar[i+28:i+28+6] = f"{new_uid:<6}".encode("ASCII")[:6] + ar[i+34:i+34+6] = f"{new_gid:<6}".encode("ASCII")[:6] + ar[i+40:i+40+8] = f"{new_filemode:<8}".encode("ASCII")[:8] + + if file_size % 2 != 0: + file_size += 1 + i += file_size + 60 + +def main(): + parser = argparse.ArgumentParser(description="Patch metadata in .a files.") + parser.add_argument("archive", help="path to the ar file") + args = parser.parse_args() + + ar = None + with open(args.archive, "rb") as ar_file: + ar = bytearray(ar_file.read()) + + ar_patch(ar, 0, 0, 37777700) + + with open(args.archive, "wb") as ar_file: + ar_file.write(ar) + +if __name__ == '__main__': + main() diff --git a/lib/ultralib/tools/shiftjis_conv.py b/lib/ultralib/tools/shiftjis_conv.py new file mode 100755 index 00000000..73037d20 --- /dev/null +++ b/lib/ultralib/tools/shiftjis_conv.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +import sys + +# Converts a file with UTF-8 Japanese glyphs in char literals, +# into one that uses u16 constants + +# Follows the layout in the manual page for easier cross reference +sjis_table = { + "ー": 0x815B, "ぜ": 0x82BA, "へ": 0x82D6, "ァ": 0x8340, "ソ": 0x835C, "ペ": 0x8379, + "ぁ": 0x829F, "そ": 0x82BB, "べ": 0x82D7, "ア": 0x8341, "ゾ": 0x835D, "ホ": 0x837A, + "あ": 0x82A0, "ぞ": 0x82BC, "ぺ": 0x82D8, "ィ": 0x8342, "タ": 0x835E, "ボ": 0x837B, + "ぃ": 0x82A1, "た": 0x82BD, "ほ": 0x82D9, "イ": 0x8343, "ダ": 0x835F, "ポ": 0x837C, + "い": 0x82A2, "だ": 0x82BE, "ぼ": 0x82DA, "ゥ": 0x8344, "チ": 0x8360, "マ": 0x837D, + "ぅ": 0x82A3, "ち": 0x82BF, "ぽ": 0x82DB, "ウ": 0x8345, "ヂ": 0x8361, "ミ": 0x837E, + "う": 0x82A4, "ぢ": 0x82C0, "ま": 0x82DC, "ェ": 0x8346, "ッ": 0x8362, "ム": 0x8380, + "ぇ": 0x82A5, "っ": 0x82C1, "み": 0x82DD, "エ": 0x8347, "ツ": 0x8363, "メ": 0x8381, + "え": 0x82A6, "つ": 0x82C2, "む": 0x82DE, "ォ": 0x8348, "ヅ": 0x8364, "モ": 0x8382, + "ぉ": 0x82A7, "づ": 0x82C3, "め": 0x82DF, "オ": 0x8349, "テ": 0x8365, "ャ": 0x8383, + "お": 0x82A8, "て": 0x82C4, "も": 0x82E0, "カ": 0x834A, "デ": 0x8366, "ヤ": 0x8384, + "か": 0x82A9, "で": 0x82C5, "ゃ": 0x82E1, "ガ": 0x834B, "ト": 0x8367, "ュ": 0x8385, + "が": 0x82AA, "と": 0x82C6, "や": 0x82E2, "キ": 0x834C, "ド": 0x8368, "ユ": 0x8386, + "き": 0x82AB, "ど": 0x82C7, "ゅ": 0x82E3, "ギ": 0x834D, "ナ": 0x8369, "ョ": 0x8387, + "ぎ": 0x82AC, "な": 0x82C8, "ゆ": 0x82E4, "ク": 0x834E, "ニ": 0x836A, "ヨ": 0x8388, + "く": 0x82AD, "に": 0x82C9, "ょ": 0x82E5, "グ": 0x834F, "ヌ": 0x836B, "ラ": 0x8389, + "ぐ": 0x82AE, "ぬ": 0x82CA, "よ": 0x82E6, "ケ": 0x8350, "ネ": 0x836C, "リ": 0x838A, + "け": 0x82AF, "ね": 0x82CB, "ら": 0x82E7, "ゲ": 0x8351, "ノ": 0x836D, "ル": 0x838B, + "げ": 0x82B0, "の": 0x82CC, "り": 0x82E8, "コ": 0x8352, "ハ": 0x836E, "レ": 0x838C, + "こ": 0x82B1, "は": 0x82CD, "る": 0x82E9, "ゴ": 0x8353, "バ": 0x836F, "ロ": 0x838D, + "ご": 0x82B2, "ば": 0x82CE, "れ": 0x82EA, "サ": 0x8354, "パ": 0x8370, "ヮ": 0x838E, + "さ": 0x82B3, "ぱ": 0x82CF, "ろ": 0x82EB, "ザ": 0x8355, "ヒ": 0x8371, "ワ": 0x838F, + "ざ": 0x82B4, "ひ": 0x82D0, "ゎ": 0x82EC, "シ": 0x8356, "ビ": 0x8372, "ヰ": 0x8390, + "し": 0x82B5, "び": 0x82D1, "わ": 0x82ED, "ジ": 0x8357, "ピ": 0x8373, "ヱ": 0x8391, + "じ": 0x82B6, "ぴ": 0x82D2, "ゐ": 0x82EE, "ス": 0x8358, "フ": 0x8374, "ヲ": 0x8392, + "す": 0x82B7, "ふ": 0x82D3, "ゑ": 0x82EF, "ズ": 0x8359, "ブ": 0x8375, "ン": 0x8393, + "ず": 0x82B8, "ぶ": 0x82D4, "を": 0x82F0, "セ": 0x835A, "プ": 0x8376, "ヴ": 0x8394, + "せ": 0x82B9, "ぷ": 0x82D5, "ん": 0x82F1, "ゼ": 0x835B, "ヘ": 0x8377, "ヵ": 0x8395, + "ベ": 0x8378, "ヶ": 0x8396, +} + +skipTimer = 0 + +def sjis_process(buf, outfile): + global skipTimer + + for i, char in enumerate(buf): + if skipTimer > 0: + skipTimer -= 1 + continue + if char == "'" and buf[i+1] in sjis_table: + if sjis_table[buf[i+1]] == 0: + print("Error: Please map %s in %s" % (buf[i+1], sys.argv[0])) + exit(1) + outfile.write("0x%X" % sjis_table[buf[i+1]]) + skipTimer = 2 + else: + outfile.write(char) + + diff --git a/lib/ultralib/tools/util.py b/lib/ultralib/tools/util.py new file mode 100644 index 00000000..b6c61559 --- /dev/null +++ b/lib/ultralib/tools/util.py @@ -0,0 +1,44 @@ + +import struct + +def enumerate_stepped(l, start=0, step=1): + p = start + for e in l: + yield p, e + p += step + +def back_align(x, al): + return x - (x % al) + +def forward_align(x, al): + return (x + (al - 1)) & ~(al - 1) + +def as_double(b): + return struct.unpack(">d", b)[0] + +def as_dword(b): + return struct.unpack(">Q", b)[0] + +def as_float(b): + return struct.unpack(">f", b)[0] + +def as_word(b): + return struct.unpack(">I", b)[0] + +def as_hword(b): + return struct.unpack(">H", b)[0] + +def as_double_list(b): + return [i[0] for i in struct.iter_unpack(">d", b)] + +def as_dword_list(b): + return [i[0] for i in struct.iter_unpack(">Q", b)] + +def as_float_list(b): + return [i[0] for i in struct.iter_unpack(">f", b)] + +def as_word_list(b): + return [i[0] for i in struct.iter_unpack(">I", b)] + +def as_hword_list(b): + return [h[0] for h in struct.iter_unpack(">H", b)] diff --git a/linker_scripts/common_undef_syms.ld b/linker_scripts/common_undef_syms.ld new file mode 100644 index 00000000..e69de29b diff --git a/linker_scripts/jp/hardware_regs.ld b/linker_scripts/jp/hardware_regs.ld new file mode 100644 index 00000000..533a42cd --- /dev/null +++ b/linker_scripts/jp/hardware_regs.ld @@ -0,0 +1,94 @@ +// Signal Processor Registers +SP_MEM_ADDR_REG = 0xA4040000; // defined:True +SP_DRAM_ADDR_REG = 0xA4040004; // defined:True +SP_RD_LEN_REG = 0xA4040008; // defined:True +SP_WR_LEN_REG = 0xA404000C; // defined:True +SP_STATUS_REG = 0xA4040010; // defined:True +SP_DMA_FULL_REG = 0xA4040014; // defined:True +SP_DMA_BUSY_REG = 0xA4040018; // defined:True +SP_SEMAPHORE_REG = 0xA404001C; // defined:True + +SP_PC = 0xA4080000; // defined:True + +// Display Processor Command Registers / Rasterizer Interface +DPC_START_REG = 0xA4100000; // defined:True +DPC_END_REG = 0xA4100004; // defined:True +DPC_CURRENT_REG = 0xA4100008; // defined:True +DPC_STATUS_REG = 0xA410000C; // defined:True +DPC_CLOCK_REG = 0xA4100010; // defined:True +DPC_BUFBUSY_REG = 0xA4100014; // defined:True +DPC_PIPEBUSY_REG = 0xA4100018; // defined:True +DPC_TMEM_REG = 0xA410001C; // defined:True + +// Display Processor Span Registers +DPS_TBIST_REG = 0xA4200000; // defined:True // DPS_TBIST_REG / DP_TMEM_BIST +DPS_TEST_MODE_REG = 0xA4200004; // defined:True +DPS_BUFTEST_ADDR_REG = 0xA4200008; // defined:True +DPS_BUFTEST_DATA_REG = 0xA420000C; // defined:True + +// MIPS Interface Registers +MI_MODE_REG = 0xA4300000; // defined:True // MI_MODE_REG / MI_INIT_MODE_REG +MI_VERSION_REG = 0xA4300004; // defined:True +MI_INTR_REG = 0xA4300008; // defined:True +MI_INTR_MASK_REG = 0xA430000C; // defined:True + +// Video Interface Registers +VI_STATUS_REG = 0xA4400000; // defined:True // VI_STATUS_REG / VI_CONTROL_REG +VI_DRAM_ADDR_REG = 0xA4400004; // defined:True // VI_DRAM_ADDR_REG / VI_ORIGIN_REG +VI_WIDTH_REG = 0xA4400008; // defined:True +VI_INTR_REG = 0xA440000C; // defined:True +VI_CURRENT_REG = 0xA4400010; // defined:True +VI_BURST_REG = 0xA4400014; // defined:True // VI_BURST_REG / VI_TIMING_REG +VI_V_SYNC_REG = 0xA4400018; // defined:True +VI_H_SYNC_REG = 0xA440001C; // defined:True +VI_LEAP_REG = 0xA4400020; // defined:True +VI_H_START_REG = 0xA4400024; // defined:True +VI_V_START_REG = 0xA4400028; // defined:True +VI_V_BURST_REG = 0xA440002C; // defined:True +VI_X_SCALE_REG = 0xA4400030; // defined:True +VI_Y_SCALE_REG = 0xA4400034; // defined:True + +// Audio Interface Registers +AI_DRAM_ADDR_REG = 0xA4500000; // defined:True +AI_LEN_REG = 0xA4500004; // defined:True +AI_CONTROL_REG = 0xA4500008; // defined:True +AI_STATUS_REG = 0xA450000C; // defined:True +AI_DACRATE_REG = 0xA4500010; // defined:True +AI_BITRATE_REG = 0xA4500014; // defined:True + +// Peripheral/Parallel Interface Registers +PI_DRAM_ADDR_REG = 0xA4600000; // defined:True +PI_CART_ADDR_REG = 0xA4600004; // defined:True +D_A4600005 = 0xA4600005; // defined:True // TODO figure out its name +D_A4600006 = 0xA4600006; // defined:True // TODO figure out its name +D_A4600007 = 0xA4600007; // defined:True // TODO figure out its name +PI_RD_LEN_REG = 0xA4600008; // defined:True +PI_WR_LEN_REG = 0xA460000C; // defined:True +PI_STATUS_REG = 0xA4600010; // defined:True +PI_BSD_DOM1_LAT_REG = 0xA4600014; // defined:True // PI dom1 latency +PI_BSD_DOM1_PWD_REG = 0xA4600018; // defined:True // PI dom1 pulse width +PI_BSD_DOM1_PGS_REG = 0xA460001C; // defined:True // PI dom1 page size +PI_BSD_DOM1_RLS_REG = 0xA4600020; // defined:True // PI dom1 release +PI_BSD_DOM2_LAT_REG = 0xA4600024; // defined:True // PI dom2 latency +PI_BSD_DOM2_LWD_REG = 0xA4600028; // defined:True // PI dom2 pulse width +PI_BSD_DOM2_PGS_REG = 0xA460002C; // defined:True // PI dom2 page size +PI_BSD_DOM2_RLS_REG = 0xA4600030; // defined:True // PI dom2 release + +// RDRAM Interface Registers +RI_MODE_REG = 0xA4700000; // defined:True +RI_CONFIG_REG = 0xA4700004; // defined:True +RI_CURRENT_LOAD_REG = 0xA4700008; // defined:True +RI_SELECT_REG = 0xA470000C; // defined:True +RI_REFRESH_REG = 0xA4700010; // defined:True +RI_LATENCY_REG = 0xA4700014; // defined:True +RI_RERROR_REG = 0xA4700018; // defined:True +RI_WERROR_REG = 0xA470001C; // defined:True + +// Serial Interface Registers +SI_DRAM_ADDR_REG = 0xA4800000; // defined:True +SI_PIF_ADDR_RD64B_REG = 0xA4800004; // defined:True +D_A4800008 = 0xA4800008; // defined:True // reserved +D_A480000C = 0xA480000C; // defined:True // reserved +SI_PIF_ADDR_WR64B_REG = 0xA4800010; // defined:True +D_A4800014 = 0xA4800014; // defined:True // reserved +SI_STATUS_REG = 0xA4800018; // defined:True diff --git a/linker_scripts/jp/ignored_addresses.txt b/linker_scripts/jp/ignored_addresses.txt new file mode 100644 index 00000000..81884434 --- /dev/null +++ b/linker_scripts/jp/ignored_addresses.txt @@ -0,0 +1,11 @@ +// For addresses that the disassembler should not try to symbolize + +D_00000000 = 0x00000000; // ignore:true + +D_01000000 = 0x01000000; // ignore:true + +D_80000000 = 0x80000000; // ignore:true +D_80000004 = 0x80000004; // ignore:true +D_80000008 = 0x80000008; // ignore:true +D_8000000C = 0x8000000C; // ignore:true +D_A0000000 = 0xA0000000; // ignore:true diff --git a/linker_scripts/jp/symbol_addrs_boot.txt b/linker_scripts/jp/symbol_addrs_boot.txt new file mode 100644 index 00000000..ec6f2a1a --- /dev/null +++ b/linker_scripts/jp/symbol_addrs_boot.txt @@ -0,0 +1,524 @@ +// .text + +entrypoint = 0x80025C00; // type:func + +func_80025C00_jp = 0x80025C00; // type:func +func_80025C60_jp = 0x80025C60; // type:func +func_80025CC0_jp = 0x80025CC0; // type:func +func_80025DF0_jp = 0x80025DF0; // type:func +func_80025E6C_jp = 0x80025E6C; // type:func +func_80025FD0_jp = 0x80025FD0; // type:func +func_800260A0_jp = 0x800260A0; // type:func +func_800261F4_jp = 0x800261F4; // type:func +func_80026240_jp = 0x80026240; // type:func +func_8002628C_jp = 0x8002628C; // type:func +func_800262D0_jp = 0x800262D0; // type:func +func_800263C0_jp = 0x800263C0; // type:func +func_800263F0_jp = 0x800263F0; // type:func +func_80026500_jp = 0x80026500; // type:func +func_800266C4_jp = 0x800266C4; // type:func +func_80026714_jp = 0x80026714; // type:func +func_80026770_jp = 0x80026770; // type:func +func_800267DC_jp = 0x800267DC; // type:func +func_80026814_jp = 0x80026814; // type:func +func_80026828_jp = 0x80026828; // type:func +func_800269E4_jp = 0x800269E4; // type:func +func_80026A64_jp = 0x80026A64; // type:func +func_80026B44_jp = 0x80026B44; // type:func +func_80026BC0_jp = 0x80026BC0; // type:func +func_80026C00_jp = 0x80026C00; // type:func +func_80026C28_jp = 0x80026C28; // type:func +func_80026C4C_jp = 0x80026C4C; // type:func +func_80026CAC_jp = 0x80026CAC; // type:func +func_80026DA0_jp = 0x80026DA0; // type:func +func_80026DCC_jp = 0x80026DCC; // type:func +func_80026E10_jp = 0x80026E10; // type:func +func_80026EA0_jp = 0x80026EA0; // type:func +func_80026F40_jp = 0x80026F40; // type:func +func_80027060_jp = 0x80027060; // type:func +func_800271E8_jp = 0x800271E8; // type:func +func_800272C0_jp = 0x800272C0; // type:func +func_800272DC_jp = 0x800272DC; // type:func +func_800272F8_jp = 0x800272F8; // type:func +func_80027320_jp = 0x80027320; // type:func +func_80027390_jp = 0x80027390; // type:func +func_80027404_jp = 0x80027404; // type:func +func_80027588_jp = 0x80027588; // type:func +func_800275DC_jp = 0x800275DC; // type:func +func_800276C0_jp = 0x800276C0; // type:func +func_800277B8_jp = 0x800277B8; // type:func +func_80027890_jp = 0x80027890; // type:func +func_80027988_jp = 0x80027988; // type:func +func_80027A3C_jp = 0x80027A3C; // type:func +func_80027A78_jp = 0x80027A78; // type:func +func_80027AB4_jp = 0x80027AB4; // type:func +func_80027B00_jp = 0x80027B00; // type:func +func_80027C4C_jp = 0x80027C4C; // type:func +func_80027C98_jp = 0x80027C98; // type:func +func_80027CF8_jp = 0x80027CF8; // type:func +func_80027D4C_jp = 0x80027D4C; // type:func +func_80027DA0_jp = 0x80027DA0; // type:func +func_80027DF4_jp = 0x80027DF4; // type:func +func_80027EA0_jp = 0x80027EA0; // type:func +func_80027F50_jp = 0x80027F50; // type:func +func_80027FF4_jp = 0x80027FF4; // type:func +func_8002808C_jp = 0x8002808C; // type:func +func_800283A8_jp = 0x800283A8; // type:func +func_800286A4_jp = 0x800286A4; // type:func +func_8002872C_jp = 0x8002872C; // type:func +func_800287BC_jp = 0x800287BC; // type:func +func_80028A88_jp = 0x80028A88; // type:func +func_80028BF4_jp = 0x80028BF4; // type:func +func_80028DF8_jp = 0x80028DF8; // type:func +func_80028F88_jp = 0x80028F88; // type:func +func_80029108_jp = 0x80029108; // type:func +func_80029278_jp = 0x80029278; // type:func +func_800292F4_jp = 0x800292F4; // type:func +func_800293B4_jp = 0x800293B4; // type:func +func_80029494_jp = 0x80029494; // type:func +func_800294D0_jp = 0x800294D0; // type:func +func_80029830_jp = 0x80029830; // type:func +func_80029884_jp = 0x80029884; // type:func +func_800299B8_jp = 0x800299B8; // type:func +func_80029AB4_jp = 0x80029AB4; // type:func +func_80029B0C_jp = 0x80029B0C; // type:func +func_80029B70_jp = 0x80029B70; // type:func +func_80029B80_jp = 0x80029B80; // type:func +func_80029C9C_jp = 0x80029C9C; // type:func +func_80029E0C_jp = 0x80029E0C; // type:func +func_80029EBC_jp = 0x80029EBC; // type:func +func_80029F5C_jp = 0x80029F5C; // type:func +func_80029FA4_jp = 0x80029FA4; // type:func +func_80029FEC_jp = 0x80029FEC; // type:func +func_8002A034_jp = 0x8002A034; // type:func +func_8002A064_jp = 0x8002A064; // type:func +func_8002A15C_jp = 0x8002A15C; // type:func +func_8002A1EC_jp = 0x8002A1EC; // type:func +func_8002A3F8_jp = 0x8002A3F8; // type:func +func_8002A448_jp = 0x8002A448; // type:func +func_8002A498_jp = 0x8002A498; // type:func +func_8002A4E8_jp = 0x8002A4E8; // type:func +func_8002A514_jp = 0x8002A514; // type:func +func_8002A524_jp = 0x8002A524; // type:func +func_8002A580_jp = 0x8002A580; // type:func +func_8002A5F0_jp = 0x8002A5F0; // type:func +func_8002A610_jp = 0x8002A610; // type:func +func_8002A618_jp = 0x8002A618; // type:func +func_8002A624_jp = 0x8002A624; // type:func +func_8002A63C_jp = 0x8002A63C; // type:func +func_8002A658_jp = 0x8002A658; // type:func +func_8002A674_jp = 0x8002A674; // type:func +func_8002A690_jp = 0x8002A690; // type:func +func_8002A698_jp = 0x8002A698; // type:func +func_8002A6A0_jp = 0x8002A6A0; // type:func +func_8002A6A8_jp = 0x8002A6A8; // type:func +func_8002A6B0_jp = 0x8002A6B0; // type:func +func_8002A6BC_jp = 0x8002A6BC; // type:func +func_8002A6C4_jp = 0x8002A6C4; // type:func +func_8002A6CC_jp = 0x8002A6CC; // type:func +func_8002A6EC_jp = 0x8002A6EC; // type:func +func_8002A70C_jp = 0x8002A70C; // type:func +func_8002A7E0_jp = 0x8002A7E0; // type:func +func_8002A8B8_jp = 0x8002A8B8; // type:func +func_8002A928_jp = 0x8002A928; // type:func +func_8002A9A0_jp = 0x8002A9A0; // type:func +func_8002A9F8_jp = 0x8002A9F8; // type:func +func_8002AA30_jp = 0x8002AA30; // type:func +func_8002AE7C_jp = 0x8002AE7C; // type:func +func_8002AEC8_jp = 0x8002AEC8; // type:func +func_8002AEEC_jp = 0x8002AEEC; // type:func +func_8002AF14_jp = 0x8002AF14; // type:func +func_8002AF28_jp = 0x8002AF28; // type:func +func_8002B3BC_jp = 0x8002B3BC; // type:func +func_8002B57C_jp = 0x8002B57C; // type:func +func_8002B5D8_jp = 0x8002B5D8; // type:func +func_8002B630_jp = 0x8002B630; // type:func +func_8002B65C_jp = 0x8002B65C; // type:func +func_8002B6E4_jp = 0x8002B6E4; // type:func +func_8002B6EC_jp = 0x8002B6EC; // type:func +func_8002B720_jp = 0x8002B720; // type:func +func_8002B750_jp = 0x8002B750; // type:func +func_8002B770_jp = 0x8002B770; // type:func +func_8002B7A0_jp = 0x8002B7A0; // type:func +func_8002B8E8_jp = 0x8002B8E8; // type:func +func_8002B910_jp = 0x8002B910; // type:func +func_8002B9C0_jp = 0x8002B9C0; // type:func +func_8002BC00_jp = 0x8002BC00; // type:func +func_8002BC34_jp = 0x8002BC34; // type:func +func_8002BC60_jp = 0x8002BC60; // type:func +func_8002BC90_jp = 0x8002BC90; // type:func +func_8002BCBC_jp = 0x8002BCBC; // type:func +func_8002BD2C_jp = 0x8002BD2C; // type:func +func_8002BD9C_jp = 0x8002BD9C; // type:func +func_8002BE6C_jp = 0x8002BE6C; // type:func +func_8002BF08_jp = 0x8002BF08; // type:func +func_8002BF78_jp = 0x8002BF78; // type:func +func_8002BFA0_jp = 0x8002BFA0; // type:func +func_8002BFF0_jp = 0x8002BFF0; // type:func +func_8002C130_jp = 0x8002C130; // type:func +func_8002C164_jp = 0x8002C164; // type:func +func_8002C184_jp = 0x8002C184; // type:func +func_8002C1A4_jp = 0x8002C1A4; // type:func +func_8002C1C4_jp = 0x8002C1C4; // type:func +func_8002C1E4_jp = 0x8002C1E4; // type:func +func_8002C204_jp = 0x8002C204; // type:func +func_8002C250_jp = 0x8002C250; // type:func +func_8002C374_jp = 0x8002C374; // type:func +func_8002C4C0_jp = 0x8002C4C0; // type:func +func_8002C500_jp = 0x8002C500; // type:func +func_8002C5E8_jp = 0x8002C5E8; // type:func +func_8002C618_jp = 0x8002C618; // type:func +func_8002C640_jp = 0x8002C640; // type:func +func_8002C64C_jp = 0x8002C64C; // type:func +func_8002C658_jp = 0x8002C658; // type:func +func_8002C668_jp = 0x8002C668; // type:func +func_8002C678_jp = 0x8002C678; // type:func +func_8002C684_jp = 0x8002C684; // type:func +func_8002C690_jp = 0x8002C690; // type:func +func_8002C6A0_jp = 0x8002C6A0; // type:func +func_8002C6B0_jp = 0x8002C6B0; // type:func +func_8002C6BC_jp = 0x8002C6BC; // type:func +func_8002C6C8_jp = 0x8002C6C8; // type:func +func_8002C6D8_jp = 0x8002C6D8; // type:func +func_8002C6E8_jp = 0x8002C6E8; // type:func +func_8002C6F4_jp = 0x8002C6F4; // type:func +func_8002C700_jp = 0x8002C700; // type:func +func_8002C710_jp = 0x8002C710; // type:func +func_8002C720_jp = 0x8002C720; // type:func +func_8002C73C_jp = 0x8002C73C; // type:func +func_8002C75C_jp = 0x8002C75C; // type:func +func_8002C77C_jp = 0x8002C77C; // type:func +func_8002C7A0_jp = 0x8002C7A0; // type:func +func_8002C7C8_jp = 0x8002C7C8; // type:func +func_8002C7F0_jp = 0x8002C7F0; // type:func +func_8002C820_jp = 0x8002C820; // type:func +func_8002C848_jp = 0x8002C848; // type:func +func_8002C89C_jp = 0x8002C89C; // type:func +func_8002C8D4_jp = 0x8002C8D4; // type:func +func_8002C8F8_jp = 0x8002C8F8; // type:func +func_8002C928_jp = 0x8002C928; // type:func +func_8002C94C_jp = 0x8002C94C; // type:func +func_8002C970_jp = 0x8002C970; // type:func +func_8002C9A0_jp = 0x8002C9A0; // type:func +func_8002C9AC_jp = 0x8002C9AC; // type:func +func_8002CA00_jp = 0x8002CA00; // type:func +func_8002CA58_jp = 0x8002CA58; // type:func +func_8002CA60_jp = 0x8002CA60; // type:func +func_8002CA88_jp = 0x8002CA88; // type:func +func_8002CAD4_jp = 0x8002CAD4; // type:func +func_8002CB30_jp = 0x8002CB30; // type:func +func_8002CB5C_jp = 0x8002CB5C; // type:func +func_8002CB84_jp = 0x8002CB84; // type:func +func_8002CBAC_jp = 0x8002CBAC; // type:func +func_8002CC10_jp = 0x8002CC10; // type:func +func_8002CC60_jp = 0x8002CC60; // type:func +func_8002CD00_jp = 0x8002CD00; // type:func +func_8002CD20_jp = 0x8002CD20; // type:func +func_8002CD28_jp = 0x8002CD28; // type:func +func_8002CE30_jp = 0x8002CE30; // type:func +func_8002CE70_jp = 0x8002CE70; // type:func +func_8002CFB4_jp = 0x8002CFB4; // type:func +func_8002D0F4_jp = 0x8002D0F4; // type:func +func_8002D12C_jp = 0x8002D12C; // type:func +func_8002D4DC_jp = 0x8002D4DC; // type:func +func_8002D5B0_jp = 0x8002D5B0; // type:func +func_8002D784_jp = 0x8002D784; // type:func +func_8002D850_jp = 0x8002D850; // type:func +func_8002D874_jp = 0x8002D874; // type:func +func_8002D8C4_jp = 0x8002D8C4; // type:func +func_8002D920_jp = 0x8002D920; // type:func +func_8002D954_jp = 0x8002D954; // type:func +func_8002D980_jp = 0x8002D980; // type:func +func_8002D9EC_jp = 0x8002D9EC; // type:func +func_8002DA3C_jp = 0x8002DA3C; // type:func +func_8002DA8C_jp = 0x8002DA8C; // type:func +func_8002DAE0_jp = 0x8002DAE0; // type:func + +func_8003B960_jp = 0x8003B960; // type:func +func_8003B9B0_jp = 0x8003B9B0; // type:func +func_8003B9E0_jp = 0x8003B9E0; // type:func +func_8003BA20_jp = 0x8003BA20; // type:func +func_8003BA60_jp = 0x8003BA60; // type:func +func_8003BAF0_jp = 0x8003BAF0; // type:func + +// .data + +D_8003BBC0_jp = 0x8003BBC0; // type:s8 +D_8003BBC4_jp = 0x8003BBC4; // +D_FLT_8003BBC8_jp = 0x8003BBC8; // type:f32 +D_FLT_8003BBCC_jp = 0x8003BBCC; // type:f32 +D_8003BBD0_jp = 0x8003BBD0; // +D_8003BBE0_jp = 0x8003BBE0; // +D_8003BBF0_jp = 0x8003BBF0; // +D_8003BC38_jp = 0x8003BC38; // +D_8003BC50_jp = 0x8003BC50; // +D_8003BC90_jp = 0x8003BC90; // +D_8003BC94_jp = 0x8003BC94; // +D_8003BCB0_jp = 0x8003BCB0; // +D_8003BD30_jp = 0x8003BD30; // +D_8003BD50_jp = 0x8003BD50; // +D_8003BD58_jp = 0x8003BD58; // +D_8003C560_jp = 0x8003C560; // +D_FLT_8003C584_jp = 0x8003C584; // type:f32 +D_8003C590_jp = 0x8003C590; // + + +// .rodata + +RO_STR_8003D180_jp = 0x8003D180; // type:asciz +RO_STR_8003D188_jp = 0x8003D188; // type:asciz +RO_STR_8003D190_jp = 0x8003D190; // type:asciz +RO_STR_8003D19C_jp = 0x8003D19C; // type:asciz +RO_FLT_8003D1A4_jp = 0x8003D1A4; // type:f32 +RO_STR_8003D1B0_jp = 0x8003D1B0; // type:asciz +RO_STR_8003D1B4_jp = 0x8003D1B4; // type:asciz +RO_STR_8003D1D8_jp = 0x8003D1D8; // type:asciz +RO_STR_8003D1EC_jp = 0x8003D1EC; // type:asciz +RO_STR_8003D214_jp = 0x8003D214; // type:asciz +RO_STR_8003D218_jp = 0x8003D218; // type:asciz +RO_STR_8003D22C_jp = 0x8003D22C; // type:asciz +RO_STR_8003D230_jp = 0x8003D230; // type:asciz +RO_STR_8003D23C_jp = 0x8003D23C; // type:asciz +RO_STR_8003D250_jp = 0x8003D250; // type:asciz +RO_STR_8003D264_jp = 0x8003D264; // type:asciz +RO_8003D268_jp = 0x8003D268; // +RO_STR_8003D26C_jp = 0x8003D26C; // type:asciz +RO_STR_8003D284_jp = 0x8003D284; // type:asciz +RO_8003D2C0_jp = 0x8003D2C0; // +RO_STR_8003D2C4_jp = 0x8003D2C4; // type:asciz +RO_STR_8003D2DC_jp = 0x8003D2DC; // type:asciz +RO_8003D31C_jp = 0x8003D31C; // +RO_STR_8003D320_jp = 0x8003D320; // type:asciz +RO_STR_8003D338_jp = 0x8003D338; // type:asciz +RO_STR_8003D378_jp = 0x8003D378; // type:asciz +RO_STR_8003D38C_jp = 0x8003D38C; // type:asciz +RO_STR_8003D3AC_jp = 0x8003D3AC; // type:asciz +RO_STR_8003D3C8_jp = 0x8003D3C8; // type:asciz +RO_STR_8003D3DC_jp = 0x8003D3DC; // type:asciz +RO_STR_8003D3F0_jp = 0x8003D3F0; // type:asciz +RO_STR_8003D400_jp = 0x8003D400; // type:asciz +RO_STR_8003D41C_jp = 0x8003D41C; // type:asciz +RO_STR_8003D440_jp = 0x8003D440; // type:asciz +RO_STR_8003D44C_jp = 0x8003D44C; // type:asciz +RO_STR_8003D460_jp = 0x8003D460; // type:asciz +RO_STR_8003D478_jp = 0x8003D478; // type:asciz +RO_STR_8003D490_jp = 0x8003D490; // type:asciz +RO_STR_8003D4A8_jp = 0x8003D4A8; // type:asciz +RO_STR_8003D4C0_jp = 0x8003D4C0; // type:asciz +RO_STR_8003D4D4_jp = 0x8003D4D4; // type:asciz +RO_STR_8003D4E8_jp = 0x8003D4E8; // type:asciz +RO_STR_8003D500_jp = 0x8003D500; // type:asciz +RO_STR_8003D518_jp = 0x8003D518; // type:asciz +RO_STR_8003D530_jp = 0x8003D530; // type:asciz +RO_STR_8003D548_jp = 0x8003D548; // type:asciz +RO_STR_8003D55C_jp = 0x8003D55C; // type:asciz +RO_STR_8003D56C_jp = 0x8003D56C; // type:asciz +RO_STR_8003D588_jp = 0x8003D588; // type:asciz +RO_STR_8003D5A4_jp = 0x8003D5A4; // type:asciz +RO_STR_8003D5BC_jp = 0x8003D5BC; // type:asciz +RO_STR_8003D5D8_jp = 0x8003D5D8; // type:asciz +RO_STR_8003D5F0_jp = 0x8003D5F0; // type:asciz +RO_STR_8003D604_jp = 0x8003D604; // type:asciz +RO_STR_8003D618_jp = 0x8003D618; // type:asciz +RO_STR_8003D624_jp = 0x8003D624; // type:asciz +RO_STR_8003D630_jp = 0x8003D630; // type:asciz +RO_STR_8003D644_jp = 0x8003D644; // type:asciz +RO_STR_8003D67C_jp = 0x8003D67C; // type:asciz +RO_STR_8003D6B4_jp = 0x8003D6B4; // type:asciz +RO_STR_8003D6FC_jp = 0x8003D6FC; // type:asciz +RO_STR_8003D748_jp = 0x8003D748; // type:asciz +RO_STR_8003D758_jp = 0x8003D758; // type:asciz +RO_STR_8003D76C_jp = 0x8003D76C; // type:asciz +RO_STR_8003D77C_jp = 0x8003D77C; // type:asciz +RO_STR_8003D790_jp = 0x8003D790; // type:asciz +RO_STR_8003D7A0_jp = 0x8003D7A0; // type:asciz +RO_STR_8003D7A8_jp = 0x8003D7A8; // type:asciz +RO_STR_8003D7AC_jp = 0x8003D7AC; // type:asciz +RO_STR_8003D7BC_jp = 0x8003D7BC; // type:asciz +RO_STR_8003D7C4_jp = 0x8003D7C4; // type:asciz +RO_STR_8003D7D8_jp = 0x8003D7D8; // type:asciz +RO_STR_8003D7F4_jp = 0x8003D7F4; // type:asciz +RO_STR_8003D810_jp = 0x8003D810; // type:asciz +RO_STR_8003D82C_jp = 0x8003D82C; // type:asciz +RO_STR_8003D848_jp = 0x8003D848; // type:asciz +RO_STR_8003D864_jp = 0x8003D864; // type:asciz +RO_STR_8003D880_jp = 0x8003D880; // type:asciz +RO_STR_8003D89C_jp = 0x8003D89C; // type:asciz +RO_STR_8003D8B8_jp = 0x8003D8B8; // type:asciz +RO_STR_8003D8D4_jp = 0x8003D8D4; // type:asciz +RO_STR_8003D8F0_jp = 0x8003D8F0; // type:asciz +RO_STR_8003D910_jp = 0x8003D910; // type:asciz +RO_STR_8003D914_jp = 0x8003D914; // type:asciz +RO_STR_8003D918_jp = 0x8003D918; // type:asciz +RO_STR_8003D91C_jp = 0x8003D91C; // type:asciz +RO_STR_8003D920_jp = 0x8003D920; // type:asciz +RO_STR_8003D924_jp = 0x8003D924; // type:asciz +RO_STR_8003D928_jp = 0x8003D928; // type:asciz +RO_STR_8003D92C_jp = 0x8003D92C; // type:asciz +RO_STR_8003D930_jp = 0x8003D930; // type:asciz +RO_STR_8003D934_jp = 0x8003D934; // type:asciz +RO_STR_8003D938_jp = 0x8003D938; // type:asciz +RO_STR_8003D950_jp = 0x8003D950; // type:asciz +RO_STR_8003D970_jp = 0x8003D970; // type:asciz +RO_STR_8003D990_jp = 0x8003D990; // type:asciz +RO_STR_8003D9B0_jp = 0x8003D9B0; // type:asciz +RO_STR_8003D9D0_jp = 0x8003D9D0; // type:asciz +RO_STR_8003D9F0_jp = 0x8003D9F0; // type:asciz +RO_STR_8003DA10_jp = 0x8003DA10; // type:asciz +RO_STR_8003DA30_jp = 0x8003DA30; // type:asciz +RO_STR_8003DA50_jp = 0x8003DA50; // type:asciz +RO_STR_8003DA70_jp = 0x8003DA70; // type:asciz +RO_STR_8003DA90_jp = 0x8003DA90; // type:asciz +RO_STR_8003DAB0_jp = 0x8003DAB0; // type:asciz +RO_STR_8003DAB4_jp = 0x8003DAB4; // type:asciz +RO_STR_8003DAB8_jp = 0x8003DAB8; // type:asciz +RO_STR_8003DABC_jp = 0x8003DABC; // type:asciz +RO_STR_8003DAC0_jp = 0x8003DAC0; // type:asciz +RO_STR_8003DAC4_jp = 0x8003DAC4; // type:asciz +RO_STR_8003DAC8_jp = 0x8003DAC8; // type:asciz +RO_STR_8003DACC_jp = 0x8003DACC; // type:asciz +RO_STR_8003DAD0_jp = 0x8003DAD0; // type:asciz +RO_STR_8003DAD4_jp = 0x8003DAD4; // type:asciz +RO_STR_8003DAD8_jp = 0x8003DAD8; // type:asciz +RO_STR_8003DB50_jp = 0x8003DB50; // type:asciz +RO_STR_8003DB84_jp = 0x8003DB84; // type:asciz +RO_STR_8003DB8C_jp = 0x8003DB8C; // type:asciz +RO_STR_8003DB98_jp = 0x8003DB98; // type:asciz +RO_STR_8003DBA0_jp = 0x8003DBA0; // type:asciz +RO_STR_8003DBA8_jp = 0x8003DBA8; // type:asciz +RO_STR_8003DBB0_jp = 0x8003DBB0; // type:asciz +RO_STR_8003DBC8_jp = 0x8003DBC8; // type:asciz +RO_STR_8003DBD4_jp = 0x8003DBD4; // type:asciz +RO_STR_8003DBE0_jp = 0x8003DBE0; // type:asciz +RO_STR_8003DC08_jp = 0x8003DC08; // type:asciz +RO_STR_8003DC14_jp = 0x8003DC14; // type:asciz +RO_STR_8003DC20_jp = 0x8003DC20; // type:asciz +RO_8003DC24_jp = 0x8003DC24; // +RO_STR_8003DC48_jp = 0x8003DC48; // type:asciz +RO_STR_8003DC80_jp = 0x8003DC80; // type:asciz +RO_STR_8003DCB4_jp = 0x8003DCB4; // type:asciz +RO_STR_8003DCE8_jp = 0x8003DCE8; // type:asciz +RO_STR_8003DD0C_jp = 0x8003DD0C; // type:asciz +RO_STR_8003DD28_jp = 0x8003DD28; // type:asciz +RO_STR_8003DD34_jp = 0x8003DD34; // type:asciz +RO_STR_8003DD50_jp = 0x8003DD50; // type:asciz +RO_STR_8003DD6C_jp = 0x8003DD6C; // type:asciz +RO_STR_8003DD88_jp = 0x8003DD88; // type:asciz +RO_STR_8003DDA4_jp = 0x8003DDA4; // type:asciz +RO_STR_8003DDAC_jp = 0x8003DDAC; // type:asciz +RO_STR_8003DDC4_jp = 0x8003DDC4; // type:asciz +RO_STR_8003DDC8_jp = 0x8003DDC8; // type:asciz +RO_STR_8003DDD0_jp = 0x8003DDD0; // type:asciz +RO_STR_8003DDD4_jp = 0x8003DDD4; // type:asciz +RO_STR_8003DDDC_jp = 0x8003DDDC; // type:asciz +RO_STR_8003DDF4_jp = 0x8003DDF4; // type:asciz +RO_STR_8003DDF8_jp = 0x8003DDF8; // type:asciz +RO_STR_8003DE00_jp = 0x8003DE00; // type:asciz +RO_STR_8003DE04_jp = 0x8003DE04; // type:asciz +RO_STR_8003DE0C_jp = 0x8003DE0C; // type:asciz +jtbl_8003DE1C_jp = 0x8003DE1C; // type:jtbl +RO_8003DE50_jp = 0x8003DE50; // +RO_STR_8003E250_jp = 0x8003E250; // type:asciz +RO_STR_8003E254_jp = 0x8003E254; // type:asciz +RO_STR_8003E25C_jp = 0x8003E25C; // type:asciz +RO_STR_8003E264_jp = 0x8003E264; // type:asciz +RO_STR_8003E270_jp = 0x8003E270; // type:asciz +RO_STR_8003E278_jp = 0x8003E278; // type:asciz +RO_STR_8003E27C_jp = 0x8003E27C; // type:asciz +jtbl_8003E290_jp = 0x8003E290; // type:jtbl +RO_STR_8003E2B0_jp = 0x8003E2B0; // type:asciz +RO_FLT_8003E2C0_jp = 0x8003E2C0; // type:f32 +RO_FLT_8003E2E4_jp = 0x8003E2E4; // type:f32 +RO_FLT_8003E2E8_jp = 0x8003E2E8; // type:f32 +RO_FLT_8003E2EC_jp = 0x8003E2EC; // type:f32 +RO_FLT_8003E2F0_jp = 0x8003E2F0; // type:f32 +RO_FLT_8003E2F4_jp = 0x8003E2F4; // type:f32 +RO_FLT_8003E2F8_jp = 0x8003E2F8; // type:f32 +RO_FLT_8003E2FC_jp = 0x8003E2FC; // type:f32 +RO_FLT_8003E300_jp = 0x8003E300; // type:f32 +RO_FLT_8003E304_jp = 0x8003E304; // type:f32 +RO_FLT_8003E308_jp = 0x8003E308; // type:f32 +RO_FLT_8003E30C_jp = 0x8003E30C; // type:f32 +RO_STR_8003E310_jp = 0x8003E310; // type:asciz +RO_STR_8003E328_jp = 0x8003E328; // type:asciz +RO_STR_8003E35C_jp = 0x8003E35C; // type:asciz +RO_STR_8003E398_jp = 0x8003E398; // type:asciz +RO_STR_8003E3C8_jp = 0x8003E3C8; // type:asciz +RO_STR_8003E400_jp = 0x8003E400; // type:asciz +RO_STR_8003E43C_jp = 0x8003E43C; // type:asciz +RO_STR_8003E46C_jp = 0x8003E46C; // type:asciz +RO_STR_8003E484_jp = 0x8003E484; // type:asciz +RO_STR_8003E49C_jp = 0x8003E49C; // type:asciz +RO_STR_8003E4C0_jp = 0x8003E4C0; // type:asciz +RO_STR_8003E4D4_jp = 0x8003E4D4; // type:asciz +RO_STR_8003E4D8_jp = 0x8003E4D8; // type:asciz +RO_STR_8003E4DC_jp = 0x8003E4DC; // type:asciz +RO_STR_8003E4E0_jp = 0x8003E4E0; // type:asciz +RO_STR_8003E4F4_jp = 0x8003E4F4; // type:asciz +RO_STR_8003E514_jp = 0x8003E514; // type:asciz +RO_STR_8003E534_jp = 0x8003E534; // type:asciz +RO_STR_8003E554_jp = 0x8003E554; // type:asciz +RO_STR_8003E588_jp = 0x8003E588; // type:asciz +RO_STR_8003E5A4_jp = 0x8003E5A4; // type:asciz + +RO_DBL_8003E890_jp = 0x8003E890; // type:f64 +RO_STR_8003E8D8_jp = 0x8003E8D8; // type:asciz +RO_STR_8003E8DC_jp = 0x8003E8DC; // type:asciz +RO_8003E8E0_jp = 0x8003E8E0; // type:u8 +RO_DBL_8003E8E8_jp = 0x8003E8E8; // type:f64 +RO_8003E8F0_jp = 0x8003E8F0; // type:s64 +RO_8003E8F8_jp = 0x8003E8F8; // type:s64 + +// .bss + +B_8003E940_jp = 0x8003E940; // +B_8003ED40_jp = 0x8003ED40; // +B_8003ED60_jp = 0x8003ED60; // +B_8003ED80_jp = 0x8003ED80; // +B_8003EF30_jp = 0x8003EF30; // +B_8003F330_jp = 0x8003F330; // +B_8003F4E0_jp = 0x8003F4E0; // +B_8003FDE0_jp = 0x8003FDE0; // +B_8003FE00_jp = 0x8003FE00; // +B_8003FEC8_jp = 0x8003FEC8; // +B_8003FEE0_jp = 0x8003FEE0; // +B_8003FF30_jp = 0x8003FF30; // type:u8 +B_8003FF31_jp = 0x8003FF31; // type:u8 +B_8003FF40_jp = 0x8003FF40; // +B_8003FF5C_jp = 0x8003FF5C; // type:u16 +B_8003FF60_jp = 0x8003FF60; // +B_8003FF78_jp = 0x8003FF78; // +B_8003FFF8_jp = 0x8003FFF8; // +B_800401A8_jp = 0x800401A8; // +B_800406A8_jp = 0x800406A8; // +B_800406AC_jp = 0x800406AC; // +B_800406B0_jp = 0x800406B0; // +B_800406B4_jp = 0x800406B4; // +B_800406C0_jp = 0x800406C0; // +B_80040AC0_jp = 0x80040AC0; // +B_80040AC4_jp = 0x80040AC4; // +B_80040AC8_jp = 0x80040AC8; // +B_80040ACC_jp = 0x80040ACC; // +B_80040AD0_jp = 0x80040AD0; // +B_80040AE0_jp = 0x80040AE0; // +B_80040AE4_jp = 0x80040AE4; // type:u8 +B_80040AE8_jp = 0x80040AE8; // +B_800410E8_jp = 0x800410E8; // +B_80041108_jp = 0x80041108; // type:u8 +B_800418D6_jp = 0x800418D6; // type:s8 +B_80041960_jp = 0x80041960; // type:s8 +B_80041964_jp = 0x80041964; // type:u16 +B_80041970_jp = 0x80041970; // type:u16 +B_80041972_jp = 0x80041972; // type:u16 +B_80041980_jp = 0x80041980; // type:u16 +B_80041982_jp = 0x80041982; // type:u16 +B_80041995_jp = 0x80041995; // type:s8 +B_80041998_jp = 0x80041998; // +B_800419A0_jp = 0x800419A0; // type:u8 +B_800419B0_jp = 0x800419B0; // +B_800419C0_jp = 0x800419C0; // +B_800419F0_jp = 0x800419F0; // +B_80041A00_jp = 0x80041A00; // + +B_80044684_jp = 0x80044684; // +D_80044690_jp = 0x80044690; // diff --git a/linker_scripts/jp/symbol_addrs_code.txt b/linker_scripts/jp/symbol_addrs_code.txt new file mode 100644 index 00000000..fd7a438a --- /dev/null +++ b/linker_scripts/jp/symbol_addrs_code.txt @@ -0,0 +1,6732 @@ +// .text + +func_80051A80_jp = 0x80051A80; // type:func +func_80051AC4_jp = 0x80051AC4; // type:func +func_80051AE4_jp = 0x80051AE4; // type:func +func_80051B44_jp = 0x80051B44; // type:func +func_80051C18_jp = 0x80051C18; // type:func +func_80051CE8_jp = 0x80051CE8; // type:func +func_80051D74_jp = 0x80051D74; // type:func +func_80051DF0_jp = 0x80051DF0; // type:func +func_80051EC4_jp = 0x80051EC4; // type:func +func_80051F3C_jp = 0x80051F3C; // type:func +func_800520DC_jp = 0x800520DC; // type:func +func_800521A8_jp = 0x800521A8; // type:func +func_80052208_jp = 0x80052208; // type:func +func_80052228_jp = 0x80052228; // type:func +func_8005228C_jp = 0x8005228C; // type:func +func_80052298_jp = 0x80052298; // type:func +func_80052310_jp = 0x80052310; // type:func +func_8005238C_jp = 0x8005238C; // type:func +func_80052408_jp = 0x80052408; // type:func +func_80052484_jp = 0x80052484; // type:func +func_80052504_jp = 0x80052504; // type:func +func_80052584_jp = 0x80052584; // type:func +func_80052610_jp = 0x80052610; // type:func +func_8005264C_jp = 0x8005264C; // type:func +func_800528D4_jp = 0x800528D4; // type:func +func_80052D20_jp = 0x80052D20; // type:func +func_800530D8_jp = 0x800530D8; // type:func +func_80053170_jp = 0x80053170; // type:func +func_800531F0_jp = 0x800531F0; // type:func +func_8005326C_jp = 0x8005326C; // type:func +func_800532E8_jp = 0x800532E8; // type:func +func_80053384_jp = 0x80053384; // type:func +func_800533F4_jp = 0x800533F4; // type:func +func_80053470_jp = 0x80053470; // type:func +func_8005376C_jp = 0x8005376C; // type:func +func_80053B54_jp = 0x80053B54; // type:func +func_80053EF8_jp = 0x80053EF8; // type:func +func_800542CC_jp = 0x800542CC; // type:func +func_80054320_jp = 0x80054320; // type:func +func_80054474_jp = 0x80054474; // type:func +func_80054504_jp = 0x80054504; // type:func +func_80054884_jp = 0x80054884; // type:func +func_800549C0_jp = 0x800549C0; // type:func +func_80054A28_jp = 0x80054A28; // type:func +func_80054A94_jp = 0x80054A94; // type:func +func_80054B44_jp = 0x80054B44; // type:func +func_80054BB0_jp = 0x80054BB0; // type:func +func_80054C88_jp = 0x80054C88; // type:func +func_80054D0C_jp = 0x80054D0C; // type:func +func_80054D3C_jp = 0x80054D3C; // type:func +func_80054F10_jp = 0x80054F10; // type:func +func_80055214_jp = 0x80055214; // type:func +func_80055248_jp = 0x80055248; // type:func +func_800554D8_jp = 0x800554D8; // type:func +func_80055598_jp = 0x80055598; // type:func +func_80055650_jp = 0x80055650; // type:func +func_8005578C_jp = 0x8005578C; // type:func +func_800558B0_jp = 0x800558B0; // type:func +func_800558F8_jp = 0x800558F8; // type:func +func_800559D4_jp = 0x800559D4; // type:func +func_80055A54_jp = 0x80055A54; // type:func +func_80055B84_jp = 0x80055B84; // type:func +func_80055C74_jp = 0x80055C74; // type:func +func_80055D94_jp = 0x80055D94; // type:func +func_80055E20_jp = 0x80055E20; // type:func +func_80055E34_jp = 0x80055E34; // type:func +func_80055E5C_jp = 0x80055E5C; // type:func +func_80055EF8_jp = 0x80055EF8; // type:func +func_80055F28_jp = 0x80055F28; // type:func +func_80055F64_jp = 0x80055F64; // type:func +func_8005603C_jp = 0x8005603C; // type:func +func_800560AC_jp = 0x800560AC; // type:func +func_8005611C_jp = 0x8005611C; // type:func +func_8005615C_jp = 0x8005615C; // type:func +func_80056234_jp = 0x80056234; // type:func +func_80056270_jp = 0x80056270; // type:func +func_80056310_jp = 0x80056310; // type:func +func_80056380_jp = 0x80056380; // type:func +func_800563F4_jp = 0x800563F4; // type:func +func_80056450_jp = 0x80056450; // type:func +func_80056494_jp = 0x80056494; // type:func +func_8005652C_jp = 0x8005652C; // type:func +func_8005658C_jp = 0x8005658C; // type:func +func_800565B8_jp = 0x800565B8; // type:func +func_80056614_jp = 0x80056614; // type:func +func_800566B0_jp = 0x800566B0; // type:func +func_8005673C_jp = 0x8005673C; // type:func +func_80056794_jp = 0x80056794; // type:func +func_800567E8_jp = 0x800567E8; // type:func +func_80056800_jp = 0x80056800; // type:func +func_80056A14_jp = 0x80056A14; // type:func +func_80056B48_jp = 0x80056B48; // type:func +func_80056CD0_jp = 0x80056CD0; // type:func +func_80056CF4_jp = 0x80056CF4; // type:func +func_80056DD0_jp = 0x80056DD0; // type:func +func_80056E1C_jp = 0x80056E1C; // type:func +func_80056E88_jp = 0x80056E88; // type:func +func_80057274_jp = 0x80057274; // type:func +func_80057304_jp = 0x80057304; // type:func +func_800575F8_jp = 0x800575F8; // type:func +func_8005773C_jp = 0x8005773C; // type:func +func_80057784_jp = 0x80057784; // type:func +func_800577F8_jp = 0x800577F8; // type:func +func_80057848_jp = 0x80057848; // type:func +func_800578E0_jp = 0x800578E0; // type:func +func_80057940_jp = 0x80057940; // type:func +func_80057A8C_jp = 0x80057A8C; // type:func +func_80057B70_jp = 0x80057B70; // type:func +func_80057BE8_jp = 0x80057BE8; // type:func +func_80057C48_jp = 0x80057C48; // type:func +func_80057D3C_jp = 0x80057D3C; // type:func +func_80057E24_jp = 0x80057E24; // type:func +func_80057FD0_jp = 0x80057FD0; // type:func +func_8005807C_jp = 0x8005807C; // type:func +func_80058160_jp = 0x80058160; // type:func +func_800581BC_jp = 0x800581BC; // type:func +func_80058298_jp = 0x80058298; // type:func +func_8005832C_jp = 0x8005832C; // type:func +func_80058428_jp = 0x80058428; // type:func +func_80058460_jp = 0x80058460; // type:func +func_800584AC_jp = 0x800584AC; // type:func +func_800584E0_jp = 0x800584E0; // type:func +func_80058528_jp = 0x80058528; // type:func +func_80058620_jp = 0x80058620; // type:func +func_80058810_jp = 0x80058810; // type:func +func_80058848_jp = 0x80058848; // type:func +func_80058880_jp = 0x80058880; // type:func +func_800588B8_jp = 0x800588B8; // type:func +func_80058928_jp = 0x80058928; // type:func +func_80058998_jp = 0x80058998; // type:func +func_80058A10_jp = 0x80058A10; // type:func +func_80058A18_jp = 0x80058A18; // type:func +func_80058AF0_jp = 0x80058AF0; // type:func +func_80058B60_jp = 0x80058B60; // type:func +func_80058BB8_jp = 0x80058BB8; // type:func +func_80058BF0_jp = 0x80058BF0; // type:func +func_80058C40_jp = 0x80058C40; // type:func +func_80058D30_jp = 0x80058D30; // type:func +func_80058D78_jp = 0x80058D78; // type:func +func_80058E5C_jp = 0x80058E5C; // type:func +func_80058FB0_jp = 0x80058FB0; // type:func +func_8005904C_jp = 0x8005904C; // type:func +func_800590B0_jp = 0x800590B0; // type:func +func_800590F4_jp = 0x800590F4; // type:func +func_800591F4_jp = 0x800591F4; // type:func +func_800592B8_jp = 0x800592B8; // type:func +func_800593A8_jp = 0x800593A8; // type:func +func_800596FC_jp = 0x800596FC; // type:func +func_80059744_jp = 0x80059744; // type:func +func_80059774_jp = 0x80059774; // type:func +func_800597C0_jp = 0x800597C0; // type:func +func_80059804_jp = 0x80059804; // type:func +func_80059840_jp = 0x80059840; // type:func +func_80059878_jp = 0x80059878; // type:func +func_80059890_jp = 0x80059890; // type:func +func_800599C0_jp = 0x800599C0; // type:func +func_80059A6C_jp = 0x80059A6C; // type:func +func_80059A80_jp = 0x80059A80; // type:func +func_80059A94_jp = 0x80059A94; // type:func +func_80059AE0_jp = 0x80059AE0; // type:func +func_80059B34_jp = 0x80059B34; // type:func +func_80059B90_jp = 0x80059B90; // type:func +func_80059BF0_jp = 0x80059BF0; // type:func +func_80059C24_jp = 0x80059C24; // type:func +func_80059EC0_jp = 0x80059EC0; // type:func +func_8005A070_jp = 0x8005A070; // type:func +func_8005A154_jp = 0x8005A154; // type:func +func_8005A238_jp = 0x8005A238; // type:func +func_8005A2FC_jp = 0x8005A2FC; // type:func +func_8005ABA0_jp = 0x8005ABA0; // type:func +func_8005ABE0_jp = 0x8005ABE0; // type:func +func_8005ACA8_jp = 0x8005ACA8; // type:func +func_8005ACC0_jp = 0x8005ACC0; // type:func +func_8005ACEC_jp = 0x8005ACEC; // type:func +func_8005AD08_jp = 0x8005AD08; // type:func +func_8005AD5C_jp = 0x8005AD5C; // type:func +func_8005ADA8_jp = 0x8005ADA8; // type:func +func_8005AE1C_jp = 0x8005AE1C; // type:func +func_8005AE40_jp = 0x8005AE40; // type:func +func_8005AE78_jp = 0x8005AE78; // type:func +func_8005AF38_jp = 0x8005AF38; // type:func +func_8005AF7C_jp = 0x8005AF7C; // type:func +func_8005AFD0_jp = 0x8005AFD0; // type:func +func_8005AFE4_jp = 0x8005AFE4; // type:func +func_8005AFF8_jp = 0x8005AFF8; // type:func +func_8005B028_jp = 0x8005B028; // type:func +func_8005B128_jp = 0x8005B128; // type:func +func_8005B204_jp = 0x8005B204; // type:func +func_8005B2F4_jp = 0x8005B2F4; // type:func +func_8005B338_jp = 0x8005B338; // type:func +func_8005B464_jp = 0x8005B464; // type:func +func_8005B4D4_jp = 0x8005B4D4; // type:func +func_8005B4E8_jp = 0x8005B4E8; // type:func +func_8005B4FC_jp = 0x8005B4FC; // type:func +func_8005B52C_jp = 0x8005B52C; // type:func +func_8005B5BC_jp = 0x8005B5BC; // type:func +func_8005B5FC_jp = 0x8005B5FC; // type:func +func_8005B610_jp = 0x8005B610; // type:func +func_8005B620_jp = 0x8005B620; // type:func +func_8005B668_jp = 0x8005B668; // type:func +func_8005B6D4_jp = 0x8005B6D4; // type:func +func_8005B6F8_jp = 0x8005B6F8; // type:func +func_8005B730_jp = 0x8005B730; // type:func +func_8005B758_jp = 0x8005B758; // type:func +func_8005B810_jp = 0x8005B810; // type:func +func_8005B8D4_jp = 0x8005B8D4; // type:func +func_8005B90C_jp = 0x8005B90C; // type:func +func_8005B92C_jp = 0x8005B92C; // type:func +func_8005BA0C_jp = 0x8005BA0C; // type:func +func_8005BB38_jp = 0x8005BB38; // type:func +func_8005BB90_jp = 0x8005BB90; // type:func +func_8005BC08_jp = 0x8005BC08; // type:func +func_8005BD24_jp = 0x8005BD24; // type:func +func_8005BDAC_jp = 0x8005BDAC; // type:func +func_8005BE34_jp = 0x8005BE34; // type:func +func_8005BEBC_jp = 0x8005BEBC; // type:func +func_8005BF40_jp = 0x8005BF40; // type:func +func_8005C07C_jp = 0x8005C07C; // type:func +func_8005C1B8_jp = 0x8005C1B8; // type:func +func_8005C228_jp = 0x8005C228; // type:func +func_8005C298_jp = 0x8005C298; // type:func +func_8005C2E4_jp = 0x8005C2E4; // type:func +func_8005C3E4_jp = 0x8005C3E4; // type:func +func_8005C444_jp = 0x8005C444; // type:func +func_8005C4F0_jp = 0x8005C4F0; // type:func +func_8005C550_jp = 0x8005C550; // type:func +func_8005C6E4_jp = 0x8005C6E4; // type:func +func_8005C778_jp = 0x8005C778; // type:func +func_8005C7B8_jp = 0x8005C7B8; // type:func +func_8005C828_jp = 0x8005C828; // type:func +func_8005C83C_jp = 0x8005C83C; // type:func +func_8005C888_jp = 0x8005C888; // type:func +func_8005C8D4_jp = 0x8005C8D4; // type:func +func_8005C918_jp = 0x8005C918; // type:func +func_8005C9BC_jp = 0x8005C9BC; // type:func +func_8005C9D0_jp = 0x8005C9D0; // type:func +func_8005C9E4_jp = 0x8005C9E4; // type:func +func_8005CA14_jp = 0x8005CA14; // type:func +func_8005CA44_jp = 0x8005CA44; // type:func +func_8005CC0C_jp = 0x8005CC0C; // type:func +func_8005CC90_jp = 0x8005CC90; // type:func +func_8005CD70_jp = 0x8005CD70; // type:func +func_8005CE34_jp = 0x8005CE34; // type:func +func_8005CEC0_jp = 0x8005CEC0; // type:func +func_8005CF04_jp = 0x8005CF04; // type:func +func_8005CF4C_jp = 0x8005CF4C; // type:func +func_8005D000_jp = 0x8005D000; // type:func +func_8005D084_jp = 0x8005D084; // type:func +func_8005D13C_jp = 0x8005D13C; // type:func +func_8005D19C_jp = 0x8005D19C; // type:func +func_8005D1B8_jp = 0x8005D1B8; // type:func +func_8005D1F4_jp = 0x8005D1F4; // type:func +func_8005D2A4_jp = 0x8005D2A4; // type:func +func_8005D338_jp = 0x8005D338; // type:func +func_8005D3C0_jp = 0x8005D3C0; // type:func +func_8005D4B0_jp = 0x8005D4B0; // type:func +func_8005D758_jp = 0x8005D758; // type:func +func_8005D7A0_jp = 0x8005D7A0; // type:func +func_8005D810_jp = 0x8005D810; // type:func +func_8005D84C_jp = 0x8005D84C; // type:func +func_8005D8E0_jp = 0x8005D8E0; // type:func +func_8005D91C_jp = 0x8005D91C; // type:func +func_8005D958_jp = 0x8005D958; // type:func +func_8005D9AC_jp = 0x8005D9AC; // type:func +func_8005DA00_jp = 0x8005DA00; // type:func +func_8005DAF0_jp = 0x8005DAF0; // type:func +func_8005DBA4_jp = 0x8005DBA4; // type:func +func_8005DC40_jp = 0x8005DC40; // type:func +func_8005DC9C_jp = 0x8005DC9C; // type:func +func_8005DCCC_jp = 0x8005DCCC; // type:func +func_8005DD2C_jp = 0x8005DD2C; // type:func +func_8005DD5C_jp = 0x8005DD5C; // type:func +func_8005DDE4_jp = 0x8005DDE4; // type:func +func_8005DE0C_jp = 0x8005DE0C; // type:func +func_8005DE60_jp = 0x8005DE60; // type:func +func_8005DE88_jp = 0x8005DE88; // type:func +func_8005DEE0_jp = 0x8005DEE0; // type:func +func_8005DF14_jp = 0x8005DF14; // type:func +func_8005DF70_jp = 0x8005DF70; // type:func +func_8005DFA0_jp = 0x8005DFA0; // type:func +func_8005DFFC_jp = 0x8005DFFC; // type:func +func_8005E02C_jp = 0x8005E02C; // type:func +func_8005E080_jp = 0x8005E080; // type:func +func_8005E0DC_jp = 0x8005E0DC; // type:func +func_8005E10C_jp = 0x8005E10C; // type:func +func_8005E15C_jp = 0x8005E15C; // type:func +func_8005E1B0_jp = 0x8005E1B0; // type:func +func_8005E1D8_jp = 0x8005E1D8; // type:func +func_8005E22C_jp = 0x8005E22C; // type:func +func_8005E254_jp = 0x8005E254; // type:func +func_8005E2B4_jp = 0x8005E2B4; // type:func +func_8005E2EC_jp = 0x8005E2EC; // type:func +func_8005E390_jp = 0x8005E390; // type:func +func_8005E3EC_jp = 0x8005E3EC; // type:func +func_8005E458_jp = 0x8005E458; // type:func +func_8005E494_jp = 0x8005E494; // type:func +func_8005E4C4_jp = 0x8005E4C4; // type:func +func_8005E4F8_jp = 0x8005E4F8; // type:func +func_8005E530_jp = 0x8005E530; // type:func +func_8005E550_jp = 0x8005E550; // type:func +func_8005E58C_jp = 0x8005E58C; // type:func +func_8005E5BC_jp = 0x8005E5BC; // type:func +func_8005E5F8_jp = 0x8005E5F8; // type:func +func_8005E628_jp = 0x8005E628; // type:func +func_8005E660_jp = 0x8005E660; // type:func +func_8005E69C_jp = 0x8005E69C; // type:func +func_8005E6CC_jp = 0x8005E6CC; // type:func +func_8005E700_jp = 0x8005E700; // type:func +func_8005E738_jp = 0x8005E738; // type:func +func_8005E758_jp = 0x8005E758; // type:func +func_8005E794_jp = 0x8005E794; // type:func +func_8005E7C4_jp = 0x8005E7C4; // type:func +func_8005E800_jp = 0x8005E800; // type:func +func_8005E83C_jp = 0x8005E83C; // type:func +func_8005E8F4_jp = 0x8005E8F4; // type:func +func_8005E9B4_jp = 0x8005E9B4; // type:func +func_8005E9C8_jp = 0x8005E9C8; // type:func +func_8005E9DC_jp = 0x8005E9DC; // type:func +func_8005E9F0_jp = 0x8005E9F0; // type:func +func_8005EA14_jp = 0x8005EA14; // type:func +func_8005EA24_jp = 0x8005EA24; // type:func +func_8005EA38_jp = 0x8005EA38; // type:func +func_8005EA4C_jp = 0x8005EA4C; // type:func +func_8005EAA0_jp = 0x8005EAA0; // type:func +func_8005EAC8_jp = 0x8005EAC8; // type:func +func_8005EAE4_jp = 0x8005EAE4; // type:func +func_8005EAFC_jp = 0x8005EAFC; // type:func +func_8005EB74_jp = 0x8005EB74; // type:func +func_8005EBD8_jp = 0x8005EBD8; // type:func +func_8005EBE8_jp = 0x8005EBE8; // type:func +func_8005ECC4_jp = 0x8005ECC4; // type:func +func_8005ECF8_jp = 0x8005ECF8; // type:func +func_8005ED24_jp = 0x8005ED24; // type:func +func_8005ED44_jp = 0x8005ED44; // type:func +func_8005ED78_jp = 0x8005ED78; // type:func +func_8005ED98_jp = 0x8005ED98; // type:func +func_8005EDC4_jp = 0x8005EDC4; // type:func +func_8005EDD8_jp = 0x8005EDD8; // type:func +func_8005EDEC_jp = 0x8005EDEC; // type:func +func_8005EE00_jp = 0x8005EE00; // type:func +func_8005EE20_jp = 0x8005EE20; // type:func +func_8005EEA0_jp = 0x8005EEA0; // type:func +func_8005EEE8_jp = 0x8005EEE8; // type:func +func_8005EF9C_jp = 0x8005EF9C; // type:func +func_8005F020_jp = 0x8005F020; // type:func +func_8005F13C_jp = 0x8005F13C; // type:func +func_8005F250_jp = 0x8005F250; // type:func +func_8005F390_jp = 0x8005F390; // type:func +func_8005F3DC_jp = 0x8005F3DC; // type:func +func_8005F4E4_jp = 0x8005F4E4; // type:func +func_8005F528_jp = 0x8005F528; // type:func +func_8005F590_jp = 0x8005F590; // type:func +func_8005F5C8_jp = 0x8005F5C8; // type:func +func_8005F67C_jp = 0x8005F67C; // type:func +func_8005F6E0_jp = 0x8005F6E0; // type:func +func_8005F704_jp = 0x8005F704; // type:func +func_8005F814_jp = 0x8005F814; // type:func +func_8005F934_jp = 0x8005F934; // type:func +func_8005F9B4_jp = 0x8005F9B4; // type:func +func_8005FB18_jp = 0x8005FB18; // type:func +func_8005FB98_jp = 0x8005FB98; // type:func +func_8005FD10_jp = 0x8005FD10; // type:func +func_8005FD48_jp = 0x8005FD48; // type:func +func_8005FDA0_jp = 0x8005FDA0; // type:func +func_8005FE9C_jp = 0x8005FE9C; // type:func +func_8005FF04_jp = 0x8005FF04; // type:func +func_8005FF3C_jp = 0x8005FF3C; // type:func +func_8005FFCC_jp = 0x8005FFCC; // type:func +func_80060154_jp = 0x80060154; // type:func +func_80060214_jp = 0x80060214; // type:func +func_800603B4_jp = 0x800603B4; // type:func +func_8006052C_jp = 0x8006052C; // type:func +func_80060548_jp = 0x80060548; // type:func +func_80060554_jp = 0x80060554; // type:func +func_80060564_jp = 0x80060564; // type:func +func_80060574_jp = 0x80060574; // type:func +func_8006058C_jp = 0x8006058C; // type:func +func_800608C8_jp = 0x800608C8; // type:func +func_800608DC_jp = 0x800608DC; // type:func +func_800608F0_jp = 0x800608F0; // type:func +func_80060904_jp = 0x80060904; // type:func +func_80060918_jp = 0x80060918; // type:func +func_80060970_jp = 0x80060970; // type:func +func_80060A6C_jp = 0x80060A6C; // type:func +func_80060B18_jp = 0x80060B18; // type:func +func_80060CDC_jp = 0x80060CDC; // type:func +func_80060D1C_jp = 0x80060D1C; // type:func +func_80060D58_jp = 0x80060D58; // type:func +func_80060D6C_jp = 0x80060D6C; // type:func +func_80060D78_jp = 0x80060D78; // type:func +func_80060DA8_jp = 0x80060DA8; // type:func +func_80060FDC_jp = 0x80060FDC; // type:func +func_80060FE8_jp = 0x80060FE8; // type:func +func_80060FF4_jp = 0x80060FF4; // type:func +func_80061000_jp = 0x80061000; // type:func +func_8006100C_jp = 0x8006100C; // type:func +func_8006109C_jp = 0x8006109C; // type:func +func_80061104_jp = 0x80061104; // type:func +func_80061134_jp = 0x80061134; // type:func +func_80061188_jp = 0x80061188; // type:func +func_800611D4_jp = 0x800611D4; // type:func +func_80061280_jp = 0x80061280; // type:func +func_8006136C_jp = 0x8006136C; // type:func +func_800613DC_jp = 0x800613DC; // type:func +func_800614E8_jp = 0x800614E8; // type:func +func_800615D4_jp = 0x800615D4; // type:func +func_800616C0_jp = 0x800616C0; // type:func +func_800617F8_jp = 0x800617F8; // type:func +func_800618E4_jp = 0x800618E4; // type:func +func_800619FC_jp = 0x800619FC; // type:func +func_80061A80_jp = 0x80061A80; // type:func +func_80061B04_jp = 0x80061B04; // type:func +func_80061C2C_jp = 0x80061C2C; // type:func +func_80061DB0_jp = 0x80061DB0; // type:func +func_80061E9C_jp = 0x80061E9C; // type:func +func_80061EC4_jp = 0x80061EC4; // type:func +func_80062000_jp = 0x80062000; // type:func +func_80062054_jp = 0x80062054; // type:func +func_80062098_jp = 0x80062098; // type:func +func_80062388_jp = 0x80062388; // type:func +func_80062410_jp = 0x80062410; // type:func +func_8006244C_jp = 0x8006244C; // type:func +func_80062510_jp = 0x80062510; // type:func +func_80062644_jp = 0x80062644; // type:func +func_80062668_jp = 0x80062668; // type:func +func_80062690_jp = 0x80062690; // type:func +func_800626E4_jp = 0x800626E4; // type:func +func_80062760_jp = 0x80062760; // type:func +func_800627A0_jp = 0x800627A0; // type:func +func_80062888_jp = 0x80062888; // type:func +func_800628F0_jp = 0x800628F0; // type:func +func_8006295C_jp = 0x8006295C; // type:func +func_80062B24_jp = 0x80062B24; // type:func +func_80062B74_jp = 0x80062B74; // type:func +func_80062BA0_jp = 0x80062BA0; // type:func +func_80062C84_jp = 0x80062C84; // type:func +func_80062CD8_jp = 0x80062CD8; // type:func +func_80062DD8_jp = 0x80062DD8; // type:func +func_80062E00_jp = 0x80062E00; // type:func +func_80062E20_jp = 0x80062E20; // type:func +func_80062E74_jp = 0x80062E74; // type:func +func_80062EA8_jp = 0x80062EA8; // type:func +func_80062F50_jp = 0x80062F50; // type:func +func_80062FAC_jp = 0x80062FAC; // type:func +func_80063018_jp = 0x80063018; // type:func +func_800630D8_jp = 0x800630D8; // type:func +func_80063144_jp = 0x80063144; // type:func +func_80063170_jp = 0x80063170; // type:func +func_800631C0_jp = 0x800631C0; // type:func +func_800631EC_jp = 0x800631EC; // type:func +func_8006328C_jp = 0x8006328C; // type:func +func_800632C8_jp = 0x800632C8; // type:func +func_8006333C_jp = 0x8006333C; // type:func +func_8006339C_jp = 0x8006339C; // type:func +func_80063468_jp = 0x80063468; // type:func +func_8006358C_jp = 0x8006358C; // type:func +func_800635B8_jp = 0x800635B8; // type:func +func_80063608_jp = 0x80063608; // type:func +func_80063628_jp = 0x80063628; // type:func +func_80063674_jp = 0x80063674; // type:func +func_8006370C_jp = 0x8006370C; // type:func +func_800637C8_jp = 0x800637C8; // type:func +func_8006393C_jp = 0x8006393C; // type:func +func_800639A0_jp = 0x800639A0; // type:func +func_80063A34_jp = 0x80063A34; // type:func +func_80063AA0_jp = 0x80063AA0; // type:func +func_80063B1C_jp = 0x80063B1C; // type:func +func_80063B8C_jp = 0x80063B8C; // type:func +func_80063CA0_jp = 0x80063CA0; // type:func +func_80063D10_jp = 0x80063D10; // type:func +func_80063D38_jp = 0x80063D38; // type:func +func_80063D9C_jp = 0x80063D9C; // type:func +func_80063E14_jp = 0x80063E14; // type:func +func_80063E94_jp = 0x80063E94; // type:func +func_80063EF0_jp = 0x80063EF0; // type:func +func_80063F9C_jp = 0x80063F9C; // type:func +func_80064028_jp = 0x80064028; // type:func +func_800640FC_jp = 0x800640FC; // type:func +func_80064124_jp = 0x80064124; // type:func +func_80064178_jp = 0x80064178; // type:func +func_800641CC_jp = 0x800641CC; // type:func +func_800641F8_jp = 0x800641F8; // type:func +func_800642D8_jp = 0x800642D8; // type:func +func_800643D4_jp = 0x800643D4; // type:func +func_80064444_jp = 0x80064444; // type:func +func_8006447C_jp = 0x8006447C; // type:func +func_800644FC_jp = 0x800644FC; // type:func +func_800645B0_jp = 0x800645B0; // type:func +func_800645EC_jp = 0x800645EC; // type:func +func_8006464C_jp = 0x8006464C; // type:func +func_800646FC_jp = 0x800646FC; // type:func +func_800649BC_jp = 0x800649BC; // type:func +func_80064B20_jp = 0x80064B20; // type:func +func_80064EA0_jp = 0x80064EA0; // type:func +func_80064EDC_jp = 0x80064EDC; // type:func +func_80064EF0_jp = 0x80064EF0; // type:func +func_80064F08_jp = 0x80064F08; // type:func +func_80064F28_jp = 0x80064F28; // type:func +func_80064F48_jp = 0x80064F48; // type:func +func_80064F84_jp = 0x80064F84; // type:func +func_80064FD8_jp = 0x80064FD8; // type:func +func_80065028_jp = 0x80065028; // type:func +func_80065040_jp = 0x80065040; // type:func +func_80065064_jp = 0x80065064; // type:func +func_80065158_jp = 0x80065158; // type:func +func_80065164_jp = 0x80065164; // type:func +func_80065170_jp = 0x80065170; // type:func +func_80065198_jp = 0x80065198; // type:func +func_800651A4_jp = 0x800651A4; // type:func +func_80065278_jp = 0x80065278; // type:func +func_80065348_jp = 0x80065348; // type:func +func_800653CC_jp = 0x800653CC; // type:func +func_800653DC_jp = 0x800653DC; // type:func +func_800654FC_jp = 0x800654FC; // type:func +func_80065508_jp = 0x80065508; // type:func +func_80065518_jp = 0x80065518; // type:func +func_80065528_jp = 0x80065528; // type:func +func_80065668_jp = 0x80065668; // type:func +func_8006568C_jp = 0x8006568C; // type:func +func_800656C8_jp = 0x800656C8; // type:func +func_80065704_jp = 0x80065704; // type:func +func_80065728_jp = 0x80065728; // type:func +func_8006574C_jp = 0x8006574C; // type:func +func_80065770_jp = 0x80065770; // type:func +func_80065794_jp = 0x80065794; // type:func +func_800657B8_jp = 0x800657B8; // type:func +func_800657DC_jp = 0x800657DC; // type:func +func_80065800_jp = 0x80065800; // type:func +func_8006584C_jp = 0x8006584C; // type:func +func_8006586C_jp = 0x8006586C; // type:func +func_80065890_jp = 0x80065890; // type:func +func_800658B4_jp = 0x800658B4; // type:func +func_800658D8_jp = 0x800658D8; // type:func +func_800658FC_jp = 0x800658FC; // type:func +func_80065920_jp = 0x80065920; // type:func +func_80065944_jp = 0x80065944; // type:func +func_80065968_jp = 0x80065968; // type:func +func_8006598C_jp = 0x8006598C; // type:func +func_800659B0_jp = 0x800659B0; // type:func +func_800659D4_jp = 0x800659D4; // type:func +func_800659F8_jp = 0x800659F8; // type:func +func_80065A1C_jp = 0x80065A1C; // type:func +func_80065A40_jp = 0x80065A40; // type:func +func_80065A64_jp = 0x80065A64; // type:func +func_80065A88_jp = 0x80065A88; // type:func +func_80065AAC_jp = 0x80065AAC; // type:func +func_80065AD0_jp = 0x80065AD0; // type:func +func_80065AF4_jp = 0x80065AF4; // type:func +func_80065B18_jp = 0x80065B18; // type:func +func_80065B5C_jp = 0x80065B5C; // type:func +func_80065B80_jp = 0x80065B80; // type:func +func_80065BA4_jp = 0x80065BA4; // type:func +func_80065BF0_jp = 0x80065BF0; // type:func +func_80065C10_jp = 0x80065C10; // type:func +func_80065C34_jp = 0x80065C34; // type:func +func_80065C58_jp = 0x80065C58; // type:func +func_80065C7C_jp = 0x80065C7C; // type:func +func_80065CA0_jp = 0x80065CA0; // type:func +func_80065CF8_jp = 0x80065CF8; // type:func +func_80065D90_jp = 0x80065D90; // type:func +func_80065EE8_jp = 0x80065EE8; // type:func +func_80065EF8_jp = 0x80065EF8; // type:func +func_80065F18_jp = 0x80065F18; // type:func +func_80065F38_jp = 0x80065F38; // type:func +func_80065F58_jp = 0x80065F58; // type:func +func_80065F78_jp = 0x80065F78; // type:func +func_80065F98_jp = 0x80065F98; // type:func +func_80066068_jp = 0x80066068; // type:func +func_80066094_jp = 0x80066094; // type:func +func_800660DC_jp = 0x800660DC; // type:func +func_80066130_jp = 0x80066130; // type:func +func_80066194_jp = 0x80066194; // type:func +func_800665C0_jp = 0x800665C0; // type:func +func_800665EC_jp = 0x800665EC; // type:func +func_80066634_jp = 0x80066634; // type:func +func_8006666C_jp = 0x8006666C; // type:func +func_80066740_jp = 0x80066740; // type:func +func_8006676C_jp = 0x8006676C; // type:func +func_800667B4_jp = 0x800667B4; // type:func +func_8006680C_jp = 0x8006680C; // type:func +func_8006685C_jp = 0x8006685C; // type:func +func_800668A4_jp = 0x800668A4; // type:func +func_800669A4_jp = 0x800669A4; // type:func +func_80066A60_jp = 0x80066A60; // type:func +func_80066A80_jp = 0x80066A80; // type:func +func_80066B18_jp = 0x80066B18; // type:func +func_80066BB0_jp = 0x80066BB0; // type:func +func_80066D4C_jp = 0x80066D4C; // type:func +func_80066DFC_jp = 0x80066DFC; // type:func +func_80066E34_jp = 0x80066E34; // type:func +func_80066E50_jp = 0x80066E50; // type:func +func_80066E90_jp = 0x80066E90; // type:func +func_80066EB8_jp = 0x80066EB8; // type:func +func_80066F1C_jp = 0x80066F1C; // type:func +func_80066F4C_jp = 0x80066F4C; // type:func +func_80066F8C_jp = 0x80066F8C; // type:func +func_8006700C_jp = 0x8006700C; // type:func +func_800670C0_jp = 0x800670C0; // type:func +func_80067190_jp = 0x80067190; // type:func +func_80067264_jp = 0x80067264; // type:func +func_80067338_jp = 0x80067338; // type:func +func_800673BC_jp = 0x800673BC; // type:func +func_800673CC_jp = 0x800673CC; // type:func +func_80067414_jp = 0x80067414; // type:func +func_80067430_jp = 0x80067430; // type:func +func_800674B0_jp = 0x800674B0; // type:func +func_800674D8_jp = 0x800674D8; // type:func +func_8006755C_jp = 0x8006755C; // type:func +func_800675E0_jp = 0x800675E0; // type:func +func_80067664_jp = 0x80067664; // type:func +func_800678AC_jp = 0x800678AC; // type:func +func_80067954_jp = 0x80067954; // type:func +func_80067B48_jp = 0x80067B48; // type:func +func_80067B70_jp = 0x80067B70; // type:func +func_80067CE8_jp = 0x80067CE8; // type:func +func_80067D98_jp = 0x80067D98; // type:func +func_80067EB0_jp = 0x80067EB0; // type:func +func_80067F50_jp = 0x80067F50; // type:func +func_8006800C_jp = 0x8006800C; // type:func +func_8006806C_jp = 0x8006806C; // type:func +func_8006811C_jp = 0x8006811C; // type:func +func_8006818C_jp = 0x8006818C; // type:func +func_800682F4_jp = 0x800682F4; // type:func +func_800683F4_jp = 0x800683F4; // type:func +func_8006844C_jp = 0x8006844C; // type:func +func_8006847C_jp = 0x8006847C; // type:func +func_800684C8_jp = 0x800684C8; // type:func +func_8006851C_jp = 0x8006851C; // type:func +func_80068570_jp = 0x80068570; // type:func +func_800685D4_jp = 0x800685D4; // type:func +func_80068648_jp = 0x80068648; // type:func +func_800686C4_jp = 0x800686C4; // type:func +func_80068730_jp = 0x80068730; // type:func +func_8006874C_jp = 0x8006874C; // type:func +func_80068768_jp = 0x80068768; // type:func +func_800687B8_jp = 0x800687B8; // type:func +func_80068808_jp = 0x80068808; // type:func +func_800688B4_jp = 0x800688B4; // type:func +func_800688D0_jp = 0x800688D0; // type:func +func_800688FC_jp = 0x800688FC; // type:func +func_80068934_jp = 0x80068934; // type:func +func_800689A4_jp = 0x800689A4; // type:func +func_800689C8_jp = 0x800689C8; // type:func +func_800689E4_jp = 0x800689E4; // type:func +func_80068A50_jp = 0x80068A50; // type:func +func_80068BB8_jp = 0x80068BB8; // type:func +func_80068C88_jp = 0x80068C88; // type:func +func_80068D10_jp = 0x80068D10; // type:func +func_80068F5C_jp = 0x80068F5C; // type:func +func_80069280_jp = 0x80069280; // type:func +func_80069354_jp = 0x80069354; // type:func +func_800694DC_jp = 0x800694DC; // type:func +func_80069558_jp = 0x80069558; // type:func +func_80069580_jp = 0x80069580; // type:func +func_80069680_jp = 0x80069680; // type:func +func_8006969C_jp = 0x8006969C; // type:func +func_80069750_jp = 0x80069750; // type:func +func_80069778_jp = 0x80069778; // type:func +func_800698C0_jp = 0x800698C0; // type:func +func_80069948_jp = 0x80069948; // type:func +func_800699D8_jp = 0x800699D8; // type:func +func_80069C00_jp = 0x80069C00; // type:func +func_80069C4C_jp = 0x80069C4C; // type:func +func_80069EF4_jp = 0x80069EF4; // type:func +func_80069F20_jp = 0x80069F20; // type:func +func_8006A13C_jp = 0x8006A13C; // type:func +func_8006A174_jp = 0x8006A174; // type:func +func_8006A490_jp = 0x8006A490; // type:func +func_8006A6FC_jp = 0x8006A6FC; // type:func +func_8006A760_jp = 0x8006A760; // type:func +func_8006A7B4_jp = 0x8006A7B4; // type:func +func_8006AA94_jp = 0x8006AA94; // type:func +func_8006AAAC_jp = 0x8006AAAC; // type:func +func_8006AB50_jp = 0x8006AB50; // type:func +func_8006AB9C_jp = 0x8006AB9C; // type:func +func_8006ABFC_jp = 0x8006ABFC; // type:func +func_8006AC74_jp = 0x8006AC74; // type:func +func_8006ACF4_jp = 0x8006ACF4; // type:func +func_8006AD0C_jp = 0x8006AD0C; // type:func +func_8006AD58_jp = 0x8006AD58; // type:func +func_8006ADA8_jp = 0x8006ADA8; // type:func +func_8006AF00_jp = 0x8006AF00; // type:func +func_8006AF14_jp = 0x8006AF14; // type:func +func_8006AF54_jp = 0x8006AF54; // type:func +func_8006B1A8_jp = 0x8006B1A8; // type:func +func_8006B39C_jp = 0x8006B39C; // type:func +func_8006B5C0_jp = 0x8006B5C0; // type:func +func_8006B664_jp = 0x8006B664; // type:func +func_8006B92C_jp = 0x8006B92C; // type:func +func_8006B97C_jp = 0x8006B97C; // type:func +func_8006BAA8_jp = 0x8006BAA8; // type:func +func_8006BAE4_jp = 0x8006BAE4; // type:func +func_8006BB64_jp = 0x8006BB64; // type:func +func_8006BB9C_jp = 0x8006BB9C; // type:func +func_8006BBE8_jp = 0x8006BBE8; // type:func +func_8006BBF8_jp = 0x8006BBF8; // type:func +func_8006BC20_jp = 0x8006BC20; // type:func +func_8006BC54_jp = 0x8006BC54; // type:func +func_8006BCB8_jp = 0x8006BCB8; // type:func +func_8006BD00_jp = 0x8006BD00; // type:func +func_8006BE78_jp = 0x8006BE78; // type:func +func_8006BF0C_jp = 0x8006BF0C; // type:func +func_8006C4B4_jp = 0x8006C4B4; // type:func +func_8006C5A8_jp = 0x8006C5A8; // type:func +func_8006C634_jp = 0x8006C634; // type:func +func_8006C740_jp = 0x8006C740; // type:func +func_8006C7B4_jp = 0x8006C7B4; // type:func +func_8006C8D0_jp = 0x8006C8D0; // type:func +func_8006C910_jp = 0x8006C910; // type:func +func_8006C980_jp = 0x8006C980; // type:func +func_8006D3B0_jp = 0x8006D3B0; // type:func +func_8006D478_jp = 0x8006D478; // type:func +func_8006D65C_jp = 0x8006D65C; // type:func +func_8006D7F4_jp = 0x8006D7F4; // type:func +func_8006D80C_jp = 0x8006D80C; // type:func +func_8006D854_jp = 0x8006D854; // type:func +func_8006D9C0_jp = 0x8006D9C0; // type:func +func_8006DA1C_jp = 0x8006DA1C; // type:func +func_8006DE00_jp = 0x8006DE00; // type:func +func_8006DF40_jp = 0x8006DF40; // type:func +func_8006DF9C_jp = 0x8006DF9C; // type:func +func_8006DFE4_jp = 0x8006DFE4; // type:func +func_8006E0AC_jp = 0x8006E0AC; // type:func +func_8006E2DC_jp = 0x8006E2DC; // type:func +func_8006E30C_jp = 0x8006E30C; // type:func +func_8006E374_jp = 0x8006E374; // type:func +func_8006E4B4_jp = 0x8006E4B4; // type:func +func_8006E548_jp = 0x8006E548; // type:func +func_8006E7A4_jp = 0x8006E7A4; // type:func +func_8006E8CC_jp = 0x8006E8CC; // type:func +func_8006E900_jp = 0x8006E900; // type:func +func_8006EA38_jp = 0x8006EA38; // type:func +func_8006EAE8_jp = 0x8006EAE8; // type:func +func_8006EBA0_jp = 0x8006EBA0; // type:func +func_8006EDC0_jp = 0x8006EDC0; // type:func +func_8006EE70_jp = 0x8006EE70; // type:func +func_8006EFB4_jp = 0x8006EFB4; // type:func +func_8006F250_jp = 0x8006F250; // type:func +func_8006F36C_jp = 0x8006F36C; // type:func +func_8006F540_jp = 0x8006F540; // type:func +func_8006F62C_jp = 0x8006F62C; // type:func +func_8006F928_jp = 0x8006F928; // type:func +func_8006FE98_jp = 0x8006FE98; // type:func +func_80070290_jp = 0x80070290; // type:func +func_80070590_jp = 0x80070590; // type:func +func_8007071C_jp = 0x8007071C; // type:func +func_8007073C_jp = 0x8007073C; // type:func +func_8007075C_jp = 0x8007075C; // type:func +func_80070880_jp = 0x80070880; // type:func +func_80070950_jp = 0x80070950; // type:func +func_80070990_jp = 0x80070990; // type:func +func_800709A8_jp = 0x800709A8; // type:func +func_800709E8_jp = 0x800709E8; // type:func +func_80070A28_jp = 0x80070A28; // type:func +func_80070AE4_jp = 0x80070AE4; // type:func +func_80070C68_jp = 0x80070C68; // type:func +func_80070D28_jp = 0x80070D28; // type:func +func_80070F5C_jp = 0x80070F5C; // type:func +func_80070FBC_jp = 0x80070FBC; // type:func +func_80071064_jp = 0x80071064; // type:func +func_800713CC_jp = 0x800713CC; // type:func +func_80071460_jp = 0x80071460; // type:func +func_80071490_jp = 0x80071490; // type:func +func_800715B4_jp = 0x800715B4; // type:func +func_80071604_jp = 0x80071604; // type:func +func_80071728_jp = 0x80071728; // type:func +func_8007175C_jp = 0x8007175C; // type:func +func_80071884_jp = 0x80071884; // type:func +func_80071A08_jp = 0x80071A08; // type:func +func_80071AB8_jp = 0x80071AB8; // type:func +func_80071B78_jp = 0x80071B78; // type:func +func_80071C1C_jp = 0x80071C1C; // type:func +func_80071DB4_jp = 0x80071DB4; // type:func +func_800721C8_jp = 0x800721C8; // type:func +func_800721E4_jp = 0x800721E4; // type:func +func_80072238_jp = 0x80072238; // type:func +func_80072264_jp = 0x80072264; // type:func +func_80072340_jp = 0x80072340; // type:func +func_80072398_jp = 0x80072398; // type:func +func_800723C4_jp = 0x800723C4; // type:func +func_80072418_jp = 0x80072418; // type:func +func_8007244C_jp = 0x8007244C; // type:func +func_8007246C_jp = 0x8007246C; // type:func +func_8007249C_jp = 0x8007249C; // type:func +func_80072530_jp = 0x80072530; // type:func +func_800725C4_jp = 0x800725C4; // type:func +func_80072610_jp = 0x80072610; // type:func +func_800727D8_jp = 0x800727D8; // type:func +func_80072828_jp = 0x80072828; // type:func +func_80072880_jp = 0x80072880; // type:func +func_800728B4_jp = 0x800728B4; // type:func +func_800728F4_jp = 0x800728F4; // type:func +func_80072938_jp = 0x80072938; // type:func +func_80072990_jp = 0x80072990; // type:func +func_80072B24_jp = 0x80072B24; // type:func +func_80072BE8_jp = 0x80072BE8; // type:func +func_80072C60_jp = 0x80072C60; // type:func +func_80072CC4_jp = 0x80072CC4; // type:func +func_80072E70_jp = 0x80072E70; // type:func +func_80072F9C_jp = 0x80072F9C; // type:func +func_800730C8_jp = 0x800730C8; // type:func +func_800731A8_jp = 0x800731A8; // type:func +func_800732DC_jp = 0x800732DC; // type:func +func_800734BC_jp = 0x800734BC; // type:func +func_8007352C_jp = 0x8007352C; // type:func +func_80073680_jp = 0x80073680; // type:func +func_80073718_jp = 0x80073718; // type:func +func_80073784_jp = 0x80073784; // type:func +func_800737D4_jp = 0x800737D4; // type:func +func_80073800_jp = 0x80073800; // type:func +func_800738A4_jp = 0x800738A4; // type:func +func_80073970_jp = 0x80073970; // type:func +func_800739FC_jp = 0x800739FC; // type:func +func_80073C38_jp = 0x80073C38; // type:func +func_80073CC0_jp = 0x80073CC0; // type:func +func_80073D80_jp = 0x80073D80; // type:func +func_80074090_jp = 0x80074090; // type:func +func_80074174_jp = 0x80074174; // type:func +func_800741DC_jp = 0x800741DC; // type:func +func_800741F4_jp = 0x800741F4; // type:func +func_80074208_jp = 0x80074208; // type:func +func_800743EC_jp = 0x800743EC; // type:func +func_80074648_jp = 0x80074648; // type:func +func_80074690_jp = 0x80074690; // type:func +func_80074860_jp = 0x80074860; // type:func +func_800749D0_jp = 0x800749D0; // type:func +func_800749F8_jp = 0x800749F8; // type:func +func_80074AA8_jp = 0x80074AA8; // type:func +func_80074BA0_jp = 0x80074BA0; // type:func +func_80074D88_jp = 0x80074D88; // type:func +func_80074EEC_jp = 0x80074EEC; // type:func +func_8007532C_jp = 0x8007532C; // type:func +func_800753B8_jp = 0x800753B8; // type:func +func_8007584C_jp = 0x8007584C; // type:func +func_80075954_jp = 0x80075954; // type:func +func_80075A10_jp = 0x80075A10; // type:func +func_80075AB4_jp = 0x80075AB4; // type:func +func_80075B28_jp = 0x80075B28; // type:func +func_80075EA0_jp = 0x80075EA0; // type:func +func_8007620C_jp = 0x8007620C; // type:func +func_80076248_jp = 0x80076248; // type:func +func_80076270_jp = 0x80076270; // type:func +func_80076280_jp = 0x80076280; // type:func +func_80076290_jp = 0x80076290; // type:func +func_80076358_jp = 0x80076358; // type:func +func_8007638C_jp = 0x8007638C; // type:func +func_800763F0_jp = 0x800763F0; // type:func +func_800763FC_jp = 0x800763FC; // type:func +func_8007648C_jp = 0x8007648C; // type:func +func_800764CC_jp = 0x800764CC; // type:func +func_800765AC_jp = 0x800765AC; // type:func +func_80076778_jp = 0x80076778; // type:func +func_800768C8_jp = 0x800768C8; // type:func +func_80076A04_jp = 0x80076A04; // type:func +func_80076B40_jp = 0x80076B40; // type:func +func_80076BA4_jp = 0x80076BA4; // type:func +func_80076BD4_jp = 0x80076BD4; // type:func +func_80076BE8_jp = 0x80076BE8; // type:func +func_80076C14_jp = 0x80076C14; // type:func +func_80076C3C_jp = 0x80076C3C; // type:func +func_80076C4C_jp = 0x80076C4C; // type:func +func_80076C60_jp = 0x80076C60; // type:func +func_80076C78_jp = 0x80076C78; // type:func +func_80076CC0_jp = 0x80076CC0; // type:func +func_80076CD4_jp = 0x80076CD4; // type:func +func_80076D2C_jp = 0x80076D2C; // type:func +func_80076D68_jp = 0x80076D68; // type:func +func_80076D90_jp = 0x80076D90; // type:func +func_80076DDC_jp = 0x80076DDC; // type:func +func_80076E00_jp = 0x80076E00; // type:func +func_80076E2C_jp = 0x80076E2C; // type:func +func_80076ED0_jp = 0x80076ED0; // type:func +func_80076F9C_jp = 0x80076F9C; // type:func +func_8007703C_jp = 0x8007703C; // type:func +func_80077078_jp = 0x80077078; // type:func +func_8007708C_jp = 0x8007708C; // type:func +func_800770CC_jp = 0x800770CC; // type:func +func_80077118_jp = 0x80077118; // type:func +func_80077158_jp = 0x80077158; // type:func +func_800771BC_jp = 0x800771BC; // type:func +func_800771FC_jp = 0x800771FC; // type:func +func_80077248_jp = 0x80077248; // type:func +func_8007725C_jp = 0x8007725C; // type:func +func_80077310_jp = 0x80077310; // type:func +func_8007734C_jp = 0x8007734C; // type:func +func_80077374_jp = 0x80077374; // type:func +func_800773C0_jp = 0x800773C0; // type:func +func_800773E4_jp = 0x800773E4; // type:func +func_80077410_jp = 0x80077410; // type:func +func_800774B4_jp = 0x800774B4; // type:func +func_80077580_jp = 0x80077580; // type:func +func_80077620_jp = 0x80077620; // type:func +func_80077640_jp = 0x80077640; // type:func +func_80077650_jp = 0x80077650; // type:func +func_800776B4_jp = 0x800776B4; // type:func +func_80077794_jp = 0x80077794; // type:func +func_800777D0_jp = 0x800777D0; // type:func +func_80077B6C_jp = 0x80077B6C; // type:func +func_80077D6C_jp = 0x80077D6C; // type:func +func_80077EF4_jp = 0x80077EF4; // type:func +func_80077F20_jp = 0x80077F20; // type:func +func_80077FF0_jp = 0x80077FF0; // type:func +func_80078014_jp = 0x80078014; // type:func +func_80078070_jp = 0x80078070; // type:func +func_80078214_jp = 0x80078214; // type:func +func_80078258_jp = 0x80078258; // type:func +func_8007841C_jp = 0x8007841C; // type:func +func_80078568_jp = 0x80078568; // type:func +func_8007858C_jp = 0x8007858C; // type:func +func_8007870C_jp = 0x8007870C; // type:func +func_8007872C_jp = 0x8007872C; // type:func +func_80078748_jp = 0x80078748; // type:func +func_800787E8_jp = 0x800787E8; // type:func +func_800788DC_jp = 0x800788DC; // type:func +func_8007891C_jp = 0x8007891C; // type:func +func_80078948_jp = 0x80078948; // type:func +func_80078978_jp = 0x80078978; // type:func +func_800789BC_jp = 0x800789BC; // type:func +func_80078A10_jp = 0x80078A10; // type:func +func_80078A88_jp = 0x80078A88; // type:func +func_80078AA8_jp = 0x80078AA8; // type:func +func_80078AD0_jp = 0x80078AD0; // type:func +func_80078ADC_jp = 0x80078ADC; // type:func +func_80078AE8_jp = 0x80078AE8; // type:func +func_80078CD8_jp = 0x80078CD8; // type:func +func_80078D30_jp = 0x80078D30; // type:func +func_80078D78_jp = 0x80078D78; // type:func +func_80078DAC_jp = 0x80078DAC; // type:func +func_80078DF4_jp = 0x80078DF4; // type:func +func_80078E28_jp = 0x80078E28; // type:func +func_80078E5C_jp = 0x80078E5C; // type:func +func_80078E90_jp = 0x80078E90; // type:func +func_80078EB4_jp = 0x80078EB4; // type:func +func_80078EE0_jp = 0x80078EE0; // type:func +func_80078F08_jp = 0x80078F08; // type:func +func_80078F34_jp = 0x80078F34; // type:func +func_80078FE8_jp = 0x80078FE8; // type:func +func_80079030_jp = 0x80079030; // type:func +func_80079080_jp = 0x80079080; // type:func +func_800790C0_jp = 0x800790C0; // type:func +func_8007919C_jp = 0x8007919C; // type:func +func_8007920C_jp = 0x8007920C; // type:func +func_800792FC_jp = 0x800792FC; // type:func +func_80079378_jp = 0x80079378; // type:func +func_800793A8_jp = 0x800793A8; // type:func +func_800793B8_jp = 0x800793B8; // type:func +func_8007942C_jp = 0x8007942C; // type:func +func_800794E4_jp = 0x800794E4; // type:func +func_8007967C_jp = 0x8007967C; // type:func +func_80079708_jp = 0x80079708; // type:func +func_80079760_jp = 0x80079760; // type:func +func_80079838_jp = 0x80079838; // type:func +func_800798DC_jp = 0x800798DC; // type:func +func_80079A24_jp = 0x80079A24; // type:func +func_80079AAC_jp = 0x80079AAC; // type:func +func_80079B28_jp = 0x80079B28; // type:func +func_80079BF8_jp = 0x80079BF8; // type:func +func_80079D00_jp = 0x80079D00; // type:func +func_80079D50_jp = 0x80079D50; // type:func +func_80079E14_jp = 0x80079E14; // type:func +func_80079E54_jp = 0x80079E54; // type:func +func_80079EA4_jp = 0x80079EA4; // type:func +func_80079EDC_jp = 0x80079EDC; // type:func +func_80079F44_jp = 0x80079F44; // type:func +func_8007A008_jp = 0x8007A008; // type:func +func_8007A070_jp = 0x8007A070; // type:func +func_8007A080_jp = 0x8007A080; // type:func +func_8007A0C0_jp = 0x8007A0C0; // type:func +func_8007A150_jp = 0x8007A150; // type:func +func_8007A160_jp = 0x8007A160; // type:func +func_8007A23C_jp = 0x8007A23C; // type:func +func_8007A2CC_jp = 0x8007A2CC; // type:func +func_8007A4B8_jp = 0x8007A4B8; // type:func +func_8007A620_jp = 0x8007A620; // type:func +func_8007A630_jp = 0x8007A630; // type:func +func_8007A68C_jp = 0x8007A68C; // type:func +func_8007A74C_jp = 0x8007A74C; // type:func +func_8007A824_jp = 0x8007A824; // type:func +func_8007A908_jp = 0x8007A908; // type:func +func_8007AC1C_jp = 0x8007AC1C; // type:func +func_8007ADF8_jp = 0x8007ADF8; // type:func +func_8007AED8_jp = 0x8007AED8; // type:func +func_8007B410_jp = 0x8007B410; // type:func +func_8007B44C_jp = 0x8007B44C; // type:func +func_8007B49C_jp = 0x8007B49C; // type:func +func_8007B4EC_jp = 0x8007B4EC; // type:func +func_8007B5C0_jp = 0x8007B5C0; // type:func +func_8007B5F4_jp = 0x8007B5F4; // type:func +func_8007B650_jp = 0x8007B650; // type:func +func_8007B670_jp = 0x8007B670; // type:func +func_8007B684_jp = 0x8007B684; // type:func +func_8007B6A4_jp = 0x8007B6A4; // type:func +func_8007B724_jp = 0x8007B724; // type:func +func_8007B760_jp = 0x8007B760; // type:func +func_8007B79C_jp = 0x8007B79C; // type:func +func_8007B7DC_jp = 0x8007B7DC; // type:func +func_8007B818_jp = 0x8007B818; // type:func +func_8007B854_jp = 0x8007B854; // type:func +func_8007B890_jp = 0x8007B890; // type:func +func_8007B8CC_jp = 0x8007B8CC; // type:func +func_8007B908_jp = 0x8007B908; // type:func +func_8007B944_jp = 0x8007B944; // type:func +func_8007B980_jp = 0x8007B980; // type:func +func_8007B9E0_jp = 0x8007B9E0; // type:func +func_8007BA1C_jp = 0x8007BA1C; // type:func +func_8007BA38_jp = 0x8007BA38; // type:func +func_8007BA4C_jp = 0x8007BA4C; // type:func +func_8007BA84_jp = 0x8007BA84; // type:func +func_8007BC28_jp = 0x8007BC28; // type:func +func_8007BCE4_jp = 0x8007BCE4; // type:func +func_8007BD9C_jp = 0x8007BD9C; // type:func +func_8007BE58_jp = 0x8007BE58; // type:func +func_8007C00C_jp = 0x8007C00C; // type:func +func_8007C0B4_jp = 0x8007C0B4; // type:func +func_8007C0C0_jp = 0x8007C0C0; // type:func +func_8007C104_jp = 0x8007C104; // type:func +func_8007C24C_jp = 0x8007C24C; // type:func +func_8007C290_jp = 0x8007C290; // type:func +func_8007C3D8_jp = 0x8007C3D8; // type:func +func_8007C484_jp = 0x8007C484; // type:func +func_8007C570_jp = 0x8007C570; // type:func +func_8007C5EC_jp = 0x8007C5EC; // type:func +func_8007C6C0_jp = 0x8007C6C0; // type:func +func_8007C808_jp = 0x8007C808; // type:func +func_8007C814_jp = 0x8007C814; // type:func +func_8007C820_jp = 0x8007C820; // type:func +func_8007C844_jp = 0x8007C844; // type:func +func_8007C868_jp = 0x8007C868; // type:func +func_8007C88C_jp = 0x8007C88C; // type:func +func_8007C8B0_jp = 0x8007C8B0; // type:func +func_8007C8D4_jp = 0x8007C8D4; // type:func +func_8007C8FC_jp = 0x8007C8FC; // type:func +func_8007C924_jp = 0x8007C924; // type:func +func_8007CB28_jp = 0x8007CB28; // type:func +func_8007CB50_jp = 0x8007CB50; // type:func +func_8007CBEC_jp = 0x8007CBEC; // type:func +func_8007CC9C_jp = 0x8007CC9C; // type:func +func_8007CDB8_jp = 0x8007CDB8; // type:func +func_8007CDD8_jp = 0x8007CDD8; // type:func +func_8007CF00_jp = 0x8007CF00; // type:func +func_8007CF34_jp = 0x8007CF34; // type:func +func_8007CF44_jp = 0x8007CF44; // type:func +func_8007CF84_jp = 0x8007CF84; // type:func +func_8007CFB4_jp = 0x8007CFB4; // type:func +func_8007CFD8_jp = 0x8007CFD8; // type:func +func_8007D030_jp = 0x8007D030; // type:func +func_8007D048_jp = 0x8007D048; // type:func +func_8007D080_jp = 0x8007D080; // type:func +func_8007D098_jp = 0x8007D098; // type:func +func_8007D0B0_jp = 0x8007D0B0; // type:func +func_8007D0C4_jp = 0x8007D0C4; // type:func +func_8007D0D8_jp = 0x8007D0D8; // type:func +func_8007D0EC_jp = 0x8007D0EC; // type:func +func_8007D100_jp = 0x8007D100; // type:func +func_8007D128_jp = 0x8007D128; // type:func +func_8007D140_jp = 0x8007D140; // type:func +func_8007D180_jp = 0x8007D180; // type:func +func_8007D1A8_jp = 0x8007D1A8; // type:func +func_8007D1DC_jp = 0x8007D1DC; // type:func +func_8007D25C_jp = 0x8007D25C; // type:func +func_8007D2B8_jp = 0x8007D2B8; // type:func +func_8007D318_jp = 0x8007D318; // type:func +func_8007D36C_jp = 0x8007D36C; // type:func +func_8007D3F0_jp = 0x8007D3F0; // type:func +func_8007D408_jp = 0x8007D408; // type:func +func_8007D418_jp = 0x8007D418; // type:func +func_8007D42C_jp = 0x8007D42C; // type:func +func_8007D43C_jp = 0x8007D43C; // type:func +func_8007D44C_jp = 0x8007D44C; // type:func +func_8007D460_jp = 0x8007D460; // type:func +func_8007D470_jp = 0x8007D470; // type:func +func_8007D490_jp = 0x8007D490; // type:func +func_8007D4A0_jp = 0x8007D4A0; // type:func +func_8007D4C4_jp = 0x8007D4C4; // type:func +func_8007D4D0_jp = 0x8007D4D0; // type:func +func_8007D4F4_jp = 0x8007D4F4; // type:func +func_8007D52C_jp = 0x8007D52C; // type:func +func_8007D554_jp = 0x8007D554; // type:func +func_8007D578_jp = 0x8007D578; // type:func +func_8007D58C_jp = 0x8007D58C; // type:func +func_8007D59C_jp = 0x8007D59C; // type:func +func_8007D5D4_jp = 0x8007D5D4; // type:func +func_8007D650_jp = 0x8007D650; // type:func +func_8007D6E0_jp = 0x8007D6E0; // type:func +func_8007D734_jp = 0x8007D734; // type:func +func_8007D784_jp = 0x8007D784; // type:func +func_8007D7BC_jp = 0x8007D7BC; // type:func +func_8007D810_jp = 0x8007D810; // type:func +func_8007D848_jp = 0x8007D848; // type:func +func_8007D880_jp = 0x8007D880; // type:func +func_8007D8D4_jp = 0x8007D8D4; // type:func +func_8007D90C_jp = 0x8007D90C; // type:func +func_8007D91C_jp = 0x8007D91C; // type:func +func_8007D930_jp = 0x8007D930; // type:func +func_8007D9C8_jp = 0x8007D9C8; // type:func +func_8007DA64_jp = 0x8007DA64; // type:func +func_8007DA6C_jp = 0x8007DA6C; // type:func +func_8007DACC_jp = 0x8007DACC; // type:func +func_8007DB20_jp = 0x8007DB20; // type:func +func_8007DBB0_jp = 0x8007DBB0; // type:func +func_8007DD84_jp = 0x8007DD84; // type:func +func_8007DDE8_jp = 0x8007DDE8; // type:func +func_8007DE2C_jp = 0x8007DE2C; // type:func +func_8007DF04_jp = 0x8007DF04; // type:func +func_8007DF98_jp = 0x8007DF98; // type:func +func_8007E0FC_jp = 0x8007E0FC; // type:func +func_8007E140_jp = 0x8007E140; // type:func +func_8007E184_jp = 0x8007E184; // type:func +func_8007E1D8_jp = 0x8007E1D8; // type:func +func_8007E22C_jp = 0x8007E22C; // type:func +func_8007E264_jp = 0x8007E264; // type:func +func_8007E3E8_jp = 0x8007E3E8; // type:func +func_8007E518_jp = 0x8007E518; // type:func +func_8007E60C_jp = 0x8007E60C; // type:func +func_8007E690_jp = 0x8007E690; // type:func +func_8007E714_jp = 0x8007E714; // type:func +func_8007E780_jp = 0x8007E780; // type:func +func_8007EB6C_jp = 0x8007EB6C; // type:func +func_8007EC28_jp = 0x8007EC28; // type:func +func_8007EC54_jp = 0x8007EC54; // type:func +func_8007ECA0_jp = 0x8007ECA0; // type:func +func_8007ECD4_jp = 0x8007ECD4; // type:func +func_8007ED08_jp = 0x8007ED08; // type:func +func_8007ED70_jp = 0x8007ED70; // type:func +func_8007EED4_jp = 0x8007EED4; // type:func +func_8007EF18_jp = 0x8007EF18; // type:func +func_8007F1A8_jp = 0x8007F1A8; // type:func +func_8007F28C_jp = 0x8007F28C; // type:func +func_8007F2D8_jp = 0x8007F2D8; // type:func +func_8007F318_jp = 0x8007F318; // type:func +func_8007F358_jp = 0x8007F358; // type:func +func_8007F6A0_jp = 0x8007F6A0; // type:func +func_8007F764_jp = 0x8007F764; // type:func +func_8007F858_jp = 0x8007F858; // type:func +func_8007F8A4_jp = 0x8007F8A4; // type:func +func_8007F8DC_jp = 0x8007F8DC; // type:func +func_8007F950_jp = 0x8007F950; // type:func +func_8007F988_jp = 0x8007F988; // type:func +func_8007FB44_jp = 0x8007FB44; // type:func +func_8007FCB8_jp = 0x8007FCB8; // type:func +func_8007FD40_jp = 0x8007FD40; // type:func +func_8007FDA8_jp = 0x8007FDA8; // type:func +func_8007FE0C_jp = 0x8007FE0C; // type:func +func_8007FE74_jp = 0x8007FE74; // type:func +func_8007FEBC_jp = 0x8007FEBC; // type:func +func_8007FF08_jp = 0x8007FF08; // type:func +func_8007FF8C_jp = 0x8007FF8C; // type:func +func_8007FFC4_jp = 0x8007FFC4; // type:func +func_80080000_jp = 0x80080000; // type:func +func_80080040_jp = 0x80080040; // type:func +func_80080080_jp = 0x80080080; // type:func +func_80080200_jp = 0x80080200; // type:func +func_8008033C_jp = 0x8008033C; // type:func +func_800804AC_jp = 0x800804AC; // type:func +func_800806A0_jp = 0x800806A0; // type:func +func_800807E0_jp = 0x800807E0; // type:func +func_800808E0_jp = 0x800808E0; // type:func +func_80080A50_jp = 0x80080A50; // type:func +func_80080C68_jp = 0x80080C68; // type:func +func_80080D68_jp = 0x80080D68; // type:func +func_80080F0C_jp = 0x80080F0C; // type:func +func_8008114C_jp = 0x8008114C; // type:func +func_80081360_jp = 0x80081360; // type:func +func_80081424_jp = 0x80081424; // type:func +func_80081434_jp = 0x80081434; // type:func +func_80081460_jp = 0x80081460; // type:func +func_800814B8_jp = 0x800814B8; // type:func +func_800815F0_jp = 0x800815F0; // type:func +func_800816C0_jp = 0x800816C0; // type:func +func_8008172C_jp = 0x8008172C; // type:func +func_80081800_jp = 0x80081800; // type:func +func_8008180C_jp = 0x8008180C; // type:func +func_80081818_jp = 0x80081818; // type:func +func_80081824_jp = 0x80081824; // type:func +func_800819C4_jp = 0x800819C4; // type:func +func_80081B98_jp = 0x80081B98; // type:func +func_80081BA4_jp = 0x80081BA4; // type:func +func_80081D24_jp = 0x80081D24; // type:func +func_80081E38_jp = 0x80081E38; // type:func +func_80081E48_jp = 0x80081E48; // type:func +func_80081E60_jp = 0x80081E60; // type:func +func_80081EA0_jp = 0x80081EA0; // type:func +func_80081EEC_jp = 0x80081EEC; // type:func +func_80081F5C_jp = 0x80081F5C; // type:func +func_80081F90_jp = 0x80081F90; // type:func +func_80081FBC_jp = 0x80081FBC; // type:func +func_80081FE8_jp = 0x80081FE8; // type:func +func_80082014_jp = 0x80082014; // type:func +func_800820B0_jp = 0x800820B0; // type:func +func_80082168_jp = 0x80082168; // type:func +func_800821B0_jp = 0x800821B0; // type:func +func_80082418_jp = 0x80082418; // type:func +func_80082450_jp = 0x80082450; // type:func +func_800824A4_jp = 0x800824A4; // type:func +func_8008256C_jp = 0x8008256C; // type:func +func_800828AC_jp = 0x800828AC; // type:func +func_80082910_jp = 0x80082910; // type:func +func_800829D4_jp = 0x800829D4; // type:func +func_80082B4C_jp = 0x80082B4C; // type:func +func_80082BD8_jp = 0x80082BD8; // type:func +func_80082C30_jp = 0x80082C30; // type:func +func_80082CC8_jp = 0x80082CC8; // type:func +func_80082DA0_jp = 0x80082DA0; // type:func +func_80082E40_jp = 0x80082E40; // type:func +func_80082FA0_jp = 0x80082FA0; // type:func +func_80083038_jp = 0x80083038; // type:func +func_800831E0_jp = 0x800831E0; // type:func +func_800835AC_jp = 0x800835AC; // type:func +func_8008366C_jp = 0x8008366C; // type:func +func_800836F8_jp = 0x800836F8; // type:func +func_80083870_jp = 0x80083870; // type:func +func_80083984_jp = 0x80083984; // type:func +func_80083AB0_jp = 0x80083AB0; // type:func +func_80083BE4_jp = 0x80083BE4; // type:func +func_80083BF0_jp = 0x80083BF0; // type:func +func_80083C00_jp = 0x80083C00; // type:func +func_80083CBC_jp = 0x80083CBC; // type:func +func_80083CE8_jp = 0x80083CE8; // type:func +func_80083D14_jp = 0x80083D14; // type:func +func_80083E08_jp = 0x80083E08; // type:func +func_8008400C_jp = 0x8008400C; // type:func +func_80084018_jp = 0x80084018; // type:func +func_80084068_jp = 0x80084068; // type:func +func_80084080_jp = 0x80084080; // type:func +func_800840AC_jp = 0x800840AC; // type:func +func_8008418C_jp = 0x8008418C; // type:func +func_800843C8_jp = 0x800843C8; // type:func +func_80084480_jp = 0x80084480; // type:func +func_800844B0_jp = 0x800844B0; // type:func +func_800844BC_jp = 0x800844BC; // type:func +func_800844C8_jp = 0x800844C8; // type:func +func_800844E0_jp = 0x800844E0; // type:func +func_8008450C_jp = 0x8008450C; // type:func +func_800845EC_jp = 0x800845EC; // type:func +func_8008468C_jp = 0x8008468C; // type:func +func_800846D4_jp = 0x800846D4; // type:func +func_800846E0_jp = 0x800846E0; // type:func +func_800846EC_jp = 0x800846EC; // type:func +func_80084700_jp = 0x80084700; // type:func +func_80084748_jp = 0x80084748; // type:func +func_800848AC_jp = 0x800848AC; // type:func +func_800848D8_jp = 0x800848D8; // type:func +func_80084904_jp = 0x80084904; // type:func +func_80084924_jp = 0x80084924; // type:func +func_80084938_jp = 0x80084938; // type:func +func_800849E0_jp = 0x800849E0; // type:func +func_80084A40_jp = 0x80084A40; // type:func +func_80084CA4_jp = 0x80084CA4; // type:func +func_80084CD8_jp = 0x80084CD8; // type:func +func_80084D08_jp = 0x80084D08; // type:func +func_80084DA4_jp = 0x80084DA4; // type:func +func_80084DE0_jp = 0x80084DE0; // type:func +func_80084DF0_jp = 0x80084DF0; // type:func +func_80084ED0_jp = 0x80084ED0; // type:func +func_80084FAC_jp = 0x80084FAC; // type:func +func_800850E4_jp = 0x800850E4; // type:func +func_80085178_jp = 0x80085178; // type:func +func_800851C8_jp = 0x800851C8; // type:func +func_800853CC_jp = 0x800853CC; // type:func +func_80085490_jp = 0x80085490; // type:func +func_8008557C_jp = 0x8008557C; // type:func +func_800855D0_jp = 0x800855D0; // type:func +func_80085918_jp = 0x80085918; // type:func +func_800859F4_jp = 0x800859F4; // type:func +func_80085A84_jp = 0x80085A84; // type:func +func_80085B40_jp = 0x80085B40; // type:func +func_80085CC0_jp = 0x80085CC0; // type:func +func_80085D44_jp = 0x80085D44; // type:func +func_80085D64_jp = 0x80085D64; // type:func +func_80085D94_jp = 0x80085D94; // type:func +func_80085FF0_jp = 0x80085FF0; // type:func +func_8008609C_jp = 0x8008609C; // type:func +func_800862DC_jp = 0x800862DC; // type:func +func_8008640C_jp = 0x8008640C; // type:func +func_800865D0_jp = 0x800865D0; // type:func +func_800867F0_jp = 0x800867F0; // type:func +func_80086BD0_jp = 0x80086BD0; // type:func +func_80086CA4_jp = 0x80086CA4; // type:func +func_80086D44_jp = 0x80086D44; // type:func +func_80086DE0_jp = 0x80086DE0; // type:func +func_80086E30_jp = 0x80086E30; // type:func +func_80086F08_jp = 0x80086F08; // type:func +func_80086FA8_jp = 0x80086FA8; // type:func +func_80086FEC_jp = 0x80086FEC; // type:func +func_80087004_jp = 0x80087004; // type:func +func_80087280_jp = 0x80087280; // type:func +func_80087380_jp = 0x80087380; // type:func +func_80087420_jp = 0x80087420; // type:func +func_800874CC_jp = 0x800874CC; // type:func +func_80087754_jp = 0x80087754; // type:func +func_8008775C_jp = 0x8008775C; // type:func +func_80087788_jp = 0x80087788; // type:func +func_800877CC_jp = 0x800877CC; // type:func +func_800878D4_jp = 0x800878D4; // type:func +func_800879B0_jp = 0x800879B0; // type:func +func_80087C30_jp = 0x80087C30; // type:func +func_80087C40_jp = 0x80087C40; // type:func +func_80087C64_jp = 0x80087C64; // type:func +func_80087C88_jp = 0x80087C88; // type:func +func_80087C9C_jp = 0x80087C9C; // type:func +func_80087D30_jp = 0x80087D30; // type:func +func_80087DC8_jp = 0x80087DC8; // type:func +func_80087E14_jp = 0x80087E14; // type:func +func_80087E58_jp = 0x80087E58; // type:func +func_80087E94_jp = 0x80087E94; // type:func +func_80087ED0_jp = 0x80087ED0; // type:func +func_80088018_jp = 0x80088018; // type:func +func_80088160_jp = 0x80088160; // type:func +func_8008819C_jp = 0x8008819C; // type:func +func_800881AC_jp = 0x800881AC; // type:func +func_80088270_jp = 0x80088270; // type:func +func_800882AC_jp = 0x800882AC; // type:func +func_800882FC_jp = 0x800882FC; // type:func +func_80088320_jp = 0x80088320; // type:func +func_80088344_jp = 0x80088344; // type:func +func_80088458_jp = 0x80088458; // type:func +func_800884E0_jp = 0x800884E0; // type:func +func_800885A8_jp = 0x800885A8; // type:func +func_80088710_jp = 0x80088710; // type:func +func_80088780_jp = 0x80088780; // type:func +func_8008883C_jp = 0x8008883C; // type:func +func_800888AC_jp = 0x800888AC; // type:func +func_80088938_jp = 0x80088938; // type:func +func_800889D8_jp = 0x800889D8; // type:func +func_80088A58_jp = 0x80088A58; // type:func +func_80088B3C_jp = 0x80088B3C; // type:func +func_80088BC0_jp = 0x80088BC0; // type:func +func_80088BFC_jp = 0x80088BFC; // type:func +func_80088C74_jp = 0x80088C74; // type:func +func_80088CBC_jp = 0x80088CBC; // type:func +func_80088CD0_jp = 0x80088CD0; // type:func +func_80088CE4_jp = 0x80088CE4; // type:func +func_80088D00_jp = 0x80088D00; // type:func +func_80088D30_jp = 0x80088D30; // type:func +func_80088D78_jp = 0x80088D78; // type:func +func_80088D9C_jp = 0x80088D9C; // type:func +func_80088E08_jp = 0x80088E08; // type:func +func_80088E34_jp = 0x80088E34; // type:func +func_80088E74_jp = 0x80088E74; // type:func +func_80088F14_jp = 0x80088F14; // type:func +func_80088F94_jp = 0x80088F94; // type:func +func_8008902C_jp = 0x8008902C; // type:func +func_8008907C_jp = 0x8008907C; // type:func +func_80089114_jp = 0x80089114; // type:func +func_800891AC_jp = 0x800891AC; // type:func +func_80089268_jp = 0x80089268; // type:func +func_800892CC_jp = 0x800892CC; // type:func +func_8008930C_jp = 0x8008930C; // type:func +func_80089348_jp = 0x80089348; // type:func +func_800893C8_jp = 0x800893C8; // type:func +func_80089404_jp = 0x80089404; // type:func +func_80089440_jp = 0x80089440; // type:func +func_800894D0_jp = 0x800894D0; // type:func +func_80089538_jp = 0x80089538; // type:func +func_800895B8_jp = 0x800895B8; // type:func +func_80089698_jp = 0x80089698; // type:func +func_80089704_jp = 0x80089704; // type:func +func_800897D0_jp = 0x800897D0; // type:func +func_80089888_jp = 0x80089888; // type:func +func_800898F4_jp = 0x800898F4; // type:func +func_800899CC_jp = 0x800899CC; // type:func +func_80089A34_jp = 0x80089A34; // type:func +func_80089AAC_jp = 0x80089AAC; // type:func +func_80089B1C_jp = 0x80089B1C; // type:func +func_80089B94_jp = 0x80089B94; // type:func +func_80089C0C_jp = 0x80089C0C; // type:func +func_80089CA0_jp = 0x80089CA0; // type:func +func_80089D18_jp = 0x80089D18; // type:func +func_80089D6C_jp = 0x80089D6C; // type:func +func_80089E84_jp = 0x80089E84; // type:func +func_80089EF8_jp = 0x80089EF8; // type:func +func_8008A000_jp = 0x8008A000; // type:func +func_8008A33C_jp = 0x8008A33C; // type:func +func_8008A3BC_jp = 0x8008A3BC; // type:func +func_8008A410_jp = 0x8008A410; // type:func +func_8008A4F8_jp = 0x8008A4F8; // type:func +func_8008A5A0_jp = 0x8008A5A0; // type:func +func_8008A608_jp = 0x8008A608; // type:func +func_8008A670_jp = 0x8008A670; // type:func +func_8008A74C_jp = 0x8008A74C; // type:func +func_8008A81C_jp = 0x8008A81C; // type:func +func_8008A960_jp = 0x8008A960; // type:func +func_8008AA24_jp = 0x8008AA24; // type:func +func_8008AA98_jp = 0x8008AA98; // type:func +func_8008AB14_jp = 0x8008AB14; // type:func +func_8008AC74_jp = 0x8008AC74; // type:func +func_8008ACA0_jp = 0x8008ACA0; // type:func +func_8008ACBC_jp = 0x8008ACBC; // type:func +func_8008ACD8_jp = 0x8008ACD8; // type:func +func_8008ADCC_jp = 0x8008ADCC; // type:func +func_8008AE70_jp = 0x8008AE70; // type:func +func_8008B1A0_jp = 0x8008B1A0; // type:func +func_8008B200_jp = 0x8008B200; // type:func +func_8008B238_jp = 0x8008B238; // type:func +func_8008B26C_jp = 0x8008B26C; // type:func +func_8008B29C_jp = 0x8008B29C; // type:func +func_8008B2D0_jp = 0x8008B2D0; // type:func +func_8008B300_jp = 0x8008B300; // type:func +func_8008B318_jp = 0x8008B318; // type:func +func_8008B330_jp = 0x8008B330; // type:func +func_8008B3E8_jp = 0x8008B3E8; // type:func +func_8008B4C0_jp = 0x8008B4C0; // type:func +func_8008B598_jp = 0x8008B598; // type:func +func_8008B66C_jp = 0x8008B66C; // type:func +func_8008B774_jp = 0x8008B774; // type:func +func_8008B7F4_jp = 0x8008B7F4; // type:func +func_8008B878_jp = 0x8008B878; // type:func +func_8008B9F8_jp = 0x8008B9F8; // type:func +func_8008BA74_jp = 0x8008BA74; // type:func +func_8008BAEC_jp = 0x8008BAEC; // type:func +func_8008BB64_jp = 0x8008BB64; // type:func +func_8008BBF0_jp = 0x8008BBF0; // type:func +func_8008BC64_jp = 0x8008BC64; // type:func +func_8008BCFC_jp = 0x8008BCFC; // type:func +func_8008BD98_jp = 0x8008BD98; // type:func +func_8008BDCC_jp = 0x8008BDCC; // type:func +func_8008BE00_jp = 0x8008BE00; // type:func +func_8008BE38_jp = 0x8008BE38; // type:func +func_8008BF34_jp = 0x8008BF34; // type:func +func_8008BFC4_jp = 0x8008BFC4; // type:func +func_8008C058_jp = 0x8008C058; // type:func +func_8008C0FC_jp = 0x8008C0FC; // type:func +func_8008C120_jp = 0x8008C120; // type:func +func_8008C130_jp = 0x8008C130; // type:func +func_8008C1E0_jp = 0x8008C1E0; // type:func +func_8008C344_jp = 0x8008C344; // type:func +func_8008C390_jp = 0x8008C390; // type:func +func_8008C3B0_jp = 0x8008C3B0; // type:func +func_8008C3D4_jp = 0x8008C3D4; // type:func +func_8008C3E8_jp = 0x8008C3E8; // type:func +func_8008C458_jp = 0x8008C458; // type:func +func_8008C478_jp = 0x8008C478; // type:func +func_8008C498_jp = 0x8008C498; // type:func +func_8008C4B8_jp = 0x8008C4B8; // type:func +func_8008C504_jp = 0x8008C504; // type:func +func_8008C524_jp = 0x8008C524; // type:func +func_8008C548_jp = 0x8008C548; // type:func +func_8008C56C_jp = 0x8008C56C; // type:func +func_8008C5F0_jp = 0x8008C5F0; // type:func +func_8008C610_jp = 0x8008C610; // type:func +func_8008C630_jp = 0x8008C630; // type:func +func_8008C650_jp = 0x8008C650; // type:func +func_8008C6AC_jp = 0x8008C6AC; // type:func +func_8008C708_jp = 0x8008C708; // type:func +func_8008C764_jp = 0x8008C764; // type:func +func_8008C798_jp = 0x8008C798; // type:func +func_8008C830_jp = 0x8008C830; // type:func +func_8008C84C_jp = 0x8008C84C; // type:func +func_8008C8C4_jp = 0x8008C8C4; // type:func +func_8008C938_jp = 0x8008C938; // type:func +func_8008C964_jp = 0x8008C964; // type:func +func_8008CA14_jp = 0x8008CA14; // type:func +func_8008CAD8_jp = 0x8008CAD8; // type:func +func_8008CC1C_jp = 0x8008CC1C; // type:func +func_8008CCFC_jp = 0x8008CCFC; // type:func +func_8008CD24_jp = 0x8008CD24; // type:func +func_8008CD74_jp = 0x8008CD74; // type:func +func_8008CE00_jp = 0x8008CE00; // type:func +func_8008CE38_jp = 0x8008CE38; // type:func +func_8008CEC0_jp = 0x8008CEC0; // type:func +func_8008CFF4_jp = 0x8008CFF4; // type:func +func_8008D12C_jp = 0x8008D12C; // type:func +func_8008D268_jp = 0x8008D268; // type:func +func_8008D3A4_jp = 0x8008D3A4; // type:func +func_8008D574_jp = 0x8008D574; // type:func +func_8008D6E0_jp = 0x8008D6E0; // type:func +func_8008D7B0_jp = 0x8008D7B0; // type:func +func_8008D884_jp = 0x8008D884; // type:func +func_8008D928_jp = 0x8008D928; // type:func +func_8008DA4C_jp = 0x8008DA4C; // type:func +func_8008DCF8_jp = 0x8008DCF8; // type:func +func_8008DD0C_jp = 0x8008DD0C; // type:func +func_8008DD3C_jp = 0x8008DD3C; // type:func +func_8008DDC8_jp = 0x8008DDC8; // type:func +func_8008DF04_jp = 0x8008DF04; // type:func +func_8008E058_jp = 0x8008E058; // type:func +func_8008E514_jp = 0x8008E514; // type:func +func_8008E5F4_jp = 0x8008E5F4; // type:func +func_8008E720_jp = 0x8008E720; // type:func +func_8008E780_jp = 0x8008E780; // type:func +func_8008E8E0_jp = 0x8008E8E0; // type:func +func_8008E9C4_jp = 0x8008E9C4; // type:func +func_8008EA5C_jp = 0x8008EA5C; // type:func +func_8008ECA0_jp = 0x8008ECA0; // type:func +func_8008ECC8_jp = 0x8008ECC8; // type:func +func_8008ECF0_jp = 0x8008ECF0; // type:func +func_8008ED14_jp = 0x8008ED14; // type:func +func_8008EE24_jp = 0x8008EE24; // type:func +func_8008EE5C_jp = 0x8008EE5C; // type:func +func_8008EE6C_jp = 0x8008EE6C; // type:func +func_8008EE7C_jp = 0x8008EE7C; // type:func +func_8008EEB4_jp = 0x8008EEB4; // type:func +func_8008EEE8_jp = 0x8008EEE8; // type:func +func_8008EF0C_jp = 0x8008EF0C; // type:func +func_8008EF6C_jp = 0x8008EF6C; // type:func +func_8008EF94_jp = 0x8008EF94; // type:func +func_8008EFDC_jp = 0x8008EFDC; // type:func +func_8008F020_jp = 0x8008F020; // type:func +func_8008F040_jp = 0x8008F040; // type:func +func_8008F0A0_jp = 0x8008F0A0; // type:func +func_8008F1BC_jp = 0x8008F1BC; // type:func +func_8008F210_jp = 0x8008F210; // type:func +func_8008F23C_jp = 0x8008F23C; // type:func +func_8008F24C_jp = 0x8008F24C; // type:func +func_8008F530_jp = 0x8008F530; // type:func +func_8008F5FC_jp = 0x8008F5FC; // type:func +func_8008F648_jp = 0x8008F648; // type:func +func_8008F768_jp = 0x8008F768; // type:func +func_8008F7C8_jp = 0x8008F7C8; // type:func +func_8008F8A0_jp = 0x8008F8A0; // type:func +func_8008F938_jp = 0x8008F938; // type:func +func_8008F968_jp = 0x8008F968; // type:func +func_8008FA28_jp = 0x8008FA28; // type:func +func_8008FA50_jp = 0x8008FA50; // type:func +func_8008FA74_jp = 0x8008FA74; // type:func +func_8008FAB4_jp = 0x8008FAB4; // type:func +func_8008FAE0_jp = 0x8008FAE0; // type:func +func_8008FB64_jp = 0x8008FB64; // type:func +func_8008FBEC_jp = 0x8008FBEC; // type:func +func_8008FCE8_jp = 0x8008FCE8; // type:func +func_8008FDD4_jp = 0x8008FDD4; // type:func +func_8008FE74_jp = 0x8008FE74; // type:func +func_8008FF60_jp = 0x8008FF60; // type:func +func_80090044_jp = 0x80090044; // type:func +func_800900B0_jp = 0x800900B0; // type:func +func_80090120_jp = 0x80090120; // type:func +func_80090130_jp = 0x80090130; // type:func +func_80090140_jp = 0x80090140; // type:func +func_80090178_jp = 0x80090178; // type:func +func_80090188_jp = 0x80090188; // type:func +func_8009028C_jp = 0x8009028C; // type:func +func_800902CC_jp = 0x800902CC; // type:func +func_8009034C_jp = 0x8009034C; // type:func +func_800903A8_jp = 0x800903A8; // type:func +func_800903CC_jp = 0x800903CC; // type:func +func_800903E4_jp = 0x800903E4; // type:func +func_8009040C_jp = 0x8009040C; // type:func +func_80090470_jp = 0x80090470; // type:func +func_800904B8_jp = 0x800904B8; // type:func +func_80090504_jp = 0x80090504; // type:func +func_80090564_jp = 0x80090564; // type:func +func_800905D4_jp = 0x800905D4; // type:func +func_80090648_jp = 0x80090648; // type:func +func_8009069C_jp = 0x8009069C; // type:func +func_80090848_jp = 0x80090848; // type:func +func_8009087C_jp = 0x8009087C; // type:func +func_80090CC0_jp = 0x80090CC0; // type:func +func_80090E1C_jp = 0x80090E1C; // type:func +func_80090E98_jp = 0x80090E98; // type:func +func_80090F10_jp = 0x80090F10; // type:func +func_8009104C_jp = 0x8009104C; // type:func +func_80091074_jp = 0x80091074; // type:func +func_80091094_jp = 0x80091094; // type:func +func_80091104_jp = 0x80091104; // type:func +func_8009113C_jp = 0x8009113C; // type:func +func_800911E8_jp = 0x800911E8; // type:func +func_800913D4_jp = 0x800913D4; // type:func +func_80091470_jp = 0x80091470; // type:func +func_800914FC_jp = 0x800914FC; // type:func +func_80091554_jp = 0x80091554; // type:func +func_800915A4_jp = 0x800915A4; // type:func +func_800915D8_jp = 0x800915D8; // type:func +func_8009167C_jp = 0x8009167C; // type:func +func_800917C8_jp = 0x800917C8; // type:func +func_800918A8_jp = 0x800918A8; // type:func +func_800918E8_jp = 0x800918E8; // type:func +func_80091900_jp = 0x80091900; // type:func +func_8009193C_jp = 0x8009193C; // type:func +func_80091980_jp = 0x80091980; // type:func +func_800919D0_jp = 0x800919D0; // type:func +func_80091A18_jp = 0x80091A18; // type:func +func_80091AB0_jp = 0x80091AB0; // type:func +func_80091C00_jp = 0x80091C00; // type:func +func_80091C98_jp = 0x80091C98; // type:func +func_80091DFC_jp = 0x80091DFC; // type:func +func_80091E0C_jp = 0x80091E0C; // type:func +func_80091E90_jp = 0x80091E90; // type:func +func_80091EC4_jp = 0x80091EC4; // type:func +func_80091F98_jp = 0x80091F98; // type:func +func_80091FCC_jp = 0x80091FCC; // type:func +func_80092000_jp = 0x80092000; // type:func +func_80092034_jp = 0x80092034; // type:func +func_800921D0_jp = 0x800921D0; // type:func +func_80092440_jp = 0x80092440; // type:func +func_80092468_jp = 0x80092468; // type:func +func_800924CC_jp = 0x800924CC; // type:func +func_80092538_jp = 0x80092538; // type:func +func_8009264C_jp = 0x8009264C; // type:func +func_800928C0_jp = 0x800928C0; // type:func +func_800928E8_jp = 0x800928E8; // type:func +func_80092B7C_jp = 0x80092B7C; // type:func +func_80092B8C_jp = 0x80092B8C; // type:func +func_80092BA0_jp = 0x80092BA0; // type:func +func_80092BE8_jp = 0x80092BE8; // type:func +func_80092C2C_jp = 0x80092C2C; // type:func +func_80092D10_jp = 0x80092D10; // type:func +func_80092E14_jp = 0x80092E14; // type:func +func_80092E80_jp = 0x80092E80; // type:func +func_80092FC4_jp = 0x80092FC4; // type:func +func_800930B0_jp = 0x800930B0; // type:func +func_800930D8_jp = 0x800930D8; // type:func +func_80093104_jp = 0x80093104; // type:func +func_80093130_jp = 0x80093130; // type:func +func_8009315C_jp = 0x8009315C; // type:func +func_80093188_jp = 0x80093188; // type:func +func_800931B4_jp = 0x800931B4; // type:func +func_800931E0_jp = 0x800931E0; // type:func +func_8009320C_jp = 0x8009320C; // type:func +func_80093238_jp = 0x80093238; // type:func +func_80093264_jp = 0x80093264; // type:func +func_80093290_jp = 0x80093290; // type:func +func_800932BC_jp = 0x800932BC; // type:func +func_800932E8_jp = 0x800932E8; // type:func +func_80093314_jp = 0x80093314; // type:func +func_80093340_jp = 0x80093340; // type:func +func_8009336C_jp = 0x8009336C; // type:func +func_80093398_jp = 0x80093398; // type:func +func_800933C4_jp = 0x800933C4; // type:func +func_800933F0_jp = 0x800933F0; // type:func +func_8009341C_jp = 0x8009341C; // type:func +func_80093478_jp = 0x80093478; // type:func +func_80093520_jp = 0x80093520; // type:func +func_800935F8_jp = 0x800935F8; // type:func +func_80093738_jp = 0x80093738; // type:func +func_80093878_jp = 0x80093878; // type:func +func_800939B8_jp = 0x800939B8; // type:func +func_80093B28_jp = 0x80093B28; // type:func +func_80093C98_jp = 0x80093C98; // type:func +func_80093DA8_jp = 0x80093DA8; // type:func +func_80093F04_jp = 0x80093F04; // type:func +func_80093F54_jp = 0x80093F54; // type:func +func_80093F94_jp = 0x80093F94; // type:func +func_800940A8_jp = 0x800940A8; // type:func +func_800941B0_jp = 0x800941B0; // type:func +func_800942A0_jp = 0x800942A0; // type:func +func_80094400_jp = 0x80094400; // type:func +func_800944B8_jp = 0x800944B8; // type:func +func_80094520_jp = 0x80094520; // type:func +func_80094690_jp = 0x80094690; // type:func +func_800946D0_jp = 0x800946D0; // type:func +func_80094744_jp = 0x80094744; // type:func +func_800947C0_jp = 0x800947C0; // type:func +func_8009480C_jp = 0x8009480C; // type:func +func_800949B0_jp = 0x800949B0; // type:func +func_800949D8_jp = 0x800949D8; // type:func +func_80094A04_jp = 0x80094A04; // type:func +func_80094A90_jp = 0x80094A90; // type:func +func_80094BE0_jp = 0x80094BE0; // type:func +func_80094BF4_jp = 0x80094BF4; // type:func +func_80094C10_jp = 0x80094C10; // type:func +func_80094C44_jp = 0x80094C44; // type:func +func_80094CAC_jp = 0x80094CAC; // type:func +func_80094DD0_jp = 0x80094DD0; // type:func +func_80094E10_jp = 0x80094E10; // type:func +func_80094E38_jp = 0x80094E38; // type:func +func_80094E90_jp = 0x80094E90; // type:func +func_80094EE0_jp = 0x80094EE0; // type:func +func_80094F04_jp = 0x80094F04; // type:func +func_80094F24_jp = 0x80094F24; // type:func +func_80094F84_jp = 0x80094F84; // type:func +func_8009504C_jp = 0x8009504C; // type:func +func_800950D8_jp = 0x800950D8; // type:func +func_800950E8_jp = 0x800950E8; // type:func +func_8009519C_jp = 0x8009519C; // type:func +func_800951C0_jp = 0x800951C0; // type:func +func_800951E4_jp = 0x800951E4; // type:func +func_80095218_jp = 0x80095218; // type:func +func_8009524C_jp = 0x8009524C; // type:func +func_80095280_jp = 0x80095280; // type:func +func_800952A4_jp = 0x800952A4; // type:func +func_800952D0_jp = 0x800952D0; // type:func +func_80095390_jp = 0x80095390; // type:func +func_800953B0_jp = 0x800953B0; // type:func +func_80095414_jp = 0x80095414; // type:func +func_8009542C_jp = 0x8009542C; // type:func +func_80095470_jp = 0x80095470; // type:func +func_80095628_jp = 0x80095628; // type:func +func_800957E4_jp = 0x800957E4; // type:func +func_80095844_jp = 0x80095844; // type:func +func_800958BC_jp = 0x800958BC; // type:func +func_8009593C_jp = 0x8009593C; // type:func +func_800959AC_jp = 0x800959AC; // type:func +func_80095A2C_jp = 0x80095A2C; // type:func +func_80095AD4_jp = 0x80095AD4; // type:func +func_80095B50_jp = 0x80095B50; // type:func +func_80095BC4_jp = 0x80095BC4; // type:func +func_80095C88_jp = 0x80095C88; // type:func +func_80095C98_jp = 0x80095C98; // type:func +func_80095E08_jp = 0x80095E08; // type:func +func_80095F30_jp = 0x80095F30; // type:func +func_80095FE0_jp = 0x80095FE0; // type:func +func_800961B8_jp = 0x800961B8; // type:func +func_80096228_jp = 0x80096228; // type:func +func_800962A8_jp = 0x800962A8; // type:func +func_80096330_jp = 0x80096330; // type:func +func_800963B8_jp = 0x800963B8; // type:func +func_80096440_jp = 0x80096440; // type:func +func_80096524_jp = 0x80096524; // type:func +func_800965A8_jp = 0x800965A8; // type:func +func_800965F4_jp = 0x800965F4; // type:func +func_800966D8_jp = 0x800966D8; // type:func +func_800966E0_jp = 0x800966E0; // type:func +func_80096710_jp = 0x80096710; // type:func +func_80096740_jp = 0x80096740; // type:func +func_80096860_jp = 0x80096860; // type:func +func_800968C0_jp = 0x800968C0; // type:func +func_80096B2C_jp = 0x80096B2C; // type:func +func_80096B4C_jp = 0x80096B4C; // type:func +func_80096B64_jp = 0x80096B64; // type:func +func_80096BF0_jp = 0x80096BF0; // type:func +func_80096C90_jp = 0x80096C90; // type:func +func_80096CA0_jp = 0x80096CA0; // type:func +func_80096CDC_jp = 0x80096CDC; // type:func +func_80096D60_jp = 0x80096D60; // type:func +func_80096F5C_jp = 0x80096F5C; // type:func +func_80097048_jp = 0x80097048; // type:func +func_800970D4_jp = 0x800970D4; // type:func +func_80097108_jp = 0x80097108; // type:func +func_800971B4_jp = 0x800971B4; // type:func +func_80097510_jp = 0x80097510; // type:func +func_800976BC_jp = 0x800976BC; // type:func +func_80097738_jp = 0x80097738; // type:func +func_800978EC_jp = 0x800978EC; // type:func +func_80097AE8_jp = 0x80097AE8; // type:func +func_80097BB0_jp = 0x80097BB0; // type:func +func_80097C54_jp = 0x80097C54; // type:func +func_80097D40_jp = 0x80097D40; // type:func +func_80097F88_jp = 0x80097F88; // type:func +func_80097FB4_jp = 0x80097FB4; // type:func +func_8009802C_jp = 0x8009802C; // type:func +func_800980C0_jp = 0x800980C0; // type:func +func_80098158_jp = 0x80098158; // type:func +func_800981B8_jp = 0x800981B8; // type:func +func_8009836C_jp = 0x8009836C; // type:func +func_800983F0_jp = 0x800983F0; // type:func +func_800984CC_jp = 0x800984CC; // type:func +func_80098558_jp = 0x80098558; // type:func +func_8009867C_jp = 0x8009867C; // type:func +func_80098794_jp = 0x80098794; // type:func +func_8009895C_jp = 0x8009895C; // type:func +func_80098980_jp = 0x80098980; // type:func +func_80098990_jp = 0x80098990; // type:func +func_80098A90_jp = 0x80098A90; // type:func +func_80098B50_jp = 0x80098B50; // type:func +func_80098CCC_jp = 0x80098CCC; // type:func +func_80098D88_jp = 0x80098D88; // type:func +func_80098DE0_jp = 0x80098DE0; // type:func +func_80098EE4_jp = 0x80098EE4; // type:func +func_80098F68_jp = 0x80098F68; // type:func +func_80098FF0_jp = 0x80098FF0; // type:func +func_800990A8_jp = 0x800990A8; // type:func +func_8009915C_jp = 0x8009915C; // type:func +func_800991EC_jp = 0x800991EC; // type:func +func_800992C8_jp = 0x800992C8; // type:func +func_80099378_jp = 0x80099378; // type:func +func_8009944C_jp = 0x8009944C; // type:func +func_8009949C_jp = 0x8009949C; // type:func +func_80099594_jp = 0x80099594; // type:func +func_800996CC_jp = 0x800996CC; // type:func +func_800996F8_jp = 0x800996F8; // type:func +func_80099718_jp = 0x80099718; // type:func +func_80099728_jp = 0x80099728; // type:func +func_80099770_jp = 0x80099770; // type:func +func_800998AC_jp = 0x800998AC; // type:func +func_800998C0_jp = 0x800998C0; // type:func +func_8009992C_jp = 0x8009992C; // type:func +func_80099980_jp = 0x80099980; // type:func +func_80099A54_jp = 0x80099A54; // type:func +func_80099A94_jp = 0x80099A94; // type:func +func_80099AD4_jp = 0x80099AD4; // type:func +func_80099B90_jp = 0x80099B90; // type:func +func_80099C18_jp = 0x80099C18; // type:func +func_80099CAC_jp = 0x80099CAC; // type:func +func_80099D14_jp = 0x80099D14; // type:func +func_80099D74_jp = 0x80099D74; // type:func +func_80099E38_jp = 0x80099E38; // type:func +func_80099E88_jp = 0x80099E88; // type:func +func_80099F30_jp = 0x80099F30; // type:func +func_80099F6C_jp = 0x80099F6C; // type:func +func_80099FE8_jp = 0x80099FE8; // type:func +func_8009A03C_jp = 0x8009A03C; // type:func +func_8009A0A4_jp = 0x8009A0A4; // type:func +func_8009A0C4_jp = 0x8009A0C4; // type:func +func_8009A108_jp = 0x8009A108; // type:func +func_8009A140_jp = 0x8009A140; // type:func +func_8009A178_jp = 0x8009A178; // type:func +func_8009A1D4_jp = 0x8009A1D4; // type:func +func_8009A210_jp = 0x8009A210; // type:func +func_8009A254_jp = 0x8009A254; // type:func +func_8009A2B0_jp = 0x8009A2B0; // type:func +func_8009A2E4_jp = 0x8009A2E4; // type:func +func_8009A2F8_jp = 0x8009A2F8; // type:func +func_8009A32C_jp = 0x8009A32C; // type:func +func_8009A374_jp = 0x8009A374; // type:func +func_8009A3EC_jp = 0x8009A3EC; // type:func +func_8009A408_jp = 0x8009A408; // type:func +func_8009A424_jp = 0x8009A424; // type:func +func_8009A440_jp = 0x8009A440; // type:func +func_8009A45C_jp = 0x8009A45C; // type:func +func_8009A478_jp = 0x8009A478; // type:func +func_8009A494_jp = 0x8009A494; // type:func +func_8009A4B8_jp = 0x8009A4B8; // type:func +func_8009A4E8_jp = 0x8009A4E8; // type:func +func_8009A514_jp = 0x8009A514; // type:func +func_8009A54C_jp = 0x8009A54C; // type:func +func_8009A570_jp = 0x8009A570; // type:func +func_8009A6B8_jp = 0x8009A6B8; // type:func +func_8009A728_jp = 0x8009A728; // type:func +func_8009A77C_jp = 0x8009A77C; // type:func +func_8009A974_jp = 0x8009A974; // type:func +func_8009AAD8_jp = 0x8009AAD8; // type:func +func_8009ABA8_jp = 0x8009ABA8; // type:func +func_8009AC4C_jp = 0x8009AC4C; // type:func +func_8009AC74_jp = 0x8009AC74; // type:func +func_8009AC80_jp = 0x8009AC80; // type:func +func_8009AC90_jp = 0x8009AC90; // type:func +func_8009AD14_jp = 0x8009AD14; // type:func +func_8009AD98_jp = 0x8009AD98; // type:func +func_8009ADA8_jp = 0x8009ADA8; // type:func +func_8009ADE0_jp = 0x8009ADE0; // type:func +func_8009AE28_jp = 0x8009AE28; // type:func +func_8009AE44_jp = 0x8009AE44; // type:func +func_8009AE60_jp = 0x8009AE60; // type:func +func_8009AF38_jp = 0x8009AF38; // type:func +func_8009B0AC_jp = 0x8009B0AC; // type:func +func_8009B160_jp = 0x8009B160; // type:func +func_8009B1E0_jp = 0x8009B1E0; // type:func +func_8009B23C_jp = 0x8009B23C; // type:func +func_8009B2A0_jp = 0x8009B2A0; // type:func +func_8009B308_jp = 0x8009B308; // type:func +func_8009B33C_jp = 0x8009B33C; // type:func +func_8009B394_jp = 0x8009B394; // type:func +func_8009B3D0_jp = 0x8009B3D0; // type:func +func_8009B504_jp = 0x8009B504; // type:func +func_8009B534_jp = 0x8009B534; // type:func +func_8009B72C_jp = 0x8009B72C; // type:func +func_8009B81C_jp = 0x8009B81C; // type:func +func_8009B884_jp = 0x8009B884; // type:func +func_8009B954_jp = 0x8009B954; // type:func +func_8009B9E0_jp = 0x8009B9E0; // type:func +func_8009BA28_jp = 0x8009BA28; // type:func +func_8009BA94_jp = 0x8009BA94; // type:func +func_8009BAC0_jp = 0x8009BAC0; // type:func +func_8009BAFC_jp = 0x8009BAFC; // type:func +func_8009BB34_jp = 0x8009BB34; // type:func +func_8009BB40_jp = 0x8009BB40; // type:func +func_8009BB8C_jp = 0x8009BB8C; // type:func +func_8009BBEC_jp = 0x8009BBEC; // type:func +func_8009BC48_jp = 0x8009BC48; // type:func +func_8009BD90_jp = 0x8009BD90; // type:func +func_8009BDD8_jp = 0x8009BDD8; // type:func +func_8009BFC0_jp = 0x8009BFC0; // type:func +func_8009BFE8_jp = 0x8009BFE8; // type:func +func_8009C010_jp = 0x8009C010; // type:func +func_8009C040_jp = 0x8009C040; // type:func +func_8009C068_jp = 0x8009C068; // type:func +func_8009C0C0_jp = 0x8009C0C0; // type:func +func_8009C0F8_jp = 0x8009C0F8; // type:func +func_8009C11C_jp = 0x8009C11C; // type:func +func_8009C16C_jp = 0x8009C16C; // type:func +func_8009C19C_jp = 0x8009C19C; // type:func +func_8009C1C0_jp = 0x8009C1C0; // type:func +func_8009C284_jp = 0x8009C284; // type:func +func_8009C2D8_jp = 0x8009C2D8; // type:func +func_8009C344_jp = 0x8009C344; // type:func +func_8009C384_jp = 0x8009C384; // type:func +func_8009C3D0_jp = 0x8009C3D0; // type:func +func_8009C414_jp = 0x8009C414; // type:func +func_8009C438_jp = 0x8009C438; // type:func +func_8009C45C_jp = 0x8009C45C; // type:func +func_8009C480_jp = 0x8009C480; // type:func +func_8009C4A0_jp = 0x8009C4A0; // type:func +func_8009C4C8_jp = 0x8009C4C8; // type:func +func_8009C4F4_jp = 0x8009C4F4; // type:func +func_8009C534_jp = 0x8009C534; // type:func +func_8009C5A4_jp = 0x8009C5A4; // type:func +func_8009C608_jp = 0x8009C608; // type:func +func_8009C67C_jp = 0x8009C67C; // type:func +func_8009C69C_jp = 0x8009C69C; // type:func +func_8009C6EC_jp = 0x8009C6EC; // type:func +func_8009C70C_jp = 0x8009C70C; // type:func +func_8009C780_jp = 0x8009C780; // type:func +func_8009C80C_jp = 0x8009C80C; // type:func +func_8009C89C_jp = 0x8009C89C; // type:func +func_8009C8C0_jp = 0x8009C8C0; // type:func +func_8009C900_jp = 0x8009C900; // type:func +func_8009C9F0_jp = 0x8009C9F0; // type:func +func_8009CA54_jp = 0x8009CA54; // type:func +func_8009CA94_jp = 0x8009CA94; // type:func +func_8009CB5C_jp = 0x8009CB5C; // type:func +func_8009CC00_jp = 0x8009CC00; // type:func +func_8009CC94_jp = 0x8009CC94; // type:func +func_8009CDA8_jp = 0x8009CDA8; // type:func +func_8009CFB0_jp = 0x8009CFB0; // type:func +func_8009CFD4_jp = 0x8009CFD4; // type:func +func_8009D03C_jp = 0x8009D03C; // type:func +func_8009D0CC_jp = 0x8009D0CC; // type:func +func_8009D100_jp = 0x8009D100; // type:func +func_8009D128_jp = 0x8009D128; // type:func +func_8009D160_jp = 0x8009D160; // type:func +func_8009D1A8_jp = 0x8009D1A8; // type:func +func_8009D1F0_jp = 0x8009D1F0; // type:func +func_8009D200_jp = 0x8009D200; // type:func +func_8009D210_jp = 0x8009D210; // type:func +func_8009D260_jp = 0x8009D260; // type:func +func_8009D274_jp = 0x8009D274; // type:func +func_8009D294_jp = 0x8009D294; // type:func +func_8009D2E8_jp = 0x8009D2E8; // type:func +func_8009D308_jp = 0x8009D308; // type:func +func_8009D3B4_jp = 0x8009D3B4; // type:func +func_8009D3E4_jp = 0x8009D3E4; // type:func +func_8009D458_jp = 0x8009D458; // type:func +func_8009D4A0_jp = 0x8009D4A0; // type:func +func_8009D4F0_jp = 0x8009D4F0; // type:func +func_8009D510_jp = 0x8009D510; // type:func +func_8009D530_jp = 0x8009D530; // type:func +func_8009D578_jp = 0x8009D578; // type:func +func_8009D5CC_jp = 0x8009D5CC; // type:func +func_8009D620_jp = 0x8009D620; // type:func +func_8009D640_jp = 0x8009D640; // type:func +func_8009D688_jp = 0x8009D688; // type:func +func_8009D6D0_jp = 0x8009D6D0; // type:func +func_8009D820_jp = 0x8009D820; // type:func +func_8009D88C_jp = 0x8009D88C; // type:func +func_8009D9A4_jp = 0x8009D9A4; // type:func +func_8009DA1C_jp = 0x8009DA1C; // type:func +func_8009DA94_jp = 0x8009DA94; // type:func +func_8009DBA4_jp = 0x8009DBA4; // type:func +func_8009DBB0_jp = 0x8009DBB0; // type:func +func_8009DBE0_jp = 0x8009DBE0; // type:func +func_8009DC04_jp = 0x8009DC04; // type:func +func_8009DC2C_jp = 0x8009DC2C; // type:func +func_8009DCD0_jp = 0x8009DCD0; // type:func +func_8009DD04_jp = 0x8009DD04; // type:func +func_8009DD2C_jp = 0x8009DD2C; // type:func +func_8009DD64_jp = 0x8009DD64; // type:func +func_8009DD8C_jp = 0x8009DD8C; // type:func +func_8009DDB8_jp = 0x8009DDB8; // type:func +func_8009DDE4_jp = 0x8009DDE4; // type:func +func_8009DE28_jp = 0x8009DE28; // type:func +func_8009DE6C_jp = 0x8009DE6C; // type:func +func_8009DE94_jp = 0x8009DE94; // type:func +func_8009DEE8_jp = 0x8009DEE8; // type:func +func_8009DF1C_jp = 0x8009DF1C; // type:func +func_8009DF90_jp = 0x8009DF90; // type:func +func_8009DFBC_jp = 0x8009DFBC; // type:func +func_8009DFF4_jp = 0x8009DFF4; // type:func +func_8009E01C_jp = 0x8009E01C; // type:func +func_8009E084_jp = 0x8009E084; // type:func +func_8009E0B0_jp = 0x8009E0B0; // type:func +func_8009E118_jp = 0x8009E118; // type:func +func_8009E144_jp = 0x8009E144; // type:func +func_8009E17C_jp = 0x8009E17C; // type:func +func_8009E1A4_jp = 0x8009E1A4; // type:func +func_8009E1D0_jp = 0x8009E1D0; // type:func +func_8009E1F8_jp = 0x8009E1F8; // type:func +func_8009E218_jp = 0x8009E218; // type:func +func_8009E264_jp = 0x8009E264; // type:func +func_8009E28C_jp = 0x8009E28C; // type:func +func_8009E2D0_jp = 0x8009E2D0; // type:func +func_8009E338_jp = 0x8009E338; // type:func +func_8009E344_jp = 0x8009E344; // type:func +func_8009E374_jp = 0x8009E374; // type:func +func_8009E388_jp = 0x8009E388; // type:func +func_8009E4C8_jp = 0x8009E4C8; // type:func +func_8009E558_jp = 0x8009E558; // type:func +func_8009E658_jp = 0x8009E658; // type:func +func_8009E6B8_jp = 0x8009E6B8; // type:func +func_8009E6C4_jp = 0x8009E6C4; // type:func +func_8009E6D4_jp = 0x8009E6D4; // type:func +func_8009E6F8_jp = 0x8009E6F8; // type:func +func_8009E8D0_jp = 0x8009E8D0; // type:func +func_8009E908_jp = 0x8009E908; // type:func +func_8009E94C_jp = 0x8009E94C; // type:func +func_8009E970_jp = 0x8009E970; // type:func +func_8009E990_jp = 0x8009E990; // type:func +func_8009E9A4_jp = 0x8009E9A4; // type:func +func_8009E9B4_jp = 0x8009E9B4; // type:func +func_8009E9C0_jp = 0x8009E9C0; // type:func +func_8009E9D0_jp = 0x8009E9D0; // type:func +func_8009E9DC_jp = 0x8009E9DC; // type:func +func_8009E9E8_jp = 0x8009E9E8; // type:func +func_8009E9F8_jp = 0x8009E9F8; // type:func +func_8009EA04_jp = 0x8009EA04; // type:func +func_8009EA18_jp = 0x8009EA18; // type:func +func_8009EA2C_jp = 0x8009EA2C; // type:func +func_8009EB44_jp = 0x8009EB44; // type:func +func_8009EBB0_jp = 0x8009EBB0; // type:func +func_8009EC88_jp = 0x8009EC88; // type:func +func_8009ED14_jp = 0x8009ED14; // type:func +func_8009EDBC_jp = 0x8009EDBC; // type:func +func_8009EE78_jp = 0x8009EE78; // type:func +func_8009EF00_jp = 0x8009EF00; // type:func +func_8009EF88_jp = 0x8009EF88; // type:func +func_8009F010_jp = 0x8009F010; // type:func +func_8009F098_jp = 0x8009F098; // type:func +func_8009F120_jp = 0x8009F120; // type:func +func_8009F1A8_jp = 0x8009F1A8; // type:func +func_8009F230_jp = 0x8009F230; // type:func +func_8009F2EC_jp = 0x8009F2EC; // type:func +func_8009F3A8_jp = 0x8009F3A8; // type:func +func_8009F428_jp = 0x8009F428; // type:func +func_8009F50C_jp = 0x8009F50C; // type:func +func_8009F5B4_jp = 0x8009F5B4; // type:func +func_8009F670_jp = 0x8009F670; // type:func +func_8009F730_jp = 0x8009F730; // type:func +func_8009F75C_jp = 0x8009F75C; // type:func +func_8009F790_jp = 0x8009F790; // type:func +func_8009F7CC_jp = 0x8009F7CC; // type:func +func_8009F800_jp = 0x8009F800; // type:func +func_8009F830_jp = 0x8009F830; // type:func +func_8009F864_jp = 0x8009F864; // type:func +func_8009F8AC_jp = 0x8009F8AC; // type:func +func_8009F9D8_jp = 0x8009F9D8; // type:func +func_8009F9F8_jp = 0x8009F9F8; // type:func +func_8009FA18_jp = 0x8009FA18; // type:func +func_8009FA38_jp = 0x8009FA38; // type:func +func_8009FA58_jp = 0x8009FA58; // type:func +func_8009FAD4_jp = 0x8009FAD4; // type:func +func_8009FB2C_jp = 0x8009FB2C; // type:func +func_8009FB54_jp = 0x8009FB54; // type:func +func_8009FBD8_jp = 0x8009FBD8; // type:func +func_8009FC2C_jp = 0x8009FC2C; // type:func +func_8009FC5C_jp = 0x8009FC5C; // type:func +func_8009FCB8_jp = 0x8009FCB8; // type:func +func_8009FCE0_jp = 0x8009FCE0; // type:func +func_8009FD40_jp = 0x8009FD40; // type:func +func_8009FD80_jp = 0x8009FD80; // type:func +func_8009FDA0_jp = 0x8009FDA0; // type:func +func_8009FDF8_jp = 0x8009FDF8; // type:func +func_8009FE4C_jp = 0x8009FE4C; // type:func +func_8009FE6C_jp = 0x8009FE6C; // type:func +func_8009FE90_jp = 0x8009FE90; // type:func +func_8009FF24_jp = 0x8009FF24; // type:func +func_8009FF68_jp = 0x8009FF68; // type:func +func_8009FFB0_jp = 0x8009FFB0; // type:func +func_800A0110_jp = 0x800A0110; // type:func +func_800A014C_jp = 0x800A014C; // type:func +func_800A0184_jp = 0x800A0184; // type:func +func_800A01C8_jp = 0x800A01C8; // type:func +func_800A03B0_jp = 0x800A03B0; // type:func +func_800A0478_jp = 0x800A0478; // type:func +func_800A04E4_jp = 0x800A04E4; // type:func +func_800A054C_jp = 0x800A054C; // type:func +func_800A05A8_jp = 0x800A05A8; // type:func +func_800A05D8_jp = 0x800A05D8; // type:func +func_800A0614_jp = 0x800A0614; // type:func +func_800A0650_jp = 0x800A0650; // type:func +func_800A06AC_jp = 0x800A06AC; // type:func +func_800A0770_jp = 0x800A0770; // type:func +func_800A07E8_jp = 0x800A07E8; // type:func +func_800A0864_jp = 0x800A0864; // type:func +func_800A08B0_jp = 0x800A08B0; // type:func +func_800A08F8_jp = 0x800A08F8; // type:func +func_800A0964_jp = 0x800A0964; // type:func +func_800A0984_jp = 0x800A0984; // type:func +func_800A09A4_jp = 0x800A09A4; // type:func +func_800A09C4_jp = 0x800A09C4; // type:func +func_800A09E4_jp = 0x800A09E4; // type:func +func_800A0A04_jp = 0x800A0A04; // type:func +func_800A0A60_jp = 0x800A0A60; // type:func +func_800A0B14_jp = 0x800A0B14; // type:func +func_800A0B34_jp = 0x800A0B34; // type:func +func_800A0B54_jp = 0x800A0B54; // type:func +func_800A0B74_jp = 0x800A0B74; // type:func +func_800A0B94_jp = 0x800A0B94; // type:func +func_800A0BB4_jp = 0x800A0BB4; // type:func +func_800A0D94_jp = 0x800A0D94; // type:func +func_800A0DB4_jp = 0x800A0DB4; // type:func +func_800A0DD4_jp = 0x800A0DD4; // type:func +func_800A0DF4_jp = 0x800A0DF4; // type:func +func_800A0FCC_jp = 0x800A0FCC; // type:func +func_800A0FEC_jp = 0x800A0FEC; // type:func +func_800A100C_jp = 0x800A100C; // type:func +func_800A102C_jp = 0x800A102C; // type:func +func_800A1078_jp = 0x800A1078; // type:func +func_800A10D8_jp = 0x800A10D8; // type:func +func_800A1124_jp = 0x800A1124; // type:func +func_800A1170_jp = 0x800A1170; // type:func +func_800A11B4_jp = 0x800A11B4; // type:func +func_800A11F8_jp = 0x800A11F8; // type:func +func_800A123C_jp = 0x800A123C; // type:func +func_800A1280_jp = 0x800A1280; // type:func +func_800A12C4_jp = 0x800A12C4; // type:func +func_800A1308_jp = 0x800A1308; // type:func +func_800A134C_jp = 0x800A134C; // type:func +func_800A1394_jp = 0x800A1394; // type:func +func_800A141C_jp = 0x800A141C; // type:func +func_800A1444_jp = 0x800A1444; // type:func +func_800A1468_jp = 0x800A1468; // type:func +func_800A148C_jp = 0x800A148C; // type:func +func_800A14B4_jp = 0x800A14B4; // type:func +func_800A14DC_jp = 0x800A14DC; // type:func +func_800A1500_jp = 0x800A1500; // type:func +func_800A1528_jp = 0x800A1528; // type:func +func_800A1550_jp = 0x800A1550; // type:func +func_800A1578_jp = 0x800A1578; // type:func +func_800A15A0_jp = 0x800A15A0; // type:func +func_800A15C8_jp = 0x800A15C8; // type:func +func_800A15F0_jp = 0x800A15F0; // type:func +func_800A1618_jp = 0x800A1618; // type:func +func_800A1640_jp = 0x800A1640; // type:func +func_800A1668_jp = 0x800A1668; // type:func +func_800A1690_jp = 0x800A1690; // type:func +func_800A16B8_jp = 0x800A16B8; // type:func +func_800A16E0_jp = 0x800A16E0; // type:func +func_800A1708_jp = 0x800A1708; // type:func +func_800A1730_jp = 0x800A1730; // type:func +func_800A1774_jp = 0x800A1774; // type:func +func_800A17B8_jp = 0x800A17B8; // type:func +func_800A17FC_jp = 0x800A17FC; // type:func +func_800A1844_jp = 0x800A1844; // type:func +func_800A186C_jp = 0x800A186C; // type:func +func_800A1894_jp = 0x800A1894; // type:func +func_800A18BC_jp = 0x800A18BC; // type:func +func_800A18E4_jp = 0x800A18E4; // type:func +func_800A190C_jp = 0x800A190C; // type:func +func_800A1954_jp = 0x800A1954; // type:func +func_800A197C_jp = 0x800A197C; // type:func +func_800A19C4_jp = 0x800A19C4; // type:func +func_800A19E4_jp = 0x800A19E4; // type:func +func_800A1A04_jp = 0x800A1A04; // type:func +func_800A1A24_jp = 0x800A1A24; // type:func +func_800A1A44_jp = 0x800A1A44; // type:func +func_800A1A64_jp = 0x800A1A64; // type:func +func_800A1A84_jp = 0x800A1A84; // type:func +func_800A1AA4_jp = 0x800A1AA4; // type:func +func_800A1AC4_jp = 0x800A1AC4; // type:func +func_800A1AE4_jp = 0x800A1AE4; // type:func +func_800A1B04_jp = 0x800A1B04; // type:func +func_800A1B4C_jp = 0x800A1B4C; // type:func +func_800A1B6C_jp = 0x800A1B6C; // type:func +func_800A1B8C_jp = 0x800A1B8C; // type:func +func_800A1BAC_jp = 0x800A1BAC; // type:func +func_800A1BCC_jp = 0x800A1BCC; // type:func +func_800A1BEC_jp = 0x800A1BEC; // type:func +func_800A1C24_jp = 0x800A1C24; // type:func +func_800A1CA4_jp = 0x800A1CA4; // type:func +func_800A1CDC_jp = 0x800A1CDC; // type:func +func_800A1D14_jp = 0x800A1D14; // type:func +func_800A1D4C_jp = 0x800A1D4C; // type:func +func_800A1DD0_jp = 0x800A1DD0; // type:func +func_800A1E38_jp = 0x800A1E38; // type:func +func_800A1EA0_jp = 0x800A1EA0; // type:func +func_800A1F1C_jp = 0x800A1F1C; // type:func +func_800A1F7C_jp = 0x800A1F7C; // type:func +func_800A1FB4_jp = 0x800A1FB4; // type:func +func_800A2000_jp = 0x800A2000; // type:func +func_800A204C_jp = 0x800A204C; // type:func +func_800A2098_jp = 0x800A2098; // type:func +func_800A20E0_jp = 0x800A20E0; // type:func +func_800A2150_jp = 0x800A2150; // type:func +func_800A21C0_jp = 0x800A21C0; // type:func +func_800A223C_jp = 0x800A223C; // type:func +func_800A24A8_jp = 0x800A24A8; // type:func +func_800A24D0_jp = 0x800A24D0; // type:func +func_800A2538_jp = 0x800A2538; // type:func +func_800A2588_jp = 0x800A2588; // type:func +func_800A2620_jp = 0x800A2620; // type:func +func_800A2648_jp = 0x800A2648; // type:func +func_800A268C_jp = 0x800A268C; // type:func +func_800A272C_jp = 0x800A272C; // type:func +func_800A2784_jp = 0x800A2784; // type:func +func_800A27FC_jp = 0x800A27FC; // type:func +func_800A287C_jp = 0x800A287C; // type:func +func_800A289C_jp = 0x800A289C; // type:func +func_800A28DC_jp = 0x800A28DC; // type:func +func_800A2904_jp = 0x800A2904; // type:func +func_800A2948_jp = 0x800A2948; // type:func +func_800A29B0_jp = 0x800A29B0; // type:func +func_800A2AB0_jp = 0x800A2AB0; // type:func +func_800A2AD0_jp = 0x800A2AD0; // type:func +func_800A2BB0_jp = 0x800A2BB0; // type:func +func_800A2C4C_jp = 0x800A2C4C; // type:func +func_800A2CE4_jp = 0x800A2CE4; // type:func +func_800A2EAC_jp = 0x800A2EAC; // type:func +func_800A3190_jp = 0x800A3190; // type:func +func_800A31D8_jp = 0x800A31D8; // type:func +func_800A3220_jp = 0x800A3220; // type:func +func_800A32D0_jp = 0x800A32D0; // type:func +func_800A3304_jp = 0x800A3304; // type:func +func_800A332C_jp = 0x800A332C; // type:func +func_800A339C_jp = 0x800A339C; // type:func +func_800A33D8_jp = 0x800A33D8; // type:func +func_800A3400_jp = 0x800A3400; // type:func +func_800A3420_jp = 0x800A3420; // type:func +func_800A345C_jp = 0x800A345C; // type:func +func_800A34E8_jp = 0x800A34E8; // type:func +func_800A35C8_jp = 0x800A35C8; // type:func +func_800A3658_jp = 0x800A3658; // type:func +func_800A36CC_jp = 0x800A36CC; // type:func +func_800A3784_jp = 0x800A3784; // type:func +func_800A37D0_jp = 0x800A37D0; // type:func +func_800A3810_jp = 0x800A3810; // type:func +func_800A3A5C_jp = 0x800A3A5C; // type:func +func_800A3B84_jp = 0x800A3B84; // type:func +func_800A3C18_jp = 0x800A3C18; // type:func +func_800A3CF0_jp = 0x800A3CF0; // type:func +func_800A3E34_jp = 0x800A3E34; // type:func +func_800A3F70_jp = 0x800A3F70; // type:func +func_800A3FB4_jp = 0x800A3FB4; // type:func +func_800A4184_jp = 0x800A4184; // type:func +func_800A41BC_jp = 0x800A41BC; // type:func +func_800A4254_jp = 0x800A4254; // type:func +func_800A43C0_jp = 0x800A43C0; // type:func +func_800A4448_jp = 0x800A4448; // type:func +func_800A44D4_jp = 0x800A44D4; // type:func +func_800A4508_jp = 0x800A4508; // type:func +func_800A456C_jp = 0x800A456C; // type:func +func_800A4614_jp = 0x800A4614; // type:func +func_800A46F0_jp = 0x800A46F0; // type:func +func_800A49E8_jp = 0x800A49E8; // type:func +func_800A4A84_jp = 0x800A4A84; // type:func +func_800A4B00_jp = 0x800A4B00; // type:func +func_800A4D10_jp = 0x800A4D10; // type:func +func_800A4DC8_jp = 0x800A4DC8; // type:func +func_800A4E74_jp = 0x800A4E74; // type:func +func_800A4F38_jp = 0x800A4F38; // type:func +func_800A4FD0_jp = 0x800A4FD0; // type:func +func_800A50AC_jp = 0x800A50AC; // type:func +func_800A518C_jp = 0x800A518C; // type:func +func_800A524C_jp = 0x800A524C; // type:func +func_800A5460_jp = 0x800A5460; // type:func +func_800A5630_jp = 0x800A5630; // type:func +func_800A56CC_jp = 0x800A56CC; // type:func +func_800A56F0_jp = 0x800A56F0; // type:func +func_800A5970_jp = 0x800A5970; // type:func +func_800A5A0C_jp = 0x800A5A0C; // type:func +func_800A5AC8_jp = 0x800A5AC8; // type:func +func_800A5B50_jp = 0x800A5B50; // type:func +func_800A5BC4_jp = 0x800A5BC4; // type:func +func_800A5CB0_jp = 0x800A5CB0; // type:func +func_800A5D30_jp = 0x800A5D30; // type:func +func_800A5DF4_jp = 0x800A5DF4; // type:func +func_800A5E58_jp = 0x800A5E58; // type:func +func_800A5F08_jp = 0x800A5F08; // type:func +func_800A62EC_jp = 0x800A62EC; // type:func +func_800A6384_jp = 0x800A6384; // type:func +func_800A63F8_jp = 0x800A63F8; // type:func +func_800A6450_jp = 0x800A6450; // type:func +func_800A6548_jp = 0x800A6548; // type:func +func_800A65C4_jp = 0x800A65C4; // type:func +func_800A6810_jp = 0x800A6810; // type:func +func_800A6920_jp = 0x800A6920; // type:func +func_800A6940_jp = 0x800A6940; // type:func +func_800A695C_jp = 0x800A695C; // type:func +func_800A6978_jp = 0x800A6978; // type:func +func_800A69C8_jp = 0x800A69C8; // type:func +func_800A6A04_jp = 0x800A6A04; // type:func +func_800A6A6C_jp = 0x800A6A6C; // type:func +func_800A6AF0_jp = 0x800A6AF0; // type:func +func_800A6B58_jp = 0x800A6B58; // type:func +func_800A6B6C_jp = 0x800A6B6C; // type:func +func_800A6B7C_jp = 0x800A6B7C; // type:func +func_800A6B9C_jp = 0x800A6B9C; // type:func +func_800A6BC8_jp = 0x800A6BC8; // type:func +func_800A6C1C_jp = 0x800A6C1C; // type:func +func_800A6C84_jp = 0x800A6C84; // type:func +func_800A6CE4_jp = 0x800A6CE4; // type:func +func_800A6D04_jp = 0x800A6D04; // type:func +func_800A6DB0_jp = 0x800A6DB0; // type:func +func_800A6DD0_jp = 0x800A6DD0; // type:func +func_800A6E0C_jp = 0x800A6E0C; // type:func +func_800A6E40_jp = 0x800A6E40; // type:func +func_800A6F48_jp = 0x800A6F48; // type:func +func_800A6FF4_jp = 0x800A6FF4; // type:func +func_800A706C_jp = 0x800A706C; // type:func +func_800A71AC_jp = 0x800A71AC; // type:func +func_800A71F8_jp = 0x800A71F8; // type:func +func_800A7238_jp = 0x800A7238; // type:func +func_800A72C0_jp = 0x800A72C0; // type:func +func_800A73D8_jp = 0x800A73D8; // type:func +func_800A74A0_jp = 0x800A74A0; // type:func +func_800A7530_jp = 0x800A7530; // type:func +func_800A75FC_jp = 0x800A75FC; // type:func +func_800A76E4_jp = 0x800A76E4; // type:func +func_800A77F0_jp = 0x800A77F0; // type:func +func_800A7858_jp = 0x800A7858; // type:func +func_800A78DC_jp = 0x800A78DC; // type:func +func_800A7A04_jp = 0x800A7A04; // type:func +func_800A7A9C_jp = 0x800A7A9C; // type:func +func_800A7AEC_jp = 0x800A7AEC; // type:func +func_800A7B34_jp = 0x800A7B34; // type:func +func_800A7BAC_jp = 0x800A7BAC; // type:func +func_800A7C10_jp = 0x800A7C10; // type:func +func_800A7C30_jp = 0x800A7C30; // type:func +func_800A7C94_jp = 0x800A7C94; // type:func +func_800A7D08_jp = 0x800A7D08; // type:func +func_800A7DA0_jp = 0x800A7DA0; // type:func +func_800A80B0_jp = 0x800A80B0; // type:func +func_800A80D8_jp = 0x800A80D8; // type:func +func_800A8148_jp = 0x800A8148; // type:func +func_800A820C_jp = 0x800A820C; // type:func +func_800A82C8_jp = 0x800A82C8; // type:func +func_800A8344_jp = 0x800A8344; // type:func +func_800A83F0_jp = 0x800A83F0; // type:func +func_800A845C_jp = 0x800A845C; // type:func +func_800A8614_jp = 0x800A8614; // type:func +func_800A86C4_jp = 0x800A86C4; // type:func +func_800A86E8_jp = 0x800A86E8; // type:func +func_800A8764_jp = 0x800A8764; // type:func +func_800A8814_jp = 0x800A8814; // type:func +func_800A8868_jp = 0x800A8868; // type:func +func_800A8AB4_jp = 0x800A8AB4; // type:func +func_800A8B10_jp = 0x800A8B10; // type:func +func_800A8B84_jp = 0x800A8B84; // type:func +func_800A8C48_jp = 0x800A8C48; // type:func +func_800A8DB4_jp = 0x800A8DB4; // type:func +func_800A8F30_jp = 0x800A8F30; // type:func +func_800A9028_jp = 0x800A9028; // type:func +func_800A9110_jp = 0x800A9110; // type:func +func_800A918C_jp = 0x800A918C; // type:func +func_800A91DC_jp = 0x800A91DC; // type:func +func_800A9364_jp = 0x800A9364; // type:func +func_800A93AC_jp = 0x800A93AC; // type:func +func_800A9468_jp = 0x800A9468; // type:func +func_800A94C8_jp = 0x800A94C8; // type:func +func_800A956C_jp = 0x800A956C; // type:func +func_800A96B0_jp = 0x800A96B0; // type:func +func_800A9780_jp = 0x800A9780; // type:func +func_800A992C_jp = 0x800A992C; // type:func +func_800A99B8_jp = 0x800A99B8; // type:func +func_800A9A98_jp = 0x800A9A98; // type:func +func_800A9BC4_jp = 0x800A9BC4; // type:func +func_800A9BD4_jp = 0x800A9BD4; // type:func +func_800A9CD4_jp = 0x800A9CD4; // type:func +func_800A9D68_jp = 0x800A9D68; // type:func +func_800A9E54_jp = 0x800A9E54; // type:func +func_800A9E7C_jp = 0x800A9E7C; // type:func +func_800A9EC8_jp = 0x800A9EC8; // type:func +func_800A9F9C_jp = 0x800A9F9C; // type:func +func_800AA028_jp = 0x800AA028; // type:func +func_800AA0B8_jp = 0x800AA0B8; // type:func +func_800AA124_jp = 0x800AA124; // type:func +func_800AA14C_jp = 0x800AA14C; // type:func +func_800AA1E0_jp = 0x800AA1E0; // type:func +func_800AA218_jp = 0x800AA218; // type:func +func_800AA29C_jp = 0x800AA29C; // type:func +func_800AA2F8_jp = 0x800AA2F8; // type:func +func_800AA35C_jp = 0x800AA35C; // type:func +func_800AA3A4_jp = 0x800AA3A4; // type:func +func_800AA438_jp = 0x800AA438; // type:func +func_800AA49C_jp = 0x800AA49C; // type:func +func_800AA4FC_jp = 0x800AA4FC; // type:func +func_800AA51C_jp = 0x800AA51C; // type:func +func_800AA790_jp = 0x800AA790; // type:func +func_800AA8C4_jp = 0x800AA8C4; // type:func +func_800AA9F4_jp = 0x800AA9F4; // type:func +func_800AAA40_jp = 0x800AAA40; // type:func +func_800AAB48_jp = 0x800AAB48; // type:func +func_800AAC88_jp = 0x800AAC88; // type:func +func_800AADE8_jp = 0x800AADE8; // type:func +func_800AAEFC_jp = 0x800AAEFC; // type:func +func_800AB054_jp = 0x800AB054; // type:func +func_800AB09C_jp = 0x800AB09C; // type:func +func_800AB134_jp = 0x800AB134; // type:func +func_800AB3A0_jp = 0x800AB3A0; // type:func +func_800AB498_jp = 0x800AB498; // type:func +func_800AB62C_jp = 0x800AB62C; // type:func +func_800AB6C8_jp = 0x800AB6C8; // type:func +func_800AB734_jp = 0x800AB734; // type:func +func_800AB7D0_jp = 0x800AB7D0; // type:func +func_800AB80C_jp = 0x800AB80C; // type:func +func_800AB8A0_jp = 0x800AB8A0; // type:func +func_800ABA14_jp = 0x800ABA14; // type:func +func_800ABAA8_jp = 0x800ABAA8; // type:func +func_800ABAF0_jp = 0x800ABAF0; // type:func +func_800ABB14_jp = 0x800ABB14; // type:func +func_800ABB24_jp = 0x800ABB24; // type:func +func_800ABCF8_jp = 0x800ABCF8; // type:func +func_800ABD90_jp = 0x800ABD90; // type:func +func_800ABE30_jp = 0x800ABE30; // type:func +func_800ABF40_jp = 0x800ABF40; // type:func +func_800AC1A0_jp = 0x800AC1A0; // type:func +func_800AC1C8_jp = 0x800AC1C8; // type:func +func_800AC1EC_jp = 0x800AC1EC; // type:func +func_800AC284_jp = 0x800AC284; // type:func +func_800AC358_jp = 0x800AC358; // type:func +func_800AC488_jp = 0x800AC488; // type:func +func_800AC558_jp = 0x800AC558; // type:func +func_800AC57C_jp = 0x800AC57C; // type:func +func_800AC804_jp = 0x800AC804; // type:func +func_800AC898_jp = 0x800AC898; // type:func +func_800ACB24_jp = 0x800ACB24; // type:func +func_800ACB54_jp = 0x800ACB54; // type:func +func_800ACC38_jp = 0x800ACC38; // type:func +func_800ACCAC_jp = 0x800ACCAC; // type:func +func_800ACD18_jp = 0x800ACD18; // type:func +func_800ACD74_jp = 0x800ACD74; // type:func +func_800ACDF8_jp = 0x800ACDF8; // type:func +func_800ACE90_jp = 0x800ACE90; // type:func +func_800ACF84_jp = 0x800ACF84; // type:func +func_800AD084_jp = 0x800AD084; // type:func +func_800AD0B8_jp = 0x800AD0B8; // type:func +func_800AD104_jp = 0x800AD104; // type:func +func_800AD154_jp = 0x800AD154; // type:func +func_800AD188_jp = 0x800AD188; // type:func +func_800AD1E0_jp = 0x800AD1E0; // type:func +func_800AD22C_jp = 0x800AD22C; // type:func +func_800AD2B8_jp = 0x800AD2B8; // type:func +func_800AD2C4_jp = 0x800AD2C4; // type:func +func_800AD338_jp = 0x800AD338; // type:func +func_800AD3BC_jp = 0x800AD3BC; // type:func +func_800AD4B8_jp = 0x800AD4B8; // type:func +func_800AD614_jp = 0x800AD614; // type:func +func_800AD6D4_jp = 0x800AD6D4; // type:func +func_800AD8C4_jp = 0x800AD8C4; // type:func +func_800AD954_jp = 0x800AD954; // type:func +func_800AD9FC_jp = 0x800AD9FC; // type:func +func_800ADBE4_jp = 0x800ADBE4; // type:func +func_800ADC28_jp = 0x800ADC28; // type:func +func_800ADC8C_jp = 0x800ADC8C; // type:func +func_800ADD20_jp = 0x800ADD20; // type:func +func_800ADEFC_jp = 0x800ADEFC; // type:func +func_800AE110_jp = 0x800AE110; // type:func +func_800AE134_jp = 0x800AE134; // type:func +func_800AE1A0_jp = 0x800AE1A0; // type:func +func_800AE1B8_jp = 0x800AE1B8; // type:func +func_800AE1D8_jp = 0x800AE1D8; // type:func +func_800AE23C_jp = 0x800AE23C; // type:func +func_800AE284_jp = 0x800AE284; // type:func +func_800AE2E8_jp = 0x800AE2E8; // type:func +func_800AE320_jp = 0x800AE320; // type:func +func_800AE37C_jp = 0x800AE37C; // type:func +func_800AE3B4_jp = 0x800AE3B4; // type:func +func_800AE4B4_jp = 0x800AE4B4; // type:func +func_800AE558_jp = 0x800AE558; // type:func +func_800AE5C8_jp = 0x800AE5C8; // type:func +func_800AE64C_jp = 0x800AE64C; // type:func +func_800AE670_jp = 0x800AE670; // type:func +func_800AE694_jp = 0x800AE694; // type:func +func_800AE6B0_jp = 0x800AE6B0; // type:func +func_800AE6CC_jp = 0x800AE6CC; // type:func +func_800AE76C_jp = 0x800AE76C; // type:func +func_800AE898_jp = 0x800AE898; // type:func +func_800AE8C8_jp = 0x800AE8C8; // type:func +func_800AEA80_jp = 0x800AEA80; // type:func +func_800AEB50_jp = 0x800AEB50; // type:func +func_800AEB9C_jp = 0x800AEB9C; // type:func +func_800AEBC8_jp = 0x800AEBC8; // type:func +func_800AEC74_jp = 0x800AEC74; // type:func +func_800AED08_jp = 0x800AED08; // type:func +func_800AED68_jp = 0x800AED68; // type:func +func_800AEDD0_jp = 0x800AEDD0; // type:func +func_800AEE38_jp = 0x800AEE38; // type:func +func_800AEE50_jp = 0x800AEE50; // type:func +func_800AEEE8_jp = 0x800AEEE8; // type:func +func_800AEF1C_jp = 0x800AEF1C; // type:func +func_800AEF4C_jp = 0x800AEF4C; // type:func +func_800AEFC4_jp = 0x800AEFC4; // type:func +func_800AF060_jp = 0x800AF060; // type:func +func_800AF0A8_jp = 0x800AF0A8; // type:func +func_800AF1E0_jp = 0x800AF1E0; // type:func +func_800AF2A8_jp = 0x800AF2A8; // type:func +func_800AF3E8_jp = 0x800AF3E8; // type:func +func_800AF614_jp = 0x800AF614; // type:func +func_800AF7BC_jp = 0x800AF7BC; // type:func +func_800AF84C_jp = 0x800AF84C; // type:func +func_800AF9C8_jp = 0x800AF9C8; // type:func +func_800AFA1C_jp = 0x800AFA1C; // type:func +func_800AFAF8_jp = 0x800AFAF8; // type:func +func_800AFC1C_jp = 0x800AFC1C; // type:func +func_800AFCAC_jp = 0x800AFCAC; // type:func +func_800AFCD8_jp = 0x800AFCD8; // type:func +func_800AFDA8_jp = 0x800AFDA8; // type:func +func_800B0010_jp = 0x800B0010; // type:func +func_800B0080_jp = 0x800B0080; // type:func +func_800B00C4_jp = 0x800B00C4; // type:func +func_800B0120_jp = 0x800B0120; // type:func +func_800B0154_jp = 0x800B0154; // type:func +func_800B01BC_jp = 0x800B01BC; // type:func +func_800B0224_jp = 0x800B0224; // type:func +func_800B02D4_jp = 0x800B02D4; // type:func +func_800B0380_jp = 0x800B0380; // type:func +func_800B03C4_jp = 0x800B03C4; // type:func +func_800B0518_jp = 0x800B0518; // type:func +func_800B0560_jp = 0x800B0560; // type:func +func_800B05B4_jp = 0x800B05B4; // type:func +func_800B0608_jp = 0x800B0608; // type:func +func_800B0698_jp = 0x800B0698; // type:func +func_800B0700_jp = 0x800B0700; // type:func +func_800B07A0_jp = 0x800B07A0; // type:func +func_800B07B0_jp = 0x800B07B0; // type:func +func_800B0850_jp = 0x800B0850; // type:func +func_800B0890_jp = 0x800B0890; // type:func +func_800B08BC_jp = 0x800B08BC; // type:func +func_800B0978_jp = 0x800B0978; // type:func +func_800B0AD0_jp = 0x800B0AD0; // type:func +func_800B0BAC_jp = 0x800B0BAC; // type:func +func_800B0BD8_jp = 0x800B0BD8; // type:func +func_800B0C40_jp = 0x800B0C40; // type:func +func_800B0CD4_jp = 0x800B0CD4; // type:func +func_800B0D78_jp = 0x800B0D78; // type:func +func_800B0DC4_jp = 0x800B0DC4; // type:func +func_800B0E48_jp = 0x800B0E48; // type:func +func_800B0EE8_jp = 0x800B0EE8; // type:func +func_800B0F1C_jp = 0x800B0F1C; // type:func +func_800B0FC0_jp = 0x800B0FC0; // type:func +func_800B1048_jp = 0x800B1048; // type:func +func_800B1094_jp = 0x800B1094; // type:func +func_800B10D8_jp = 0x800B10D8; // type:func +func_800B111C_jp = 0x800B111C; // type:func +func_800B1160_jp = 0x800B1160; // type:func +func_800B11B0_jp = 0x800B11B0; // type:func +func_800B11F8_jp = 0x800B11F8; // type:func +func_800B1264_jp = 0x800B1264; // type:func +func_800B12A0_jp = 0x800B12A0; // type:func +func_800B12C8_jp = 0x800B12C8; // type:func +func_800B12F4_jp = 0x800B12F4; // type:func +func_800B131C_jp = 0x800B131C; // type:func +func_800B1364_jp = 0x800B1364; // type:func +func_800B1384_jp = 0x800B1384; // type:func +func_800B1410_jp = 0x800B1410; // type:func +func_800B149C_jp = 0x800B149C; // type:func +func_800B14BC_jp = 0x800B14BC; // type:func +func_800B1590_jp = 0x800B1590; // type:func +func_800B1614_jp = 0x800B1614; // type:func +func_800B1650_jp = 0x800B1650; // type:func +func_800B167C_jp = 0x800B167C; // type:func +func_800B16D0_jp = 0x800B16D0; // type:func +func_800B16F8_jp = 0x800B16F8; // type:func +func_800B1784_jp = 0x800B1784; // type:func +func_800B1838_jp = 0x800B1838; // type:func +func_800B190C_jp = 0x800B190C; // type:func +func_800B1944_jp = 0x800B1944; // type:func +func_800B1960_jp = 0x800B1960; // type:func +func_800B19C4_jp = 0x800B19C4; // type:func +func_800B1A28_jp = 0x800B1A28; // type:func +func_800B1A60_jp = 0x800B1A60; // type:func +func_800B1AA0_jp = 0x800B1AA0; // type:func +func_800B1AE0_jp = 0x800B1AE0; // type:func +func_800B1B3C_jp = 0x800B1B3C; // type:func +func_800B1B6C_jp = 0x800B1B6C; // type:func +func_800B1BB8_jp = 0x800B1BB8; // type:func +func_800B1BE8_jp = 0x800B1BE8; // type:func +func_800B1C84_jp = 0x800B1C84; // type:func +func_800B1C90_jp = 0x800B1C90; // type:func +func_800B1CBC_jp = 0x800B1CBC; // type:func +func_800B1CE0_jp = 0x800B1CE0; // type:func +func_800B1D14_jp = 0x800B1D14; // type:func +func_800B1D40_jp = 0x800B1D40; // type:func +func_800B1D68_jp = 0x800B1D68; // type:func +func_800B1D94_jp = 0x800B1D94; // type:func +func_800B1DE8_jp = 0x800B1DE8; // type:func +func_800B1E94_jp = 0x800B1E94; // type:func +func_800B1EB0_jp = 0x800B1EB0; // type:func +func_800B1EDC_jp = 0x800B1EDC; // type:func +func_800B1F74_jp = 0x800B1F74; // type:func +func_800B1F84_jp = 0x800B1F84; // type:func +func_800B1FAC_jp = 0x800B1FAC; // type:func +func_800B2008_jp = 0x800B2008; // type:func +func_800B2060_jp = 0x800B2060; // type:func +func_800B20A8_jp = 0x800B20A8; // type:func +func_800B2170_jp = 0x800B2170; // type:func +func_800B21A0_jp = 0x800B21A0; // type:func +func_800B21D0_jp = 0x800B21D0; // type:func +func_800B21E0_jp = 0x800B21E0; // type:func +func_800B21F0_jp = 0x800B21F0; // type:func +func_800B2244_jp = 0x800B2244; // type:func +func_800B2284_jp = 0x800B2284; // type:func +func_800B22A4_jp = 0x800B22A4; // type:func +func_800B22D0_jp = 0x800B22D0; // type:func +func_800B22FC_jp = 0x800B22FC; // type:func +func_800B2350_jp = 0x800B2350; // type:func +func_800B23A4_jp = 0x800B23A4; // type:func +func_800B23DC_jp = 0x800B23DC; // type:func +func_800B2414_jp = 0x800B2414; // type:func +func_800B2450_jp = 0x800B2450; // type:func +func_800B24A0_jp = 0x800B24A0; // type:func +func_800B24F8_jp = 0x800B24F8; // type:func +func_800B255C_jp = 0x800B255C; // type:func +func_800B25F4_jp = 0x800B25F4; // type:func +func_800B2698_jp = 0x800B2698; // type:func +func_800B26E8_jp = 0x800B26E8; // type:func +func_800B2720_jp = 0x800B2720; // type:func +func_800B2778_jp = 0x800B2778; // type:func +func_800B27B0_jp = 0x800B27B0; // type:func +func_800B2814_jp = 0x800B2814; // type:func +func_800B286C_jp = 0x800B286C; // type:func +func_800B28B0_jp = 0x800B28B0; // type:func +func_800B2908_jp = 0x800B2908; // type:func +func_800B2A04_jp = 0x800B2A04; // type:func +func_800B2A48_jp = 0x800B2A48; // type:func +func_800B2A8C_jp = 0x800B2A8C; // type:func +func_800B2AD0_jp = 0x800B2AD0; // type:func +func_800B2B08_jp = 0x800B2B08; // type:func +func_800B2B60_jp = 0x800B2B60; // type:func +func_800B2BA0_jp = 0x800B2BA0; // type:func +func_800B2BE0_jp = 0x800B2BE0; // type:func +func_800B2C3C_jp = 0x800B2C3C; // type:func +func_800B2C80_jp = 0x800B2C80; // type:func +func_800B2CD8_jp = 0x800B2CD8; // type:func +func_800B2D18_jp = 0x800B2D18; // type:func +func_800B2D74_jp = 0x800B2D74; // type:func +func_800B2DAC_jp = 0x800B2DAC; // type:func +func_800B2EBC_jp = 0x800B2EBC; // type:func +func_800B2F1C_jp = 0x800B2F1C; // type:func +func_800B2F7C_jp = 0x800B2F7C; // type:func +func_800B2FDC_jp = 0x800B2FDC; // type:func +func_800B30A4_jp = 0x800B30A4; // type:func +func_800B3104_jp = 0x800B3104; // type:func +func_800B314C_jp = 0x800B314C; // type:func +func_800B31B4_jp = 0x800B31B4; // type:func +func_800B321C_jp = 0x800B321C; // type:func +func_800B3284_jp = 0x800B3284; // type:func +func_800B32EC_jp = 0x800B32EC; // type:func +func_800B32FC_jp = 0x800B32FC; // type:func +func_800B3330_jp = 0x800B3330; // type:func +func_800B33AC_jp = 0x800B33AC; // type:func +func_800B3408_jp = 0x800B3408; // type:func +func_800B34B8_jp = 0x800B34B8; // type:func +func_800B34F4_jp = 0x800B34F4; // type:func +func_800B3534_jp = 0x800B3534; // type:func +func_800B3588_jp = 0x800B3588; // type:func +func_800B35E4_jp = 0x800B35E4; // type:func +func_800B3660_jp = 0x800B3660; // type:func +func_800B36E0_jp = 0x800B36E0; // type:func +func_800B370C_jp = 0x800B370C; // type:func +func_800B3730_jp = 0x800B3730; // type:func +func_800B375C_jp = 0x800B375C; // type:func +func_800B3780_jp = 0x800B3780; // type:func +func_800B37AC_jp = 0x800B37AC; // type:func +func_800B3864_jp = 0x800B3864; // type:func +func_800B3A48_jp = 0x800B3A48; // type:func +func_800B3A60_jp = 0x800B3A60; // type:func +func_800B3A74_jp = 0x800B3A74; // type:func +func_800B3A84_jp = 0x800B3A84; // type:func +func_800B3AD4_jp = 0x800B3AD4; // type:func +func_800B3B24_jp = 0x800B3B24; // type:func +func_800B3B74_jp = 0x800B3B74; // type:func +func_800B3BBC_jp = 0x800B3BBC; // type:func +func_800B3C14_jp = 0x800B3C14; // type:func +func_800B3C64_jp = 0x800B3C64; // type:func +func_800B3CB4_jp = 0x800B3CB4; // type:func +func_800B3CDC_jp = 0x800B3CDC; // type:func +func_800B3DD0_jp = 0x800B3DD0; // type:func +func_800B3F30_jp = 0x800B3F30; // type:func +func_800B4038_jp = 0x800B4038; // type:func +func_800B553C_jp = 0x800B553C; // type:func +func_800B5598_jp = 0x800B5598; // type:func +func_800B55D0_jp = 0x800B55D0; // type:func +func_800B5620_jp = 0x800B5620; // type:func +func_800B5678_jp = 0x800B5678; // type:func +func_800B56A4_jp = 0x800B56A4; // type:func +func_800B56D0_jp = 0x800B56D0; // type:func +func_800B5718_jp = 0x800B5718; // type:func +func_800B5760_jp = 0x800B5760; // type:func +func_800B579C_jp = 0x800B579C; // type:func +func_800B57D8_jp = 0x800B57D8; // type:func +func_800B5830_jp = 0x800B5830; // type:func +func_800B5880_jp = 0x800B5880; // type:func +func_800B58C4_jp = 0x800B58C4; // type:func +func_800B5910_jp = 0x800B5910; // type:func +func_800B593C_jp = 0x800B593C; // type:func +func_800B594C_jp = 0x800B594C; // type:func +func_800B5980_jp = 0x800B5980; // type:func +func_800B5AA0_jp = 0x800B5AA0; // type:func +func_800B5AB8_jp = 0x800B5AB8; // type:func +func_800B5B1C_jp = 0x800B5B1C; // type:func +func_800B5B70_jp = 0x800B5B70; // type:func +func_800B5BC0_jp = 0x800B5BC0; // type:func +func_800B5C10_jp = 0x800B5C10; // type:func +func_800B5C60_jp = 0x800B5C60; // type:func +func_800B5CD4_jp = 0x800B5CD4; // type:func +func_800B5D34_jp = 0x800B5D34; // type:func +func_800B5DA8_jp = 0x800B5DA8; // type:func +func_800B5DEC_jp = 0x800B5DEC; // type:func +func_800B5E30_jp = 0x800B5E30; // type:func +func_800B5EA4_jp = 0x800B5EA4; // type:func +func_800B5F18_jp = 0x800B5F18; // type:func +func_800B5FD0_jp = 0x800B5FD0; // type:func +func_800B6074_jp = 0x800B6074; // type:func +func_800B60E0_jp = 0x800B60E0; // type:func +func_800B6170_jp = 0x800B6170; // type:func +func_800B61E8_jp = 0x800B61E8; // type:func +func_800B62B0_jp = 0x800B62B0; // type:func +func_800B6474_jp = 0x800B6474; // type:func +func_800B6520_jp = 0x800B6520; // type:func +func_800B6564_jp = 0x800B6564; // type:func +func_800B6618_jp = 0x800B6618; // type:func +func_800B6640_jp = 0x800B6640; // type:func +func_800B66CC_jp = 0x800B66CC; // type:func +func_800B6718_jp = 0x800B6718; // type:func +func_800B67C0_jp = 0x800B67C0; // type:func +func_800B6838_jp = 0x800B6838; // type:func +func_800B68E8_jp = 0x800B68E8; // type:func +func_800B690C_jp = 0x800B690C; // type:func +func_800B6A3C_jp = 0x800B6A3C; // type:func +func_800B6AC8_jp = 0x800B6AC8; // type:func +func_800B6B94_jp = 0x800B6B94; // type:func +func_800B6C14_jp = 0x800B6C14; // type:func +func_800B6C88_jp = 0x800B6C88; // type:func +func_800B6D40_jp = 0x800B6D40; // type:func +func_800B6D80_jp = 0x800B6D80; // type:func +func_800B6DCC_jp = 0x800B6DCC; // type:func +func_800B6EBC_jp = 0x800B6EBC; // type:func +func_800B6FD4_jp = 0x800B6FD4; // type:func +func_800B702C_jp = 0x800B702C; // type:func +func_800B706C_jp = 0x800B706C; // type:func +func_800B7164_jp = 0x800B7164; // type:func +func_800B71D4_jp = 0x800B71D4; // type:func +func_800B7218_jp = 0x800B7218; // type:func +func_800B72B8_jp = 0x800B72B8; // type:func +func_800B7328_jp = 0x800B7328; // type:func +func_800B7350_jp = 0x800B7350; // type:func +func_800B7468_jp = 0x800B7468; // type:func +func_800B74E8_jp = 0x800B74E8; // type:func +func_800B7560_jp = 0x800B7560; // type:func +func_800B7624_jp = 0x800B7624; // type:func +func_800B7680_jp = 0x800B7680; // type:func +func_800B7700_jp = 0x800B7700; // type:func +func_800B7780_jp = 0x800B7780; // type:func +func_800B77A4_jp = 0x800B77A4; // type:func +func_800B77C4_jp = 0x800B77C4; // type:func +func_800B7804_jp = 0x800B7804; // type:func +func_800B785C_jp = 0x800B785C; // type:func +func_800B7914_jp = 0x800B7914; // type:func +func_800B795C_jp = 0x800B795C; // type:func +func_800B7998_jp = 0x800B7998; // type:func +func_800B79E0_jp = 0x800B79E0; // type:func +func_800B7A00_jp = 0x800B7A00; // type:func +func_800B7A94_jp = 0x800B7A94; // type:func +func_800B7AB0_jp = 0x800B7AB0; // type:func +func_800B7ADC_jp = 0x800B7ADC; // type:func +func_800B7B8C_jp = 0x800B7B8C; // type:func +func_800B7BC0_jp = 0x800B7BC0; // type:func +func_800B7CD0_jp = 0x800B7CD0; // type:func +func_800B7D50_jp = 0x800B7D50; // type:func +func_800B7D90_jp = 0x800B7D90; // type:func +func_800B7F00_jp = 0x800B7F00; // type:func +func_800B7F48_jp = 0x800B7F48; // type:func +func_800B7F78_jp = 0x800B7F78; // type:func +func_800B7FA0_jp = 0x800B7FA0; // type:func +func_800B7FD4_jp = 0x800B7FD4; // type:func +func_800B8068_jp = 0x800B8068; // type:func +func_800B80B4_jp = 0x800B80B4; // type:func +func_800B8128_jp = 0x800B8128; // type:func +func_800B81A4_jp = 0x800B81A4; // type:func +func_800B8204_jp = 0x800B8204; // type:func +func_800B828C_jp = 0x800B828C; // type:func +func_800B8318_jp = 0x800B8318; // type:func +func_800B83D4_jp = 0x800B83D4; // type:func +func_800B8544_jp = 0x800B8544; // type:func +func_800B86EC_jp = 0x800B86EC; // type:func +func_800B88EC_jp = 0x800B88EC; // type:func +func_800B8A88_jp = 0x800B8A88; // type:func +func_800B8B08_jp = 0x800B8B08; // type:func +func_800B8B8C_jp = 0x800B8B8C; // type:func +func_800B8BE4_jp = 0x800B8BE4; // type:func +func_800B8C10_jp = 0x800B8C10; // type:func +func_800B8C20_jp = 0x800B8C20; // type:func +func_800B8C34_jp = 0x800B8C34; // type:func +func_800B8C9C_jp = 0x800B8C9C; // type:func +func_800B8D18_jp = 0x800B8D18; // type:func +func_800B8D3C_jp = 0x800B8D3C; // type:func +func_800B8D64_jp = 0x800B8D64; // type:func +func_800B8EE4_jp = 0x800B8EE4; // type:func +func_800B8F20_jp = 0x800B8F20; // type:func +func_800B8FB8_jp = 0x800B8FB8; // type:func +func_800B9038_jp = 0x800B9038; // type:func +func_800B9170_jp = 0x800B9170; // type:func +func_800B9350_jp = 0x800B9350; // type:func +func_800B93AC_jp = 0x800B93AC; // type:func +func_800B947C_jp = 0x800B947C; // type:func +func_800B94E0_jp = 0x800B94E0; // type:func +func_800B9704_jp = 0x800B9704; // type:func +func_800B9790_jp = 0x800B9790; // type:func +func_800B97C8_jp = 0x800B97C8; // type:func +func_800B97F8_jp = 0x800B97F8; // type:func +func_800B996C_jp = 0x800B996C; // type:func +func_800B9AF0_jp = 0x800B9AF0; // type:func +func_800B9B2C_jp = 0x800B9B2C; // type:func +func_800B9C34_jp = 0x800B9C34; // type:func +func_800B9DAC_jp = 0x800B9DAC; // type:func +func_800B9E44_jp = 0x800B9E44; // type:func +func_800B9E90_jp = 0x800B9E90; // type:func +func_800B9EB4_jp = 0x800B9EB4; // type:func +func_800B9ED4_jp = 0x800B9ED4; // type:func +func_800B9F00_jp = 0x800B9F00; // type:func +func_800B9F74_jp = 0x800B9F74; // type:func +func_800B9FA0_jp = 0x800B9FA0; // type:func +func_800BA014_jp = 0x800BA014; // type:func +func_800BA054_jp = 0x800BA054; // type:func +func_800BA09C_jp = 0x800BA09C; // type:func +func_800BA0E4_jp = 0x800BA0E4; // type:func +func_800BA130_jp = 0x800BA130; // type:func +func_800BA150_jp = 0x800BA150; // type:func +func_800BA18C_jp = 0x800BA18C; // type:func +func_800BA214_jp = 0x800BA214; // type:func +func_800BA2B0_jp = 0x800BA2B0; // type:func +func_800BA2D4_jp = 0x800BA2D4; // type:func +func_800BA344_jp = 0x800BA344; // type:func +func_800BA3D0_jp = 0x800BA3D0; // type:func +func_800BA404_jp = 0x800BA404; // type:func +func_800BA494_jp = 0x800BA494; // type:func +func_800BA50C_jp = 0x800BA50C; // type:func +func_800BA660_jp = 0x800BA660; // type:func +func_800BA690_jp = 0x800BA690; // type:func +func_800BA6F0_jp = 0x800BA6F0; // type:func +func_800BA778_jp = 0x800BA778; // type:func +func_800BA7C8_jp = 0x800BA7C8; // type:func +func_800BA7E8_jp = 0x800BA7E8; // type:func +func_800BA8A0_jp = 0x800BA8A0; // type:func +func_800BA8F4_jp = 0x800BA8F4; // type:func +func_800BAA10_jp = 0x800BAA10; // type:func +func_800BAA7C_jp = 0x800BAA7C; // type:func +func_800BAAA4_jp = 0x800BAAA4; // type:func +func_800BABE8_jp = 0x800BABE8; // type:func +func_800BAC84_jp = 0x800BAC84; // type:func +func_800BACEC_jp = 0x800BACEC; // type:func +func_800BADBC_jp = 0x800BADBC; // type:func +func_800BAE78_jp = 0x800BAE78; // type:func +func_800BAF90_jp = 0x800BAF90; // type:func +func_800BB0A8_jp = 0x800BB0A8; // type:func +func_800BB0E8_jp = 0x800BB0E8; // type:func +func_800BB10C_jp = 0x800BB10C; // type:func +func_800BB270_jp = 0x800BB270; // type:func +func_800BB3A4_jp = 0x800BB3A4; // type:func +func_800BB4B0_jp = 0x800BB4B0; // type:func +func_800BB5DC_jp = 0x800BB5DC; // type:func +func_800BB634_jp = 0x800BB634; // type:func +func_800BB658_jp = 0x800BB658; // type:func +func_800BB67C_jp = 0x800BB67C; // type:func +func_800BB6A0_jp = 0x800BB6A0; // type:func +func_800BB6F0_jp = 0x800BB6F0; // type:func +func_800BB740_jp = 0x800BB740; // type:func +func_800BB86C_jp = 0x800BB86C; // type:func +func_800BB990_jp = 0x800BB990; // type:func +func_800BBAB0_jp = 0x800BBAB0; // type:func +func_800BBB30_jp = 0x800BBB30; // type:func +func_800BBBEC_jp = 0x800BBBEC; // type:func +func_800BBCBC_jp = 0x800BBCBC; // type:func +func_800BBD00_jp = 0x800BBD00; // type:func +func_800BBD68_jp = 0x800BBD68; // type:func +func_800BBD90_jp = 0x800BBD90; // type:func +func_800BBDE0_jp = 0x800BBDE0; // type:func +func_800BBE78_jp = 0x800BBE78; // type:func +func_800BBEE0_jp = 0x800BBEE0; // type:func +func_800BBF3C_jp = 0x800BBF3C; // type:func +func_800BBF98_jp = 0x800BBF98; // type:func +func_800BC064_jp = 0x800BC064; // type:func +func_800BC10C_jp = 0x800BC10C; // type:func +func_800BC12C_jp = 0x800BC12C; // type:func +func_800BC14C_jp = 0x800BC14C; // type:func +func_800BC1E4_jp = 0x800BC1E4; // type:func +func_800BC28C_jp = 0x800BC28C; // type:func +func_800BC33C_jp = 0x800BC33C; // type:func +func_800BC368_jp = 0x800BC368; // type:func +func_800BC394_jp = 0x800BC394; // type:func +func_800BC414_jp = 0x800BC414; // type:func +func_800BC454_jp = 0x800BC454; // type:func +func_800BC528_jp = 0x800BC528; // type:func +func_800BC5D4_jp = 0x800BC5D4; // type:func +func_800BC6B0_jp = 0x800BC6B0; // type:func +func_800BC724_jp = 0x800BC724; // type:func +func_800BC830_jp = 0x800BC830; // type:func +func_800BC938_jp = 0x800BC938; // type:func +func_800BCBA0_jp = 0x800BCBA0; // type:func +func_800BCBDC_jp = 0x800BCBDC; // type:func +func_800BCC20_jp = 0x800BCC20; // type:func +func_800BCC30_jp = 0x800BCC30; // type:func +func_800BCC40_jp = 0x800BCC40; // type:func +func_800BCCFC_jp = 0x800BCCFC; // type:func +func_800BCDCC_jp = 0x800BCDCC; // type:func +func_800BCDFC_jp = 0x800BCDFC; // type:func +func_800BCE80_jp = 0x800BCE80; // type:func +func_800BCEA4_jp = 0x800BCEA4; // type:func +func_800BCF64_jp = 0x800BCF64; // type:func +func_800BCFA4_jp = 0x800BCFA4; // type:func +func_800BCFC8_jp = 0x800BCFC8; // type:func +func_800BD02C_jp = 0x800BD02C; // type:func +func_800BD1E4_jp = 0x800BD1E4; // type:func +func_800BD2B0_jp = 0x800BD2B0; // type:func +func_800BD37C_jp = 0x800BD37C; // type:func +func_800BD3EC_jp = 0x800BD3EC; // type:func +func_800BD428_jp = 0x800BD428; // type:func +func_800BD448_jp = 0x800BD448; // type:func +func_800BD470_jp = 0x800BD470; // type:func +func_800BD498_jp = 0x800BD498; // type:func +func_800BD4C0_jp = 0x800BD4C0; // type:func +func_800BD4E8_jp = 0x800BD4E8; // type:func +func_800BD510_jp = 0x800BD510; // type:func +func_800BD538_jp = 0x800BD538; // type:func +func_800BD598_jp = 0x800BD598; // type:func +func_800BD5C0_jp = 0x800BD5C0; // type:func +func_800BD5E8_jp = 0x800BD5E8; // type:func +func_800BD648_jp = 0x800BD648; // type:func +func_800BD68C_jp = 0x800BD68C; // type:func +func_800BD6D0_jp = 0x800BD6D0; // type:func +func_800BD6F8_jp = 0x800BD6F8; // type:func +func_800BD720_jp = 0x800BD720; // type:func +func_800BD748_jp = 0x800BD748; // type:func +func_800BD770_jp = 0x800BD770; // type:func +func_800BD798_jp = 0x800BD798; // type:func +func_800BD7C0_jp = 0x800BD7C0; // type:func +func_800BD804_jp = 0x800BD804; // type:func +func_800BD8A8_jp = 0x800BD8A8; // type:func +func_800BD9D8_jp = 0x800BD9D8; // type:func +func_800BD9FC_jp = 0x800BD9FC; // type:func +func_800BDA20_jp = 0x800BDA20; // type:func +func_800BDAA8_jp = 0x800BDAA8; // type:func +func_800BDBB4_jp = 0x800BDBB4; // type:func +func_800BDF90_jp = 0x800BDF90; // type:func +func_800BE030_jp = 0x800BE030; // type:func +func_800BE070_jp = 0x800BE070; // type:func +func_800BE094_jp = 0x800BE094; // type:func +func_800BE0E4_jp = 0x800BE0E4; // type:func +func_800BE12C_jp = 0x800BE12C; // type:func +func_800BE184_jp = 0x800BE184; // type:func +func_800BE1D4_jp = 0x800BE1D4; // type:func +func_800BE27C_jp = 0x800BE27C; // type:func +func_800BE320_jp = 0x800BE320; // type:func +func_800BE4F8_jp = 0x800BE4F8; // type:func +func_800BE660_jp = 0x800BE660; // type:func +func_800BE69C_jp = 0x800BE69C; // type:func +func_800BE6D8_jp = 0x800BE6D8; // type:func +func_800BE72C_jp = 0x800BE72C; // type:func +func_800BE844_jp = 0x800BE844; // type:func +func_800BEA50_jp = 0x800BEA50; // type:func +func_800BEBEC_jp = 0x800BEBEC; // type:func +func_800BEC3C_jp = 0x800BEC3C; // type:func +func_800BEC80_jp = 0x800BEC80; // type:func +func_800BED5C_jp = 0x800BED5C; // type:func +func_800BEE50_jp = 0x800BEE50; // type:func +func_800BEEB4_jp = 0x800BEEB4; // type:func +func_800BEEC4_jp = 0x800BEEC4; // type:func +func_800BEFCC_jp = 0x800BEFCC; // type:func +func_800BF10C_jp = 0x800BF10C; // type:func +func_800BF230_jp = 0x800BF230; // type:func +func_800BF26C_jp = 0x800BF26C; // type:func +func_800BF27C_jp = 0x800BF27C; // type:func +func_800BF338_jp = 0x800BF338; // type:func +func_800BF410_jp = 0x800BF410; // type:func +func_800BF480_jp = 0x800BF480; // type:func +func_800BF4F4_jp = 0x800BF4F4; // type:func +func_800BF56C_jp = 0x800BF56C; // type:func +func_800BF580_jp = 0x800BF580; // type:func +func_800BF5A0_jp = 0x800BF5A0; // type:func +func_800BF5F4_jp = 0x800BF5F4; // type:func +func_800BF770_jp = 0x800BF770; // type:func +func_800BF7EC_jp = 0x800BF7EC; // type:func +func_800BF8E8_jp = 0x800BF8E8; // type:func +func_800BF9B0_jp = 0x800BF9B0; // type:func +func_800BFA78_jp = 0x800BFA78; // type:func +func_800BFAA8_jp = 0x800BFAA8; // type:func +func_800BFC00_jp = 0x800BFC00; // type:func +func_800BFC5C_jp = 0x800BFC5C; // type:func +func_800BFCF0_jp = 0x800BFCF0; // type:func +func_800BFF8C_jp = 0x800BFF8C; // type:func +func_800BFFC0_jp = 0x800BFFC0; // type:func +func_800C0194_jp = 0x800C0194; // type:func +func_800C0490_jp = 0x800C0490; // type:func +func_800C05E0_jp = 0x800C05E0; // type:func +func_800C0684_jp = 0x800C0684; // type:func +func_800C088C_jp = 0x800C088C; // type:func +func_800C092C_jp = 0x800C092C; // type:func +func_800C0AAC_jp = 0x800C0AAC; // type:func +func_800C0BA0_jp = 0x800C0BA0; // type:func +func_800C0CB4_jp = 0x800C0CB4; // type:func +func_800C0CF0_jp = 0x800C0CF0; // type:func +func_800C0D48_jp = 0x800C0D48; // type:func +func_800C0DA0_jp = 0x800C0DA0; // type:func +func_800C0DEC_jp = 0x800C0DEC; // type:func +func_800C0E98_jp = 0x800C0E98; // type:func +func_800C1070_jp = 0x800C1070; // type:func +func_800C1230_jp = 0x800C1230; // type:func +func_800C1428_jp = 0x800C1428; // type:func +func_800C1498_jp = 0x800C1498; // type:func +func_800C15A8_jp = 0x800C15A8; // type:func +func_800C1610_jp = 0x800C1610; // type:func +func_800C164C_jp = 0x800C164C; // type:func +func_800C165C_jp = 0x800C165C; // type:func +func_800C1674_jp = 0x800C1674; // type:func +func_800C16F0_jp = 0x800C16F0; // type:func +func_800C1764_jp = 0x800C1764; // type:func +func_800C17F8_jp = 0x800C17F8; // type:func +func_800C1BF0_jp = 0x800C1BF0; // type:func +func_800C1C38_jp = 0x800C1C38; // type:func +func_800C1C70_jp = 0x800C1C70; // type:func +func_800C1CB8_jp = 0x800C1CB8; // type:func +func_800C1CE8_jp = 0x800C1CE8; // type:func +func_800C1D08_jp = 0x800C1D08; // type:func +func_800C1D3C_jp = 0x800C1D3C; // type:func +func_800C1D5C_jp = 0x800C1D5C; // type:func +func_800C1EB8_jp = 0x800C1EB8; // type:func +func_800C1F08_jp = 0x800C1F08; // type:func +func_800C1F5C_jp = 0x800C1F5C; // type:func +func_800C1F90_jp = 0x800C1F90; // type:func +func_800C2060_jp = 0x800C2060; // type:func +func_800C2070_jp = 0x800C2070; // type:func +func_800C22F8_jp = 0x800C22F8; // type:func +func_800C2354_jp = 0x800C2354; // type:func +func_800C2380_jp = 0x800C2380; // type:func +func_800C23EC_jp = 0x800C23EC; // type:func +func_800C2480_jp = 0x800C2480; // type:func +func_800C2578_jp = 0x800C2578; // type:func +func_800C2718_jp = 0x800C2718; // type:func +func_800C284C_jp = 0x800C284C; // type:func +func_800C297C_jp = 0x800C297C; // type:func +func_800C2AAC_jp = 0x800C2AAC; // type:func +func_800C2B70_jp = 0x800C2B70; // type:func +func_800C2CC8_jp = 0x800C2CC8; // type:func +func_800C2D2C_jp = 0x800C2D2C; // type:func +func_800C2D8C_jp = 0x800C2D8C; // type:func +func_800C2DF0_jp = 0x800C2DF0; // type:func +func_800C2E80_jp = 0x800C2E80; // type:func +func_800C2EE0_jp = 0x800C2EE0; // type:func +func_800C2FF0_jp = 0x800C2FF0; // type:func +func_800C3054_jp = 0x800C3054; // type:func +func_800C3118_jp = 0x800C3118; // type:func +func_800C31D0_jp = 0x800C31D0; // type:func +func_800C327C_jp = 0x800C327C; // type:func +func_800C3398_jp = 0x800C3398; // type:func +func_800C33CC_jp = 0x800C33CC; // type:func +func_800C3418_jp = 0x800C3418; // type:func +func_800C3488_jp = 0x800C3488; // type:func +func_800C34D0_jp = 0x800C34D0; // type:func +func_800C37BC_jp = 0x800C37BC; // type:func +func_800C3970_jp = 0x800C3970; // type:func +func_800C3AAC_jp = 0x800C3AAC; // type:func +func_800C3BB4_jp = 0x800C3BB4; // type:func +func_800C3BCC_jp = 0x800C3BCC; // type:func +func_800C3D50_jp = 0x800C3D50; // type:func +func_800C3DA8_jp = 0x800C3DA8; // type:func +func_800C3E30_jp = 0x800C3E30; // type:func +func_800C3F70_jp = 0x800C3F70; // type:func +func_800C4084_jp = 0x800C4084; // type:func +func_800C40F8_jp = 0x800C40F8; // type:func +func_800C4168_jp = 0x800C4168; // type:func +func_800C41B8_jp = 0x800C41B8; // type:func +func_800C4228_jp = 0x800C4228; // type:func +func_800C42E8_jp = 0x800C42E8; // type:func +func_800C4350_jp = 0x800C4350; // type:func +func_800C43B8_jp = 0x800C43B8; // type:func +func_800C4420_jp = 0x800C4420; // type:func +func_800C4440_jp = 0x800C4440; // type:func +func_800C453C_jp = 0x800C453C; // type:func +func_800C4648_jp = 0x800C4648; // type:func +func_800C46AC_jp = 0x800C46AC; // type:func +func_800C4728_jp = 0x800C4728; // type:func +func_800C47B4_jp = 0x800C47B4; // type:func +func_800C497C_jp = 0x800C497C; // type:func +func_800C49D4_jp = 0x800C49D4; // type:func +func_800C4C60_jp = 0x800C4C60; // type:func +func_800C4CC4_jp = 0x800C4CC4; // type:func +func_800C4D1C_jp = 0x800C4D1C; // type:func +func_800C4D80_jp = 0x800C4D80; // type:func +func_800C4D8C_jp = 0x800C4D8C; // type:func +func_800C4DB0_jp = 0x800C4DB0; // type:func +func_800C4DD8_jp = 0x800C4DD8; // type:func +func_800C4DFC_jp = 0x800C4DFC; // type:func +func_800C4E2C_jp = 0x800C4E2C; // type:func +func_800C4E58_jp = 0x800C4E58; // type:func +func_800C50C4_jp = 0x800C50C4; // type:func +func_800C50EC_jp = 0x800C50EC; // type:func +func_800C510C_jp = 0x800C510C; // type:func +func_800C5228_jp = 0x800C5228; // type:func +func_800C524C_jp = 0x800C524C; // type:func +func_800C5328_jp = 0x800C5328; // type:func +func_800C535C_jp = 0x800C535C; // type:func +func_800C53B8_jp = 0x800C53B8; // type:func +func_800C543C_jp = 0x800C543C; // type:func +func_800C54A8_jp = 0x800C54A8; // type:func +func_800C54F4_jp = 0x800C54F4; // type:func +func_800C557C_jp = 0x800C557C; // type:func +func_800C55E4_jp = 0x800C55E4; // type:func +func_800C5640_jp = 0x800C5640; // type:func +func_800C56AC_jp = 0x800C56AC; // type:func +func_800C5798_jp = 0x800C5798; // type:func +func_800C582C_jp = 0x800C582C; // type:func +func_800C58B4_jp = 0x800C58B4; // type:func +func_800C592C_jp = 0x800C592C; // type:func +func_800C5960_jp = 0x800C5960; // type:func +func_800C5984_jp = 0x800C5984; // type:func +func_800C59B0_jp = 0x800C59B0; // type:func +func_800C5A08_jp = 0x800C5A08; // type:func +func_800C5A60_jp = 0x800C5A60; // type:func +func_800C5AA0_jp = 0x800C5AA0; // type:func +func_800C5B30_jp = 0x800C5B30; // type:func +func_800C5B5C_jp = 0x800C5B5C; // type:func +func_800C5B74_jp = 0x800C5B74; // type:func +func_800C5C30_jp = 0x800C5C30; // type:func +func_800C5CC4_jp = 0x800C5CC4; // type:func +func_800C5D68_jp = 0x800C5D68; // type:func +func_800C5E10_jp = 0x800C5E10; // type:func +func_800C5EA0_jp = 0x800C5EA0; // type:func +func_800C5F0C_jp = 0x800C5F0C; // type:func +func_800C5F64_jp = 0x800C5F64; // type:func +func_800C60EC_jp = 0x800C60EC; // type:func +func_800C6144_jp = 0x800C6144; // type:func +func_800C61CC_jp = 0x800C61CC; // type:func +func_800C62C4_jp = 0x800C62C4; // type:func +func_800C639C_jp = 0x800C639C; // type:func +func_800C65E4_jp = 0x800C65E4; // type:func +func_800C6678_jp = 0x800C6678; // type:func +func_800C6690_jp = 0x800C6690; // type:func +func_800C68C8_jp = 0x800C68C8; // type:func +func_800C6960_jp = 0x800C6960; // type:func +func_800C69F4_jp = 0x800C69F4; // type:func +func_800C6A28_jp = 0x800C6A28; // type:func +func_800C6A5C_jp = 0x800C6A5C; // type:func +func_800C6A90_jp = 0x800C6A90; // type:func +func_800C6AC4_jp = 0x800C6AC4; // type:func +func_800C6AD0_jp = 0x800C6AD0; // type:func +func_800C6AE0_jp = 0x800C6AE0; // type:func +func_800C6B50_jp = 0x800C6B50; // type:func +func_800C6BB0_jp = 0x800C6BB0; // type:func +func_800C6BD4_jp = 0x800C6BD4; // type:func +func_800C6BF8_jp = 0x800C6BF8; // type:func +func_800C6C10_jp = 0x800C6C10; // type:func +func_800C6D14_jp = 0x800C6D14; // type:func +func_800C6D5C_jp = 0x800C6D5C; // type:func +func_800C6E14_jp = 0x800C6E14; // type:func +func_800C6E80_jp = 0x800C6E80; // type:func +func_800C6F68_jp = 0x800C6F68; // type:func +func_800C7018_jp = 0x800C7018; // type:func +func_800C7374_jp = 0x800C7374; // type:func +func_800C7388_jp = 0x800C7388; // type:func +func_800C73E0_jp = 0x800C73E0; // type:func +func_800C7468_jp = 0x800C7468; // type:func +func_800C7708_jp = 0x800C7708; // type:func +func_800C776C_jp = 0x800C776C; // type:func +func_800C78FC_jp = 0x800C78FC; // type:func +func_800C7A8C_jp = 0x800C7A8C; // type:func +func_800C7AF0_jp = 0x800C7AF0; // type:func +func_800C7B74_jp = 0x800C7B74; // type:func +func_800C7BF8_jp = 0x800C7BF8; // type:func +func_800C7C58_jp = 0x800C7C58; // type:func +func_800C7C9C_jp = 0x800C7C9C; // type:func +func_800C7CE0_jp = 0x800C7CE0; // type:func +func_800C7EF8_jp = 0x800C7EF8; // type:func +func_800C7F40_jp = 0x800C7F40; // type:func +func_800C80B0_jp = 0x800C80B0; // type:func +func_800C8218_jp = 0x800C8218; // type:func +func_800C82E0_jp = 0x800C82E0; // type:func +func_800C83E8_jp = 0x800C83E8; // type:func +func_800C84B0_jp = 0x800C84B0; // type:func +func_800C85BC_jp = 0x800C85BC; // type:func +func_800C8684_jp = 0x800C8684; // type:func +func_800C8790_jp = 0x800C8790; // type:func +func_800C87E4_jp = 0x800C87E4; // type:func +func_800C8828_jp = 0x800C8828; // type:func +func_800C8888_jp = 0x800C8888; // type:func +func_800C8B88_jp = 0x800C8B88; // type:func +func_800C8BC4_jp = 0x800C8BC4; // type:func +func_800C8CC8_jp = 0x800C8CC8; // type:func +func_800C8D04_jp = 0x800C8D04; // type:func +func_800C8D40_jp = 0x800C8D40; // type:func +func_800C8D98_jp = 0x800C8D98; // type:func +func_800C8E08_jp = 0x800C8E08; // type:func +func_800C8E50_jp = 0x800C8E50; // type:func +func_800C8ECC_jp = 0x800C8ECC; // type:func +func_800C8F5C_jp = 0x800C8F5C; // type:func +func_800C8F84_jp = 0x800C8F84; // type:func +func_800C8FB8_jp = 0x800C8FB8; // type:func +func_800C9010_jp = 0x800C9010; // type:func +func_800C9088_jp = 0x800C9088; // type:func +func_800C909C_jp = 0x800C909C; // type:func +func_800C90BC_jp = 0x800C90BC; // type:func +func_800C90F0_jp = 0x800C90F0; // type:func +func_800C91E0_jp = 0x800C91E0; // type:func +func_800C92FC_jp = 0x800C92FC; // type:func +func_800C9338_jp = 0x800C9338; // type:func +func_800C93D0_jp = 0x800C93D0; // type:func +func_800C942C_jp = 0x800C942C; // type:func +func_800C94AC_jp = 0x800C94AC; // type:func +func_800C9508_jp = 0x800C9508; // type:func +func_800C9580_jp = 0x800C9580; // type:func +func_800C9634_jp = 0x800C9634; // type:func +func_800C96B0_jp = 0x800C96B0; // type:func +func_800C9728_jp = 0x800C9728; // type:func +func_800C98A0_jp = 0x800C98A0; // type:func +func_800C9D38_jp = 0x800C9D38; // type:func +func_800C9F88_jp = 0x800C9F88; // type:func +func_800CA008_jp = 0x800CA008; // type:func +func_800CA070_jp = 0x800CA070; // type:func +func_800CA1DC_jp = 0x800CA1DC; // type:func +func_800CA230_jp = 0x800CA230; // type:func +func_800CA240_jp = 0x800CA240; // type:func +func_800CA278_jp = 0x800CA278; // type:func +func_800CA2A8_jp = 0x800CA2A8; // type:func +func_800CA2BC_jp = 0x800CA2BC; // type:func +func_800CA2DC_jp = 0x800CA2DC; // type:func +func_800CA350_jp = 0x800CA350; // type:func +func_800CA570_jp = 0x800CA570; // type:func +func_800CA63C_jp = 0x800CA63C; // type:func +func_800CA8A0_jp = 0x800CA8A0; // type:func +func_800CA90C_jp = 0x800CA90C; // type:func +func_800CA9C4_jp = 0x800CA9C4; // type:func +func_800CAA60_jp = 0x800CAA60; // type:func +func_800CAAB0_jp = 0x800CAAB0; // type:func +func_800CAAD0_jp = 0x800CAAD0; // type:func +func_800CAAE0_jp = 0x800CAAE0; // type:func +func_800CAB10_jp = 0x800CAB10; // type:func +func_800CAB30_jp = 0x800CAB30; // type:func +func_800CAB64_jp = 0x800CAB64; // type:func +func_800CAB8C_jp = 0x800CAB8C; // type:func +func_800CAC40_jp = 0x800CAC40; // type:func +func_800CACAC_jp = 0x800CACAC; // type:func +func_800CAD9C_jp = 0x800CAD9C; // type:func +func_800CAE00_jp = 0x800CAE00; // type:func +func_800CB018_jp = 0x800CB018; // type:func +func_800CB064_jp = 0x800CB064; // type:func +func_800CB400_jp = 0x800CB400; // type:func +func_800CB604_jp = 0x800CB604; // type:func +func_800CB7B0_jp = 0x800CB7B0; // type:func +func_800CBA70_jp = 0x800CBA70; // type:func +func_800CBC00_jp = 0x800CBC00; // type:func +func_800CBF80_jp = 0x800CBF80; // type:func +func_800CBFBC_jp = 0x800CBFBC; // type:func +func_800CC3EC_jp = 0x800CC3EC; // type:func +func_800CC9C4_jp = 0x800CC9C4; // type:func +func_800CC9EC_jp = 0x800CC9EC; // type:func +func_800CCB44_jp = 0x800CCB44; // type:func +func_800CCE08_jp = 0x800CCE08; // type:func +func_800CCE40_jp = 0x800CCE40; // type:func +func_800CD194_jp = 0x800CD194; // type:func +func_800CD59C_jp = 0x800CD59C; // type:func +func_800CD640_jp = 0x800CD640; // type:func +func_800CD68C_jp = 0x800CD68C; // type:func +func_800CD730_jp = 0x800CD730; // type:func +func_800CD760_jp = 0x800CD760; // type:func +func_800CD82C_jp = 0x800CD82C; // type:func +func_800CD8F8_jp = 0x800CD8F8; // type:func +func_800CD990_jp = 0x800CD990; // type:func +func_800CD9F0_jp = 0x800CD9F0; // type:func +func_800CDA4C_jp = 0x800CDA4C; // type:func +func_800CDA90_jp = 0x800CDA90; // type:func +func_800CDAD0_jp = 0x800CDAD0; // type:func +func_800CDB10_jp = 0x800CDB10; // type:func +func_800CDBE0_jp = 0x800CDBE0; // type:func +func_800CDBF0_jp = 0x800CDBF0; // type:func +func_800CDC10_jp = 0x800CDC10; // type:func +func_800CDC30_jp = 0x800CDC30; // type:func +func_800CDCC0_jp = 0x800CDCC0; // type:func +func_800CDDE0_jp = 0x800CDDE0; // type:func +func_800CDE54_jp = 0x800CDE54; // type:func +func_800CDECC_jp = 0x800CDECC; // type:func +func_800CDEDC_jp = 0x800CDEDC; // type:func +func_800CDF78_jp = 0x800CDF78; // type:func +func_800CE04C_jp = 0x800CE04C; // type:func +func_800CE090_jp = 0x800CE090; // type:func +func_800CE0E8_jp = 0x800CE0E8; // type:func +func_800CE110_jp = 0x800CE110; // type:func +func_800CE120_jp = 0x800CE120; // type:func +func_800CE1CC_jp = 0x800CE1CC; // type:func +func_800CE328_jp = 0x800CE328; // type:func +func_800CE4B0_jp = 0x800CE4B0; // type:func +func_800CE4F4_jp = 0x800CE4F4; // type:func +func_800CE554_jp = 0x800CE554; // type:func +func_800CE694_jp = 0x800CE694; // type:func +func_800CE7E4_jp = 0x800CE7E4; // type:func +func_800CE874_jp = 0x800CE874; // type:func +func_800CE8F0_jp = 0x800CE8F0; // type:func +func_800CE9C4_jp = 0x800CE9C4; // type:func +func_800CEB1C_jp = 0x800CEB1C; // type:func +func_800CEC30_jp = 0x800CEC30; // type:func +func_800CEC98_jp = 0x800CEC98; // type:func +func_800CEE24_jp = 0x800CEE24; // type:func +func_800CEED4_jp = 0x800CEED4; // type:func +func_800CF05C_jp = 0x800CF05C; // type:func +func_800CF16C_jp = 0x800CF16C; // type:func +func_800CF240_jp = 0x800CF240; // type:func +func_800CF6EC_jp = 0x800CF6EC; // type:func +func_800CF780_jp = 0x800CF780; // type:func +func_800CF82C_jp = 0x800CF82C; // type:func +func_800CF868_jp = 0x800CF868; // type:func +func_800CF89C_jp = 0x800CF89C; // type:func +func_800CF8D0_jp = 0x800CF8D0; // type:func +func_800CF8F4_jp = 0x800CF8F4; // type:func +func_800CF9C0_jp = 0x800CF9C0; // type:func +func_800CF9E0_jp = 0x800CF9E0; // type:func +func_800CFB70_jp = 0x800CFB70; // type:func +func_800CFBAC_jp = 0x800CFBAC; // type:func +func_800CFED8_jp = 0x800CFED8; // type:func +func_800CFFA0_jp = 0x800CFFA0; // type:func +func_800D043C_jp = 0x800D043C; // type:func +func_800D0474_jp = 0x800D0474; // type:func +func_800D04AC_jp = 0x800D04AC; // type:func +func_800D050C_jp = 0x800D050C; // type:func +func_800D0530_jp = 0x800D0530; // type:func +func_800D0878_jp = 0x800D0878; // type:func +func_800D08C0_jp = 0x800D08C0; // type:func +func_800D08E4_jp = 0x800D08E4; // type:func +func_800D13A4_jp = 0x800D13A4; // type:func +func_800D1448_jp = 0x800D1448; // type:func +func_800D149C_jp = 0x800D149C; // type:func +func_800D14E0_jp = 0x800D14E0; // type:func +func_800D1500_jp = 0x800D1500; // type:func +func_800D1520_jp = 0x800D1520; // type:func +func_800D1540_jp = 0x800D1540; // type:func +func_800D1560_jp = 0x800D1560; // type:func +func_800D1580_jp = 0x800D1580; // type:func +func_800D15A0_jp = 0x800D15A0; // type:func +func_800D15C0_jp = 0x800D15C0; // type:func +func_800D15E0_jp = 0x800D15E0; // type:func +func_800D1604_jp = 0x800D1604; // type:func +func_800D1624_jp = 0x800D1624; // type:func +func_800D1644_jp = 0x800D1644; // type:func +func_800D1664_jp = 0x800D1664; // type:func +func_800D1688_jp = 0x800D1688; // type:func +func_800D16A8_jp = 0x800D16A8; // type:func +func_800D16CC_jp = 0x800D16CC; // type:func +func_800D16F0_jp = 0x800D16F0; // type:func +func_800D16FC_jp = 0x800D16FC; // type:func +func_800D1708_jp = 0x800D1708; // type:func +func_800D1714_jp = 0x800D1714; // type:func +func_800D1728_jp = 0x800D1728; // type:func +func_800D1748_jp = 0x800D1748; // type:func +func_800D17D4_jp = 0x800D17D4; // type:func +func_800D17F4_jp = 0x800D17F4; // type:func +func_800D1810_jp = 0x800D1810; // type:func +func_800D1824_jp = 0x800D1824; // type:func +func_800D1848_jp = 0x800D1848; // type:func +func_800D1864_jp = 0x800D1864; // type:func +func_800D1888_jp = 0x800D1888; // type:func +func_800D18B0_jp = 0x800D18B0; // type:func +func_800D195C_jp = 0x800D195C; // type:func +func_800D197C_jp = 0x800D197C; // type:func +func_800D199C_jp = 0x800D199C; // type:func +func_800D19BC_jp = 0x800D19BC; // type:func +func_800D19DC_jp = 0x800D19DC; // type:func +func_800D19FC_jp = 0x800D19FC; // type:func +func_800D1A24_jp = 0x800D1A24; // type:func +func_800D1A4C_jp = 0x800D1A4C; // type:func +func_800D1A74_jp = 0x800D1A74; // type:func +func_800D1A9C_jp = 0x800D1A9C; // type:func +func_800D1AC4_jp = 0x800D1AC4; // type:func +func_800D1B00_jp = 0x800D1B00; // type:func +func_800D1B3C_jp = 0x800D1B3C; // type:func +func_800D1B78_jp = 0x800D1B78; // type:func +func_800D1BB4_jp = 0x800D1BB4; // type:func +func_800D1BE4_jp = 0x800D1BE4; // type:func +func_800D1C20_jp = 0x800D1C20; // type:func +func_800D1C48_jp = 0x800D1C48; // type:func +func_800D1C70_jp = 0x800D1C70; // type:func +func_800D1C98_jp = 0x800D1C98; // type:func +func_800D1CB8_jp = 0x800D1CB8; // type:func +func_800D1CE0_jp = 0x800D1CE0; // type:func +func_800D1D08_jp = 0x800D1D08; // type:func +func_800D1D58_jp = 0x800D1D58; // type:func +func_800D1D94_jp = 0x800D1D94; // type:func +func_800D1DBC_jp = 0x800D1DBC; // type:func +func_800D1DE4_jp = 0x800D1DE4; // type:func +func_800D1E20_jp = 0x800D1E20; // type:func +func_800D1E58_jp = 0x800D1E58; // type:func +func_800D1E78_jp = 0x800D1E78; // type:func +func_800D1E98_jp = 0x800D1E98; // type:func +func_800D1EE8_jp = 0x800D1EE8; // type:func +func_800D1F10_jp = 0x800D1F10; // type:func +func_800D1F30_jp = 0x800D1F30; // type:func +func_800D1F50_jp = 0x800D1F50; // type:func +func_800D1F70_jp = 0x800D1F70; // type:func +func_800D1F90_jp = 0x800D1F90; // type:func +func_800D1FB0_jp = 0x800D1FB0; // type:func +func_800D1FF0_jp = 0x800D1FF0; // type:func +func_800D2010_jp = 0x800D2010; // type:func +func_800D2064_jp = 0x800D2064; // type:func +func_800D208C_jp = 0x800D208C; // type:func +func_800D20B4_jp = 0x800D20B4; // type:func +func_800D20D4_jp = 0x800D20D4; // type:func +func_800D20F4_jp = 0x800D20F4; // type:func +func_800D2114_jp = 0x800D2114; // type:func +func_800D213C_jp = 0x800D213C; // type:func +func_800D215C_jp = 0x800D215C; // type:func +func_800D2184_jp = 0x800D2184; // type:func +func_800D21CC_jp = 0x800D21CC; // type:func +func_800D21EC_jp = 0x800D21EC; // type:func +func_800D220C_jp = 0x800D220C; // type:func +func_800D2234_jp = 0x800D2234; // type:func +func_800D227C_jp = 0x800D227C; // type:func +func_800D22A4_jp = 0x800D22A4; // type:func +func_800D22CC_jp = 0x800D22CC; // type:func +func_800D22F4_jp = 0x800D22F4; // type:func +func_800D2314_jp = 0x800D2314; // type:func +func_800D2334_jp = 0x800D2334; // type:func +func_800D2354_jp = 0x800D2354; // type:func +func_800D2360_jp = 0x800D2360; // type:func +func_800D236C_jp = 0x800D236C; // type:func +func_800D2394_jp = 0x800D2394; // type:func +func_800D23B4_jp = 0x800D23B4; // type:func +func_800D2438_jp = 0x800D2438; // type:func +func_800D24C4_jp = 0x800D24C4; // type:func +func_800D24EC_jp = 0x800D24EC; // type:func +func_800D252C_jp = 0x800D252C; // type:func +func_800D2568_jp = 0x800D2568; // type:func +func_800D2578_jp = 0x800D2578; // type:func +func_800D2590_jp = 0x800D2590; // type:func +func_800D25D0_jp = 0x800D25D0; // type:func +func_800D287C_jp = 0x800D287C; // type:func +func_800D289C_jp = 0x800D289C; // type:func +func_800D2AA0_jp = 0x800D2AA0; // type:func +func_800D2AD0_jp = 0x800D2AD0; // type:func +func_800D2B94_jp = 0x800D2B94; // type:func +func_800D2BEC_jp = 0x800D2BEC; // type:func +func_800D2C10_jp = 0x800D2C10; // type:func +func_800D2CB4_jp = 0x800D2CB4; // type:func +func_800D2CDC_jp = 0x800D2CDC; // type:func +func_800D2E00_jp = 0x800D2E00; // type:func +func_800D2E58_jp = 0x800D2E58; // type:func +func_800D2F74_jp = 0x800D2F74; // type:func +func_800D307C_jp = 0x800D307C; // type:func +func_800D321C_jp = 0x800D321C; // type:func +func_800D3294_jp = 0x800D3294; // type:func +func_800D32DC_jp = 0x800D32DC; // type:func +func_800D334C_jp = 0x800D334C; // type:func +func_800D33F4_jp = 0x800D33F4; // type:func +func_800D3464_jp = 0x800D3464; // type:func +func_800D353C_jp = 0x800D353C; // type:func +func_800D3618_jp = 0x800D3618; // type:func +func_800D368C_jp = 0x800D368C; // type:func +func_800D3698_jp = 0x800D3698; // type:func +func_800D36A4_jp = 0x800D36A4; // type:func +func_800D36B0_jp = 0x800D36B0; // type:func +func_800D36D4_jp = 0x800D36D4; // type:func +func_800D36F4_jp = 0x800D36F4; // type:func +func_800D3720_jp = 0x800D3720; // type:func +func_800D3740_jp = 0x800D3740; // type:func +func_800D37AC_jp = 0x800D37AC; // type:func +func_800D37F8_jp = 0x800D37F8; // type:func +func_800D3848_jp = 0x800D3848; // type:func +func_800D3860_jp = 0x800D3860; // type:func +func_800D386C_jp = 0x800D386C; // type:func +func_800D38A0_jp = 0x800D38A0; // type:func +func_800D38E0_jp = 0x800D38E0; // type:func +func_800D39AC_jp = 0x800D39AC; // type:func +func_800D3B84_jp = 0x800D3B84; // type:func +func_800D3C94_jp = 0x800D3C94; // type:func +func_800D3D04_jp = 0x800D3D04; // type:func +func_800D3DD8_jp = 0x800D3DD8; // type:func +func_800D3E14_jp = 0x800D3E14; // type:func +func_800D3E40_jp = 0x800D3E40; // type:func +func_800D3F28_jp = 0x800D3F28; // type:func +func_800D4200_jp = 0x800D4200; // type:func +func_800D4428_jp = 0x800D4428; // type:func +func_800D4568_jp = 0x800D4568; // type:func +func_800D4710_jp = 0x800D4710; // type:func +func_800D47B4_jp = 0x800D47B4; // type:func +func_800D4848_jp = 0x800D4848; // type:func +func_800D48B4_jp = 0x800D48B4; // type:func +func_800D4920_jp = 0x800D4920; // type:func +func_800D49C8_jp = 0x800D49C8; // type:func +func_800D49E8_jp = 0x800D49E8; // type:func +func_800D4A6C_jp = 0x800D4A6C; // type:func +func_800D4B04_jp = 0x800D4B04; // type:func +func_800D4B24_jp = 0x800D4B24; // type:func +func_800D4BEC_jp = 0x800D4BEC; // type:func +func_800D4CBC_jp = 0x800D4CBC; // type:func +func_800D4DC0_jp = 0x800D4DC0; // type:func +func_800D4E20_jp = 0x800D4E20; // type:func +func_800D4E94_jp = 0x800D4E94; // type:func +func_800D4F18_jp = 0x800D4F18; // type:func +func_800D4F6C_jp = 0x800D4F6C; // type:func +func_800D4FB8_jp = 0x800D4FB8; // type:func +func_800D5004_jp = 0x800D5004; // type:func +func_800D5090_jp = 0x800D5090; // type:func +func_800D5104_jp = 0x800D5104; // type:func +func_800D5164_jp = 0x800D5164; // type:func +func_800D51E0_jp = 0x800D51E0; // type:func +func_800D52C0_jp = 0x800D52C0; // type:func +func_800D53A4_jp = 0x800D53A4; // type:func +func_800D53DC_jp = 0x800D53DC; // type:func +func_800D5414_jp = 0x800D5414; // type:func +func_800D5480_jp = 0x800D5480; // type:func +func_800D54DC_jp = 0x800D54DC; // type:func +func_800D56B8_jp = 0x800D56B8; // type:func +func_800D56CC_jp = 0x800D56CC; // type:func +func_800D572C_jp = 0x800D572C; // type:func +func_800D579C_jp = 0x800D579C; // type:func +func_800D57FC_jp = 0x800D57FC; // type:func +func_800D585C_jp = 0x800D585C; // type:func +func_800D58BC_jp = 0x800D58BC; // type:func +func_800D5930_jp = 0x800D5930; // type:func +func_800D5944_jp = 0x800D5944; // type:func +func_800D59E8_jp = 0x800D59E8; // type:func +func_800D5A8C_jp = 0x800D5A8C; // type:func +func_800D5B34_jp = 0x800D5B34; // type:func +func_800D5BDC_jp = 0x800D5BDC; // type:func +func_800D5C84_jp = 0x800D5C84; // type:func +func_800D5CF8_jp = 0x800D5CF8; // type:func +func_800D5D6C_jp = 0x800D5D6C; // type:func +func_800D5D94_jp = 0x800D5D94; // type:func +func_800D5E70_jp = 0x800D5E70; // type:func +func_800D5EA8_jp = 0x800D5EA8; // type:func +func_800D5EE4_jp = 0x800D5EE4; // type:func +func_800D5EFC_jp = 0x800D5EFC; // type:func +func_800D5F28_jp = 0x800D5F28; // type:func +func_800D5F44_jp = 0x800D5F44; // type:func +func_800D5FA0_jp = 0x800D5FA0; // type:func +func_800D60E4_jp = 0x800D60E4; // type:func +func_800D6218_jp = 0x800D6218; // type:func +func_800D6390_jp = 0x800D6390; // type:func +func_800D63A4_jp = 0x800D63A4; // type:func +func_800D6410_jp = 0x800D6410; // type:func +func_800D6490_jp = 0x800D6490; // type:func +func_800D64E0_jp = 0x800D64E0; // type:func +func_800D66D0_jp = 0x800D66D0; // type:func +func_800D6A10_jp = 0x800D6A10; // type:func +func_800D6A44_jp = 0x800D6A44; // type:func +func_800D6A74_jp = 0x800D6A74; // type:func +func_800D6AA4_jp = 0x800D6AA4; // type:func +func_800D6AD4_jp = 0x800D6AD4; // type:func +func_800D6AEC_jp = 0x800D6AEC; // type:func +func_800D6B0C_jp = 0x800D6B0C; // type:func +func_800D6B34_jp = 0x800D6B34; // type:func +func_800D6B8C_jp = 0x800D6B8C; // type:func +func_800D6C88_jp = 0x800D6C88; // type:func +func_800D6ED0_jp = 0x800D6ED0; // type:func +func_800D7050_jp = 0x800D7050; // type:func +func_800D7180_jp = 0x800D7180; // type:func +func_800D7198_jp = 0x800D7198; // type:func +func_800D731C_jp = 0x800D731C; // type:func +func_800D7358_jp = 0x800D7358; // type:func +func_800D73F0_jp = 0x800D73F0; // type:func +func_800D753C_jp = 0x800D753C; // type:func +func_800D763C_jp = 0x800D763C; // type:func +func_800D765C_jp = 0x800D765C; // type:func +func_800D7678_jp = 0x800D7678; // type:func +func_800D76A0_jp = 0x800D76A0; // type:func +func_800D7794_jp = 0x800D7794; // type:func +func_800D78F4_jp = 0x800D78F4; // type:func +func_800D7948_jp = 0x800D7948; // type:func +func_800D79BC_jp = 0x800D79BC; // type:func +func_800D79F4_jp = 0x800D79F4; // type:func +func_800D7AE0_jp = 0x800D7AE0; // type:func +func_800D7B60_jp = 0x800D7B60; // type:func +func_800D7BAC_jp = 0x800D7BAC; // type:func +func_800D7C70_jp = 0x800D7C70; // type:func +func_800D7DD4_jp = 0x800D7DD4; // type:func +func_800D7E74_jp = 0x800D7E74; // type:func +func_800D7EFC_jp = 0x800D7EFC; // type:func +func_800D8094_jp = 0x800D8094; // type:func +func_800D81B4_jp = 0x800D81B4; // type:func +func_800D82BC_jp = 0x800D82BC; // type:func +func_800D8500_jp = 0x800D8500; // type:func +func_800D85EC_jp = 0x800D85EC; // type:func +func_800D8618_jp = 0x800D8618; // type:func +func_800D8644_jp = 0x800D8644; // type:func +func_800D8670_jp = 0x800D8670; // type:func +func_800D87C0_jp = 0x800D87C0; // type:func +func_800D88A0_jp = 0x800D88A0; // type:func +func_800D88B0_jp = 0x800D88B0; // type:func +func_800D88D4_jp = 0x800D88D4; // type:func +func_800D88E0_jp = 0x800D88E0; // type:func +func_800D8A54_jp = 0x800D8A54; // type:func +func_800D8DD4_jp = 0x800D8DD4; // type:func +func_800D8E18_jp = 0x800D8E18; // type:func +func_800D9018_jp = 0x800D9018; // type:func +func_800D93F4_jp = 0x800D93F4; // type:func +func_800D94F0_jp = 0x800D94F0; // type:func +func_800D9514_jp = 0x800D9514; // type:func +func_800D9524_jp = 0x800D9524; // type:func +func_800D955C_jp = 0x800D955C; // type:func +func_800D9618_jp = 0x800D9618; // type:func +func_800D96A8_jp = 0x800D96A8; // type:func +func_800D96E8_jp = 0x800D96E8; // type:func +func_800D9700_jp = 0x800D9700; // type:func +func_800D9750_jp = 0x800D9750; // type:func +func_800D9760_jp = 0x800D9760; // type:func +func_800D9770_jp = 0x800D9770; // type:func +func_800D9788_jp = 0x800D9788; // type:func +func_800D97A0_jp = 0x800D97A0; // type:func +func_800D97F8_jp = 0x800D97F8; // type:func +func_800D986C_jp = 0x800D986C; // type:func +func_800D9890_jp = 0x800D9890; // type:func +func_800D98C0_jp = 0x800D98C0; // type:func +func_800D9900_jp = 0x800D9900; // type:func +func_800D99F0_jp = 0x800D99F0; // type:func +func_800D9A6C_jp = 0x800D9A6C; // type:func +func_800D9B44_jp = 0x800D9B44; // type:func +func_800D9BA0_jp = 0x800D9BA0; // type:func +func_800D9C30_jp = 0x800D9C30; // type:func +func_800D9C60_jp = 0x800D9C60; // type:func +func_800D9D60_jp = 0x800D9D60; // type:func +func_800D9E24_jp = 0x800D9E24; // type:func +func_800D9E4C_jp = 0x800D9E4C; // type:func +func_800D9EA0_jp = 0x800D9EA0; // type:func +func_800D9EF4_jp = 0x800D9EF4; // type:func +func_800D9FA0_jp = 0x800D9FA0; // type:func +func_800DA028_jp = 0x800DA028; // type:func +func_800DA148_jp = 0x800DA148; // type:func +func_800DA3F4_jp = 0x800DA3F4; // type:func +func_800DA4E0_jp = 0x800DA4E0; // type:func +func_800DA540_jp = 0x800DA540; // type:func +func_800DA720_jp = 0x800DA720; // type:func +func_800DA79C_jp = 0x800DA79C; // type:func +func_800DA7E8_jp = 0x800DA7E8; // type:func +func_800DA834_jp = 0x800DA834; // type:func +func_800DA858_jp = 0x800DA858; // type:func +func_800DA910_jp = 0x800DA910; // type:func +func_800DA9E4_jp = 0x800DA9E4; // type:func +func_800DAA48_jp = 0x800DAA48; // type:func +func_800DAB88_jp = 0x800DAB88; // type:func +func_800DADAC_jp = 0x800DADAC; // type:func +func_800DADC4_jp = 0x800DADC4; // type:func +func_800DADE8_jp = 0x800DADE8; // type:func +func_800DAE2C_jp = 0x800DAE2C; // type:func +func_800DAE5C_jp = 0x800DAE5C; // type:func +func_800DAE88_jp = 0x800DAE88; // type:func +func_800DAEB0_jp = 0x800DAEB0; // type:func +func_800DAED8_jp = 0x800DAED8; // type:func +func_800DAEF8_jp = 0x800DAEF8; // type:func +func_800DAF70_jp = 0x800DAF70; // type:func +func_800DAFB0_jp = 0x800DAFB0; // type:func +func_800DAFF0_jp = 0x800DAFF0; // type:func +func_800DB030_jp = 0x800DB030; // type:func +func_800DB0A4_jp = 0x800DB0A4; // type:func +func_800DB10C_jp = 0x800DB10C; // type:func +func_800DB1B8_jp = 0x800DB1B8; // type:func +func_800DB368_jp = 0x800DB368; // type:func +func_800DB4E4_jp = 0x800DB4E4; // type:func +func_800DBF5C_jp = 0x800DBF5C; // type:func +func_800DC0C8_jp = 0x800DC0C8; // type:func +func_800DC154_jp = 0x800DC154; // type:func +func_800DC268_jp = 0x800DC268; // type:func +func_800DC2A8_jp = 0x800DC2A8; // type:func +func_800DC2E4_jp = 0x800DC2E4; // type:func +func_800DC31C_jp = 0x800DC31C; // type:func +func_800DC3A0_jp = 0x800DC3A0; // type:func +func_800DC6BC_jp = 0x800DC6BC; // type:func +func_800DC704_jp = 0x800DC704; // type:func +func_800DC754_jp = 0x800DC754; // type:func +func_800DC804_jp = 0x800DC804; // type:func +func_800DC8B0_jp = 0x800DC8B0; // type:func +func_800DC92C_jp = 0x800DC92C; // type:func +func_800DCAA0_jp = 0x800DCAA0; // type:func +func_800DCB14_jp = 0x800DCB14; // type:func +func_800DCE30_jp = 0x800DCE30; // type:func +func_800DCE78_jp = 0x800DCE78; // type:func +func_800DCF2C_jp = 0x800DCF2C; // type:func +func_800DCFA8_jp = 0x800DCFA8; // type:func +func_800DD130_jp = 0x800DD130; // type:func +func_800DD1A4_jp = 0x800DD1A4; // type:func +func_800DD4EC_jp = 0x800DD4EC; // type:func +func_800DD534_jp = 0x800DD534; // type:func +func_800DD5E8_jp = 0x800DD5E8; // type:func +func_800DD664_jp = 0x800DD664; // type:func +func_800DD7F0_jp = 0x800DD7F0; // type:func +func_800DD864_jp = 0x800DD864; // type:func +func_800DD940_jp = 0x800DD940; // type:func +func_800DDA48_jp = 0x800DDA48; // type:func +func_800DDBAC_jp = 0x800DDBAC; // type:func +func_800DDC5C_jp = 0x800DDC5C; // type:func +func_800DDCAC_jp = 0x800DDCAC; // type:func +func_800DDDF4_jp = 0x800DDDF4; // type:func +func_800DDFFC_jp = 0x800DDFFC; // type:func +func_800DE13C_jp = 0x800DE13C; // type:func +func_800DE55C_jp = 0x800DE55C; // type:func +func_800DE618_jp = 0x800DE618; // type:func +func_800DEFEC_jp = 0x800DEFEC; // type:func +func_800DF46C_jp = 0x800DF46C; // type:func +func_800DF48C_jp = 0x800DF48C; // type:func +func_800DF4AC_jp = 0x800DF4AC; // type:func +func_800DF4CC_jp = 0x800DF4CC; // type:func +func_800DF5A4_jp = 0x800DF5A4; // type:func +func_800DF5C4_jp = 0x800DF5C4; // type:func +func_800DF734_jp = 0x800DF734; // type:func +func_800DF754_jp = 0x800DF754; // type:func +func_800DF924_jp = 0x800DF924; // type:func +func_800DFCA4_jp = 0x800DFCA4; // type:func +func_800DFD10_jp = 0x800DFD10; // type:func +func_800DFD7C_jp = 0x800DFD7C; // type:func +func_800DFDE8_jp = 0x800DFDE8; // type:func +func_800DFE78_jp = 0x800DFE78; // type:func +func_800DFF04_jp = 0x800DFF04; // type:func +func_800DFF90_jp = 0x800DFF90; // type:func +func_800E0008_jp = 0x800E0008; // type:func +func_800E0198_jp = 0x800E0198; // type:func +func_800E01D0_jp = 0x800E01D0; // type:func +func_800E020C_jp = 0x800E020C; // type:func +func_800E0244_jp = 0x800E0244; // type:func +func_800E0260_jp = 0x800E0260; // type:func +func_800E0284_jp = 0x800E0284; // type:func +func_800E02AC_jp = 0x800E02AC; // type:func +func_800E02BC_jp = 0x800E02BC; // type:func +func_800E0314_jp = 0x800E0314; // type:func +func_800E041C_jp = 0x800E041C; // type:func +func_800E0500_jp = 0x800E0500; // type:func +func_800E0698_jp = 0x800E0698; // type:func +func_800E0834_jp = 0x800E0834; // type:func +func_800E09CC_jp = 0x800E09CC; // type:func +func_800E0C80_jp = 0x800E0C80; // type:func +func_800E0FD4_jp = 0x800E0FD4; // type:func +func_800E1180_jp = 0x800E1180; // type:func +func_800E139C_jp = 0x800E139C; // type:func +func_800E13C4_jp = 0x800E13C4; // type:func +func_800E13F0_jp = 0x800E13F0; // type:func +func_800E141C_jp = 0x800E141C; // type:func +func_800E14D4_jp = 0x800E14D4; // type:func +func_800E14FC_jp = 0x800E14FC; // type:func +func_800E1548_jp = 0x800E1548; // type:func +func_800E1594_jp = 0x800E1594; // type:func +func_800E15E0_jp = 0x800E15E0; // type:func +func_800E1668_jp = 0x800E1668; // type:func +func_800E18BC_jp = 0x800E18BC; // type:func +func_800E196C_jp = 0x800E196C; // type:func +func_800E19A4_jp = 0x800E19A4; // type:func +func_800E1AA0_jp = 0x800E1AA0; // type:func +func_800E1C38_jp = 0x800E1C38; // type:func +func_800E1DD0_jp = 0x800E1DD0; // type:func +func_800E221C_jp = 0x800E221C; // type:func +func_800E2318_jp = 0x800E2318; // type:func +func_800E25FC_jp = 0x800E25FC; // type:func +func_800E28E0_jp = 0x800E28E0; // type:func +func_800E28F0_jp = 0x800E28F0; // type:func +func_800E290C_jp = 0x800E290C; // type:func +func_800E291C_jp = 0x800E291C; // type:func +func_800E292C_jp = 0x800E292C; // type:func +func_800E293C_jp = 0x800E293C; // type:func +func_800E2950_jp = 0x800E2950; // type:func +func_800E299C_jp = 0x800E299C; // type:func +func_800E29B0_jp = 0x800E29B0; // type:func +func_800E2C08_jp = 0x800E2C08; // type:func +func_800E2C88_jp = 0x800E2C88; // type:func +func_800E2CCC_jp = 0x800E2CCC; // type:func +func_800E2D20_jp = 0x800E2D20; // type:func +func_800E30D4_jp = 0x800E30D4; // type:func +func_800E319C_jp = 0x800E319C; // type:func +func_800E3398_jp = 0x800E3398; // type:func +func_800E3408_jp = 0x800E3408; // type:func +func_800E34B0_jp = 0x800E34B0; // type:func +func_800E3558_jp = 0x800E3558; // type:func +func_800E3560_jp = 0x800E3560; // type:func +func_800E3580_jp = 0x800E3580; // type:func +func_800E3588_jp = 0x800E3588; // type:func +func_800E3590_jp = 0x800E3590; // type:func +func_800E3598_jp = 0x800E3598; // type:func +func_800E35CC_jp = 0x800E35CC; // type:func +func_800E35D4_jp = 0x800E35D4; // type:func +func_800E35DC_jp = 0x800E35DC; // type:func +func_800E35E4_jp = 0x800E35E4; // type:func +func_800E3618_jp = 0x800E3618; // type:func +func_800E3620_jp = 0x800E3620; // type:func +func_800E3628_jp = 0x800E3628; // type:func +func_800E3654_jp = 0x800E3654; // type:func +func_800E365C_jp = 0x800E365C; // type:func +func_800E3664_jp = 0x800E3664; // type:func +func_800E366C_jp = 0x800E366C; // type:func +func_800E3674_jp = 0x800E3674; // type:func +func_800E3698_jp = 0x800E3698; // type:func +func_800E36CC_jp = 0x800E36CC; // type:func +func_800E36D4_jp = 0x800E36D4; // type:func +func_800E36FC_jp = 0x800E36FC; // type:func +func_800E3724_jp = 0x800E3724; // type:func +func_800E3740_jp = 0x800E3740; // type:func +func_800E3748_jp = 0x800E3748; // type:func +func_800E3750_jp = 0x800E3750; // type:func +func_800E376C_jp = 0x800E376C; // type:func +func_800E37A0_jp = 0x800E37A0; // type:func +func_800E37A8_jp = 0x800E37A8; // type:func +func_800E37D4_jp = 0x800E37D4; // type:func +func_800E37DC_jp = 0x800E37DC; // type:func +func_800E37E4_jp = 0x800E37E4; // type:func +func_800E37EC_jp = 0x800E37EC; // type:func +func_800E37F4_jp = 0x800E37F4; // type:func +func_800E37FC_jp = 0x800E37FC; // type:func +func_800E3804_jp = 0x800E3804; // type:func +func_800E380C_jp = 0x800E380C; // type:func +func_800E3830_jp = 0x800E3830; // type:func +func_800E3848_jp = 0x800E3848; // type:func +func_800E38AC_jp = 0x800E38AC; // type:func +func_800E3A40_jp = 0x800E3A40; // type:func +func_800E3C38_jp = 0x800E3C38; // type:func +func_800E3DD8_jp = 0x800E3DD8; // type:func +func_800E3E80_jp = 0x800E3E80; // type:func +func_800E3F40_jp = 0x800E3F40; // type:func +func_800E3FEC_jp = 0x800E3FEC; // type:func +func_800E4098_jp = 0x800E4098; // type:func +func_800E41E4_jp = 0x800E41E4; // type:func +func_800E4250_jp = 0x800E4250; // type:func +func_800E42BC_jp = 0x800E42BC; // type:func +func_800E42C4_jp = 0x800E42C4; // type:func +func_800E4304_jp = 0x800E4304; // type:func +func_800E4378_jp = 0x800E4378; // type:func +func_800E4558_jp = 0x800E4558; // type:func +func_800E4600_jp = 0x800E4600; // type:func +func_800E4B6C_jp = 0x800E4B6C; // type:func +func_800E5A38_jp = 0x800E5A38; // type:func +func_800E5CEC_jp = 0x800E5CEC; // type:func +func_800E5D8C_jp = 0x800E5D8C; // type:func +func_800E6248_jp = 0x800E6248; // type:func +func_800E6500_jp = 0x800E6500; // type:func +func_800E651C_jp = 0x800E651C; // type:func +func_800E6660_jp = 0x800E6660; // type:func +func_800E6728_jp = 0x800E6728; // type:func +func_800E680C_jp = 0x800E680C; // type:func +func_800E6884_jp = 0x800E6884; // type:func +func_800E6924_jp = 0x800E6924; // type:func +func_800E694C_jp = 0x800E694C; // type:func +func_800E69A4_jp = 0x800E69A4; // type:func +func_800E69FC_jp = 0x800E69FC; // type:func +func_800E6A34_jp = 0x800E6A34; // type:func +func_800E6A6C_jp = 0x800E6A6C; // type:func +func_800E6AC8_jp = 0x800E6AC8; // type:func +func_800E6B14_jp = 0x800E6B14; // type:func +func_800E6B6C_jp = 0x800E6B6C; // type:func +func_800E6B94_jp = 0x800E6B94; // type:func +func_800E6BA8_jp = 0x800E6BA8; // type:func +func_800E6BD8_jp = 0x800E6BD8; // type:func +func_800E6BE8_jp = 0x800E6BE8; // type:func +func_800E6D28_jp = 0x800E6D28; // type:func +func_800E6D88_jp = 0x800E6D88; // type:func +func_800E6E0C_jp = 0x800E6E0C; // type:func +func_800E6E90_jp = 0x800E6E90; // type:func +func_800E6F54_jp = 0x800E6F54; // type:func +func_800E7018_jp = 0x800E7018; // type:func +func_800E77AC_jp = 0x800E77AC; // type:func +func_800E7804_jp = 0x800E7804; // type:func +func_800E7910_jp = 0x800E7910; // type:func +func_800E7CE4_jp = 0x800E7CE4; // type:func +func_800E7D14_jp = 0x800E7D14; // type:func +func_800E7D68_jp = 0x800E7D68; // type:func +func_800E7DC0_jp = 0x800E7DC0; // type:func +func_800E7F9C_jp = 0x800E7F9C; // type:func +func_800E7FA4_jp = 0x800E7FA4; // type:func +func_800E8068_jp = 0x800E8068; // type:func +func_800E80D4_jp = 0x800E80D4; // type:func +func_800E83D8_jp = 0x800E83D8; // type:func +func_800E899C_jp = 0x800E899C; // type:func +func_800E89F4_jp = 0x800E89F4; // type:func +func_800E8A78_jp = 0x800E8A78; // type:func +func_800E8AE8_jp = 0x800E8AE8; // type:func +func_800E8B80_jp = 0x800E8B80; // type:func +func_800E8E70_jp = 0x800E8E70; // type:func +func_800E8FE4_jp = 0x800E8FE4; // type:func +func_800E90D4_jp = 0x800E90D4; // type:func +func_800E9118_jp = 0x800E9118; // type:func +func_800E91B8_jp = 0x800E91B8; // type:func +func_800E91F4_jp = 0x800E91F4; // type:func +func_800E9344_jp = 0x800E9344; // type:func +func_800E9400_jp = 0x800E9400; // type:func +func_800E942C_jp = 0x800E942C; // type:func +func_800E945C_jp = 0x800E945C; // type:func +func_800E96C8_jp = 0x800E96C8; // type:func +func_800E9764_jp = 0x800E9764; // type:func +func_800E9808_jp = 0x800E9808; // type:func +func_800E9D5C_jp = 0x800E9D5C; // type:func +func_800E9FF0_jp = 0x800E9FF0; // type:func +func_800EA0DC_jp = 0x800EA0DC; // type:func +func_800EA418_jp = 0x800EA418; // type:func +func_800EA6B0_jp = 0x800EA6B0; // type:func +func_800EA728_jp = 0x800EA728; // type:func +func_800EA7A0_jp = 0x800EA7A0; // type:func +func_800EA818_jp = 0x800EA818; // type:func +func_800EA848_jp = 0x800EA848; // type:func +func_800EA878_jp = 0x800EA878; // type:func +func_800EA8D8_jp = 0x800EA8D8; // type:func +func_800EA908_jp = 0x800EA908; // type:func +func_800EA968_jp = 0x800EA968; // type:func +func_800EAA04_jp = 0x800EAA04; // type:func +func_800EAA6C_jp = 0x800EAA6C; // type:func +func_800EAB58_jp = 0x800EAB58; // type:func +func_800EAC28_jp = 0x800EAC28; // type:func +func_800EAC60_jp = 0x800EAC60; // type:func +func_800EACA4_jp = 0x800EACA4; // type:func +func_800EACE8_jp = 0x800EACE8; // type:func +func_800EAD2C_jp = 0x800EAD2C; // type:func +func_800EAD70_jp = 0x800EAD70; // type:func +func_800EAE20_jp = 0x800EAE20; // type:func +func_800EAEC8_jp = 0x800EAEC8; // type:func +func_800EAF38_jp = 0x800EAF38; // type:func +func_800EAF80_jp = 0x800EAF80; // type:func +func_800EAFD0_jp = 0x800EAFD0; // type:func +func_800EB100_jp = 0x800EB100; // type:func +func_800EB154_jp = 0x800EB154; // type:func +func_800EB174_jp = 0x800EB174; // type:func +func_800EB290_jp = 0x800EB290; // type:func +func_800EB394_jp = 0x800EB394; // type:func +func_800EB638_jp = 0x800EB638; // type:func +func_800EB674_jp = 0x800EB674; // type:func +func_800EB6C8_jp = 0x800EB6C8; // type:func +func_800EB70C_jp = 0x800EB70C; // type:func +func_800EB978_jp = 0x800EB978; // type:func +func_800EBA9C_jp = 0x800EBA9C; // type:func +func_800EBAB0_jp = 0x800EBAB0; // type:func +func_800EBB88_jp = 0x800EBB88; // type:func +func_800EBB90_jp = 0x800EBB90; // type:func +func_800EBBB0_jp = 0x800EBBB0; // type:func +func_800EBF3C_jp = 0x800EBF3C; // type:func +func_800EBF6C_jp = 0x800EBF6C; // type:func +func_800EBF78_jp = 0x800EBF78; // type:func +func_800EBF84_jp = 0x800EBF84; // type:func +func_800EBF90_jp = 0x800EBF90; // type:func +func_800EBFA0_jp = 0x800EBFA0; // type:func +func_800EC000_jp = 0x800EC000; // type:func +func_800EC3A4_jp = 0x800EC3A4; // type:func +func_800EC3B8_jp = 0x800EC3B8; // type:func +func_800EC588_jp = 0x800EC588; // type:func +func_800EC618_jp = 0x800EC618; // type:func +func_800EC620_jp = 0x800EC620; // type:func +func_800EC694_jp = 0x800EC694; // type:func +func_800EC81C_jp = 0x800EC81C; // type:func +func_800EC8A0_jp = 0x800EC8A0; // type:func +func_800EC8B4_jp = 0x800EC8B4; // type:func +func_800EC998_jp = 0x800EC998; // type:func +func_800EC9C8_jp = 0x800EC9C8; // type:func +func_800ECA4C_jp = 0x800ECA4C; // type:func +func_800ECB70_jp = 0x800ECB70; // type:func +func_800ECC94_jp = 0x800ECC94; // type:func +func_800ECCA0_jp = 0x800ECCA0; // type:func +func_800ECDDC_jp = 0x800ECDDC; // type:func +func_800ECF70_jp = 0x800ECF70; // type:func +func_800ED000_jp = 0x800ED000; // type:func +func_800ED070_jp = 0x800ED070; // type:func +func_800ED084_jp = 0x800ED084; // type:func +func_800ED1CC_jp = 0x800ED1CC; // type:func +func_800ED5C4_jp = 0x800ED5C4; // type:func +func_800ED778_jp = 0x800ED778; // type:func +func_800ED7C0_jp = 0x800ED7C0; // type:func +func_800ED8F4_jp = 0x800ED8F4; // type:func +func_800ED94C_jp = 0x800ED94C; // type:func +func_800EDDC8_jp = 0x800EDDC8; // type:func +func_800EDF08_jp = 0x800EDF08; // type:func +func_800EDF10_jp = 0x800EDF10; // type:func +func_800EDF18_jp = 0x800EDF18; // type:func +func_800EDF20_jp = 0x800EDF20; // type:func +func_800EDF8C_jp = 0x800EDF8C; // type:func +func_800EDFE4_jp = 0x800EDFE4; // type:func +func_800EE020_jp = 0x800EE020; // type:func +func_800EE050_jp = 0x800EE050; // type:func +func_800EE7C4_jp = 0x800EE7C4; // type:func +func_800EEC6C_jp = 0x800EEC6C; // type:func +func_800EECAC_jp = 0x800EECAC; // type:func +func_800EECE4_jp = 0x800EECE4; // type:func +func_800EED90_jp = 0x800EED90; // type:func +func_800EEDFC_jp = 0x800EEDFC; // type:func +func_800EEE20_jp = 0x800EEE20; // type:func +func_800EEE44_jp = 0x800EEE44; // type:func +func_800EEE74_jp = 0x800EEE74; // type:func +func_800EEEA4_jp = 0x800EEEA4; // type:func +func_800EEF3C_jp = 0x800EEF3C; // type:func +func_800EEF5C_jp = 0x800EEF5C; // type:func +func_800EF09C_jp = 0x800EF09C; // type:func +func_800EF168_jp = 0x800EF168; // type:func +func_800EF1CC_jp = 0x800EF1CC; // type:func +func_800EF1EC_jp = 0x800EF1EC; // type:func +func_800EF224_jp = 0x800EF224; // type:func +func_800EF27C_jp = 0x800EF27C; // type:func +func_800EF2D4_jp = 0x800EF2D4; // type:func +func_800EF374_jp = 0x800EF374; // type:func +func_800EF3C0_jp = 0x800EF3C0; // type:func +func_800EF404_jp = 0x800EF404; // type:func +func_800EF420_jp = 0x800EF420; // type:func +func_800EF450_jp = 0x800EF450; // type:func +func_800EF45C_jp = 0x800EF45C; // type:func +func_800EF634_jp = 0x800EF634; // type:func +func_800EF87C_jp = 0x800EF87C; // type:func +func_800EF8C4_jp = 0x800EF8C4; // type:func +func_800EF8E8_jp = 0x800EF8E8; // type:func +func_800EF91C_jp = 0x800EF91C; // type:func +func_800EF940_jp = 0x800EF940; // type:func +func_800EF980_jp = 0x800EF980; // type:func +func_800EF9B4_jp = 0x800EF9B4; // type:func +func_800EF9F0_jp = 0x800EF9F0; // type:func +func_800EFAFC_jp = 0x800EFAFC; // type:func +func_800EFB1C_jp = 0x800EFB1C; // type:func +func_800EFB3C_jp = 0x800EFB3C; // type:func +func_800EFC24_jp = 0x800EFC24; // type:func +func_800EFCA0_jp = 0x800EFCA0; // type:func +func_800EFCC0_jp = 0x800EFCC0; // type:func +func_800EFD00_jp = 0x800EFD00; // type:func +func_800EFD40_jp = 0x800EFD40; // type:func +func_800EFDB4_jp = 0x800EFDB4; // type:func +func_800EFDF0_jp = 0x800EFDF0; // type:func +func_800EFE60_jp = 0x800EFE60; // type:func +func_800EFEF0_jp = 0x800EFEF0; // type:func +func_800F033C_jp = 0x800F033C; // type:func +func_800F03F4_jp = 0x800F03F4; // type:func +func_800F04B4_jp = 0x800F04B4; // type:func +func_800F0518_jp = 0x800F0518; // type:func +func_800F0A38_jp = 0x800F0A38; // type:func +func_800F0A74_jp = 0x800F0A74; // type:func +func_800F0B48_jp = 0x800F0B48; // type:func +func_800F0C2C_jp = 0x800F0C2C; // type:func +func_800F0D20_jp = 0x800F0D20; // type:func +func_800F0E64_jp = 0x800F0E64; // type:func +func_800F11AC_jp = 0x800F11AC; // type:func +func_800F11CC_jp = 0x800F11CC; // type:func +func_800F11EC_jp = 0x800F11EC; // type:func +func_800F11FC_jp = 0x800F11FC; // type:func +func_800F124C_jp = 0x800F124C; // type:func +func_800F12F0_jp = 0x800F12F0; // type:func +func_800F1450_jp = 0x800F1450; // type:func +func_800F158C_jp = 0x800F158C; // type:func +func_800F15CC_jp = 0x800F15CC; // type:func +func_800F15F8_jp = 0x800F15F8; // type:func +func_800F1678_jp = 0x800F1678; // type:func +func_800F17F8_jp = 0x800F17F8; // type:func +func_800F182C_jp = 0x800F182C; // type:func +func_800F1858_jp = 0x800F1858; // type:func +func_800F18A4_jp = 0x800F18A4; // type:func +func_800F1908_jp = 0x800F1908; // type:func +func_800F1A00_jp = 0x800F1A00; // type:func +func_800F1CD4_jp = 0x800F1CD4; // type:func +func_800F1E10_jp = 0x800F1E10; // type:func +func_800F2010_jp = 0x800F2010; // type:func +func_800F2168_jp = 0x800F2168; // type:func +func_800F21C4_jp = 0x800F21C4; // type:func +func_800F21FC_jp = 0x800F21FC; // type:func +func_800F2408_jp = 0x800F2408; // type:func +func_800F2464_jp = 0x800F2464; // type:func +func_800F2554_jp = 0x800F2554; // type:func +func_800F2580_jp = 0x800F2580; // type:func +func_800F25A8_jp = 0x800F25A8; // type:func +func_800F2930_jp = 0x800F2930; // type:func +func_800F2998_jp = 0x800F2998; // type:func +func_800F2B74_jp = 0x800F2B74; // type:func +func_800F2CDC_jp = 0x800F2CDC; // type:func +func_800F2E34_jp = 0x800F2E34; // type:func +func_800F2EB0_jp = 0x800F2EB0; // type:func +func_800F2F00_jp = 0x800F2F00; // type:func +func_800F2F70_jp = 0x800F2F70; // type:func +func_800F3068_jp = 0x800F3068; // type:func +func_800F30E8_jp = 0x800F30E8; // type:func +func_800F3180_jp = 0x800F3180; // type:func +func_800F31A8_jp = 0x800F31A8; // type:func +func_800F3264_jp = 0x800F3264; // type:func +func_800F3354_jp = 0x800F3354; // type:func +func_800F3394_jp = 0x800F3394; // type:func +func_800F3438_jp = 0x800F3438; // type:func +func_800F344C_jp = 0x800F344C; // type:func +func_800F3484_jp = 0x800F3484; // type:func +func_800F34C4_jp = 0x800F34C4; // type:func +func_800F35E0_jp = 0x800F35E0; // type:func +func_800F3674_jp = 0x800F3674; // type:func +func_800F3760_jp = 0x800F3760; // type:func +func_800F3B58_jp = 0x800F3B58; // type:func +func_800F42D0_jp = 0x800F42D0; // type:func +func_800F46D4_jp = 0x800F46D4; // type:func +func_800F472C_jp = 0x800F472C; // type:func +func_800F47A0_jp = 0x800F47A0; // type:func +func_800F484C_jp = 0x800F484C; // type:func +func_800F4870_jp = 0x800F4870; // type:func +func_800F5660_jp = 0x800F5660; // type:func +func_800F6034_jp = 0x800F6034; // type:func +func_800F60F0_jp = 0x800F60F0; // type:func +func_800F6140_jp = 0x800F6140; // type:func +func_800F6210_jp = 0x800F6210; // type:func +func_800F62EC_jp = 0x800F62EC; // type:func +func_800F63BC_jp = 0x800F63BC; // type:func +func_800F6460_jp = 0x800F6460; // type:func +func_800F64A0_jp = 0x800F64A0; // type:func +func_800F65F4_jp = 0x800F65F4; // type:func +func_800F6644_jp = 0x800F6644; // type:func +func_800F67AC_jp = 0x800F67AC; // type:func +func_800F6884_jp = 0x800F6884; // type:func +func_800F695C_jp = 0x800F695C; // type:func +func_800F6A20_jp = 0x800F6A20; // type:func +func_800F6AA4_jp = 0x800F6AA4; // type:func +func_800F6B0C_jp = 0x800F6B0C; // type:func +func_800F6B34_jp = 0x800F6B34; // type:func +func_800F6BB4_jp = 0x800F6BB4; // type:func +func_800F6BF8_jp = 0x800F6BF8; // type:func +func_800F6FCC_jp = 0x800F6FCC; // type:func +func_800F7078_jp = 0x800F7078; // type:func +func_800F70B0_jp = 0x800F70B0; // type:func +func_800F70E8_jp = 0x800F70E8; // type:func +func_800F71A0_jp = 0x800F71A0; // type:func +func_800F7288_jp = 0x800F7288; // type:func +func_800F755C_jp = 0x800F755C; // type:func +func_800F7620_jp = 0x800F7620; // type:func +func_800F76CC_jp = 0x800F76CC; // type:func +func_800F7810_jp = 0x800F7810; // type:func +func_800F7870_jp = 0x800F7870; // type:func +func_800F7A24_jp = 0x800F7A24; // type:func +func_800F7A7C_jp = 0x800F7A7C; // type:func +func_800F7DA0_jp = 0x800F7DA0; // type:func +func_800F8024_jp = 0x800F8024; // type:func +func_800F8164_jp = 0x800F8164; // type:func +func_800F83E4_jp = 0x800F83E4; // type:func +func_800F8440_jp = 0x800F8440; // type:func +func_800F8448_jp = 0x800F8448; // type:func +func_800F84AC_jp = 0x800F84AC; // type:func +func_800F85B4_jp = 0x800F85B4; // type:func +func_800F85D0_jp = 0x800F85D0; // type:func +func_800F86B8_jp = 0x800F86B8; // type:func +func_800F87A4_jp = 0x800F87A4; // type:func +func_800F8814_jp = 0x800F8814; // type:func +func_800F8848_jp = 0x800F8848; // type:func +func_800F8850_jp = 0x800F8850; // type:func +func_800F88BC_jp = 0x800F88BC; // type:func +func_800F88E8_jp = 0x800F88E8; // type:func +func_800F8984_jp = 0x800F8984; // type:func +func_800F89C0_jp = 0x800F89C0; // type:func +func_800F8B2C_jp = 0x800F8B2C; // type:func +func_800F8B4C_jp = 0x800F8B4C; // type:func +func_800F8C94_jp = 0x800F8C94; // type:func +func_800F8CE0_jp = 0x800F8CE0; // type:func +func_800F8D08_jp = 0x800F8D08; // type:func +func_800F8D24_jp = 0x800F8D24; // type:func +func_800F8D40_jp = 0x800F8D40; // type:func +func_800F8D5C_jp = 0x800F8D5C; // type:func +func_800F8E24_jp = 0x800F8E24; // type:func +func_800F8FC4_jp = 0x800F8FC4; // type:func +func_800F9064_jp = 0x800F9064; // type:func +func_800F9118_jp = 0x800F9118; // type:func +func_800F9170_jp = 0x800F9170; // type:func +func_800F91E0_jp = 0x800F91E0; // type:func +func_800F91FC_jp = 0x800F91FC; // type:func +func_800F9C24_jp = 0x800F9C24; // type:func +func_800F9C44_jp = 0x800F9C44; // type:func +func_800F9C54_jp = 0x800F9C54; // type:func +func_800F9C60_jp = 0x800F9C60; // type:func +func_800FA0AC_jp = 0x800FA0AC; // type:func +func_800FA2E0_jp = 0x800FA2E0; // type:func +func_800FA2F0_jp = 0x800FA2F0; // type:func +func_800FA354_jp = 0x800FA354; // type:func +func_800FA498_jp = 0x800FA498; // type:func +func_800FA510_jp = 0x800FA510; // type:func +func_800FA520_jp = 0x800FA520; // type:func +func_800FA580_jp = 0x800FA580; // type:func +func_800FA720_jp = 0x800FA720; // type:func +func_800FA7B0_jp = 0x800FA7B0; // type:func +func_800FA88C_jp = 0x800FA88C; // type:func +func_800FA92C_jp = 0x800FA92C; // type:func +func_800FAA14_jp = 0x800FAA14; // type:func +func_800FAB8C_jp = 0x800FAB8C; // type:func +func_800FAC58_jp = 0x800FAC58; // type:func +func_800FAC84_jp = 0x800FAC84; // type:func +func_800FACC8_jp = 0x800FACC8; // type:func +func_800FAD38_jp = 0x800FAD38; // type:func +func_800FAE84_jp = 0x800FAE84; // type:func +func_800FB128_jp = 0x800FB128; // type:func +func_800FB234_jp = 0x800FB234; // type:func +func_800FB29C_jp = 0x800FB29C; // type:func +func_800FB2D8_jp = 0x800FB2D8; // type:func +func_800FB350_jp = 0x800FB350; // type:func +func_800FB39C_jp = 0x800FB39C; // type:func +func_800FB3E8_jp = 0x800FB3E8; // type:func +func_800FB744_jp = 0x800FB744; // type:func +func_800FBA90_jp = 0x800FBA90; // type:func +func_800FBB44_jp = 0x800FBB44; // type:func +func_800FBB7C_jp = 0x800FBB7C; // type:func +func_800FBBBC_jp = 0x800FBBBC; // type:func +func_800FBCA8_jp = 0x800FBCA8; // type:func +func_800FBD80_jp = 0x800FBD80; // type:func +func_800FBE20_jp = 0x800FBE20; // type:func +func_800FBEF4_jp = 0x800FBEF4; // type:func +func_800FBFF8_jp = 0x800FBFF8; // type:func +func_800FC02C_jp = 0x800FC02C; // type:func +func_800FC0B8_jp = 0x800FC0B8; // type:func +func_800FC110_jp = 0x800FC110; // type:func +func_800FC16C_jp = 0x800FC16C; // type:func +func_800FC19C_jp = 0x800FC19C; // type:func +func_800FC1F0_jp = 0x800FC1F0; // type:func +func_800FC254_jp = 0x800FC254; // type:func +func_800FC3F0_jp = 0x800FC3F0; // type:func +func_800FC430_jp = 0x800FC430; // type:func +func_800FC520_jp = 0x800FC520; // type:func +func_800FC564_jp = 0x800FC564; // type:func +func_800FC5C8_jp = 0x800FC5C8; // type:func +func_800FC6A0_jp = 0x800FC6A0; // type:func +func_800FC920_jp = 0x800FC920; // type:func +func_800FCA40_jp = 0x800FCA40; // type:func +func_800FCAD8_jp = 0x800FCAD8; // type:func +func_800FCE80_jp = 0x800FCE80; // type:func +func_800FCEEC_jp = 0x800FCEEC; // type:func +func_800FD0A4_jp = 0x800FD0A4; // type:func +func_800FD0D4_jp = 0x800FD0D4; // type:func +func_800FD13C_jp = 0x800FD13C; // type:func +func_800FD170_jp = 0x800FD170; // type:func +func_800FD280_jp = 0x800FD280; // type:func +D_800FD2D0_jp = 0x800FD2D0; // +func_800FE220_jp = 0x800FE220; // type:func +func_800FE420_jp = 0x800FE420; // type:func +func_800FE480_jp = 0x800FE480; // type:func +func_800FE670_jp = 0x800FE670; // type:func +func_800FE8D0_jp = 0x800FE8D0; // type:func +func_800FEABC_jp = 0x800FEABC; // type:func +func_800FEBE0_jp = 0x800FEBE0; // type:func +func_800FECD0_jp = 0x800FECD0; // type:func +func_800FEE10_jp = 0x800FEE10; // type:func +func_800FEF9C_jp = 0x800FEF9C; // type:func +func_800FF060_jp = 0x800FF060; // type:func +D_800FF370_jp = 0x800FF370; // +func_801002CC_jp = 0x801002CC; // type:func +D_801002F0_jp = 0x801002F0; // + +// .data + +D_80100C30_jp = 0x80100C30; // +D_80100C50_jp = 0x80100C50; // type:u16 +D_80100C5C_jp = 0x80100C5C; // +D_80100C60_jp = 0x80100C60; // +D_80100C64_jp = 0x80100C64; // +D_80100C68_jp = 0x80100C68; // +D_80100C70_jp = 0x80100C70; // +D_80100C90_jp = 0x80100C90; // +D_80100CA4_jp = 0x80100CA4; // +D_8010119C_jp = 0x8010119C; // type:u8 +D_801024F4_jp = 0x801024F4; // type:u8 +D_801025B0_jp = 0x801025B0; // +D_801025C0_jp = 0x801025C0; // +D_FLT_801025C8_jp = 0x801025C8; // type:f32 +D_801025F8_jp = 0x801025F8; // +D_80102600_jp = 0x80102600; // +D_80102608_jp = 0x80102608; // +D_80102610_jp = 0x80102610; // +D_80102620_jp = 0x80102620; // +D_80102628_jp = 0x80102628; // +D_80102630_jp = 0x80102630; // type:u8 +D_80102634_jp = 0x80102634; // +D_80102658_jp = 0x80102658; // type:u8 +D_801026D8_jp = 0x801026D8; // +D_801026E0_jp = 0x801026E0; // +D_80102700_jp = 0x80102700; // +D_80102754_jp = 0x80102754; // type:u8 +D_80102770_jp = 0x80102770; // +D_FLT_8010277C_jp = 0x8010277C; // type:f32 +D_80102784_jp = 0x80102784; // +D_FLT_80102788_jp = 0x80102788; // type:f32 +D_801027B8_jp = 0x801027B8; // type:u16 +D_801027BE_jp = 0x801027BE; // +D_801027C4_jp = 0x801027C4; // +D_80102800_jp = 0x80102800; // type:s16 +D_80102808_jp = 0x80102808; // type:s16 +D_80102810_jp = 0x80102810; // type:s8 +D_80102834_jp = 0x80102834; // +D_80102838_jp = 0x80102838; // +D_8010283C_jp = 0x8010283C; // +D_80102840_jp = 0x80102840; // +D_801028C0_jp = 0x801028C0; // +D_FLT_801028C8_jp = 0x801028C8; // type:f32 +D_FLT_801028CC_jp = 0x801028CC; // type:f32 +D_FLT_801028D0_jp = 0x801028D0; // type:f32 +D_801028D4_jp = 0x801028D4; // +D_801028E0_jp = 0x801028E0; // +D_80102A18_jp = 0x80102A18; // +D_80102A48_jp = 0x80102A48; // +D_80102A80_jp = 0x80102A80; // +D_80102C04_jp = 0x80102C04; // +D_80102C14_jp = 0x80102C14; // +D_80102C28_jp = 0x80102C28; // +D_80102C68_jp = 0x80102C68; // +D_80103C68_jp = 0x80103C68; // +D_80103CE0_jp = 0x80103CE0; // +D_80103D50_jp = 0x80103D50; // +D_80103D55_jp = 0x80103D55; // type:u8 +D_80103D59_jp = 0x80103D59; // type:u8 +D_80103D60_jp = 0x80103D60; // +D_80103D84_jp = 0x80103D84; // type:s16 +D_80103E04_jp = 0x80103E04; // type:s16 +D_80103E94_jp = 0x80103E94; // +D_80103E98_jp = 0x80103E98; // +D_80103E9C_jp = 0x80103E9C; // +D_80103EA4_jp = 0x80103EA4; // +D_FLT_80103EB0_jp = 0x80103EB0; // type:f32 +D_80103F10_jp = 0x80103F10; // +D_80103F1C_jp = 0x80103F1C; // +D_80103F28_jp = 0x80103F28; // +D_80103F34_jp = 0x80103F34; // +D_80103F40_jp = 0x80103F40; // +D_80103F4C_jp = 0x80103F4C; // +D_80103F68_jp = 0x80103F68; // +D_80103F9C_jp = 0x80103F9C; // +D_80103FA4_jp = 0x80103FA4; // +D_80103FAC_jp = 0x80103FAC; // +D_80103FB4_jp = 0x80103FB4; // +D_80103FBC_jp = 0x80103FBC; // +D_80103FC4_jp = 0x80103FC4; // +D_80103FCC_jp = 0x80103FCC; // +D_80103FD4_jp = 0x80103FD4; // +D_80103FDC_jp = 0x80103FDC; // +D_801040FC_jp = 0x801040FC; // +D_8010410C_jp = 0x8010410C; // +D_8010411C_jp = 0x8010411C; // +D_8010412C_jp = 0x8010412C; // +D_8010413C_jp = 0x8010413C; // +D_8010414C_jp = 0x8010414C; // +D_8010415C_jp = 0x8010415C; // +D_80104174_jp = 0x80104174; // +D_8010417C_jp = 0x8010417C; // +D_80104184_jp = 0x80104184; // +D_8010418C_jp = 0x8010418C; // +D_80104194_jp = 0x80104194; // +D_801041A4_jp = 0x801041A4; // +D_801041AC_jp = 0x801041AC; // +D_801041B0_jp = 0x801041B0; // +D_801041B8_jp = 0x801041B8; // +D_801041C4_jp = 0x801041C4; // +D_801041CC_jp = 0x801041CC; // +D_801041D8_jp = 0x801041D8; // +D_801041E4_jp = 0x801041E4; // +D_801041F0_jp = 0x801041F0; // +D_801041FC_jp = 0x801041FC; // +D_80104208_jp = 0x80104208; // +D_80104214_jp = 0x80104214; // +D_80104220_jp = 0x80104220; // +D_80104224_jp = 0x80104224; // type:u8 +D_80104228_jp = 0x80104228; // +D_80104230_jp = 0x80104230; // +D_8010423C_jp = 0x8010423C; // type:u8 +D_80104248_jp = 0x80104248; // +D_80104260_jp = 0x80104260; // +D_80104278_jp = 0x80104278; // +D_80104290_jp = 0x80104290; // +D_801042D0_jp = 0x801042D0; // type:u8 +D_80104310_jp = 0x80104310; // +D_80104318_jp = 0x80104318; // +D_80104320_jp = 0x80104320; // +D_8010432C_jp = 0x8010432C; // type:u8 +D_8010436C_jp = 0x8010436C; // +D_80104370_jp = 0x80104370; // +D_801043D0_jp = 0x801043D0; // +D_801043DC_jp = 0x801043DC; // +D_801043E8_jp = 0x801043E8; // +D_801043F4_jp = 0x801043F4; // +D_FLT_80104400_jp = 0x80104400; // type:f32 +D_80104430_jp = 0x80104430; // +D_8010443C_jp = 0x8010443C; // +D_80104448_jp = 0x80104448; // +D_80104454_jp = 0x80104454; // +D_80104460_jp = 0x80104460; // +D_8010446C_jp = 0x8010446C; // +D_80104478_jp = 0x80104478; // +D_80104484_jp = 0x80104484; // +D_80104490_jp = 0x80104490; // +D_8010449C_jp = 0x8010449C; // +D_801044A8_jp = 0x801044A8; // +D_801044B4_jp = 0x801044B4; // +D_801044C0_jp = 0x801044C0; // +D_801044CC_jp = 0x801044CC; // +D_801044D8_jp = 0x801044D8; // +D_801044E4_jp = 0x801044E4; // +D_801044F0_jp = 0x801044F0; // +D_801044FC_jp = 0x801044FC; // +D_80104508_jp = 0x80104508; // type:u8 +D_80104509_jp = 0x80104509; // type:u8 +D_8010450A_jp = 0x8010450A; // type:u8 +D_8010450B_jp = 0x8010450B; // type:u8 +D_8010450C_jp = 0x8010450C; // type:u8 +D_8010450D_jp = 0x8010450D; // type:u8 +D_8010450E_jp = 0x8010450E; // type:u8 +D_8010450F_jp = 0x8010450F; // type:u8 +D_80104510_jp = 0x80104510; // type:u8 +D_80104518_jp = 0x80104518; // +D_8010451C_jp = 0x8010451C; // +D_80104528_jp = 0x80104528; // +D_80104534_jp = 0x80104534; // +D_80104540_jp = 0x80104540; // +D_80104548_jp = 0x80104548; // +D_80104550_jp = 0x80104550; // +D_8010455C_jp = 0x8010455C; // +D_FLT_80104568_jp = 0x80104568; // type:f32 +D_801045B0_jp = 0x801045B0; // +D_801045BC_jp = 0x801045BC; // +D_801045C8_jp = 0x801045C8; // +D_801045D4_jp = 0x801045D4; // +D_801045E0_jp = 0x801045E0; // +D_801045EC_jp = 0x801045EC; // +D_FLT_801045F8_jp = 0x801045F8; // type:f32 +D_801045FC_jp = 0x801045FC; // +D_80104674_jp = 0x80104674; // +D_8010467C_jp = 0x8010467C; // +D_80104688_jp = 0x80104688; // +D_80104690_jp = 0x80104690; // +D_801046A0_jp = 0x801046A0; // +D_801046AC_jp = 0x801046AC; // +D_801046C4_jp = 0x801046C4; // +D_801046D0_jp = 0x801046D0; // +D_80104710_jp = 0x80104710; // +D_8010471C_jp = 0x8010471C; // +D_80104740_jp = 0x80104740; // +D_80104764_jp = 0x80104764; // +D_80104770_jp = 0x80104770; // +D_80104790_jp = 0x80104790; // +D_80104794_jp = 0x80104794; // +D_80104798_jp = 0x80104798; // +D_8010479C_jp = 0x8010479C; // +D_801047A4_jp = 0x801047A4; // +D_801047A8_jp = 0x801047A8; // +D_801047B0_jp = 0x801047B0; // +D_801047B8_jp = 0x801047B8; // +D_801047C0_jp = 0x801047C0; // +D_801047C8_jp = 0x801047C8; // +D_801047F8_jp = 0x801047F8; // +D_80104800_jp = 0x80104800; // +D_80104810_jp = 0x80104810; // +D_80104814_jp = 0x80104814; // type:s8 +D_8010485C_jp = 0x8010485C; // type:u8 +D_8010487C_jp = 0x8010487C; // type:s16 +D_80104880_jp = 0x80104880; // type:u8 +D_801048A0_jp = 0x801048A0; // type:u16 +D_80104938_jp = 0x80104938; // type:u8 +D_80104960_jp = 0x80104960; // +D_801049F8_jp = 0x801049F8; // +D_801049FC_jp = 0x801049FC; // +D_80104A00_jp = 0x80104A00; // +D_80104A04_jp = 0x80104A04; // +D_80104A08_jp = 0x80104A08; // +D_80104A0C_jp = 0x80104A0C; // +D_80104A10_jp = 0x80104A10; // +D_80104A14_jp = 0x80104A14; // +D_80104A18_jp = 0x80104A18; // +D_FLT_80104A20_jp = 0x80104A20; // type:f32 +D_80104A60_jp = 0x80104A60; // type:s16 +D_80104A70_jp = 0x80104A70; // +D_80104A74_jp = 0x80104A74; // +D_80104A90_jp = 0x80104A90; // +D_80104AAC_jp = 0x80104AAC; // +D_80104AE4_jp = 0x80104AE4; // +D_80104AE8_jp = 0x80104AE8; // +D_80104B20_jp = 0x80104B20; // +D_80104B60_jp = 0x80104B60; // +D_80104F2C_jp = 0x80104F2C; // +D_80104F90_jp = 0x80104F90; // +D_80104F94_jp = 0x80104F94; // +D_80104F98_jp = 0x80104F98; // +D_80104F9C_jp = 0x80104F9C; // +D_80104FA0_jp = 0x80104FA0; // type:s16 +D_80104FAC_jp = 0x80104FAC; // +D_80104FB0_jp = 0x80104FB0; // +D_80104FB4_jp = 0x80104FB4; // +D_80104FB8_jp = 0x80104FB8; // type:s16 +D_80104FBC_jp = 0x80104FBC; // +D_80104FC8_jp = 0x80104FC8; // +D_80104FD4_jp = 0x80104FD4; // +D_80104FE0_jp = 0x80104FE0; // type:u16 +D_80105008_jp = 0x80105008; // +D_8010500C_jp = 0x8010500C; // +D_80105010_jp = 0x80105010; // +D_80105030_jp = 0x80105030; // +D_8010506C_jp = 0x8010506C; // +D_8010507C_jp = 0x8010507C; // +D_8010508C_jp = 0x8010508C; // +D_80105094_jp = 0x80105094; // +D_80105098_jp = 0x80105098; // +D_8010509C_jp = 0x8010509C; // +D_801050AC_jp = 0x801050AC; // +D_801050BC_jp = 0x801050BC; // +D_801050CC_jp = 0x801050CC; // +D_801050DC_jp = 0x801050DC; // +D_801050E4_jp = 0x801050E4; // +D_801050F4_jp = 0x801050F4; // +D_801050FC_jp = 0x801050FC; // +D_8010510C_jp = 0x8010510C; // +D_80105114_jp = 0x80105114; // +D_80105124_jp = 0x80105124; // +D_8010512C_jp = 0x8010512C; // +D_8010513C_jp = 0x8010513C; // +D_80105144_jp = 0x80105144; // +D_80105154_jp = 0x80105154; // +D_8010515C_jp = 0x8010515C; // +D_8010516C_jp = 0x8010516C; // +D_80105174_jp = 0x80105174; // +D_80105190_jp = 0x80105190; // +D_80105194_jp = 0x80105194; // +D_801051A4_jp = 0x801051A4; // +D_801051B0_jp = 0x801051B0; // +D_801051BC_jp = 0x801051BC; // +D_801051C4_jp = 0x801051C4; // +D_801051C8_jp = 0x801051C8; // +D_801051CC_jp = 0x801051CC; // +D_801051DC_jp = 0x801051DC; // +D_801051E8_jp = 0x801051E8; // +D_801051F4_jp = 0x801051F4; // +D_80105200_jp = 0x80105200; // +D_80105208_jp = 0x80105208; // +D_80105214_jp = 0x80105214; // +D_8010521C_jp = 0x8010521C; // +D_80105228_jp = 0x80105228; // +D_80105230_jp = 0x80105230; // +D_8010523C_jp = 0x8010523C; // +D_80105244_jp = 0x80105244; // +D_80105250_jp = 0x80105250; // +D_80105258_jp = 0x80105258; // +D_80105264_jp = 0x80105264; // +D_8010526C_jp = 0x8010526C; // +D_80105278_jp = 0x80105278; // +D_80105280_jp = 0x80105280; // +D_8010529C_jp = 0x8010529C; // +D_801052A0_jp = 0x801052A0; // +D_801052B0_jp = 0x801052B0; // +D_801052C0_jp = 0x801052C0; // +D_801052D0_jp = 0x801052D0; // +D_801052E0_jp = 0x801052E0; // +D_801052E8_jp = 0x801052E8; // +D_801052F8_jp = 0x801052F8; // +D_80105300_jp = 0x80105300; // +D_80105310_jp = 0x80105310; // +D_80105318_jp = 0x80105318; // +D_80105328_jp = 0x80105328; // +D_80105330_jp = 0x80105330; // +D_80105340_jp = 0x80105340; // +D_80105348_jp = 0x80105348; // +D_80105358_jp = 0x80105358; // +D_80105360_jp = 0x80105360; // +D_80105370_jp = 0x80105370; // +D_80105378_jp = 0x80105378; // +D_80105394_jp = 0x80105394; // +D_80105398_jp = 0x80105398; // +D_801053A8_jp = 0x801053A8; // +D_801053B8_jp = 0x801053B8; // +D_801053C8_jp = 0x801053C8; // +D_801053D0_jp = 0x801053D0; // +D_801053D4_jp = 0x801053D4; // +D_801053D8_jp = 0x801053D8; // +D_801053E8_jp = 0x801053E8; // +D_801053F4_jp = 0x801053F4; // +D_80105400_jp = 0x80105400; // +D_80105408_jp = 0x80105408; // +D_8010540C_jp = 0x8010540C; // +D_80105410_jp = 0x80105410; // +D_80105420_jp = 0x80105420; // +D_8010542C_jp = 0x8010542C; // +D_80105438_jp = 0x80105438; // +D_80105440_jp = 0x80105440; // +D_80105444_jp = 0x80105444; // +D_80105448_jp = 0x80105448; // +D_80105458_jp = 0x80105458; // +D_8010546C_jp = 0x8010546C; // +D_80105480_jp = 0x80105480; // +D_80105488_jp = 0x80105488; // +D_8010548C_jp = 0x8010548C; // +D_80105490_jp = 0x80105490; // +D_801054A0_jp = 0x801054A0; // +D_801054AC_jp = 0x801054AC; // +D_801054B8_jp = 0x801054B8; // +D_801054C0_jp = 0x801054C0; // +D_801054C4_jp = 0x801054C4; // +D_801054C8_jp = 0x801054C8; // +D_801054D8_jp = 0x801054D8; // +D_801054E8_jp = 0x801054E8; // +D_801054F8_jp = 0x801054F8; // +D_80105500_jp = 0x80105500; // +D_80105510_jp = 0x80105510; // +D_80105518_jp = 0x80105518; // +D_80105528_jp = 0x80105528; // +D_80105530_jp = 0x80105530; // +D_80105540_jp = 0x80105540; // +D_80105548_jp = 0x80105548; // +D_80105558_jp = 0x80105558; // +D_80105560_jp = 0x80105560; // +D_80105570_jp = 0x80105570; // +D_80105578_jp = 0x80105578; // +D_80105588_jp = 0x80105588; // +D_80105590_jp = 0x80105590; // +D_801055AC_jp = 0x801055AC; // +D_801055B0_jp = 0x801055B0; // +D_801055C0_jp = 0x801055C0; // +D_801055C4_jp = 0x801055C4; // +D_801055C8_jp = 0x801055C8; // +D_801055D0_jp = 0x801055D0; // +D_801055D4_jp = 0x801055D4; // +D_801055D8_jp = 0x801055D8; // +D_801055E8_jp = 0x801055E8; // +D_80105624_jp = 0x80105624; // +D_80105628_jp = 0x80105628; // +D_80105670_jp = 0x80105670; // +D_801056A0_jp = 0x801056A0; // +D_80105830_jp = 0x80105830; // +D_80106030_jp = 0x80106030; // +D_80106130_jp = 0x80106130; // +D_80106158_jp = 0x80106158; // type:s16 +D_80106170_jp = 0x80106170; // +D_801061A0_jp = 0x801061A0; // +D_801061A4_jp = 0x801061A4; // type:u8 +D_801061A7_jp = 0x801061A7; // type:u8 +D_801061AC_jp = 0x801061AC; // type:u8 +D_801061B4_jp = 0x801061B4; // +D_801061B8_jp = 0x801061B8; // +D_801061C0_jp = 0x801061C0; // +D_801061D4_jp = 0x801061D4; // +D_801061E4_jp = 0x801061E4; // +D_80106200_jp = 0x80106200; // +D_80106204_jp = 0x80106204; // +D_80106208_jp = 0x80106208; // +D_80106408_jp = 0x80106408; // type:u16 +D_80106478_jp = 0x80106478; // +D_80106488_jp = 0x80106488; // +D_801064D0_jp = 0x801064D0; // +D_80106518_jp = 0x80106518; // +D_80106560_jp = 0x80106560; // +D_80106638_jp = 0x80106638; // +D_80106660_jp = 0x80106660; // +D_801066CC_jp = 0x801066CC; // +D_80106738_jp = 0x80106738; // +D_8010674C_jp = 0x8010674C; // +D_80106794_jp = 0x80106794; // +D_801067A4_jp = 0x801067A4; // +D_80106814_jp = 0x80106814; // +D_80106818_jp = 0x80106818; // +D_80106820_jp = 0x80106820; // +D_80106824_jp = 0x80106824; // +D_80106828_jp = 0x80106828; // +D_8010682C_jp = 0x8010682C; // +D_80106830_jp = 0x80106830; // +D_8010685C_jp = 0x8010685C; // +D_FLT_80106890_jp = 0x80106890; // type:f32 +D_FLT_8010689C_jp = 0x8010689C; // type:f32 +D_FLT_801068A8_jp = 0x801068A8; // type:f32 +D_FLT_801068AC_jp = 0x801068AC; // type:f32 +D_801068C0_jp = 0x801068C0; // +D_801068CC_jp = 0x801068CC; // +D_801068D8_jp = 0x801068D8; // +D_FLT_80106920_jp = 0x80106920; // type:f32 +D_FLT_80106968_jp = 0x80106968; // type:f32 +D_8010696C_jp = 0x8010696C; // +D_80106978_jp = 0x80106978; // +D_80106984_jp = 0x80106984; // +D_801069E0_jp = 0x801069E0; // +D_80106A08_jp = 0x80106A08; // type:u16 +D_80106A0C_jp = 0x80106A0C; // +D_80106A10_jp = 0x80106A10; // +D_80106A14_jp = 0x80106A14; // type:s8 +D_80106A3C_jp = 0x80106A3C; // +D_80106A40_jp = 0x80106A40; // +D_80106A4C_jp = 0x80106A4C; // +D_80106A50_jp = 0x80106A50; // +D_FLT_80106A58_jp = 0x80106A58; // type:f32 +D_80106A60_jp = 0x80106A60; // +D_80106A64_jp = 0x80106A64; // +D_80106A68_jp = 0x80106A68; // +D_80106A78_jp = 0x80106A78; // +D_80106A7C_jp = 0x80106A7C; // +D_80106A90_jp = 0x80106A90; // +D_80106A94_jp = 0x80106A94; // +D_80106A98_jp = 0x80106A98; // type:u8 +D_80106A9C_jp = 0x80106A9C; // +D_80106AA0_jp = 0x80106AA0; // +D_80106AA4_jp = 0x80106AA4; // +D_80106AA8_jp = 0x80106AA8; // +D_80106AAC_jp = 0x80106AAC; // +D_80106AB0_jp = 0x80106AB0; // +D_80106AB4_jp = 0x80106AB4; // +D_80106ABC_jp = 0x80106ABC; // +D_80106ACC_jp = 0x80106ACC; // +D_80106AF0_jp = 0x80106AF0; // type:s8 +D_80106AF4_jp = 0x80106AF4; // type:u8 +D_80106BF4_jp = 0x80106BF4; // type:s8 +D_80106BF5_jp = 0x80106BF5; // type:s8 +D_80106CB8_jp = 0x80106CB8; // +D_80106D20_jp = 0x80106D20; // +D_FLT_80106D24_jp = 0x80106D24; // type:f32 +D_80106D30_jp = 0x80106D30; // +D_80106D38_jp = 0x80106D38; // +D_80106D4C_jp = 0x80106D4C; // +D_80106D50_jp = 0x80106D50; // +D_80106D64_jp = 0x80106D64; // +D_80106D78_jp = 0x80106D78; // +D_80106D8C_jp = 0x80106D8C; // +D_80106DA0_jp = 0x80106DA0; // +D_80106E10_jp = 0x80106E10; // +D_80106E20_jp = 0x80106E20; // +D_80106E50_jp = 0x80106E50; // +D_80106E80_jp = 0x80106E80; // +D_80106EB0_jp = 0x80106EB0; // +D_80106EE0_jp = 0x80106EE0; // +D_80106F10_jp = 0x80106F10; // +D_80106F40_jp = 0x80106F40; // +D_80106F70_jp = 0x80106F70; // +D_80106FA0_jp = 0x80106FA0; // +D_80106FD0_jp = 0x80106FD0; // +D_80107000_jp = 0x80107000; // +D_80107010_jp = 0x80107010; // +D_80107020_jp = 0x80107020; // +D_801071A4_jp = 0x801071A4; // +D_801071B8_jp = 0x801071B8; // +D_801071CC_jp = 0x801071CC; // +D_801075E0_jp = 0x801075E0; // +D_80107620_jp = 0x80107620; // +D_80107630_jp = 0x80107630; // +D_80107634_jp = 0x80107634; // +D_80107638_jp = 0x80107638; // +D_8010763C_jp = 0x8010763C; // +D_80107640_jp = 0x80107640; // +D_80107644_jp = 0x80107644; // +D_8010764C_jp = 0x8010764C; // +D_80107674_jp = 0x80107674; // +D_80107678_jp = 0x80107678; // +D_8010767C_jp = 0x8010767C; // +D_801076A0_jp = 0x801076A0; // +D_801076A4_jp = 0x801076A4; // +D_801076B0_jp = 0x801076B0; // +D_801076BC_jp = 0x801076BC; // +D_FLT_80107730_jp = 0x80107730; // type:f32 +D_FLT_80107744_jp = 0x80107744; // type:f32 +D_80107760_jp = 0x80107760; // type:s8 +D_80107764_jp = 0x80107764; // type:s16 +D_80107768_jp = 0x80107768; // +D_8010778C_jp = 0x8010778C; // +D_801078BC_jp = 0x801078BC; // +D_801079EC_jp = 0x801079EC; // +D_80107A14_jp = 0x80107A14; // +D_80107A3C_jp = 0x80107A3C; // +D_80107A64_jp = 0x80107A64; // +D_80107A8C_jp = 0x80107A8C; // +D_80107A9C_jp = 0x80107A9C; // +D_80107AA8_jp = 0x80107AA8; // type:u8 +D_FLT_80107AD0_jp = 0x80107AD0; // type:f32 +D_FLT_80107ADC_jp = 0x80107ADC; // type:f32 +D_FLT_80107AE8_jp = 0x80107AE8; // type:f32 +D_80107AF0_jp = 0x80107AF0; // +D_80107B00_jp = 0x80107B00; // +D_80107B30_jp = 0x80107B30; // +D_80107B3C_jp = 0x80107B3C; // +D_80107B50_jp = 0x80107B50; // +D_80107B60_jp = 0x80107B60; // +D_80107B70_jp = 0x80107B70; // +D_80107B75_jp = 0x80107B75; // type:s8 +D_80107B78_jp = 0x80107B78; // type:u8 +D_80107B88_jp = 0x80107B88; // type:s8 +D_80107B90_jp = 0x80107B90; // type:u8 +D_80107C90_jp = 0x80107C90; // type:s8 +D_80107C94_jp = 0x80107C94; // type:u8 +D_80107C9C_jp = 0x80107C9C; // type:u16 +D_80107CA4_jp = 0x80107CA4; // type:u16 +D_80107CB4_jp = 0x80107CB4; // type:u8 +D_80107CB8_jp = 0x80107CB8; // +D_80107E40_jp = 0x80107E40; // +D_80107EC0_jp = 0x80107EC0; // +D_80107F40_jp = 0x80107F40; // +D_80107FC0_jp = 0x80107FC0; // +D_801087C0_jp = 0x801087C0; // +D_801097C0_jp = 0x801097C0; // +D_8010A7C0_jp = 0x8010A7C0; // +D_8010A8E8_jp = 0x8010A8E8; // +D_8010A928_jp = 0x8010A928; // +D_8010AD28_jp = 0x8010AD28; // +D_8010AD98_jp = 0x8010AD98; // +D_8010AE00_jp = 0x8010AE00; // +D_8010AE20_jp = 0x8010AE20; // +D_8010AE40_jp = 0x8010AE40; // +D_8010AE48_jp = 0x8010AE48; // +D_8010AE50_jp = 0x8010AE50; // +D_8010AEC0_jp = 0x8010AEC0; // +D_8010AEC8_jp = 0x8010AEC8; // type:u8 +D_8010AECC_jp = 0x8010AECC; // +D_8010AEE0_jp = 0x8010AEE0; // +D_8010AEF4_jp = 0x8010AEF4; // +D_8010AF58_jp = 0x8010AF58; // type:u8 +D_8010B034_jp = 0x8010B034; // +D_8010B074_jp = 0x8010B074; // +D_8010B078_jp = 0x8010B078; // +D_8010B09C_jp = 0x8010B09C; // +D_8010B0BC_jp = 0x8010B0BC; // +D_8010B1BC_jp = 0x8010B1BC; // +D_8010B1DC_jp = 0x8010B1DC; // +D_8010B21C_jp = 0x8010B21C; // +D_8010B25C_jp = 0x8010B25C; // +D_8010B264_jp = 0x8010B264; // +D_8010B270_jp = 0x8010B270; // +D_8010B2A8_jp = 0x8010B2A8; // +D_8010B2AC_jp = 0x8010B2AC; // +D_8010B30C_jp = 0x8010B30C; // +D_8010B32C_jp = 0x8010B32C; // +D_8010B330_jp = 0x8010B330; // +D_8010B334_jp = 0x8010B334; // +D_8010B374_jp = 0x8010B374; // type:s16 +D_8010B478_jp = 0x8010B478; // +D_8010B484_jp = 0x8010B484; // +D_8010B490_jp = 0x8010B490; // +D_8010B4A0_jp = 0x8010B4A0; // +D_8010B4B0_jp = 0x8010B4B0; // type:u16 +D_8010B4FC_jp = 0x8010B4FC; // type:u16 +D_8010B500_jp = 0x8010B500; // +D_8010B504_jp = 0x8010B504; // type:s16 +D_8010B510_jp = 0x8010B510; // type:u16 +D_8010B810_jp = 0x8010B810; // +D_8010B818_jp = 0x8010B818; // +D_8010B81C_jp = 0x8010B81C; // +D_8010B824_jp = 0x8010B824; // +D_8010B850_jp = 0x8010B850; // +D_8010B868_jp = 0x8010B868; // +D_8010B880_jp = 0x8010B880; // +D_8010B888_jp = 0x8010B888; // +D_8010B890_jp = 0x8010B890; // +D_8010B898_jp = 0x8010B898; // +D_8010B8A4_jp = 0x8010B8A4; // +D_8010B8B0_jp = 0x8010B8B0; // +D_8010B8B8_jp = 0x8010B8B8; // type:u8 +D_8010B8C0_jp = 0x8010B8C0; // +D_8010B908_jp = 0x8010B908; // +D_8010B91A_jp = 0x8010B91A; // +D_8010B91C_jp = 0x8010B91C; // +D_8010B934_jp = 0x8010B934; // +D_8010B950_jp = 0x8010B950; // type:u16 +D_8010B952_jp = 0x8010B952; // type:u8 +D_8010B953_jp = 0x8010B953; // type:u8 +D_8010B968_jp = 0x8010B968; // +D_8010B970_jp = 0x8010B970; // +D_8010B9A8_jp = 0x8010B9A8; // +D_8010B9B0_jp = 0x8010B9B0; // +D_8010B9E8_jp = 0x8010B9E8; // +D_8010B9F0_jp = 0x8010B9F0; // +D_8010BA28_jp = 0x8010BA28; // +D_8010BA30_jp = 0x8010BA30; // +D_8010BA68_jp = 0x8010BA68; // +D_8010BA70_jp = 0x8010BA70; // +D_8010BAB8_jp = 0x8010BAB8; // +D_8010BAC0_jp = 0x8010BAC0; // +D_8010BB08_jp = 0x8010BB08; // +D_8010BB10_jp = 0x8010BB10; // +D_8010BB30_jp = 0x8010BB30; // +D_8010BB34_jp = 0x8010BB34; // +D_8010BB38_jp = 0x8010BB38; // +D_8010BB74_jp = 0x8010BB74; // +D_8010BB7C_jp = 0x8010BB7C; // +D_8010BB80_jp = 0x8010BB80; // +D_8010BB8C_jp = 0x8010BB8C; // +D_8010BB94_jp = 0x8010BB94; // +D_8010BB98_jp = 0x8010BB98; // +D_8010BB9C_jp = 0x8010BB9C; // +D_8010BBD8_jp = 0x8010BBD8; // +D_8010BBE0_jp = 0x8010BBE0; // +D_8010BBE4_jp = 0x8010BBE4; // +D_8010BBEC_jp = 0x8010BBEC; // +D_8010BC28_jp = 0x8010BC28; // +D_8010BC30_jp = 0x8010BC30; // +D_8010BC3C_jp = 0x8010BC3C; // +D_8010BC48_jp = 0x8010BC48; // +D_8010BC50_jp = 0x8010BC50; // +D_8010BC5C_jp = 0x8010BC5C; // +D_8010BC60_jp = 0x8010BC60; // +D_8010BC68_jp = 0x8010BC68; // +D_8010BCBC_jp = 0x8010BCBC; // +D_8010BCC4_jp = 0x8010BCC4; // +D_8010BCE0_jp = 0x8010BCE0; // +D_8010BD10_jp = 0x8010BD10; // +D_8010BD18_jp = 0x8010BD18; // +D_8010BD20_jp = 0x8010BD20; // +D_8010BF2C_jp = 0x8010BF2C; // +D_8010BF30_jp = 0x8010BF30; // +D_8010BF74_jp = 0x8010BF74; // type:u8 +D_8010BF88_jp = 0x8010BF88; // +D_8010BFD0_jp = 0x8010BFD0; // +D_8010C050_jp = 0x8010C050; // +D_8010C0D0_jp = 0x8010C0D0; // +D_8010C0D4_jp = 0x8010C0D4; // +D_8010C0DC_jp = 0x8010C0DC; // +D_8010C0E4_jp = 0x8010C0E4; // +D_8010C0E8_jp = 0x8010C0E8; // +D_8010C2F0_jp = 0x8010C2F0; // +D_8010C4F8_jp = 0x8010C4F8; // +D_8010C538_jp = 0x8010C538; // type:s8 +D_8010C5B0_jp = 0x8010C5B0; // +D_8010C5C4_jp = 0x8010C5C4; // +D_8010C5D8_jp = 0x8010C5D8; // type:u16 +D_8010C5E4_jp = 0x8010C5E4; // +D_8010C5F4_jp = 0x8010C5F4; // +D_8010C610_jp = 0x8010C610; // +D_8010C618_jp = 0x8010C618; // +D_8010C620_jp = 0x8010C620; // +D_8010C630_jp = 0x8010C630; // +D_8010C640_jp = 0x8010C640; // +D_8010C648_jp = 0x8010C648; // +D_8010C650_jp = 0x8010C650; // type:u8 +D_8010C65C_jp = 0x8010C65C; // +D_8010C66C_jp = 0x8010C66C; // type:u16 +D_8010C670_jp = 0x8010C670; // type:u16 +D_8010C680_jp = 0x8010C680; // +D_8010C684_jp = 0x8010C684; // +D_8010C694_jp = 0x8010C694; // +D_8010C69C_jp = 0x8010C69C; // type:u8 +D_8010C6A4_jp = 0x8010C6A4; // +D_8010C6B0_jp = 0x8010C6B0; // +D_8010C6B8_jp = 0x8010C6B8; // +D_8010C6C0_jp = 0x8010C6C0; // +D_8010C6C4_jp = 0x8010C6C4; // +D_8010C6C8_jp = 0x8010C6C8; // +D_8010C6CC_jp = 0x8010C6CC; // +D_8010C6F8_jp = 0x8010C6F8; // +D_8010C848_jp = 0x8010C848; // type:u8 +D_8010C850_jp = 0x8010C850; // +D_8010C858_jp = 0x8010C858; // +D_8010C860_jp = 0x8010C860; // +D_8010C868_jp = 0x8010C868; // +D_8010C870_jp = 0x8010C870; // +D_8010C878_jp = 0x8010C878; // +D_8010C880_jp = 0x8010C880; // +D_8010C888_jp = 0x8010C888; // +D_8010C890_jp = 0x8010C890; // +D_8010C8A0_jp = 0x8010C8A0; // +D_8010C8B0_jp = 0x8010C8B0; // +D_8010C8C0_jp = 0x8010C8C0; // +D_8010C8D0_jp = 0x8010C8D0; // +D_8010C8E0_jp = 0x8010C8E0; // +D_8010C8F0_jp = 0x8010C8F0; // +D_8010C900_jp = 0x8010C900; // +D_8010C910_jp = 0x8010C910; // +D_8010C928_jp = 0x8010C928; // +D_8010C940_jp = 0x8010C940; // +D_8010C958_jp = 0x8010C958; // +D_8010C970_jp = 0x8010C970; // +D_8010C9D0_jp = 0x8010C9D0; // type:u8 +D_8010CB20_jp = 0x8010CB20; // +D_8010CB30_jp = 0x8010CB30; // +D_8010CB90_jp = 0x8010CB90; // +D_8010CBC0_jp = 0x8010CBC0; // +D_8010CBF0_jp = 0x8010CBF0; // +D_8010CC20_jp = 0x8010CC20; // +D_8010CC50_jp = 0x8010CC50; // +D_8010CC80_jp = 0x8010CC80; // +D_8010CCB0_jp = 0x8010CCB0; // +D_8010CD10_jp = 0x8010CD10; // +D_8010CD70_jp = 0x8010CD70; // +D_8010CDA0_jp = 0x8010CDA0; // +D_8010CDD0_jp = 0x8010CDD0; // +D_8010CE00_jp = 0x8010CE00; // +D_8010CE60_jp = 0x8010CE60; // +D_8010CE90_jp = 0x8010CE90; // +D_8010CEC0_jp = 0x8010CEC0; // type:u8 +D_8010D274_jp = 0x8010D274; // +D_8010D28C_jp = 0x8010D28C; // +D_8010D2A4_jp = 0x8010D2A4; // +D_8010D2BC_jp = 0x8010D2BC; // +D_8010D2D4_jp = 0x8010D2D4; // +D_8010D2EC_jp = 0x8010D2EC; // +D_8010D2FC_jp = 0x8010D2FC; // +D_8010D314_jp = 0x8010D314; // type:u8 +D_8010D418_jp = 0x8010D418; // +D_8010D6C8_jp = 0x8010D6C8; // +D_8010D6D0_jp = 0x8010D6D0; // +D_8010D6D8_jp = 0x8010D6D8; // +D_8010D6E0_jp = 0x8010D6E0; // +D_8010D6E8_jp = 0x8010D6E8; // type:u8 +D_8010DA9C_jp = 0x8010DA9C; // +D_8010DAA0_jp = 0x8010DAA0; // +D_8010DADC_jp = 0x8010DADC; // +D_8010DAE8_jp = 0x8010DAE8; // +D_8010DAF4_jp = 0x8010DAF4; // +D_8010DB00_jp = 0x8010DB00; // +D_8010DB0C_jp = 0x8010DB0C; // +D_8010DB18_jp = 0x8010DB18; // +D_8010DB24_jp = 0x8010DB24; // +D_8010DB30_jp = 0x8010DB30; // +D_8010DB3C_jp = 0x8010DB3C; // +D_8010DB48_jp = 0x8010DB48; // +D_8010DB54_jp = 0x8010DB54; // +D_8010DB60_jp = 0x8010DB60; // +D_8010DB6C_jp = 0x8010DB6C; // +D_8010DBAC_jp = 0x8010DBAC; // type:u16 +D_8010DBCC_jp = 0x8010DBCC; // +D_8010DBEC_jp = 0x8010DBEC; // +D_8010DBF8_jp = 0x8010DBF8; // +D_8010DC04_jp = 0x8010DC04; // +D_8010DC10_jp = 0x8010DC10; // +D_8010DC1C_jp = 0x8010DC1C; // +D_8010DC2C_jp = 0x8010DC2C; // type:u16 +D_8010DC3C_jp = 0x8010DC3C; // +D_8010DC5C_jp = 0x8010DC5C; // +D_8010DC6C_jp = 0x8010DC6C; // +D_8010DC7C_jp = 0x8010DC7C; // type:u8 +D_8010DC84_jp = 0x8010DC84; // +D_8010DC88_jp = 0x8010DC88; // type:u8 +D_8010DC8C_jp = 0x8010DC8C; // type:u8 +D_8010DC90_jp = 0x8010DC90; // type:u8 +D_8010DCA0_jp = 0x8010DCA0; // +D_8010DCB0_jp = 0x8010DCB0; // +D_8010DCC4_jp = 0x8010DCC4; // +D_8010DCE0_jp = 0x8010DCE0; // +D_8010DCE4_jp = 0x8010DCE4; // +D_8010DCE8_jp = 0x8010DCE8; // +D_8010DCEC_jp = 0x8010DCEC; // +D_8010DD08_jp = 0x8010DD08; // +D_8010DD24_jp = 0x8010DD24; // +D_8010DD38_jp = 0x8010DD38; // +D_8010DD80_jp = 0x8010DD80; // +D_8010DDAC_jp = 0x8010DDAC; // type:s16 +D_8010DDBC_jp = 0x8010DDBC; // type:s16 +D_8010DDD0_jp = 0x8010DDD0; // +D_8010ED60_jp = 0x8010ED60; // +D_8010EDA0_jp = 0x8010EDA0; // +D_8010EDA4_jp = 0x8010EDA4; // +D_8010EDA8_jp = 0x8010EDA8; // +D_8010EDBC_jp = 0x8010EDBC; // +D_8010EDD0_jp = 0x8010EDD0; // type:s16 +D_8010EDE0_jp = 0x8010EDE0; // +D_8010EE50_jp = 0x8010EE50; // +D_8010EE54_jp = 0x8010EE54; // type:u8 +D_8010EE55_jp = 0x8010EE55; // type:u8 +D_8010EE5C_jp = 0x8010EE5C; // type:u8 +D_8010EEE4_jp = 0x8010EEE4; // type:s8 +D_8010EEE8_jp = 0x8010EEE8; // +D_8010EEEC_jp = 0x8010EEEC; // +D_8010EEF0_jp = 0x8010EEF0; // +D_8010EF00_jp = 0x8010EF00; // +D_8010EF10_jp = 0x8010EF10; // +D_8010EF24_jp = 0x8010EF24; // +D_8010EF2C_jp = 0x8010EF2C; // +D_8010EF30_jp = 0x8010EF30; // +D_8010EF48_jp = 0x8010EF48; // type:u16 +D_8010EF50_jp = 0x8010EF50; // +D_8010EF60_jp = 0x8010EF60; // +D_8010EF70_jp = 0x8010EF70; // +D_8010EF80_jp = 0x8010EF80; // +D_8010EF90_jp = 0x8010EF90; // +D_8010EFA0_jp = 0x8010EFA0; // +D_8010EFB0_jp = 0x8010EFB0; // +D_8010EFB8_jp = 0x8010EFB8; // +D_8010EFC0_jp = 0x8010EFC0; // +D_8010EFC8_jp = 0x8010EFC8; // +D_8010EFD0_jp = 0x8010EFD0; // +D_8010EFD4_jp = 0x8010EFD4; // +D_8010EFD8_jp = 0x8010EFD8; // +D_8010EFE0_jp = 0x8010EFE0; // type:u8 +D_8010EFFC_jp = 0x8010EFFC; // +D_8010F3DC_jp = 0x8010F3DC; // +D_8010F3E0_jp = 0x8010F3E0; // +D_8010F3E4_jp = 0x8010F3E4; // +D_8010F3E8_jp = 0x8010F3E8; // type:u8 +D_8010F3F0_jp = 0x8010F3F0; // +D_8010F3F4_jp = 0x8010F3F4; // +D_8010F400_jp = 0x8010F400; // +D_8010F410_jp = 0x8010F410; // +D_8010F450_jp = 0x8010F450; // type:u8 +D_FLT_8010F460_jp = 0x8010F460; // type:f32 +D_FLT_8010F490_jp = 0x8010F490; // type:f32 +D_8010F4A0_jp = 0x8010F4A0; // +D_8010F4AC_jp = 0x8010F4AC; // +D_8010F4C0_jp = 0x8010F4C0; // type:u16 +D_8010FCC0_jp = 0x8010FCC0; // type:u16 +D_8010FCD0_jp = 0x8010FCD0; // +D_8010FD10_jp = 0x8010FD10; // +D_8010FD50_jp = 0x8010FD50; // +D_8010FD54_jp = 0x8010FD54; // +D_8010FD58_jp = 0x8010FD58; // +D_8010FD5C_jp = 0x8010FD5C; // +D_8010FD60_jp = 0x8010FD60; // +D_8010FD70_jp = 0x8010FD70; // +D_80110000_jp = 0x80110000; // type:s16 +D_80110D70_jp = 0x80110D70; // type:s16 +D_80110E70_jp = 0x80110E70; // type:s16 +D_80110F60_jp = 0x80110F60; // type:s16 +D_801115F0_jp = 0x801115F0; // type:s16 +D_80111C80_jp = 0x80111C80; // +D_80111E88_jp = 0x80111E88; // +D_FLT_80111EA4_jp = 0x80111EA4; // type:f32 +D_FLT_801120A4_jp = 0x801120A4; // type:f32 +D_FLT_801122A4_jp = 0x801122A4; // type:f32 +D_FLT_801126A4_jp = 0x801126A4; // type:f32 +D_801128A4_jp = 0x801128A4; // +D_801128B4_jp = 0x801128B4; // +D_801128C4_jp = 0x801128C4; // +D_801128D4_jp = 0x801128D4; // +D_801128F4_jp = 0x801128F4; // +D_80112914_jp = 0x80112914; // type:u16 +D_80112992_jp = 0x80112992; // type:u16 +D_FLT_80112A18_jp = 0x80112A18; // type:f32 +D_FLT_80112C14_jp = 0x80112C14; // type:f32 +D_FLT_80112C18_jp = 0x80112C18; // type:f32 +D_FLT_80112E14_jp = 0x80112E14; // type:f32 +D_FLT_80112E18_jp = 0x80112E18; // type:f32 +D_FLT_80113014_jp = 0x80113014; // type:f32 +D_801130A0_jp = 0x801130A0; // +D_801130A4_jp = 0x801130A4; // type:u16 +D_801130C4_jp = 0x801130C4; // +D_801130C8_jp = 0x801130C8; // +D_801130CC_jp = 0x801130CC; // +D_801130D0_jp = 0x801130D0; // +D_801130E0_jp = 0x801130E0; // +D_801130E4_jp = 0x801130E4; // +D_801130E8_jp = 0x801130E8; // +D_801130EC_jp = 0x801130EC; // +D_801130F0_jp = 0x801130F0; // +D_80113100_jp = 0x80113100; // +D_80113108_jp = 0x80113108; // +D_8011310C_jp = 0x8011310C; // +D_80113110_jp = 0x80113110; // +D_80113120_jp = 0x80113120; // +D_80113124_jp = 0x80113124; // type:s16 +D_80113138_jp = 0x80113138; // +D_801131A8_jp = 0x801131A8; // +D_80113210_jp = 0x80113210; // type:u8 +D_80113298_jp = 0x80113298; // +D_8011329C_jp = 0x8011329C; // +D_801132A0_jp = 0x801132A0; // type:u8 +D_80113310_jp = 0x80113310; // +D_80113320_jp = 0x80113320; // +D_80113330_jp = 0x80113330; // +D_80113344_jp = 0x80113344; // +D_80113358_jp = 0x80113358; // +D_80113364_jp = 0x80113364; // +D_80113370_jp = 0x80113370; // +D_80113380_jp = 0x80113380; // +D_801137AE_jp = 0x801137AE; // type:u16 +D_801137DE_jp = 0x801137DE; // type:u16 +D_8011380E_jp = 0x8011380E; // type:u16 +D_80113840_jp = 0x80113840; // +D_80113844_jp = 0x80113844; // type:s8 +D_80113848_jp = 0x80113848; // type:u8 +D_8011384C_jp = 0x8011384C; // type:s8 +D_80113854_jp = 0x80113854; // type:u8 +D_80113858_jp = 0x80113858; // type:s8 +D_8011385C_jp = 0x8011385C; // +D_80113860_jp = 0x80113860; // +D_80113864_jp = 0x80113864; // +D_80113868_jp = 0x80113868; // type:u8 +D_FLT_8011386C_jp = 0x8011386C; // type:f32 +D_80113870_jp = 0x80113870; // +D_80113894_jp = 0x80113894; // type:u8 +D_80113898_jp = 0x80113898; // type:u8 +D_8011389C_jp = 0x8011389C; // +D_801138A0_jp = 0x801138A0; // type:s8 +D_801138A4_jp = 0x801138A4; // type:s8 +D_801138A8_jp = 0x801138A8; // type:u8 +D_801138AC_jp = 0x801138AC; // +D_801138B0_jp = 0x801138B0; // +D_801138B4_jp = 0x801138B4; // type:u8 +D_801138B8_jp = 0x801138B8; // type:u8 +D_801138BC_jp = 0x801138BC; // +D_801138C0_jp = 0x801138C0; // type:s16 +D_801138C8_jp = 0x801138C8; // +D_801138CC_jp = 0x801138CC; // type:u8 +D_801138D0_jp = 0x801138D0; // +D_801138D4_jp = 0x801138D4; // type:s8 +D_FLT_801138D8_jp = 0x801138D8; // type:f32 +D_FLT_801138DC_jp = 0x801138DC; // type:f32 +D_FLT_801138E0_jp = 0x801138E0; // type:f32 +D_FLT_801138E4_jp = 0x801138E4; // type:f32 +D_801138E8_jp = 0x801138E8; // type:s16 +D_801138EC_jp = 0x801138EC; // type:u16 +D_801138F0_jp = 0x801138F0; // type:u16 +D_801138F4_jp = 0x801138F4; // +D_801138F8_jp = 0x801138F8; // type:s16 +D_FLT_801138FC_jp = 0x801138FC; // type:f32 +D_80113900_jp = 0x80113900; // type:s16 +D_80113904_jp = 0x80113904; // +D_80113908_jp = 0x80113908; // +D_80113910_jp = 0x80113910; // +D_80113914_jp = 0x80113914; // +D_80113918_jp = 0x80113918; // type:u8 +D_8011391C_jp = 0x8011391C; // type:s8 +D_80113928_jp = 0x80113928; // type:u8 +D_8011392C_jp = 0x8011392C; // type:u8 +D_80113930_jp = 0x80113930; // type:u16 +D_80113934_jp = 0x80113934; // type:u16 +D_FLT_80113938_jp = 0x80113938; // type:f32 +D_8011393C_jp = 0x8011393C; // type:u8 +D_80113940_jp = 0x80113940; // +D_FLT_80113944_jp = 0x80113944; // type:f32 +D_FLT_80113948_jp = 0x80113948; // type:f32 +D_FLT_8011394C_jp = 0x8011394C; // type:f32 +D_80113950_jp = 0x80113950; // type:s8 +D_80113954_jp = 0x80113954; // type:u8 +D_80113958_jp = 0x80113958; // +D_8011395C_jp = 0x8011395C; // +D_80113964_jp = 0x80113964; // type:u8 +D_80113A64_jp = 0x80113A64; // type:u16 +D_80113AFC_jp = 0x80113AFC; // type:u16 +D_80113B14_jp = 0x80113B14; // type:u16 +D_80113B2C_jp = 0x80113B2C; // type:u8 +D_80113B84_jp = 0x80113B84; // type:u8 +D_80113C04_jp = 0x80113C04; // type:s8 +D_80113C34_jp = 0x80113C34; // type:u16 +D_FLT_80113CF4_jp = 0x80113CF4; // type:f32 +D_80113D3C_jp = 0x80113D3C; // type:u8 +D_FLT_80113D44_jp = 0x80113D44; // type:f32 +D_80113D4C_jp = 0x80113D4C; // type:s8 +D_80113DB4_jp = 0x80113DB4; // +D_80113E04_jp = 0x80113E04; // +D_80114124_jp = 0x80114124; // type:s8 +D_8011412C_jp = 0x8011412C; // +D_801142BC_jp = 0x801142BC; // type:s16 +D_FLT_801142C4_jp = 0x801142C4; // type:f32 +D_FLT_80114324_jp = 0x80114324; // type:f32 +D_8011437C_jp = 0x8011437C; // +D_80114380_jp = 0x80114380; // +D_80114390_jp = 0x80114390; // type:s16 +D_80114394_jp = 0x80114394; // +D_80114398_jp = 0x80114398; // +D_801143A0_jp = 0x801143A0; // +D_801143A4_jp = 0x801143A4; // +D_801143A8_jp = 0x801143A8; // +D_801143B0_jp = 0x801143B0; // type:s16 +D_801143B4_jp = 0x801143B4; // +D_801143BC_jp = 0x801143BC; // +D_801143C0_jp = 0x801143C0; // +D_801143D0_jp = 0x801143D0; // +D_801143E8_jp = 0x801143E8; // +D_80114420_jp = 0x80114420; // +D_80114700_jp = 0x80114700; // +D_80115020_jp = 0x80115020; // +D_80115090_jp = 0x80115090; // type:s16 +D_80115D80_jp = 0x80115D80; // +D_801160C0_jp = 0x801160C0; // +D_801160CE_jp = 0x801160CE; // type:u16 + +// .rodata + +RO_FLT_80116110_jp = 0x80116110; // type:f32 +RO_FLT_80116114_jp = 0x80116114; // type:f32 +RO_FLT_80116118_jp = 0x80116118; // type:f32 +RO_FLT_8011611C_jp = 0x8011611C; // type:f32 +RO_FLT_80116120_jp = 0x80116120; // type:f32 +RO_FLT_80116124_jp = 0x80116124; // type:f32 +RO_FLT_80116128_jp = 0x80116128; // type:f32 +RO_FLT_8011612C_jp = 0x8011612C; // type:f32 +RO_FLT_80116130_jp = 0x80116130; // type:f32 +RO_FLT_80116134_jp = 0x80116134; // type:f32 +RO_FLT_80116138_jp = 0x80116138; // type:f32 +RO_FLT_8011613C_jp = 0x8011613C; // type:f32 +RO_FLT_80116140_jp = 0x80116140; // type:f32 +RO_FLT_80116144_jp = 0x80116144; // type:f32 +RO_FLT_80116148_jp = 0x80116148; // type:f32 +RO_FLT_8011614C_jp = 0x8011614C; // type:f32 +RO_FLT_80116150_jp = 0x80116150; // type:f32 +RO_FLT_80116154_jp = 0x80116154; // type:f32 +RO_STR_80116160_jp = 0x80116160; // type:asciz +RO_STR_80116184_jp = 0x80116184; // type:asciz +RO_STR_801161B0_jp = 0x801161B0; // type:asciz +RO_801161C4_jp = 0x801161C4; // +RO_STR_801161C8_jp = 0x801161C8; // type:asciz +RO_STR_801161DC_jp = 0x801161DC; // type:asciz +RO_801161E8_jp = 0x801161E8; // +RO_FLT_801161F0_jp = 0x801161F0; // type:f32 +RO_FLT_801161F4_jp = 0x801161F4; // type:f32 +RO_FLT_801161F8_jp = 0x801161F8; // type:f32 +RO_FLT_801161FC_jp = 0x801161FC; // type:f32 +RO_STR_80116200_jp = 0x80116200; // type:asciz +RO_STR_80116214_jp = 0x80116214; // type:asciz +RO_STR_80116234_jp = 0x80116234; // type:asciz +RO_8011624C_jp = 0x8011624C; // +RO_FLT_80116250_jp = 0x80116250; // type:f32 +RO_FLT_80116254_jp = 0x80116254; // type:f32 +RO_FLT_80116258_jp = 0x80116258; // type:f32 +RO_FLT_8011625C_jp = 0x8011625C; // type:f32 +RO_FLT_80116260_jp = 0x80116260; // type:f32 +RO_FLT_80116264_jp = 0x80116264; // type:f32 +RO_FLT_80116268_jp = 0x80116268; // type:f32 +RO_FLT_8011626C_jp = 0x8011626C; // type:f32 +RO_FLT_80116270_jp = 0x80116270; // type:f32 +RO_FLT_80116274_jp = 0x80116274; // type:f32 +RO_FLT_80116280_jp = 0x80116280; // type:f32 +RO_FLT_80116284_jp = 0x80116284; // type:f32 +RO_FLT_80116288_jp = 0x80116288; // type:f32 +RO_FLT_8011628C_jp = 0x8011628C; // type:f32 +RO_FLT_80116290_jp = 0x80116290; // type:f32 +jtbl_80116294_jp = 0x80116294; // type:jtbl +jtbl_801162A8_jp = 0x801162A8; // type:jtbl +RO_FLT_801162BC_jp = 0x801162BC; // type:f32 +RO_FLT_801162C0_jp = 0x801162C0; // type:f32 +jtbl_801162D0_jp = 0x801162D0; // type:jtbl +RO_FLT_801162F8_jp = 0x801162F8; // type:f32 +RO_FLT_801162FC_jp = 0x801162FC; // type:f32 +RO_FLT_80116300_jp = 0x80116300; // type:f32 +RO_FLT_80116304_jp = 0x80116304; // type:f32 +RO_FLT_80116308_jp = 0x80116308; // type:f32 +RO_FLT_8011630C_jp = 0x8011630C; // type:f32 +RO_FLT_80116310_jp = 0x80116310; // type:f32 +RO_FLT_80116314_jp = 0x80116314; // type:f32 +RO_FLT_80116318_jp = 0x80116318; // type:f32 +RO_FLT_8011631C_jp = 0x8011631C; // type:f32 +RO_FLT_80116320_jp = 0x80116320; // type:f32 +jtbl_80116324_jp = 0x80116324; // type:jtbl +RO_FLT_80116358_jp = 0x80116358; // type:f32 +RO_FLT_8011635C_jp = 0x8011635C; // type:f32 +RO_FLT_80116360_jp = 0x80116360; // type:f32 +RO_FLT_80116364_jp = 0x80116364; // type:f32 +RO_FLT_80116368_jp = 0x80116368; // type:f32 +RO_FLT_8011636C_jp = 0x8011636C; // type:f32 +RO_FLT_80116370_jp = 0x80116370; // type:f32 +RO_FLT_80116374_jp = 0x80116374; // type:f32 +RO_FLT_80116378_jp = 0x80116378; // type:f32 +RO_FLT_8011637C_jp = 0x8011637C; // type:f32 +RO_FLT_80116380_jp = 0x80116380; // type:f32 +RO_FLT_80116384_jp = 0x80116384; // type:f32 +RO_FLT_80116388_jp = 0x80116388; // type:f32 +RO_FLT_8011638C_jp = 0x8011638C; // type:f32 +RO_FLT_80116390_jp = 0x80116390; // type:f32 +RO_FLT_80116394_jp = 0x80116394; // type:f32 +RO_FLT_80116398_jp = 0x80116398; // type:f32 +RO_FLT_8011639C_jp = 0x8011639C; // type:f32 +RO_FLT_801163A0_jp = 0x801163A0; // type:f32 +RO_FLT_801163A4_jp = 0x801163A4; // type:f32 +RO_FLT_801163A8_jp = 0x801163A8; // type:f32 +RO_FLT_801163AC_jp = 0x801163AC; // type:f32 +RO_FLT_801163B0_jp = 0x801163B0; // type:f32 +RO_FLT_801163B4_jp = 0x801163B4; // type:f32 +RO_FLT_801163B8_jp = 0x801163B8; // type:f32 +RO_FLT_801163BC_jp = 0x801163BC; // type:f32 +RO_FLT_801163C0_jp = 0x801163C0; // type:f32 +RO_FLT_801163C4_jp = 0x801163C4; // type:f32 +RO_FLT_801163C8_jp = 0x801163C8; // type:f32 +RO_FLT_801163CC_jp = 0x801163CC; // type:f32 +RO_FLT_801163D0_jp = 0x801163D0; // type:f32 +RO_FLT_801163D4_jp = 0x801163D4; // type:f32 +RO_FLT_801163D8_jp = 0x801163D8; // type:f32 +RO_STR_801163E0_jp = 0x801163E0; // type:asciz +RO_STR_801163F4_jp = 0x801163F4; // type:asciz +RO_STR_80116408_jp = 0x80116408; // type:asciz +RO_STR_8011641C_jp = 0x8011641C; // type:asciz +RO_FLT_80116430_jp = 0x80116430; // type:f32 +RO_FLT_80116434_jp = 0x80116434; // type:f32 +RO_FLT_80116438_jp = 0x80116438; // type:f32 +RO_FLT_8011643C_jp = 0x8011643C; // type:f32 +RO_FLT_80116440_jp = 0x80116440; // type:f32 +RO_FLT_80116444_jp = 0x80116444; // type:f32 +RO_FLT_80116448_jp = 0x80116448; // type:f32 +RO_FLT_8011644C_jp = 0x8011644C; // type:f32 +RO_STR_80116450_jp = 0x80116450; // type:asciz +RO_80116464_jp = 0x80116464; // +RO_STR_80116470_jp = 0x80116470; // type:asciz +RO_FLT_80116484_jp = 0x80116484; // type:f32 +RO_801164B4_jp = 0x801164B4; // +RO_801164D4_jp = 0x801164D4; // +RO_FLT_801164E0_jp = 0x801164E0; // type:f32 +RO_FLT_801164E4_jp = 0x801164E4; // type:f32 +RO_FLT_801164E8_jp = 0x801164E8; // type:f32 +RO_FLT_801164EC_jp = 0x801164EC; // type:f32 +RO_FLT_801164F0_jp = 0x801164F0; // type:f32 +RO_FLT_801164F4_jp = 0x801164F4; // type:f32 +RO_FLT_801164F8_jp = 0x801164F8; // type:f32 +jtbl_801164FC_jp = 0x801164FC; // type:jtbl +RO_FLT_80116514_jp = 0x80116514; // type:f32 +RO_FLT_80116518_jp = 0x80116518; // type:f32 +RO_FLT_8011651C_jp = 0x8011651C; // type:f32 +RO_FLT_80116520_jp = 0x80116520; // type:f32 +RO_FLT_80116524_jp = 0x80116524; // type:f32 +RO_FLT_80116528_jp = 0x80116528; // type:f32 +RO_FLT_8011652C_jp = 0x8011652C; // type:f32 +RO_FLT_80116530_jp = 0x80116530; // type:f32 +RO_FLT_80116534_jp = 0x80116534; // type:f32 +RO_FLT_80116538_jp = 0x80116538; // type:f32 +RO_FLT_8011653C_jp = 0x8011653C; // type:f32 +RO_FLT_80116540_jp = 0x80116540; // type:f32 +RO_FLT_80116544_jp = 0x80116544; // type:f32 +RO_FLT_80116548_jp = 0x80116548; // type:f32 +RO_FLT_8011654C_jp = 0x8011654C; // type:f32 +RO_FLT_80116550_jp = 0x80116550; // type:f32 +RO_FLT_80116554_jp = 0x80116554; // type:f32 +RO_FLT_80116558_jp = 0x80116558; // type:f32 +RO_FLT_8011655C_jp = 0x8011655C; // type:f32 +RO_FLT_80116560_jp = 0x80116560; // type:f32 +jtbl_80116564_jp = 0x80116564; // type:jtbl +RO_FLT_8011657C_jp = 0x8011657C; // type:f32 +RO_FLT_80116580_jp = 0x80116580; // type:f32 +RO_FLT_80116584_jp = 0x80116584; // type:f32 +RO_FLT_80116588_jp = 0x80116588; // type:f32 +RO_FLT_8011658C_jp = 0x8011658C; // type:f32 +RO_FLT_80116590_jp = 0x80116590; // type:f32 +RO_FLT_80116594_jp = 0x80116594; // type:f32 +RO_FLT_80116598_jp = 0x80116598; // type:f32 +RO_FLT_8011659C_jp = 0x8011659C; // type:f32 +RO_FLT_801165A0_jp = 0x801165A0; // type:f32 +RO_FLT_801165A4_jp = 0x801165A4; // type:f32 +RO_FLT_801165A8_jp = 0x801165A8; // type:f32 +RO_FLT_801165AC_jp = 0x801165AC; // type:f32 +RO_FLT_801165B0_jp = 0x801165B0; // type:f32 +RO_FLT_801165B4_jp = 0x801165B4; // type:f32 +RO_FLT_801165B8_jp = 0x801165B8; // type:f32 +RO_FLT_801165BC_jp = 0x801165BC; // type:f32 +jtbl_801165C0_jp = 0x801165C0; // type:jtbl +jtbl_801166BC_jp = 0x801166BC; // type:jtbl +RO_FLT_80116728_jp = 0x80116728; // type:f32 +RO_FLT_8011672C_jp = 0x8011672C; // type:f32 +jtbl_80116730_jp = 0x80116730; // type:jtbl +jtbl_801167B0_jp = 0x801167B0; // type:jtbl +RO_FLT_801167D4_jp = 0x801167D4; // type:f32 +RO_FLT_801167D8_jp = 0x801167D8; // type:f32 +RO_FLT_801167E0_jp = 0x801167E0; // type:f32 +RO_FLT_801167E4_jp = 0x801167E4; // type:f32 +RO_FLT_801167E8_jp = 0x801167E8; // type:f32 +RO_FLT_801167EC_jp = 0x801167EC; // type:f32 +RO_FLT_801167F0_jp = 0x801167F0; // type:f32 +RO_FLT_801167F4_jp = 0x801167F4; // type:f32 +RO_80116800_jp = 0x80116800; // +RO_STR_80116804_jp = 0x80116804; // type:asciz +RO_80116808_jp = 0x80116808; // +jtbl_80116810_jp = 0x80116810; // type:jtbl +RO_FLT_80116828_jp = 0x80116828; // type:f32 +RO_STR_80116830_jp = 0x80116830; // type:asciz +RO_STR_80116834_jp = 0x80116834; // type:asciz +RO_STR_80116838_jp = 0x80116838; // type:asciz +RO_STR_8011683C_jp = 0x8011683C; // type:asciz +RO_STR_80116844_jp = 0x80116844; // type:asciz +RO_STR_8011684C_jp = 0x8011684C; // type:asciz +RO_STR_80116854_jp = 0x80116854; // type:asciz +RO_STR_8011685C_jp = 0x8011685C; // type:asciz +RO_STR_80116864_jp = 0x80116864; // type:asciz +RO_STR_8011686C_jp = 0x8011686C; // type:asciz +RO_STR_80116874_jp = 0x80116874; // type:asciz +RO_STR_8011687C_jp = 0x8011687C; // type:asciz +RO_STR_80116884_jp = 0x80116884; // type:asciz +RO_STR_8011688C_jp = 0x8011688C; // type:asciz +RO_STR_80116890_jp = 0x80116890; // type:asciz +RO_STR_80116894_jp = 0x80116894; // type:asciz +RO_STR_80116898_jp = 0x80116898; // type:asciz +RO_STR_801168A0_jp = 0x801168A0; // type:asciz +RO_STR_801168A8_jp = 0x801168A8; // type:asciz +RO_STR_801168B0_jp = 0x801168B0; // type:asciz +RO_STR_801168B8_jp = 0x801168B8; // type:asciz +RO_STR_801168C0_jp = 0x801168C0; // type:asciz +RO_STR_801168C8_jp = 0x801168C8; // type:asciz +RO_STR_801168D0_jp = 0x801168D0; // type:asciz +RO_STR_801168D8_jp = 0x801168D8; // type:asciz +RO_STR_801168E0_jp = 0x801168E0; // type:asciz +RO_STR_801168E8_jp = 0x801168E8; // type:asciz +RO_STR_801168F0_jp = 0x801168F0; // type:asciz +RO_STR_801168F8_jp = 0x801168F8; // type:asciz +RO_STR_80116900_jp = 0x80116900; // type:asciz +RO_STR_80116908_jp = 0x80116908; // type:asciz +RO_STR_8011690C_jp = 0x8011690C; // type:asciz +RO_STR_80116918_jp = 0x80116918; // type:asciz +RO_STR_80116920_jp = 0x80116920; // type:asciz +RO_STR_80116928_jp = 0x80116928; // type:asciz +RO_STR_80116930_jp = 0x80116930; // type:asciz +RO_STR_80116938_jp = 0x80116938; // type:asciz +RO_STR_80116940_jp = 0x80116940; // type:asciz +RO_STR_80116948_jp = 0x80116948; // type:asciz +RO_STR_80116950_jp = 0x80116950; // type:asciz +RO_STR_80116958_jp = 0x80116958; // type:asciz +RO_STR_80116960_jp = 0x80116960; // type:asciz +RO_STR_80116974_jp = 0x80116974; // type:asciz +RO_STR_80116994_jp = 0x80116994; // type:asciz +RO_STR_801169B0_jp = 0x801169B0; // type:asciz +RO_STR_801169CC_jp = 0x801169CC; // type:asciz +RO_STR_801169D4_jp = 0x801169D4; // type:asciz +RO_STR_801169D8_jp = 0x801169D8; // type:asciz +jtbl_801169DC_jp = 0x801169DC; // type:jtbl +jtbl_80116A00_jp = 0x80116A00; // type:jtbl +jtbl_80116A30_jp = 0x80116A30; // type:jtbl +RO_FLT_80116A84_jp = 0x80116A84; // type:f32 +RO_FLT_80116A88_jp = 0x80116A88; // type:f32 +RO_FLT_80116A8C_jp = 0x80116A8C; // type:f32 +RO_80116A90_jp = 0x80116A90; // type:u8 +RO_STR_80116AAC_jp = 0x80116AAC; // type:asciz +RO_STR_80116AB0_jp = 0x80116AB0; // type:asciz +RO_STR_80116AB4_jp = 0x80116AB4; // type:asciz +RO_STR_80116AC8_jp = 0x80116AC8; // type:asciz +jtbl_80116ADC_jp = 0x80116ADC; // type:jtbl +jtbl_80116B30_jp = 0x80116B30; // type:jtbl +jtbl_80116B48_jp = 0x80116B48; // type:jtbl +jtbl_80116B9C_jp = 0x80116B9C; // type:jtbl +jtbl_80116BB4_jp = 0x80116BB4; // type:jtbl +jtbl_80116C04_jp = 0x80116C04; // type:jtbl +jtbl_80116C54_jp = 0x80116C54; // type:jtbl +jtbl_80116CB0_jp = 0x80116CB0; // type:jtbl +RO_FLT_80116D10_jp = 0x80116D10; // type:f32 +RO_FLT_80116D20_jp = 0x80116D20; // type:f32 +RO_FLT_80116D24_jp = 0x80116D24; // type:f32 +RO_FLT_80116D30_jp = 0x80116D30; // type:f32 +RO_STR_80116D40_jp = 0x80116D40; // type:asciz +RO_STR_80116D50_jp = 0x80116D50; // type:asciz +RO_STR_80116D60_jp = 0x80116D60; // type:asciz +RO_STR_80116D70_jp = 0x80116D70; // type:asciz +RO_STR_80116D84_jp = 0x80116D84; // type:asciz +RO_STR_80116D98_jp = 0x80116D98; // type:asciz +RO_STR_80116DAC_jp = 0x80116DAC; // type:asciz +RO_STR_80116DC0_jp = 0x80116DC0; // type:asciz +RO_STR_80116DD4_jp = 0x80116DD4; // type:asciz +RO_STR_80116DE8_jp = 0x80116DE8; // type:asciz +RO_STR_80116DFC_jp = 0x80116DFC; // type:asciz +RO_STR_80116E10_jp = 0x80116E10; // type:asciz +RO_STR_80116E24_jp = 0x80116E24; // type:asciz +RO_STR_80116E40_jp = 0x80116E40; // type:asciz +RO_STR_80116E54_jp = 0x80116E54; // type:asciz +RO_STR_80116E58_jp = 0x80116E58; // type:asciz +jtbl_80116E70_jp = 0x80116E70; // type:jtbl +jtbl_80116E94_jp = 0x80116E94; // type:jtbl +jtbl_80116EB8_jp = 0x80116EB8; // type:jtbl +RO_FLT_80116EDC_jp = 0x80116EDC; // type:f32 +RO_FLT_80116EE0_jp = 0x80116EE0; // type:f32 +RO_FLT_80116EE4_jp = 0x80116EE4; // type:f32 +jtbl_80116EE8_jp = 0x80116EE8; // type:jtbl +RO_STR_80116F10_jp = 0x80116F10; // type:asciz +RO_STR_80116F14_jp = 0x80116F14; // type:asciz +RO_STR_80116F18_jp = 0x80116F18; // type:asciz +RO_STR_80116F1C_jp = 0x80116F1C; // type:asciz +RO_STR_80116F20_jp = 0x80116F20; // type:asciz +RO_STR_80116F24_jp = 0x80116F24; // type:asciz +RO_STR_80116F28_jp = 0x80116F28; // type:asciz +RO_STR_80116F30_jp = 0x80116F30; // type:asciz +RO_STR_80116F44_jp = 0x80116F44; // type:asciz +RO_STR_80116F58_jp = 0x80116F58; // type:asciz +RO_STR_80116F6C_jp = 0x80116F6C; // type:asciz +RO_FLT_80116F80_jp = 0x80116F80; // type:f32 +RO_FLT_80116F84_jp = 0x80116F84; // type:f32 +jtbl_80116F88_jp = 0x80116F88; // type:jtbl +RO_FLT_80116FB0_jp = 0x80116FB0; // type:f32 +RO_FLT_80116FB4_jp = 0x80116FB4; // type:f32 +RO_STR_80116FC0_jp = 0x80116FC0; // type:asciz +RO_STR_80116FD0_jp = 0x80116FD0; // type:asciz +RO_STR_80116FE0_jp = 0x80116FE0; // type:asciz +RO_STR_80116FF0_jp = 0x80116FF0; // type:asciz +RO_STR_80117000_jp = 0x80117000; // type:asciz +RO_STR_80117010_jp = 0x80117010; // type:asciz +RO_STR_80117020_jp = 0x80117020; // type:asciz +RO_STR_80117030_jp = 0x80117030; // type:asciz +RO_STR_80117040_jp = 0x80117040; // type:asciz +RO_STR_80117050_jp = 0x80117050; // type:asciz +RO_STR_80117060_jp = 0x80117060; // type:asciz +RO_STR_80117070_jp = 0x80117070; // type:asciz +RO_STR_80117080_jp = 0x80117080; // type:asciz +RO_STR_80117090_jp = 0x80117090; // type:asciz +RO_FLT_801170A0_jp = 0x801170A0; // type:f32 +RO_STR_801170B0_jp = 0x801170B0; // type:asciz +RO_FLT_801170D0_jp = 0x801170D0; // type:f32 +RO_FLT_801170D4_jp = 0x801170D4; // type:f32 +RO_FLT_801170D8_jp = 0x801170D8; // type:f32 +RO_FLT_801170DC_jp = 0x801170DC; // type:f32 +RO_FLT_801170E0_jp = 0x801170E0; // type:f32 +RO_FLT_801170E4_jp = 0x801170E4; // type:f32 +RO_801170F0_jp = 0x801170F0; // +jtbl_80117140_jp = 0x80117140; // type:jtbl +RO_FLT_801171A8_jp = 0x801171A8; // type:f32 +RO_FLT_801171AC_jp = 0x801171AC; // type:f32 +RO_FLT_801171B0_jp = 0x801171B0; // type:f32 +RO_FLT_801171B4_jp = 0x801171B4; // type:f32 +RO_FLT_801171B8_jp = 0x801171B8; // type:f32 +RO_FLT_801171BC_jp = 0x801171BC; // type:f32 +RO_FLT_801171C0_jp = 0x801171C0; // type:f32 +RO_FLT_801171C4_jp = 0x801171C4; // type:f32 +RO_FLT_801171C8_jp = 0x801171C8; // type:f32 +RO_FLT_801171CC_jp = 0x801171CC; // type:f32 +RO_FLT_801171D0_jp = 0x801171D0; // type:f32 +RO_FLT_801171D4_jp = 0x801171D4; // type:f32 +RO_FLT_801171D8_jp = 0x801171D8; // type:f32 +RO_FLT_801171DC_jp = 0x801171DC; // type:f32 +RO_FLT_801171E0_jp = 0x801171E0; // type:f32 +RO_FLT_801171E4_jp = 0x801171E4; // type:f32 +RO_FLT_801171E8_jp = 0x801171E8; // type:f32 +RO_FLT_801171EC_jp = 0x801171EC; // type:f32 +RO_FLT_801171F0_jp = 0x801171F0; // type:f32 +RO_FLT_801171F4_jp = 0x801171F4; // type:f32 +RO_FLT_801171F8_jp = 0x801171F8; // type:f32 +RO_FLT_801171FC_jp = 0x801171FC; // type:f32 +RO_FLT_80117200_jp = 0x80117200; // type:f32 +jtbl_80117204_jp = 0x80117204; // type:jtbl +RO_FLT_80117218_jp = 0x80117218; // type:f32 +RO_FLT_8011721C_jp = 0x8011721C; // type:f32 +RO_FLT_80117220_jp = 0x80117220; // type:f32 +RO_FLT_80117224_jp = 0x80117224; // type:f32 +RO_FLT_80117228_jp = 0x80117228; // type:f32 +RO_FLT_8011722C_jp = 0x8011722C; // type:f32 +RO_FLT_80117230_jp = 0x80117230; // type:f32 +RO_FLT_80117234_jp = 0x80117234; // type:f32 +RO_FLT_80117240_jp = 0x80117240; // type:f32 +RO_FLT_80117244_jp = 0x80117244; // type:f32 +RO_STR_80117250_jp = 0x80117250; // type:asciz +RO_STR_80117260_jp = 0x80117260; // type:asciz +RO_STR_80117270_jp = 0x80117270; // type:asciz +RO_STR_80117280_jp = 0x80117280; // type:asciz +RO_STR_80117290_jp = 0x80117290; // type:asciz +RO_FLT_80117294_jp = 0x80117294; // type:f32 +RO_FLT_80117298_jp = 0x80117298; // type:f32 +RO_FLT_801172A0_jp = 0x801172A0; // type:f32 +RO_FLT_801172A4_jp = 0x801172A4; // type:f32 +RO_FLT_801172A8_jp = 0x801172A8; // type:f32 +RO_STR_801172B0_jp = 0x801172B0; // type:asciz +RO_STR_801172BC_jp = 0x801172BC; // type:asciz +RO_STR_801172C8_jp = 0x801172C8; // type:asciz +RO_STR_801172D4_jp = 0x801172D4; // type:asciz +RO_STR_801172E0_jp = 0x801172E0; // type:asciz +RO_STR_801172EC_jp = 0x801172EC; // type:asciz +RO_STR_801172F8_jp = 0x801172F8; // type:asciz +RO_STR_80117304_jp = 0x80117304; // type:asciz +RO_STR_80117310_jp = 0x80117310; // type:asciz +RO_STR_8011731C_jp = 0x8011731C; // type:asciz +RO_STR_80117328_jp = 0x80117328; // type:asciz +RO_STR_80117334_jp = 0x80117334; // type:asciz +RO_STR_8011733C_jp = 0x8011733C; // type:asciz +RO_STR_80117344_jp = 0x80117344; // type:asciz +RO_STR_80117350_jp = 0x80117350; // type:asciz +RO_FLT_80117360_jp = 0x80117360; // type:f32 +RO_FLT_80117364_jp = 0x80117364; // type:f32 +RO_FLT_80117368_jp = 0x80117368; // type:f32 +RO_FLT_8011736C_jp = 0x8011736C; // type:f32 +RO_FLT_80117370_jp = 0x80117370; // type:f32 +RO_FLT_80117374_jp = 0x80117374; // type:f32 +RO_FLT_80117378_jp = 0x80117378; // type:f32 +RO_FLT_8011737C_jp = 0x8011737C; // type:f32 +RO_STR_80117380_jp = 0x80117380; // type:asciz +RO_STR_80117394_jp = 0x80117394; // type:asciz +RO_STR_801173A8_jp = 0x801173A8; // type:asciz +RO_STR_801173BC_jp = 0x801173BC; // type:asciz +RO_STR_801173D0_jp = 0x801173D0; // type:asciz +RO_STR_801173E4_jp = 0x801173E4; // type:asciz +RO_STR_801173F8_jp = 0x801173F8; // type:asciz +RO_STR_8011740C_jp = 0x8011740C; // type:asciz +RO_FLT_80117420_jp = 0x80117420; // type:f32 +RO_FLT_80117424_jp = 0x80117424; // type:f32 +RO_FLT_80117428_jp = 0x80117428; // type:f32 +RO_FLT_8011742C_jp = 0x8011742C; // type:f32 +jtbl_80117430_jp = 0x80117430; // type:jtbl +jtbl_80117450_jp = 0x80117450; // type:jtbl +RO_STR_80117490_jp = 0x80117490; // type:asciz +RO_STR_80117498_jp = 0x80117498; // type:asciz +RO_STR_801174A0_jp = 0x801174A0; // type:asciz +jtbl_801174A8_jp = 0x801174A8; // type:jtbl +RO_STR_80117570_jp = 0x80117570; // type:asciz +RO_STR_80117574_jp = 0x80117574; // type:asciz +RO_STR_80117578_jp = 0x80117578; // type:asciz +RO_STR_8011757C_jp = 0x8011757C; // type:asciz +RO_STR_80117580_jp = 0x80117580; // type:asciz +RO_STR_80117584_jp = 0x80117584; // type:asciz +jtbl_80117588_jp = 0x80117588; // type:jtbl +RO_STR_801175B0_jp = 0x801175B0; // type:asciz +RO_STR_801175C0_jp = 0x801175C0; // type:asciz +RO_STR_801175D4_jp = 0x801175D4; // type:asciz +RO_STR_801175E4_jp = 0x801175E4; // type:asciz +RO_STR_801175F8_jp = 0x801175F8; // type:asciz +RO_STR_80117614_jp = 0x80117614; // type:asciz +RO_STR_80117634_jp = 0x80117634; // type:asciz +RO_STR_80117640_jp = 0x80117640; // type:asciz +RO_STR_80117654_jp = 0x80117654; // type:asciz +RO_STR_80117668_jp = 0x80117668; // type:asciz +RO_STR_8011767C_jp = 0x8011767C; // type:asciz +RO_STR_80117694_jp = 0x80117694; // type:asciz +RO_STR_801176A4_jp = 0x801176A4; // type:asciz +RO_STR_801176C0_jp = 0x801176C0; // type:asciz +jtbl_801176D0_jp = 0x801176D0; // type:jtbl +jtbl_801176E4_jp = 0x801176E4; // type:jtbl +RO_STR_80117740_jp = 0x80117740; // type:asciz +RO_STR_80117760_jp = 0x80117760; // type:asciz +RO_STR_8011776C_jp = 0x8011776C; // type:asciz +RO_STR_80117778_jp = 0x80117778; // type:asciz +RO_STR_80117784_jp = 0x80117784; // type:asciz +RO_STR_80117790_jp = 0x80117790; // type:asciz +RO_STR_80117794_jp = 0x80117794; // type:asciz +RO_STR_80117798_jp = 0x80117798; // type:asciz +RO_STR_8011779C_jp = 0x8011779C; // type:asciz +RO_STR_801177A0_jp = 0x801177A0; // type:asciz +RO_STR_801177AC_jp = 0x801177AC; // type:asciz +RO_STR_801177C4_jp = 0x801177C4; // type:asciz +RO_STR_801177D8_jp = 0x801177D8; // type:asciz +RO_STR_801177F0_jp = 0x801177F0; // type:asciz +RO_STR_80117808_jp = 0x80117808; // type:asciz +jtbl_80117820_jp = 0x80117820; // type:jtbl +jtbl_80117834_jp = 0x80117834; // type:jtbl +jtbl_80117888_jp = 0x80117888; // type:jtbl +RO_STR_801178E0_jp = 0x801178E0; // type:asciz +RO_STR_801178F0_jp = 0x801178F0; // type:asciz +RO_STR_80117900_jp = 0x80117900; // type:asciz +RO_STR_80117910_jp = 0x80117910; // type:asciz +RO_STR_80117920_jp = 0x80117920; // type:asciz +RO_STR_8011792C_jp = 0x8011792C; // type:asciz +RO_STR_8011793C_jp = 0x8011793C; // type:asciz +RO_STR_80117950_jp = 0x80117950; // type:asciz +RO_STR_8011796C_jp = 0x8011796C; // type:asciz +RO_STR_8011797C_jp = 0x8011797C; // type:asciz +RO_STR_80117988_jp = 0x80117988; // type:asciz +RO_STR_80117994_jp = 0x80117994; // type:asciz +RO_STR_80117998_jp = 0x80117998; // type:asciz +RO_STR_8011799C_jp = 0x8011799C; // type:asciz +RO_STR_801179B0_jp = 0x801179B0; // type:asciz +RO_STR_801179CC_jp = 0x801179CC; // type:asciz +RO_STR_801179EC_jp = 0x801179EC; // type:asciz +RO_STR_801179FC_jp = 0x801179FC; // type:asciz +jtbl_80117A0C_jp = 0x80117A0C; // type:jtbl +RO_STR_80117A30_jp = 0x80117A30; // type:asciz +RO_STR_80117A40_jp = 0x80117A40; // type:asciz +RO_STR_80117A50_jp = 0x80117A50; // type:asciz +RO_FLT_80117A60_jp = 0x80117A60; // type:f32 +RO_FLT_80117A70_jp = 0x80117A70; // type:f32 +RO_FLT_80117A74_jp = 0x80117A74; // type:f32 +RO_STR_80117A80_jp = 0x80117A80; // type:asciz +RO_FLT_80117AA0_jp = 0x80117AA0; // type:f32 +RO_FLT_80117AA4_jp = 0x80117AA4; // type:f32 +RO_FLT_80117AA8_jp = 0x80117AA8; // type:f32 +RO_FLT_80117AAC_jp = 0x80117AAC; // type:f32 +jtbl_80117AB0_jp = 0x80117AB0; // type:jtbl +RO_FLT_80117AD4_jp = 0x80117AD4; // type:f32 +RO_FLT_80117AD8_jp = 0x80117AD8; // type:f32 +RO_FLT_80117ADC_jp = 0x80117ADC; // type:f32 +RO_80117AE0_jp = 0x80117AE0; // +RO_80117AE8_jp = 0x80117AE8; // +RO_STR_80117AF4_jp = 0x80117AF4; // type:asciz +RO_STR_80117AFC_jp = 0x80117AFC; // type:asciz +RO_STR_80117B04_jp = 0x80117B04; // type:asciz +RO_STR_80117B0C_jp = 0x80117B0C; // type:asciz +RO_STR_80117B14_jp = 0x80117B14; // type:asciz +RO_STR_80117B1C_jp = 0x80117B1C; // type:asciz +RO_FLT_80117B24_jp = 0x80117B24; // type:f32 +RO_FLT_80117B30_jp = 0x80117B30; // type:f32 +RO_FLT_80117B34_jp = 0x80117B34; // type:f32 +jtbl_80117B40_jp = 0x80117B40; // type:jtbl +RO_FLT_80117B54_jp = 0x80117B54; // type:f32 +RO_FLT_80117B58_jp = 0x80117B58; // type:f32 +RO_FLT_80117B5C_jp = 0x80117B5C; // type:f32 +RO_FLT_80117B60_jp = 0x80117B60; // type:f32 +RO_FLT_80117B64_jp = 0x80117B64; // type:f32 +RO_FLT_80117B68_jp = 0x80117B68; // type:f32 +RO_FLT_80117B6C_jp = 0x80117B6C; // type:f32 +RO_FLT_80117B70_jp = 0x80117B70; // type:f32 +RO_FLT_80117B74_jp = 0x80117B74; // type:f32 +RO_FLT_80117B78_jp = 0x80117B78; // type:f32 +RO_FLT_80117B7C_jp = 0x80117B7C; // type:f32 +RO_FLT_80117B80_jp = 0x80117B80; // type:f32 +RO_FLT_80117B84_jp = 0x80117B84; // type:f32 +RO_FLT_80117B88_jp = 0x80117B88; // type:f32 +RO_STR_80117B90_jp = 0x80117B90; // type:asciz +RO_80117BA0_jp = 0x80117BA0; // type:u8 +RO_FLT_80117BE0_jp = 0x80117BE0; // type:f32 +RO_FLT_80117BE4_jp = 0x80117BE4; // type:f32 +RO_FLT_80117BE8_jp = 0x80117BE8; // type:f32 +jtbl_80117BF0_jp = 0x80117BF0; // type:jtbl +jtbl_80117C50_jp = 0x80117C50; // type:jtbl +RO_STR_80117C80_jp = 0x80117C80; // type:asciz +RO_STR_80117CA0_jp = 0x80117CA0; // type:asciz +RO_STR_80117CC0_jp = 0x80117CC0; // type:asciz +RO_80117CE0_jp = 0x80117CE0; // type:u16 +RO_STR_80117D00_jp = 0x80117D00; // type:asciz +RO_STR_80117D0C_jp = 0x80117D0C; // type:asciz +RO_STR_80117D20_jp = 0x80117D20; // type:asciz +RO_STR_80117D3C_jp = 0x80117D3C; // type:asciz +RO_STR_80117D50_jp = 0x80117D50; // type:asciz +RO_STR_80117D60_jp = 0x80117D60; // type:asciz +RO_STR_80117D6C_jp = 0x80117D6C; // type:asciz +RO_STR_80117D78_jp = 0x80117D78; // type:asciz +RO_STR_80117D90_jp = 0x80117D90; // type:asciz +jtbl_80117DB0_jp = 0x80117DB0; // type:jtbl +RO_80117DD0_jp = 0x80117DD0; // type:u8 +RO_80117DEC_jp = 0x80117DEC; // +RO_80117E54_jp = 0x80117E54; // +RO_80117E5C_jp = 0x80117E5C; // type:u8 +RO_STR_80117E70_jp = 0x80117E70; // type:asciz +RO_STR_80117E90_jp = 0x80117E90; // type:asciz +RO_STR_80117EB0_jp = 0x80117EB0; // type:asciz +RO_STR_80117EB8_jp = 0x80117EB8; // type:asciz +RO_STR_80117EC0_jp = 0x80117EC0; // type:asciz +RO_STR_80117EC8_jp = 0x80117EC8; // type:asciz +RO_STR_80117ED0_jp = 0x80117ED0; // type:asciz +RO_STR_80117F58_jp = 0x80117F58; // type:asciz +RO_STR_80118000_jp = 0x80118000; // type:asciz +RO_STR_8011800C_jp = 0x8011800C; // type:asciz +RO_STR_80118034_jp = 0x80118034; // type:asciz +jtbl_8011805C_jp = 0x8011805C; // type:jtbl +RO_DBL_80118080_jp = 0x80118080; // type:f64 +RO_STR_80118090_jp = 0x80118090; // type:asciz +RO_FLT_801180B0_jp = 0x801180B0; // type:f32 +RO_FLT_801180B4_jp = 0x801180B4; // type:f32 +RO_FLT_801180B8_jp = 0x801180B8; // type:f32 +RO_FLT_801180BC_jp = 0x801180BC; // type:f32 +RO_FLT_801180C0_jp = 0x801180C0; // type:f32 +RO_FLT_801180D0_jp = 0x801180D0; // type:f32 +RO_FLT_801180D4_jp = 0x801180D4; // type:f32 +RO_FLT_801180D8_jp = 0x801180D8; // type:f32 +RO_FLT_801180DC_jp = 0x801180DC; // type:f32 +RO_FLT_801180E0_jp = 0x801180E0; // type:f32 +RO_FLT_801180E4_jp = 0x801180E4; // type:f32 +RO_FLT_801180E8_jp = 0x801180E8; // type:f32 +RO_FLT_801180EC_jp = 0x801180EC; // type:f32 +RO_FLT_801180F0_jp = 0x801180F0; // type:f32 +RO_FLT_801180F4_jp = 0x801180F4; // type:f32 +RO_FLT_801180F8_jp = 0x801180F8; // type:f32 +RO_FLT_801180FC_jp = 0x801180FC; // type:f32 +RO_FLT_80118100_jp = 0x80118100; // type:f32 +RO_FLT_80118104_jp = 0x80118104; // type:f32 +RO_FLT_80118108_jp = 0x80118108; // type:f32 +RO_FLT_8011810C_jp = 0x8011810C; // type:f32 +RO_FLT_80118110_jp = 0x80118110; // type:f32 +RO_FLT_80118114_jp = 0x80118114; // type:f32 +RO_FLT_80118118_jp = 0x80118118; // type:f32 +RO_FLT_8011811C_jp = 0x8011811C; // type:f32 +RO_FLT_80118120_jp = 0x80118120; // type:f32 +RO_FLT_80118124_jp = 0x80118124; // type:f32 +RO_FLT_80118128_jp = 0x80118128; // type:f32 +RO_FLT_8011812C_jp = 0x8011812C; // type:f32 +RO_FLT_80118130_jp = 0x80118130; // type:f32 +RO_FLT_80118134_jp = 0x80118134; // type:f32 +RO_FLT_80118138_jp = 0x80118138; // type:f32 +RO_FLT_8011813C_jp = 0x8011813C; // type:f32 +RO_FLT_80118140_jp = 0x80118140; // type:f32 +RO_FLT_80118144_jp = 0x80118144; // type:f32 +RO_FLT_80118148_jp = 0x80118148; // type:f32 +RO_FLT_8011814C_jp = 0x8011814C; // type:f32 +RO_FLT_80118150_jp = 0x80118150; // type:f32 +RO_FLT_80118154_jp = 0x80118154; // type:f32 +RO_FLT_80118158_jp = 0x80118158; // type:f32 +RO_FLT_80118160_jp = 0x80118160; // type:f32 +RO_FLT_80118170_jp = 0x80118170; // type:f32 +RO_FLT_80118174_jp = 0x80118174; // type:f32 +RO_FLT_80118178_jp = 0x80118178; // type:f32 +RO_FLT_8011817C_jp = 0x8011817C; // type:f32 +RO_FLT_80118180_jp = 0x80118180; // type:f32 +RO_FLT_80118184_jp = 0x80118184; // type:f32 +RO_FLT_80118188_jp = 0x80118188; // type:f32 +RO_FLT_8011818C_jp = 0x8011818C; // type:f32 +RO_FLT_80118190_jp = 0x80118190; // type:f32 +RO_FLT_80118194_jp = 0x80118194; // type:f32 +jtbl_801181A0_jp = 0x801181A0; // type:jtbl +jtbl_801181D0_jp = 0x801181D0; // type:jtbl +RO_FLT_801181F0_jp = 0x801181F0; // type:f32 +RO_FLT_80118200_jp = 0x80118200; // type:f32 +RO_FLT_80118204_jp = 0x80118204; // type:f32 +RO_FLT_80118208_jp = 0x80118208; // type:f32 +jtbl_8011820C_jp = 0x8011820C; // type:jtbl +RO_FLT_80118220_jp = 0x80118220; // type:f32 +jtbl_80118224_jp = 0x80118224; // type:jtbl +RO_STR_80118250_jp = 0x80118250; // type:asciz +RO_STR_8011825C_jp = 0x8011825C; // type:asciz +RO_STR_80118268_jp = 0x80118268; // type:asciz +RO_STR_80118274_jp = 0x80118274; // type:asciz +RO_STR_80118280_jp = 0x80118280; // type:asciz +jtbl_80118288_jp = 0x80118288; // type:jtbl +jtbl_8011829C_jp = 0x8011829C; // type:jtbl +RO_FLT_801182B0_jp = 0x801182B0; // type:f32 +RO_FLT_801182B4_jp = 0x801182B4; // type:f32 +RO_FLT_801182B8_jp = 0x801182B8; // type:f32 +jtbl_801182C0_jp = 0x801182C0; // type:jtbl +jtbl_80118340_jp = 0x80118340; // type:jtbl +jtbl_80118380_jp = 0x80118380; // type:jtbl +jtbl_801183B8_jp = 0x801183B8; // type:jtbl +RO_FLT_80118410_jp = 0x80118410; // type:f32 +RO_FLT_80118414_jp = 0x80118414; // type:f32 +RO_FLT_80118418_jp = 0x80118418; // type:f32 +RO_FLT_8011841C_jp = 0x8011841C; // type:f32 +RO_FLT_80118420_jp = 0x80118420; // type:f32 +jtbl_80118430_jp = 0x80118430; // type:jtbl +jtbl_80118454_jp = 0x80118454; // type:jtbl +RO_FLT_80118468_jp = 0x80118468; // type:f32 +RO_FLT_8011846C_jp = 0x8011846C; // type:f32 +RO_FLT_80118470_jp = 0x80118470; // type:f32 +jtbl_80118480_jp = 0x80118480; // type:jtbl +jtbl_801184B8_jp = 0x801184B8; // type:jtbl +RO_FLT_801184F4_jp = 0x801184F4; // type:f32 +RO_FLT_801184F8_jp = 0x801184F8; // type:f32 +jtbl_801184FC_jp = 0x801184FC; // type:jtbl +RO_FLT_80118518_jp = 0x80118518; // type:f32 +RO_FLT_8011851C_jp = 0x8011851C; // type:f32 +jtbl_80118520_jp = 0x80118520; // type:jtbl +jtbl_80118668_jp = 0x80118668; // type:jtbl +jtbl_8011870C_jp = 0x8011870C; // type:jtbl +jtbl_80118890_jp = 0x80118890; // type:jtbl +jtbl_80118950_jp = 0x80118950; // type:jtbl +RO_FLT_80118B20_jp = 0x80118B20; // type:f32 +jtbl_80118B24_jp = 0x80118B24; // type:jtbl +RO_FLT_80118B38_jp = 0x80118B38; // type:f32 +RO_FLT_80118B3C_jp = 0x80118B3C; // type:f32 +RO_FLT_80118B40_jp = 0x80118B40; // type:f32 +RO_FLT_80118B44_jp = 0x80118B44; // type:f32 +RO_FLT_80118B48_jp = 0x80118B48; // type:f32 +RO_FLT_80118B4C_jp = 0x80118B4C; // type:f32 +RO_FLT_80118B50_jp = 0x80118B50; // type:f32 +jtbl_80118B54_jp = 0x80118B54; // type:jtbl +RO_FLT_80118BF8_jp = 0x80118BF8; // type:f32 +RO_FLT_80118BFC_jp = 0x80118BFC; // type:f32 +RO_FLT_80118C00_jp = 0x80118C00; // type:f32 +RO_FLT_80118C04_jp = 0x80118C04; // type:f32 +RO_FLT_80118C08_jp = 0x80118C08; // type:f32 +RO_FLT_80118C0C_jp = 0x80118C0C; // type:f32 +RO_FLT_80118C10_jp = 0x80118C10; // type:f32 +RO_FLT_80118C14_jp = 0x80118C14; // type:f32 +RO_FLT_80118C18_jp = 0x80118C18; // type:f32 +RO_FLT_80118C1C_jp = 0x80118C1C; // type:f32 +RO_FLT_80118C20_jp = 0x80118C20; // type:f32 +jtbl_80118C24_jp = 0x80118C24; // type:jtbl +RO_FLT_80118C40_jp = 0x80118C40; // type:f32 +RO_FLT_80118C44_jp = 0x80118C44; // type:f32 +RO_FLT_80118C48_jp = 0x80118C48; // type:f32 +RO_FLT_80118C4C_jp = 0x80118C4C; // type:f32 +RO_FLT_80118C50_jp = 0x80118C50; // type:f32 +RO_FLT_80118C54_jp = 0x80118C54; // type:f32 +RO_FLT_80118C58_jp = 0x80118C58; // type:f32 +RO_FLT_80118C5C_jp = 0x80118C5C; // type:f32 +RO_FLT_80118C60_jp = 0x80118C60; // type:f32 +RO_FLT_80118C64_jp = 0x80118C64; // type:f32 +jtbl_80118C68_jp = 0x80118C68; // type:jtbl +RO_FLT_80118C88_jp = 0x80118C88; // type:f32 +RO_FLT_80118C8C_jp = 0x80118C8C; // type:f32 +RO_FLT_80118C90_jp = 0x80118C90; // type:f32 +RO_FLT_80118C94_jp = 0x80118C94; // type:f32 +RO_FLT_80118C98_jp = 0x80118C98; // type:f32 +RO_FLT_80118C9C_jp = 0x80118C9C; // type:f32 +RO_FLT_80118CA0_jp = 0x80118CA0; // type:f32 +jtbl_80118CA4_jp = 0x80118CA4; // type:jtbl +RO_FLT_80118CD0_jp = 0x80118CD0; // type:f32 +RO_FLT_80118CD4_jp = 0x80118CD4; // type:f32 +RO_FLT_80118CD8_jp = 0x80118CD8; // type:f32 +RO_FLT_80118CDC_jp = 0x80118CDC; // type:f32 +RO_FLT_80118CE0_jp = 0x80118CE0; // type:f32 +RO_FLT_80118CE4_jp = 0x80118CE4; // type:f32 +RO_FLT_80118CE8_jp = 0x80118CE8; // type:f32 +RO_FLT_80118CEC_jp = 0x80118CEC; // type:f32 +RO_FLT_80118CF0_jp = 0x80118CF0; // type:f32 +RO_FLT_80118CF4_jp = 0x80118CF4; // type:f32 +RO_FLT_80118CF8_jp = 0x80118CF8; // type:f32 +RO_FLT_80118CFC_jp = 0x80118CFC; // type:f32 +RO_FLT_80118D00_jp = 0x80118D00; // type:f32 +RO_FLT_80118D04_jp = 0x80118D04; // type:f32 +RO_FLT_80118D08_jp = 0x80118D08; // type:f32 +RO_FLT_80118D0C_jp = 0x80118D0C; // type:f32 +RO_FLT_80118D10_jp = 0x80118D10; // type:f32 +RO_FLT_80118D14_jp = 0x80118D14; // type:f32 +jtbl_80118D18_jp = 0x80118D18; // type:jtbl +RO_FLT_80118D2C_jp = 0x80118D2C; // type:f32 +RO_FLT_80118D30_jp = 0x80118D30; // type:f32 +jtbl_80118D34_jp = 0x80118D34; // type:jtbl +RO_FLT_80118DD8_jp = 0x80118DD8; // type:f32 +RO_FLT_80118DDC_jp = 0x80118DDC; // type:f32 +RO_FLT_80118DE0_jp = 0x80118DE0; // type:f32 +RO_FLT_80118DE4_jp = 0x80118DE4; // type:f32 +RO_FLT_80118DE8_jp = 0x80118DE8; // type:f32 +jtbl_80118DEC_jp = 0x80118DEC; // type:jtbl +jtbl_80118E08_jp = 0x80118E08; // type:jtbl +RO_FLT_80118E70_jp = 0x80118E70; // type:f32 +RO_FLT_80118E74_jp = 0x80118E74; // type:f32 +jtbl_80118E78_jp = 0x80118E78; // type:jtbl +RO_FLT_80118E8C_jp = 0x80118E8C; // type:f32 +RO_FLT_80118E90_jp = 0x80118E90; // type:f32 +jtbl_80118E94_jp = 0x80118E94; // type:jtbl +jtbl_80118ED0_jp = 0x80118ED0; // type:jtbl +RO_FLT_80118EF8_jp = 0x80118EF8; // type:f32 +jtbl_80118EFC_jp = 0x80118EFC; // type:jtbl +RO_FLT_80118F38_jp = 0x80118F38; // type:f32 +RO_FLT_80118F3C_jp = 0x80118F3C; // type:f32 +jtbl_80118F40_jp = 0x80118F40; // type:jtbl +jtbl_80119120_jp = 0x80119120; // type:jtbl +jtbl_80119150_jp = 0x80119150; // type:jtbl +jtbl_80119168_jp = 0x80119168; // type:jtbl +RO_80119240_jp = 0x80119240; // +RO_80119640_jp = 0x80119640; // +D_80119A42_jp = 0x80119A42; // type:s16 +RO_80119A44_jp = 0x80119A44; // +RO_80119A48_jp = 0x80119A48; // +RO_80119A4C_jp = 0x80119A4C; // +RO_80119A50_jp = 0x80119A50; // +RO_8011B080_jp = 0x8011B080; // +RO_8011B4A0_jp = 0x8011B4A0; // + +// .bss + +B_8011B830_jp = 0x8011B830; // type:u8 +B_8011B83C_jp = 0x8011B83C; // type:u8 +B_8011B850_jp = 0x8011B850; // +B_8011B890_jp = 0x8011B890; // +B_8011B8A0_jp = 0x8011B8A0; // +B_8011B8B0_jp = 0x8011B8B0; // +B_8011B8B4_jp = 0x8011B8B4; // +B_8011B8B8_jp = 0x8011B8B8; // +B_FLT_8011B8BC_jp = 0x8011B8BC; // type:f32 +B_8011B8C0_jp = 0x8011B8C0; // +B_8011B8D0_jp = 0x8011B8D0; // +B_8011C0D0_jp = 0x8011C0D0; // +B_8011C8D0_jp = 0x8011C8D0; // +B_8011D0D0_jp = 0x8011D0D0; // +B_8011D4D0_jp = 0x8011D4D0; // +B_8011D6D0_jp = 0x8011D6D0; // +B_8011DED0_jp = 0x8011DED0; // +B_8011E6D0_jp = 0x8011E6D0; // +B_8011EED0_jp = 0x8011EED0; // +B_8011F2D0_jp = 0x8011F2D0; // +B_8011F4D0_jp = 0x8011F4D0; // +B_8011F6D0_jp = 0x8011F6D0; // +B_8011FED0_jp = 0x8011FED0; // +B_801206D0_jp = 0x801206D0; // +B_80120ED0_jp = 0x80120ED0; // +B_80120EF0_jp = 0x80120EF0; // +B_80120F10_jp = 0x80120F10; // +B_80120F30_jp = 0x80120F30; // +B_80120F50_jp = 0x80120F50; // +B_80120F70_jp = 0x80120F70; // +B_80120F90_jp = 0x80120F90; // +B_80120FB0_jp = 0x80120FB0; // +B_801217B0_jp = 0x801217B0; // +B_80121FB0_jp = 0x80121FB0; // +B_80121FD0_jp = 0x80121FD0; // +B_801223D0_jp = 0x801223D0; // +B_801227D0_jp = 0x801227D0; // +B_801228D0_jp = 0x801228D0; // +B_80122CD0_jp = 0x80122CD0; // +B_801234D0_jp = 0x801234D0; // +B_801238D0_jp = 0x801238D0; // +B_80123AD0_jp = 0x80123AD0; // +B_80123CD0_jp = 0x80123CD0; // type:s8 +B_80123CD8_jp = 0x80123CD8; // +B_80123CE0_jp = 0x80123CE0; // type:s8 +B_80123CE1_jp = 0x80123CE1; // type:s8 +B_80123CE4_jp = 0x80123CE4; // +B_80123CEC_jp = 0x80123CEC; // type:s8 +B_80123CED_jp = 0x80123CED; // type:s8 +B_80123CF8_jp = 0x80123CF8; // +B_80123CFC_jp = 0x80123CFC; // type:s8 +B_80123D00_jp = 0x80123D00; // +B_80123D08_jp = 0x80123D08; // +B_80123E04_jp = 0x80123E04; // +B_80123E0C_jp = 0x80123E0C; // type:s8 +B_80123E0D_jp = 0x80123E0D; // type:s8 +B_80123E10_jp = 0x80123E10; // +B_80123F00_jp = 0x80123F00; // +B_80123F04_jp = 0x80123F04; // +B_80123F08_jp = 0x80123F08; // +B_80123F0C_jp = 0x80123F0C; // +B_80123F49_jp = 0x80123F49; // type:s8 +B_80123F4A_jp = 0x80123F4A; // type:s8 +B_80123F4C_jp = 0x80123F4C; // +B_80123F58_jp = 0x80123F58; // type:s16 +B_80123F5A_jp = 0x80123F5A; // type:s16 +B_80123F5C_jp = 0x80123F5C; // +B_80123F64_jp = 0x80123F64; // +B_80123F68_jp = 0x80123F68; // type:u8 +B_80123F6C_jp = 0x80123F6C; // +B_80123F70_jp = 0x80123F70; // +B_80123F80_jp = 0x80123F80; // +B_80123FA0_jp = 0x80123FA0; // +B_80123FC0_jp = 0x80123FC0; // +B_80123FCC_jp = 0x80123FCC; // +B_80123FD8_jp = 0x80123FD8; // +B_80124000_jp = 0x80124000; // +B_80124014_jp = 0x80124014; // +B_8012405C_jp = 0x8012405C; // +B_80124070_jp = 0x80124070; // +B_80124072_jp = 0x80124072; // +B_801240B6_jp = 0x801240B6; // type:s16 +B_80124150_jp = 0x80124150; // +B_80124160_jp = 0x80124160; // +B_FLT_80124170_jp = 0x80124170; // type:f32 +B_FLT_80124278_jp = 0x80124278; // type:f32 +B_FLT_80124380_jp = 0x80124380; // type:f32 +B_FLT_80124580_jp = 0x80124580; // type:f32 +B_80124780_jp = 0x80124780; // +B_801250E0_jp = 0x801250E0; // +B_801250E4_jp = 0x801250E4; // +B_80126AE4_jp = 0x80126AE4; // +B_FLT_80126AE8_jp = 0x80126AE8; // type:f32 +B_FLT_80126CF8_jp = 0x80126CF8; // type:f32 +B_80126D04_jp = 0x80126D04; // +B_80126D0C_jp = 0x80126D0C; // +B_80126D14_jp = 0x80126D14; // +B_80126D20_jp = 0x80126D20; // +B_80126D2C_jp = 0x80126D2C; // +B_FLT_80126D3C_jp = 0x80126D3C; // type:f32 +B_80126D5C_jp = 0x80126D5C; // +B_80126D60_jp = 0x80126D60; // +B_80126E60_jp = 0x80126E60; // +B_80126E70_jp = 0x80126E70; // +B_80126E74_jp = 0x80126E74; // +B_80126E9C_jp = 0x80126E9C; // +B_80126EA0_jp = 0x80126EA0; // +B_80126EAA_jp = 0x80126EAA; // +B_80126EB4_jp = 0x80126EB4; // +B_80126EB8_jp = 0x80126EB8; // type:u8 +B_80126EB9_jp = 0x80126EB9; // type:u8 +B_80126EC0_jp = 0x80126EC0; // type:u8 +B_80126F00_jp = 0x80126F00; // +B_8012711C_jp = 0x8012711C; // +B_801279AC_jp = 0x801279AC; // type:u8 +B_80129E00_jp = 0x80129E00; // +B_80129E06_jp = 0x80129E06; // type:s8 +B_80129E08_jp = 0x80129E08; // type:u16 +B_80129E0A_jp = 0x80129E0A; // +B_8012A428_jp = 0x8012A428; // +B_8012A444_jp = 0x8012A444; // +B_8012A44A_jp = 0x8012A44A; // type:u16 +B_8012A8A0_jp = 0x8012A8A0; // +B_8012AF08_jp = 0x8012AF08; // +B_8012AF20_jp = 0x8012AF20; // +B_8012AF68_jp = 0x8012AF68; // type:u8 +B_8012D148_jp = 0x8012D148; // type:u16 +B_8012D948_jp = 0x8012D948; // +B_8012DB48_jp = 0x8012DB48; // +B_8012DC28_jp = 0x8012DC28; // +B_8012E956_jp = 0x8012E956; // +B_8012E958_jp = 0x8012E958; // +B_8012E976_jp = 0x8012E976; // +B_8012E978_jp = 0x8012E978; // +B_8012EEA0_jp = 0x8012EEA0; // type:u16 +B_80130D48_jp = 0x80130D48; // type:u16 +B_80130DB8_jp = 0x80130DB8; // type:u16 +B_80130DC3_jp = 0x80130DC3; // type:u8 +B_801312A4_jp = 0x801312A4; // +B_801312E0_jp = 0x801312E0; // type:u8 +B_80131548_jp = 0x80131548; // +B_80132780_jp = 0x80132780; // +B_80134148_jp = 0x80134148; // +B_80135B10_jp = 0x80135B10; // type:u16 +B_80135B1C_jp = 0x80135B1C; // +B_80135B20_jp = 0x80135B20; // +B_80135B22_jp = 0x80135B22; // +B_80135BC2_jp = 0x80135BC2; // type:u16 +B_80135BC4_jp = 0x80135BC4; // type:u16 +B_80135BC6_jp = 0x80135BC6; // type:u16 +B_80135BC8_jp = 0x80135BC8; // type:u16 +B_80135C00_jp = 0x80135C00; // type:u16 +B_80135C02_jp = 0x80135C02; // type:s16 +B_80135C08_jp = 0x80135C08; // type:s8 +B_80135C09_jp = 0x80135C09; // type:s8 +B_80135C10_jp = 0x80135C10; // +B_80135C12_jp = 0x80135C12; // type:u16 +B_80135C14_jp = 0x80135C14; // +B_80135C18_jp = 0x80135C18; // +B_80135C1C_jp = 0x80135C1C; // type:u16 +B_80135C1D_jp = 0x80135C1D; // +B_80135C20_jp = 0x80135C20; // +B_80135C28_jp = 0x80135C28; // +B_80135C2C_jp = 0x80135C2C; // type:s16 +B_80135C2E_jp = 0x80135C2E; // +B_80135C3A_jp = 0x80135C3A; // type:u16 +B_80135C3C_jp = 0x80135C3C; // type:s8 +B_80135C3D_jp = 0x80135C3D; // type:s8 +B_80135C3E_jp = 0x80135C3E; // type:s8 +B_80135C40_jp = 0x80135C40; // +B_80135C44_jp = 0x80135C44; // +B_80135C4C_jp = 0x80135C4C; // +B_80135C50_jp = 0x80135C50; // +B_80135C58_jp = 0x80135C58; // +B_80135C60_jp = 0x80135C60; // type:u16 +B_80135C62_jp = 0x80135C62; // type:u16 +B_80135C8C_jp = 0x80135C8C; // +B_80135CDC_jp = 0x80135CDC; // +B_80135CE0_jp = 0x80135CE0; // type:u8 +B_80135CE1_jp = 0x80135CE1; // type:s8 +B_80135CE2_jp = 0x80135CE2; // type:s8 +B_80135CE3_jp = 0x80135CE3; // type:s8 +B_80135CE4_jp = 0x80135CE4; // type:u16 +B_80135CEC_jp = 0x80135CEC; // type:u16 +B_80135CF0_jp = 0x80135CF0; // type:s16 +B_80135CF4_jp = 0x80135CF4; // +B_80135CF8_jp = 0x80135CF8; // type:u8 +B_80135CF9_jp = 0x80135CF9; // type:u8 +B_80135D00_jp = 0x80135D00; // +B_80135DEC_jp = 0x80135DEC; // +B_80135DF8_jp = 0x80135DF8; // type:u16 +B_80135DFA_jp = 0x80135DFA; // type:s8 +B_80135DFC_jp = 0x80135DFC; // +B_80135E04_jp = 0x80135E04; // +B_80135E08_jp = 0x80135E08; // type:s16 +B_80135E0C_jp = 0x80135E0C; // +B_80136140_jp = 0x80136140; // +B_801361E4_jp = 0x801361E4; // +B_8013620C_jp = 0x8013620C; // type:u8 +B_80136288_jp = 0x80136288; // type:s16 +B_8013628A_jp = 0x8013628A; // type:s16 +B_8013628C_jp = 0x8013628C; // +B_80136294_jp = 0x80136294; // type:s16 +B_80136296_jp = 0x80136296; // type:u16 +B_8013629A_jp = 0x8013629A; // +B_801362BC_jp = 0x801362BC; // type:u8 +B_801362C8_jp = 0x801362C8; // +B_801362CC_jp = 0x801362CC; // +B_801362D1_jp = 0x801362D1; // type:u8 +B_801362D4_jp = 0x801362D4; // type:u16 +B_801362D6_jp = 0x801362D6; // type:u8 +B_801362D7_jp = 0x801362D7; // type:u8 +B_801362D8_jp = 0x801362D8; // type:s8 +B_801362D9_jp = 0x801362D9; // type:s8 +B_801362DC_jp = 0x801362DC; // +B_8013669C_jp = 0x8013669C; // +B_801366A4_jp = 0x801366A4; // +B_801366DC_jp = 0x801366DC; // +B_801366E0_jp = 0x801366E0; // +B_8013670C_jp = 0x8013670C; // type:u8 +B_8013673C_jp = 0x8013673C; // +B_8013673F_jp = 0x8013673F; // type:u8 +B_80136741_jp = 0x80136741; // type:u8 +B_80136742_jp = 0x80136742; // type:u16 +B_80136744_jp = 0x80136744; // type:u8 +B_80136747_jp = 0x80136747; // type:u8 +B_80136749_jp = 0x80136749; // type:u8 +B_8013674A_jp = 0x8013674A; // type:u16 +B_8013674C_jp = 0x8013674C; // type:u8 +B_80136751_jp = 0x80136751; // type:s8 +B_80136EA0_jp = 0x80136EA0; // type:u8 +B_80136EA1_jp = 0x80136EA1; // type:s8 +B_80136EA2_jp = 0x80136EA2; // type:u8 +B_80136EA3_jp = 0x80136EA3; // type:u8 +B_80136EA4_jp = 0x80136EA4; // +B_80136EAC_jp = 0x80136EAC; // +B_80136ECC_jp = 0x80136ECC; // +B_80136EEC_jp = 0x80136EEC; // +B_80136F2C_jp = 0x80136F2C; // +B_80136F34_jp = 0x80136F34; // +B_80136F38_jp = 0x80136F38; // +B_80136F3C_jp = 0x80136F3C; // +B_80136FAC_jp = 0x80136FAC; // +B_80136FB0_jp = 0x80136FB0; // +B_80136FB8_jp = 0x80136FB8; // +B_80136FBC_jp = 0x80136FBC; // type:u8 +B_80136FBD_jp = 0x80136FBD; // type:u8 +B_80136FBE_jp = 0x80136FBE; // type:u8 +B_80136FBF_jp = 0x80136FBF; // type:u8 +B_80136FC0_jp = 0x80136FC0; // type:u8 +B_80136FC1_jp = 0x80136FC1; // type:u8 +B_80136FC2_jp = 0x80136FC2; // type:u16 +B_80136FCB_jp = 0x80136FCB; // type:u8 +B_80136FCC_jp = 0x80136FCC; // +B_80136FD8_jp = 0x80136FD8; // +B_80136FDC_jp = 0x80136FDC; // +B_80136FE0_jp = 0x80136FE0; // type:s8 +B_80136FE1_jp = 0x80136FE1; // +B_80136FE8_jp = 0x80136FE8; // type:s8 +B_80136FE9_jp = 0x80136FE9; // type:u8 +B_80136FEA_jp = 0x80136FEA; // type:u8 +B_80136FEB_jp = 0x80136FEB; // type:s8 +B_80136FEE_jp = 0x80136FEE; // type:s16 +B_80136FF5_jp = 0x80136FF5; // type:u8 +B_80136FF8_jp = 0x80136FF8; // +B_80137000_jp = 0x80137000; // type:s16 +B_8013702F_jp = 0x8013702F; // type:u8 +B_80137030_jp = 0x80137030; // type:u16 +B_80137032_jp = 0x80137032; // type:u16 +B_80137034_jp = 0x80137034; // type:u16 +B_80137348_jp = 0x80137348; // type:u16 +B_8013734A_jp = 0x8013734A; // type:s16 +B_8013734E_jp = 0x8013734E; // type:u8 +B_8013734F_jp = 0x8013734F; // type:s8 +B_8013740C_jp = 0x8013740C; // type:s16 +B_80137410_jp = 0x80137410; // +B_80137424_jp = 0x80137424; // +B_80137438_jp = 0x80137438; // +B_80137440_jp = 0x80137440; // +B_80137444_jp = 0x80137444; // +B_8013744C_jp = 0x8013744C; // type:s8 +B_80137454_jp = 0x80137454; // +B_80137534_jp = 0x80137534; // type:u8 +B_801375B0_jp = 0x801375B0; // type:u16 +B_801375B4_jp = 0x801375B4; // type:u16 +B_801375B9_jp = 0x801375B9; // type:u8 +B_801375BC_jp = 0x801375BC; // type:u8 +B_801375EC_jp = 0x801375EC; // +B_801375F4_jp = 0x801375F4; // +B_801375FC_jp = 0x801375FC; // +B_80137610_jp = 0x80137610; // +B_80137620_jp = 0x80137620; // +B_8013762C_jp = 0x8013762C; // +B_80137634_jp = 0x80137634; // +B_80137640_jp = 0x80137640; // +B_80137648_jp = 0x80137648; // type:s16 +B_8013764A_jp = 0x8013764A; // type:s16 +B_8013764C_jp = 0x8013764C; // type:s16 +B_80137654_jp = 0x80137654; // type:s8 +B_80137655_jp = 0x80137655; // type:s8 +B_80137656_jp = 0x80137656; // type:s16 +B_80137658_jp = 0x80137658; // +B_8013767D_jp = 0x8013767D; // type:s8 +B_8013767E_jp = 0x8013767E; // type:s8 +B_80137680_jp = 0x80137680; // type:s8 +B_80137681_jp = 0x80137681; // type:s8 +B_80137684_jp = 0x80137684; // type:s16 +B_80137688_jp = 0x80137688; // type:s16 +B_8013768A_jp = 0x8013768A; // type:s16 +B_8013768C_jp = 0x8013768C; // type:u8 +B_8013768D_jp = 0x8013768D; // type:u8 +B_80137694_jp = 0x80137694; // +B_8013777E_jp = 0x8013777E; // type:s16 +B_80137780_jp = 0x80137780; // type:u8 +B_80137781_jp = 0x80137781; // type:u8 +B_80137788_jp = 0x80137788; // +B_8013778C_jp = 0x8013778C; // +B_8013779C_jp = 0x8013779C; // type:u8 +B_8013779D_jp = 0x8013779D; // type:u8 +B_801377A4_jp = 0x801377A4; // +B_801377A8_jp = 0x801377A8; // +B_801378D8_jp = 0x801378D8; // type:s8 +B_801378DA_jp = 0x801378DA; // type:s8 +B_801378DC_jp = 0x801378DC; // type:s8 +B_801378DE_jp = 0x801378DE; // +B_801378DF_jp = 0x801378DF; // +B_801378E3_jp = 0x801378E3; // type:s8 +B_801378F0_jp = 0x801378F0; // +B_80137908_jp = 0x80137908; // type:u8 +B_8013790A_jp = 0x8013790A; // type:s8 +B_8013790B_jp = 0x8013790B; // type:u8 +B_80137919_jp = 0x80137919; // +B_8013791A_jp = 0x8013791A; // +B_8013791C_jp = 0x8013791C; // type:s8 +B_8013791D_jp = 0x8013791D; // type:s8 +B_8013791E_jp = 0x8013791E; // type:s8 +B_80137924_jp = 0x80137924; // +B_80137934_jp = 0x80137934; // type:s16 +B_80137944_jp = 0x80137944; // +B_80137960_jp = 0x80137960; // +B_80137C40_jp = 0x80137C40; // +B_80137C48_jp = 0x80137C48; // +B_80138818_jp = 0x80138818; // +B_80138E40_jp = 0x80138E40; // +B_80138E44_jp = 0x80138E44; // +B_80138E50_jp = 0x80138E50; // +B_80138E60_jp = 0x80138E60; // +B_80138E70_jp = 0x80138E70; // type:s8 +B_80138E73_jp = 0x80138E73; // +B_80139C30_jp = 0x80139C30; // +B_80139C40_jp = 0x80139C40; // +B_80139F70_jp = 0x80139F70; // +B_80139F98_jp = 0x80139F98; // +B_8013A098_jp = 0x8013A098; // type:u8 +B_8013A099_jp = 0x8013A099; // type:s8 +B_8013A09A_jp = 0x8013A09A; // +B_8013A0A8_jp = 0x8013A0A8; // +B_8013A0DE_jp = 0x8013A0DE; // +B_8013A0E0_jp = 0x8013A0E0; // +B_8013A0E4_jp = 0x8013A0E4; // +B_8013A0FC_jp = 0x8013A0FC; // +B_8013A100_jp = 0x8013A100; // +B_8013A104_jp = 0x8013A104; // +B_8013A118_jp = 0x8013A118; // +B_8013A120_jp = 0x8013A120; // type:u8 +B_8013A130_jp = 0x8013A130; // +B_8013A168_jp = 0x8013A168; // +B_8013A248_jp = 0x8013A248; // +B_FLT_8013A250_jp = 0x8013A250; // type:f32 +B_FLT_8013A258_jp = 0x8013A258; // type:f32 +B_FLT_8013A25C_jp = 0x8013A25C; // type:f32 +B_8013A270_jp = 0x8013A270; // +B_8013A2B0_jp = 0x8013A2B0; // +B_8013A2D0_jp = 0x8013A2D0; // +B_8013A350_jp = 0x8013A350; // +B_8013A358_jp = 0x8013A358; // +B_8013A360_jp = 0x8013A360; // +B_8013A368_jp = 0x8013A368; // type:u16 +B_8013A36A_jp = 0x8013A36A; // type:s16 +B_8013A36C_jp = 0x8013A36C; // type:s16 +B_8013A370_jp = 0x8013A370; // type:s16 +B_8013A374_jp = 0x8013A374; // +B_8013A37A_jp = 0x8013A37A; // +B_8013A380_jp = 0x8013A380; // +B_8013A398_jp = 0x8013A398; // +B_8013A3A4_jp = 0x8013A3A4; // +B_8013A3C0_jp = 0x8013A3C0; // +B_8013A440_jp = 0x8013A440; // +B_8013A4C0_jp = 0x8013A4C0; // +B_8013A540_jp = 0x8013A540; // +B_8013A5C0_jp = 0x8013A5C0; // +B_8013A640_jp = 0x8013A640; // +B_8013A680_jp = 0x8013A680; // +B_80140680_jp = 0x80140680; // type:s8 +B_80140748_jp = 0x80140748; // type:u8 +B_801407C0_jp = 0x801407C0; // +B_80141390_jp = 0x80141390; // +B_80141DE0_jp = 0x80141DE0; // +B_80141DE4_jp = 0x80141DE4; // type:s8 +B_80141DE8_jp = 0x80141DE8; // type:s16 +B_80141DF0_jp = 0x80141DF0; // +B_FLT_80141DF4_jp = 0x80141DF4; // type:f32 +B_FLT_80141DF8_jp = 0x80141DF8; // type:f32 +B_FLT_80141DFC_jp = 0x80141DFC; // type:f32 +B_80141E00_jp = 0x80141E00; // +B_80141E04_jp = 0x80141E04; // type:s16 +B_80141E10_jp = 0x80141E10; // +B_80141E18_jp = 0x80141E18; // +B_80141FA0_jp = 0x80141FA0; // +B_80141FC8_jp = 0x80141FC8; // +B_80141FE0_jp = 0x80141FE0; // +B_80141FF0_jp = 0x80141FF0; // +B_80142410_jp = 0x80142410; // +B_8014241C_jp = 0x8014241C; // +B_801425C0_jp = 0x801425C0; // +B_80142700_jp = 0x80142700; // +B_8014270A_jp = 0x8014270A; // +B_80142714_jp = 0x80142714; // +B_8014271E_jp = 0x8014271E; // +B_80142730_jp = 0x80142730; // +B_801427E0_jp = 0x801427E0; // +B_80142BA0_jp = 0x80142BA0; // +B_80142BBE_jp = 0x80142BBE; // +B_80142BC0_jp = 0x80142BC0; // type:u8 +B_80142BE0_jp = 0x80142BE0; // +B_80142C00_jp = 0x80142C00; // +B_80142CF0_jp = 0x80142CF0; // +B_80142D08_jp = 0x80142D08; // +B_80142E38_jp = 0x80142E38; // +B_80142E58_jp = 0x80142E58; // +B_80142E78_jp = 0x80142E78; // +B_80142E80_jp = 0x80142E80; // +B_80142E98_jp = 0x80142E98; // +B_80142EB8_jp = 0x80142EB8; // +B_80142ED8_jp = 0x80142ED8; // type:s8 +B_80142EDA_jp = 0x80142EDA; // type:u8 +B_80142EDB_jp = 0x80142EDB; // type:s8 +B_80142EDC_jp = 0x80142EDC; // type:u16 +B_80142EDE_jp = 0x80142EDE; // type:s16 +B_80142EE0_jp = 0x80142EE0; // type:s8 +B_80142F50_jp = 0x80142F50; // +B_80142F58_jp = 0x80142F58; // +B_80142F60_jp = 0x80142F60; // +B_80142F68_jp = 0x80142F68; // +B_80142F70_jp = 0x80142F70; // +B_80142F80_jp = 0x80142F80; // +B_80143028_jp = 0x80143028; // +B_80143388_jp = 0x80143388; // +B_801438B0_jp = 0x801438B0; // +B_801438B8_jp = 0x801438B8; // +B_801438BC_jp = 0x801438BC; // +B_801438C0_jp = 0x801438C0; // +B_80143900_jp = 0x80143900; // +B_80143904_jp = 0x80143904; // +B_80143908_jp = 0x80143908; // +B_8014390C_jp = 0x8014390C; // +B_80143910_jp = 0x80143910; // +B_80143960_jp = 0x80143960; // type:s8 +B_8014399C_jp = 0x8014399C; // type:s16 +B_801439A0_jp = 0x801439A0; // +B_80144570_jp = 0x80144570; // +B_80144620_jp = 0x80144620; // type:s16 +B_80144624_jp = 0x80144624; // +B_80144628_jp = 0x80144628; // +B_8014462C_jp = 0x8014462C; // +B_80144650_jp = 0x80144650; // +B_80144660_jp = 0x80144660; // +B_80144670_jp = 0x80144670; // +B_80144680_jp = 0x80144680; // +B_80144690_jp = 0x80144690; // +B_801446A0_jp = 0x801446A0; // +B_FLT_801446A8_jp = 0x801446A8; // type:f32 +B_FLT_801446AC_jp = 0x801446AC; // type:f32 +B_FLT_801446B0_jp = 0x801446B0; // type:f32 +B_FLT_801446B4_jp = 0x801446B4; // type:f32 +B_801446BA_jp = 0x801446BA; // type:s16 +B_801446BC_jp = 0x801446BC; // type:u8 +B_801446BD_jp = 0x801446BD; // +B_801446C7_jp = 0x801446C7; // type:u8 +B_801446C8_jp = 0x801446C8; // +B_FLT_801446D0_jp = 0x801446D0; // type:f32 +B_801446D4_jp = 0x801446D4; // +B_801446DB_jp = 0x801446DB; // type:u8 +B_801446E0_jp = 0x801446E0; // +B_801446F8_jp = 0x801446F8; // +B_80144700_jp = 0x80144700; // +B_80144718_jp = 0x80144718; // +B_80144B18_jp = 0x80144B18; // +B_80144B38_jp = 0x80144B38; // +B_80144CE8_jp = 0x80144CE8; // +B_80144CEC_jp = 0x80144CEC; // +B_80144CFC_jp = 0x80144CFC; // +B_80144D04_jp = 0x80144D04; // +B_80144D0C_jp = 0x80144D0C; // +B_80144D14_jp = 0x80144D14; // +B_80144D20_jp = 0x80144D20; // +B_80144D28_jp = 0x80144D28; // type:s8 +B_80144E00_jp = 0x80144E00; // +B_80144FB2_jp = 0x80144FB2; // type:s8 +B_80144FB3_jp = 0x80144FB3; // type:s8 +B_80144FB8_jp = 0x80144FB8; // +B_80144FC0_jp = 0x80144FC0; // type:u8 +B_80145014_jp = 0x80145014; // +B_80145020_jp = 0x80145020; // +B_80145040_jp = 0x80145040; // type:s16 +B_80145044_jp = 0x80145044; // +B_80145048_jp = 0x80145048; // type:u8 +B_FLT_8014504C_jp = 0x8014504C; // type:f32 +B_FLT_80145050_jp = 0x80145050; // type:f32 +B_FLT_80145054_jp = 0x80145054; // type:f32 +B_80145060_jp = 0x80145060; // +B_80145070_jp = 0x80145070; // +B_80145080_jp = 0x80145080; // +B_80145370_jp = 0x80145370; // type:s8 +B_80145390_jp = 0x80145390; // +B_80145610_jp = 0x80145610; // +B_80145620_jp = 0x80145620; // +B_80145628_jp = 0x80145628; // type:u8 +B_80145630_jp = 0x80145630; // +B_801457E0_jp = 0x801457E0; // +B_80145800_jp = 0x80145800; // +B_80145820_jp = 0x80145820; // +B_80145840_jp = 0x80145840; // +B_80145860_jp = 0x80145860; // +B_80145880_jp = 0x80145880; // +B_80145898_jp = 0x80145898; // +B_8014589C_jp = 0x8014589C; // +B_801458A0_jp = 0x801458A0; // +B_801458B0_jp = 0x801458B0; // +B_801458B8_jp = 0x801458B8; // +B_801458E0_jp = 0x801458E0; // +B_801458EC_jp = 0x801458EC; // +B_801458F0_jp = 0x801458F0; // +B_80145D70_jp = 0x80145D70; // +B_80145D80_jp = 0x80145D80; // +B_80145DB8_jp = 0x80145DB8; // +B_80145FD8_jp = 0x80145FD8; // +B_80145FDC_jp = 0x80145FDC; // +B_80145FE0_jp = 0x80145FE0; // +B_80145FE4_jp = 0x80145FE4; // +B_80145FE8_jp = 0x80145FE8; // +B_80145FEC_jp = 0x80145FEC; // +B_80145FF0_jp = 0x80145FF0; // +B_80145FF4_jp = 0x80145FF4; // +B_80145FF8_jp = 0x80145FF8; // +B_80145FFC_jp = 0x80145FFC; // +B_80146000_jp = 0x80146000; // +B_80146008_jp = 0x80146008; // +B_80146010_jp = 0x80146010; // +B_80146018_jp = 0x80146018; // +B_80146020_jp = 0x80146020; // +B_80146024_jp = 0x80146024; // +B_80146028_jp = 0x80146028; // +B_8014602C_jp = 0x8014602C; // +B_80146030_jp = 0x80146030; // +B_80146034_jp = 0x80146034; // +B_80146038_jp = 0x80146038; // +B_8014603C_jp = 0x8014603C; // +B_80146040_jp = 0x80146040; // +B_80146044_jp = 0x80146044; // +B_80146050_jp = 0x80146050; // +B_80146058_jp = 0x80146058; // +B_80146060_jp = 0x80146060; // +B_80146064_jp = 0x80146064; // +B_80146068_jp = 0x80146068; // +B_8014606C_jp = 0x8014606C; // +B_80146070_jp = 0x80146070; // +B_80146080_jp = 0x80146080; // +B_80146084_jp = 0x80146084; // +B_FLT_80146090_jp = 0x80146090; // type:f32 +B_FLT_80146094_jp = 0x80146094; // type:f32 +B_FLT_80146098_jp = 0x80146098; // type:f32 +B_FLT_801460A0_jp = 0x801460A0; // type:f32 +B_FLT_801460A4_jp = 0x801460A4; // type:f32 +B_FLT_801460A8_jp = 0x801460A8; // type:f32 +B_801460B0_jp = 0x801460B0; // +B_FLT_801460C0_jp = 0x801460C0; // type:f32 +B_FLT_801460C4_jp = 0x801460C4; // type:f32 +B_FLT_801460C8_jp = 0x801460C8; // type:f32 +B_FLT_801460D0_jp = 0x801460D0; // type:f32 +B_FLT_801460D4_jp = 0x801460D4; // type:f32 +B_FLT_801460D8_jp = 0x801460D8; // type:f32 +B_FLT_801460E0_jp = 0x801460E0; // type:f32 +B_FLT_801460E4_jp = 0x801460E4; // type:f32 +B_FLT_801460E8_jp = 0x801460E8; // type:f32 +B_FLT_801460F0_jp = 0x801460F0; // type:f32 +B_FLT_801460F4_jp = 0x801460F4; // type:f32 +B_FLT_801460F8_jp = 0x801460F8; // type:f32 +B_FLT_80146100_jp = 0x80146100; // type:f32 +B_FLT_80146104_jp = 0x80146104; // type:f32 +B_FLT_80146108_jp = 0x80146108; // type:f32 +B_FLT_80146110_jp = 0x80146110; // type:f32 +B_FLT_80146114_jp = 0x80146114; // type:f32 +B_FLT_80146118_jp = 0x80146118; // type:f32 +B_FLT_80146120_jp = 0x80146120; // type:f32 +B_FLT_80146124_jp = 0x80146124; // type:f32 +B_FLT_80146128_jp = 0x80146128; // type:f32 +B_FLT_80146130_jp = 0x80146130; // type:f32 +B_FLT_80146134_jp = 0x80146134; // type:f32 +B_FLT_80146138_jp = 0x80146138; // type:f32 +B_FLT_8014613C_jp = 0x8014613C; // type:f32 +B_FLT_80146140_jp = 0x80146140; // type:f32 +B_FLT_80146144_jp = 0x80146144; // type:f32 +B_80146148_jp = 0x80146148; // +B_FLT_80146154_jp = 0x80146154; // type:f32 +B_FLT_80146158_jp = 0x80146158; // type:f32 +B_FLT_8014615C_jp = 0x8014615C; // type:f32 +B_FLT_80146160_jp = 0x80146160; // type:f32 +B_FLT_80146164_jp = 0x80146164; // type:f32 +B_80146170_jp = 0x80146170; // +B_FLT_80146188_jp = 0x80146188; // type:f32 +B_FLT_8014618C_jp = 0x8014618C; // type:f32 +B_FLT_80146190_jp = 0x80146190; // type:f32 +B_FLT_80146198_jp = 0x80146198; // type:f32 +B_FLT_8014619C_jp = 0x8014619C; // type:f32 +B_FLT_801461A0_jp = 0x801461A0; // type:f32 +B_FLT_801461A8_jp = 0x801461A8; // type:f32 +B_FLT_801461AC_jp = 0x801461AC; // type:f32 +B_FLT_801461B0_jp = 0x801461B0; // type:f32 +B_801461B8_jp = 0x801461B8; // +B_801461C4_jp = 0x801461C4; // +B_FLT_801461D0_jp = 0x801461D0; // type:f32 +B_FLT_801461D4_jp = 0x801461D4; // type:f32 +B_FLT_801461D8_jp = 0x801461D8; // type:f32 +B_801461E0_jp = 0x801461E0; // +B_801461E4_jp = 0x801461E4; // +B_801461E8_jp = 0x801461E8; // +B_801461F0_jp = 0x801461F0; // type:s16 +B_801461F2_jp = 0x801461F2; // type:s16 +B_801461F4_jp = 0x801461F4; // type:s16 +B_801461F6_jp = 0x801461F6; // type:s16 +B_801461F8_jp = 0x801461F8; // type:s16 +B_801461FA_jp = 0x801461FA; // type:s16 +B_801461FC_jp = 0x801461FC; // type:s16 +B_801461FE_jp = 0x801461FE; // type:s16 +B_80146200_jp = 0x80146200; // +B_80146210_jp = 0x80146210; // +B_FLT_80146224_jp = 0x80146224; // type:f32 +B_FLT_80146228_jp = 0x80146228; // type:f32 +B_FLT_80146230_jp = 0x80146230; // type:f32 +B_FLT_8014623C_jp = 0x8014623C; // type:f32 +B_FLT_80146244_jp = 0x80146244; // type:f32 +B_FLT_80146248_jp = 0x80146248; // type:f32 +B_FLT_8014624C_jp = 0x8014624C; // type:f32 +B_FLT_80146250_jp = 0x80146250; // type:f32 +B_FLT_80146254_jp = 0x80146254; // type:f32 +B_FLT_80146258_jp = 0x80146258; // type:f32 +B_FLT_8014625C_jp = 0x8014625C; // type:f32 +B_FLT_80146260_jp = 0x80146260; // type:f32 +B_FLT_80146264_jp = 0x80146264; // type:f32 +B_FLT_80146268_jp = 0x80146268; // type:f32 +B_FLT_8014626C_jp = 0x8014626C; // type:f32 +B_FLT_80146270_jp = 0x80146270; // type:f32 +B_FLT_80146274_jp = 0x80146274; // type:f32 +B_80146278_jp = 0x80146278; // +B_80146288_jp = 0x80146288; // +B_FLT_80146298_jp = 0x80146298; // type:f32 +B_FLT_8014629C_jp = 0x8014629C; // type:f32 +B_FLT_801462A0_jp = 0x801462A0; // type:f32 +B_801462B0_jp = 0x801462B0; // +B_801462B4_jp = 0x801462B4; // +B_801462C0_jp = 0x801462C0; // +B_80147AC0_jp = 0x80147AC0; // +B_801480C0_jp = 0x801480C0; // +B_801488C0_jp = 0x801488C0; // +B_80148DC0_jp = 0x80148DC0; // +B_801492C0_jp = 0x801492C0; // +B_801492E0_jp = 0x801492E0; // +B_801492F0_jp = 0x801492F0; // +B_80149310_jp = 0x80149310; // +B_80149328_jp = 0x80149328; // +B_80149368_jp = 0x80149368; // +B_801493B0_jp = 0x801493B0; // +B_801493B8_jp = 0x801493B8; // +B_801493C8_jp = 0x801493C8; // +B_801493CC_jp = 0x801493CC; // +B_801493D0_jp = 0x801493D0; // +B_801493D4_jp = 0x801493D4; // +B_801493E0_jp = 0x801493E0; // +B_801493E4_jp = 0x801493E4; // type:s8 +B_801493F0_jp = 0x801493F0; // +B_801493F4_jp = 0x801493F4; // type:s8 +B_80149400_jp = 0x80149400; // +B_801494C0_jp = 0x801494C0; // +B_801494E0_jp = 0x801494E0; // type:u8 +B_801494E1_jp = 0x801494E1; // type:s8 +B_801494E6_jp = 0x801494E6; // +B_801494E8_jp = 0x801494E8; // +B_801494EC_jp = 0x801494EC; // +B_801494F0_jp = 0x801494F0; // +B_80149502_jp = 0x80149502; // type:s16 +B_80149504_jp = 0x80149504; // type:s16 +B_80149508_jp = 0x80149508; // type:s16 +B_8014950A_jp = 0x8014950A; // type:s16 +B_8014950E_jp = 0x8014950E; // type:s16 +B_80149580_jp = 0x80149580; // +B_801495A8_jp = 0x801495A8; // +B_801495D0_jp = 0x801495D0; // +B_801495E0_jp = 0x801495E0; // +B_80149A60_jp = 0x80149A60; // +B_8014A020_jp = 0x8014A020; // +B_8014AC6C_jp = 0x8014AC6C; // +B_8014B1F0_jp = 0x8014B1F0; // +B_8014B248_jp = 0x8014B248; // +B_8014B320_jp = 0x8014B320; // +B_8014B338_jp = 0x8014B338; // +B_8014B378_jp = 0x8014B378; // +B_8014B390_jp = 0x8014B390; // +B_8014B3D0_jp = 0x8014B3D0; // +B_8014B3E8_jp = 0x8014B3E8; // +B_8014BAE8_jp = 0x8014BAE8; // +B_8014BB00_jp = 0x8014BB00; // +B_8014BB04_jp = 0x8014BB04; // +B_8014BD30_jp = 0x8014BD30; // +B_8014BD34_jp = 0x8014BD34; // +B_8014BD38_jp = 0x8014BD38; // +B_8014BD40_jp = 0x8014BD40; // +B_8014BD48_jp = 0x8014BD48; // +B_8014BD4C_jp = 0x8014BD4C; // type:s16 +B_8014BD4E_jp = 0x8014BD4E; // type:u16 +B_8014BD58_jp = 0x8014BD58; // type:s16 +B_8014BD60_jp = 0x8014BD60; // type:s16 +B_FLT_8014BD68_jp = 0x8014BD68; // type:f32 +B_FLT_8014BD6C_jp = 0x8014BD6C; // type:f32 +B_FLT_8014BD70_jp = 0x8014BD70; // type:f32 +B_FLT_8014BD74_jp = 0x8014BD74; // type:f32 +B_8014BD98_jp = 0x8014BD98; // +B_8014BD9C_jp = 0x8014BD9C; // type:s16 +B_8014BD9E_jp = 0x8014BD9E; // type:s8 +B_8014BDA0_jp = 0x8014BDA0; // +B_8014BE7C_jp = 0x8014BE7C; // +B_8014BE88_jp = 0x8014BE88; // +B_8014BE8C_jp = 0x8014BE8C; // +B_8014BE90_jp = 0x8014BE90; // +B_8014BE94_jp = 0x8014BE94; // +B_8014BE98_jp = 0x8014BE98; // type:s8 +B_8014BEA0_jp = 0x8014BEA0; // +B_8014BEB0_jp = 0x8014BEB0; // +B_8014BEC0_jp = 0x8014BEC0; // +B_8014BED0_jp = 0x8014BED0; // +B_8014BF00_jp = 0x8014BF00; // +B_8014BF10_jp = 0x8014BF10; // +B_8014BF20_jp = 0x8014BF20; // +B_8014BF30_jp = 0x8014BF30; // +B_8014BF34_jp = 0x8014BF34; // +B_8014C004_jp = 0x8014C004; // +B_8014C008_jp = 0x8014C008; // +B_8014C040_jp = 0x8014C040; // +B_8014C044_jp = 0x8014C044; // +B_8014C114_jp = 0x8014C114; // +B_8014C118_jp = 0x8014C118; // +B_8014C132_jp = 0x8014C132; // type:s16 +B_8014C13E_jp = 0x8014C13E; // type:s16 +B_8014C150_jp = 0x8014C150; // +B_8014C154_jp = 0x8014C154; // +B_8014C224_jp = 0x8014C224; // +B_8014C228_jp = 0x8014C228; // +B_8014C242_jp = 0x8014C242; // type:s16 +B_8014C24E_jp = 0x8014C24E; // type:s16 +B_8014C260_jp = 0x8014C260; // +B_8014C26C_jp = 0x8014C26C; // +B_8014C3F0_jp = 0x8014C3F0; // +B_8014C3F8_jp = 0x8014C3F8; // +B_8014C400_jp = 0x8014C400; // +B_8014C680_jp = 0x8014C680; // +B_8014C684_jp = 0x8014C684; // +B_8014C688_jp = 0x8014C688; // +B_8014C694_jp = 0x8014C694; // +B_8014C914_jp = 0x8014C914; // +B_8014C918_jp = 0x8014C918; // +B_8014C924_jp = 0x8014C924; // +B_8014C928_jp = 0x8014C928; // +B_8014C930_jp = 0x8014C930; // +B_8014C93C_jp = 0x8014C93C; // +B_8014C948_jp = 0x8014C948; // type:u8 +B_8014C9E8_jp = 0x8014C9E8; // type:u8 +B_8014CA88_jp = 0x8014CA88; // type:u8 +B_8014CB79_jp = 0x8014CB79; // type:u8 +B_8014CB80_jp = 0x8014CB80; // +B_8014CB84_jp = 0x8014CB84; // +B_8014CB8C_jp = 0x8014CB8C; // +B_8014CB90_jp = 0x8014CB90; // +B_8014CE58_jp = 0x8014CE58; // type:u16 +B_8014CF30_jp = 0x8014CF30; // +B_8014D270_jp = 0x8014D270; // +B_8014D2F0_jp = 0x8014D2F0; // +B_8014DCE0_jp = 0x8014DCE0; // +B_80150010_jp = 0x80150010; // +B_80150020_jp = 0x80150020; // +B_80150030_jp = 0x80150030; // +B_80150040_jp = 0x80150040; // +B_801514E0_jp = 0x801514E0; // +B_801514F4_jp = 0x801514F4; // +B_80151A70_jp = 0x80151A70; // +B_80151AF0_jp = 0x80151AF0; // +B_80151B70_jp = 0x80151B70; // +B_80151B88_jp = 0x80151B88; // +B_80151B98_jp = 0x80151B98; // +B_80151BA8_jp = 0x80151BA8; // +B_80151BB8_jp = 0x80151BB8; // +B_80151BC8_jp = 0x80151BC8; // +B_80151BE8_jp = 0x80151BE8; // +B_80151BEC_jp = 0x80151BEC; // +B_80151BF4_jp = 0x80151BF4; // +B_80151C0C_jp = 0x80151C0C; // +B_80151C24_jp = 0x80151C24; // +B_80151C3C_jp = 0x80151C3C; // +B_80151C40_jp = 0x80151C40; // +B_80151C44_jp = 0x80151C44; // +B_80152458_jp = 0x80152458; // +B_8015245C_jp = 0x8015245C; // +B_80152460_jp = 0x80152460; // +B_80152464_jp = 0x80152464; // +B_80152468_jp = 0x80152468; // +B_80152480_jp = 0x80152480; // +B_801524A0_jp = 0x801524A0; // +B_801524B8_jp = 0x801524B8; // diff --git a/linker_scripts/jp/symbol_addrs_libultra.txt b/linker_scripts/jp/symbol_addrs_libultra.txt new file mode 100644 index 00000000..73670426 --- /dev/null +++ b/linker_scripts/jp/symbol_addrs_libultra.txt @@ -0,0 +1,449 @@ +// .text + +osSendMesg = 0x8002DB20; // type:func size:0x14C (sendmesg, true) +osPfsFreeBlocks = 0x8002DC70; // type:func size:0x198 (pfsfreeblocks, true) +osStopThread = 0x8002DE10; // type:func size:0xC0 (stopthread, true) +osFlashReadId = 0x8002DED0; // type:func size:0xCC (flashreadid, true) +osRecvMesg = 0x8002DFA0; // type:func size:0x138 (recvmesg, true) +osSetIntMask = 0x8002E0E0; // type:func size:0xA0 (setintmask, true) +osGetIntMask = 0x8002E180; // type:func size:0x60 (getintmask, true) +guScale = 0x8002E1E0; // type:func size:0xA4 (scale, true) +sinf = 0x8002E290; // type:func size:0x1C0 (sinf, true) +sins = 0x8002E450; // type:func size:0x70 (sins, true) + +func_8002E4C0_jp = 0x8002E4C0; // type:func + +osSpTaskLoad = 0x8002E5CC; // type:func size:0x168 (sptask, true) +osSpTaskStartGo = 0x8002E734; // type:func size:0x40 (sptask, true) + +osDestroyThread = 0x8002E780; // type:func size:0x104 (destroythread, true) + +__ull_rshift = 0x8002E890; // type:func size:0x2C (ll, true) +__ull_rem = 0x8002E8BC; // type:func size:0x3C (ll, true) +__ull_div = 0x8002E8F8; // type:func size:0x3C (ll, true) +__ll_lshift = 0x8002E934; // type:func size:0x2C (ll, true) +__ll_rem = 0x8002E960; // type:func size:0x3C (ll, true) +__ll_div = 0x8002E99C; // type:func size:0x5C (ll, true) +__ll_mul = 0x8002E9F8; // type:func size:0x30 (ll, true) +__ull_divremi = 0x8002EA28; // type:func size:0x60 (ll, true) +__ll_mod = 0x8002EA88; // type:func size:0x9C (ll, true) +__ll_rshift = 0x8002EB24; // type:func size:0x2C (ll, true) + +__osExceptionPreamble = 0x8002EB50; // type:func size:0x10 (exceptasm, true) +__osException = 0x8002EB60; // type:func size:0x54C (exceptasm, true) +send_mesg = 0x8002F0AC; // type:func size:0xB4 (exceptasm, true) +handle_CpU = 0x8002F160; // type:func size:0x34 (exceptasm, true) +__osEnqueueAndYield = 0x8002F194; // type:func size:0x100 (exceptasm, true) +__osEnqueueThread = 0x8002F294; // type:func size:0x48 (exceptasm, true) +__osPopThread = 0x8002F2DC; // type:func size:0x10 (exceptasm, true) +__osNop = 0x8002F2EC; // type:func size:0x8 (exceptasm, true) +__osDispatchThread = 0x8002F2F4; // type:func size:0x17C (exceptasm, true) +__osCleanupThread = 0x8002F470; // type:func size:0x8 (exceptasm, true) +__osDequeueThread = 0x8002F480; // type:func size:0x40 (thread, true) + +bzero = 0x8002F4C0; // type:func (bzero, true) +osContInit = 0x8002F560; // type:func size:0x15C (controller, true) + +__osContGetInitData = 0x8002F6BC; // type:func size:0xAC (controller, true) +__osPackRequestData = 0x8002F768; // type:func size:0xD4 (controller, true) +__osSiCreateAccessQueue = 0x8002F840; // type:func (controller, false) +__osSiGetAccess = 0x8002F890; // type:func (conteepread, false) +__osSiRelAccess = 0x8002F8D4; // type:func (conteepread, false) + +osFlashSectorErase = 0x8002F900; // type:func size:0x144 (flashsectorerase, true) +osCreateThread = 0x8002FA50; // type:func size:0x144 (createthread, true) +osContStartReadData = 0x8002FBA0; // type:func size:0x84 (contreaddata, true) +osContGetReadData = 0x8002FC24; // type:func size:0x8C (contreaddata, true) +func_8002FCB0_jp = 0x8002FCB0; // type:func + +osVirtualToPhysical = 0x8002FD80; // type:func size:0x7C (virtualtophysical, true) +osWritebackDCache = 0x8002FE00; // type:func size:0x74 (writebackdcache, true) +__createSpeedParam = 0x8002FE80; // type:func size:0x9C (initialize, true) +__osInitialize_common = 0x8002FF1C; // type:func size:0x2AC (initialize, true) +__osInitialize_autodetect = 0x800301C8; // type:func size:0x8 (initialize, true) +func_800301D0_jp = 0x800301D0; // type:func + +__osSetSR = 0x80030230; // type:func size:0x10 (setsr, true) +__osGetSR = 0x80030240; // type:func size:0xC (getsr, true) +func_80030250_jp = 0x80030250; // type:func + +guPerspectiveF = 0x80030290; // type:func size:0x230 (perspective, true) +guPerspective = 0x800304C0; // type:func size:0x58 (perspective, true) + +__osSpRawStartDma = 0x80030520; // type:func size:0x84 (sprawdma, true) +__osSiRawStartDma = 0x800305B0; // type:func size:0xAC (sirawdma, true) +osEPiLinkHandle = 0x80030660; // type:func size:0x44 (epilinkhandle, true) +osViBlack = 0x800306B0; // type:func size:0x64 (viblack, true) +__osSiRawReadIo = 0x80030720; // type:func (initialize, false) +osGetThreadId = 0x80030770; // type:func size:0x18 (getthreadid, true) +osSpTaskYield = 0x80030790; // type:func size:0x20 (sptaskyield, true) + +func_800307B0_jp = 0x800307B0; // type:func + +osPfsReadWriteFile = 0x80030884; // type:func size:0x378 (pfsreadwritefile, true) +__osPfsGetStatus = 0x80030C00; // type:func size:0xD0 (pfsgetstatus, true) +__osPfsRequestOneChannel = 0x80030CD0; // type:func size:0xC4 (pfsgetstatus, true) +__osPfsGetOneChannelData = 0x80030D94; // type:func size:0x98 (pfsgetstatus, true) + +func_80030E30_jp = 0x80030E30; // type:func +guMtxIdentF = 0x80030E40; // type:func size:0x48 (mtxidentf, true) +osViSetMode = 0x80030E90; // type:func size:0x58 (visetmode, true) +osFlashInit = 0x80030EF0; // type:func size:0xF0 (flashinit, true) +guLookAtF = 0x80030FE0; // type:func size:0x2A4 (lookat, true) +guLookAt = 0x80031284; // type:func size:0x74 (lookat, true) +__osMotorAccess = 0x80031300; // type:func size:0x168 (motor, true) + +func_80031468_jp = 0x80031468; // type:func + +osMotorInit = 0x80031574; // type:func size:0x15C (motor, true) +osPfsAllocateFile = 0x800316D0; // type:func size:0x334 (pfsallocatefile, true) +__osPfsDeclearPage = 0x80031A04; // type:func size:0x140 (pfsallocatefile, true) +osStopTimer = 0x80031B50; // type:func size:0xE8 (stoptimer, true) +__osProbeTLB = 0x80031C40; // type:func size:0xB8 (probetlb, true) +osCreatePiManager = 0x80031D00; // type:func size:0x170 (pimgr, true) + +__osPiCreateAccessQueue = 0x80031E70; // type:func (pimgr, false) +__osPiGetAccess = 0x80031EC0; // type:func (cartrominit, false) +__osPiRelAccess = 0x80031F04; // type:func (cartrominit, false) +__osDevMgrMain = 0x80031F40; // type:func size:0x410 (devmgr, true) +__osPiRawStartDma = 0x80032350; // type:func size:0xC8 (pirawdma, true) +__osSumcalc = 0x80032420; // type:func size:0x74 (contpfs, true) + +__osIdCheckSum = 0x80032494; // type:func size:0xFC (contpfs, true) +__osRepairPackId = 0x80032590; // type:func size:0x350 (contpfs, true) +__osCheckPackId = 0x800328E0; // type:func size:0x164 (contpfs, true) +__osGetId = 0x80032A44; // type:func size:0x1AC (contpfs, true) +__osCheckId = 0x80032BF0; // type:func size:0xD4 (contpfs, true) +__osPfsRWInode = 0x80032CC4; // type:func size:0x2D4 (contpfs, true) + +osGetCount = 0x80032FA0; // type:func size:0xC (getcount, true) +func_80032FB0_jp = 0x80032FB0; // type:func + +guMtxL2F = 0x80032FC0; // type:func size:0x68 (mtxl2f, true) +osFlashReadStatus = 0x80033030; // type:func size:0x90 (flashreadstatus, true) +osGetMemSize = 0x800330C0; // type:func size:0x114 (getmemsize, true) +osPfsFindFile = 0x800331E0; // type:func size:0x1C4 (pfssearchfile, true) +osSetEventMesg = 0x800333B0; // type:func size:0xB4 (seteventmesg, true) + +sqrtf = 0x80033470; // type:func size:0x8 (sqrtf, true) + +osAfterPreNMI = 0x80033480; // type:func size:0x20 (afterprenmi, true) +osContStartQuery = 0x800334A0; // type:func size:0x7C (contquery, true) +osContGetQuery = 0x8003351C; // type:func size:0x24 (contquery, true) +guLookAtHiliteF = 0x80033540; // type:func size:0x7C0 (lookathil, true) +guLookAtHilite = 0x80033D00; // type:func size:0xB8 (lookathil, true) +_Printf = 0x80033DC0; // type:func size:0x648 (xprintf, true) + +func_80034408_jp = 0x80034408; // type:func + +osUnmapTLBAll = 0x80034AA0; // type:func size:0x44 (unmaptlball, true) +osEPiStartDma = 0x80034AF0; // type:func size:0x9C (epidma, true) +strchr = 0x80034B90; // type:func size:0x40 (string, true) +strlen = 0x80034BD0; // type:func size:0x28 (string, true) +memcpy = 0x80034BF8; // type:func size:0x2C (string, true) +osInvalDCache = 0x80034C30; // type:func size:0xAC (invaldcache, true) +osInvalICache = 0x80034CE0; // type:func size:0x74 (invalicache, true) +osCreateMesgQueue = 0x80034D60; // type:func size:0x2C (createmesgqueue, true) +osPfsRepairId = 0x80034D90; // type:func size:0x58 (pfsrepairid, true) + +__osTimerServicesInit = 0x80034DF0; // type:func size:0x8C (timerintr, true) +__osTimerInterrupt = 0x80034E7C; // type:func size:0x178 (timerintr, true) +__osSetTimerIntr = 0x80034FF4; // type:func size:0xA0 (timerintr, true) +__osInsertTimer = 0x80035094; // type:func size:0x188 (timerintr, true) +__osSpDeviceBusy = 0x80035220; // type:func size:0x24 (sp, true) +__osSiDeviceBusy = 0x80035250; // type:func size:0x24 (si, true) + +guMtxIdent = 0x80035280; // type:func size:0x4C (mtxident, true) +osJamMesg = 0x800352D0; // type:func size:0x150 (jammesg, true) +osSetThreadPri = 0x80035420; // type:func size:0xE0 (setthreadpri, true) +osGetThreadPri = 0x80035500; // type:func size:0x18 (getthreadpri, true) +__osEPiRawReadIo = 0x80035520; // type:func size:0x15C (epirawread, true) +osViSwapBuffer = 0x80035680; // type:func size:0x4C (viswapbuf, true) +guPositionF = 0x800356D0; // type:func size:0x1A8 (position, true) +guPosition = 0x80035878; // type:func size:0x64 (position, true) +__osEPiRawStartDma = 0x800358E0; // type:func size:0x1E0 (epirawdma, true) +osSpTaskYielded = 0x80035AC0; // type:func size:0x60 (sptaskyielded, true) + +bcmp = 0x80035B20; // type:func (bcmp, true) + +osGetTime = 0x80035C40; // type:func size:0x84 (gettime, true) +guRotateF = 0x80035CD0; // type:func size:0x184 (rotate, true) +guRotate = 0x80035E54; // type:func size:0x4C (rotate, true) +__osSetGlobalIntMask = 0x80035EA0; // type:func size:0x4C (setglobalintmask, true) +osAiSetFrequency = 0x80035EF0; // type:func size:0x144 (aisetfreq, true) +func_80036040_jp = 0x80036040; // type:func +guNormalize = 0x80036060; // type:func size:0x54 (normalize, true) +__osSetCompare = 0x800360C0; // type:func size:0xC (setcompare, true) + +osAiGetStatus = 0x800360D0; // type:func size:0xC (aigetstat, true) +bcopy = 0x800360E0; // type:func (bcopy, true) +__osResetGlobalIntMask = 0x800363F0; // type:func size:0x58 (resetglobalintmask, true) +osPfsDeleteFile = 0x80036450; // type:func size:0x1D8 (pfsdeletefile, true) +__osPfsReleasePages = 0x80036628; // type:func size:0x90 (pfsdeletefile, true) +guOrthoF = 0x800366C0; // type:func size:0x154 (ortho, true) +guOrtho = 0x80036814; // type:func size:0x64 (ortho, true) +osGbpakInit = 0x80036880; // type:func size:0x230 (gbpakinit, true) + +__osViInit = 0x80036AB0; // type:func size:0x114 (vi, true) +__osViSwapContext = 0x80036BD0; // type:func size:0x2F8 (viswapcontext, true) +__osDisableInt = 0x80036ED0; // type:func size:0x70 (interrupt, true) +__osRestoreInt = 0x80036F40; // type:func size:0x1C (interrupt, true) +osPiGetCmdQueue = 0x80036F60; // type:func size:0x28 (pigetcmdq, true) +cosf = 0x80036F90; // type:func size:0x168 (cosf, true) +osEPiReadIo = 0x80037100; // type:func (flashallerase, false) +osViSetSpecialFeatures = 0x80037150; // type:func size:0x15C (visetspecial, true) + +coss = 0x800372B0; // type:func size:0x30 (coss, true) +osFlashWriteArray = 0x800372E0; // type:func size:0x15C (flashwritearray, true) +osFlashAllErase = 0x80037440; // type:func size:0x13C (flashallerase, true) +osFlashClearStatus = 0x80037580; // type:func size:0x4C (flashclearstatus, true) +osViSetEvent = 0x800375D0; // type:func size:0x5C (visetevent, true) +osPfsIsPlug = 0x80037630; // type:func size:0x18C (pfsisplug, true) +__osPfsRequestData = 0x800377BC; // type:func size:0xB4 (pfsisplug, true) +__osPfsGetInitData = 0x80037870; // type:func size:0xAC (pfsisplug, true) +osFlashWriteBuffer = 0x80037920; // type:func size:0x88 (flashwritebuffer, true) +osPfsNumFiles = 0x800379B0; // type:func size:0x128 (pfsnumfiles, true) +osCartRomInit = 0x80037AE0; // type:func size:0x154 (cartrominit, true) +guS2DInitBg = 0x80037C40; // type:func size:0x174 (us2dex, true) +__osPfsSelectBank = 0x80037DC0; // type:func size:0x78 (pfsselectbank, true) +osContSetCh = 0x80037E40; // type:func size:0x58 (contsetch, true) +__osSetFpcCsr = 0x80037EA0; // type:func size:0x10 (setfpccsr, true) +__osGetFpcCsr = 0x80037EB0; // type:func size:0xC (getfpccsr, true) +osPfsFileState = 0x80037EC0; // type:func size:0x1DC (pfsfilestate, true) +osPfsInitPak = 0x800380A0; // type:func size:0x208 (pfsinitpak, true) + +func_800382A8_jp = 0x800382A8; // type:func + +osPfsChecker = 0x800383B0; // type:func size:0x538 (pfschecker, true) +corrupted_init = 0x800388E8; // type:func size:0x2D8 (pfschecker, true) +corrupted = 0x80038BC0; // type:func size:0x19C (pfschecker, true) +osAiGetLength = 0x80038D60; // type:func size:0xC (aigetlen, true) +osEPiWriteIo = 0x80038D70; // type:func (flashallerase, false) +osMapTLBRdb = 0x80038DC0; // type:func size:0x58 (maptlbrdb, true) +osYieldThread = 0x80038E20; // type:func size:0x4C (yieldthread, true) +func_80038E70_jp = 0x80038E70; // type:func + +guTranslate = 0x80038E80; // type:func size:0xC8 (translate, true) + +__osGetCause = 0x80038F50; // type:func size:0xC (getcause, true) +__osContRamWrite = 0x80038F60; // type:func size:0x24C (contramwrite, true) +__osContRamRead = 0x800391B0; // type:func size:0x224 (contramread, true) +__osContAddressCrc = 0x800393E0; // type:func size:0xD0 (crc, true) +__osContDataCrc = 0x800394B0; // type:func size:0x94 (crc, true) +__osEPiRawWriteIo = 0x80039550; // type:func size:0x158 (epirawwrite, true) +osSetTimer = 0x800396B0; // type:func size:0x188 (settimer, true) +_Ldtob = 0x80039840; // type:func size:0x490 (xldtob, true) + +func_80039CD0_jp = 0x80039CD0; // type:func + +func_80039D88_jp = 0x80039D88; // type:func + +ldiv = 0x8003A350; // type:func size:0x84 (ldiv, true) +lldiv = 0x8003A3D4; // type:func size:0x100 (ldiv, true) +_Litob = 0x8003A4E0; // type:func size:0x298 (xlitob, true) +__osSiRawWriteIo = 0x8003A780; // type:func (initialize, false) +__osSpSetStatus = 0x8003A7D0; // type:func size:0xC (spsetstat, true) +__osSpGetStatus = 0x8003A7E0; // type:func size:0xC (spgetstat, true) + +func_8003A7F0_jp = 0x8003A7F0; // type:func +osCreateViManager = 0x8003A800; // type:func size:0x180 (vimgr, true) +func_8003A980_jp = 0x8003A980; // type:func +__osViGetCurrentContext = 0x8003AB10; // type:func (vimgr, false) +osWritebackDCacheAll = 0x8003AB20; // type:func size:0x28 (writebackdcacheall, true) +func_8003AB50_jp = 0x8003AB50; // type:func +guMtxF2L = 0x8003AB60; // type:func size:0x64 (mtxf2l, true) + +osStartThread = 0x8003ABD0; // type:func size:0x150 (startthread, true) + +__d_to_ll = 0x8003AD20; // type:func size:0x1C (llcvt, true) +__f_to_ll = 0x8003AD3C; // type:func size:0x1C (llcvt, true) +__d_to_ull = 0x8003AD58; // type:func size:0xA0 (llcvt, true) +__f_to_ull = 0x8003ADF8; // type:func size:0x9C (llcvt, true) +__ll_to_d = 0x8003AE94; // type:func size:0x18 (llcvt, true) +__ll_to_f = 0x8003AEAC; // type:func size:0x18 (llcvt, true) +__ull_to_d = 0x8003AEC4; // type:func size:0x34 (llcvt, true) +__ull_to_f = 0x8003AEF8; // type:func size:0x30 (llcvt, true) + +osViSetYScale = 0x8003AF30; // type:func size:0x4C (visetyscale, true) +osViSetXScale = 0x8003AF80; // type:func size:0x10C (visetxscale, true) +osEepromRead = 0x8003B090; // type:func size:0x1D0 (conteepread, true) + +func_8003B260_jp = 0x8003B260; // type:func + +osEepromWrite = 0x8003B2F0; // type:func size:0x1C4 (conteepwrite, true) + +func_8003B4B4_jp = 0x8003B4B4; // type:func + +__osEepStatus = 0x8003B560; // type:func size:0x1A8 (conteepwrite, true) +func_8003B710_jp = 0x8003B710; // type:func +__osSpSetPc = 0x8003B750; // type:func size:0x2C (spsetpc, true) +osFlashReadArray = 0x8003B780; // type:func size:0x194 (flashreadarray, true) +__osFlashGetAddr = 0x8003B920; // type:func size:0x24 (flashgetaddr, true) +__osSetWatchLo = 0x8003B950; // type:func size:0x10 (setwatchlo, true) + + +// .data + +osViModePalLan1 = 0x8003C5A0; // size:0x50 (vi, false) + +D_8003C5F0_jp = 0x8003C5F0; // type:s16 size:0x800 (sins, false) + +__osHwIntTable = 0x8003CDF0; // size:0x28 (exceptasm, true) +__osPiIntTable = 0x8003CE18; // size:0x8 (exceptasm, true) +__osThreadTail = 0x8003CE20; // size:0x8 (createmesgqueue, false) +__osRunQueue = 0x8003CE28; // size:0x4 (setthreadpri, false) +__osActiveQueue = 0x8003CE2C; // size:0x4 (createthread, false) +__osRunningThread = 0x8003CE30; // size:0x4 (destroythread, false) +__osFaultedThread = 0x8003CE34; // (exceptasm, false) +__osContinitialized = 0x8003CE40; // size:0x4 (controller, true) +D_8003CE50_jp = 0x8003CE50; // + +osClockRate = 0x8003CE60; // size:0x8 (initialize, true) +osViClock = 0x8003CE68; // size:0x4 (aisetfreq, false) +__osShutdown = 0x8003CE6C; // size:0x4 (seteventmesg, false) +__OSGlobalIntMask = 0x8003CE70; // size:0x4 (resetglobalintmask, false) +__osPiDevMgr = 0x8003CE80; // size:0x1C (epidma, false) +__osPiTable = 0x8003CE9C; // size:0x4 (cartrominit, false) +__osCurrentHandle = 0x8003CEA0; // (epirawdma, false) +__osPiAccessQueueEnabled = 0x8003CEB0; // size:0x4 (pimgr, false) +__osPfsInodeCacheChannel = 0x8003CF10; // size:0x4 (contpfs, true) +__osPfsInodeCacheBank = 0x8003CF14; // type:s8 size:0x1 (contpfs, true) +__osPreNMI = 0x8003CF20; // size:0x4 (seteventmesg, true) + +D_8003CF30_jp = 0x8003CF30; // +D_8003CF54_jp = 0x8003CF54; // + +__osTimerList = 0x8003CF80; // size:0x4 (settimer, false) + +D_FLT_8003CF90_jp = 0x8003CF90; // type:f32 +D_FLT_8003CFA0_jp = 0x8003CFA0; // type:f32 + +osViModeNtscLan1 = 0x8003CFB0; // size:0x50 (vi, false) +osViModeMpalLan1 = 0x8003D000; // size:0x50 (vi, false) + +D_8003D050_jp = 0x8003D050; // size:0x70 (vi, false) +__osViCurr = 0x8003D0B0; // size:0x4 (vi, true) +__osViNext = 0x8003D0B4; // size:0x4 (vi, true) + +D_8003D0C0_jp = 0x8003D0C0; // size:0x10 (cartrominit, false) +D_8003D0D0_jp = 0x8003D0D0; // + +__osPfsLastChannel = 0x8003D120; // size:0x4 (contramread, true) + +D_8003D130_jp = 0x8003D130; // size:0x30 (xlitob, false) + +__osViDevMgr = 0x8003D160; // size:0x5 (vimgr, true) +__additional_scanline = 0x8003D17C; // size:0x4 (vimgr, true) + + +// .rodata + +__osRcpImTable = 0x8003E5D0; // type:u16 size:0x80 (setintmask, true) + +RO_DBL_8003E650_jp = 0x8003E650; // type:f64 (sinf, false) +RO_DBL_8003E678_jp = 0x8003E678; // type:f64 +RO_DBL_8003E680_jp = 0x8003E680; // type:f64 +RO_DBL_8003E688_jp = 0x8003E688; // type:f64 +RO_FLT_8003E690_jp = 0x8003E690; // type:f32 + +RO_8003E6A0_jp = 0x8003E6A0; // type:u8 (exceptasm, false) +jtbl_8003E6C0_jp = 0x8003E6C0; // type:jtbl + +RO_DBL_8003E6F0_jp = 0x8003E6F0; // type:f64 (perspective, false) + +jtbl_8003E700_jp = 0x8003E700; // type:jtbl (devmgr, false) + +RO_DBL_8003E720_jp = 0x8003E720; // type:f64 (lookathil, false) +RO_DBL_8003E728_jp = 0x8003E728; // type:f64 + +RO_STR_8003E730_jp = 0x8003E730; // type:asciz (xprintf, false) +RO_STR_8003E734_jp = 0x8003E734; // type:asciz +RO_8003E73C_jp = 0x8003E73C; // +jtbl_8003E754_jp = 0x8003E754; // type:jtbl + +RO_DBL_8003E830_jp = 0x8003E830; // type:f64 (cosf, false) +RO_DBL_8003E858_jp = 0x8003E858; // type:f64 +RO_DBL_8003E860_jp = 0x8003E860; // type:f64 +RO_DBL_8003E868_jp = 0x8003E868; // type:f64 +RO_FLT_8003E870_jp = 0x8003E870; // type:f32 + +__libm_qnan_f = 0x8003E880; // type:f32 size:0x4 (cosf, false) + +// .rodata = 0x8003E890; // size:0x60 (xldtob, false) + +// .rodata = 0x8003E8F0; // size:0x10 (llcvt, false) + + + +// .bss + +B_80041A10_jp = 0x80041A10; // size:0x40 (sptask, false) + +__osContPifRam = 0x80041A50; // size:0x40 (contquery, false) +__osContLastCmd = 0x80041A90; // type:s8 size:0x1 size:0x1 (conteepread, false) +__osMaxControllers = 0x80041A91; // type:s8 size:0x1 size:0x1 (contreaddata, false) + +B_80041A92_jp = 0x80041A92; // + +__osEepromTimerQ = 0x80041AB8; // size:0x18 (controller, true) +__osEepromTimerMsg = 0x80041AD0; // size:0x4 (controller, true) + +B_80041AD4_jp = 0x80041AD4; // +B_80041AE0_jp = 0x80041AE0; // +B_80041AE8_jp = 0x80041AE8; // + +__osFinalrom = 0x80041B00; // size:0x4 (initialize, true) + +B_80041B04_jp = 0x80041B04; // + +__osThreadSave = 0x80041B10; // (exceptasm, false) + +__osFlashID = 0x80041CC0; // size:0x10 (flashreadid, false) +__osFlashMsg = 0x80041CD0; // size:0x18 (flashreadid, false) +__osFlashMessageQ = 0x80041CE8; // size:0x18 (flashinit, true) +__osFlashHandler = 0x80041D00; // size:0x74 (flashallerase, false) +__osFlashMsgBuf = 0x80041D74; // size:0x4 (flashinit, true) +__osFlashVersion = 0x80041D78; // size:0x4 (flashgetaddr, false) + +B_80041D7C_jp = 0x80041D7C; // + +B_80041D80_jp = 0x80041D80; // + +__Dom1SpeedParam = 0x80041E80; // type:s8 size:0x74 (initialize, false) +__Dom2SpeedParam = 0x80041EF8; // type:s8 size:0x74 (initialize, false) +B_80041F6C_jp = 0x80041F6C; // +B_80041F70_jp = 0x80041F70; // +B_80043120_jp = 0x80043120; // +B_80043138_jp = 0x80043138; // +B_80043140_jp = 0x80043140; // + +__osPiAccessQueue = 0x80043148; // size:0x18 (pimgr, false) +__osPfsInodeCache = 0x80043160; // size:0x100 (contpfs, true) +__osEventStateTab = 0x80043260; // size:0x78 (seteventmesg, true) +B_800432D8_jp = 0x800432D8; // +B_800432E0_jp = 0x800432E0; // + +__osCurrentTime = 0x80043300; // size:0x8 (gettime, false) +__osBaseCounter = 0x80043308; // size:0x4 (gettime, false) +__osViIntrCount = 0x8004330C; // size:0x4 (timerintr, true) +__osTimerCounter = 0x80043310; // size:0x4 (settimer, false) +B_80043314_jp = 0x80043314; // + +__osGbpakTimer = 0x80043320; // size:0x20 (gbpakinit, true) +__osGbpakTimerQ = 0x80043340; // size:0x18 (gbpakinit, true) +__osGbpakTimerMsg = 0x80043358; // size:0x4 (gbpakinit, true) +B_8004335C_jp = 0x8004335C; // + +__osPfsPifRam = 0x80043360; // type:u8 size:0x40 (contramread, false) +__CartRomHandle = 0x800433A0; // size:0x74 (cartrominit, true) + + +B_80043420_jp = 0x80043420; // 0x1220 (vimgr, false) +B_800445D0_jp = 0x800445D0; // +B_800445E8_jp = 0x800445E8; // +B_80044600_jp = 0x80044600; // +B_80044618_jp = 0x80044618; // +B_80044630_jp = 0x80044630; // + +__osEepPifRam = 0x80044640; // type:s8 size:0x40 (conteepread, true) +__osEepromRead16K = 0x80044680; // size:0x4 (conteepread, true) diff --git a/linker_scripts/jp/undefined_syms.ld b/linker_scripts/jp/undefined_syms.ld new file mode 100644 index 00000000..064005f8 --- /dev/null +++ b/linker_scripts/jp/undefined_syms.ld @@ -0,0 +1,7 @@ +func_84001064 = 0x84001064; +D_80104508 = 0x80104508; +D_8010450C = 0x8010450C; +D_801061A4 = 0x801061A4; +D_80106BF4 = 0x80106BF4; +D_8010B950 = 0x8010B950; +D_8010EE54 = 0x8010EE54; diff --git a/linker_scripts/libultra_syms.ld b/linker_scripts/libultra_syms.ld new file mode 100644 index 00000000..141d7f94 --- /dev/null +++ b/linker_scripts/libultra_syms.ld @@ -0,0 +1,9 @@ +leoBootID = 0x800001A0; +osTvType = 0x80000300; +osRomType = 0x80000304; +osRomBase = 0x80000308; +osResetType = 0x8000030C; +osCicId = 0x80000310; +osVersion = 0x80000314; +osMemSize = 0x80000318; +osAppNMIBuffer = 0x8000031C; diff --git a/relocs/reloc_addrs.jp.txt b/relocs/reloc_addrs.jp.txt new file mode 100644 index 00000000..e69de29b diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..9a9e5e64 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +-r tools/splat/requirements.txt +mapfile-parser>=1.1.2<2.0.0 diff --git a/src/boot/boot_main.c b/src/boot/boot_main.c new file mode 100644 index 00000000..fd0904f4 --- /dev/null +++ b/src/boot/boot_main.c @@ -0,0 +1,5 @@ +#include "ultra64.h" + +#pragma GLOBAL_ASM("asm/jp/nonmatchings/boot/boot_main/func_80025C60_jp.s") + +#pragma GLOBAL_ASM("asm/jp/nonmatchings/boot/boot_main/func_80025CC0_jp.s") diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 00000000..9f688426 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,2 @@ +ido/ +*.tar.gz diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 00000000..2e155fc3 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,47 @@ +UNAME_S := $(shell uname -s) +ifeq ($(OS),Windows_NT) + DETECTED_OS := windows + DOWNLOAD_OS := windows-latest +else ifeq ($(UNAME_S),Linux) + DETECTED_OS := linux + DOWNLOAD_OS := ubuntu-20.04 +else ifeq ($(UNAME_S),Darwin) + DETECTED_OS := macos + DOWNLOAD_OS := macos-latest +endif + + +IDO_5_3_DIR := ido/$(DETECTED_OS)/5.3 +IDO_5_3 := $(IDO_5_3_DIR)/cc + +IDO_7_1_DIR := ido/$(DETECTED_OS)/7.1 +IDO_7_1 := $(IDO_7_1_DIR)/cc + +all: $(IDO_5_3) $(IDO_7_1) + +clean: + $(RM) -rf $(IDO_5_3_DIR) $(IDO_7_1_DIR) + +distclean: clean + $(RM) -rf ido + +.PHONY: all clean distclean + + +$(IDO_5_3): | $(IDO_5_3_DIR) + wget https://github.com/decompals/ido-static-recomp/releases/latest/download/ido-5.3-recomp-$(DOWNLOAD_OS).tar.gz + tar xf ido-5.3-recomp-$(DOWNLOAD_OS).tar.gz -C $(IDO_5_3_DIR) + $(RM) ido-5.3-recomp-$(DOWNLOAD_OS).tar.gz + +$(IDO_7_1): | $(IDO_7_1_DIR) + wget https://github.com/decompals/ido-static-recomp/releases/latest/download/ido-7.1-recomp-$(DOWNLOAD_OS).tar.gz + tar xf ido-7.1-recomp-$(DOWNLOAD_OS).tar.gz -C $(IDO_7_1_DIR) + $(RM) ido-7.1-recomp-$(DOWNLOAD_OS).tar.gz + +$(IDO_5_3_DIR): + mkdir -p $@ + +$(IDO_7_1_DIR): + mkdir -p $@ + +distclean: clean diff --git a/tools/asm-differ/.gitignore b/tools/asm-differ/.gitignore new file mode 100644 index 00000000..a2b216fe --- /dev/null +++ b/tools/asm-differ/.gitignore @@ -0,0 +1,4 @@ +.mypy_cache/ +__pycache__/ +.vscode/ +poetry.lock diff --git a/tools/asm-differ/.gitrepo b/tools/asm-differ/.gitrepo new file mode 100644 index 00000000..a98d53e4 --- /dev/null +++ b/tools/asm-differ/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:simonlindholm/asm-differ.git + branch = main + commit = 857b39804a6f764634483cff7adc168a2f3e5c87 + parent = 6e36168761e33e6c33e6f15c2678733ce61ddffb + method = merge + cmdver = 0.4.3 diff --git a/tools/asm-differ/.pre-commit-config.yaml b/tools/asm-differ/.pre-commit-config.yaml new file mode 100644 index 00000000..67ba03d1 --- /dev/null +++ b/tools/asm-differ/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: +- repo: https://github.com/psf/black + rev: 22.3.0 + hooks: + - id: black diff --git a/tools/asm-differ/LICENSE b/tools/asm-differ/LICENSE new file mode 100644 index 00000000..cf1ab25d --- /dev/null +++ b/tools/asm-differ/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/tools/asm-differ/README.md b/tools/asm-differ/README.md new file mode 100644 index 00000000..1d0932c9 --- /dev/null +++ b/tools/asm-differ/README.md @@ -0,0 +1,56 @@ +# asm-differ + +Nice differ for assembly code. Currently supports MIPS, PPC, AArch64, and ARM32; should be easy to hack to support other instruction sets. + +![](screenshot.png) + +## Dependencies + +- Python >= 3.6 +- `python3 -m pip install --user colorama watchdog levenshtein cxxfilt` (also `dataclasses` if on 3.6) + +## Usage + +Create a file `diff_settings.py` in some directory (see the one in this repo for an example). Then from that directory, run + +```bash +/path/to/diff.py [flags] (function|rom addr) +``` + +Recommended flags are `-mwo` (automatically run `make` on source file changes, and include symbols in diff). See `--help` for more details. + +### Tab completion + +[argcomplete](https://kislyuk.github.io/argcomplete/) can be optionally installed (with `python3 -m pip install argcomplete`) to enable tab completion in a bash shell, completing options and symbol names using the linker map. It also requires a bit more setup: + +If invoking the script **exactly** as `./diff.py`, the following should be added to the `.bashrc` according to argcomplete's instructions: + +```bash +eval "$(register-python-argcomplete ./diff.py)" +``` + +If that doesn't work, run `register-python-argcomplete ./diff.py` in your terminal and copy the output to `.bashrc`. + +If setup correctly (don't forget to restart the shell), `complete | grep ./diff.py` should output: + +```bash +complete -o bashdefault -o default -o nospace -F _python_argcomplete ./diff.py +``` + +Note for developers or for general troubleshooting: run `export _ARC_DEBUG=` to enable debug output during tab-completion, it may show otherwise silenced errors. Use `unset _ARC_DEBUG` or restart the terminal to disable. + +### Contributing + +Contributions are very welcome! Some notes on workflow: + +`black` is used for code formatting. You can either run `black diff.py` manually, or set up a pre-commit hook: +```bash +pip install pre-commit black +pre-commit install +``` + +Type annotations are used for all Python code. `mypy` should pass without any errors. + +PRs that skip the above are still welcome, however. + +The targeted Python version is 3.6. There are currently no tests. diff --git a/tools/asm-differ/diff-stylesheet.css b/tools/asm-differ/diff-stylesheet.css new file mode 100644 index 00000000..79da120d --- /dev/null +++ b/tools/asm-differ/diff-stylesheet.css @@ -0,0 +1,67 @@ +table.diff { + border: none; + font-family: Monospace; + white-space: pre; +} +tr.data-ref { + background-color: gray; +} +.immediate { + color: lightblue; +} +.stack { + color: yellow; +} +.register { + color: yellow; +} +.delay-slot { + font-weight: bold; + color: gray; +} +.diff-change { + color: lightblue; +} +.diff-add { + color: green; +} +.diff-remove { + color: red; +} +.source-filename { + font-weight: bold; +} +.source-function { + font-weight: bold; + text-decoration: underline; +} +.source-other { + font-style: italic; +} +.rotation-0 { + color: magenta; +} +.rotation-1 { + color: cyan; +} +.rotation-2 { + color: green; +} +.rotation-3 { + color: red; +} +.rotation-4 { + color: yellow; +} +.rotation-5 { + color: pink; +} +.rotation-6 { + color: blue; +} +.rotation-7 { + color: lime; +} +.rotation-8 { + color: gray; +} diff --git a/tools/asm-differ/diff.py b/tools/asm-differ/diff.py new file mode 100755 index 00000000..1b12f9a4 --- /dev/null +++ b/tools/asm-differ/diff.py @@ -0,0 +1,3465 @@ +#!/usr/bin/env python3 +# PYTHON_ARGCOMPLETE_OK +import argparse +import enum +import sys +from typing import ( + Any, + Callable, + Dict, + Iterator, + List, + Match, + NoReturn, + Optional, + Pattern, + Set, + Tuple, + Type, + Union, +) + + +def fail(msg: str) -> NoReturn: + print(msg, file=sys.stderr) + sys.exit(1) + + +def static_assert_unreachable(x: NoReturn) -> NoReturn: + raise Exception("Unreachable! " + repr(x)) + + +class DiffMode(enum.Enum): + SINGLE = "single" + SINGLE_BASE = "single_base" + NORMAL = "normal" + THREEWAY_PREV = "3prev" + THREEWAY_BASE = "3base" + + +# ==== COMMAND-LINE ==== + +if __name__ == "__main__": + # Prefer to use diff_settings.py from the current working directory + sys.path.insert(0, ".") + try: + import diff_settings + except ModuleNotFoundError: + fail("Unable to find diff_settings.py in the same directory.") + sys.path.pop(0) + + try: + import argcomplete + except ModuleNotFoundError: + argcomplete = None + + parser = argparse.ArgumentParser( + description="Diff MIPS, PPC, AArch64, or ARM32 assembly." + ) + + start_argument = parser.add_argument( + "start", + help="Function name or address to start diffing from.", + ) + + if argcomplete: + + def complete_symbol( + prefix: str, parsed_args: argparse.Namespace, **kwargs: object + ) -> List[str]: + if not prefix or prefix.startswith("-"): + # skip reading the map file, which would + # result in a lot of useless completions + return [] + config: Dict[str, Any] = {} + diff_settings.apply(config, parsed_args) # type: ignore + mapfile = config.get("mapfile") + if not mapfile: + return [] + completes = [] + with open(mapfile) as f: + data = f.read() + # assume symbols are prefixed by a space character + search = f" {prefix}" + pos = data.find(search) + while pos != -1: + # skip the space character in the search string + pos += 1 + # assume symbols are suffixed by either a space + # character or a (unix-style) line return + spacePos = data.find(" ", pos) + lineReturnPos = data.find("\n", pos) + if lineReturnPos == -1: + endPos = spacePos + elif spacePos == -1: + endPos = lineReturnPos + else: + endPos = min(spacePos, lineReturnPos) + if endPos == -1: + match = data[pos:] + pos = -1 + else: + match = data[pos:endPos] + pos = data.find(search, endPos) + completes.append(match) + return completes + + setattr(start_argument, "completer", complete_symbol) + + parser.add_argument( + "end", + nargs="?", + help="Address to end diff at.", + ) + parser.add_argument( + "-o", + dest="diff_obj", + action="store_true", + help="""Diff .o files rather than a whole binary. This makes it possible to + see symbol names. (Recommended)""", + ) + parser.add_argument( + "-f", + "--objfile", + dest="objfile", + type=str, + help="""File path for an object file being diffed. When used + the map file isn't searched for the function given. Useful for dynamically + linked libraries.""", + ) + parser.add_argument( + "-e", + "--elf", + dest="diff_elf_symbol", + metavar="SYMBOL", + help="""Diff a given function in two ELFs, one being stripped and the other + one non-stripped. Requires objdump from binutils 2.33+.""", + ) + parser.add_argument( + "-c", + "--source", + dest="show_source", + action="store_true", + help="Show source code (if possible). Only works with -o or -e.", + ) + parser.add_argument( + "-C", + "--source-old-binutils", + dest="source_old_binutils", + action="store_true", + help="""Tweak --source handling to make it work with binutils < 2.33. + Implies --source.""", + ) + parser.add_argument( + "-j", + "--section", + dest="diff_section", + default=".text", + metavar="SECTION", + help="Diff restricted to a given output section.", + ) + parser.add_argument( + "-L", + "--line-numbers", + dest="show_line_numbers", + action="store_const", + const=True, + help="""Show source line numbers in output, when available. May be enabled by + default depending on diff_settings.py.""", + ) + parser.add_argument( + "--no-line-numbers", + dest="show_line_numbers", + action="store_const", + const=False, + help="Hide source line numbers in output.", + ) + parser.add_argument( + "--inlines", + dest="inlines", + action="store_true", + help="Show inline function calls (if possible). Only works with -o or -e.", + ) + parser.add_argument( + "--base-asm", + dest="base_asm", + metavar="FILE", + help="Read assembly from given file instead of configured base img.", + ) + parser.add_argument( + "--write-asm", + dest="write_asm", + metavar="FILE", + help="Write the current assembly output to file, e.g. for use with --base-asm.", + ) + parser.add_argument( + "-m", + "--make", + dest="make", + action="store_true", + help="Automatically run 'make' on the .o file or binary before diffing.", + ) + parser.add_argument( + "-l", + "--skip-lines", + dest="skip_lines", + metavar="LINES", + type=int, + default=0, + help="Skip the first LINES lines of output.", + ) + parser.add_argument( + "-s", + "--stop-at-ret", + dest="stop_at_ret", + action="store_true", + help="""Stop disassembling at the first return instruction. + Some functions have multiple return points, so use with care!""", + ) + parser.add_argument( + "-i", + "--ignore-large-imms", + dest="ignore_large_imms", + action="store_true", + help="Pretend all large enough immediates are the same.", + ) + parser.add_argument( + "-I", + "--ignore-addr-diffs", + dest="ignore_addr_diffs", + action="store_true", + help="Ignore address differences. Currently only affects AArch64 and ARM32.", + ) + parser.add_argument( + "-B", + "--no-show-branches", + dest="show_branches", + action="store_false", + help="Don't visualize branches/branch targets.", + ) + parser.add_argument( + "-R", + "--no-show-rodata-refs", + dest="show_rodata_refs", + action="store_false", + help="Don't show .rodata -> .text references (typically from jump tables).", + ) + parser.add_argument( + "-S", + "--base-shift", + dest="base_shift", + metavar="N", + type=str, + default="0", + help="""Diff position N in our img against position N + shift in the base img. + Arithmetic is allowed, so e.g. |-S "0x1234 - 0x4321"| is a reasonable + flag to pass if it is known that position 0x1234 in the base img syncs + up with position 0x4321 in our img. Not supported together with -o.""", + ) + parser.add_argument( + "-w", + "--watch", + dest="watch", + action="store_true", + help="""Automatically update when source/object files change. + Recommended in combination with -m.""", + ) + parser.add_argument( + "-0", + "--diff_mode=single_base", + dest="diff_mode", + action="store_const", + const=DiffMode.SINGLE_BASE, + help="""View the base asm only (not a diff).""", + ) + parser.add_argument( + "-1", + "--diff_mode=single", + dest="diff_mode", + action="store_const", + const=DiffMode.SINGLE, + help="""View the current asm only (not a diff).""", + ) + parser.add_argument( + "-3", + "--threeway=prev", + dest="diff_mode", + action="store_const", + const=DiffMode.THREEWAY_PREV, + help="""Show a three-way diff between target asm, current asm, and asm + prior to -w rebuild. Requires -w.""", + ) + parser.add_argument( + "-b", + "--threeway=base", + dest="diff_mode", + action="store_const", + const=DiffMode.THREEWAY_BASE, + help="""Show a three-way diff between target asm, current asm, and asm + when diff.py was started. Requires -w.""", + ) + parser.add_argument( + "--width", + dest="column_width", + metavar="COLS", + type=int, + default=50, + help="Sets the width of the left and right view column.", + ) + parser.add_argument( + "--algorithm", + dest="algorithm", + default="levenshtein", + choices=["levenshtein", "difflib"], + help="""Diff algorithm to use. Levenshtein gives the minimum diff, while difflib + aims for long sections of equal opcodes. Defaults to %(default)s.""", + ) + parser.add_argument( + "--max-size", + "--max-lines", + metavar="LINES", + dest="max_lines", + type=int, + default=1024, + help="The maximum length of the diff, in lines.", + ) + parser.add_argument( + "--no-pager", + dest="no_pager", + action="store_true", + help="""Disable the pager; write output directly to stdout, then exit. + Incompatible with --watch.""", + ) + parser.add_argument( + "--format", + choices=("color", "plain", "html", "json"), + default="color", + help="Output format, default is color. --format=html or json implies --no-pager.", + ) + parser.add_argument( + "-U", + "--compress-matching", + metavar="N", + dest="compress_matching", + type=int, + help="""Compress streaks of matching lines, leaving N lines of context + around non-matching parts.""", + ) + parser.add_argument( + "-V", + "--compress-sameinstr", + metavar="N", + dest="compress_sameinstr", + type=int, + help="""Compress streaks of lines with same instructions (but possibly + different regalloc), leaving N lines of context around other parts.""", + ) + + # Project-specific flags, e.g. different versions/make arguments. + add_custom_arguments_fn = getattr(diff_settings, "add_custom_arguments", None) + if add_custom_arguments_fn: + add_custom_arguments_fn(parser) + + if argcomplete: + argcomplete.autocomplete(parser) + +# ==== IMPORTS ==== + +# (We do imports late to optimize auto-complete performance.) + +import abc +from collections import Counter, defaultdict +from dataclasses import asdict, dataclass, field, replace +import difflib +import html +import itertools +import json +import os +import queue +import re +import string +import struct +import subprocess +import threading +import time +import traceback + + +MISSING_PREREQUISITES = ( + "Missing prerequisite python module {}. " + "Run `python3 -m pip install --user colorama watchdog levenshtein cxxfilt` to install prerequisites (cxxfilt only needed with --source)." +) + +try: + from colorama import Back, Fore, Style + import watchdog +except ModuleNotFoundError as e: + fail(MISSING_PREREQUISITES.format(e.name)) + +# ==== CONFIG ==== + + +@dataclass +class ProjectSettings: + arch_str: str + objdump_executable: str + objdump_flags: List[str] + build_command: List[str] + map_format: str + build_dir: str + ms_map_address_offset: int + baseimg: Optional[str] + myimg: Optional[str] + mapfile: Optional[str] + source_directories: Optional[List[str]] + source_extensions: List[str] + show_line_numbers_default: bool + disassemble_all: bool + reg_categories: Dict[str, int] + expected_dir: str + + +@dataclass +class Compress: + context: int + same_instr: bool + + +@dataclass +class Config: + arch: "ArchSettings" + + # Build/objdump options + diff_obj: bool + objfile: Optional[str] + make: bool + source_old_binutils: bool + diff_section: str + inlines: bool + max_function_size_lines: int + max_function_size_bytes: int + + # Display options + formatter: "Formatter" + diff_mode: DiffMode + base_shift: int + skip_lines: int + compress: Optional[Compress] + show_rodata_refs: bool + show_branches: bool + show_line_numbers: bool + show_source: bool + stop_at_ret: bool + ignore_large_imms: bool + ignore_addr_diffs: bool + algorithm: str + reg_categories: Dict[str, int] + + # Score options + score_stack_differences = True + penalty_stackdiff = 1 + penalty_regalloc = 5 + penalty_reordering = 60 + penalty_insertion = 100 + penalty_deletion = 100 + + +def create_project_settings(settings: Dict[str, Any]) -> ProjectSettings: + return ProjectSettings( + arch_str=settings.get("arch", "mips"), + baseimg=settings.get("baseimg"), + myimg=settings.get("myimg"), + mapfile=settings.get("mapfile"), + build_command=settings.get( + "make_command", ["make", *settings.get("makeflags", [])] + ), + source_directories=settings.get("source_directories"), + source_extensions=settings.get( + "source_extensions", [".c", ".h", ".cpp", ".hpp", ".s"] + ), + objdump_executable=get_objdump_executable(settings.get("objdump_executable")), + objdump_flags=settings.get("objdump_flags", []), + expected_dir=settings.get("expected_dir", "expected/"), + map_format=settings.get("map_format", "gnu"), + ms_map_address_offset=settings.get("ms_map_address_offset", 0), + build_dir=settings.get("build_dir", settings.get("mw_build_dir", "build/")), + show_line_numbers_default=settings.get("show_line_numbers_default", True), + disassemble_all=settings.get("disassemble_all", False), + reg_categories=settings.get("reg_categories", {}), + ) + + +def create_config(args: argparse.Namespace, project: ProjectSettings) -> Config: + arch = get_arch(project.arch_str) + + formatter: Formatter + if args.format == "plain": + formatter = PlainFormatter(column_width=args.column_width) + elif args.format == "color": + formatter = AnsiFormatter(column_width=args.column_width) + elif args.format == "html": + formatter = HtmlFormatter() + elif args.format == "json": + formatter = JsonFormatter(arch_str=arch.name) + else: + raise ValueError(f"Unsupported --format: {args.format}") + + compress = None + if args.compress_matching is not None: + compress = Compress(args.compress_matching, False) + if args.compress_sameinstr is not None: + if compress is not None: + raise ValueError( + "Cannot pass both --compress-matching and --compress-sameinstr" + ) + compress = Compress(args.compress_sameinstr, True) + + show_line_numbers = args.show_line_numbers + if show_line_numbers is None: + show_line_numbers = project.show_line_numbers_default + + return Config( + arch=arch, + # Build/objdump options + diff_obj=args.diff_obj, + objfile=args.objfile, + make=args.make, + source_old_binutils=args.source_old_binutils, + diff_section=args.diff_section, + inlines=args.inlines, + max_function_size_lines=args.max_lines, + max_function_size_bytes=args.max_lines * 4, + # Display options + formatter=formatter, + diff_mode=args.diff_mode or DiffMode.NORMAL, + base_shift=eval_int( + args.base_shift, "Failed to parse --base-shift (-S) argument as an integer." + ), + skip_lines=args.skip_lines, + compress=compress, + show_rodata_refs=args.show_rodata_refs, + show_branches=args.show_branches, + show_line_numbers=show_line_numbers, + show_source=args.show_source or args.source_old_binutils, + stop_at_ret=args.stop_at_ret, + ignore_large_imms=args.ignore_large_imms, + ignore_addr_diffs=args.ignore_addr_diffs, + algorithm=args.algorithm, + reg_categories=project.reg_categories, + ) + + +def get_objdump_executable(objdump_executable: Optional[str]) -> str: + if objdump_executable is not None: + return objdump_executable + + objdump_candidates = [ + "mips-linux-gnu-objdump", + "mips64-elf-objdump", + "mips-elf-objdump", + ] + for objdump_cand in objdump_candidates: + try: + subprocess.check_call( + [objdump_cand, "--version"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + return objdump_cand + except subprocess.CalledProcessError: + pass + except FileNotFoundError: + pass + + return fail( + f"Missing binutils; please ensure {' or '.join(objdump_candidates)} exists, or configure objdump_executable." + ) + + +def get_arch(arch_str: str) -> "ArchSettings": + for settings in ARCH_SETTINGS: + if arch_str == settings.name: + return settings + raise ValueError(f"Unknown architecture: {arch_str}") + + +BUFFER_CMD: List[str] = ["tail", "-c", str(10**9)] + +# -S truncates long lines instead of wrapping them +# -R interprets color escape sequences +# -i ignores case when searching +# -c something about how the screen gets redrawn; I don't remember the purpose +# -#6 makes left/right arrow keys scroll by 6 characters +LESS_CMD: List[str] = ["less", "-SRic", "-#6"] + +DEBOUNCE_DELAY: float = 0.1 + +# ==== FORMATTING ==== + + +@enum.unique +class BasicFormat(enum.Enum): + NONE = enum.auto() + IMMEDIATE = enum.auto() + STACK = enum.auto() + REGISTER = enum.auto() + REGISTER_CATEGORY = enum.auto() + DELAY_SLOT = enum.auto() + DIFF_CHANGE = enum.auto() + DIFF_ADD = enum.auto() + DIFF_REMOVE = enum.auto() + SOURCE_FILENAME = enum.auto() + SOURCE_FUNCTION = enum.auto() + SOURCE_LINE_NUM = enum.auto() + SOURCE_OTHER = enum.auto() + + +@dataclass(frozen=True) +class RotationFormat: + group: str + index: int + key: str + + +Format = Union[BasicFormat, RotationFormat] +FormatFunction = Callable[[str], Format] + + +class Text: + segments: List[Tuple[str, Format]] + + def __init__(self, line: str = "", f: Format = BasicFormat.NONE) -> None: + self.segments = [(line, f)] if line else [] + + def reformat(self, f: Format) -> "Text": + return Text(self.plain(), f) + + def plain(self) -> str: + return "".join(s for s, f in self.segments) + + def __repr__(self) -> str: + return f"" + + def __bool__(self) -> bool: + return any(s for s, f in self.segments) + + def __str__(self) -> str: + # Use Formatter.apply(...) instead + return NotImplemented + + def __eq__(self, other: object) -> bool: + return NotImplemented + + def __add__(self, other: Union["Text", str]) -> "Text": + if isinstance(other, str): + other = Text(other) + result = Text() + # If two adjacent segments have the same format, merge their lines + if ( + self.segments + and other.segments + and self.segments[-1][1] == other.segments[0][1] + ): + result.segments = ( + self.segments[:-1] + + [(self.segments[-1][0] + other.segments[0][0], self.segments[-1][1])] + + other.segments[1:] + ) + else: + result.segments = self.segments + other.segments + return result + + def __radd__(self, other: Union["Text", str]) -> "Text": + if isinstance(other, str): + other = Text(other) + return other + self + + def finditer(self, pat: Pattern[str]) -> Iterator[Match[str]]: + """Replacement for `pat.finditer(text)` that operates on the inner text, + and returns the exact same matches as `Text.sub(pat, ...)`.""" + for chunk, f in self.segments: + for match in pat.finditer(chunk): + yield match + + def sub(self, pat: Pattern[str], sub_fn: Callable[[Match[str]], "Text"]) -> "Text": + result = Text() + for chunk, f in self.segments: + i = 0 + for match in pat.finditer(chunk): + start, end = match.start(), match.end() + assert i <= start <= end <= len(chunk) + sub = sub_fn(match) + if i != start: + result.segments.append((chunk[i:start], f)) + result.segments.extend(sub.segments) + i = end + if chunk[i:]: + result.segments.append((chunk[i:], f)) + return result + + def ljust(self, column_width: int) -> "Text": + length = sum(len(x) for x, _ in self.segments) + return self + " " * max(column_width - length, 0) + + +@dataclass +class TableLine: + key: Optional[str] + is_data_ref: bool + cells: Tuple[Tuple[Text, Optional["Line"]], ...] + + +@dataclass +class TableData: + headers: Tuple[Text, ...] + current_score: int + max_score: int + previous_score: Optional[int] + lines: List[TableLine] + + +class Formatter(abc.ABC): + @abc.abstractmethod + def apply_format(self, chunk: str, f: Format) -> str: + """Apply the formatting `f` to `chunk` and escape the contents.""" + ... + + @abc.abstractmethod + def table(self, data: TableData) -> str: + """Format a multi-column table with metadata""" + ... + + def apply(self, text: Text) -> str: + return "".join(self.apply_format(chunk, f) for chunk, f in text.segments) + + @staticmethod + def outputline_texts(line: TableLine) -> Tuple[Text, ...]: + return tuple(cell[0] for cell in line.cells) + + +@dataclass +class PlainFormatter(Formatter): + column_width: int + + def apply_format(self, chunk: str, f: Format) -> str: + return chunk + + def table(self, data: TableData) -> str: + rows = [data.headers] + [self.outputline_texts(line) for line in data.lines] + return "\n".join( + "".join(self.apply(x.ljust(self.column_width)) for x in row) for row in rows + ) + + +@dataclass +class AnsiFormatter(Formatter): + # Additional ansi escape codes not in colorama. See: + # https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters + STYLE_UNDERLINE = "\x1b[4m" + STYLE_NO_UNDERLINE = "\x1b[24m" + STYLE_INVERT = "\x1b[7m" + STYLE_RESET = "\x1b[0m" + + BASIC_ANSI_CODES = { + BasicFormat.NONE: "", + BasicFormat.IMMEDIATE: Fore.LIGHTBLUE_EX, + BasicFormat.STACK: Fore.YELLOW, + BasicFormat.REGISTER: Fore.YELLOW, + BasicFormat.REGISTER_CATEGORY: Fore.LIGHTYELLOW_EX, + BasicFormat.DIFF_CHANGE: Fore.LIGHTBLUE_EX, + BasicFormat.DIFF_ADD: Fore.GREEN, + BasicFormat.DIFF_REMOVE: Fore.RED, + BasicFormat.SOURCE_FILENAME: Style.DIM + Style.BRIGHT, + BasicFormat.SOURCE_FUNCTION: Style.DIM + Style.BRIGHT + STYLE_UNDERLINE, + BasicFormat.SOURCE_LINE_NUM: Fore.LIGHTBLACK_EX, + BasicFormat.SOURCE_OTHER: Style.DIM, + } + + BASIC_ANSI_CODES_UNDO = { + BasicFormat.NONE: "", + BasicFormat.SOURCE_FILENAME: Style.NORMAL, + BasicFormat.SOURCE_FUNCTION: Style.NORMAL + STYLE_NO_UNDERLINE, + BasicFormat.SOURCE_OTHER: Style.NORMAL, + } + + ROTATION_ANSI_COLORS = [ + Fore.MAGENTA, + Fore.CYAN, + Fore.GREEN, + Fore.RED, + Fore.LIGHTYELLOW_EX, + Fore.LIGHTMAGENTA_EX, + Fore.LIGHTCYAN_EX, + Fore.LIGHTGREEN_EX, + Fore.LIGHTBLACK_EX, + ] + + column_width: int + + def apply_format(self, chunk: str, f: Format) -> str: + if f == BasicFormat.NONE: + return chunk + undo_ansi_code = Fore.RESET + if isinstance(f, BasicFormat): + ansi_code = self.BASIC_ANSI_CODES[f] + undo_ansi_code = self.BASIC_ANSI_CODES_UNDO.get(f, undo_ansi_code) + elif isinstance(f, RotationFormat): + ansi_code = self.ROTATION_ANSI_COLORS[ + f.index % len(self.ROTATION_ANSI_COLORS) + ] + else: + static_assert_unreachable(f) + return f"{ansi_code}{chunk}{undo_ansi_code}" + + def table(self, data: TableData) -> str: + rows = [(data.headers, False)] + [ + ( + self.outputline_texts(line), + line.is_data_ref, + ) + for line in data.lines + ] + return "\n".join( + "".join( + (self.STYLE_INVERT if is_data_ref else "") + + self.apply(x.ljust(self.column_width)) + + (self.STYLE_RESET if is_data_ref else "") + for x in row + ) + for (row, is_data_ref) in rows + ) + + +@dataclass +class HtmlFormatter(Formatter): + rotation_formats: int = 9 + + def apply_format(self, chunk: str, f: Format) -> str: + chunk = html.escape(chunk) + if f == BasicFormat.NONE: + return chunk + if isinstance(f, BasicFormat): + class_name = f.name.lower().replace("_", "-") + data_attr = "" + elif isinstance(f, RotationFormat): + class_name = f"rotation-{f.index % self.rotation_formats}" + rotation_key = html.escape(f"{f.group};{f.key}", quote=True) + data_attr = f'data-rotation="{rotation_key}"' + else: + static_assert_unreachable(f) + return f"{chunk}" + + def table(self, data: TableData) -> str: + def table_row(line: Tuple[Text, ...], is_data_ref: bool, cell_el: str) -> str: + tr_attrs = " class='data-ref'" if is_data_ref else "" + output_row = f" " + for cell in line: + cell_html = self.apply(cell) + output_row += f"<{cell_el}>{cell_html}" + output_row += "\n" + return output_row + + output = "\n" + output += " \n" + output += table_row(data.headers, False, "th") + output += " \n" + output += " \n" + output += "".join( + table_row(self.outputline_texts(line), line.is_data_ref, "td") + for line in data.lines + ) + output += " \n" + output += "
\n" + return output + + +@dataclass +class JsonFormatter(Formatter): + arch_str: str + + def apply_format(self, chunk: str, f: Format) -> str: + # This method is unused by this formatter + return NotImplemented + + def table(self, data: TableData) -> str: + def serialize_format(s: str, f: Format) -> Dict[str, Any]: + if f == BasicFormat.NONE: + return {"text": s} + elif isinstance(f, BasicFormat): + return {"text": s, "format": f.name.lower()} + elif isinstance(f, RotationFormat): + attrs = asdict(f) + attrs.update({"text": s, "format": "rotation"}) + return attrs + else: + static_assert_unreachable(f) + + def serialize(text: Optional[Text]) -> List[Dict[str, Any]]: + if text is None: + return [] + return [serialize_format(s, f) for s, f in text.segments] + + output: Dict[str, Any] = {} + output["arch_str"] = self.arch_str + output["header"] = { + name: serialize(h) + for h, name in zip(data.headers, ("base", "current", "previous")) + } + output["current_score"] = data.current_score + output["max_score"] = data.max_score + if data.previous_score is not None: + output["previous_score"] = data.previous_score + output_rows: List[Dict[str, Any]] = [] + for row in data.lines: + output_row: Dict[str, Any] = {} + output_row["key"] = row.key + output_row["is_data_ref"] = row.is_data_ref + iters: List[Tuple[str, Text, Optional[Line]]] = [ + (label, *cell) + for label, cell in zip(("base", "current", "previous"), row.cells) + ] + if all(line is None for _, _, line in iters): + # Skip rows that were only for displaying source code + continue + for column_name, text, line in iters: + column: Dict[str, Any] = {} + column["text"] = serialize(text) + if line: + if line.line_num is not None: + column["line"] = line.line_num + if line.branch_target is not None: + column["branch"] = line.branch_target + if line.source_lines: + column["src"] = line.source_lines + if line.comment is not None: + column["src_comment"] = line.comment + if line.source_line_num is not None: + column["src_line"] = line.source_line_num + if line or column["text"]: + output_row[column_name] = column + output_rows.append(output_row) + output["rows"] = output_rows + return json.dumps(output) + + +def format_fields( + pat: Pattern[str], + out1: Text, + out2: Text, + color1: FormatFunction, + color2: Optional[FormatFunction] = None, +) -> Tuple[Text, Text]: + diffs = [ + of.group() != nf.group() + for (of, nf) in zip(out1.finditer(pat), out2.finditer(pat)) + ] + + it = iter(diffs) + + def maybe_color(color: FormatFunction, s: str) -> Text: + return Text(s, color(s)) if next(it, False) else Text(s) + + out1 = out1.sub(pat, lambda m: maybe_color(color1, m.group())) + it = iter(diffs) + out2 = out2.sub(pat, lambda m: maybe_color(color2 or color1, m.group())) + + return out1, out2 + + +def symbol_formatter(group: str, base_index: int) -> FormatFunction: + symbol_formats: Dict[str, Format] = {} + + def symbol_format(s: str) -> Format: + # TODO: it would be nice to use a unique Format for each symbol, so we could + # add extra UI elements in the HTML version + f = symbol_formats.get(s) + if f is None: + index = len(symbol_formats) + base_index + f = RotationFormat(key=s, index=index, group=group) + symbol_formats[s] = f + return f + + return symbol_format + + +# ==== LOGIC ==== + +ObjdumpCommand = Tuple[List[str], str, Optional[str]] + +# eval_expr adapted from https://stackoverflow.com/a/9558001 + +import ast +import operator as op + +# supported operators +operators: Dict[Type[Union[ast.operator, ast.unaryop]], Any] = { + ast.Add: op.add, + ast.Sub: op.sub, + ast.Mult: op.mul, + ast.Div: op.truediv, + ast.Pow: op.pow, + ast.BitXor: op.xor, + ast.USub: op.neg, +} + + +def eval_expr(expr: str) -> Any: + return eval_(ast.parse(expr, mode="eval").body) + + +def eval_(node: ast.AST) -> Any: + if isinstance(node, ast.Num): # + return node.n + elif isinstance(node, ast.BinOp): # + return operators[type(node.op)](eval_(node.left), eval_(node.right)) + elif isinstance(node, ast.UnaryOp): # e.g., -1 + return operators[type(node.op)](eval_(node.operand)) + else: + raise TypeError(node) + + +def maybe_eval_int(expr: str) -> Optional[int]: + try: + ret = eval_expr(expr) + if not isinstance(ret, int): + raise Exception("not an integer") + return ret + except Exception: + return None + + +def eval_int(expr: str, emsg: str) -> int: + ret = maybe_eval_int(expr) + if ret is None: + fail(emsg) + return ret + + +def eval_line_num(expr: str) -> Optional[int]: + expr = expr.strip().replace(":", "") + if expr == "": + return None + return int(expr, 16) + + +def run_make(target: str, project: ProjectSettings) -> None: + subprocess.check_call(project.build_command + [target]) + + +def run_make_capture_output( + target: str, project: ProjectSettings +) -> "subprocess.CompletedProcess[bytes]": + return subprocess.run( + project.build_command + [target], + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + +def restrict_to_function(dump: str, fn_name: str) -> str: + try: + ind = dump.index("\n", dump.index(f"<{fn_name}>:")) + return dump[ind + 1 :] + except ValueError: + return "" + + +def serialize_rodata_references(references: List[Tuple[int, int, str]]) -> str: + return "".join( + f"DATAREF {text_offset} {from_offset} {from_section}\n" + for (text_offset, from_offset, from_section) in references + ) + + +def maybe_get_objdump_source_flags(config: Config) -> List[str]: + flags = [] + + if config.show_line_numbers or config.show_source: + flags.append("--line-numbers") + + if config.show_source: + flags.append("--source") + + if not config.source_old_binutils: + flags.append("--source-comment=│ ") + + if config.inlines: + flags.append("--inlines") + + return flags + + +def run_objdump(cmd: ObjdumpCommand, config: Config, project: ProjectSettings) -> str: + flags, target, restrict = cmd + try: + out = subprocess.run( + [project.objdump_executable] + + config.arch.arch_flags + + project.objdump_flags + + flags + + [target], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ).stdout + except subprocess.CalledProcessError as e: + print(e.stdout) + print(e.stderr) + if "unrecognized option '--source-comment" in e.stderr: + fail("** Try using --source-old-binutils instead of --source **") + raise e + + obj_data: Optional[bytes] = None + if config.diff_obj: + with open(target, "rb") as f: + obj_data = f.read() + + return preprocess_objdump_out(restrict, obj_data, out, config) + + +def preprocess_objdump_out( + restrict: Optional[str], obj_data: Optional[bytes], objdump_out: str, config: Config +) -> str: + """ + Preprocess the output of objdump into a format that `process()` expects. + This format is suitable for saving to disk with `--write-asm`. + + - Optionally filter the output to a single function (`restrict`) + - Otherwise, strip objdump header (7 lines) + - Prepend .data references ("DATAREF" lines) when working with object files + """ + out = objdump_out + + if restrict is not None: + out = restrict_to_function(out, restrict) + else: + for i in range(7): + out = out[out.find("\n") + 1 :] + out = out.rstrip("\n") + + if obj_data and config.show_rodata_refs: + out = ( + serialize_rodata_references(parse_elf_rodata_references(obj_data, config)) + + out + ) + + return out + + +def search_build_objects(objname: str, project: ProjectSettings) -> Optional[str]: + objfiles = [ + os.path.join(dirpath, f) + for dirpath, _, filenames in os.walk(project.build_dir) + for f in filenames + if f == objname + ] + if len(objfiles) > 1: + all_objects = "\n".join(objfiles) + fail( + f"Found multiple objects of the same name {objname} in {project.build_dir}, " + f"cannot determine which to diff against: \n{all_objects}" + ) + if len(objfiles) == 1: + return objfiles[0] + + return None + + +def search_map_file( + fn_name: str, project: ProjectSettings, config: Config, *, for_binary: bool +) -> Tuple[Optional[str], Optional[int]]: + if not project.mapfile: + fail(f"No map file configured; cannot find function {fn_name}.") + + try: + with open(project.mapfile) as f: + contents = f.read() + except Exception: + fail(f"Failed to open map file {project.mapfile} for reading.") + + if project.map_format == "gnu": + if for_binary and "load address" not in contents: + fail( + 'Failed to find "load address" in map file. Maybe you need to add\n' + '"export LANG := C" to your Makefile to avoid localized output?' + ) + + lines = contents.split("\n") + + try: + cur_objfile = None + ram_to_rom = None + cands = [] + last_line = "" + for line in lines: + if line.startswith(" " + config.diff_section): + cur_objfile = line.split()[3] + if "load address" in line: + tokens = last_line.split() + line.split() + ram = int(tokens[1], 0) + rom = int(tokens[5], 0) + ram_to_rom = rom - ram + if line.endswith(" " + fn_name) or f" {fn_name} = 0x" in line: + ram = int(line.split()[0], 0) + if (for_binary and ram_to_rom is not None) or ( + not for_binary and cur_objfile is not None + ): + cands.append((cur_objfile, ram + (ram_to_rom or 0))) + last_line = line + except Exception as e: + traceback.print_exc() + fail(f"Internal error while parsing map file") + + if len(cands) > 1: + fail(f"Found multiple occurrences of function {fn_name} in map file.") + if len(cands) == 1: + return cands[0] + elif project.map_format == "mw": + find = re.findall( + # ram elf rom alignment + r" \S+ \S+ (\S+) (\S+) +\S+ " + + re.escape(fn_name) + + r"(?: \(entry of " + + re.escape(config.diff_section) + + r"\))? \t" + # object name + + "(\S+)", + contents, + ) + if len(find) > 1: + fail(f"Found multiple occurrences of function {fn_name} in map file.") + if len(find) == 1: + rom = int(find[0][1], 16) + objname = find[0][2] + objfile = search_build_objects(objname, project) + + # TODO Currently the ram-rom conversion only works for diffing ELF + # executables, but it would likely be more convenient to diff DOLs. + # At this time it is recommended to always use -o when running the diff + # script as this mode does not make use of the ram-rom conversion. + if objfile is not None: + return objfile, rom + elif project.map_format == "ms": + load_address_find = re.search( + r"Preferred load address is ([0-9a-f]+)", + contents, + ) + if not load_address_find: + fail(f"Couldn't find module load address in map file.") + load_address = int(load_address_find.group(1), 16) + + diff_segment_find = re.search( + r"([0-9a-f]+):[0-9a-f]+ [0-9a-f]+H " + re.escape(config.diff_section), + contents, + ) + if not diff_segment_find: + fail(f"Couldn't find segment for section in map file.") + diff_segment = diff_segment_find.group(1) + + find = re.findall( + r" (?:" + + re.escape(diff_segment) + + r")\S+\s+(?:" + + re.escape(fn_name) + + r")\s+\S+ ... \S+", + contents, + ) + if len(find) > 1: + fail(f"Found multiple occurrences of function {fn_name} in map file.") + if len(find) == 1: + names_find = re.search(r"(\S+) ... (\S+)", find[0]) + assert names_find is not None + fileofs = ( + int(names_find.group(1), 16) + - load_address + + project.ms_map_address_offset + ) + if for_binary: + return None, fileofs + + objname = names_find.group(2) + objfile = search_build_objects(objname, project) + if objfile is not None: + return objfile, fileofs + else: + fail(f"Linker map format {project.map_format} unrecognised.") + return None, None + + +def parse_elf_rodata_references( + data: bytes, config: Config +) -> List[Tuple[int, int, str]]: + e_ident = data[:16] + if e_ident[:4] != b"\x7FELF": + return [] + + SHT_SYMTAB = 2 + SHT_REL = 9 + SHT_RELA = 4 + R_MIPS_32 = 2 + R_MIPS_GPREL32 = 12 + + is_32bit = e_ident[4] == 1 + is_little_endian = e_ident[5] == 1 + str_end = "<" if is_little_endian else ">" + str_off = "I" if is_32bit else "Q" + + def read(spec: str, offset: int) -> Tuple[int, ...]: + spec = spec.replace("P", str_off) + size = struct.calcsize(spec) + return struct.unpack(str_end + spec, data[offset : offset + size]) + + ( + e_type, + e_machine, + e_version, + e_entry, + e_phoff, + e_shoff, + e_flags, + e_ehsize, + e_phentsize, + e_phnum, + e_shentsize, + e_shnum, + e_shstrndx, + ) = read("HHIPPPIHHHHHH", 16) + if e_type != 1: # relocatable + return [] + assert e_shoff != 0 + assert e_shnum != 0 # don't support > 0xFF00 sections + assert e_shstrndx != 0 + + @dataclass + class Section: + sh_name: int + sh_type: int + sh_flags: int + sh_addr: int + sh_offset: int + sh_size: int + sh_link: int + sh_info: int + sh_addralign: int + sh_entsize: int + + sections = [ + Section(*read("IIPPPPIIPP", e_shoff + i * e_shentsize)) for i in range(e_shnum) + ] + shstr = sections[e_shstrndx] + sec_name_offs = [shstr.sh_offset + s.sh_name for s in sections] + sec_names = [data[offset : data.index(b"\0", offset)] for offset in sec_name_offs] + + symtab_sections = [i for i in range(e_shnum) if sections[i].sh_type == SHT_SYMTAB] + assert len(symtab_sections) == 1 + symtab = sections[symtab_sections[0]] + + section_name = config.diff_section.encode("utf-8") + text_sections = [ + i + for i in range(e_shnum) + if sec_names[i] == section_name and sections[i].sh_size != 0 + ] + if len(text_sections) != 1: + return [] + text_section = text_sections[0] + + ret: List[Tuple[int, int, str]] = [] + for s in sections: + if s.sh_type == SHT_REL or s.sh_type == SHT_RELA: + if s.sh_info == text_section: + # Skip section_name -> section_name references + continue + sec_name = sec_names[s.sh_info].decode("latin1") + if sec_name not in (".rodata", ".late_rodata"): + continue + sec_base = sections[s.sh_info].sh_offset + for i in range(0, s.sh_size, s.sh_entsize): + if s.sh_type == SHT_REL: + r_offset, r_info = read("PP", s.sh_offset + i) + else: + r_offset, r_info, r_addend = read("PPP", s.sh_offset + i) + + if is_32bit: + r_sym = r_info >> 8 + r_type = r_info & 0xFF + sym_offset = symtab.sh_offset + symtab.sh_entsize * r_sym + st_name, st_value, st_size, st_info, st_other, st_shndx = read( + "IIIBBH", sym_offset + ) + else: + r_sym = r_info >> 32 + r_type = r_info & 0xFFFFFFFF + sym_offset = symtab.sh_offset + symtab.sh_entsize * r_sym + st_name, st_info, st_other, st_shndx, st_value, st_size = read( + "IBBHQQ", sym_offset + ) + if st_shndx == text_section: + if s.sh_type == SHT_REL: + if e_machine == 8 and r_type in (R_MIPS_32, R_MIPS_GPREL32): + (r_addend,) = read("I", sec_base + r_offset) + else: + continue + text_offset = (st_value + r_addend) & 0xFFFFFFFF + ret.append((text_offset, r_offset, sec_name)) + return ret + + +def dump_elf( + start: str, + end: Optional[str], + diff_elf_symbol: str, + config: Config, + project: ProjectSettings, +) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: + if not project.baseimg or not project.myimg: + fail("Missing myimg/baseimg in config.") + if config.base_shift: + fail("--base-shift not compatible with -e") + + start_addr = eval_int(start, "Start address must be an integer expression.") + + if end is not None: + end_addr = eval_int(end, "End address must be an integer expression.") + else: + end_addr = start_addr + config.max_function_size_bytes + + flags1 = [ + f"--start-address={start_addr}", + f"--stop-address={end_addr}", + ] + + if project.disassemble_all: + disassemble_flag = "-D" + else: + disassemble_flag = "-d" + + flags2 = [ + f"--disassemble={diff_elf_symbol}", + ] + + objdump_flags = [disassemble_flag, "-rz", "-j", config.diff_section] + return ( + project.myimg, + (objdump_flags + flags1, project.baseimg, None), + ( + objdump_flags + flags2 + maybe_get_objdump_source_flags(config), + project.myimg, + None, + ), + ) + + +def dump_objfile( + start: str, end: Optional[str], config: Config, project: ProjectSettings +) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: + if config.base_shift: + fail("--base-shift not compatible with -o") + if end is not None: + fail("end address not supported together with -o") + if start.startswith("0"): + fail("numerical start address not supported with -o; pass a function name") + + objfile = config.objfile + if not objfile: + objfile, _ = search_map_file(start, project, config, for_binary=False) + + if not objfile: + fail("Not able to find .o file for function.") + + if config.make: + run_make(objfile, project) + + if not os.path.isfile(objfile): + fail(f"Not able to find .o file for function: {objfile} is not a file.") + + refobjfile = os.path.join(project.expected_dir, objfile) + if config.diff_mode != DiffMode.SINGLE and not os.path.isfile(refobjfile): + fail(f'Please ensure an OK .o file exists at "{refobjfile}".') + + if project.disassemble_all: + disassemble_flag = "-D" + else: + disassemble_flag = "-d" + + objdump_flags = [disassemble_flag, "-rz", "-j", config.diff_section] + return ( + objfile, + (objdump_flags, refobjfile, start), + (objdump_flags + maybe_get_objdump_source_flags(config), objfile, start), + ) + + +def dump_binary( + start: str, end: Optional[str], config: Config, project: ProjectSettings +) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: + if not project.baseimg or not project.myimg: + fail("Missing myimg/baseimg in config.") + if config.make: + run_make(project.myimg, project) + start_addr = maybe_eval_int(start) + if start_addr is None: + _, start_addr = search_map_file(start, project, config, for_binary=True) + if start_addr is None: + fail("Not able to find function in map file.") + if end is not None: + end_addr = eval_int(end, "End address must be an integer expression.") + else: + end_addr = start_addr + config.max_function_size_bytes + objdump_flags = ["-Dz", "-bbinary"] + ["-EB" if config.arch.big_endian else "-EL"] + flags1 = [ + f"--start-address={start_addr + config.base_shift}", + f"--stop-address={end_addr + config.base_shift}", + ] + flags2 = [f"--start-address={start_addr}", f"--stop-address={end_addr}"] + return ( + project.myimg, + (objdump_flags + flags1, project.baseimg, None), + (objdump_flags + flags2, project.myimg, None), + ) + + +# Example: "ldr r4, [pc, #56] ; (4c )" +ARM32_LOAD_POOL_PATTERN = r"(ldr\s+r([0-9]|1[0-3]),\s+\[pc,.*;\s*)(\([a-fA-F0-9]+.*\))" + + +# The base class is a no-op. +class AsmProcessor: + def __init__(self, config: Config) -> None: + self.config = config + + def pre_process( + self, mnemonic: str, args: str, next_row: Optional[str] + ) -> Tuple[str, str]: + return mnemonic, args + + def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]: + return prev, None + + def normalize(self, mnemonic: str, row: str) -> str: + """This should be called exactly once for each line.""" + arch = self.config.arch + row = self._normalize_arch_specific(mnemonic, row) + if self.config.ignore_large_imms and mnemonic not in arch.branch_instructions: + row = re.sub(self.config.arch.re_large_imm, "", row) + return row + + def _normalize_arch_specific(self, mnemonic: str, row: str) -> str: + return row + + def post_process(self, lines: List["Line"]) -> None: + return + + def is_end_of_function(self, mnemonic: str, args: str) -> bool: + return False + + +class AsmProcessorMIPS(AsmProcessor): + def __init__(self, config: Config) -> None: + super().__init__(config) + self.seen_jr_ra = False + + def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]: + arch = self.config.arch + if "R_MIPS_NONE" in row or "R_MIPS_JALR" in row: + # GNU as emits no-op relocations immediately after real ones when + # assembling with -mabi=64. Return without trying to parse 'imm' as an + # integer. + return prev, None + before, imm, after = parse_relocated_line(prev) + repl = row.split()[-1] + reloc_addend_from_imm(imm, before, self.config.arch) + if "R_MIPS_LO16" in row: + repl = f"%lo({repl})" + elif "R_MIPS_HI16" in row: + # Ideally we'd pair up R_MIPS_LO16 and R_MIPS_HI16 to generate a + # correct addend for each, but objdump doesn't give us the order of + # the relocations, so we can't find the right LO16. :( + repl = f"%hi({repl})" + elif "R_MIPS_26" in row: + # Function calls + pass + elif "R_MIPS_PC16" in row: + # Branch to glabel. This gives confusing output, but there's not much + # we can do here. + pass + elif "R_MIPS_GPREL16" in row: + repl = f"%gp_rel({repl})" + elif "R_MIPS_GOT16" in row: + repl = f"%got({repl})" + elif "R_MIPS_CALL16" in row: + repl = f"%call16({repl})" + else: + assert False, f"unknown relocation type '{row}' for line '{prev}'" + return before + repl + after, repl + + def is_end_of_function(self, mnemonic: str, args: str) -> bool: + if self.seen_jr_ra: + return True + if mnemonic == "jr" and args == "ra": + self.seen_jr_ra = True + return False + + +class AsmProcessorPPC(AsmProcessor): + def pre_process( + self, mnemonic: str, args: str, next_row: Optional[str] + ) -> Tuple[str, str]: + + if next_row and "R_PPC_EMB_SDA21" in next_row: + # With sda21 relocs, the linker transforms `r0` into `r2`/`r13`, and + # we may encounter this in either pre-transformed or post-transformed + # versions depending on if the .o file comes from compiler output or + # from disassembly. Normalize, to make sure both forms are treated as + # equivalent. + + args = args.replace("(r2)", "(0)") + args = args.replace("(r13)", "(0)") + args = args.replace(",r2,", ",0,") + args = args.replace(",r13,", ",0,") + + # We want to convert li and lis with an sda21 reloc, + # because the r0 to r2/r13 transformation results in + # turning an li/lis into an addi/addis with r2/r13 arg + # our preprocessing normalizes all versions to addi with a 0 arg + if mnemonic in {"li", "lis"}: + mnemonic = mnemonic.replace("li", "addi") + args_parts = args.split(",") + args = args_parts[0] + ",0," + args_parts[1] + + return mnemonic, args + + def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]: + arch = self.config.arch + assert any( + r in row + for r in ["R_PPC_REL24", "R_PPC_ADDR16", "R_PPC_EMB_SDA21", "R_PPC_REL14"] + ), f"unknown relocation type '{row}' for line '{prev}'" + before, imm, after = parse_relocated_line(prev) + repl = row.split()[-1] + if "R_PPC_REL24" in row: + # function calls + pass + if "R_PPC_REL14" in row: + pass + elif "R_PPC_ADDR16_HI" in row: + # absolute hi of addr + repl = f"{repl}@h" + elif "R_PPC_ADDR16_HA" in row: + # adjusted hi of addr + repl = f"{repl}@ha" + elif "R_PPC_ADDR16_LO" in row: + # lo of addr + repl = f"{repl}@l" + elif "R_PPC_ADDR16" in row: + # 16-bit absolute addr + if "+0x7" in repl: + # remove the very large addends as they are an artifact of (label-_SDA(2)_BASE_) + # computations and are unimportant in a diff setting. + if int(repl.split("+")[1], 16) > 0x70000000: + repl = repl.split("+")[0] + elif "R_PPC_EMB_SDA21" in row: + # sda21 relocations; r2/r13 --> 0 swaps are performed in pre_process + repl = f"{repl}@sda21" + + return before + repl + after, repl + + def is_end_of_function(self, mnemonic: str, args: str) -> bool: + return mnemonic == "blr" + + +class AsmProcessorARM32(AsmProcessor): + def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]: + arch = self.config.arch + if "R_ARM_V4BX" in row: + # R_ARM_V4BX converts "bx " to "mov pc," for some targets. + # Ignore for now. + return prev, None + if "R_ARM_ABS32" in row and not prev.startswith(".word"): + # Don't crash on R_ARM_ABS32 relocations incorrectly applied to code. + # (We may want to do something more fancy here that actually shows the + # related symbol, but this serves as a stop-gap.) + return prev, None + before, imm, after = parse_relocated_line(prev) + repl = row.split()[-1] + reloc_addend_from_imm(imm, before, self.config.arch) + return before + repl + after, repl + + def _normalize_arch_specific(self, mnemonic: str, row: str) -> str: + if self.config.ignore_addr_diffs: + row = self._normalize_bl(mnemonic, row) + row = self._normalize_data_pool(row) + return row + + def _normalize_bl(self, mnemonic: str, row: str) -> str: + if mnemonic != "bl": + return row + + row, _ = split_off_address(row) + return row + "" + + def _normalize_data_pool(self, row: str) -> str: + pool_match = re.search(ARM32_LOAD_POOL_PATTERN, row) + return pool_match.group(1) if pool_match else row + + def post_process(self, lines: List["Line"]) -> None: + lines_by_line_number = {} + for line in lines: + lines_by_line_number[line.line_num] = line + for line in lines: + if line.data_pool_addr is None: + continue + + # Add data symbol and its address to the line. + line_original = lines_by_line_number[line.data_pool_addr].original + value = line_original.split()[1] + addr = "{:x}".format(line.data_pool_addr) + line.original = line.normalized_original + f"={value} ({addr})" + + +class AsmProcessorAArch64(AsmProcessor): + def __init__(self, config: Config) -> None: + super().__init__(config) + self._adrp_pair_registers: Set[str] = set() + + def _normalize_arch_specific(self, mnemonic: str, row: str) -> str: + if self.config.ignore_addr_diffs: + row = self._normalize_adrp_differences(mnemonic, row) + row = self._normalize_bl(mnemonic, row) + return row + + def _normalize_bl(self, mnemonic: str, row: str) -> str: + if mnemonic != "bl": + return row + + row, _ = split_off_address(row) + return row + "" + + def _normalize_adrp_differences(self, mnemonic: str, row: str) -> str: + """Identifies ADRP + LDR/ADD pairs that are used to access the GOT and + suppresses any immediate differences. + + Whenever an ADRP is seen, the destination register is added to the set of registers + that are part of an ADRP + LDR/ADD pair. Registers are removed from the set as soon + as they are used for an LDR or ADD instruction which completes the pair. + + This method is somewhat crude but should manage to detect most such pairs. + """ + row_parts = row.split("\t", 1) + if mnemonic == "adrp": + self._adrp_pair_registers.add(row_parts[1].strip().split(",")[0]) + row, _ = split_off_address(row) + return row + "" + elif mnemonic == "ldr": + for reg in self._adrp_pair_registers: + # ldr xxx, [reg] + # ldr xxx, [reg, ] + if f", [{reg}" in row_parts[1]: + self._adrp_pair_registers.remove(reg) + return normalize_imms(row, AARCH64_SETTINGS) + elif mnemonic == "add": + for reg in self._adrp_pair_registers: + # add reg, reg, + if row_parts[1].startswith(f"{reg}, {reg}, "): + self._adrp_pair_registers.remove(reg) + return normalize_imms(row, AARCH64_SETTINGS) + + return row + + +class AsmProcessorI686(AsmProcessor): + def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]: + repl = row.split()[-1] + mnemonic, args = prev.split(maxsplit=1) + + addr_imm = re.search(r"(? bool: + return mnemonic == "ret" + + +@dataclass +class ArchSettings: + name: str + re_int: Pattern[str] + re_comment: Pattern[str] + re_reg: Pattern[str] + re_sprel: Pattern[str] + re_large_imm: Pattern[str] + re_imm: Pattern[str] + re_reloc: Pattern[str] + branch_instructions: Set[str] + instructions_with_address_immediates: Set[str] + forbidden: Set[str] = field(default_factory=lambda: set(string.ascii_letters + "_")) + arch_flags: List[str] = field(default_factory=list) + branch_likely_instructions: Set[str] = field(default_factory=set) + proc: Type[AsmProcessor] = AsmProcessor + big_endian: Optional[bool] = True + delay_slot_instructions: Set[str] = field(default_factory=set) + + +MIPS_BRANCH_LIKELY_INSTRUCTIONS = { + "beql", + "bnel", + "beqzl", + "bnezl", + "bgezl", + "bgtzl", + "blezl", + "bltzl", + "bc1tl", + "bc1fl", +} +MIPS_BRANCH_INSTRUCTIONS = MIPS_BRANCH_LIKELY_INSTRUCTIONS.union( + { + "b", + "beq", + "bne", + "beqz", + "bnez", + "bgez", + "bgtz", + "blez", + "bltz", + "bc1t", + "bc1f", + } +) + +ARM32_PREFIXES = {"b", "bl"} +ARM32_CONDS = { + "", + "eq", + "ne", + "cs", + "cc", + "mi", + "pl", + "vs", + "vc", + "hi", + "ls", + "ge", + "lt", + "gt", + "le", + "al", +} +ARM32_SUFFIXES = {"", ".n", ".w"} +ARM32_BRANCH_INSTRUCTIONS = { + f"{prefix}{cond}{suffix}" + for prefix in ARM32_PREFIXES + for cond in ARM32_CONDS + for suffix in ARM32_SUFFIXES +} + +AARCH64_BRANCH_INSTRUCTIONS = { + "b", + "b.eq", + "b.ne", + "b.cs", + "b.hs", + "b.cc", + "b.lo", + "b.mi", + "b.pl", + "b.vs", + "b.vc", + "b.hi", + "b.ls", + "b.ge", + "b.lt", + "b.gt", + "b.le", + "cbz", + "cbnz", + "tbz", + "tbnz", +} + +PPC_BRANCH_INSTRUCTIONS = { + "b", + "beq", + "beq+", + "beq-", + "bne", + "bne+", + "bne-", + "blt", + "blt+", + "blt-", + "ble", + "ble+", + "ble-", + "bdnz", + "bdnz+", + "bdnz-", + "bge", + "bge+", + "bge-", + "bgt", + "bgt+", + "bgt-", +} + +I686_BRANCH_INSTRUCTIONS = { + "call", + "jmp", + "ljmp", + "ja", + "jae", + "jb", + "jbe", + "jc", + "jcxz", + "jecxz", + "jrcxz", + "je", + "jg", + "jge", + "jl", + "jle", + "jna", + "jnae", + "jnb", + "jnbe", + "jnc", + "jne", + "jng", + "jnge", + "jnl", + "jnle", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "jpe", + "jpo", + "js", + "jz", + "ja", + "jae", + "jb", + "jbe", + "jc", + "je", + "jz", + "jg", + "jge", + "jl", + "jle", + "jna", + "jnae", + "jnb", + "jnbe", + "jnc", + "jne", + "jng", + "jnge", + "jnl", + "jnle", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "jpe", + "jpo", + "js", + "jz", +} + +MIPS_SETTINGS = ArchSettings( + name="mips", + re_int=re.compile(r"[0-9]+"), + re_comment=re.compile(r"<.*>"), + # Includes: + # - General purpose registers v0..1, a0..7, t0..9, s0..8, zero, at, fp, k0..1/kt0..1 + # - Float registers f0..31, or fv0..1, fa0..7, ft0..15, fs0..8 plus odd complements + # (actually used number depends on ABI) + # sp, gp should not be in this list + re_reg=re.compile(r"\$?\b([astv][0-9]|at|f[astv]?[0-9]+f?|kt?[01]|fp|ra|zero)\b"), + re_sprel=re.compile(r"(?<=,)([0-9]+|0x[0-9a-f]+)\(sp\)"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile( + r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(sp)|%(lo|hi|got|gp_rel|call16)\([^)]*\)" + ), + re_reloc=re.compile(r"R_MIPS_"), + arch_flags=["-m", "mips:4300"], + branch_likely_instructions=MIPS_BRANCH_LIKELY_INSTRUCTIONS, + branch_instructions=MIPS_BRANCH_INSTRUCTIONS, + instructions_with_address_immediates=MIPS_BRANCH_INSTRUCTIONS.union({"j", "jal"}), + delay_slot_instructions=MIPS_BRANCH_INSTRUCTIONS.union({"j", "jal", "jr", "jalr"}), + proc=AsmProcessorMIPS, +) + +MIPSEL_SETTINGS = replace(MIPS_SETTINGS, name="mipsel", big_endian=False) + +MIPSEE_SETTINGS = replace( + MIPSEL_SETTINGS, name="mipsee", arch_flags=["-m", "mips:5900"] +) + +MIPS_ARCH_NAMES = {"mips", "mipsel", "mipsee"} + +ARM32_SETTINGS = ArchSettings( + name="arm32", + re_int=re.compile(r"[0-9]+"), + re_comment=re.compile(r"(<.*>|//.*$)"), + # Includes: + # - General purpose registers: r0..13 + # - Frame pointer registers: lr (r14), pc (r15) + # - VFP/NEON registers: s0..31, d0..31, q0..15, fpscr, fpexc, fpsid + # SP should not be in this list. + re_reg=re.compile( + r"\$?\b([rq][0-9]|[rq]1[0-5]|pc|lr|[ds][12]?[0-9]|[ds]3[01]|fp(scr|exc|sid))\b" + ), + re_sprel=re.compile(r"sp, #-?(0x[0-9a-fA-F]+|[0-9]+)\b"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile(r"(?|//.*$)"), + # GPRs and FP registers: X0-X30, W0-W30, [BHSDVQ]0..31 + # (FP registers may be followed by data width and number of elements, e.g. V0.4S) + # The zero registers and SP should not be in this list. + re_reg=re.compile( + r"\$?\b([bhsdvq]([12]?[0-9]|3[01])(\.\d\d?[bhsdvq])?|[xw][12]?[0-9]|[xw]30)\b" + ), + re_sprel=re.compile(r"sp, #-?(0x[0-9a-fA-F]+|[0-9]+)\b"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile(r"(?|//.*$)"), + # r1 not included + re_reg=re.compile(r"\$?\b([rf](?:[02-9]|[1-9][0-9]+)|f1)\b"), + re_sprel=re.compile(r"(?<=,)(-?[0-9]+|-?0x[0-9a-f]+)\(r1\)"), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_imm=re.compile( + r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(r1)|[^ \t,]+@(l|ha|h|sda21)" + ), + re_reloc=re.compile(r"R_PPC_"), + arch_flags=["-m", "powerpc", "-M", "broadway"], + branch_instructions=PPC_BRANCH_INSTRUCTIONS, + instructions_with_address_immediates=PPC_BRANCH_INSTRUCTIONS.union({"bl"}), + proc=AsmProcessorPPC, +) + +I686_SETTINGS = ArchSettings( + name="i686", + re_int=re.compile(r"[0-9]+"), + re_comment=re.compile(r"<.*>"), + # Includes: + # - (e)a-d(x,l,h) + # - (e)s,d,b(i,p)(l) + # - cr0-7 + # - x87 st + # - MMX, SSE vector registers + # - cursed registers: eal ebl ebh edl edh... + re_reg=re.compile( + r"\%?\b(e?(([sd]i|[sb]p)l?|[abcd][xhl])|[cdesfg]s|cr[0-7]|x?mm[0-7]|st)\b" + ), + re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"), + re_sprel=re.compile(r"-?(0x[0-9a-f]+|[0-9]+)(?=\((%ebp|%esi)\))"), + re_imm=re.compile(r"-?(0x[0-9a-f]+|[0-9]+)"), + re_reloc=re.compile(r"R_386_"), + # The x86 architecture has a variable instruction length. The raw bytes of + # an instruction as displayed by objdump can line wrap if it's long enough. + # This destroys the objdump output processor logic, so we avoid this. + arch_flags=["-m", "i386", "--no-show-raw-insn"], + branch_instructions=I686_BRANCH_INSTRUCTIONS, + instructions_with_address_immediates=I686_BRANCH_INSTRUCTIONS.union({"mov"}), + proc=AsmProcessorI686, +) + +ARCH_SETTINGS = [ + MIPS_SETTINGS, + MIPSEL_SETTINGS, + MIPSEE_SETTINGS, + ARM32_SETTINGS, + ARMEL_SETTINGS, + AARCH64_SETTINGS, + PPC_SETTINGS, + I686_SETTINGS, +] + + +def hexify_int(row: str, pat: Match[str], arch: ArchSettings) -> str: + full = pat.group(0) + if len(full) <= 1: + # leave one-digit ints alone + return full + start, end = pat.span() + if start and row[start - 1] in arch.forbidden: + return full + if end < len(row) and row[end] in arch.forbidden: + return full + return hex(int(full)) + + +def parse_relocated_line(line: str) -> Tuple[str, str, str]: + # Pick out the last argument + for c in ",\t ": + if c in line: + ind2 = line.rindex(c) + break + else: + raise Exception(f"failed to parse relocated line: {line}") + before = line[: ind2 + 1] + after = line[ind2 + 1 :] + # Move an optional ($reg) part of it to 'after' + ind2 = after.find("(") + if ind2 == -1: + imm, after = after, "" + else: + imm, after = after[:ind2], after[ind2:] + return before, imm, after + + +def reloc_addend_from_imm(imm: str, before: str, arch: ArchSettings) -> str: + """For architectures like MIPS where relocations have addends embedded in + the code as immediates, convert such an immediate into an addition/ + subtraction that can occur just after the symbol.""" + # TODO this is incorrect for MIPS %lo/%hi which need to be paired up + # and combined. In practice, this means we only get symbol offsets within + # %lo, while %hi just shows the symbol. Unfortunately, objdump's output + # loses relocation order, so we cannot do this without parsing ELF relocs + # ourselves... + mnemonic = before.split()[0] + if mnemonic in arch.instructions_with_address_immediates: + addend = int(imm, 16) + else: + addend = int(imm, 0) + if addend == 0: + return "" + elif addend < 0: + return hex(addend) + else: + return "+" + hex(addend) + + +def pad_mnemonic(line: str) -> str: + if "\t" not in line: + return line + mn, args = line.split("\t", 1) + return f"{mn:<7s} {args}" + + +@dataclass +class Line: + mnemonic: str + diff_row: str + original: str + normalized_original: str + scorable_line: str + symbol: Optional[str] = None + line_num: Optional[int] = None + branch_target: Optional[int] = None + data_pool_addr: Optional[int] = None + source_filename: Optional[str] = None + source_line_num: Optional[int] = None + source_lines: List[str] = field(default_factory=list) + comment: Optional[str] = None + + +def process(dump: str, config: Config) -> List[Line]: + arch = config.arch + processor = arch.proc(config) + source_lines = [] + source_filename = None + source_line_num = None + + i = 0 + num_instr = 0 + data_refs: Dict[int, Dict[str, List[int]]] = defaultdict(lambda: defaultdict(list)) + output: List[Line] = [] + lines = dump.split("\n") + while i < len(lines): + row = lines[i] + i += 1 + + if not row: + continue + + if re.match(r"^[0-9a-f]+ <.*>:$", row): + continue + + if row.startswith("DATAREF"): + parts = row.split(" ", 3) + text_offset = int(parts[1]) + from_offset = int(parts[2]) + from_section = parts[3] + data_refs[text_offset][from_section].append(from_offset) + continue + + if config.diff_obj and num_instr >= config.max_function_size_lines: + output.append( + Line( + mnemonic="...", + diff_row="...", + original="...", + normalized_original="...", + scorable_line="...", + ) + ) + break + + if not re.match(r"^\s+[0-9a-f]+:\s+", row): + # This regex is conservative, and assumes the file path does not contain "weird" + # characters like tabs or angle brackets. + if re.match(r"^[^ \t<>][^\t<>]*:[0-9]+( \(discriminator [0-9]+\))?$", row): + source_filename, _, tail = row.rpartition(":") + source_line_num = int(tail.partition(" ")[0]) + source_lines.append(row) + continue + + # If the instructions loads a data pool symbol, extract the address of + # the symbol. + data_pool_addr = None + pool_match = re.search(ARM32_LOAD_POOL_PATTERN, row) + if pool_match: + offset = pool_match.group(3).split(" ")[0][1:] + data_pool_addr = int(offset, 16) + + m_comment = re.search(arch.re_comment, row) + comment = m_comment[0] if m_comment else None + row = re.sub(arch.re_comment, "", row) + line_num_str = row.split(":")[0] + row = row.rstrip() + tabs = row.split("\t") + line_num = eval_line_num(line_num_str.strip()) + + # TODO: use --no-show-raw-insn for all arches + if arch.name == "i686": + row = "\t".join(tabs[1:]) + else: + row = "\t".join(tabs[2:]) + + if line_num in data_refs: + refs = data_refs[line_num] + ref_str = "; ".join( + section_name + "+" + ",".join(hex(off) for off in offs) + for section_name, offs in refs.items() + ) + output.append( + Line( + mnemonic="", + diff_row="", + original=ref_str, + normalized_original=ref_str, + scorable_line="", + ) + ) + + if "\t" in row: + row_parts = row.split("\t", 1) + else: + # powerpc-eabi-objdump doesn't use tabs + row_parts = [part.lstrip() for part in row.split(" ", 1)] + + mnemonic = row_parts[0].strip() + args = row_parts[1].strip() if len(row_parts) >= 2 else "" + + next_line = lines[i] if i < len(lines) else None + mnemonic, args = processor.pre_process(mnemonic, args, next_line) + row = mnemonic + "\t" + args.replace("\t", " ") + + addr = "" + if mnemonic in arch.instructions_with_address_immediates: + row, addr = split_off_address(row) + # objdump prefixes addresses with 0x/-0x if they don't resolve to some + # symbol + offset. Strip that. + addr = addr.replace("0x", "") + + row = re.sub(arch.re_int, lambda m: hexify_int(row, m, arch), row) + row += addr + + # Let 'original' be 'row' with relocations applied, while we continue + # transforming 'row' into a coarser version that ignores registers and + # immediates. + original = row + + symbol = None + while i < len(lines): + reloc_row = lines[i] + if re.search(arch.re_reloc, reloc_row): + original, reloc_symbol = processor.process_reloc(reloc_row, original) + if reloc_symbol is not None: + symbol = reloc_symbol + else: + break + i += 1 + + is_text_relative_j = False + if ( + arch.name in MIPS_ARCH_NAMES + and mnemonic == "j" + and symbol is not None + and symbol.startswith(".text") + ): + symbol = None + original = row + is_text_relative_j = True + + normalized_original = processor.normalize(mnemonic, original) + + scorable_line = normalized_original + if not config.score_stack_differences: + scorable_line = re.sub(arch.re_sprel, "addr(sp)", scorable_line) + + row = re.sub(arch.re_reg, "", row) + row = re.sub(arch.re_sprel, "addr(sp)", row) + if mnemonic in arch.instructions_with_address_immediates: + row = row.strip() + row, _ = split_off_address(row) + row += "" + else: + row = normalize_imms(row, arch) + + branch_target = None + if ( + mnemonic in arch.branch_instructions or is_text_relative_j + ) and symbol is None: + x86_longjmp = re.search(r"\*(.*)\(", args) + if x86_longjmp: + capture = x86_longjmp.group(1) + if capture != "": + branch_target = int(capture, 16) + else: + branch_target = int(args.split(",")[-1], 16) + + output.append( + Line( + mnemonic=mnemonic, + diff_row=row, + original=original, + normalized_original=normalized_original, + scorable_line=scorable_line, + symbol=symbol, + line_num=line_num, + branch_target=branch_target, + data_pool_addr=data_pool_addr, + source_filename=source_filename, + source_line_num=source_line_num, + source_lines=source_lines, + comment=comment, + ) + ) + num_instr += 1 + source_lines = [] + + if config.stop_at_ret and processor.is_end_of_function(mnemonic, args): + break + + processor.post_process(output) + return output + + +def normalize_imms(row: str, arch: ArchSettings) -> str: + return re.sub(arch.re_imm, "", row) + + +def normalize_stack(row: str, arch: ArchSettings) -> str: + return re.sub(arch.re_sprel, "addr(sp)", row) + + +def check_for_symbol_mismatch( + old_line: Line, new_line: Line, symbol_map: Dict[str, str] +) -> bool: + + assert old_line.symbol is not None + assert new_line.symbol is not None + + if new_line.symbol.startswith("%hi"): + return False + + if old_line.symbol not in symbol_map: + symbol_map[old_line.symbol] = new_line.symbol + return False + elif symbol_map[old_line.symbol] == new_line.symbol: + return False + + return True + + +def field_matches_any_symbol(field: str, arch: ArchSettings) -> bool: + if arch.name == "ppc": + if "..." in field: + return True + + parts = field.rsplit("@", 1) + if len(parts) == 2 and parts[1] in {"l", "h", "ha", "sda21"}: + field = parts[0] + + return re.fullmatch((r"^@\d+$"), field) is not None + + if arch.name in MIPS_ARCH_NAMES: + return "." in field + + # Example: ".text+0x34" + if arch.name == "arm32": + return "." in field + + return False + + +def split_off_address(line: str) -> Tuple[str, str]: + """Split e.g. 'beqz $r0,1f0' into 'beqz $r0,' and '1f0'.""" + parts = line.split(",") + if len(parts) < 2: + parts = line.split(None, 1) + if len(parts) < 2: + parts.append("") + off = len(line) - len(parts[-1].strip()) + return line[:off], line[off:] + + +def diff_sequences_difflib( + seq1: List[str], seq2: List[str] +) -> List[Tuple[str, int, int, int, int]]: + differ = difflib.SequenceMatcher(a=seq1, b=seq2, autojunk=False) + return differ.get_opcodes() + + +def diff_sequences( + seq1: List[str], seq2: List[str], algorithm: str +) -> List[Tuple[str, int, int, int, int]]: + if algorithm != "levenshtein": + return diff_sequences_difflib(seq1, seq2) + + # The Levenshtein library assumes that we compare strings, not lists. Convert. + remapping: Dict[str, str] = {} + + def remap(seq: List[str]) -> str: + seq = seq[:] + for i in range(len(seq)): + val = remapping.get(seq[i]) + if val is None: + val = chr(len(remapping)) + remapping[seq[i]] = val + seq[i] = val + return "".join(seq) + + try: + rem1 = remap(seq1) + rem2 = remap(seq2) + except ValueError as e: + if len(seq1) + len(seq2) < 0x110000: + raise + # If there are too many unique elements, chr() doesn't work. + # Assume this is the case and fall back to difflib. + return diff_sequences_difflib(seq1, seq2) + + import Levenshtein + + ret: List[Tuple[str, int, int, int, int]] = Levenshtein.opcodes(rem1, rem2) + return ret + + +def diff_lines( + lines1: List[Line], + lines2: List[Line], + algorithm: str, +) -> List[Tuple[Optional[Line], Optional[Line]]]: + ret = [] + for (tag, i1, i2, j1, j2) in diff_sequences( + [line.mnemonic for line in lines1], + [line.mnemonic for line in lines2], + algorithm, + ): + for line1, line2 in itertools.zip_longest(lines1[i1:i2], lines2[j1:j2]): + if tag == "replace": + if line1 is None: + tag = "insert" + elif line2 is None: + tag = "delete" + elif tag == "insert": + assert line1 is None + elif tag == "delete": + assert line2 is None + ret.append((line1, line2)) + + return ret + + +def diff_sameline( + old_line: Line, new_line: Line, config: Config, symbol_map: Dict[str, str] +) -> Tuple[int, int, bool]: + + old = old_line.scorable_line + new = new_line.scorable_line + if old == new: + return (0, 0, False) + + num_stack_penalties = 0 + num_regalloc_penalties = 0 + has_symbol_mismatch = False + + ignore_last_field = False + if config.score_stack_differences: + oldsp = re.search(config.arch.re_sprel, old) + newsp = re.search(config.arch.re_sprel, new) + if oldsp and newsp: + oldrel = int(oldsp.group(1) or "0", 0) + newrel = int(newsp.group(1) or "0", 0) + num_stack_penalties += abs(oldrel - newrel) + ignore_last_field = True + + # Probably regalloc difference, or signed vs unsigned + + # Compare each field in order + new_parts, old_parts = new.split(None, 1), old.split(None, 1) + newfields, oldfields = new_parts[1].split(","), old_parts[1].split(",") + if ignore_last_field: + newfields = newfields[:-1] + oldfields = oldfields[:-1] + else: + # If the last field has a parenthesis suffix, e.g. "0x38(r7)" + # we split that part out to make it a separate field + # however, we don't split if it has a proceeding % macro, e.g. "%lo(.data)" + re_paren = re.compile(r"(? int: + # This logic is copied from `scorer.py` from the decomp permuter project + # https://github.com/simonlindholm/decomp-permuter/blob/main/src/scorer.py + num_stack_penalties = 0 + num_regalloc_penalties = 0 + num_reordering_penalties = 0 + num_insertion_penalties = 0 + num_deletion_penalties = 0 + deletions = [] + insertions = [] + + def diff_insert(line: str) -> None: + # Reordering or totally different codegen. + # Defer this until later when we can tell. + insertions.append(line) + + def diff_delete(line: str) -> None: + deletions.append(line) + + # Find the end of the last long streak of matching mnemonics, if it looks + # like the objdump output was truncated. This is used to skip scoring + # misaligned lines at the end of the diff. + last_mismatch = -1 + max_index = None + lines_were_truncated = False + for index, (line1, line2) in enumerate(lines): + if (line1 and line1.original == "...") or (line2 and line2.original == "..."): + lines_were_truncated = True + if line1 and line2 and line1.mnemonic == line2.mnemonic: + if index - last_mismatch >= 50: + max_index = index + else: + last_mismatch = index + if not lines_were_truncated: + max_index = None + + for index, (line1, line2) in enumerate(lines): + if max_index is not None and index > max_index: + break + if line1 and line2 and line1.mnemonic == line2.mnemonic: + sp, rp, _ = diff_sameline(line1, line2, config, symbol_map) + num_stack_penalties += sp + num_regalloc_penalties += rp + else: + if line1: + diff_delete(line1.scorable_line) + if line2: + diff_insert(line2.scorable_line) + + insertions_co = Counter(insertions) + deletions_co = Counter(deletions) + for item in insertions_co + deletions_co: + ins = insertions_co[item] + dels = deletions_co[item] + common = min(ins, dels) + num_insertion_penalties += ins - common + num_deletion_penalties += dels - common + num_reordering_penalties += common + + return ( + num_stack_penalties * config.penalty_stackdiff + + num_regalloc_penalties * config.penalty_regalloc + + num_reordering_penalties * config.penalty_reordering + + num_insertion_penalties * config.penalty_insertion + + num_deletion_penalties * config.penalty_deletion + ) + + +@dataclass(frozen=True) +class OutputLine: + base: Optional[Text] = field(compare=False) + fmt2: Text = field(compare=False) + key2: Optional[str] + boring: bool = field(compare=False) + is_data_ref: bool = field(compare=False) + line1: Optional[Line] = field(compare=False) + line2: Optional[Line] = field(compare=False) + + +@dataclass(frozen=True) +class Diff: + lines: List[OutputLine] + score: int + max_score: int + + +def trim_nops(lines: List[Line], arch: ArchSettings) -> List[Line]: + lines = lines[:] + while ( + lines + and lines[-1].mnemonic == "nop" + and (len(lines) == 1 or lines[-2].mnemonic not in arch.delay_slot_instructions) + ): + lines.pop() + return lines + + +def do_diff(lines1: List[Line], lines2: List[Line], config: Config) -> Diff: + if config.show_source: + import cxxfilt + arch = config.arch + fmt = config.formatter + output: List[OutputLine] = [] + symbol_map: Dict[str, str] = {} + + sc1 = symbol_formatter("base-reg", 0) + sc2 = symbol_formatter("my-reg", 0) + sc3 = symbol_formatter("base-stack", 4) + sc4 = symbol_formatter("my-stack", 4) + sc5 = symbol_formatter("base-branch", 0) + sc6 = symbol_formatter("my-branch", 0) + bts1: Set[int] = set() + bts2: Set[int] = set() + + if config.show_branches: + for (lines, btset, sc) in [ + (lines1, bts1, sc5), + (lines2, bts2, sc6), + ]: + for line in lines: + bt = line.branch_target + if bt is not None: + btset.add(bt) + sc(str(bt)) + + lines1 = trim_nops(lines1, arch) + lines2 = trim_nops(lines2, arch) + + diffed_lines = diff_lines(lines1, lines2, config.algorithm) + + line_num_base = -1 + line_num_offset = 0 + line_num_2to1 = {} + for (line1, line2) in diffed_lines: + if line1 is not None and line1.line_num is not None: + line_num_base = line1.line_num + line_num_offset = 0 + else: + line_num_offset += 1 + if line2 is not None and line2.line_num is not None: + line_num_2to1[line2.line_num] = (line_num_base, line_num_offset) + + for (line1, line2) in diffed_lines: + line_color1 = line_color2 = sym_color = BasicFormat.NONE + line_prefix = " " + is_data_ref = False + out1 = Text() if not line1 else Text(pad_mnemonic(line1.original)) + out2 = Text() if not line2 else Text(pad_mnemonic(line2.original)) + if line1 and line2 and line1.diff_row == line2.diff_row: + if line1.diff_row == "": + if line1.normalized_original != line2.normalized_original: + line_prefix = "i" + sym_color = BasicFormat.DIFF_CHANGE + out1 = out1.reformat(sym_color) + out2 = out2.reformat(sym_color) + is_data_ref = True + elif ( + line1.normalized_original == line2.normalized_original + and line2.branch_target is None + ): + # Fast path: no coloring needed. We don't include branch instructions + # in this case because we need to check that their targets line up in + # the diff, and don't just happen to have the are the same address + # by accident. + pass + else: + mnemonic = line1.original.split()[0] + branchless1, address1 = out1.plain(), "" + branchless2, address2 = out2.plain(), "" + if mnemonic in arch.instructions_with_address_immediates: + branchless1, address1 = split_off_address(branchless1) + branchless2, address2 = split_off_address(branchless2) + + out1 = Text(branchless1) + out2 = Text(branchless2) + out1, out2 = format_fields( + arch.re_imm, out1, out2, lambda _: BasicFormat.IMMEDIATE + ) + + if line2.branch_target is not None: + target = line2.branch_target + line2_target = line_num_2to1.get(line2.branch_target) + if line2_target is None: + # If the target is outside the disassembly, extrapolate. + # This only matters near the bottom. + assert line2.line_num is not None + line2_line = line_num_2to1[line2.line_num] + line2_target = (line2_line[0] + (target - line2.line_num), 0) + + # Adjust the branch target for scoring and three-way diffing. + norm2, norm_branch2 = split_off_address(line2.normalized_original) + if norm_branch2 != "": + retargetted = hex(line2_target[0]).replace("0x", "") + if line2_target[1] != 0: + retargetted += f"+{line2_target[1]}" + line2.normalized_original = norm2 + retargetted + sc_base, _ = split_off_address(line2.scorable_line) + line2.scorable_line = sc_base + retargetted + same_target = line2_target == (line1.branch_target, 0) + else: + # Do a naive comparison for non-branches (e.g. function calls). + same_target = address1 == address2 + + if normalize_imms(branchless1, arch) == normalize_imms( + branchless2, arch + ): + ( + stack_penalties, + regalloc_penalties, + has_symbol_mismatch, + ) = diff_sameline(line1, line2, config, symbol_map) + + if ( + regalloc_penalties == 0 + and stack_penalties == 0 + and not has_symbol_mismatch + ): + # ignore differences due to %lo(.rodata + ...) vs symbol + out1 = out1.reformat(BasicFormat.NONE) + out2 = out2.reformat(BasicFormat.NONE) + elif line2.branch_target is not None and same_target: + # same-target branch, don't color + pass + else: + # must have an imm difference (or else we would have hit the + # fast path) + sym_color = BasicFormat.IMMEDIATE + line_prefix = "i" + else: + out1, out2 = format_fields(arch.re_sprel, out1, out2, sc3, sc4) + if normalize_stack(branchless1, arch) == normalize_stack( + branchless2, arch + ): + # only stack differences (luckily stack and imm + # differences can't be combined in MIPS, so we + # don't have to think about that case) + sym_color = BasicFormat.STACK + line_prefix = "s" + else: + # reg differences and maybe imm as well + out1, out2 = format_fields(arch.re_reg, out1, out2, sc1, sc2) + cats = config.reg_categories + if cats and any( + cats.get(of.group()) != cats.get(nf.group()) + for (of, nf) in zip( + out1.finditer(arch.re_reg), out2.finditer(arch.re_reg) + ) + ): + sym_color = BasicFormat.REGISTER_CATEGORY + line_prefix = "R" + else: + sym_color = BasicFormat.REGISTER + line_prefix = "r" + line_color1 = line_color2 = sym_color + + if same_target: + address_imm_fmt = BasicFormat.NONE + else: + address_imm_fmt = BasicFormat.IMMEDIATE + out1 += Text(address1, address_imm_fmt) + out2 += Text(address2, address_imm_fmt) + elif line1 and line2: + line_prefix = "|" + line_color1 = line_color2 = sym_color = BasicFormat.DIFF_CHANGE + out1 = out1.reformat(line_color1) + out2 = out2.reformat(line_color2) + elif line1: + line_prefix = "<" + line_color1 = sym_color = BasicFormat.DIFF_REMOVE + out1 = out1.reformat(line_color1) + out2 = Text() + elif line2: + line_prefix = ">" + line_color2 = sym_color = BasicFormat.DIFF_ADD + out1 = Text() + out2 = out2.reformat(line_color2) + + if config.show_source and line2 and line2.comment: + out2 += f" {line2.comment}" + + def format_part( + out: Text, + line: Optional[Line], + line_color: Format, + btset: Set[int], + sc: FormatFunction, + ) -> Optional[Text]: + if line is None: + return None + if line.line_num is None: + return out + in_arrow = Text(" ") + out_arrow = Text() + if config.show_branches: + if line.line_num in btset: + in_arrow = Text("~>", sc(str(line.line_num))) + if line.branch_target is not None: + out_arrow = " " + Text("~>", sc(str(line.branch_target))) + formatted_line_num = Text(hex(line.line_num)[2:] + ":", line_color) + return formatted_line_num + " " + in_arrow + " " + out + out_arrow + + part1 = format_part(out1, line1, line_color1, bts1, sc5) + part2 = format_part(out2, line2, line_color2, bts2, sc6) + + if config.show_source and line2: + for source_line in line2.source_lines: + line_format = BasicFormat.SOURCE_OTHER + if config.source_old_binutils: + if source_line and re.fullmatch(".*\.c(?:pp)?:\d+", source_line): + line_format = BasicFormat.SOURCE_FILENAME + elif source_line and source_line.endswith("():"): + line_format = BasicFormat.SOURCE_FUNCTION + try: + source_line = cxxfilt.demangle( + source_line[:-3], external_only=False + ) + except: + pass + else: + # File names and function names + if source_line and source_line[0] != "│": + line_format = BasicFormat.SOURCE_FILENAME + # Function names + if source_line.endswith("():"): + line_format = BasicFormat.SOURCE_FUNCTION + try: + source_line = cxxfilt.demangle( + source_line[:-3], external_only=False + ) + except: + pass + padding = " " * 7 if config.show_line_numbers else " " * 2 + output.append( + OutputLine( + base=None, + fmt2=padding + Text(source_line, line_format), + key2=source_line, + boring=True, + is_data_ref=False, + line1=None, + line2=None, + ) + ) + + key2 = line2.normalized_original if line2 else None + boring = False + if line_prefix == " ": + boring = True + elif config.compress and config.compress.same_instr and line_prefix in "irs": + boring = True + + if config.show_line_numbers: + if line2 and line2.source_line_num is not None: + num_color = ( + BasicFormat.SOURCE_LINE_NUM + if sym_color == BasicFormat.NONE + else sym_color + ) + num2 = Text(f"{line2.source_line_num:5}", num_color) + else: + num2 = Text(" " * 5) + else: + num2 = Text() + + fmt2 = Text(line_prefix, sym_color) + num2 + " " + (part2 or Text()) + + output.append( + OutputLine( + base=part1, + fmt2=fmt2, + key2=key2, + boring=boring, + is_data_ref=is_data_ref, + line1=line1, + line2=line2, + ) + ) + + output = output[config.skip_lines :] + + score = score_diff_lines(diffed_lines, config, symbol_map) + max_score = len(lines1) * config.penalty_deletion + return Diff(lines=output, score=score, max_score=max_score) + + +def chunk_diff_lines( + diff: List[OutputLine], +) -> List[Union[List[OutputLine], OutputLine]]: + """Chunk a diff into an alternating list like A B A B ... A, where: + * A is a List[OutputLine] of insertions, + * B is a single non-insertion OutputLine, with .base != None.""" + cur_right: List[OutputLine] = [] + chunks: List[Union[List[OutputLine], OutputLine]] = [] + for output_line in diff: + if output_line.base is not None: + chunks.append(cur_right) + chunks.append(output_line) + cur_right = [] + else: + cur_right.append(output_line) + chunks.append(cur_right) + return chunks + + +def compress_matching( + li: List[Tuple[OutputLine, ...]], context: int +) -> List[Tuple[OutputLine, ...]]: + ret: List[Tuple[OutputLine, ...]] = [] + matching_streak: List[Tuple[OutputLine, ...]] = [] + context = max(context, 0) + + def flush_matching() -> None: + if len(matching_streak) <= 2 * context + 1: + ret.extend(matching_streak) + else: + ret.extend(matching_streak[:context]) + skipped = len(matching_streak) - 2 * context + filler = OutputLine( + base=Text(f"<{skipped} lines>", BasicFormat.SOURCE_OTHER), + fmt2=Text(), + key2=None, + boring=False, + is_data_ref=False, + line1=None, + line2=None, + ) + columns = len(matching_streak[0]) + ret.append(tuple([filler] * columns)) + if context > 0: + ret.extend(matching_streak[-context:]) + matching_streak.clear() + + for line in li: + if line[0].boring: + matching_streak.append(line) + else: + flush_matching() + ret.append(line) + + flush_matching() + return ret + + +def align_diffs(old_diff: Diff, new_diff: Diff, config: Config) -> TableData: + headers: Tuple[Text, ...] + diff_lines: List[Tuple[OutputLine, ...]] + padding = " " * 7 if config.show_line_numbers else " " * 2 + + if config.diff_mode in (DiffMode.THREEWAY_PREV, DiffMode.THREEWAY_BASE): + old_chunks = chunk_diff_lines(old_diff.lines) + new_chunks = chunk_diff_lines(new_diff.lines) + diff_lines = [] + empty = OutputLine(Text(), Text(), None, True, False, None, None) + assert len(old_chunks) == len(new_chunks), "same target" + for old_chunk, new_chunk in zip(old_chunks, new_chunks): + if isinstance(old_chunk, list): + assert isinstance(new_chunk, list) + if not old_chunk and not new_chunk: + # Most of the time lines sync up without insertions/deletions, + # and there's no interdiffing to be done. + continue + differ = difflib.SequenceMatcher( + a=old_chunk, b=new_chunk, autojunk=False + ) + for (tag, i1, i2, j1, j2) in differ.get_opcodes(): + if tag in ["equal", "replace"]: + for i, j in zip(range(i1, i2), range(j1, j2)): + diff_lines.append((empty, new_chunk[j], old_chunk[i])) + if tag in ["insert", "replace"]: + for j in range(j1 + i2 - i1, j2): + diff_lines.append((empty, new_chunk[j], empty)) + if tag in ["delete", "replace"]: + for i in range(i1 + j2 - j1, i2): + diff_lines.append((empty, empty, old_chunk[i])) + else: + assert isinstance(new_chunk, OutputLine) + # old_chunk.base and new_chunk.base have the same text since + # both diffs are based on the same target, but they might + # differ in color. Use the new version. + diff_lines.append((new_chunk, new_chunk, old_chunk)) + diff_lines = [ + (base, new, old if old != new else empty) for base, new, old in diff_lines + ] + headers = ( + Text("TARGET"), + Text(f"{padding}CURRENT ({new_diff.score})"), + Text(f"{padding}PREVIOUS ({old_diff.score})"), + ) + current_score = new_diff.score + max_score = new_diff.max_score + previous_score = old_diff.score + elif config.diff_mode in (DiffMode.SINGLE, DiffMode.SINGLE_BASE): + header = Text("BASE" if config.diff_mode == DiffMode.SINGLE_BASE else "CURRENT") + diff_lines = [(line,) for line in new_diff.lines] + headers = (header,) + # Scoring is disabled for view mode + current_score = 0 + max_score = 0 + previous_score = None + else: + diff_lines = [(line, line) for line in new_diff.lines] + headers = ( + Text("TARGET"), + Text(f"{padding}CURRENT ({new_diff.score})"), + ) + current_score = new_diff.score + max_score = new_diff.max_score + previous_score = None + if config.compress: + diff_lines = compress_matching(diff_lines, config.compress.context) + + def diff_line_to_table_line(line: Tuple[OutputLine, ...]) -> TableLine: + cells = [ + (line[0].base or Text(), line[0].line1) + ] + for ol in line[1:]: + cells.append((ol.fmt2, ol.line2)) + + return TableLine( + key=line[0].key2, + is_data_ref=line[0].is_data_ref, + cells=tuple(cells), + ) + + return TableData( + headers=headers, + current_score=current_score, + max_score=max_score, + previous_score=previous_score, + lines=[diff_line_to_table_line(line) for line in diff_lines], + ) + + +def debounced_fs_watch( + targets: List[str], + outq: "queue.Queue[Optional[float]]", + config: Config, + project: ProjectSettings, +) -> None: + import watchdog.events + import watchdog.observers + + class WatchEventHandler(watchdog.events.FileSystemEventHandler): + def __init__( + self, queue: "queue.Queue[float]", file_targets: List[str] + ) -> None: + self.queue = queue + self.file_targets = file_targets + + def on_modified(self, ev: object) -> None: + if isinstance(ev, watchdog.events.FileModifiedEvent): + self.changed(ev.src_path) + + def on_moved(self, ev: object) -> None: + if isinstance(ev, watchdog.events.FileMovedEvent): + self.changed(ev.dest_path) + + def should_notify(self, path: str) -> bool: + for target in self.file_targets: + if os.path.normpath(path) == target: + return True + if config.make and any( + path.endswith(suffix) for suffix in project.source_extensions + ): + return True + return False + + def changed(self, path: str) -> None: + if self.should_notify(path): + self.queue.put(time.time()) + + def debounce_thread() -> NoReturn: + listenq: "queue.Queue[float]" = queue.Queue() + file_targets: List[str] = [] + event_handler = WatchEventHandler(listenq, file_targets) + observer = watchdog.observers.Observer() + observed = set() + for target in targets: + if os.path.isdir(target): + observer.schedule(event_handler, target, recursive=True) + else: + file_targets.append(os.path.normpath(target)) + target = os.path.dirname(target) or "." + if target not in observed: + observed.add(target) + observer.schedule(event_handler, target) + observer.start() + while True: + t = listenq.get() + more = True + while more: + delay = t + DEBOUNCE_DELAY - time.time() + if delay > 0: + time.sleep(delay) + # consume entire queue + more = False + try: + while True: + t = listenq.get(block=False) + more = True + except queue.Empty: + pass + outq.put(t) + + th = threading.Thread(target=debounce_thread, daemon=True) + th.start() + + +class Display: + basedump: str + mydump: str + last_refresh_key: object + config: Config + emsg: Optional[str] + last_diff_output: Optional[Diff] + pending_update: Optional[str] + ready_queue: "queue.Queue[None]" + watch_queue: "queue.Queue[Optional[float]]" + less_proc: "Optional[subprocess.Popen[bytes]]" + + def __init__(self, basedump: str, mydump: str, config: Config) -> None: + self.config = config + self.base_lines = process(basedump, config) + self.mydump = mydump + self.emsg = None + self.last_refresh_key = None + self.last_diff_output = None + + def run_diff(self) -> Tuple[str, object]: + if self.emsg is not None: + return (self.emsg, self.emsg) + + my_lines = process(self.mydump, self.config) + + if self.config.diff_mode == DiffMode.SINGLE_BASE: + diff_output = do_diff(self.base_lines, self.base_lines, self.config) + elif self.config.diff_mode == DiffMode.SINGLE: + diff_output = do_diff(my_lines, my_lines, self.config) + else: + diff_output = do_diff(self.base_lines, my_lines, self.config) + + last_diff_output = self.last_diff_output or diff_output + if self.config.diff_mode != DiffMode.THREEWAY_BASE or not self.last_diff_output: + self.last_diff_output = diff_output + + data = align_diffs(last_diff_output, diff_output, self.config) + output = self.config.formatter.table(data) + + refresh_key = ( + [line.key2 for line in diff_output.lines], + diff_output.score, + ) + + return (output, refresh_key) + + def run_less( + self, output: str + ) -> "Tuple[subprocess.Popen[bytes], subprocess.Popen[bytes]]": + # Pipe the output through 'tail' and only then to less, to ensure the + # write call doesn't block. ('tail' has to buffer all its input before + # it starts writing.) This also means we don't have to deal with pipe + # closure errors. + buffer_proc = subprocess.Popen( + BUFFER_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) + less_proc = subprocess.Popen(LESS_CMD, stdin=buffer_proc.stdout) + assert buffer_proc.stdin + assert buffer_proc.stdout + buffer_proc.stdin.write(output.encode()) + buffer_proc.stdin.close() + buffer_proc.stdout.close() + return (buffer_proc, less_proc) + + def run_sync(self) -> None: + output, _ = self.run_diff() + proca, procb = self.run_less(output) + procb.wait() + proca.wait() + + def run_async(self, watch_queue: "queue.Queue[Optional[float]]") -> None: + self.watch_queue = watch_queue + self.ready_queue = queue.Queue() + self.pending_update = None + output, refresh_key = self.run_diff() + self.last_refresh_key = refresh_key + dthread = threading.Thread(target=self.display_thread, args=(output,)) + dthread.start() + self.ready_queue.get() + + def display_thread(self, initial_output: str) -> None: + proca, procb = self.run_less(initial_output) + self.less_proc = procb + self.ready_queue.put(None) + while True: + ret = procb.wait() + proca.wait() + self.less_proc = None + if ret != 0: + # fix the terminal + os.system("tput reset") + if ret != 0 and self.pending_update is not None: + # killed by program with the intent to refresh + output = self.pending_update + self.pending_update = None + proca, procb = self.run_less(output) + self.less_proc = procb + self.ready_queue.put(None) + else: + # terminated by user, or killed + self.watch_queue.put(None) + self.ready_queue.put(None) + break + + def progress(self, msg: str) -> None: + # Write message to top-left corner + sys.stdout.write("\x1b7\x1b[1;1f{}\x1b8".format(msg + " ")) + sys.stdout.flush() + + def update(self, text: str, error: bool) -> None: + if not error and not self.emsg and text == self.mydump: + self.progress("Unchanged. ") + return + if not error: + self.mydump = text + self.emsg = None + else: + self.emsg = text + output, refresh_key = self.run_diff() + if refresh_key == self.last_refresh_key: + self.progress("Unchanged. ") + return + self.last_refresh_key = refresh_key + self.pending_update = output + if not self.less_proc: + return + self.less_proc.kill() + self.ready_queue.get() + + def terminate(self) -> None: + if not self.less_proc: + return + self.less_proc.kill() + self.ready_queue.get() + + +def main() -> None: + args = parser.parse_args() + + # Apply project-specific configuration. + settings: Dict[str, Any] = {} + diff_settings.apply(settings, args) # type: ignore + project = create_project_settings(settings) + + try: + config = create_config(args, project) + except ValueError as e: + fail(str(e)) + + if config.algorithm == "levenshtein": + try: + import Levenshtein + except ModuleNotFoundError as e: + fail(MISSING_PREREQUISITES.format(e.name)) + + if config.show_source: + try: + import cxxfilt + except ModuleNotFoundError as e: + fail(MISSING_PREREQUISITES.format(e.name)) + + if ( + config.diff_mode in (DiffMode.THREEWAY_BASE, DiffMode.THREEWAY_PREV) + and not args.watch + ): + fail("Threeway diffing requires -w.") + + if args.diff_elf_symbol: + make_target, basecmd, mycmd = dump_elf( + args.start, args.end, args.diff_elf_symbol, config, project + ) + elif config.diff_obj: + make_target, basecmd, mycmd = dump_objfile( + args.start, args.end, config, project + ) + else: + make_target, basecmd, mycmd = dump_binary(args.start, args.end, config, project) + + map_build_target_fn = getattr(diff_settings, "map_build_target", None) + if map_build_target_fn: + make_target = map_build_target_fn(make_target=make_target) + + if args.write_asm is not None: + mydump = run_objdump(mycmd, config, project) + with open(args.write_asm, "w") as f: + f.write(mydump) + print(f"Wrote assembly to {args.write_asm}.") + sys.exit(0) + + if args.base_asm is not None: + with open(args.base_asm) as f: + basedump = f.read() + elif config.diff_mode != DiffMode.SINGLE: + basedump = run_objdump(basecmd, config, project) + else: + basedump = "" + + mydump = run_objdump(mycmd, config, project) + + display = Display(basedump, mydump, config) + + if args.no_pager or args.format in ("html", "json"): + print(display.run_diff()[0]) + elif not args.watch: + display.run_sync() + else: + if not args.make: + yn = input( + "Warning: watch-mode (-w) enabled without auto-make (-m). " + "You will have to run make manually. Ok? (Y/n) " + ) + if yn.lower() == "n": + return + if args.make: + watch_sources = None + watch_sources_for_target_fn = getattr( + diff_settings, "watch_sources_for_target", None + ) + if watch_sources_for_target_fn: + watch_sources = watch_sources_for_target_fn(make_target) + watch_sources = watch_sources or project.source_directories + if not watch_sources: + fail("Missing source_directories config, don't know what to watch.") + else: + watch_sources = [make_target] + q: "queue.Queue[Optional[float]]" = queue.Queue() + debounced_fs_watch(watch_sources, q, config, project) + display.run_async(q) + last_build = 0.0 + try: + while True: + t = q.get() + if t is None: + break + if t < last_build: + continue + last_build = time.time() + if args.make: + display.progress("Building...") + ret = run_make_capture_output(make_target, project) + if ret.returncode != 0: + display.update( + ret.stderr.decode("utf-8-sig", "replace") + or ret.stdout.decode("utf-8-sig", "replace"), + error=True, + ) + continue + mydump = run_objdump(mycmd, config, project) + display.update(mydump, error=False) + except KeyboardInterrupt: + display.terminate() + + +if __name__ == "__main__": + main() diff --git a/tools/asm-differ/diff_settings.py b/tools/asm-differ/diff_settings.py new file mode 100644 index 00000000..19d67d54 --- /dev/null +++ b/tools/asm-differ/diff_settings.py @@ -0,0 +1,12 @@ +def apply(config, args): + config["baseimg"] = "target.bin" + config["myimg"] = "source.bin" + config["mapfile"] = "build.map" + config["source_directories"] = ["."] + # config["show_line_numbers_default"] = True + # config["arch"] = "mips" + # config["map_format"] = "gnu" # gnu, mw, ms + # config["build_dir"] = "build/" # only needed for mw and ms map format + # config["expected_dir"] = "expected/" # needed for -o + # config["makeflags"] = [] + # config["objdump_executable"] = "" diff --git a/tools/asm-differ/mypy.ini b/tools/asm-differ/mypy.ini new file mode 100644 index 00000000..138b9393 --- /dev/null +++ b/tools/asm-differ/mypy.ini @@ -0,0 +1,17 @@ +[mypy] +check_untyped_defs = True +disallow_any_generics = True +disallow_incomplete_defs = True +disallow_untyped_calls = True +disallow_untyped_decorators = True +disallow_untyped_defs = True +no_implicit_optional = True +warn_redundant_casts = True +warn_return_any = True +warn_unused_ignores = True +ignore_missing_imports = True +python_version = 3.6 +files = diff.py + +[mypy-diff_settings] +ignore_errors = True diff --git a/tools/asm-differ/pyproject.toml b/tools/asm-differ/pyproject.toml new file mode 100644 index 00000000..7a112aee --- /dev/null +++ b/tools/asm-differ/pyproject.toml @@ -0,0 +1,21 @@ +[tool.poetry] +name = "asm-differ" +version = "0.1.0" +description = "" +authors = ["Simon Lindholm "] +license = "UNLICENSE" +readme = "README.md" +packages = [{ include = "diff.py" }] + +[tool.poetry.dependencies] +python = "^3.7" +colorama = "^0.4.6" +ansiwrap = "^0.8.4" +watchdog = "^2.2.0" +levenshtein = "^0.20.9" +cxxfilt = "^0.3.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/tools/asm-differ/screenshot.png b/tools/asm-differ/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3230555328cd9acdf388ce1626415ceb78760535 GIT binary patch literal 99842 zcmd431yG#Zx~@w?g1b9Gg1b8j?(Ul4?yezdaCdiicXxMpXxtjt+nIC8T?|I+RzvN^@;bCxKz`(%Z#l?gaz`)*jgWgV15TGr};=9eDAJ8^p z>h@q@2))1G@8YNtaKXSnfr$%!RdPu^S#woWo_ig*yyF8fki`5Th6sk)PK;JWNis|Z zsu^+aDCNg#=!G|=0-dGpsRFN!*d=R5V@HWtjq$!zFb{tE^mFtRRO-tUcq%diOwffV zZ^T4S^`iOdq5b%}ds!X2tgI|Lksp!(6cH8H*o@VW-y=UH*`6J5CQL_(Z*_qu*{tga7bR<#a{)OOf4fWVsTgfN-|O~^HU_AgLGLcgL@F$H4n zWr;G-r0}(Es%!V>?c=6wf1ONQ`%w_<1L{LxpY?I@Q-aQ`neWb-rQz3gs#AUH&UsU< zY)xdWjZP#W(P)lq3pRdOxv<-GjZ?%dMuI)7(gO+PE$QRg!DbZbrc6Ovt=^Fq766-5)c zGoJ(ITpZQBar&%xo?I~-vuyJnJBZ*?jigQ@u}@?ogV3@)qEfx%#l}N|r64mG?-`8F zC|c7jt0s+N&^*JzapP;uL>btv30uhMTA6lvAKR9Z$Y&$&h6d2+Y>bJ=mZsGoa5s;2HN!v8s<;Ip1Pf~_@MNjk&d(l7Sf(N7P_`YCW+gYaKmom&3px9qBtjw3|*?;4C zWYSRGs%><_9@!+@vPfgbZQ1gw9dAhe97l8AtHUX3V!}u0`Y2W}g)=yRVqpgc^@(8# zyTX-TaYA|I>_d|(sgQU~Dt+Q^E9jyoI)Is(F}N?#8#r6M#|}oXTZaGM8>l!KbYZx+ zWFc2-%4&qLqa(Fjac)$@qY-EyBh#wN){174%ry zAqm9t3_bi5842voGw*BplO2k@d(jWyeuN{uoyPw$4`s@$wLCykf6TeBCMWjPzM z%;z6e7*CsAvzNXpNt)f;I+bb;H+x3iZG0TgDY@m+4`3xfTljS^I7TWLRB1HU(Z zcp=R2bPm{VtswGqVfo{lV~W`6#Hw<|7CWS}pz0RHc)XngJ_zMzS9$roDh95$b*p|w zq)2{m^ou2Tw9Oy(K1l~rqilZCk-}CTnLCkx8!9EaE=xK^^?Fm6<1LCdA&rsbu6}vZ$nN3VBk^*_{vTVn6%)|Ofsb!l z-*oP1^F5~!k3DN19EQGb@0und49n(;=)6EeiR zlh&o_FGPZ(o|0;5UT~(mr&Fkd)XGI0nJ|x)-?~F^KIEw+NSN(%%0NP(pkay0O>$;W z2XFC3WM6#KN9QK&m-571d0|efRqK`yQuxeijWy)jBR(EtCmZvZzC4o6}C?EOp=3f`~j66SNK z#;z<<$zn6Qs?!WPyIE2h0xrRMcWcJ|H3KjBP(j@yx?3CDj;;G`S;^`WMZdxlosn?rLJheNxys8Q zPKs6=j$^7Jcn6;C7;TxGO38>&4YAW9A*H3?*-)p=Q1gG6$fkec4&SV4pq(Gije6=GAa zLLusT?mQz}LF+S#H+lJY5*k(8Id^*^zRg;|9^GOICQy+X2xWW+ zJU5l{#Xfg}3w-33rRTArnXJ3Y^4UYkR-B!#82O^HkS?XWikPq>%aF!rIAl(BsmVW< zb}Pm>&}s*-W403IT%z$kHco1EFXov=AD(~Xj6HvGXG{KLS{pMVy{Y@gRZY0p5O>Ur z>+Z}KqTZN)%+r-wyVKZKacHABdkz z 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 literal 0 HcmV?d00001 diff --git a/tools/asm-processor/.gitignore b/tools/asm-processor/.gitignore new file mode 100644 index 00000000..cc5bba4b --- /dev/null +++ b/tools/asm-processor/.gitignore @@ -0,0 +1,2 @@ +*.o +*.py[cod] diff --git a/tools/asm-processor/.gitrepo b/tools/asm-processor/.gitrepo new file mode 100644 index 00000000..ef2baa13 --- /dev/null +++ b/tools/asm-processor/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:simonlindholm/asm-processor.git + branch = main + commit = bbd86ea1faf84e6a7a0e101ab8068a00a3dfb2fc + parent = 75437386de04179489f4fd5fb345d122ff8a2dc0 + method = merge + cmdver = 0.4.3 diff --git a/tools/asm-processor/LICENSE b/tools/asm-processor/LICENSE new file mode 100644 index 00000000..cf1ab25d --- /dev/null +++ b/tools/asm-processor/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/tools/asm-processor/README.md b/tools/asm-processor/README.md new file mode 100644 index 00000000..009147c0 --- /dev/null +++ b/tools/asm-processor/README.md @@ -0,0 +1,112 @@ +# asm-processor + +Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C. + +## Usage + +Let's say you have a file compiled with `-g` on the IDO compiler, that looks like this: +```c +float func4(void) { + "func4"; + return 0.2f; +} +``` + +This script enables replacing it by: +```asm +GLOBAL_ASM( +.rdata +.word 0x66756e63 # func +.word 0x34000000 # 4\0\0\0 + +.late_rodata +glabel rv +.word 0x3e4ccccd # 0.2f + +.text +glabel func4 +lui $at, %hi(rv) +jr $ra +lwc1 $f0, %lo(rv)($at) +jr $ra +nop +jr $ra +nop +) +``` + +To compile the file, run `python3 build.py $CC -- $AS $ASFLAGS -- $CFLAGS -o out.o in.c`, where $CC points to an IDO binary (5.3/7.1 and recomp/qemu all supported), $AS is e.g. `mips-linux-gnu-as`, $ASFLAGS e.g. `-march=vr4300 -mabi=32` and $CFLAGS e.g. `-Wab,-r4300_mul -non_shared -G 0 -Xcpluscomm -g`. build.py may be customized as needed. + +In addition to an .o file, build.py also generates a .d file with Makefile dependencies for .s files referenced by the input .c file. +This functionality may be removed if not needed. + +Reading assembly from file is also supported, by either `GLOBAL_ASM("file.s")` or `#pragma GLOBAL_ASM("file.s")`. + +### What is supported? + +`.text`, `.data`, `.bss` and `.rodata` sections, `.word`/`.incbin`, `.ascii`/`.asciz`, and `-g`, `-g3`, `-O1`, `-O2`, `-framepointer` and `-mips1`/`-mips2` flags to the IDO compiler. + +### What is not supported? + +* complicated assembly (.ifdef, macro declarations/calls other than `glabel`, pseudo-instructions that expand to several real instructions) +* non-IDO compilers +* `-O3` (due to function reordering) + +C `#ifdef`s only work outside of `GLOBAL_ASM` calls, but is otherwise able to replace `.ifdef`. + +### What's up with "late rodata"? + +The IDO compiler emits rodata in two passes: first array/string contents, then large literals/switch jump tables. + +Data declared within `.rdata`/`.section .rodata` will end up in the first half, and `.late_rodata`/`.section .late_rodata` in the second half. + +### How does it work? + +It's a bit of a hack! +The basic idea is replace `GLOBAL_ASM` blocks with dummy C functions/global vars of the same sections sizes as the assembly. +Then the C file gets compiled, and the dummy contents overwritten with the injected assembly. + +To accomplish this, asm-processor has logic for guessing the size of assembly contents +(which assumes the assembly isn't too complicated, e.g. no macros), +and for emitting C code of exact sizes for a bunch of different IDO compiler flags. + +The assembler code is padded with nops to line it up with its correct position in the C; +this allows C and asm ELF files to be merged easily without having to fix up e.g. symbol addresses. + +The most difficult part is `late_rodata`, which is hard to create programmatically. +asm-processor does that by emitting code that uses dummy float literals/double literals/jump tables, +assembles the late_rodata at another location of the .rodata section, then overwrites the dummy rodata. +This does require some movement of symbols and relocations, and quite a bit of care in what code to +emit and how to preserve .double alignment. + +It's worth noting some alternative ways in which asm-processor would have been implemented: +- One idea to get rid of the C/asm size estimations is to emit arbitrary code, and then move code, +symbols and relocations to the correct place after the sizes are known. +Given the machinery for `late_rodata` this wouldn't have been too difficult, and it would have the upside of improved portability. +There is a big downside, however: using dummy code of incorrect size throws off alignment and can introduce unintended padding. +Fixing this would require running multiple passes of asm-processor, with one compile per `ASM_GLOBAL`. +- Another idea is to run the compiler with -S to emit assembly, modify the emitted assembly, then run the assembler +(which in IDO's case may perform additional instruction reordering etc.). +This option has not been investigated in much detail, and would perhaps be superior to the current implementation. +It does have a few unknowns to it, e.g. instruction encoding differences between GNU `as` and IDO's assembler, +how to avoid reordering the injected assembly, and how .rodata/.late_rodata are implemented. + +### Testing + +There are a few tests to ensure you don't break anything when hacking on asm-processor: `./run-tests.sh` should exit without output if they pass, or else output a diff from previous to new version. + +Tests need the environment variable `MIPS_CC` set to point to the IDO 7.1 compiler, with Pascal support enabled. + +For example if asm-processor is cloned in the same directory as [ido static recomp](https://github.com/decompals/ido-static-recomp) and the working directory is asm-processor, tests can be run using: + +```sh +MIPS_CC=../ido-static-recomp/build/7.1/out/cc ./run-tests.sh +``` + +Or using [qemu-irix](https://github.com/zeldaret/oot/releases/tag/0.1q) (don't forget `chmod u+x qemu-irix`) to emulate IDO: + +```sh +MIPS_CC='./qemu-irix -silent -L ../ido-static-recomp/ido/7.1/ ../ido-static-recomp/ido/7.1/usr/bin/cc' ./run-tests.sh +``` + +To skip running Pascal tests, remove the `tests/*.p` glob from `run-tests.sh`. diff --git a/tools/asm-processor/add-test.sh b/tools/asm-processor/add-test.sh new file mode 100755 index 00000000..708548e5 --- /dev/null +++ b/tools/asm-processor/add-test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +for A in "$@"; do + OBJDUMPFLAGS="-srt" + ./compile-test.sh "$A" && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" > "${A%.*}.objdump" +done diff --git a/tools/asm-processor/asm_processor.py b/tools/asm-processor/asm_processor.py new file mode 100644 index 00000000..0d62bc32 --- /dev/null +++ b/tools/asm-processor/asm_processor.py @@ -0,0 +1,1472 @@ +#!/usr/bin/env python3 +import argparse +import tempfile +import struct +import copy +import sys +import re +import os +from collections import namedtuple +from io import StringIO + +MAX_FN_SIZE = 100 +SLOW_CHECKS = False + +EI_NIDENT = 16 +EI_CLASS = 4 +EI_DATA = 5 +EI_VERSION = 6 +EI_OSABI = 7 +EI_ABIVERSION = 8 +STN_UNDEF = 0 + +SHN_UNDEF = 0 +SHN_ABS = 0xfff1 +SHN_COMMON = 0xfff2 +SHN_XINDEX = 0xffff +SHN_LORESERVE = 0xff00 + +STT_NOTYPE = 0 +STT_OBJECT = 1 +STT_FUNC = 2 +STT_SECTION = 3 +STT_FILE = 4 +STT_COMMON = 5 +STT_TLS = 6 + +STB_LOCAL = 0 +STB_GLOBAL = 1 +STB_WEAK = 2 + +STV_DEFAULT = 0 +STV_INTERNAL = 1 +STV_HIDDEN = 2 +STV_PROTECTED = 3 + +SHT_NULL = 0 +SHT_PROGBITS = 1 +SHT_SYMTAB = 2 +SHT_STRTAB = 3 +SHT_RELA = 4 +SHT_HASH = 5 +SHT_DYNAMIC = 6 +SHT_NOTE = 7 +SHT_NOBITS = 8 +SHT_REL = 9 +SHT_SHLIB = 10 +SHT_DYNSYM = 11 +SHT_INIT_ARRAY = 14 +SHT_FINI_ARRAY = 15 +SHT_PREINIT_ARRAY = 16 +SHT_GROUP = 17 +SHT_SYMTAB_SHNDX = 18 +SHT_MIPS_GPTAB = 0x70000003 +SHT_MIPS_DEBUG = 0x70000005 +SHT_MIPS_REGINFO = 0x70000006 +SHT_MIPS_OPTIONS = 0x7000000d + +SHF_WRITE = 0x1 +SHF_ALLOC = 0x2 +SHF_EXECINSTR = 0x4 +SHF_MERGE = 0x10 +SHF_STRINGS = 0x20 +SHF_INFO_LINK = 0x40 +SHF_LINK_ORDER = 0x80 +SHF_OS_NONCONFORMING = 0x100 +SHF_GROUP = 0x200 +SHF_TLS = 0x400 + +R_MIPS_32 = 2 +R_MIPS_26 = 4 +R_MIPS_HI16 = 5 +R_MIPS_LO16 = 6 + +MIPS_DEBUG_ST_STATIC = 2 +MIPS_DEBUG_ST_STATIC_PROC = 14 + + +class ElfFormat: + def __init__(self, is_big_endian): + self.is_big_endian = is_big_endian + self.struct_char = ">" if is_big_endian else "<" + + def pack(self, fmt, *args): + return struct.pack(self.struct_char + fmt, *args) + + def unpack(self, fmt, data): + return struct.unpack(self.struct_char + fmt, data) + + +class ElfHeader: + """ + typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; + } Elf32_Ehdr; + """ + + def __init__(self, data): + self.e_ident = data[:EI_NIDENT] + assert self.e_ident[EI_CLASS] == 1 # 32-bit + self.fmt = ElfFormat(is_big_endian=(self.e_ident[EI_DATA] == 2)) + self.e_type, self.e_machine, self.e_version, self.e_entry, self.e_phoff, self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx = self.fmt.unpack('HHIIIIIHHHHHH', data[EI_NIDENT:]) + assert self.e_type == 1 # relocatable + assert self.e_machine == 8 # MIPS I Architecture + assert self.e_phoff == 0 # no program header + assert self.e_shoff != 0 # section header + assert self.e_shstrndx != SHN_UNDEF + + def to_bin(self): + return self.e_ident + self.fmt.pack('HHIIIIIHHHHHH', self.e_type, + self.e_machine, self.e_version, self.e_entry, self.e_phoff, + self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, + self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx) + + +class Symbol: + """ + typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; + } Elf32_Sym; + """ + + def __init__(self, fmt, data, strtab, name=None): + self.fmt = fmt + self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx = fmt.unpack('IIIBBH', data) + assert self.st_shndx != SHN_XINDEX, "too many sections (SHN_XINDEX not supported)" + self.bind = st_info >> 4 + self.type = st_info & 15 + self.name = name if name is not None else strtab.lookup_str(self.st_name) + self.visibility = self.st_other & 3 + + @staticmethod + def from_parts(fmt, st_name, st_value, st_size, st_info, st_other, st_shndx, strtab, name): + header = fmt.pack('IIIBBH', st_name, st_value, st_size, st_info, st_other, st_shndx) + return Symbol(fmt, header, strtab, name) + + def to_bin(self): + st_info = (self.bind << 4) | self.type + return self.fmt.pack('IIIBBH', self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx) + + +class Relocation: + def __init__(self, fmt, data, sh_type): + self.fmt = fmt + self.sh_type = sh_type + if sh_type == SHT_REL: + self.r_offset, self.r_info = fmt.unpack('II', data) + else: + self.r_offset, self.r_info, self.r_addend = fmt.unpack('III', data) + self.sym_index = self.r_info >> 8 + self.rel_type = self.r_info & 0xff + + def to_bin(self): + self.r_info = (self.sym_index << 8) | self.rel_type + if self.sh_type == SHT_REL: + return self.fmt.pack('II', self.r_offset, self.r_info) + else: + return self.fmt.pack('III', self.r_offset, self.r_info, self.r_addend) + + +class Section: + """ + typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; + } Elf32_Shdr; + """ + + def __init__(self, fmt, header, data, index): + self.fmt = fmt + self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize = fmt.unpack('IIIIIIIIII', header) + assert not self.sh_flags & SHF_LINK_ORDER + if self.sh_entsize != 0: + assert self.sh_size % self.sh_entsize == 0 + if self.sh_type == SHT_NOBITS: + self.data = b'' + else: + self.data = data[self.sh_offset:self.sh_offset + self.sh_size] + self.index = index + self.relocated_by = [] + + @staticmethod + def from_parts(fmt, sh_name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data, index): + header = fmt.pack('IIIIIIIIII', sh_name, sh_type, sh_flags, 0, 0, len(data), sh_link, sh_info, sh_addralign, sh_entsize) + return Section(fmt, header, data, index) + + def lookup_str(self, index): + assert self.sh_type == SHT_STRTAB + to = self.data.find(b'\0', index) + assert to != -1 + return self.data[index:to].decode('latin1') + + def add_str(self, string): + assert self.sh_type == SHT_STRTAB + ret = len(self.data) + self.data += string.encode('latin1') + b'\0' + return ret + + def is_rel(self): + return self.sh_type == SHT_REL or self.sh_type == SHT_RELA + + def header_to_bin(self): + if self.sh_type != SHT_NOBITS: + self.sh_size = len(self.data) + return self.fmt.pack('IIIIIIIIII', self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize) + + def late_init(self, sections): + if self.sh_type == SHT_SYMTAB: + self.init_symbols(sections) + elif self.is_rel(): + self.rel_target = sections[self.sh_info] + self.rel_target.relocated_by.append(self) + self.init_relocs() + + def find_symbol(self, name): + assert self.sh_type == SHT_SYMTAB + for s in self.symbol_entries: + if s.name == name: + return (s.st_shndx, s.st_value) + return None + + def find_symbol_in_section(self, name, section): + pos = self.find_symbol(name) + assert pos is not None + assert pos[0] == section.index + return pos[1] + + def init_symbols(self, sections): + assert self.sh_type == SHT_SYMTAB + assert self.sh_entsize == 16 + self.strtab = sections[self.sh_link] + entries = [] + for i in range(0, self.sh_size, self.sh_entsize): + entries.append(Symbol(self.fmt, self.data[i:i+self.sh_entsize], self.strtab)) + self.symbol_entries = entries + + def init_relocs(self): + assert self.is_rel() + entries = [] + for i in range(0, self.sh_size, self.sh_entsize): + entries.append(Relocation(self.fmt, self.data[i:i+self.sh_entsize], self.sh_type)) + self.relocations = entries + + def local_symbols(self): + assert self.sh_type == SHT_SYMTAB + return self.symbol_entries[:self.sh_info] + + def global_symbols(self): + assert self.sh_type == SHT_SYMTAB + return self.symbol_entries[self.sh_info:] + + def relocate_mdebug(self, original_offset): + assert self.sh_type == SHT_MIPS_DEBUG + new_data = bytearray(self.data) + shift_by = self.sh_offset - original_offset + + # Update the file-relative offsets in the Symbolic HDRR + hdrr_magic, hdrr_vstamp, hdrr_ilineMax, hdrr_cbLine, \ + hdrr_cbLineOffset, hdrr_idnMax, hdrr_cbDnOffset, hdrr_ipdMax, \ + hdrr_cbPdOffset, hdrr_isymMax, hdrr_cbSymOffset, hdrr_ioptMax, \ + hdrr_cbOptOffset, hdrr_iauxMax, hdrr_cbAuxOffset, hdrr_issMax, \ + hdrr_cbSsOffset, hdrr_issExtMax, hdrr_cbSsExtOffset, hdrr_ifdMax, \ + hdrr_cbFdOffset, hdrr_crfd, hdrr_cbRfdOffset, hdrr_iextMax, \ + hdrr_cbExtOffset = self.fmt.unpack("HHIIIIIIIIIIIIIIIIIIIIIII", self.data[0:0x60]) + + assert hdrr_magic == 0x7009, "Invalid magic value for .mdebug symbolic header" + + hdrr_cbLineOffset += shift_by + hdrr_cbDnOffset += shift_by + hdrr_cbPdOffset += shift_by + hdrr_cbSymOffset += shift_by + hdrr_cbOptOffset += shift_by + hdrr_cbAuxOffset += shift_by + hdrr_cbSsOffset += shift_by + hdrr_cbSsExtOffset += shift_by + hdrr_cbFdOffset += shift_by + hdrr_cbRfdOffset += shift_by + hdrr_cbExtOffset += shift_by + + new_data[0:0x60] = self.fmt.pack("HHIIIIIIIIIIIIIIIIIIIIIII", hdrr_magic, hdrr_vstamp, hdrr_ilineMax, hdrr_cbLine, \ + hdrr_cbLineOffset, hdrr_idnMax, hdrr_cbDnOffset, hdrr_ipdMax, \ + hdrr_cbPdOffset, hdrr_isymMax, hdrr_cbSymOffset, hdrr_ioptMax, \ + hdrr_cbOptOffset, hdrr_iauxMax, hdrr_cbAuxOffset, hdrr_issMax, \ + hdrr_cbSsOffset, hdrr_issExtMax, hdrr_cbSsExtOffset, hdrr_ifdMax, \ + hdrr_cbFdOffset, hdrr_crfd, hdrr_cbRfdOffset, hdrr_iextMax, \ + hdrr_cbExtOffset) + + self.data = bytes(new_data) + +class ElfFile: + def __init__(self, data): + self.data = data + assert data[:4] == b'\x7fELF', "not an ELF file" + + self.elf_header = ElfHeader(data[0:52]) + self.fmt = self.elf_header.fmt + + offset, size = self.elf_header.e_shoff, self.elf_header.e_shentsize + null_section = Section(self.fmt, data[offset:offset + size], data, 0) + num_sections = self.elf_header.e_shnum or null_section.sh_size + + self.sections = [null_section] + for i in range(1, num_sections): + ind = offset + i * size + self.sections.append(Section(self.fmt, data[ind:ind + size], data, i)) + + symtab = None + for s in self.sections: + if s.sh_type == SHT_SYMTAB: + assert not symtab + symtab = s + assert symtab is not None + self.symtab = symtab + + shstr = self.sections[self.elf_header.e_shstrndx] + for s in self.sections: + s.name = shstr.lookup_str(s.sh_name) + s.late_init(self.sections) + + def find_section(self, name): + for s in self.sections: + if s.name == name: + return s + return None + + def add_section(self, name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data): + shstr = self.sections[self.elf_header.e_shstrndx] + sh_name = shstr.add_str(name) + s = Section.from_parts(self.fmt, sh_name=sh_name, sh_type=sh_type, + sh_flags=sh_flags, sh_link=sh_link, sh_info=sh_info, + sh_addralign=sh_addralign, sh_entsize=sh_entsize, data=data, + index=len(self.sections)) + self.sections.append(s) + s.name = name + s.late_init(self.sections) + return s + + def drop_mdebug_gptab(self): + # We can only drop sections at the end, since otherwise section + # references might be wrong. Luckily, these sections typically are. + while self.sections[-1].sh_type in [SHT_MIPS_DEBUG, SHT_MIPS_GPTAB]: + self.sections.pop() + + def write(self, filename): + outfile = open(filename, 'wb') + outidx = 0 + def write_out(data): + nonlocal outidx + outfile.write(data) + outidx += len(data) + def pad_out(align): + if align and outidx % align: + write_out(b'\0' * (align - outidx % align)) + + self.elf_header.e_shnum = len(self.sections) + write_out(self.elf_header.to_bin()) + + for s in self.sections: + if s.sh_type != SHT_NOBITS and s.sh_type != SHT_NULL: + pad_out(s.sh_addralign) + old_offset = s.sh_offset + s.sh_offset = outidx + if s.sh_type == SHT_MIPS_DEBUG and s.sh_offset != old_offset: + # The .mdebug section has moved, relocate offsets + s.relocate_mdebug(old_offset) + write_out(s.data) + + pad_out(4) + self.elf_header.e_shoff = outidx + for s in self.sections: + write_out(s.header_to_bin()) + + outfile.seek(0) + outfile.write(self.elf_header.to_bin()) + outfile.close() + + +def is_temp_name(name): + return name.startswith('_asmpp_') + + +# https://stackoverflow.com/a/241506 +def re_comment_replacer(match): + s = match.group(0) + if s[0] in "/#": + return " " + else: + return s + + +re_comment_or_string = re.compile( + r'#.*|/\*.*?\*/|"(?:\\.|[^\\"])*"' +) + + +class Failure(Exception): + def __init__(self, message): + self.message = message + + def __str__(self): + return self.message + + +class GlobalState: + def __init__(self, min_instr_count, skip_instr_count, use_jtbl_for_rodata, prelude_if_late_rodata, mips1, pascal): + # A value that hopefully never appears as a 32-bit rodata constant (or we + # miscompile late rodata). Increases by 1 in each step. + self.late_rodata_hex = 0xE0123456 + self.valuectr = 0 + self.namectr = 0 + self.min_instr_count = min_instr_count + self.skip_instr_count = skip_instr_count + self.use_jtbl_for_rodata = use_jtbl_for_rodata + self.prelude_if_late_rodata = prelude_if_late_rodata + self.mips1 = mips1 + self.pascal = pascal + + def next_late_rodata_hex(self): + dummy_bytes = struct.pack('>I', self.late_rodata_hex) + if (self.late_rodata_hex & 0xffff) == 0: + # Avoid lui + self.late_rodata_hex += 1 + self.late_rodata_hex += 1 + return dummy_bytes + + def make_name(self, cat): + self.namectr += 1 + return '_asmpp_{}{}'.format(cat, self.namectr) + + def func_prologue(self, name): + if self.pascal: + return " ".join([ + "procedure {}();".format(name), + "type", + " pi = ^integer;", + " pf = ^single;", + " pd = ^double;", + "var", + " vi: pi;", + " vf: pf;", + " vd: pd;", + "begin", + " vi := vi;", + " vf := vf;", + " vd := vd;", + ]) + else: + return 'void {}(void) {{'.format(name) + + def func_epilogue(self): + if self.pascal: + return "end;" + else: + return "}" + + def pascal_assignment(self, tp, val): + self.valuectr += 1 + address = (8 * self.valuectr) & 0x7FFF + return 'v{} := p{}({}); v{}^ := {};'.format(tp, tp, address, tp, val) + +Function = namedtuple('Function', ['text_glabels', 'asm_conts', 'late_rodata_dummy_bytes', 'jtbl_rodata_size', 'late_rodata_asm_conts', 'fn_desc', 'data']) + + +class GlobalAsmBlock: + def __init__(self, fn_desc): + self.fn_desc = fn_desc + self.cur_section = '.text' + self.asm_conts = [] + self.late_rodata_asm_conts = [] + self.late_rodata_alignment = 0 + self.late_rodata_alignment_from_content = False + self.text_glabels = [] + self.fn_section_sizes = { + '.text': 0, + '.data': 0, + '.bss': 0, + '.rodata': 0, + '.late_rodata': 0, + } + self.fn_ins_inds = [] + self.glued_line = '' + self.num_lines = 0 + + def fail(self, message, line=None): + context = self.fn_desc + if line: + context += ", at line \"" + line + "\"" + raise Failure(message + "\nwithin " + context) + + def count_quoted_size(self, line, z, real_line, output_enc): + line = line.encode(output_enc).decode('latin1') + in_quote = False + has_comma = True + num_parts = 0 + ret = 0 + i = 0 + digits = "0123456789" # 0-7 would be more sane, but this matches GNU as + while i < len(line): + c = line[i] + i += 1 + if not in_quote: + if c == '"': + in_quote = True + if z and not has_comma: + self.fail(".asciiz with glued strings is not supported due to GNU as version diffs") + num_parts += 1 + elif c == ',': + has_comma = True + else: + if c == '"': + in_quote = False + has_comma = False + continue + ret += 1 + if c != '\\': + continue + if i == len(line): + self.fail("backslash at end of line not supported", real_line) + c = line[i] + i += 1 + # (if c is in "bfnrtv", we have a real escaped literal) + if c == 'x': + # hex literal, consume any number of hex chars, possibly none + while i < len(line) and line[i] in digits + "abcdefABCDEF": + i += 1 + elif c in digits: + # octal literal, consume up to two more digits + it = 0 + while i < len(line) and line[i] in digits and it < 2: + i += 1 + it += 1 + + if in_quote: + self.fail("unterminated string literal", real_line) + if num_parts == 0: + self.fail(".ascii with no string", real_line) + return ret + num_parts if z else ret + + def align2(self): + while self.fn_section_sizes[self.cur_section] % 2 != 0: + self.fn_section_sizes[self.cur_section] += 1 + + def align4(self): + while self.fn_section_sizes[self.cur_section] % 4 != 0: + self.fn_section_sizes[self.cur_section] += 1 + + def add_sized(self, size, line): + if self.cur_section in ['.text', '.late_rodata']: + if size % 4 != 0: + self.fail("size must be a multiple of 4", line) + if size < 0: + self.fail("size cannot be negative", line) + self.fn_section_sizes[self.cur_section] += size + if self.cur_section == '.text': + if not self.text_glabels: + self.fail(".text block without an initial glabel", line) + self.fn_ins_inds.append((self.num_lines - 1, size // 4)) + + def process_line(self, line, output_enc): + self.num_lines += 1 + if line.endswith('\\'): + self.glued_line += line[:-1] + return + line = self.glued_line + line + self.glued_line = '' + + real_line = line + line = re.sub(re_comment_or_string, re_comment_replacer, line) + line = line.strip() + line = re.sub(r'^[a-zA-Z0-9_]+:\s*', '', line) + changed_section = False + emitting_double = False + if line.startswith('glabel ') and self.cur_section == '.text': + self.text_glabels.append(line.split()[1]) + if not line: + pass # empty line + elif line.startswith('glabel ') or line.startswith('dlabel ') or line.startswith('endlabel ') or (' ' not in line and line.endswith(':')): + pass # label + elif line.startswith('.section') or line in ['.text', '.data', '.rdata', '.rodata', '.bss', '.late_rodata']: + # section change + self.cur_section = '.rodata' if line == '.rdata' else line.split(',')[0].split()[-1] + if self.cur_section not in ['.data', '.text', '.rodata', '.late_rodata', '.bss']: + self.fail("unrecognized .section directive", real_line) + changed_section = True + elif line.startswith('.late_rodata_alignment'): + if self.cur_section != '.late_rodata': + self.fail(".late_rodata_alignment must occur within .late_rodata section", real_line) + value = int(line.split()[1]) + if value not in [4, 8]: + self.fail(".late_rodata_alignment argument must be 4 or 8", real_line) + if self.late_rodata_alignment and self.late_rodata_alignment != value: + self.fail(".late_rodata_alignment alignment assumption conflicts with earlier .double directive. Make sure to provide explicit alignment padding.") + self.late_rodata_alignment = value + changed_section = True + elif line.startswith('.incbin'): + self.add_sized(int(line.split(',')[-1].strip(), 0), real_line) + elif line.startswith('.word') or line.startswith('.gpword') or line.startswith('.float'): + self.align4() + self.add_sized(4 * len(line.split(',')), real_line) + elif line.startswith('.double'): + self.align4() + if self.cur_section == '.late_rodata': + align8 = self.fn_section_sizes[self.cur_section] % 8 + # Automatically set late_rodata_alignment, so the generated C code uses doubles. + # This gives us correct alignment for the transferred doubles even when the + # late_rodata_alignment is wrong, e.g. for non-matching compilation. + if not self.late_rodata_alignment: + self.late_rodata_alignment = 8 - align8 + self.late_rodata_alignment_from_content = True + elif self.late_rodata_alignment != 8 - align8: + if self.late_rodata_alignment_from_content: + self.fail("found two .double directives with different start addresses mod 8. Make sure to provide explicit alignment padding.", real_line) + else: + self.fail(".double at address that is not 0 mod 8 (based on .late_rodata_alignment assumption). Make sure to provide explicit alignment padding.", real_line) + self.add_sized(8 * len(line.split(',')), real_line) + emitting_double = True + elif line.startswith('.space'): + self.add_sized(int(line.split()[1], 0), real_line) + elif line.startswith('.balign') or line.startswith('.align'): + align = int(line.split()[1]) + if align != 4: + self.fail("only .balign 4 is supported", real_line) + self.align4() + elif line.startswith('.asci'): + z = (line.startswith('.asciz') or line.startswith('.asciiz')) + self.add_sized(self.count_quoted_size(line, z, real_line, output_enc), real_line) + elif line.startswith('.byte'): + self.add_sized(len(line.split(',')), real_line) + elif line.startswith('.half'): + self.align2() + self.add_sized(2*len(line.split(',')), real_line) + elif line.startswith('.'): + # .macro, ... + self.fail("asm directive not supported", real_line) + else: + # Unfortunately, macros are hard to support for .rodata -- + # we don't know how how space they will expand to before + # running the assembler, but we need that information to + # construct the C code. So if we need that we'll either + # need to run the assembler twice (at least in some rare + # cases), or change how this program is invoked. + # Similarly, we can't currently deal with pseudo-instructions + # that expand to several real instructions. + if self.cur_section != '.text': + self.fail("instruction or macro call in non-.text section? not supported", real_line) + self.add_sized(4, real_line) + if self.cur_section == '.late_rodata': + if not changed_section: + if emitting_double: + self.late_rodata_asm_conts.append(".align 0") + self.late_rodata_asm_conts.append(real_line) + if emitting_double: + self.late_rodata_asm_conts.append(".align 2") + else: + self.asm_conts.append(real_line) + + def finish(self, state): + src = [''] * (self.num_lines + 1) + late_rodata_dummy_bytes = [] + jtbl_rodata_size = 0 + late_rodata_fn_output = [] + + num_instr = self.fn_section_sizes['.text'] // 4 + + if self.fn_section_sizes['.late_rodata'] > 0: + # Generate late rodata by emitting unique float constants. + # This requires 3 instructions for each 4 bytes of rodata. + # If we know alignment, we can use doubles, which give 3 + # instructions for 8 bytes of rodata. + size = self.fn_section_sizes['.late_rodata'] // 4 + skip_next = False + needs_double = (self.late_rodata_alignment != 0) + extra_mips1_nop = False + if state.pascal: + jtbl_size = 9 if state.mips1 else 8 + jtbl_min_rodata_size = 2 + else: + jtbl_size = 11 if state.mips1 else 9 + jtbl_min_rodata_size = 5 + for i in range(size): + if skip_next: + skip_next = False + continue + # Jump tables give 9 instructions (11 with -mips1) for >= 5 words of rodata, + # and should be emitted when: + # - -O2 or -O2 -g3 are used, which give the right codegen + # - we have emitted our first .float/.double (to ensure that we find the + # created rodata in the binary) + # - we have emitted our first .double, if any (to ensure alignment of doubles + # in shifted rodata sections) + # - we have at least 5 words of rodata left to emit (otherwise IDO does not + # generate a jump table) + # - we have at least 10 more instructions to go in this function (otherwise our + # function size computation will be wrong since the delay slot goes unused) + if (not needs_double and state.use_jtbl_for_rodata and i >= 1 and + size - i >= jtbl_min_rodata_size and + num_instr - len(late_rodata_fn_output) >= jtbl_size + 1): + if state.pascal: + cases = " ".join("{}: ;".format(case) for case in range(size - i)) + line = "case 0 of " + cases + " otherwise end;" + else: + cases = " ".join("case {}:".format(case) for case in range(size - i)) + line = "switch (*(volatile int*)0) { " + cases + " ; }" + late_rodata_fn_output.append(line) + late_rodata_fn_output.extend([""] * (jtbl_size - 1)) + jtbl_rodata_size = (size - i) * 4 + extra_mips1_nop = i != 2 + break + dummy_bytes = state.next_late_rodata_hex() + late_rodata_dummy_bytes.append(dummy_bytes) + if self.late_rodata_alignment == 4 * ((i + 1) % 2 + 1) and i + 1 < size: + dummy_bytes2 = state.next_late_rodata_hex() + late_rodata_dummy_bytes.append(dummy_bytes2) + fval, = struct.unpack('>d', dummy_bytes + dummy_bytes2) + if state.pascal: + line = state.pascal_assignment('d', fval) + else: + line = '*(volatile double*)0 = {};'.format(fval) + late_rodata_fn_output.append(line) + skip_next = True + needs_double = False + if state.mips1: + # mips1 does not have ldc1/sdc1 + late_rodata_fn_output.append('') + late_rodata_fn_output.append('') + extra_mips1_nop = False + else: + fval, = struct.unpack('>f', dummy_bytes) + if state.pascal: + line = state.pascal_assignment('f', fval) + else: + line = '*(volatile float*)0 = {}f;'.format(fval) + late_rodata_fn_output.append(line) + extra_mips1_nop = True + late_rodata_fn_output.append('') + late_rodata_fn_output.append('') + if state.mips1 and extra_mips1_nop: + late_rodata_fn_output.append('') + + text_name = None + if self.fn_section_sizes['.text'] > 0 or late_rodata_fn_output: + text_name = state.make_name('func') + src[0] = state.func_prologue(text_name) + src[self.num_lines] = state.func_epilogue() + instr_count = self.fn_section_sizes['.text'] // 4 + if instr_count < state.min_instr_count: + self.fail("too short .text block") + tot_emitted = 0 + tot_skipped = 0 + fn_emitted = 0 + fn_skipped = 0 + skipping = True + rodata_stack = late_rodata_fn_output[::-1] + for (line, count) in self.fn_ins_inds: + for _ in range(count): + if (fn_emitted > MAX_FN_SIZE and instr_count - tot_emitted > state.min_instr_count and + (not rodata_stack or rodata_stack[-1])): + # Don't let functions become too large. When a function reaches 284 + # instructions, and -O2 -framepointer flags are passed, the IRIX + # compiler decides it is a great idea to start optimizing more. + # Also, Pascal cannot handle too large functions before it runs out + # of unique statements to write. + fn_emitted = 0 + fn_skipped = 0 + skipping = True + src[line] += (' ' + state.func_epilogue() + ' ' + + state.func_prologue(state.make_name('large_func')) + ' ') + if ( + skipping and + fn_skipped < state.skip_instr_count + + (state.prelude_if_late_rodata if rodata_stack else 0) + ): + fn_skipped += 1 + tot_skipped += 1 + else: + skipping = False + if rodata_stack: + src[line] += rodata_stack.pop() + elif state.pascal: + src[line] += state.pascal_assignment('i', '0') + else: + src[line] += '*(volatile int*)0 = 0;' + tot_emitted += 1 + fn_emitted += 1 + if rodata_stack: + size = len(late_rodata_fn_output) // 3 + available = instr_count - tot_skipped + self.fail( + "late rodata to text ratio is too high: {} / {} must be <= 1/3\n" + "add .late_rodata_alignment (4|8) to the .late_rodata " + "block to double the allowed ratio." + .format(size, available)) + + rodata_name = None + if self.fn_section_sizes['.rodata'] > 0: + if state.pascal: + self.fail(".rodata isn't supported with Pascal for now") + rodata_name = state.make_name('rodata') + src[self.num_lines] += ' const char {}[{}] = {{1}};'.format(rodata_name, self.fn_section_sizes['.rodata']) + + data_name = None + if self.fn_section_sizes['.data'] > 0: + data_name = state.make_name('data') + if state.pascal: + line = ' var {}: packed array[1..{}] of char := [otherwise: 0];'.format(data_name, self.fn_section_sizes['.data']) + else: + line = ' char {}[{}] = {{1}};'.format(data_name, self.fn_section_sizes['.data']) + src[self.num_lines] += line + + bss_name = None + if self.fn_section_sizes['.bss'] > 0: + if state.pascal: + self.fail(".bss isn't supported with Pascal") + bss_name = state.make_name('bss') + src[self.num_lines] += ' char {}[{}];'.format(bss_name, self.fn_section_sizes['.bss']) + + fn = Function( + text_glabels=self.text_glabels, + asm_conts=self.asm_conts, + late_rodata_dummy_bytes=late_rodata_dummy_bytes, + jtbl_rodata_size=jtbl_rodata_size, + late_rodata_asm_conts=self.late_rodata_asm_conts, + fn_desc=self.fn_desc, + data={ + '.text': (text_name, self.fn_section_sizes['.text']), + '.data': (data_name, self.fn_section_sizes['.data']), + '.rodata': (rodata_name, self.fn_section_sizes['.rodata']), + '.bss': (bss_name, self.fn_section_sizes['.bss']), + }) + return src, fn + +cutscene_data_regexpr = re.compile(r"CutsceneData (.|\n)*\[\] = {") +float_regexpr = re.compile(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?f") + +def repl_float_hex(m): + return str(struct.unpack(">I", struct.pack(">f", float(m.group(0).strip().rstrip("f"))))[0]) + +Opts = namedtuple('Opts', ['opt', 'framepointer', 'mips1', 'kpic', 'pascal', 'input_enc', 'output_enc']) + +def parse_source(f, opts, out_dependencies, print_source=None): + if opts.opt in ['O1', 'O2']: + if opts.framepointer: + min_instr_count = 6 + skip_instr_count = 5 + else: + min_instr_count = 2 + skip_instr_count = 1 + elif opts.opt == 'O0': + if opts.framepointer: + min_instr_count = 8 + skip_instr_count = 8 + else: + min_instr_count = 4 + skip_instr_count = 4 + elif opts.opt == 'g': + if opts.framepointer: + min_instr_count = 7 + skip_instr_count = 7 + else: + min_instr_count = 4 + skip_instr_count = 4 + elif opts.opt == 'g3': + if opts.framepointer: + min_instr_count = 4 + skip_instr_count = 4 + else: + min_instr_count = 2 + skip_instr_count = 2 + else: + raise Failure("must pass one of -g, -O0, -O1, -O2, -O2 -g3") + prelude_if_late_rodata = 0 + if opts.kpic: + # Without optimizations, the PIC prelude always takes up 3 instructions. + # With optimizations, the prelude is optimized out if there's no late rodata. + if opts.opt in ('g3', 'O2'): + prelude_if_late_rodata = 3 + else: + min_instr_count += 3 + skip_instr_count += 3 + + use_jtbl_for_rodata = False + if opts.opt in ['O2', 'g3'] and not opts.framepointer and not opts.kpic: + use_jtbl_for_rodata = True + + state = GlobalState(min_instr_count, skip_instr_count, use_jtbl_for_rodata, prelude_if_late_rodata, opts.mips1, opts.pascal) + output_enc = opts.output_enc + + global_asm = None + asm_functions = [] + output_lines = [ + '#line 1 "' + f.name + '"' + ] + + is_cutscene_data = False + is_early_include = False + + for line_no, raw_line in enumerate(f, 1): + raw_line = raw_line.rstrip() + line = raw_line.lstrip() + + # Print exactly one output line per source line, to make compiler + # errors have correct line numbers. These will be overridden with + # reasonable content further down. + output_lines.append('') + + if global_asm is not None: + if line.startswith(')'): + src, fn = global_asm.finish(state) + for i, line2 in enumerate(src): + output_lines[start_index + i] = line2 + asm_functions.append(fn) + global_asm = None + else: + global_asm.process_line(raw_line, output_enc) + elif line in ['GLOBAL_ASM(', '#pragma GLOBAL_ASM(']: + global_asm = GlobalAsmBlock("GLOBAL_ASM block at line " + str(line_no)) + start_index = len(output_lines) + elif ((line.startswith('GLOBAL_ASM("') or line.startswith('#pragma GLOBAL_ASM("')) + and line.endswith('")')): + fname = line[line.index('(') + 2 : -2] + out_dependencies.append(fname) + global_asm = GlobalAsmBlock(fname) + with open(fname, encoding=opts.input_enc) as f: + for line2 in f: + global_asm.process_line(line2.rstrip(), output_enc) + src, fn = global_asm.finish(state) + output_lines[-1] = ''.join(src) + asm_functions.append(fn) + global_asm = None + elif line == '#pragma asmproc recurse': + # C includes qualified as + # #pragma asmproc recurse + # #include "file.c" + # will be processed recursively when encountered + is_early_include = True + elif is_early_include: + # Previous line was a #pragma asmproc recurse + is_early_include = False + if not line.startswith("#include "): + raise Failure("#pragma asmproc recurse must be followed by an #include ") + fpath = os.path.dirname(f.name) + fname = os.path.join(fpath, line[line.index(' ') + 2 : -1]) + out_dependencies.append(fname) + include_src = StringIO() + with open(fname, encoding=opts.input_enc) as include_file: + parse_source(include_file, opts, out_dependencies, include_src) + include_src.write('#line ' + str(line_no + 1) + ' "' + f.name + '"') + output_lines[-1] = include_src.getvalue() + include_src.close() + else: + # This is a hack to replace all floating-point numbers in an array of a particular type + # (in this case CutsceneData) with their corresponding IEEE-754 hexadecimal representation + if cutscene_data_regexpr.search(line) is not None: + is_cutscene_data = True + elif line.endswith("};"): + is_cutscene_data = False + if is_cutscene_data: + raw_line = re.sub(float_regexpr, repl_float_hex, raw_line) + output_lines[-1] = raw_line + + if print_source: + if isinstance(print_source, StringIO): + for line in output_lines: + print_source.write(line + '\n') + else: + newline_encoded = "\n".encode(output_enc) + for line in output_lines: + try: + line_encoded = line.encode(output_enc) + except UnicodeEncodeError: + print("Failed to encode a line to", output_enc) + print("The line:", line) + print("The line, utf-8-encoded:", line.encode("utf-8")) + raise + print_source.write(line_encoded) + print_source.write(newline_encoded) + print_source.flush() + + return asm_functions + +def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc, drop_mdebug_gptab, convert_statics): + SECTIONS = ['.data', '.text', '.rodata', '.bss'] + + with open(objfile_name, 'rb') as f: + objfile = ElfFile(f.read()) + fmt = objfile.fmt + + prev_locs = { + '.text': 0, + '.data': 0, + '.rodata': 0, + '.bss': 0, + } + to_copy = { + '.text': [], + '.data': [], + '.rodata': [], + '.bss': [], + } + asm = [] + all_late_rodata_dummy_bytes = [] + all_jtbl_rodata_size = [] + late_rodata_asm = [] + late_rodata_source_name_start = None + late_rodata_source_name_end = None + + # Generate an assembly file with all the assembly we need to fill in. For + # simplicity we pad with nops/.space so that addresses match exactly, so we + # don't have to fix up relocations/symbol references. + all_text_glabels = set() + func_sizes = {} + for function in functions: + ifdefed = False + for sectype, (temp_name, size) in function.data.items(): + if temp_name is None: + continue + assert size > 0 + loc = objfile.symtab.find_symbol(temp_name) + if loc is None: + ifdefed = True + break + loc = loc[1] + prev_loc = prev_locs[sectype] + if loc < prev_loc: + # If the dummy C generates too little asm, and we have two + # consecutive GLOBAL_ASM blocks, we detect that error here. + # On the other hand, if it generates too much, we don't have + # a good way of discovering that error: it's indistinguishable + # from a static symbol occurring after the GLOBAL_ASM block. + raise Failure("Wrongly computed size for section {} (diff {}). This is an asm-processor bug!".format(sectype, prev_loc- loc)) + if loc != prev_loc: + asm.append('.section ' + sectype) + if sectype == '.text': + for i in range((loc - prev_loc) // 4): + asm.append('nop') + else: + asm.append('.space {}'.format(loc - prev_loc)) + to_copy[sectype].append((loc, size, temp_name, function.fn_desc)) + if function.text_glabels and sectype == '.text': + func_sizes[function.text_glabels[0]] = size + prev_locs[sectype] = loc + size + if not ifdefed: + all_text_glabels.update(function.text_glabels) + all_late_rodata_dummy_bytes.append(function.late_rodata_dummy_bytes) + all_jtbl_rodata_size.append(function.jtbl_rodata_size) + late_rodata_asm.append(function.late_rodata_asm_conts) + for sectype, (temp_name, size) in function.data.items(): + if temp_name is not None: + asm.append('.section ' + sectype) + asm.append('glabel ' + temp_name + '_asm_start') + asm.append('.text') + for line in function.asm_conts: + asm.append(line) + for sectype, (temp_name, size) in function.data.items(): + if temp_name is not None: + asm.append('.section ' + sectype) + asm.append('glabel ' + temp_name + '_asm_end') + if any(late_rodata_asm): + late_rodata_source_name_start = '_asmpp_late_rodata_start' + late_rodata_source_name_end = '_asmpp_late_rodata_end' + asm.append('.section .late_rodata') + # Put some padding at the start to avoid conflating symbols with + # references to the whole section. + asm.append('.word 0, 0') + asm.append('glabel {}'.format(late_rodata_source_name_start)) + for conts in late_rodata_asm: + asm.extend(conts) + asm.append('glabel {}'.format(late_rodata_source_name_end)) + + o_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.o', delete=False) + o_name = o_file.name + o_file.close() + s_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.s', delete=False) + s_name = s_file.name + try: + s_file.write(asm_prelude + b'\n') + for line in asm: + s_file.write(line.encode(output_enc) + b'\n') + s_file.close() + ret = os.system(assembler + " " + s_name + " -o " + o_name) + if ret != 0: + raise Failure("failed to assemble") + with open(o_name, 'rb') as f: + asm_objfile = ElfFile(f.read()) + + # Remove clutter from objdump output for tests, and make the tests + # portable by avoiding absolute paths. Outside of tests .mdebug is + # useful for showing source together with asm, though. + mdebug_section = objfile.find_section('.mdebug') + if drop_mdebug_gptab: + objfile.drop_mdebug_gptab() + + # Unify reginfo sections + target_reginfo = objfile.find_section('.reginfo') + if target_reginfo is not None: + source_reginfo_data = list(asm_objfile.find_section('.reginfo').data) + data = list(target_reginfo.data) + for i in range(20): + data[i] |= source_reginfo_data[i] + target_reginfo.data = bytes(data) + + # Move over section contents + modified_text_positions = set() + jtbl_rodata_positions = set() + last_rodata_pos = 0 + for sectype in SECTIONS: + if not to_copy[sectype]: + continue + source = asm_objfile.find_section(sectype) + assert source is not None, "didn't find source section: " + sectype + for (pos, count, temp_name, fn_desc) in to_copy[sectype]: + loc1 = asm_objfile.symtab.find_symbol_in_section(temp_name + '_asm_start', source) + loc2 = asm_objfile.symtab.find_symbol_in_section(temp_name + '_asm_end', source) + assert loc1 == pos, "assembly and C files don't line up for section " + sectype + ", " + fn_desc + if loc2 - loc1 != count: + raise Failure("incorrectly computed size for section " + sectype + ", " + fn_desc + ". If using .double, make sure to provide explicit alignment padding.") + if sectype == '.bss': + continue + target = objfile.find_section(sectype) + assert target is not None, "missing target section of type " + sectype + data = list(target.data) + for (pos, count, _, _) in to_copy[sectype]: + data[pos:pos + count] = source.data[pos:pos + count] + if sectype == '.text': + assert count % 4 == 0 + assert pos % 4 == 0 + for i in range(count // 4): + modified_text_positions.add(pos + 4 * i) + elif sectype == '.rodata': + last_rodata_pos = pos + count + target.data = bytes(data) + + # Move over late rodata. This is heuristic, sadly, since I can't think + # of another way of doing it. + moved_late_rodata = {} + if any(all_late_rodata_dummy_bytes) or any(all_jtbl_rodata_size): + source = asm_objfile.find_section('.late_rodata') + target = objfile.find_section('.rodata') + source_pos = asm_objfile.symtab.find_symbol_in_section(late_rodata_source_name_start, source) + source_end = asm_objfile.symtab.find_symbol_in_section(late_rodata_source_name_end, source) + if source_end - source_pos != sum(map(len, all_late_rodata_dummy_bytes)) * 4 + sum(all_jtbl_rodata_size): + raise Failure("computed wrong size of .late_rodata") + new_data = list(target.data) + for dummy_bytes_list, jtbl_rodata_size in zip(all_late_rodata_dummy_bytes, all_jtbl_rodata_size): + for index, dummy_bytes in enumerate(dummy_bytes_list): + if not fmt.is_big_endian: + dummy_bytes = dummy_bytes[::-1] + pos = target.data.index(dummy_bytes, last_rodata_pos) + # This check is nice, but makes time complexity worse for large files: + if SLOW_CHECKS and target.data.find(dummy_bytes, pos + 4) != -1: + raise Failure("multiple occurrences of late_rodata hex magic. Change asm-processor to use something better than 0xE0123456!") + if index == 0 and len(dummy_bytes_list) > 1 and target.data[pos+4:pos+8] == b'\0\0\0\0': + # Ugly hack to handle double alignment for non-matching builds. + # We were told by .late_rodata_alignment (or deduced from a .double) + # that a function's late_rodata started out 4 (mod 8), and emitted + # a float and then a double. But it was actually 0 (mod 8), so our + # double was moved by 4 bytes. To make them adjacent to keep jump + # tables correct, move the float by 4 bytes as well. + new_data[pos:pos+4] = b'\0\0\0\0' + pos += 4 + new_data[pos:pos+4] = source.data[source_pos:source_pos+4] + moved_late_rodata[source_pos] = pos + last_rodata_pos = pos + 4 + source_pos += 4 + if jtbl_rodata_size > 0: + assert dummy_bytes_list, "should always have dummy bytes before jtbl data" + pos = last_rodata_pos + new_data[pos : pos + jtbl_rodata_size] = \ + source.data[source_pos : source_pos + jtbl_rodata_size] + for i in range(0, jtbl_rodata_size, 4): + moved_late_rodata[source_pos + i] = pos + i + jtbl_rodata_positions.add(pos + i) + last_rodata_pos += jtbl_rodata_size + source_pos += jtbl_rodata_size + target.data = bytes(new_data) + + # Merge strtab data. + strtab_adj = len(objfile.symtab.strtab.data) + objfile.symtab.strtab.data += asm_objfile.symtab.strtab.data + + # Find relocated symbols + relocated_symbols = set() + for sectype in SECTIONS + ['.late_rodata']: + for obj in [asm_objfile, objfile]: + sec = obj.find_section(sectype) + if sec is None: + continue + for reltab in sec.relocated_by: + for rel in reltab.relocations: + relocated_symbols.add(obj.symtab.symbol_entries[rel.sym_index]) + + # Move over symbols, deleting the temporary function labels. + # Skip over new local symbols that aren't relocated against, to + # avoid conflicts. + empty_symbol = objfile.symtab.symbol_entries[0] + new_syms = [s for s in objfile.symtab.symbol_entries[1:] if not is_temp_name(s.name)] + + for i, s in enumerate(asm_objfile.symtab.symbol_entries): + is_local = (i < asm_objfile.symtab.sh_info) + if is_local and s not in relocated_symbols: + continue + if is_temp_name(s.name): + assert s not in relocated_symbols + continue + if s.st_shndx not in [SHN_UNDEF, SHN_ABS]: + section_name = asm_objfile.sections[s.st_shndx].name + target_section_name = section_name + if section_name == ".late_rodata": + target_section_name = ".rodata" + elif section_name not in SECTIONS: + raise Failure("generated assembly .o must only have symbols for .text, .data, .rodata, .late_rodata, ABS and UNDEF, but found " + section_name) + objfile_section = objfile.find_section(target_section_name) + if objfile_section is None: + raise Failure("generated assembly .o has section that real objfile lacks: " + target_section_name) + s.st_shndx = objfile_section.index + # glabel's aren't marked as functions, making objdump output confusing. Fix that. + if s.name in all_text_glabels: + s.type = STT_FUNC + if s.name in func_sizes: + s.st_size = func_sizes[s.name] + if section_name == '.late_rodata': + if s.st_value == 0: + # This must be a symbol corresponding to the whole .late_rodata + # section, being referred to from a relocation. + # Moving local symbols is tricky, because it requires fixing up + # lo16/hi16 relocation references to .late_rodata+. + # Just disallow it for now. + raise Failure("local symbols in .late_rodata are not allowed") + s.st_value = moved_late_rodata[s.st_value] + s.st_name += strtab_adj + new_syms.append(s) + make_statics_global = convert_statics in ("global", "global-with-filename") + + # Add static symbols from .mdebug, so they can be referred to from GLOBAL_ASM + if mdebug_section and convert_statics != "no": + strtab_index = len(objfile.symtab.strtab.data) + new_strtab_data = [] + ifd_max, cb_fd_offset = fmt.unpack('II', mdebug_section.data[18*4 : 20*4]) + cb_sym_offset, = fmt.unpack('I', mdebug_section.data[9*4 : 10*4]) + cb_ss_offset, = fmt.unpack('I', mdebug_section.data[15*4 : 16*4]) + for i in range(ifd_max): + offset = cb_fd_offset + 18*4*i + iss_base, _, isym_base, csym = fmt.unpack('IIII', objfile.data[offset + 2*4 : offset + 6*4]) + for j in range(csym): + offset2 = cb_sym_offset + 12 * (isym_base + j) + iss, value, st_sc_index = fmt.unpack('III', objfile.data[offset2 : offset2 + 12]) + st = (st_sc_index >> 26) + sc = (st_sc_index >> 21) & 0x1f + if st in [MIPS_DEBUG_ST_STATIC, MIPS_DEBUG_ST_STATIC_PROC]: + symbol_name_offset = cb_ss_offset + iss_base + iss + symbol_name_offset_end = objfile.data.find(b'\0', symbol_name_offset) + assert symbol_name_offset_end != -1 + symbol_name = objfile.data[symbol_name_offset : symbol_name_offset_end + 1] + emitted_symbol_name = symbol_name + if convert_statics == "global-with-filename": + # Change the emitted symbol name to include the filename, + # but don't let that affect deduplication logic. + emitted_symbol_name = objfile_name.encode("utf-8") + b":" + symbol_name + section_name = {1: '.text', 2: '.data', 3: '.bss', 15: '.rodata'}[sc] + section = objfile.find_section(section_name) + symtype = STT_FUNC if sc == 1 else STT_OBJECT + binding = STB_GLOBAL if make_statics_global else STB_LOCAL + sym = Symbol.from_parts( + fmt, + st_name=strtab_index, + st_value=value, + st_size=0, + st_info=(binding << 4 | symtype), + st_other=STV_DEFAULT, + st_shndx=section.index, + strtab=objfile.symtab.strtab, + name=symbol_name[:-1].decode('latin1')) + strtab_index += len(emitted_symbol_name) + new_strtab_data.append(emitted_symbol_name) + new_syms.append(sym) + objfile.symtab.strtab.data += b''.join(new_strtab_data) + + # Get rid of duplicate symbols, favoring ones that are not UNDEF. + # Skip this for unnamed local symbols though. + new_syms.sort(key=lambda s: 0 if s.st_shndx != SHN_UNDEF else 1) + old_syms = [] + newer_syms = [] + name_to_sym = {} + for s in new_syms: + if s.name == "_gp_disp": + s.type = STT_OBJECT + if s.bind == STB_LOCAL and s.st_shndx == SHN_UNDEF: + raise Failure("local symbol \"" + s.name + "\" is undefined") + if not s.name: + if s.bind != STB_LOCAL: + raise Failure("global symbol with no name") + newer_syms.append(s) + else: + existing = name_to_sym.get(s.name) + if not existing: + name_to_sym[s.name] = s + newer_syms.append(s) + elif s.st_shndx != SHN_UNDEF: + raise Failure("symbol \"" + s.name + "\" defined twice") + else: + s.replace_by = existing + old_syms.append(s) + new_syms = newer_syms + + # Put local symbols in front, with the initial dummy entry first, and + # _gp_disp at the end if it exists. + new_syms.insert(0, empty_symbol) + new_syms.sort(key=lambda s: (s.bind != STB_LOCAL, s.name == "_gp_disp")) + num_local_syms = sum(1 for s in new_syms if s.bind == STB_LOCAL) + + for i, s in enumerate(new_syms): + s.new_index = i + for s in old_syms: + s.new_index = s.replace_by.new_index + objfile.symtab.data = b''.join(s.to_bin() for s in new_syms) + objfile.symtab.sh_info = num_local_syms + + # Fix up relocation symbol references + for sectype in SECTIONS: + target = objfile.find_section(sectype) + + if target is not None: + # fixup relocation symbol indices, since we butchered them above + for reltab in target.relocated_by: + nrels = [] + for rel in reltab.relocations: + if (sectype == '.text' and rel.r_offset in modified_text_positions or + sectype == '.rodata' and rel.r_offset in jtbl_rodata_positions): + # don't include relocations for late_rodata dummy code + continue + rel.sym_index = objfile.symtab.symbol_entries[rel.sym_index].new_index + nrels.append(rel) + reltab.relocations = nrels + reltab.data = b''.join(rel.to_bin() for rel in nrels) + + # Move over relocations + for sectype in SECTIONS + ['.late_rodata']: + source = asm_objfile.find_section(sectype) + if source is None or not source.data: + continue + + target_sectype = '.rodata' if sectype == '.late_rodata' else sectype + target = objfile.find_section(target_sectype) + assert target is not None, target_sectype + target_reltab = objfile.find_section('.rel' + target_sectype) + target_reltaba = objfile.find_section('.rela' + target_sectype) + for reltab in source.relocated_by: + for rel in reltab.relocations: + rel.sym_index = asm_objfile.symtab.symbol_entries[rel.sym_index].new_index + if sectype == '.late_rodata': + rel.r_offset = moved_late_rodata[rel.r_offset] + new_data = b''.join(rel.to_bin() for rel in reltab.relocations) + if reltab.sh_type == SHT_REL: + if not target_reltab: + target_reltab = objfile.add_section('.rel' + target_sectype, + sh_type=SHT_REL, sh_flags=0, + sh_link=objfile.symtab.index, sh_info=target.index, + sh_addralign=4, sh_entsize=8, data=b'') + target_reltab.data += new_data + else: + if not target_reltaba: + target_reltaba = objfile.add_section('.rela' + target_sectype, + sh_type=SHT_RELA, sh_flags=0, + sh_link=objfile.symtab.index, sh_info=target.index, + sh_addralign=4, sh_entsize=12, data=b'') + target_reltaba.data += new_data + + objfile.write(objfile_name) + finally: + s_file.close() + os.remove(s_name) + try: + os.remove(o_name) + except: + pass + +def run_wrapped(argv, outfile, functions): + parser = argparse.ArgumentParser(description="Pre-process .c files and post-process .o files to enable embedding assembly into C.") + parser.add_argument('filename', help="path to .c code") + parser.add_argument('--post-process', dest='objfile', help="path to .o file to post-process") + parser.add_argument('--assembler', dest='assembler', help="assembler command (e.g. \"mips-linux-gnu-as -march=vr4300 -mabi=32\")") + parser.add_argument('--asm-prelude', dest='asm_prelude', help="path to a file containing a prelude to the assembly file (with .set and .macro directives, e.g.)") + parser.add_argument('--input-enc', default='latin1', help="input encoding (default: %(default)s)") + parser.add_argument('--output-enc', default='latin1', help="output encoding (default: %(default)s)") + parser.add_argument('--drop-mdebug-gptab', dest='drop_mdebug_gptab', action='store_true', help="drop mdebug and gptab sections") + parser.add_argument('--convert-statics', dest='convert_statics', choices=["no", "local", "global", "global-with-filename"], default="local", help="change static symbol visibility (default: %(default)s)") + parser.add_argument('--force', dest='force', action='store_true', help="force processing of files without GLOBAL_ASM blocks") + parser.add_argument('-framepointer', dest='framepointer', action='store_true') + parser.add_argument('-mips1', dest='mips1', action='store_true') + parser.add_argument('-g3', dest='g3', action='store_true') + parser.add_argument('-KPIC', dest='kpic', action='store_true') + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-O0', dest='opt', action='store_const', const='O0') + group.add_argument('-O1', dest='opt', action='store_const', const='O1') + group.add_argument('-O2', dest='opt', action='store_const', const='O2') + group.add_argument('-g', dest='opt', action='store_const', const='g') + args = parser.parse_args(argv) + opt = args.opt + pascal = any(args.filename.endswith(ext) for ext in (".p", ".pas", ".pp")) + if args.g3: + if opt != 'O2': + raise Failure("-g3 is only supported together with -O2") + opt = 'g3' + if args.mips1 and (opt not in ('O1', 'O2') or args.framepointer): + raise Failure("-mips1 is only supported together with -O1 or -O2") + if pascal and opt not in ('O1', 'O2', 'g3'): + raise Failure("Pascal is only supported together with -O1, -O2 or -O2 -g3") + opts = Opts(opt, args.framepointer, args.mips1, args.kpic, pascal, args.input_enc, args.output_enc) + + if args.objfile is None: + with open(args.filename, encoding=args.input_enc) as f: + deps = [] + functions = parse_source(f, opts, out_dependencies=deps, print_source=outfile) + return functions, deps + else: + if args.assembler is None: + raise Failure("must pass assembler command") + if functions is None: + with open(args.filename, encoding=args.input_enc) as f: + functions = parse_source(f, opts, out_dependencies=[]) + if not functions and not args.force: + return + asm_prelude = b'' + if args.asm_prelude: + with open(args.asm_prelude, 'rb') as f: + asm_prelude = f.read() + fixup_objfile(args.objfile, functions, asm_prelude, args.assembler, args.output_enc, args.drop_mdebug_gptab, args.convert_statics) + +def run(argv, outfile=sys.stdout.buffer, functions=None): + try: + return run_wrapped(argv, outfile, functions) + except Failure as e: + print("Error:", e, file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + run(sys.argv[1:]) diff --git a/tools/asm-processor/build.py b/tools/asm-processor/build.py new file mode 100644 index 00000000..efbaade4 --- /dev/null +++ b/tools/asm-processor/build.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +import sys +from pathlib import Path +import shlex +import subprocess +import tempfile +import uuid +import asm_processor + +# Boolean for debugging purposes +# Preprocessed files are temporary, set to True to keep a copy +keep_preprocessed_files = False + +dir_path = Path(__file__).resolve().parent +asm_prelude_path = dir_path / "prelude.inc" + +all_args = sys.argv[1:] +sep0 = next(index for index, arg in enumerate(all_args) if not arg.startswith("-")) +sep1 = all_args.index("--") +sep2 = all_args.index("--", sep1 + 1) + +asmproc_flags = all_args[:sep0] +compiler = all_args[sep0:sep1] + +assembler_args = all_args[sep1 + 1 : sep2] +assembler_sh = " ".join(shlex.quote(x) for x in assembler_args) + + +compile_args = all_args[sep2 + 1 :] + +in_file = Path(compile_args[-1]) +del compile_args[-1] + +out_ind = compile_args.index("-o") +out_file = Path(compile_args[out_ind + 1]) +del compile_args[out_ind + 1] +del compile_args[out_ind] + + +in_dir = in_file.resolve().parent +opt_flags = [ + x for x in compile_args if x in {"-g3", "-g", "-O0", "-O1", "-O2", "-framepointer", "-KPIC"} +] +if "-mips2" not in compile_args: + opt_flags.append("-mips1") + +asmproc_flags += opt_flags + [str(in_file)] + +# Drop .mdebug and .gptab sections from resulting binaries. This makes +# resulting .o files much smaller and speeds up builds, but loses line +# number debug data. +# asmproc_flags += ["--drop-mdebug-gptab"] + +# Convert encoding before compiling. +# asmproc_flags += ["--input-enc", "utf-8", "--output-enc", "euc-jp"] + +with tempfile.TemporaryDirectory(prefix="asm_processor") as tmpdirname: + tmpdir_path = Path(tmpdirname) + preprocessed_filename = "preprocessed_" + uuid.uuid4().hex + in_file.suffix + preprocessed_path = tmpdir_path / preprocessed_filename + + with preprocessed_path.open("wb") as f: + functions, deps = asm_processor.run(asmproc_flags, outfile=f) + + if keep_preprocessed_files: + import shutil + + keep_output_dir = Path("./asm_processor_preprocessed") + keep_output_dir.mkdir(parents=True, exist_ok=True) + + shutil.copy( + preprocessed_path, + keep_output_dir / (in_file.stem + "_" + preprocessed_filename), + ) + + compile_cmdline = ( + compiler + + compile_args + + ["-I", str(in_dir), "-o", str(out_file), str(preprocessed_path)] + ) + + try: + subprocess.check_call(compile_cmdline) + except subprocess.CalledProcessError as e: + print("Failed to compile file " + str(in_file) + ". Command line:") + print() + print(" ".join(shlex.quote(x) for x in compile_cmdline)) + print() + sys.exit(55) + + asm_processor.run( + asmproc_flags + + [ + "--post-process", + str(out_file), + "--assembler", + assembler_sh, + "--asm-prelude", + str(asm_prelude_path), + ], + functions=functions, + ) + + deps_file = out_file.with_suffix(".asmproc.d") + if deps: + with deps_file.open("w") as f: + f.write(str(out_file) + ": " + " \\\n ".join(deps) + "\n") + for dep in deps: + f.write("\n" + dep + ":\n") + else: + try: + deps_file.unlink() + except OSError: + pass diff --git a/tools/asm-processor/compile-test.sh b/tools/asm-processor/compile-test.sh new file mode 100755 index 00000000..65516629 --- /dev/null +++ b/tools/asm-processor/compile-test.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -o pipefail +INPUT="$1" +OUTPUT="${INPUT%.*}.o" + +rm -f "$OUTPUT" + +CC="$MIPS_CC" # ido 7.1 via recomp or qemu-irix +AS="mips-linux-gnu-as" +ASFLAGS="-march=vr4300 -mabi=32" +OPTFLAGS=$(grep 'COMPILE-FLAGS: ' $INPUT | sed 's#^.*COMPILE-FLAGS: ##' | sed 's#}$##') +ASMPFLAGS=$(grep 'ASMP-FLAGS: ' $INPUT | sed 's#^.*ASMP-FLAGS: ##' | sed 's#}$##') +ISET=$(grep 'COMPILE-ISET: ' $INPUT | sed 's#^.*COMPILE-ISET: ##' | sed 's#}$##') +if [[ -z "$OPTFLAGS" ]]; then + OPTFLAGS="-g" +fi +CFLAGS="-Wab,-r4300_mul -G 0 -Xcpluscomm -fullwarn -wlint -woff 819,820,852,821 -signed -c" +if [[ -z "$ISET" ]]; then + CFLAGS="$CFLAGS -mips2" +fi +if [[ "$OPTFLAGS" != *-KPIC* ]]; then + CFLAGS="$CFLAGS -non_shared" +fi + +set -e +python3 build.py --drop-mdebug-gptab $ASMPFLAGS $CC -- $AS $ASFLAGS -- $CFLAGS $OPTFLAGS $ISET -o "$OUTPUT" "$INPUT" diff --git a/tools/asm-processor/prelude.inc b/tools/asm-processor/prelude.inc new file mode 100644 index 00000000..3e58ff14 --- /dev/null +++ b/tools/asm-processor/prelude.inc @@ -0,0 +1,43 @@ +.set noat +.set noreorder +.set gp=64 +.macro glabel label + .global \label + \label: +.endm + + +# Float register aliases (o32 ABI, odd ones are rarely used) + +.set $fv0, $f0 +.set $fv0f, $f1 +.set $fv1, $f2 +.set $fv1f, $f3 +.set $ft0, $f4 +.set $ft0f, $f5 +.set $ft1, $f6 +.set $ft1f, $f7 +.set $ft2, $f8 +.set $ft2f, $f9 +.set $ft3, $f10 +.set $ft3f, $f11 +.set $fa0, $f12 +.set $fa0f, $f13 +.set $fa1, $f14 +.set $fa1f, $f15 +.set $ft4, $f16 +.set $ft4f, $f17 +.set $ft5, $f18 +.set $ft5f, $f19 +.set $fs0, $f20 +.set $fs0f, $f21 +.set $fs1, $f22 +.set $fs1f, $f23 +.set $fs2, $f24 +.set $fs2f, $f25 +.set $fs3, $f26 +.set $fs3f, $f27 +.set $fs4, $f28 +.set $fs4f, $f29 +.set $fs5, $f30 +.set $fs5f, $f31 diff --git a/tools/asm-processor/run-tests.sh b/tools/asm-processor/run-tests.sh new file mode 100755 index 00000000..5cae0a74 --- /dev/null +++ b/tools/asm-processor/run-tests.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +for A in tests/*.c tests/*.p; do + OBJDUMPFLAGS=-srt + echo $A + ./compile-test.sh "$A" && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" | diff - "${A%.*}.objdump" || echo FAIL "$A" +done diff --git a/tools/asm-processor/tests/ascii.c b/tools/asm-processor/tests/ascii.c new file mode 100644 index 00000000..bb27d252 --- /dev/null +++ b/tools/asm-processor/tests/ascii.c @@ -0,0 +1,19 @@ +void foo(void) { "abcdef"; } + +GLOBAL_ASM( +.rdata + .ascii "AB" + .ascii "CD", "EF" + .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK" +) + +void bar(void) { "hello"; } + +GLOBAL_ASM( +.rdata + .asciiz "12" + .asciiz "34", "56" + .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A" +) + +void baz(void) { "ghijkl"; } diff --git a/tools/asm-processor/tests/ascii.objdump b/tools/asm-processor/tests/ascii.objdump new file mode 100644 index 00000000..bf42638a --- /dev/null +++ b/tools/asm-processor/tests/ascii.objdump @@ -0,0 +1,29 @@ + +tests/ascii.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000030 .text +00000000 l d .rodata 00000050 .rodata +00000000 g F .text 00000010 foo +00000010 g F .text 00000010 bar +00000020 g F .text 00000010 baz + + +Contents of section .text: + 0000 03e00008 00000000 03e00008 00000000 ................ + 0010 03e00008 00000000 03e00008 00000000 ................ + 0020 03e00008 00000000 03e00008 00000000 ................ +Contents of section .rodata: + 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH + 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ + 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3 + 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$ + 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl.. +Contents of section .options: + 0000 01200000 00000000 80000000 00000000 . .............. + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000000 00000000 00000000 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/comments.c b/tools/asm-processor/tests/comments.c new file mode 100644 index 00000000..4c936699 --- /dev/null +++ b/tools/asm-processor/tests/comments.c @@ -0,0 +1,6 @@ +const char before[] = "^"; +GLOBAL_ASM( +.rdata +.asciz "aaaa /* bbbb */ # cccc", /**//**//**//**/ /*/ "xxxx" /*/ /* dddd " eeee */ "# ffff" # gggg "hhhh" /* iiii */ +) +const char after[] = "$"; diff --git a/tools/asm-processor/tests/comments.objdump b/tools/asm-processor/tests/comments.objdump new file mode 100644 index 00000000..246df209 --- /dev/null +++ b/tools/asm-processor/tests/comments.objdump @@ -0,0 +1,21 @@ + +tests/comments.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .rodata 00000030 .rodata +00000000 g O .rodata 00000002 before +00000024 g O .rodata 00000002 after + + +Contents of section .rodata: + 0000 5e000000 61616161 202f2a20 62626262 ^...aaaa /* bbbb + 0010 202a2f20 23206363 63630023 20666666 */ # cccc.# fff + 0020 66000000 24000000 00000000 00000000 f...$........... +Contents of section .options: + 0000 01200000 00000000 00000000 00000000 . .............. + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/force.c b/tools/asm-processor/tests/force.c new file mode 100644 index 00000000..03b630c1 --- /dev/null +++ b/tools/asm-processor/tests/force.c @@ -0,0 +1,17 @@ +// COMPILE-FLAGS: -O2 +// ASMP-FLAGS: --convert-statics=global-with-filename --force +static int xtext(int a, int b, int c); +const int rodata1[] = {1}; +static const int rodata2[] = {2}; +int data1[] = {3}; +static int data2[] = {4}; +int bss1; +static int bss2; + +static int xtext(int a, int b, int c) { + return 1; +} + +void baz(void) { + xtext(bss2, rodata2[0], data2[0]); +} diff --git a/tools/asm-processor/tests/force.objdump b/tools/asm-processor/tests/force.objdump new file mode 100644 index 00000000..7ef70247 --- /dev/null +++ b/tools/asm-processor/tests/force.objdump @@ -0,0 +1,47 @@ + +tests/force.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000050 .text +00000000 l d .rodata 00000010 .rodata +00000000 l d .data 00000010 .data +00000000 l d .bss 00000010 .bss +00000000 g O .rodata 00000004 rodata1 +00000000 g O .data 00000004 data1 +00000000 g O .bss 00000004 bss1 +00000014 g F .text 00000034 baz +00000004 g O .rodata 00000000 tests/force.o:rodata2 +00000004 g O .data 00000000 tests/force.o:data2 +00000004 g O .bss 00000000 tests/force.o:bss2 +00000000 g F .text 00000000 tests/force.o:xtext + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +0000001c R_MIPS_HI16 .bss +00000034 R_MIPS_LO16 .bss +00000020 R_MIPS_HI16 .rodata +0000002c R_MIPS_LO16 .rodata +00000024 R_MIPS_HI16 .data +00000028 R_MIPS_LO16 .data +00000030 R_MIPS_26 .text + + +Contents of section .text: + 0000 afa40000 afa50004 afa60008 03e00008 ................ + 0010 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... + 0020 3c050000 3c060000 8cc60004 8ca50004 <...<........... + 0030 0c000000 8c840004 8fbf0014 27bd0018 ............'... + 0040 03e00008 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 00000001 00000002 00000000 00000000 ................ +Contents of section .data: + 0000 00000003 00000004 00000000 00000000 ................ +Contents of section .options: + 0000 01200000 00000000 a0000074 00000000 . .........t.... + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a0000074 00000000 00000000 00000000 ...t............ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/kpic-o1.c b/tools/asm-processor/tests/kpic-o1.c new file mode 100644 index 00000000..4d3346d2 --- /dev/null +++ b/tools/asm-processor/tests/kpic-o1.c @@ -0,0 +1,93 @@ +// COMPILE-FLAGS: -O1 -KPIC +GLOBAL_ASM( +glabel foo +addiu $a0, $a0, 1 +addiu $a0, $a0, 2 +addiu $a0, $a0, 3 +addiu $a0, $a0, 4 +addiu $a0, $a0, 5 +addiu $a0, $a0, 6 +addiu $a0, $a0, 7 +addiu $a0, $a0, 8 +addiu $a0, $a0, 9 +addiu $a0, $a0, 10 +addiu $a0, $a0, 11 +addiu $a0, $a0, 12 +) +GLOBAL_ASM( +.late_rodata +.float 1 +.text +glabel float_fn +addiu $a0, $a0, 13 +addiu $a0, $a0, 14 +addiu $a0, $a0, 15 +addiu $a0, $a0, 16 +addiu $a0, $a0, 17 +addiu $a0, $a0, 18 +addiu $a0, $a0, 19 +addiu $a0, $a0, 20 +addiu $a0, $a0, 21 +addiu $a0, $a0, 22 +addiu $a0, $a0, 23 +addiu $a0, $a0, 24 +addiu $a0, $a0, 25 +addiu $a0, $a0, 26 +addiu $a0, $a0, 27 +addiu $a0, $a0, 28 +addiu $a0, $a0, 29 +addiu $a0, $a0, 30 +) +GLOBAL_ASM( +.late_rodata +.late_rodata_alignment 4 +.float 2 +.double 1 +.double 2 +.double 3 +.double 4 +.double 5 +.double 6 +.double 7 +.double 8 +.text +glabel doubles +addiu $a0, $a0, 31 +addiu $a0, $a0, 32 +addiu $a0, $a0, 33 +addiu $a0, $a0, 34 +addiu $a0, $a0, 35 +addiu $a0, $a0, 36 +addiu $a0, $a0, 37 +addiu $a0, $a0, 38 +addiu $a0, $a0, 39 +addiu $a0, $a0, 40 +addiu $a0, $a0, 41 +addiu $a0, $a0, 42 +addiu $a0, $a0, 43 +addiu $a0, $a0, 44 +addiu $a0, $a0, 45 +addiu $a0, $a0, 46 +addiu $a0, $a0, 47 +addiu $a0, $a0, 48 +addiu $a0, $a0, 49 +addiu $a0, $a0, 50 +addiu $a0, $a0, 51 +addiu $a0, $a0, 52 +addiu $a0, $a0, 53 +addiu $a0, $a0, 54 +addiu $a0, $a0, 55 +addiu $a0, $a0, 56 +addiu $a0, $a0, 57 +addiu $a0, $a0, 58 +addiu $a0, $a0, 59 +addiu $a0, $a0, 60 +addiu $a0, $a0, 61 +addiu $a0, $a0, 62 +addiu $a0, $a0, 63 +addiu $a0, $a0, 64 +addiu $a0, $a0, 65 +addiu $a0, $a0, 66 +addiu $a0, $a0, 67 +addiu $a0, $a0, 68 +) diff --git a/tools/asm-processor/tests/kpic-o1.objdump b/tools/asm-processor/tests/kpic-o1.objdump new file mode 100644 index 00000000..6e336753 --- /dev/null +++ b/tools/asm-processor/tests/kpic-o1.objdump @@ -0,0 +1,46 @@ + +tests/kpic-o1.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000110 .text +00000000 l d .rodata 00000050 .rodata +00000000 g F .text 00000030 foo +00000030 g F .text 00000048 float_fn +00000078 g F .text 00000098 doubles +00000000 O *UND* 00000000 _gp_disp + + +RELOCATION RECORDS FOR [.text]: (none) + +Contents of section .text: + 0000 24840001 24840002 24840003 24840004 $...$...$...$... + 0010 24840005 24840006 24840007 24840008 $...$...$...$... + 0020 24840009 2484000a 2484000b 2484000c $...$...$...$... + 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$... + 0040 24840011 24840012 24840013 24840014 $...$...$...$... + 0050 24840015 24840016 24840017 24840018 $...$...$...$... + 0060 24840019 2484001a 2484001b 2484001c $...$...$...$... + 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$.. + 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$ + 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..( + 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$.., + 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0 + 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4 + 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8 + 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..< + 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@ + 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D +Contents of section .rodata: + 0000 3f800000 40000000 3ff00000 00000000 ?...@...?....... + 0010 40000000 00000000 40080000 00000000 @.......@....... + 0020 40100000 00000000 40140000 00000000 @.......@....... + 0030 40180000 00000000 401c0000 00000000 @.......@....... + 0040 40200000 00000000 00000000 00000000 @ .............. +Contents of section .options: + 0000 01200000 00000000 92000002 00000000 . .............. + 0010 000f0ff0 00000000 00000000 00000000 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 92000012 00000000 000f0ff0 00000000 ................ + 0010 00000000 00000000 ........ diff --git a/tools/asm-processor/tests/kpic-o2.c b/tools/asm-processor/tests/kpic-o2.c new file mode 100644 index 00000000..f037341c --- /dev/null +++ b/tools/asm-processor/tests/kpic-o2.c @@ -0,0 +1,92 @@ +// COMPILE-FLAGS: -O2 -KPIC +GLOBAL_ASM( +glabel foo +addiu $a0, $a0, 1 +addiu $a0, $a0, 2 +addiu $a0, $a0, 3 +addiu $a0, $a0, 4 +addiu $a0, $a0, 5 +addiu $a0, $a0, 6 +addiu $a0, $a0, 7 +addiu $a0, $a0, 8 +addiu $a0, $a0, 9 +addiu $a0, $a0, 10 +addiu $a0, $a0, 11 +addiu $a0, $a0, 12 +) +GLOBAL_ASM( +.late_rodata +.float 1 +.text +glabel float_fn +addiu $a0, $a0, 13 +addiu $a0, $a0, 14 +addiu $a0, $a0, 15 +addiu $a0, $a0, 16 +addiu $a0, $a0, 17 +addiu $a0, $a0, 18 +addiu $a0, $a0, 19 +addiu $a0, $a0, 20 +addiu $a0, $a0, 21 +addiu $a0, $a0, 22 +addiu $a0, $a0, 23 +addiu $a0, $a0, 24 +addiu $a0, $a0, 25 +addiu $a0, $a0, 26 +addiu $a0, $a0, 27 +addiu $a0, $a0, 28 +addiu $a0, $a0, 29 +addiu $a0, $a0, 30 +) +GLOBAL_ASM( +.late_rodata +.float 2 +.double 1 +.double 2 +.double 3 +.double 4 +.double 5 +.double 6 +.double 7 +.double 8 +.text +glabel doubles +addiu $a0, $a0, 31 +addiu $a0, $a0, 32 +addiu $a0, $a0, 33 +addiu $a0, $a0, 34 +addiu $a0, $a0, 35 +addiu $a0, $a0, 36 +addiu $a0, $a0, 37 +addiu $a0, $a0, 38 +addiu $a0, $a0, 39 +addiu $a0, $a0, 40 +addiu $a0, $a0, 41 +addiu $a0, $a0, 42 +addiu $a0, $a0, 43 +addiu $a0, $a0, 44 +addiu $a0, $a0, 45 +addiu $a0, $a0, 46 +addiu $a0, $a0, 47 +addiu $a0, $a0, 48 +addiu $a0, $a0, 49 +addiu $a0, $a0, 50 +addiu $a0, $a0, 51 +addiu $a0, $a0, 52 +addiu $a0, $a0, 53 +addiu $a0, $a0, 54 +addiu $a0, $a0, 55 +addiu $a0, $a0, 56 +addiu $a0, $a0, 57 +addiu $a0, $a0, 58 +addiu $a0, $a0, 59 +addiu $a0, $a0, 60 +addiu $a0, $a0, 61 +addiu $a0, $a0, 62 +addiu $a0, $a0, 63 +addiu $a0, $a0, 64 +addiu $a0, $a0, 65 +addiu $a0, $a0, 66 +addiu $a0, $a0, 67 +addiu $a0, $a0, 68 +) diff --git a/tools/asm-processor/tests/kpic-o2.objdump b/tools/asm-processor/tests/kpic-o2.objdump new file mode 100644 index 00000000..abf87aeb --- /dev/null +++ b/tools/asm-processor/tests/kpic-o2.objdump @@ -0,0 +1,46 @@ + +tests/kpic-o2.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000110 .text +00000000 l d .rodata 00000050 .rodata +00000000 g F .text 00000030 foo +00000030 g F .text 00000048 float_fn +00000078 g F .text 00000098 doubles +00000000 O *UND* 00000000 _gp_disp + + +RELOCATION RECORDS FOR [.text]: (none) + +Contents of section .text: + 0000 24840001 24840002 24840003 24840004 $...$...$...$... + 0010 24840005 24840006 24840007 24840008 $...$...$...$... + 0020 24840009 2484000a 2484000b 2484000c $...$...$...$... + 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$... + 0040 24840011 24840012 24840013 24840014 $...$...$...$... + 0050 24840015 24840016 24840017 24840018 $...$...$...$... + 0060 24840019 2484001a 2484001b 2484001c $...$...$...$... + 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$.. + 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$ + 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..( + 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$.., + 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0 + 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4 + 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8 + 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..< + 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@ + 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D +Contents of section .rodata: + 0000 3f800000 40000000 3ff00000 00000000 ?...@...?....... + 0010 40000000 00000000 40080000 00000000 @.......@....... + 0020 40100000 00000000 40140000 00000000 @.......@....... + 0030 40180000 00000000 401c0000 00000000 @.......@....... + 0040 40200000 00000000 00000000 00000000 @ .............. +Contents of section .options: + 0000 01200000 00000000 92000002 00000000 . .............. + 0010 000f0ff0 00000000 00000000 00000000 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 92000012 00000000 000f0ff0 00000000 ................ + 0010 00000000 00000000 ........ diff --git a/tools/asm-processor/tests/label-sameline.c b/tools/asm-processor/tests/label-sameline.c new file mode 100644 index 00000000..a35b43d8 --- /dev/null +++ b/tools/asm-processor/tests/label-sameline.c @@ -0,0 +1,7 @@ +GLOBAL_ASM( +.rdata +.word 0x12345678 +glabel blah +.word blah2 + /*a*/ blah2: /*b*/ .word blah /*c*/ +) diff --git a/tools/asm-processor/tests/label-sameline.objdump b/tools/asm-processor/tests/label-sameline.objdump new file mode 100644 index 00000000..1f1aacff --- /dev/null +++ b/tools/asm-processor/tests/label-sameline.objdump @@ -0,0 +1,25 @@ + +tests/label-sameline.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .rodata 00000010 .rodata +00000000 l d .rodata 00000000 +00000004 g .rodata 00000000 blah + + +RELOCATION RECORDS FOR [.rodata]: +OFFSET TYPE VALUE +00000004 R_MIPS_32 +00000008 R_MIPS_32 blah + + +Contents of section .rodata: + 0000 12345678 00000008 00000000 00000000 .4Vx............ +Contents of section .options: + 0000 01200000 00000000 00000000 00000000 . .............. + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/large.c b/tools/asm-processor/tests/large.c new file mode 100644 index 00000000..4ffb4ac1 --- /dev/null +++ b/tools/asm-processor/tests/large.c @@ -0,0 +1,164 @@ + +GLOBAL_ASM( +glabel test + +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 +addiu $sp, $sp, -24 + sw $zero, 4($sp) +lw $t6, 4($sp) +addu $t7, $a0, $t6 +sb $zero, ($t7) +lw $t8, 4($sp) +addiu $t9, $t8, 1 +slt $at, $t9, $a1 + sw $t9, 4($sp) + nop +jr $ra + addiu $sp, $sp, 24 + +) + +void foo(void) {} diff --git a/tools/asm-processor/tests/large.objdump b/tools/asm-processor/tests/large.objdump new file mode 100644 index 00000000..17409a7a --- /dev/null +++ b/tools/asm-processor/tests/large.objdump @@ -0,0 +1,58 @@ + +tests/large.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000280 .text +00000270 g F .text 00000010 foo +00000000 g F .text 00000270 test + + +Contents of section .text: + 0000 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0010 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0020 afb90004 00000000 03e00008 27bd0018 ............'... + 0030 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0040 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0050 afb90004 00000000 03e00008 27bd0018 ............'... + 0060 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0070 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0080 afb90004 00000000 03e00008 27bd0018 ............'... + 0090 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 00a0 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 00b0 afb90004 00000000 03e00008 27bd0018 ............'... + 00c0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 00d0 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 00e0 afb90004 00000000 03e00008 27bd0018 ............'... + 00f0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0100 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0110 afb90004 00000000 03e00008 27bd0018 ............'... + 0120 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0130 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0140 afb90004 00000000 03e00008 27bd0018 ............'... + 0150 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0160 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0170 afb90004 00000000 03e00008 27bd0018 ............'... + 0180 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0190 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 01a0 afb90004 00000000 03e00008 27bd0018 ............'... + 01b0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 01c0 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 01d0 afb90004 00000000 03e00008 27bd0018 ............'... + 01e0 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 01f0 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0200 afb90004 00000000 03e00008 27bd0018 ............'... + 0210 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0220 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0230 afb90004 00000000 03e00008 27bd0018 ............'... + 0240 27bdffe8 afa00004 8fae0004 008e7821 '.............x! + 0250 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0260 afb90004 00000000 03e00008 27bd0018 ............'... + 0270 03e00008 00000000 03e00008 00000000 ................ +Contents of section .options: + 0000 01200000 00000000 80000000 00000000 . .............. + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a300c032 00000000 00000000 00000000 ...2............ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_align.c b/tools/asm-processor/tests/late_rodata_align.c new file mode 100644 index 00000000..7367c792 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_align.c @@ -0,0 +1,80 @@ +GLOBAL_ASM( +.late_rodata + .float 4.1 + .float 4.2 + .float 4.3 + .float 4.4 +.text +glabel a + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float foo(void) { "foo"; return 1.1f; } + +GLOBAL_ASM( +.late_rodata +.late_rodata_alignment 4 + .float 5.1 + .float 5.2 + .float 5.3 + .float 5.4 +.text +glabel b + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float bar(void) { "bar"; return 1.2f; } + +GLOBAL_ASM( +.late_rodata +.late_rodata_alignment 8 + .float 6.1 + .float 6.2 + .float 6.3 + .float 6.4 + .float 6.5 +.text +glabel c + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + diff --git a/tools/asm-processor/tests/late_rodata_align.objdump b/tools/asm-processor/tests/late_rodata_align.objdump new file mode 100644 index 00000000..87c05e86 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_align.objdump @@ -0,0 +1,51 @@ + +tests/late_rodata_align.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000000f0 .text +00000000 l d .rodata 00000050 .rodata +00000040 g F .text 0000001c foo +00000090 g F .text 0000001c bar +00000000 g F .text 00000040 a +0000005c g F .text 00000034 b +000000ac g F .text 00000038 c + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000040 R_MIPS_HI16 .rodata +00000048 R_MIPS_LO16 .rodata +00000090 R_MIPS_HI16 .rodata +00000098 R_MIPS_LO16 .rodata + + +Contents of section .text: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00000000 00000000 00000000 ................ + 0020 00000000 00000000 00000000 00000000 ................ + 0030 00000000 00000000 00000000 00000000 ................ + 0040 3c010000 03e00008 c4200018 03e00008 <........ ...... + 0050 00000000 03e00008 00000000 00000000 ................ + 0060 00000000 00000000 00000000 00000000 ................ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 3c010000 03e00008 c420002c 03e00008 <........ .,.... + 00a0 00000000 03e00008 00000000 00000000 ................ + 00b0 00000000 00000000 00000000 00000000 ................ + 00c0 00000000 00000000 00000000 00000000 ................ + 00d0 00000000 00000000 00000000 00000000 ................ + 00e0 00000000 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 666f6f00 62617200 40833333 40866666 foo.bar.@.33@.ff + 0010 4089999a 408ccccd 3f8ccccd 40a33333 @...@...?...@.33 + 0020 40a66666 40a9999a 40accccd 3f99999a @.ff@...@...?... + 0030 40c33333 40c66666 40c9999a 40cccccd @.33@.ff@...@... + 0040 40d00000 00000000 00000000 00000000 @............... +Contents of section .options: + 0000 01200000 00000000 80000002 00000000 . .............. + 0010 000005f1 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000002 00000000 000005f1 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_doubles.c b/tools/asm-processor/tests/late_rodata_doubles.c new file mode 100644 index 00000000..0a27b414 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_doubles.c @@ -0,0 +1,83 @@ +GLOBAL_ASM( +.late_rodata + .float 4.1 +.text +glabel a + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float foo(void) { + return 4.15f; +} + +GLOBAL_ASM( +.late_rodata + .float 4.2 + .word 0 + .double 4.3 +.text +glabel b + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float bar(void) { + return 4.4f; +} + +GLOBAL_ASM( +.late_rodata + .float 4.55 + .double 4.6 +.text +glabel c + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float baz(void) { + return 4.6f; +} diff --git a/tools/asm-processor/tests/late_rodata_doubles.objdump b/tools/asm-processor/tests/late_rodata_doubles.objdump new file mode 100644 index 00000000..84d7e67f --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_doubles.objdump @@ -0,0 +1,55 @@ + +tests/late_rodata_doubles.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000120 .text +00000000 l d .rodata 00000030 .rodata +00000040 g F .text 0000001c foo +0000009c g F .text 0000001c bar +000000f8 g F .text 0000001c baz +00000000 g F .text 00000040 a +0000005c g F .text 00000040 b +000000b8 g F .text 00000040 c + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000040 R_MIPS_HI16 .rodata +00000048 R_MIPS_LO16 .rodata +0000009c R_MIPS_HI16 .rodata +000000a4 R_MIPS_LO16 .rodata +000000f8 R_MIPS_HI16 .rodata +00000100 R_MIPS_LO16 .rodata + + +Contents of section .text: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00000000 00000000 00000000 ................ + 0020 00000000 00000000 00000000 00000000 ................ + 0030 00000000 00000000 00000000 00000000 ................ + 0040 3c010000 03e00008 c4200004 03e00008 <........ ...... + 0050 00000000 03e00008 00000000 00000000 ................ + 0060 00000000 00000000 00000000 00000000 ................ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 00000000 00000000 00000000 3c010000 ............<... + 00a0 03e00008 c4200018 03e00008 00000000 ..... .......... + 00b0 03e00008 00000000 00000000 00000000 ................ + 00c0 00000000 00000000 00000000 00000000 ................ + 00d0 00000000 00000000 00000000 00000000 ................ + 00e0 00000000 00000000 00000000 00000000 ................ + 00f0 00000000 00000000 3c010000 03e00008 ........<....... + 0100 c4200028 03e00008 00000000 03e00008 . .(............ + 0110 00000000 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff.... + 0010 40113333 33333333 408ccccd 4091999a @.333333@...@... + 0020 40126666 66666666 40933333 00000000 @.ffffff@.33.... +Contents of section .options: + 0000 01200000 00000000 80000002 00000000 . .............. + 0010 000000f1 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000002 00000000 000000f1 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_doubles_mips1.c b/tools/asm-processor/tests/late_rodata_doubles_mips1.c new file mode 100644 index 00000000..b97261f6 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_doubles_mips1.c @@ -0,0 +1,86 @@ +// COMPILE-FLAGS: -O2 +// COMPILE-ISET: -mips1 +// exact copy of late_rodata_doubles.c except for the -mips1 -O2 additions +GLOBAL_ASM( +.late_rodata + .float 4.1 +.text +glabel a + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float foo(void) { + return 4.15f; +} + +GLOBAL_ASM( +.late_rodata + .float 4.2 + .word 0 + .double 4.3 +.text +glabel b + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float bar(void) { + return 4.4f; +} + +GLOBAL_ASM( +.late_rodata + .float 4.55 + .double 4.6 +.text +glabel c + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +float baz(void) { + return 4.6f; +} diff --git a/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump b/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump new file mode 100644 index 00000000..8fac85f4 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump @@ -0,0 +1,52 @@ + +tests/late_rodata_doubles_mips1.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000000f0 .text +00000000 l d .rodata 00000030 .rodata +00000040 g F .text 00000010 foo +00000090 g F .text 00000010 bar +000000e0 g F .text 00000010 baz +00000000 g F .text 00000040 a +00000050 g F .text 00000040 b +000000a0 g F .text 00000040 c + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000040 R_MIPS_HI16 .rodata +00000044 R_MIPS_LO16 .rodata +00000090 R_MIPS_HI16 .rodata +00000094 R_MIPS_LO16 .rodata +000000e0 R_MIPS_HI16 .rodata +000000e4 R_MIPS_LO16 .rodata + + +Contents of section .text: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00000000 00000000 00000000 ................ + 0020 00000000 00000000 00000000 00000000 ................ + 0030 00000000 00000000 00000000 00000000 ................ + 0040 3c010000 c4200004 03e00008 00000000 <.... .......... + 0050 00000000 00000000 00000000 00000000 ................ + 0060 00000000 00000000 00000000 00000000 ................ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 3c010000 c4200018 03e00008 00000000 <.... .......... + 00a0 00000000 00000000 00000000 00000000 ................ + 00b0 00000000 00000000 00000000 00000000 ................ + 00c0 00000000 00000000 00000000 00000000 ................ + 00d0 00000000 00000000 00000000 00000000 ................ + 00e0 3c010000 c4200028 03e00008 00000000 <.... .(........ +Contents of section .rodata: + 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff.... + 0010 40113333 33333333 408ccccd 4091999a @.333333@...@... + 0020 40126666 66666666 40933333 00000000 @.ffffff@.33.... +Contents of section .options: + 0000 01200000 00000000 80000002 00000000 . .............. + 0010 000c0011 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000002 00000000 000c0011 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_jtbl.c b/tools/asm-processor/tests/late_rodata_jtbl.c new file mode 100644 index 00000000..3c2a5bba --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_jtbl.c @@ -0,0 +1,153 @@ +// COMPILE-FLAGS: -O2 +GLOBAL_ASM( +.late_rodata +.double 1 +.double 2 +.double 3 +.double 4 +.double 5 +.double 6 +.double 7 +.double 8 +.text +glabel doubles1 +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +) + +float a(void) { return 1.1f; } + +GLOBAL_ASM( +.late_rodata +.float 1 +.double 2 +.double 3 +.double 4 +.double 5 +.double 6 +.double 7 +.double 8 +.double 9 +.float 10 +.text +glabel doubles2 +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +) + +GLOBAL_ASM( +glabel a2 +move $a0, $a0 +nop +nop +nop +jr $ra +move $a0, $a0 +) + +GLOBAL_ASM( +.late_rodata + +glabel jtbl +.word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10 +.word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20 +.word case21, case22, case23, case24, case25, case26 + +.text +glabel foo +sltiu $at, $a0, 0xa +beqz $at, .L756E659B + sll $t7, $a0, 2 +lui $at, %hi(jtbl) +addu $at, $at, $t7 +lw $t7, %lo(jtbl)($at) +jr $t7 + nop +case0: addiu $a0, $a0, 1 +case1: addiu $a0, $a0, 1 +case2: addiu $a0, $a0, 1 +case3: addiu $a0, $a0, 1 +case4: addiu $a0, $a0, 1 +case5: addiu $a0, $a0, 1 +case6: addiu $a0, $a0, 1 +case7: addiu $a0, $a0, 1 +case8: addiu $a0, $a0, 1 +case9: addiu $a0, $a0, 1 +case10: addiu $a0, $a0, 1 +case11: addiu $a0, $a0, 1 +case12: addiu $a0, $a0, 1 +case13: addiu $a0, $a0, 1 +case14: addiu $a0, $a0, 1 +case15: addiu $a0, $a0, 1 +case16: addiu $a0, $a0, 1 +case17: addiu $a0, $a0, 1 +case18: addiu $a0, $a0, 1 +case19: addiu $a0, $a0, 1 +case20: addiu $a0, $a0, 1 +case21: addiu $a0, $a0, 1 +case22: addiu $a0, $a0, 1 +case23: addiu $a0, $a0, 1 +case24: addiu $a0, $a0, 1 +case25: addiu $a0, $a0, 1 +case26: +jr $ra + addiu $v0, $a0, 1 + +.L756E659B: +addiu $v0, $zero, 2 +jr $ra + nop +) + +GLOBAL_ASM( +glabel b2 +move $a0, $a0 +nop +nop +jr $ra +move $a0, $a0 +) + +float b(void) { return 1.2f; } diff --git a/tools/asm-processor/tests/late_rodata_jtbl.objdump b/tools/asm-processor/tests/late_rodata_jtbl.objdump new file mode 100644 index 00000000..44bb6e84 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_jtbl.objdump @@ -0,0 +1,110 @@ + +tests/late_rodata_jtbl.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000001a0 .text +00000000 l d .rodata 00000100 .rodata +00000000 l d .text 00000000 +0000005c g F .text 0000000c a +0000018c g F .text 0000000c b +00000000 g F .text 0000005c doubles1 +00000068 g F .text 0000005c doubles2 +000000c4 g F .text 00000018 a2 +000000dc g F .text 0000009c foo +0000008c g .rodata 00000000 jtbl +00000178 g F .text 00000014 b2 + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +0000005c R_MIPS_HI16 .rodata +00000064 R_MIPS_LO16 .rodata +0000018c R_MIPS_HI16 .rodata +00000194 R_MIPS_LO16 .rodata +000000e8 R_MIPS_HI16 jtbl +000000f0 R_MIPS_LO16 jtbl + + +RELOCATION RECORDS FOR [.rodata]: +OFFSET TYPE VALUE +0000008c R_MIPS_32 +00000090 R_MIPS_32 +00000094 R_MIPS_32 +00000098 R_MIPS_32 +0000009c R_MIPS_32 +000000a0 R_MIPS_32 +000000a4 R_MIPS_32 +000000a8 R_MIPS_32 +000000ac R_MIPS_32 +000000b0 R_MIPS_32 +000000b4 R_MIPS_32 +000000b8 R_MIPS_32 +000000bc R_MIPS_32 +000000c0 R_MIPS_32 +000000c4 R_MIPS_32 +000000c8 R_MIPS_32 +000000cc R_MIPS_32 +000000d0 R_MIPS_32 +000000d4 R_MIPS_32 +000000d8 R_MIPS_32 +000000dc R_MIPS_32 +000000e0 R_MIPS_32 +000000e4 R_MIPS_32 +000000e8 R_MIPS_32 +000000ec R_MIPS_32 +000000f0 R_MIPS_32 +000000f4 R_MIPS_32 + + +Contents of section .text: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00000000 00000000 00000000 ................ + 0020 00000000 00000000 00000000 00000000 ................ + 0030 00000000 00000000 00000000 00000000 ................ + 0040 00000000 00000000 00000000 00000000 ................ + 0050 00000000 00000000 00000000 3c010000 ............<... + 0060 03e00008 c4200040 00000000 00000000 ..... .@........ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 00000000 00000000 00000000 00000000 ................ + 00a0 00000000 00000000 00000000 00000000 ................ + 00b0 00000000 00000000 00000000 00000000 ................ + 00c0 00000000 00802025 00000000 00000000 ...... %........ + 00d0 00000000 03e00008 00802025 2c81000a .......... %,... + 00e0 10200022 00047880 3c010000 002f0821 . ."..x.<..../.! + 00f0 8c2f0000 01e00008 00000000 24840001 ./..........$... + 0100 24840001 24840001 24840001 24840001 $...$...$...$... + 0110 24840001 24840001 24840001 24840001 $...$...$...$... + 0120 24840001 24840001 24840001 24840001 $...$...$...$... + 0130 24840001 24840001 24840001 24840001 $...$...$...$... + 0140 24840001 24840001 24840001 24840001 $...$...$...$... + 0150 24840001 24840001 24840001 24840001 $...$...$...$... + 0160 24840001 03e00008 24820001 24020002 $.......$...$... + 0170 03e00008 00000000 00802025 00000000 .......... %.... + 0180 00000000 03e00008 00802025 3c010000 .......... %<... + 0190 03e00008 c42000f8 00000000 00000000 ..... .......... +Contents of section .rodata: + 0000 3ff00000 00000000 40000000 00000000 ?.......@....... + 0010 40080000 00000000 40100000 00000000 @.......@....... + 0020 40140000 00000000 40180000 00000000 @.......@....... + 0030 401c0000 00000000 40200000 00000000 @.......@ ...... + 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@....... + 0050 40080000 00000000 40100000 00000000 @.......@....... + 0060 40140000 00000000 40180000 00000000 @.......@....... + 0070 401c0000 00000000 40200000 00000000 @.......@ ...... + 0080 40220000 00000000 41200000 000000fc @"......A ...... + 0090 00000100 00000104 00000108 0000010c ................ + 00a0 00000110 00000114 00000118 0000011c ................ + 00b0 00000120 00000124 00000128 0000012c ... ...$...(..., + 00c0 00000130 00000134 00000138 0000013c ...0...4...8...< + 00d0 00000140 00000144 00000148 0000014c ...@...D...H...L + 00e0 00000150 00000154 00000158 0000015c ...P...T...X...\ + 00f0 00000160 00000164 3f99999a 00000000 ...`...d?....... +Contents of section .options: + 0000 01200000 00000000 80004002 00000000 . ........@..... + 0010 000000f1 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 8000c016 00000000 000000f1 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_jtbl_mips1.c b/tools/asm-processor/tests/late_rodata_jtbl_mips1.c new file mode 100644 index 00000000..505f4c1d --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_jtbl_mips1.c @@ -0,0 +1,155 @@ +// COMPILE-FLAGS: -O2 +// COMPILE-ISET: -mips1 +// exact copy of late_rodata_jtbl.c except for the -mips1 addition +GLOBAL_ASM( +.late_rodata +.double 1 +.double 2 +.double 3 +.double 4 +.double 5 +.double 6 +.double 7 +.double 8 +.text +glabel doubles1 +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +) + +float a(void) { return 1.1f; } + +GLOBAL_ASM( +.late_rodata +.float 1 +.double 2 +.double 3 +.double 4 +.double 5 +.double 6 +.double 7 +.double 8 +.double 9 +.float 10 +.text +glabel doubles2 +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +) + +GLOBAL_ASM( +glabel a2 +move $a0, $a0 +nop +nop +nop +jr $ra +move $a0, $a0 +) + +GLOBAL_ASM( +.late_rodata + +glabel jtbl +.word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10 +.word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20 +.word case21, case22, case23, case24, case25, case26 + +.text +glabel foo +sltiu $at, $a0, 0xa +beqz $at, .L756E659B + sll $t7, $a0, 2 +lui $at, %hi(jtbl) +addu $at, $at, $t7 +lw $t7, %lo(jtbl)($at) +jr $t7 + nop +case0: addiu $a0, $a0, 1 +case1: addiu $a0, $a0, 1 +case2: addiu $a0, $a0, 1 +case3: addiu $a0, $a0, 1 +case4: addiu $a0, $a0, 1 +case5: addiu $a0, $a0, 1 +case6: addiu $a0, $a0, 1 +case7: addiu $a0, $a0, 1 +case8: addiu $a0, $a0, 1 +case9: addiu $a0, $a0, 1 +case10: addiu $a0, $a0, 1 +case11: addiu $a0, $a0, 1 +case12: addiu $a0, $a0, 1 +case13: addiu $a0, $a0, 1 +case14: addiu $a0, $a0, 1 +case15: addiu $a0, $a0, 1 +case16: addiu $a0, $a0, 1 +case17: addiu $a0, $a0, 1 +case18: addiu $a0, $a0, 1 +case19: addiu $a0, $a0, 1 +case20: addiu $a0, $a0, 1 +case21: addiu $a0, $a0, 1 +case22: addiu $a0, $a0, 1 +case23: addiu $a0, $a0, 1 +case24: addiu $a0, $a0, 1 +case25: addiu $a0, $a0, 1 +case26: +jr $ra + addiu $v0, $a0, 1 + +.L756E659B: +addiu $v0, $zero, 2 +jr $ra + nop +) + +GLOBAL_ASM( +glabel b2 +move $a0, $a0 +nop +nop +jr $ra +move $a0, $a0 +) + +float b(void) { return 1.2f; } diff --git a/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump b/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump new file mode 100644 index 00000000..d37c8bb9 --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump @@ -0,0 +1,110 @@ + +tests/late_rodata_jtbl_mips1.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000001a0 .text +00000000 l d .rodata 00000100 .rodata +00000000 l d .text 00000000 +0000005c g F .text 00000010 a +00000190 g F .text 00000010 b +00000000 g F .text 0000005c doubles1 +0000006c g F .text 0000005c doubles2 +000000c8 g F .text 00000018 a2 +000000e0 g F .text 0000009c foo +0000008c g .rodata 00000000 jtbl +0000017c g F .text 00000014 b2 + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +0000005c R_MIPS_HI16 .rodata +00000060 R_MIPS_LO16 .rodata +00000190 R_MIPS_HI16 .rodata +00000194 R_MIPS_LO16 .rodata +000000ec R_MIPS_HI16 jtbl +000000f4 R_MIPS_LO16 jtbl + + +RELOCATION RECORDS FOR [.rodata]: +OFFSET TYPE VALUE +0000008c R_MIPS_32 +00000090 R_MIPS_32 +00000094 R_MIPS_32 +00000098 R_MIPS_32 +0000009c R_MIPS_32 +000000a0 R_MIPS_32 +000000a4 R_MIPS_32 +000000a8 R_MIPS_32 +000000ac R_MIPS_32 +000000b0 R_MIPS_32 +000000b4 R_MIPS_32 +000000b8 R_MIPS_32 +000000bc R_MIPS_32 +000000c0 R_MIPS_32 +000000c4 R_MIPS_32 +000000c8 R_MIPS_32 +000000cc R_MIPS_32 +000000d0 R_MIPS_32 +000000d4 R_MIPS_32 +000000d8 R_MIPS_32 +000000dc R_MIPS_32 +000000e0 R_MIPS_32 +000000e4 R_MIPS_32 +000000e8 R_MIPS_32 +000000ec R_MIPS_32 +000000f0 R_MIPS_32 +000000f4 R_MIPS_32 + + +Contents of section .text: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00000000 00000000 00000000 ................ + 0020 00000000 00000000 00000000 00000000 ................ + 0030 00000000 00000000 00000000 00000000 ................ + 0040 00000000 00000000 00000000 00000000 ................ + 0050 00000000 00000000 00000000 3c010000 ............<... + 0060 c4200040 03e00008 00000000 00000000 . .@............ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 00000000 00000000 00000000 00000000 ................ + 00a0 00000000 00000000 00000000 00000000 ................ + 00b0 00000000 00000000 00000000 00000000 ................ + 00c0 00000000 00000000 00802025 00000000 .......... %.... + 00d0 00000000 00000000 03e00008 00802025 .............. % + 00e0 2c81000a 10200022 00047880 3c010000 ,.... ."..x.<... + 00f0 002f0821 8c2f0000 01e00008 00000000 ./.!./.......... + 0100 24840001 24840001 24840001 24840001 $...$...$...$... + 0110 24840001 24840001 24840001 24840001 $...$...$...$... + 0120 24840001 24840001 24840001 24840001 $...$...$...$... + 0130 24840001 24840001 24840001 24840001 $...$...$...$... + 0140 24840001 24840001 24840001 24840001 $...$...$...$... + 0150 24840001 24840001 24840001 24840001 $...$...$...$... + 0160 24840001 24840001 03e00008 24820001 $...$.......$... + 0170 24020002 03e00008 00000000 00802025 $............. % + 0180 00000000 00000000 03e00008 00802025 .............. % + 0190 3c010000 c42000f8 03e00008 00000000 <.... .......... +Contents of section .rodata: + 0000 3ff00000 00000000 40000000 00000000 ?.......@....... + 0010 40080000 00000000 40100000 00000000 @.......@....... + 0020 40140000 00000000 40180000 00000000 @.......@....... + 0030 401c0000 00000000 40200000 00000000 @.......@ ...... + 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@....... + 0050 40080000 00000000 40100000 00000000 @.......@....... + 0060 40140000 00000000 40180000 00000000 @.......@....... + 0070 401c0000 00000000 40200000 00000000 @.......@ ...... + 0080 40220000 00000000 41200000 00000100 @"......A ...... + 0090 00000104 00000108 0000010c 00000110 ................ + 00a0 00000114 00000118 0000011c 00000120 ............... + 00b0 00000124 00000128 0000012c 00000130 ...$...(...,...0 + 00c0 00000134 00000138 0000013c 00000140 ...4...8...<...@ + 00d0 00000144 00000148 0000014c 00000150 ...D...H...L...P + 00e0 00000154 00000158 0000015c 00000160 ...T...X...\...` + 00f0 00000164 00000168 3f99999a 00000000 ...d...h?....... +Contents of section .options: + 0000 01200000 00000000 80004002 00000000 . ........@..... + 0010 000000f1 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 8000c016 00000000 000000f1 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/late_rodata_misaligned_doubles.c b/tools/asm-processor/tests/late_rodata_misaligned_doubles.c new file mode 100644 index 00000000..a453dbdd --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_misaligned_doubles.c @@ -0,0 +1,77 @@ +GLOBAL_ASM( +.late_rodata + .float 4.01 + .word 0 + .double 4.02 +.text +glabel a + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +double foo(void) { return 4.03; } + +GLOBAL_ASM( +.late_rodata + .float 4.04 + .double 4.05 +.text +glabel b + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + +double bar(void) { return 4.06; } +float baz(void) { return 4.07f; } + +GLOBAL_ASM( +.late_rodata + .double 4.08 +.text +glabel c + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +) + diff --git a/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump b/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump new file mode 100644 index 00000000..cdba84de --- /dev/null +++ b/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump @@ -0,0 +1,56 @@ + +tests/late_rodata_misaligned_doubles.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000120 .text +00000000 l d .rodata 00000040 .rodata +00000040 g F .text 0000001c foo +0000009c g F .text 0000001c bar +000000b8 g F .text 0000001c baz +00000000 g F .text 00000040 a +0000005c g F .text 00000040 b +000000d4 g F .text 00000040 c + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000040 R_MIPS_HI16 .rodata +00000048 R_MIPS_LO16 .rodata +0000009c R_MIPS_HI16 .rodata +000000a4 R_MIPS_LO16 .rodata +000000b8 R_MIPS_HI16 .rodata +000000c0 R_MIPS_LO16 .rodata + + +Contents of section .text: + 0000 00000000 00000000 00000000 00000000 ................ + 0010 00000000 00000000 00000000 00000000 ................ + 0020 00000000 00000000 00000000 00000000 ................ + 0030 00000000 00000000 00000000 00000000 ................ + 0040 3c010000 03e00008 d4200010 03e00008 <........ ...... + 0050 00000000 03e00008 00000000 00000000 ................ + 0060 00000000 00000000 00000000 00000000 ................ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 00000000 00000000 00000000 3c010000 ............<... + 00a0 03e00008 d4200028 03e00008 00000000 ..... .(........ + 00b0 03e00008 00000000 3c010000 03e00008 ........<....... + 00c0 c4200030 03e00008 00000000 03e00008 . .0............ + 00d0 00000000 00000000 00000000 00000000 ................ + 00e0 00000000 00000000 00000000 00000000 ................ + 00f0 00000000 00000000 00000000 00000000 ................ + 0100 00000000 00000000 00000000 00000000 ................ + 0110 00000000 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 408051ec 00000000 4010147a e147ae14 @.Q.....@..z.G.. + 0010 40101eb8 51eb851f 00000000 408147ae @...Q.......@.G. + 0020 40103333 33333333 40103d70 a3d70a3d @.333333@.=p...= + 0030 40823d71 00000000 401051eb 851eb852 @.=q....@.Q....R +Contents of section .options: + 0000 01200000 00000000 80000002 00000000 . .............. + 0010 000000f3 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000002 00000000 000000f3 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/line-continuation-separate-file.s b/tools/asm-processor/tests/line-continuation-separate-file.s new file mode 100644 index 00000000..e1301804 --- /dev/null +++ b/tools/asm-processor/tests/line-continuation-separate-file.s @@ -0,0 +1,4 @@ +.rdata + label: .asciiz "1\n\ +2", \ + "34", "56" diff --git a/tools/asm-processor/tests/line-continuation.asmproc.d b/tools/asm-processor/tests/line-continuation.asmproc.d new file mode 100644 index 00000000..687dd1ae --- /dev/null +++ b/tools/asm-processor/tests/line-continuation.asmproc.d @@ -0,0 +1,3 @@ +tests/line-continuation.o: tests/line-continuation-separate-file.s + +tests/line-continuation-separate-file.s: diff --git a/tools/asm-processor/tests/line-continuation.c b/tools/asm-processor/tests/line-continuation.c new file mode 100644 index 00000000..d5ab0937 --- /dev/null +++ b/tools/asm-processor/tests/line-continuation.c @@ -0,0 +1,22 @@ +void foo(void) { "abcdef"; } + +GLOBAL_ASM( +.rdata + .ascii "AB" \ + "CD", "EF" + .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK" +) + +void bar(void) { "hello"; } + +GLOBAL_ASM( +.rdata + .asciiz "1\ +2" + .asciiz "34", "56" + .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A" +) + +void baz(void) { "ghijkl"; } + +GLOBAL_ASM("tests/line-continuation-separate-file.s") diff --git a/tools/asm-processor/tests/line-continuation.objdump b/tools/asm-processor/tests/line-continuation.objdump new file mode 100644 index 00000000..038766fd --- /dev/null +++ b/tools/asm-processor/tests/line-continuation.objdump @@ -0,0 +1,30 @@ + +tests/line-continuation.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000030 .text +00000000 l d .rodata 00000060 .rodata +00000000 g F .text 00000010 foo +00000010 g F .text 00000010 bar +00000020 g F .text 00000010 baz + + +Contents of section .text: + 0000 03e00008 00000000 03e00008 00000000 ................ + 0010 03e00008 00000000 03e00008 00000000 ................ + 0020 03e00008 00000000 03e00008 00000000 ................ +Contents of section .rodata: + 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH + 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ + 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3 + 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$ + 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl.. + 0050 310a3200 33340035 36000000 00000000 1.2.34.56....... +Contents of section .options: + 0000 01200000 00000000 80000000 00000000 . .............. + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000000 00000000 00000000 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/o0.c b/tools/asm-processor/tests/o0.c new file mode 100644 index 00000000..6f8e5e41 --- /dev/null +++ b/tools/asm-processor/tests/o0.c @@ -0,0 +1,28 @@ +// COMPILE-FLAGS: -O0 + +int a(void) { return 1; } +GLOBAL_ASM( +glabel foo +addiu $a0, $a0, 1 +addiu $a0, $a0, 2 +addiu $a0, $a0, 3 +jr $ra +addiu $a0, $a0, 4 +) +float b(void) { return 1.2f; } +GLOBAL_ASM( +.late_rodata +glabel float1 +.float 12.34 + +.text +glabel bar +addiu $a0, $a0, 5 +addiu $a0, $a0, 6 +addiu $a0, $a0, 7 +addiu $a0, $a0, 8 +lui $v0, %hi(float1 + 1) +jr $ra +addiu $v0, $v0, %lo(float1 + 1) +) +float c(void) { return 1.3f; } diff --git a/tools/asm-processor/tests/o0.objdump b/tools/asm-processor/tests/o0.objdump new file mode 100644 index 00000000..f94ec7a0 --- /dev/null +++ b/tools/asm-processor/tests/o0.objdump @@ -0,0 +1,44 @@ + +tests/o0.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000090 .text +00000000 l d .rodata 00000010 .rodata +00000000 g F .text 0000001c a +00000030 g F .text 00000020 b +0000006c g F .text 00000020 c +0000001c g F .text 00000014 foo +00000050 g F .text 0000001c bar +00000004 g .rodata 00000000 float1 + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000030 R_MIPS_HI16 .rodata +00000034 R_MIPS_LO16 .rodata +0000006c R_MIPS_HI16 .rodata +00000070 R_MIPS_LO16 .rodata +00000060 R_MIPS_HI16 float1 +00000068 R_MIPS_LO16 float1 + + +Contents of section .text: + 0000 24020001 03e00008 00000000 03e00008 $............... + 0010 00000000 03e00008 00000000 24840001 ............$... + 0020 24840002 24840003 03e00008 24840004 $...$.......$... + 0030 3c010000 c4200000 03e00008 00000000 <.... .......... + 0040 03e00008 00000000 03e00008 00000000 ................ + 0050 24840005 24840006 24840007 24840008 $...$...$...$... + 0060 3c020000 03e00008 24420001 3c010000 <.......$B..<... + 0070 c4200008 03e00008 00000000 03e00008 . .............. + 0080 00000000 03e00008 00000000 00000000 ................ +Contents of section .rodata: + 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff.... +Contents of section .options: + 0000 01200000 00000000 80000006 00000000 . .............. + 0010 00000011 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000016 00000000 00000011 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/o2.c b/tools/asm-processor/tests/o2.c new file mode 100644 index 00000000..144a604e --- /dev/null +++ b/tools/asm-processor/tests/o2.c @@ -0,0 +1,26 @@ +// COMPILE-FLAGS: -O2 + +int a(void) { return 1; } +GLOBAL_ASM( +glabel foo +addiu $a0, $a0, 1 +addiu $a0, $a0, 2 +addiu $a0, $a0, 3 +jr $ra +addiu $a0, $a0, 4 +) +float b(void) { return 1.2f; } +GLOBAL_ASM( +.late_rodata +glabel float1 +.float 12.34 + +.text +glabel bar +addiu $a0, $a0, 5 +addiu $a0, $a0, 6 +lui $v0, %hi(float1 + 1) +jr $ra +addiu $v0, $v0, %lo(float1 + 1) +) +float c(void) { return 1.3f; } diff --git a/tools/asm-processor/tests/o2.objdump b/tools/asm-processor/tests/o2.objdump new file mode 100644 index 00000000..61e3fb0e --- /dev/null +++ b/tools/asm-processor/tests/o2.objdump @@ -0,0 +1,40 @@ + +tests/o2.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000050 .text +00000000 l d .rodata 00000010 .rodata +00000000 g F .text 00000008 a +0000001c g F .text 0000000c b +0000003c g F .text 0000000c c +00000008 g F .text 00000014 foo +00000028 g F .text 00000014 bar +00000004 g .rodata 00000000 float1 + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +0000001c R_MIPS_HI16 .rodata +00000024 R_MIPS_LO16 .rodata +0000003c R_MIPS_HI16 .rodata +00000044 R_MIPS_LO16 .rodata +00000030 R_MIPS_HI16 float1 +00000038 R_MIPS_LO16 float1 + + +Contents of section .text: + 0000 03e00008 24020001 24840001 24840002 ....$...$...$... + 0010 24840003 03e00008 24840004 3c010000 $.......$...<... + 0020 03e00008 c4200000 24840005 24840006 ..... ..$...$... + 0030 3c020000 03e00008 24420001 3c010000 <.......$B..<... + 0040 03e00008 c4200008 00000000 00000000 ..... .......... +Contents of section .rodata: + 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff.... +Contents of section .options: + 0000 01200000 00000000 80000006 00000000 . .............. + 0010 00000011 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80000016 00000000 00000011 00000000 ................ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/pascal.objdump b/tools/asm-processor/tests/pascal.objdump new file mode 100644 index 00000000..cb3740f0 --- /dev/null +++ b/tools/asm-processor/tests/pascal.objdump @@ -0,0 +1,137 @@ + +tests/pascal.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000000e0 .text +00000000 l d .rodata 00000030 .rodata +00000000 l d .data 00000010 .data +00000000 l d .bss 00000010 .bss +00000000 l O .bss 00000000 $dat +00000000 g F .text 0000000c foo +000000d0 g F .text 0000000c bar +0000000c g F .text 00000004 test +00000048 g F .text 00000004 test2 +0000008c g F .text 00000044 test3 +00000000 *UND* 00000000 get +00000000 *UND* 00000000 put +00000000 *UND* 00000000 pascal_close +00000000 *UND* 00000000 fflush +00000000 *UND* 00000000 filesize +00000000 *UND* 00000000 curpos +00000000 *UND* 00000000 seek +00000000 *UND* 00000000 eof +00000000 *UND* 00000000 eoln +00000000 *UND* 00000000 page +00000000 *UND* 00000000 reset +00000000 *UND* 00000000 rewrite +00000000 *UND* 00000000 cos +00000000 *UND* 00000000 exp +00000000 *UND* 00000000 sqrt +00000000 *UND* 00000000 log +00000000 *UND* 00000000 atan +00000000 *UND* 00000000 sin +00000000 *UND* 00000000 __random_float +00000000 *UND* 00000000 clock +00000000 *UND* 00000000 exit +00000000 *UND* 00000000 __date +00000000 *UND* 00000000 __time +00000000 *UND* 00000000 get_arg +00000000 *UND* 00000000 new +00000000 *UND* 00000000 dispose +00000000 *UND* 00000000 initfile +00000000 *UND* 00000000 peek_char +00000000 *UND* 00000000 next_char +00000000 *UND* 00000000 readln +00000000 *UND* 00000000 read_int64 +00000000 *UND* 00000000 read_card64 +00000000 *UND* 00000000 read_integer +00000000 *UND* 00000000 read_cardinal +00000000 *UND* 00000000 read_integer_range +00000000 *UND* 00000000 read_real +00000000 *UND* 00000000 read_double +00000000 *UND* 00000000 read_extended +00000000 *UND* 00000000 read_string +00000000 *UND* 00000000 read_enum +00000000 *UND* 00000000 read_char +00000000 *UND* 00000000 read_char_range +00000000 *UND* 00000000 read_boolean +00000000 *UND* 00000000 read_set +00000000 *UND* 00000000 writeln +00000000 *UND* 00000000 write_int64 +00000000 *UND* 00000000 write_card64 +00000000 *UND* 00000000 write_integer +00000000 *UND* 00000000 write_cardinal +00000000 *UND* 00000000 write_boolean +00000000 *UND* 00000000 write_char +00000000 *UND* 00000000 write_real +00000000 *UND* 00000000 write_double +00000000 *UND* 00000000 write_extended +00000000 *UND* 00000000 write_string +00000000 *UND* 00000000 write_enum +00000000 *UND* 00000000 write_set +00000000 *UND* 00000000 caseerror +00000000 *UND* 00000000 __pc_nloc_goto +00000000 *UND* 00000000 memcpy +00000000 *UND* 00000000 __in_range +00000000 *UND* 00000000 __ll_mul +00000000 *UND* 00000000 __ll_div +00000000 *UND* 00000000 __ull_div +00000000 *UND* 00000000 __ll_mod +00000000 *UND* 00000000 __ll_rem +00000000 *UND* 00000000 __ull_rem +00000000 *UND* 00000000 __ll_lshift +00000000 *UND* 00000000 __ll_rshift +00000000 *UND* 00000000 __ll_to_f +00000000 *UND* 00000000 __ull_to_f +00000000 *UND* 00000000 __ll_to_d +00000000 *UND* 00000000 __ull_to_d +00000000 *UND* 00000000 __f_ll_ll +00000000 *UND* 00000000 __f_to_ull +00000000 *UND* 00000000 __d_to_ll +00000000 *UND* 00000000 __d_to_ull +00000000 *UND* 00000000 round64 +00000000 *UND* 00000000 trunc64 +00000000 *UND* 00000000 max64 +00000000 *UND* 00000000 min64 +00000000 *UND* 00000000 abs64 +00000000 *UND* 00000000 odd64 +00000000 *UND* 00000000 trapNaN +00000000 *UND* 00000008 input +00000000 *UND* 00000008 output +00000000 *UND* 00000008 err +00000000 *UND* 00000008 __Argc + + +RELOCATION RECORDS FOR [.text]: (none) + +RELOCATION RECORDS FOR [.rodata]: (none) + +Contents of section .text: + 0000 00041080 03e00008 00441023 27bdffe8 .........D.#'... + 0010 18a00009 afa00004 8fae0004 008e7821 ..............x! + 0020 a1e00000 8fb80004 27190001 0325082a ........'....%.* + 0030 1420fff9 afb90004 10000001 00000000 . .............. + 0040 03e00008 27bd0018 00000000 00000000 ....'........... + 0050 00000000 00000000 00000000 00000000 ................ + 0060 00000000 00000000 00000000 00000000 ................ + 0070 00000000 00000000 00000000 00000000 ................ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 00000000 00000000 00000000 00000000 ................ + 00a0 00000000 00000000 00000000 00000000 ................ + 00b0 00000000 00000000 00000000 00000000 ................ + 00c0 00000000 00000000 00000000 00000000 ................ + 00d0 00041080 03e00008 00441023 00000000 .........D.#.... +Contents of section .rodata: + 0000 00123123 00456456 00789789 00000001 ..1#.EdV.x...... + 0010 3ff19999 9999999a 00000002 00000003 ?............... + 0020 4000cccc cccccccd 00000000 00000000 @............... +Contents of section .data: + 0000 00002323 00003434 00000000 00000000 ..##..44........ +Contents of section .options: + 0000 01200000 00000000 80004016 00000000 . ........@..... + 0010 000000f0 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a300c036 00000000 000000f0 00000000 ...6............ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/pascal.p b/tools/asm-processor/tests/pascal.p new file mode 100644 index 00000000..0886126a --- /dev/null +++ b/tools/asm-processor/tests/pascal.p @@ -0,0 +1,95 @@ +{ COMPILE-FLAGS: -O2 } + +function foo(x: integer): integer; +begin + foo := x * 3 +end; + +GLOBAL_ASM( +.section .data +.word 0x2323 + +.late_rodata +.word 0x123123 +.word 0x456456 +.word 0x789789 +.text +glabel test +/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 +/* 000094 00400094 18A00009 */ blez $a1, .L004000BC +/* 000098 00400098 AFA00004 */ sw $zero, 4($sp) +.L0040009C: +/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) +/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 +/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) +/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) +/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 +/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 +/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C +/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) +.L004000BC: +/* 0000BC 004000BC 10000001 */ b .L004000C4 +/* 0000C0 004000C0 00000000 */ nop +.L004000C4: +/* 0000C4 004000C4 03E00008 */ jr $ra +/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 +) + +GLOBAL_ASM( +.section .data +.word 0x3434 + +.late_rodata +.word 0x1 +.double 1.1 +.word 0x2, 0x3 +.text +glabel test2 +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +) + +GLOBAL_ASM( +.late_rodata +.double 2.1 +.text +glabel test3 +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +nop +) + +function bar(x: integer): integer; +begin + return x * 3 +end; + diff --git a/tools/asm-processor/tests/static-global.c b/tools/asm-processor/tests/static-global.c new file mode 100644 index 00000000..a7f61690 --- /dev/null +++ b/tools/asm-processor/tests/static-global.c @@ -0,0 +1,33 @@ +// COMPILE-FLAGS: -O2 +// ASMP-FLAGS: --convert-statics=global +static int xtext(int a, int b, int c); +const int rodata1[] = {1}; +static const int rodata2[] = {2}; +int data1[] = {3}; +static int data2[] = {4}; +int bss1; +static int bss2; + +GLOBAL_ASM( +glabel bar +lui $a0, %hi(rodata2) +lw $a0, %lo(rodata2)($a0) +lui $a1, %hi(data2) +lw $a1, %lo(data2)($a0) +lui $a2, %hi(bss2) +lw $a2, %lo(bss2)($a0) +jal xtext +nop +jr $ra +nop +nop +nop +) + +static int xtext(int a, int b, int c) { + return 1; +} + +void baz(void) { + xtext(bss2, rodata2[0], data2[0]); +} diff --git a/tools/asm-processor/tests/static-global.objdump b/tools/asm-processor/tests/static-global.objdump new file mode 100644 index 00000000..a519e4f4 --- /dev/null +++ b/tools/asm-processor/tests/static-global.objdump @@ -0,0 +1,58 @@ + +tests/static-global.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000080 .text +00000000 l d .rodata 00000010 .rodata +00000000 l d .data 00000010 .data +00000000 l d .bss 00000010 .bss +00000000 g O .rodata 00000004 rodata1 +00000000 g O .data 00000004 data1 +00000000 g O .bss 00000004 bss1 +00000044 g F .text 00000034 baz +00000000 g F .text 00000030 bar +00000004 g O .rodata 00000000 rodata2 +00000004 g O .data 00000000 data2 +00000004 g O .bss 00000000 bss2 +00000030 g F .text 00000000 xtext + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +0000004c R_MIPS_HI16 .bss +00000064 R_MIPS_LO16 .bss +00000050 R_MIPS_HI16 .rodata +0000005c R_MIPS_LO16 .rodata +00000054 R_MIPS_HI16 .data +00000058 R_MIPS_LO16 .data +00000060 R_MIPS_26 .text +00000000 R_MIPS_HI16 rodata2 +00000004 R_MIPS_LO16 rodata2 +00000008 R_MIPS_HI16 data2 +0000000c R_MIPS_LO16 data2 +00000010 R_MIPS_HI16 bss2 +00000014 R_MIPS_LO16 bss2 +00000018 R_MIPS_26 xtext + + +Contents of section .text: + 0000 3c040000 8c840000 3c050000 8c850000 <.......<....... + 0010 3c060000 8c860000 0c000000 00000000 <............... + 0020 03e00008 00000000 00000000 00000000 ................ + 0030 afa40000 afa50004 afa60008 03e00008 ................ + 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... + 0050 3c050000 3c060000 8cc60004 8ca50004 <...<........... + 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'... + 0070 03e00008 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 00000001 00000002 00000000 00000000 ................ +Contents of section .data: + 0000 00000003 00000004 00000000 00000000 ................ +Contents of section .options: + 0000 01200000 00000000 a0000074 00000000 . .........t.... + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a0000074 00000000 00000000 00000000 ...t............ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/static.c b/tools/asm-processor/tests/static.c new file mode 100644 index 00000000..c265021e --- /dev/null +++ b/tools/asm-processor/tests/static.c @@ -0,0 +1,32 @@ +// COMPILE-FLAGS: -O2 +static int xtext(int a, int b, int c); +const int rodata1[] = {1}; +static const int rodata2[] = {2}; +int data1[] = {3}; +static int data2[] = {4}; +int bss1; +static int bss2; + +GLOBAL_ASM( +glabel bar +lui $a0, %hi(rodata2) +lw $a0, %lo(rodata2)($a0) +lui $a1, %hi(data2) +lw $a1, %lo(data2)($a0) +lui $a2, %hi(bss2) +lw $a2, %lo(bss2)($a0) +jal xtext +nop +jr $ra +nop +nop +nop +) + +static int xtext(int a, int b, int c) { + return 1; +} + +void baz(void) { + xtext(bss2, rodata2[0], data2[0]); +} diff --git a/tools/asm-processor/tests/static.objdump b/tools/asm-processor/tests/static.objdump new file mode 100644 index 00000000..dd62c94c --- /dev/null +++ b/tools/asm-processor/tests/static.objdump @@ -0,0 +1,58 @@ + +tests/static.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 00000080 .text +00000000 l d .rodata 00000010 .rodata +00000000 l d .data 00000010 .data +00000000 l d .bss 00000010 .bss +00000004 l O .rodata 00000000 rodata2 +00000004 l O .data 00000000 data2 +00000004 l O .bss 00000000 bss2 +00000030 l F .text 00000000 xtext +00000000 g O .rodata 00000004 rodata1 +00000000 g O .data 00000004 data1 +00000000 g O .bss 00000004 bss1 +00000044 g F .text 00000034 baz +00000000 g F .text 00000030 bar + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +0000004c R_MIPS_HI16 .bss +00000064 R_MIPS_LO16 .bss +00000050 R_MIPS_HI16 .rodata +0000005c R_MIPS_LO16 .rodata +00000054 R_MIPS_HI16 .data +00000058 R_MIPS_LO16 .data +00000060 R_MIPS_26 .text +00000000 R_MIPS_HI16 rodata2 +00000004 R_MIPS_LO16 rodata2 +00000008 R_MIPS_HI16 data2 +0000000c R_MIPS_LO16 data2 +00000010 R_MIPS_HI16 bss2 +00000014 R_MIPS_LO16 bss2 +00000018 R_MIPS_26 xtext + + +Contents of section .text: + 0000 3c040000 8c840000 3c050000 8c850000 <.......<....... + 0010 3c060000 8c860000 0c000000 00000000 <............... + 0020 03e00008 00000000 00000000 00000000 ................ + 0030 afa40000 afa50004 afa60008 03e00008 ................ + 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<... + 0050 3c050000 3c060000 8cc60004 8ca50004 <...<........... + 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'... + 0070 03e00008 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 00000001 00000002 00000000 00000000 ................ +Contents of section .data: + 0000 00000003 00000004 00000000 00000000 ................ +Contents of section .options: + 0000 01200000 00000000 a0000074 00000000 . .........t.... + 0010 00000000 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a0000074 00000000 00000000 00000000 ...t............ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/test1.c b/tools/asm-processor/tests/test1.c new file mode 100644 index 00000000..475555a7 --- /dev/null +++ b/tools/asm-processor/tests/test1.c @@ -0,0 +1,71 @@ + +GLOBAL_ASM( +.rdata +.word 0x1212 +) + +GLOBAL_ASM( +.late_rodata +.word 0x123123 +.text +glabel test +/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 +/* 000094 00400094 18A00009 */ blez $a1, .L004000BC +/* 000098 00400098 AFA00004 */ sw $zero, 4($sp) +.L0040009C: +/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) +/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 +/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) +/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) +/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 +/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 +/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C +/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) +.L004000BC: +/* 0000BC 004000BC 10000001 */ b .L004000C4 +/* 0000C0 004000C0 00000000 */ nop +.L004000C4: +/* 0000C4 004000C4 03E00008 */ jr $ra +/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 +) + +char bss1[3]; +GLOBAL_ASM( +.bss +bss2: +.space 3 +) +char bss3[3]; +char bss4[3]; +const int rodata1[2] = {1}; +extern int some_rodata; + +unsigned g(float, int); +unsigned f(void) { + return g(1.1f, some_rodata); +} + +GLOBAL_ASM( +.rdata +glabel some_rodata +.word 0x1313 +.text +.late_rodata +.word 0x321321 +.text +glabel g +/* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18 +/* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp) +/* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4 +/* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100) +/* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at) +/* 0000D4 004000D4 0C10002C */ jal func_004000B0 +/* 0000D8 004000D8 00000000 */ nop +/* 0000DC 004000DC 10000001 */ b .L004000E4 +/* 0000E0 004000E0 00000000 */ nop +.L004000E4: +/* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp) +/* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18 +/* 0000EC 004000EC 03E00008 */ jr $ra +/* 0000F0 004000F0 00000000 */ nop +) diff --git a/tools/asm-processor/tests/test1.objdump b/tools/asm-processor/tests/test1.objdump new file mode 100644 index 00000000..b97ae46e --- /dev/null +++ b/tools/asm-processor/tests/test1.objdump @@ -0,0 +1,54 @@ + +tests/test1.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000000b0 .text +00000000 l d .rodata 00000020 .rodata +00000000 l d .bss 00000010 .bss +00000000 g O .bss 00000003 bss1 +00000008 g O .bss 00000003 bss3 +0000000c g O .bss 00000003 bss4 +00000004 g O .rodata 00000008 rodata1 +0000003c g F .text 0000003c f +00000000 g F .text 0000003c test +0000000c g .rodata 00000000 some_rodata +00000078 g F .text 00000004 g +00000000 *UND* 00000000 D_410100 +00000000 *UND* 00000000 func_004000B0 + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000044 R_MIPS_HI16 .rodata +00000054 R_MIPS_LO16 .rodata +00000048 R_MIPS_HI16 some_rodata +0000004c R_MIPS_LO16 some_rodata +00000050 R_MIPS_26 g +00000084 R_MIPS_HI16 D_410100 +00000088 R_MIPS_LO16 D_410100 +0000008c R_MIPS_26 func_004000B0 + + +Contents of section .text: + 0000 27bdffe8 18a00009 afa00004 8fae0004 '............... + 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'... + 0020 0325082a 1420fff9 afb90004 10000001 .%.*. .......... + 0030 00000000 03e00008 27bd0018 27bdffe8 ........'...'... + 0040 afbf0014 3c010000 3c050000 8ca50000 ....<...<....... + 0050 0c000000 c42c0014 10000003 00000000 .....,.......... + 0060 10000001 00000000 8fbf0014 27bd0018 ............'... + 0070 03e00008 00000000 27bdffe8 afbf0014 ........'....... + 0080 240e0004 3c010000 ac2e0000 0c000000 $...<........... + 0090 00000000 10000001 00000000 8fbf0014 ................ + 00a0 27bd0018 03e00008 00000000 00000000 '............... +Contents of section .rodata: + 0000 00001212 00000001 00000000 00001313 ................ + 0010 00123123 3f8ccccd 00321321 00000000 ..1#?....2.!.... +Contents of section .options: + 0000 01200000 00000000 a0000022 00000000 . .........".... + 0010 00001010 00000000 00000000 00007ff0 ................ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a300c032 00000000 00001010 00000000 ...2............ + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/test2.c b/tools/asm-processor/tests/test2.c new file mode 100644 index 00000000..15969feb --- /dev/null +++ b/tools/asm-processor/tests/test2.c @@ -0,0 +1,69 @@ +const char buf1[1] = {1}; +float func1(void) { + "func1"; + return 0.1f; +} +const char buf2[1] = {2}; +void func2(void) { + *(volatile float*)0 = -3.5792360305786133f; + *(volatile float*)0 = -3.5792362689971924f; + // "func2"; + // return 0.2f; +} +const char buf3[1] = {3}; +int func3(int x) { + switch(x) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 3; + case 3: + return 4; + case 4: + return 5; + case 5: + return 4; + case 6: + return 4; + case 7: + return 4; + default: + return 3; + } +} + +#if 1 +GLOBAL_ASM( +.rdata +.word 0x66756e63 # func +.word 0x34000000 # 4\0\0\0 +.word jumptarget + 4 + +.late_rodata +glabel rv +.word 0x3e4ccccd # 0.2f +.word jumptarget + 8 + +.text +glabel func4 +lui $at, %hi(rv) +glabel jumptarget +jr $ra +lwc1 $f0, %lo(rv)($at) +jr $ra +nop +jr $ra +nop +jr $ra +nop +jr $ra +nop +) +#else +float func4(void) { + "func4"; + return 0.2f; +} +#endif diff --git a/tools/asm-processor/tests/test2.objdump b/tools/asm-processor/tests/test2.objdump new file mode 100644 index 00000000..276ed9f1 --- /dev/null +++ b/tools/asm-processor/tests/test2.objdump @@ -0,0 +1,76 @@ + +tests/test2.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000000f0 .text +00000000 l d .rodata 00000060 .rodata +00000000 g O .rodata 00000001 buf1 +00000000 g F .text 0000001c func1 +0000000c g O .rodata 00000001 buf2 +0000001c g F .text 00000028 func2 +00000010 g O .rodata 00000001 buf3 +00000044 g F .text 0000007c func3 +000000c4 g F .text 00000000 jumptarget +000000c0 g F .text 0000000c func4 +0000004c g .rodata 00000000 rv + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000000 R_MIPS_HI16 .rodata +00000008 R_MIPS_LO16 .rodata +0000001c R_MIPS_HI16 .rodata +00000020 R_MIPS_LO16 .rodata +00000028 R_MIPS_HI16 .rodata +0000002c R_MIPS_LO16 .rodata +00000054 R_MIPS_HI16 .rodata +0000005c R_MIPS_LO16 .rodata +000000c0 R_MIPS_HI16 rv +000000c8 R_MIPS_LO16 rv + + +RELOCATION RECORDS FOR [.rodata]: +OFFSET TYPE VALUE +0000002c R_MIPS_32 .text +00000030 R_MIPS_32 .text +00000034 R_MIPS_32 .text +00000038 R_MIPS_32 .text +0000003c R_MIPS_32 .text +00000040 R_MIPS_32 .text +00000044 R_MIPS_32 .text +00000048 R_MIPS_32 .text +0000001c R_MIPS_32 jumptarget +00000050 R_MIPS_32 jumptarget + + +Contents of section .text: + 0000 3c010000 03e00008 c4200020 03e00008 <........ . .... + 0010 00000000 03e00008 00000000 3c010000 ............<... + 0020 c4240024 e4040000 3c010000 c4260028 .$.$....<....&.( + 0030 e4060000 03e00008 00000000 03e00008 ................ + 0040 00000000 2c810008 10200017 00000000 ....,.... ...... + 0050 00047080 3c010000 002e0821 8c2e002c ..p.<......!..., + 0060 01c00008 00000000 03e00008 24020001 ............$... + 0070 03e00008 24020002 03e00008 24020003 ....$.......$... + 0080 03e00008 24020004 03e00008 24020005 ....$.......$... + 0090 03e00008 24020004 03e00008 24020004 ....$.......$... + 00a0 03e00008 24020004 03e00008 24020003 ....$.......$... + 00b0 03e00008 00000000 03e00008 00000000 ................ + 00c0 3c010000 03e00008 c4200000 03e00008 <........ ...... + 00d0 00000000 03e00008 00000000 03e00008 ................ + 00e0 00000000 03e00008 00000000 00000000 ................ +Contents of section .rodata: + 0000 01000000 66756e63 31000000 02000000 ....func1....... + 0010 03000000 66756e63 34000000 00000004 ....func4....... + 0020 3dcccccd c0651234 c0651235 00000068 =....e.4.e.5...h + 0030 00000070 00000078 00000080 00000088 ...p...x........ + 0040 00000090 00000098 000000a0 3e4ccccd ............>L.. + 0050 00000008 00000000 00000000 00000000 ................ +Contents of section .options: + 0000 01200000 00000000 80004016 00000000 . ........@..... + 0010 00000051 00000000 00000000 00007ff0 ...Q............ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 80004016 00000000 00000051 00000000 ..@........Q.... + 0010 00000000 00007ff0 ........ diff --git a/tools/asm-processor/tests/test3.c b/tools/asm-processor/tests/test3.c new file mode 100644 index 00000000..d74bb4cb --- /dev/null +++ b/tools/asm-processor/tests/test3.c @@ -0,0 +1,70 @@ + +GLOBAL_ASM( +.rdata +.word 321321 +.text +glabel test +/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24 +/* 000094 00400094 18A00009 */ blez $a1, .L004000BC +/* 000098 00400098 AFA00004 */ sw $zero, 4($sp) +.L0040009C: +/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp) +/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6 +/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7) +/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp) +/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1 +/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1 +/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C +/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp) +.L004000BC: +/* 0000BC 004000BC 10000001 */ b .L004000C4 +/* 0000C0 004000C0 00000000 */ nop +.L004000C4: +/* 0000C4 004000C4 03E00008 */ jr $ra +/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24 +) + +// static -> no symbols +// bss +char globalBuf[4]; +const char constBuf[4]; + +// data +char globalBufInit[4] = {1}; + +// rodata +const char constBufInit[4] = {1}; +const char constBufInit2[1] = {2}; +const char constBufInit3[1] = {3}; + +unsigned g(void); +unsigned f(void) { + // aligns to 4 or 8 byte boundary (char -> 4, double -> 8) + double x = 5.1; + float y = 5.2f; + float z = 5.3f; + "Hello "; + "World"; + return g(); +} + +GLOBAL_ASM( +.rdata +.word 123123 +.text +glabel g +/* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18 +/* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp) +/* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4 +/* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100) +/* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at) +/* 0000D4 004000D4 0C10002C */ jal func_004000B0 +/* 0000D8 004000D8 00000000 */ nop +/* 0000DC 004000DC 10000001 */ b .L004000E4 +/* 0000E0 004000E0 00000000 */ nop +.L004000E4: +/* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp) +/* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18 +/* 0000EC 004000EC 03E00008 */ jr $ra +/* 0000F0 004000F0 00000000 */ nop +) diff --git a/tools/asm-processor/tests/test3.objdump b/tools/asm-processor/tests/test3.objdump new file mode 100644 index 00000000..bfa7f6e3 --- /dev/null +++ b/tools/asm-processor/tests/test3.objdump @@ -0,0 +1,64 @@ + +tests/test3.o: file format elf32-tradbigmips + +SYMBOL TABLE: +00000000 l d .text 000000d0 .text +00000000 l d .rodata 00000040 .rodata +00000000 l d .data 00000010 .data +00000000 l d .bss 00000010 .bss +00000000 g O .bss 00000004 globalBuf +00000004 g O .bss 00000004 constBuf +00000000 g O .data 00000004 globalBufInit +00000004 g O .rodata 00000004 constBufInit +00000008 g O .rodata 00000001 constBufInit2 +0000000c g O .rodata 00000001 constBufInit3 +0000003c g F .text 00000054 f +00000000 g F .text 00000004 test +00000090 g F .text 00000004 g +00000000 *UND* 00000000 D_410100 +00000000 *UND* 00000000 func_004000B0 + + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +00000044 R_MIPS_HI16 .rodata +00000048 R_MIPS_LO16 .rodata +00000050 R_MIPS_HI16 .rodata +00000054 R_MIPS_LO16 .rodata +0000005c R_MIPS_HI16 .rodata +00000060 R_MIPS_LO16 .rodata +00000068 R_MIPS_26 g +0000009c R_MIPS_HI16 D_410100 +000000a0 R_MIPS_LO16 D_410100 +000000a4 R_MIPS_26 func_004000B0 + + +Contents of section .text: + 0000 27bdffe8 18a00009 afa00004 8fae0004 '............... + 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'... + 0020 0325082a 1420fff9 afb90004 10000001 .%.*. .......... + 0030 00000000 03e00008 27bd0018 27bdffd8 ........'...'... + 0040 afbf0014 3c010000 d4240028 f7a40020 ....<....$.(... + 0050 3c010000 c4260030 e7a6001c 3c010000 <....&.0....<... + 0060 c4280034 e7a80018 0c000000 00000000 .(.4............ + 0070 10000003 00000000 10000001 00000000 ................ + 0080 8fbf0014 27bd0028 03e00008 00000000 ....'..(........ + 0090 27bdffe8 afbf0014 240e0004 3c010000 '.......$...<... + 00a0 ac2e0000 0c000000 00000000 10000001 ................ + 00b0 00000000 8fbf0014 27bd0018 03e00008 ........'....... + 00c0 00000000 00000000 00000000 00000000 ................ +Contents of section .rodata: + 0000 0004e729 01000000 02000000 03000000 ...)............ + 0010 48656c6c 6f202000 576f726c 64000000 Hello .World... + 0020 0001e0f3 00000000 40146666 66666666 ........@.ffffff + 0030 40a66666 40a9999a 00000000 00000000 @.ff@........... +Contents of section .data: + 0000 01000000 00000000 00000000 00000000 ................ +Contents of section .options: + 0000 01200000 00000000 a0000002 00000000 . .............. + 0010 00000170 00000000 00000000 00007ff0 ...p............ + 0020 07100000 00000000 00000000 00000000 ................ + 0030 08100000 00000000 00000000 00000000 ................ +Contents of section .reginfo: + 0000 a300c032 00000000 00000170 00000000 ...2.......p.... + 0010 00000000 00007ff0 ........ diff --git a/tools/decompress_baserom.py b/tools/decompress_baserom.py new file mode 100755 index 00000000..bf910b94 --- /dev/null +++ b/tools/decompress_baserom.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 + +import hashlib, io, struct, sys +from pathlib import Path +import argparse + +from libyaz0 import decompress + +FILE_TABLE_OFFSET = { + "jp": 0x19D40, + "cn": 0x21D80, +} + +VERSIONS_MD5S = { + "jp": "d7ae64f2f47a9fa3f87686a3c5ce09af", + "cn": "af83e0cf36298e62e9eb2eb8c89aa710", +} + +description = "Convert a rom that uses dmadata to an uncompressed one." + +parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawTextHelpFormatter) +parser.add_argument("-v", "--version", help="Version of the game to extract.", default="jp") + +args = parser.parse_args() + +BASEROM_PATH = Path(f"baserom.{args.version}.z64") +UNCOMPRESSED_PATH = Path(f"baserom_uncompressed.{args.version}.z64") + + +Version = args.version + +file_table_offset = FILE_TABLE_OFFSET[Version] +correct_str_hash = VERSIONS_MD5S[Version] + + + +def round_up(n,shift): + mod = 1 << shift + return (n + mod - 1) >> shift << shift + +def as_word(b, off=0): + return struct.unpack(">I", b[off:off+4])[0] + +def as_word_list(b): + return [i[0] for i in struct.iter_unpack(">I", b)] + +def calc_crc(rom_data, cic_type): + start = 0x1000 + end = 0x101000 + + unsigned_long = lambda i: i & 0xFFFFFFFF + rol = lambda i, b: unsigned_long(i << b) | (i >> (-b & 0x1F)) + + if cic_type == 6101 or cic_type == 6102: + seed = 0xF8CA4DDC + elif cic_type == 6103: + seed = 0xA3886759 + elif cic_type == 6105: + seed = 0xDF26F436 + elif cic_type == 6106: + seed = 0x1FEA617A + else: + assert False, f"Unknown cic type: {cic_type}" + + t1 = t2 = t3 = t4 = t5 = t6 = seed + + for pos in range(start, end, 4): + d = as_word(rom_data, pos) + r = rol(d, d & 0x1F) + + t6d = unsigned_long(t6 + d) + if t6d < t6: + t4 = unsigned_long(t4 + 1) + t6 = t6d + t3 ^= d + t5 = unsigned_long(t5 + r) + + if t2 > d: + t2 ^= r + else: + t2 ^= t6 ^ d + + if cic_type == 6105: + t1 = unsigned_long(t1 + (as_word(rom_data, 0x0750 + (pos & 0xFF)) ^ d)) + else: + t1 = unsigned_long(t1 + (t5 ^ d)) + + chksum = [0,0] + + if cic_type == 6103: + chksum[0] = unsigned_long((t6 ^ t4) + t3) + chksum[1] = unsigned_long((t5 ^ t2) + t1) + elif cic_type == 6106: + chksum[0] = unsigned_long((t6 * t4) + t3) + chksum[1] = unsigned_long((t5 * t2) + t1) + else: + chksum[0] = t6 ^ t4 ^ t3 + chksum[1] = t5 ^ t2 ^ t1 + + return struct.pack(">II", chksum[0], chksum[1]) + +def read_dmadata_entry(addr): + return as_word_list(fileContent[addr:addr+0x10]) + +def read_dmadata(start): + dmadata = [] + addr = start + entry = read_dmadata_entry(addr) + i = 0 + while any([e != 0 for e in entry]): + # print(f"0x{addr:08X} " + str([f"{e:08X}" for e in entry])) + dmadata.append(entry) + addr += 0x10 + i += 1 + entry = read_dmadata_entry(addr) + # print(f"0x{addr:08X} " + str([f"{e:08X}" for e in entry])) + return dmadata + +def update_crc(decompressed): + print("Recalculating crc...") + new_crc = calc_crc(decompressed.getbuffer(), 6105) + + decompressed.seek(0x10) + decompressed.write(new_crc) + return decompressed + +def decompress_rom(dmadata_addr, dmadata): + rom_segments = {} # vrom start : data s.t. len(data) == vrom_end - vrom_start + new_dmadata = bytearray() # new dmadata: {vrom start , vrom end , vrom start , 0} + + decompressed = io.BytesIO(b"") + + for v_start, v_end, p_start, p_end in dmadata: + if p_start == 0xFFFFFFFF and p_end == 0xFFFFFFFF: + new_dmadata.extend(struct.pack(">IIII", v_start, v_end, p_start, p_end)) + continue + if p_end == 0: # uncompressed + rom_segments.update({v_start : fileContent[p_start:p_start + v_end - v_start]}) + else: # compressed + rom_segments.update({v_start : decompress(fileContent[p_start:p_end])}) + new_dmadata.extend(struct.pack(">IIII", v_start, v_end, v_start, 0)) + + # write rom segments to vaddrs + for vrom_st,data in rom_segments.items(): + decompressed.seek(vrom_st) + decompressed.write(data) + # write new dmadata + decompressed.seek(dmadata_addr) + decompressed.write(new_dmadata) + # pad to size + padding_end = round_up(dmadata[-1][1], 14) + decompressed.seek(padding_end-1) + decompressed.write(bytearray([0])) + # re-calculate crc + return update_crc(decompressed) + + +def get_str_hash(byte_array): + return str(hashlib.md5(byte_array).hexdigest()) + +# If the baserom exists and is correct, we don't need to change anything +if UNCOMPRESSED_PATH.exists(): + with UNCOMPRESSED_PATH.open(mode="rb") as file: + fileContent = bytearray(file.read()) + if get_str_hash(fileContent) == correct_str_hash: + print("Found valid baserom - exiting early") + sys.exit(0) + +# Determine if we have a ROM file +romFileName = BASEROM_PATH +if BASEROM_PATH.with_suffix(".z64").exists(): + romFileName = BASEROM_PATH.with_suffix(".z64") +elif BASEROM_PATH.with_suffix(".n64").exists(): + romFileName = BASEROM_PATH.with_suffix(".n64") +elif BASEROM_PATH.with_suffix(".v64").exists(): + romFileName = BASEROM_PATH.with_suffix(".v64") +else: + print(f"Error: Could not find {BASEROM_PATH}/.n64/.v64") + sys.exit(1) + +# Read in the original ROM +print(f"File '{str(romFileName)}' found.") +with romFileName.open(mode="rb") as file: + fileContent = bytearray(file.read()) + +fileContentLen = len(fileContent) + +# Check if ROM needs to be byte/word swapped +# Little-endian +if fileContent[0] == 0x40: + # Word Swap ROM + print("ROM needs to be word swapped...") + words = str(int(fileContentLen/4)) + little_byte_format = "<" + words + "I" + big_byte_format = ">" + words + "I" + tmp = struct.unpack_from(little_byte_format, fileContent, 0) + struct.pack_into(big_byte_format, fileContent, 0, *tmp) + + print("Word swapping done.") + +# Byte-swapped +elif fileContent[0] == 0x37: + # Byte Swap ROM + print("ROM needs to be byte swapped...") + halfwords = str(int(fileContentLen/2)) + little_byte_format = "<" + halfwords + "H" + big_byte_format = ">" + halfwords + "H" + tmp = struct.unpack_from(little_byte_format, fileContent, 0) + struct.pack_into(big_byte_format, fileContent, 0, *tmp) + + print("Byte swapping done.") + +dmadata = read_dmadata(file_table_offset) +# Decompress +if any([b != 0 for b in fileContent[file_table_offset + 0xAC:file_table_offset + 0xAC + 0x4]]): + print("Decompressing rom...") + fileContent = decompress_rom(file_table_offset, dmadata).getbuffer() + print(f"{len(fileContent):X}") + +padding_start = round_up(dmadata[-1][1], 12) +padding_end = round_up(dmadata[-1][1], 14) +print(f"Padding from {padding_start:X} to {padding_end:X}...") +for i in range(padding_start,padding_end): + fileContent[i] = 0xFF + +# Check to see if the ROM is a "vanilla" ROM +str_hash = get_str_hash(bytearray(fileContent)) +if str_hash != correct_str_hash: + print("Error: Expected a hash of " + correct_str_hash + " but got " + str_hash + ". " + + "The baserom has probably been tampered, find a new one") + sys.exit(1) + +# Write out our new ROM +print(f"Writing new ROM {UNCOMPRESSED_PATH}.") +with UNCOMPRESSED_PATH.open("wb") as file: + file.write(bytes(fileContent)) + +print("Done!") diff --git a/tools/fado/.clang-format b/tools/fado/.clang-format new file mode 100644 index 00000000..c7b900f0 --- /dev/null +++ b/tools/fado/.clang-format @@ -0,0 +1,23 @@ +IndentWidth: 4 +Language: Cpp +UseTab: Never +ColumnLimit: 120 +PointerAlignment: Left +BreakBeforeBraces: Attach +SpaceAfterCStyleCast: false +Cpp11BracedListStyle: false +IndentCaseLabels: true +BinPackArguments: true +BinPackParameters: true +AlignAfterOpenBracket: Align +AlignOperands: true +BreakBeforeTernaryOperators: true +BreakBeforeBinaryOperators: None +AllowShortBlocksOnASingleLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AlignEscapedNewlines: Left +AlignTrailingComments: true +SortIncludes: false diff --git a/tools/fado/.gitignore b/tools/fado/.gitignore new file mode 100644 index 00000000..83b94860 --- /dev/null +++ b/tools/fado/.gitignore @@ -0,0 +1,56 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# Custom +build/ +.vscode diff --git a/tools/fado/.gitrepo b/tools/fado/.gitrepo new file mode 100644 index 00000000..2e5a3619 --- /dev/null +++ b/tools/fado/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:EllipticEllipsis/fado.git + branch = master + commit = 8d896ee97d565508755584803c409fc33bb0c953 + parent = f07748a7a0efa944186240ee136389d32b682ba6 + method = merge + cmdver = 0.4.3 diff --git a/tools/fado/LICENSE b/tools/fado/LICENSE new file mode 100644 index 00000000..0ad25db4 --- /dev/null +++ b/tools/fado/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/tools/fado/Makefile b/tools/fado/Makefile new file mode 100644 index 00000000..135f5125 --- /dev/null +++ b/tools/fado/Makefile @@ -0,0 +1,74 @@ +DEBUG ?= 0 +LLD ?= 0 +ASAN ?= 0 +EXPERIMENTAL?= 0 + +ELF := fado.elf + +CC := $(shell ./find_program.sh gcc clang clang-[0-9][0-9] clang-[0-9]) +LD := $(shell ./find_program.sh ld ld.lld ld.lld-*) +INC := -I include -I lib +WARNINGS := -Wall -Wextra -Wpedantic -Wshadow -Werror=implicit-function-declaration -Wvla -Wno-unused-function +CFLAGS := -std=c11 +LDFLAGS := + +ifeq ($(DEBUG),0) + OPTFLAGS := -O2 + CFLAGS += -Werror +else + OPTFLAGS := -O0 -g3 -DDEBUG_ON +endif + +ifneq ($(ASAN),0) + CFLAGS += -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined +endif + +ifneq ($(LLD),0) + LDFLAGS += -fuse-ld=lld +else +ifneq ($(LD),ld) + LDFLAGS += -fuse-ld=lld +endif +endif + +ifneq ($(EXPERIMENTAL),0) + CFLAGS += -DEXPERIMENTAL +endif + +# GCC is too stupid to be trusted with these warnings +ifeq ($(CC),gcc) + WARNINGS += -Wno-implicit-fallthrough -Wno-maybe-uninitialized +endif + +SRC_DIRS := $(shell find src -type d) +C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) +H_FILES := $(foreach dir,$(INC),$(wildcard $(dir)/*.h)) +O_FILES := $(foreach f,$(C_FILES:.c=.o),build/$f) + +LIB_DIRS := $(shell find lib -type d) +# exclude test file since we don't want it +C_LIB_FILES := $(filter-out lib/vc_vector/vc_vector_test.c, $(foreach dir,$(LIB_DIRS),$(wildcard $(dir)/*.c))) +O_LIB_FILES := $(foreach f,$(C_LIB_FILES:.c=.o),build/$f) + +# Main targets +all: $(ELF) + +clean: + $(RM) -r build $(ELF) + +format: + clang-format-11 -i $(C_FILES) $(H_FILES) lib/fairy/* + +.PHONY: all clean format + +# create build directories +$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir)) $(foreach dir,$(LIB_DIRS),build/$(dir))) + +$(ELF): $(O_FILES) $(O_LIB_FILES) + $(CC) $(INC) $(WARNINGS) $(CFLAGS) $(OPTFLAGS) $(LDFLAGS) -o $@ $^ + +build/%.o: %.c $(H_FILES) + $(CC) -c $(INC) $(WARNINGS) $(CFLAGS) $(OPTFLAGS) -o $@ $< + +build/lib/%.o: lib/%.c + $(CC) -c $(INC) $(WARNINGS) $(CFLAGS) $(OPTFLAGS) -o $@ $< diff --git a/tools/fado/README.md b/tools/fado/README.md new file mode 100644 index 00000000..61b32d60 --- /dev/null +++ b/tools/fado/README.md @@ -0,0 +1,77 @@ +# fado +*Fairy-Assisted (relocations for) Decomplied Overlays* + + +Contains +- **Fairy** a library for reading relocatable MIPS ELF object files (big-endian, suitable for Nintendo 64 games) +- **Fado** a program for generating the `.ovl`/relocation section for Zelda64 overlay files +- **Mido** an automatic dependency file generator + +Compatible with both IDO and GCC (although [see below](N_B)). Both ordinary MIPS REL sections and RELA sections are now supported. + +Output format is the standard "Zelda64" .ovl section, with the relocs divided by section, as used by +- *The Legend of Zelda: Ocarina of Time* (all Nintendo 64/Gamecube/iQue releases) +- *The Legend of Zelda: Majora's Mask* (all Nintendo 64/Gamecube releases) + +In theory it will also work for other Nintendo 64 games that use this system, such as *Yoshi's Story*, but has yet to be tested with these. + + +## Explanation + +The overlay relocation sections used by Zelda64 is described [here](z64_relocation_section_format.md). Fado will produce a `.ovl` section compatible with this format, although as noted there, some compilers need persuasion to produce compatible objects. + + +## How to use + +Compile by running `make`. + +A standalone invocation of Fado would look something like + +```sh +./fado.elf z_en_hs2.o -n ovl_En_Hs2 -o ovl_En_Hs2_reloc.s +``` +This takes as input the compiled object file from the C file (e.g. [this one](https://github.com/zeldaret/oot/blob/eadc477187888e1ae078d021b4a00b1366f0c9a4/src/overlays/actors/ovl_En_Hs2/z_en_hs2.c)), the name of the overlay (`ovl_En_Hs2`) and will output an assembly file `ovl_En_Hs2_reloc.s` containing the relocation section. An example output is included in the repo [here](ovl_En_Hs_reloc.s). Fado will print information from the object file to assist with debugging, by splitting relocs by section, and for each, printing the type, offset, and associated symbol (or section if static): + +```mips +# TEXT RELOCS +.word 0x45000084 # R_MIPS_HI16 0x000084 .data +.word 0x4600008C # R_MIPS_LO16 0x00008C .data +.word 0x450000B4 # R_MIPS_HI16 0x0000B4 .rodata +.word 0x460000BC # R_MIPS_LO16 0x0000BC .rodata +.word 0x450000C0 # R_MIPS_HI16 0x0000C0 func_80A6F1A4 +.word 0x460000C4 # R_MIPS_LO16 0x0000C4 func_80A6F1A4 +``` + +If invoking in a makefile, you will probably want to generate these from a predefined filelist, and with the appropriate dependencies. [The Ocarina of Time decomp repository](http://github.com/zeldaret/oot) contains an example of how to do this using a supplementary program to parse the `spec` format. + +More information can be obtained by running + +```sh +./fado.elf --help +``` + +which contains information on the various options, such as automatic dependency file generation, etc. + + +## N.B. + +- Fado expects the linker script to output symbols for the section sizes, and for them to be declared separately, in the format + +``` +_SEGMENTNAMESegmentSECTIONSize +``` + +e.g. + +``` +_ovl_En_Hs2SegmentTextSize +``` + +etc. + +- By default Fado expects sections to be 0x10-aligned, as is usual for IDO. Some versions of GCC like to align sections to smaller widths, which Fado will handle appropriately, but the linker script must also address this, and at least the default settings seem unable to size the sections correctly due ot placing `fill`s in the wrong places. For now it is recommended to manually align sections to 0x10 if the compiler does not automatically. + - The experimental flag `--alignment`/`-a` can be passed to Fado, and it will use the alignment declared by each section in the elf file instead of padding them to 0x10 bytes, It should be noted this option has not been fully tested because currently we don't have any linker script tool that can properly address the incorrect placing of `fill`s. Fado must be rebuilt passing `EXPERIMENTAL=1` to be able to use this flag. + +- To prevent GCC producing non-compliant HI/LOs, you must pass *both* of the following compiler flags: `-mno-explicit-relocs -mno-split-addresses`. See [here](z64_relocation_section_format.md#hilo) for more details. + +- It is recommended, though not strictly required, that `-fno-merge-constants` is used for GCC, to avoid unpredictable section sizes, and comply with the Zelda64 relocation format's expectation of at most one rodata section. See [here](z64_relocation_section_format.md#rodata) for more details. diff --git a/tools/fado/find_program.sh b/tools/fado/find_program.sh new file mode 100755 index 00000000..77eb53cb --- /dev/null +++ b/tools/fado/find_program.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +for i in "${@:2}" + do + RESULT=$(IFS=:;find $PATH -maxdepth 1 -name "$i" -print -quit 2> /dev/null | grep -o '[^/]*$') + COUNT=$(echo "$RESULT" | wc -c) + + if [ $COUNT -gt 1 ] + then + echo $RESULT + exit 0 + fi + done + +echo $1 +exit 0 diff --git a/tools/fado/include/fado.h b/tools/fado/include/fado.h new file mode 100644 index 00000000..6044d0a2 --- /dev/null +++ b/tools/fado/include/fado.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include + +void Fado_Relocs(FILE* outputFile, int inputFilesCount, FILE** inputFiles, const char* ovlName); +// void Fado_WriteRelocFile(FILE* outputFile, FILE** inputFiles, int inputFilesCount); diff --git a/tools/fado/include/help.h b/tools/fado/include/help.h new file mode 100644 index 00000000..35e8f595 --- /dev/null +++ b/tools/fado/include/help.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include +#include + +typedef struct { + struct option longOpt; + char* helpArg; + char* helpMsg; +} OptInfo; + +typedef struct { + char* helpArg; + char* helpMsg; +} PosArgInfo; + +/* Formatting sizes used by Help_PrintHelp. Change them before calling Help_PrintHelp to use custom values */ +extern size_t helpTextWidth; +extern size_t helpDtIndent; +extern size_t helpDdIndent; + +void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo* posArgInfo, size_t optCount, + const OptInfo* optInfo, const char* epilogue); diff --git a/tools/fado/include/macros.h b/tools/fado/include/macros.h new file mode 100644 index 00000000..e201f8d3 --- /dev/null +++ b/tools/fado/include/macros.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include "vc_vector/vc_vector.h" + +/* C macros */ +#define ARRAY_COUNT(arr) (signed long long)(sizeof(arr) / sizeof(arr[0])) +#define ARRAY_COUNTU(arr) (unsigned long long)(sizeof(arr) / sizeof(arr[0])) + +#define ALIGN(val, align) (((val) + (align - 1)) / (align) * (align)) + +/* Mathematical macros */ +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +#define CLAMP(x, min, max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x)) +#define CLAMP_MAX(x, max) ((x) > (max) ? (max) : (x)) +#define CLAMP_MIN(x, min) ((x) < (min) ? (min) : (x)) +#define MEDIAN3(a1, a2, a3) \ + ((a2 >= a1) ? ((a3 >= a2) ? a2 : ((a1 >= a3) ? a1 : a3)) : ((a2 >= a3) ? a2 : ((a3 >= a1) ? a1 : a3))) + +/* vc_vector macros - really these should go in vc_vector.h, but not much choice without touching the library files */ +#define VC_FOREACH(i, v) for (i = vc_vector_begin(v); i != vc_vector_end(v); i = vc_vector_next(v, i)) diff --git a/tools/fado/include/mido.h b/tools/fado/include/mido.h new file mode 100644 index 00000000..b40d8a4c --- /dev/null +++ b/tools/fado/include/mido.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include "vc_vector/vc_vector.h" + +int Mido_WriteDependencyFile(FILE* dependencyFile, const char* relocFile, vc_vector* inputFilesVector); diff --git a/tools/fado/include/mips_elf.h b/tools/fado/include/mips_elf.h new file mode 100644 index 00000000..122e98d2 --- /dev/null +++ b/tools/fado/include/mips_elf.h @@ -0,0 +1,659 @@ +/* This file contains enough of the ELF format definitions for MIPS to enable Fairy and Fado to work. More may need to + * be added later. The content is excerpted directly from elf.h from the GNU C Library, and therefore: */ +/* Copyright (C) 1995-2020 Free Software Foundation, Inc. */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef MIPS_ELF_H +#define MIPS_ELF_H + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_IAMCU 6 /* Intel MCU */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ +/* reserved 11-14 */ +#define EM_PARISC 15 /* HPPA */ +/* reserved 16 */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ +#define EM_SPU 23 /* IBM SPU/SPC */ +/* reserved 24-35 */ +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam */ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ +#define EM_PDP10 64 /* Digital PDP-10 */ +#define EM_PDP11 65 /* Digital PDP-11 */ +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit emb.proc */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit emb.proc */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_COMPACT 93 /* ARC International ARCompact */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore */ +#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Proc */ +#define EM_NS32K 97 /* National Semi. 32000 */ +#define EM_TPC 98 /* Tenor Network TPC */ +#define EM_SNP1K 99 /* Trebia SNP 1000 */ +#define EM_ST200 100 /* STMicroelectronics ST200 */ +#define EM_IP2K 101 /* Ubicom IP2xxx */ +#define EM_MAX 102 /* MAX processor */ +#define EM_CR 103 /* National Semi. CompactRISC */ +#define EM_F2MC16 104 /* Fujitsu F2MC16 */ +#define EM_MSP430 105 /* Texas Instruments msp430 */ +#define EM_BLACKFIN 106 /* Analog Devices Blackfin DSP */ +#define EM_SE_C33 107 /* Seiko Epson S1C33 family */ +#define EM_SEP 108 /* Sharp embedded microprocessor */ +#define EM_ARCA 109 /* Arca RISC */ +#define EM_UNICORE 110 /* PKU-Unity & MPRC Peking Uni. mc series */ +#define EM_EXCESS 111 /* eXcess configurable cpu */ +#define EM_DXP 112 /* Icera Semi. Deep Execution Processor */ +#define EM_ALTERA_NIOS2 113 /* Altera Nios II */ +#define EM_CRX 114 /* National Semi. CompactRISC CRX */ +#define EM_XGATE 115 /* Motorola XGATE */ +#define EM_C166 116 /* Infineon C16x/XC16x */ +#define EM_M16C 117 /* Renesas M16C */ +#define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F */ +#define EM_CE 119 /* Freescale Communication Engine RISC */ +#define EM_M32C 120 /* Renesas M32C */ +/* reserved 121-130 */ +#define EM_TSK3000 131 /* Altium TSK3000 */ +#define EM_RS08 132 /* Freescale RS08 */ +#define EM_SHARC 133 /* Analog Devices SHARC family */ +#define EM_ECOG2 134 /* Cyan Technology eCOG2 */ +#define EM_SCORE7 135 /* Sunplus S+core7 RISC */ +#define EM_DSP24 136 /* New Japan Radio (NJR) 24-bit DSP */ +#define EM_VIDEOCORE3 137 /* Broadcom VideoCore III */ +#define EM_LATTICEMICO32 138 /* RISC for Lattice FPGA */ +#define EM_SE_C17 139 /* Seiko Epson C17 */ +#define EM_TI_C6000 140 /* Texas Instruments TMS320C6000 DSP */ +#define EM_TI_C2000 141 /* Texas Instruments TMS320C2000 DSP */ +#define EM_TI_C5500 142 /* Texas Instruments TMS320C55x DSP */ +#define EM_TI_ARP32 143 /* Texas Instruments App. Specific RISC */ +#define EM_TI_PRU 144 /* Texas Instruments Prog. Realtime Unit */ +/* reserved 145-159 */ +#define EM_MMDSP_PLUS 160 /* STMicroelectronics 64bit VLIW DSP */ +#define EM_CYPRESS_M8C 161 /* Cypress M8C */ +#define EM_R32C 162 /* Renesas R32C */ +#define EM_TRIMEDIA 163 /* NXP Semi. TriMedia */ +#define EM_QDSP6 164 /* QUALCOMM DSP6 */ +#define EM_8051 165 /* Intel 8051 and variants */ +#define EM_STXP7X 166 /* STMicroelectronics STxP7x */ +#define EM_NDS32 167 /* Andes Tech. compact code emb. RISC */ +#define EM_ECOG1X 168 /* Cyan Technology eCOG1X */ +#define EM_MAXQ30 169 /* Dallas Semi. MAXQ30 mc */ +#define EM_XIMO16 170 /* New Japan Radio (NJR) 16-bit DSP */ +#define EM_MANIK 171 /* M2000 Reconfigurable RISC */ +#define EM_CRAYNV2 172 /* Cray NV2 vector architecture */ +#define EM_RX 173 /* Renesas RX */ +#define EM_METAG 174 /* Imagination Tech. META */ +#define EM_MCST_ELBRUS 175 /* MCST Elbrus */ +#define EM_ECOG16 176 /* Cyan Technology eCOG16 */ +#define EM_CR16 177 /* National Semi. CompactRISC CR16 */ +#define EM_ETPU 178 /* Freescale Extended Time Processing Unit */ +#define EM_SLE9X 179 /* Infineon Tech. SLE9X */ +#define EM_L10M 180 /* Intel L10M */ +#define EM_K10M 181 /* Intel K10M */ +/* reserved 182 */ +#define EM_AARCH64 183 /* ARM AARCH64 */ +/* reserved 184 */ +#define EM_AVR32 185 /* Amtel 32-bit microprocessor */ +#define EM_STM8 186 /* STMicroelectronics STM8 */ +#define EM_TILE64 187 /* Tileta TILE64 */ +#define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ +#define EM_CUDA 190 /* NVIDIA CUDA */ +#define EM_TILEGX 191 /* Tilera TILE-Gx */ +#define EM_CLOUDSHIELD 192 /* CloudShield */ +#define EM_COREA_1ST 193 /* KIPO-KAIST Core-A 1st gen. */ +#define EM_COREA_2ND 194 /* KIPO-KAIST Core-A 2nd gen. */ +#define EM_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */ +#define EM_OPEN8 196 /* Open8 RISC */ +#define EM_RL78 197 /* Renesas RL78 */ +#define EM_VIDEOCORE5 198 /* Broadcom VideoCore V */ +#define EM_78KOR 199 /* Renesas 78KOR */ +#define EM_56800EX 200 /* Freescale 56800EX DSC */ +#define EM_BA1 201 /* Beyond BA1 */ +#define EM_BA2 202 /* Beyond BA2 */ +#define EM_XCORE 203 /* XMOS xCORE */ +#define EM_MCHP_PIC 204 /* Microchip 8-bit PIC(r) */ +/* reserved 205-209 */ +#define EM_KM32 210 /* KM211 KM32 */ +#define EM_KMX32 211 /* KM211 KMX32 */ +#define EM_EMX16 212 /* KM211 KMX16 */ +#define EM_EMX8 213 /* KM211 KMX8 */ +#define EM_KVARC 214 /* KM211 KVARC */ +#define EM_CDP 215 /* Paneve CDP */ +#define EM_COGE 216 /* Cognitive Smart Memory Processor */ +#define EM_COOL 217 /* Bluechip CoolEngine */ +#define EM_NORC 218 /* Nanoradio Optimized RISC */ +#define EM_CSR_KALIMBA 219 /* CSR Kalimba */ +#define EM_Z80 220 /* Zilog Z80 */ +#define EM_VISIUM 221 /* Controls and Data Services VISIUMcore */ +#define EM_FT32 222 /* FTDI Chip FT32 */ +#define EM_MOXIE 223 /* Moxie processor */ +#define EM_AMDGPU 224 /* AMD GPU */ +/* reserved 225-242 */ +#define EM_RISCV 243 /* RISC-V */ + +#define EM_BPF 247 /* Linux BPF -- in-kernel virtual machine */ +#define EM_CSKY 252 /* C-SKY */ + +#define EM_NUM 253 + +/* Old spellings/synonyms. */ + +#define EM_ARC_A5 EM_ARC_COMPACT + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct { + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Symbol table entry. */ + +typedef struct { + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4) +#define ELF32_ST_TYPE(val) ((val)&0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND(val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o)&0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val)&0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff)) + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */ +#define EF_MIPS_PIC 2 /* Contains PIC code. */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */ +#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */ +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ +#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ +#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ + +/* The following are unofficial names and should not be used. */ + +#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1 +#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2 +#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3 +#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4 +#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5 +#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32 +#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64 + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 +#define SHT_MIPS_XHASH 0x7000002b + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 +/* Keep this the last entry. */ +#define R_MIPS_NUM 128 + +#endif /* MIPS_ELF_H */ diff --git a/tools/fado/lib/fairy/fairy.c b/tools/fado/lib/fairy/fairy.c new file mode 100644 index 00000000..8fc09030 --- /dev/null +++ b/tools/fado/lib/fairy/fairy.c @@ -0,0 +1,418 @@ +/** + * Functions for working with N64 ELF files. + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fairy.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "vc_vector/vc_vector.h" +#include "macros.h" + +VerbosityLevel gVerbosity = VERBOSITY_NONE; +bool gUseElfAlignment = false; + +int Fairy_DebugPrintf(const char* file, int line, const char* func, VerbosityLevel level, const char* fmt, ...) { + if (gVerbosity >= level) { + int ret = 0; + va_list args; + va_start(args, fmt); + + if (gVerbosity >= VERBOSITY_DEBUG) { + ret += fprintf(stderr, "%s:%d:%s: ", file, line, func); + } + + ret += vfprintf(stderr, fmt, args); + va_end(args); + return ret; + } + return 0; +} + +/* Endian readers. MIPS is BE, so only need these */ +static Elf32_Half Fairy_ReadHalf(const uint8_t* data) { + return data[0] << 8 | data[1] << 0; +} + +static Elf32_Word Fairy_ReadWord(const uint8_t* data) { + return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3] << 0; +} + +static bool Fairy_VerifyMagic(const uint8_t* data) { + return (data[0] == 0x7F && data[1] == 'E' && data[2] == 'L' && data[3] == 'F'); +} + +static uint16_t Fairy_Swap16(uint16_t x) { + return ((x & 0xFF) << 0x8) | ((x & 0xFF00) >> 0x8); +} + +static uint32_t Fairy_Swap32(uint32_t x) { + return ((x & 0xFF) << 0x18) | ((x & 0xFF00) << 0x8) | ((x & 0xFF0000) >> 0x8) | ((x & 0xFF000000) >> 0x18); +} + +/* Both GCC and Clang define these, so we can avoid an endian header altogether */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define REEND16(x) Fairy_Swap16(x) +#define REEND32(x) Fairy_Swap32(x) +#else +#define REEND16(x) (x) +#define REEND32(x) (x) +#endif + +const char* Fairy_StringFromDefine(const FairyDefineString* dict, int define) { + size_t i; + for (i = 0; dict[i].string != NULL; i++) { + if (dict[i].define == define) { + return dict[i].string; + } + } + return NULL; +} + +/** + * Returns true if the string 'initial' is contained in the string 'string' + * 'initial' must be null-terminated, 'string' ideally is. + */ +bool Fairy_StartsWith(const char* string, const char* initial) { + char s; + char i; + do { + s = *string++; + i = *initial++; + if (i == '\0') { + return true; + } + } while (s == i); + return false; +} + +/* Reading functions */ + +/** + * Every reading function: + * - Returns the pointer to the struct + * - Takes the ouput struct or array as its first argument. This must be pre-allocated + * - Takes the input file as the second argument (At least until I am persuaded to read the whole file into RAM...) + * - The rest of the arguments are important information about the struct it is reading (offset and size, usually) + */ + +FairyFileHeader* Fairy_ReadFileHeader(FairyFileHeader* header, FILE* file) { + fseek(file, 0, SEEK_SET); + assert(fread(header, sizeof(char), 0x34, file) == 0x34); + + if (!Fairy_VerifyMagic(header->e_ident)) { + fprintf(stderr, "Not a valid ELF file.\n"); + return NULL; + } + + if (header->e_ident[EI_CLASS] != ELFCLASS32) { + fprintf(stderr, "Not a 32-bit ELF file.\n"); + return NULL; + } + + header->e_type = REEND16(header->e_type); + if (header->e_type != ET_REL) { + fprintf(stderr, "Not a relocatable object file.\n"); + return NULL; + } + + header->e_machine = REEND16(header->e_machine); + if (header->e_machine != EM_MIPS) { + fprintf(stderr, "Not a MIPS object file.\n"); + return NULL; + } + + header->e_version = REEND32(header->e_version); + header->e_entry = REEND32(header->e_entry); + header->e_phoff = REEND32(header->e_phoff); + header->e_shoff = REEND32(header->e_shoff); + header->e_flags = REEND32(header->e_flags); + header->e_ehsize = REEND16(header->e_ehsize); + header->e_phentsize = REEND16(header->e_phentsize); + header->e_phnum = REEND16(header->e_phnum); + header->e_shentsize = REEND16(header->e_shentsize); + header->e_shnum = REEND16(header->e_shnum); + header->e_shstrndx = REEND16(header->e_shstrndx); + + return header; +} + +/* tableOffset and number should be obtained from the file header */ +FairySecHeader* Fairy_ReadSectionTable(FairySecHeader* sectionTable, FILE* file, size_t tableOffset, size_t number) { + size_t entrySize = sizeof(FairySecHeader); + size_t tableSize = number * entrySize; + + fseek(file, tableOffset, SEEK_SET); + assert(fread(sectionTable, sizeof(char), tableSize, file) == tableSize); + + /* Since the section table happens to only have entries of width 4, we can byteswap it by pretending it is a raw + * uint32_t array */ + { + size_t i; + uint32_t* data = (uint32_t*)sectionTable; + for (i = 0; i < tableSize / sizeof(uint32_t); i++) { + data[i] = REEND32(data[i]); + } + } + + return sectionTable; +} + +size_t Fairy_ReadSymbolTable(FairySym** symbolTableOut, FILE* file, size_t tableOffset, size_t tableSize) { + size_t number = tableSize / sizeof(FairySym); + FairySym* symbolTable = malloc(tableSize); + + *symbolTableOut = NULL; + + if (symbolTable == NULL) { + return 0; + } + if (fseek(file, tableOffset, SEEK_SET) != 0 || fread(symbolTable, sizeof(char), tableSize, file) != tableSize) { + free(symbolTable); + return 0; + } + + /* Reend the variables that are wider than bytes */ + { + size_t i; + for (i = 0; i < number; i++) { + symbolTable[i].st_name = REEND32(symbolTable[i].st_name); + symbolTable[i].st_value = REEND32(symbolTable[i].st_value); + symbolTable[i].st_size = REEND32(symbolTable[i].st_size); + symbolTable[i].st_shndx = REEND16(symbolTable[i].st_shndx); + } + } + + *symbolTableOut = symbolTable; + return number; +} + +/* Can be used for both the section header string table and the strtab */ +char* Fairy_ReadStringTable(char* stringTable, FILE* file, size_t tableOffset, size_t tableSize) { + fseek(file, tableOffset, SEEK_SET); + assert(fread(stringTable, sizeof(char), tableSize, file) == tableSize); + return stringTable; +} + +/* offset and number are attained from the section table, the returned pointer must be freed */ +size_t Fairy_ReadRelocs(FairyRela** relocsOut, FILE* file, int type, size_t offset, size_t size) { + /* Final size of the relocation table, relocations of type SHT_REL need more space for extra addend of 0 */ + size_t finalSize = (type == SHT_REL) ? ((size * sizeof(FairyRela)) / sizeof(FairyRel)) : size; + void* readBuf = malloc(size); + FairyRela* relocTable = malloc(finalSize); + + *relocsOut = NULL; + + if (readBuf == NULL) { + return 0; + } + if (relocTable == NULL) { + free(readBuf); + return 0; + } + if (fseek(file, offset, SEEK_SET) != 0 || fread(readBuf, sizeof(char), size, file) != size) { + free(readBuf); + free(relocTable); + return 0; + } + + /* Reend the variables that are wider than bytes */ + { + size_t i; + uint32_t* data = (uint32_t*)readBuf; + for (i = 0; i < size / sizeof(uint32_t); i++) { + data[i] = REEND32(data[i]); + } + } + + /* Make the relocation table, for SHT_REL sections add an addend of 0 */ + if (type == SHT_REL) { + size_t i; + FairyRel* rel = (FairyRel*)readBuf; + + for (i = 0; i < size / sizeof(FairyRel); i++) { + relocTable[i].r_info = rel[i].r_info; + relocTable[i].r_offset = rel[i].r_offset; + relocTable[i].r_addend = 0; + } + } else { + memcpy(relocTable, readBuf, size); + } + free(readBuf); + + *relocsOut = relocTable; + return finalSize / sizeof(FairyRela); +} + +char* Fairy_GetSectionName(FairySecHeader* sectionTable, char* shstrtab, size_t index) { + return &shstrtab[sectionTable[index].sh_name]; +} + +/* Look up the index in the symbol table and return a pointer to the beginning of its string */ +char* Fairy_GetSymbolName(FairySym* symtab, char* strtab, size_t index) { + return &strtab[symtab[index].st_name]; +} + +/* FairyFileInfo functions */ + +void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + char* shstrtab; + int i; + + assert(fileInfo != NULL); + assert(file != NULL); + + fileInfo->progBitsSections = vc_vector_create(3, sizeof(Elf32_Section), NULL); + for (i = 0; i < 3; i++) { + fileInfo->progBitsSizes[i] = 0; + } + Fairy_ReadFileHeader(&fileHeader, file); + + sectionTable = malloc(fileHeader.e_shnum * fileHeader.e_shentsize); + Fairy_ReadSectionTable(sectionTable, file, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[fileHeader.e_shstrndx].sh_size * sizeof(char)); + fseek(file, sectionTable[fileHeader.e_shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sizeof(char), sectionTable[fileHeader.e_shstrndx].sh_size, file) == + sectionTable[fileHeader.e_shstrndx].sh_size); + + /* Search for the sections we need */ + { + size_t currentIndex; + FairySecHeader currentSection; + for (currentIndex = 0; currentIndex < 3; currentIndex++) { + fileInfo->relocTablesInfo[currentIndex].sectionData = NULL; + } + + for (currentIndex = 0; currentIndex < fileHeader.e_shnum; currentIndex++) { + size_t off = 0; + + currentSection = sectionTable[currentIndex]; + + switch (currentSection.sh_type) { + case SHT_PROGBITS: + assert(vc_vector_push_back(fileInfo->progBitsSections, ¤tIndex)); + + { + FairySection sectionType = FAIRY_SECTION_OTHER; + const char* sectionName = &shstrtab[currentSection.sh_name + 1]; + size_t alignedSize; + + /* Ignore the leading "." */ + if (strcmp(sectionName, "text") == 0) { + sectionType = FAIRY_SECTION_TEXT; + } else if (strcmp(sectionName, "data") == 0) { + sectionType = FAIRY_SECTION_DATA; + } else if (Fairy_StartsWith(sectionName, "rodata")) { /* May be several */ + sectionType = FAIRY_SECTION_RODATA; + } + + if (sectionType != FAIRY_SECTION_OTHER) { + if (gUseElfAlignment) { + /* Ensure the next file will start at its correct alignment */ + fileInfo->progBitsSizes[sectionType] = + ALIGN(fileInfo->progBitsSizes[sectionType], currentSection.sh_addralign); + + alignedSize = ALIGN(currentSection.sh_size, currentSection.sh_addralign); + + FAIRY_DEBUG_PRINTF("%s section alignment: 0x%X\n", sectionName, + currentSection.sh_addralign); + FAIRY_DEBUG_PRINTF("%s section size before align: 0x%X\n", sectionName, + currentSection.sh_size); + FAIRY_DEBUG_PRINTF("%s section size after align: 0x%X\n", sectionName, alignedSize); + + fileInfo->progBitsSizes[sectionType] += alignedSize; + } else { + fileInfo->progBitsSizes[sectionType] += ALIGN(currentSection.sh_size, 0x10); + } + + FAIRY_DEBUG_PRINTF("%s section size: 0x%X\n", sectionName, + fileInfo->progBitsSizes[sectionType]); + } + } + + break; + + case SHT_SYMTAB: + if (strcmp(&shstrtab[currentSection.sh_name + 1], "symtab") == 0) { + fileInfo->symtabInfo.sectionType = SHT_SYMTAB; + fileInfo->symtabInfo.sectionEntrySize = sizeof(FairySym); + fileInfo->symtabInfo.sectionEntryCount = + Fairy_ReadSymbolTable((FairySym**)&fileInfo->symtabInfo.sectionData, file, + currentSection.sh_offset, currentSection.sh_size); + } + break; + + case SHT_STRTAB: + if (strcmp(&shstrtab[currentSection.sh_name + 1], "strtab") == 0) { + FAIRY_DEBUG_PRINTF("%s", "strtab found\n"); + fileInfo->strtab = malloc(currentSection.sh_size); + Fairy_ReadStringTable(fileInfo->strtab, file, currentSection.sh_offset, currentSection.sh_size); + } + break; + + case SHT_RELA: + off += 1; + case SHT_REL: + off += 5; + /* This assumes only one reloc section of each name */ + // TODO: is this a problem? + { + FairySection relocSection = FAIRY_SECTION_OTHER; + + /* Ignore the first 5/6 chars, which will always be ".rel."/".rela." */ + if (strcmp(&shstrtab[currentSection.sh_name + off], "text") == 0) { + relocSection = FAIRY_SECTION_TEXT; + } else if (strcmp(&shstrtab[currentSection.sh_name + off], "data") == 0) { + relocSection = FAIRY_SECTION_DATA; + } else if (strcmp(&shstrtab[currentSection.sh_name + off], "rodata") == 0) { + relocSection = FAIRY_SECTION_RODATA; + } else { + break; + } + FAIRY_DEBUG_PRINTF("Found %s section\n", &shstrtab[currentSection.sh_name]); + + fileInfo->relocTablesInfo[relocSection].sectionType = SHT_RELA; + fileInfo->relocTablesInfo[relocSection].sectionEntrySize = sizeof(FairyRela); + fileInfo->relocTablesInfo[relocSection].sectionEntryCount = + Fairy_ReadRelocs((FairyRela**)&fileInfo->relocTablesInfo[relocSection].sectionData, file, + currentSection.sh_type, currentSection.sh_offset, currentSection.sh_size); + } + break; + + default: + break; + } + } + } + + free(sectionTable); + free(shstrtab); +} + +void Fairy_DestroyFile(FairyFileInfo* fileInfo) { + size_t i; + for (i = 0; i < ARRAY_COUNTU(fileInfo->relocTablesInfo); i++) { + if (fileInfo->relocTablesInfo[i].sectionData != NULL) { + FAIRY_DEBUG_PRINTF("Freeing reloc section %zd data\n", i); + free(fileInfo->relocTablesInfo[i].sectionData); + } + } + + vc_vector_release(fileInfo->progBitsSections); + + FAIRY_DEBUG_PRINTF("%s", "Freeing symtab data\n"); + free(fileInfo->symtabInfo.sectionData); + + FAIRY_DEBUG_PRINTF("%s", "Freeing strtab data\n"); + free(fileInfo->strtab); +} diff --git a/tools/fado/lib/fairy/fairy.h b/tools/fado/lib/fairy/fairy.h new file mode 100644 index 00000000..5a3cb3d9 --- /dev/null +++ b/tools/fado/lib/fairy/fairy.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include +#include +#include "mips_elf.h" + +#include "vc_vector/vc_vector.h" + +#define FAIRY_DEF_STRING(prefix, x) \ + { prefix##x, #x } + +typedef enum { + VERBOSITY_NONE, + VERBOSITY_INFO, + VERBOSITY_DEBUG //, +} VerbosityLevel; + +extern VerbosityLevel gVerbosity; +extern bool gUseElfAlignment; + +typedef Elf32_Ehdr FairyFileHeader; +typedef Elf32_Shdr FairySecHeader; +typedef Elf32_Sym FairySym; +typedef Elf32_Rel FairyRel; +typedef Elf32_Rela FairyRela; + +typedef struct { + int define; + const char* string; +} FairyDefineString; + +typedef struct { + void* sectionData; + int sectionType; + size_t sectionEntryCount; + size_t sectionEntrySize; +} FairySectionInfo; + +typedef struct { + FairySectionInfo symtabInfo; + char* strtab; + Elf32_Word progBitsSizes[3]; + vc_vector* progBitsSections; + FairySectionInfo relocTablesInfo[3]; +} FairyFileInfo; + +typedef enum { + FAIRY_SECTION_TEXT, + FAIRY_SECTION_DATA, + FAIRY_SECTION_RODATA, + FAIRY_SECTION_OTHER //, +} FairySection; + +/* Prints debugging information to stderr. To be used via the macros. */ +int Fairy_DebugPrintf(const char* file, int line, const char* func, VerbosityLevel level, const char* fmt, ...); +#define FAIRY_INFO_PRINTF(fmt, ...) Fairy_DebugPrintf(__FILE__, __LINE__, __func__, VERBOSITY_INFO, fmt, __VA_ARGS__) +#define FAIRY_DEBUG_PRINTF(fmt, ...) Fairy_DebugPrintf(__FILE__, __LINE__, __func__, VERBOSITY_DEBUG, fmt, __VA_ARGS__) + +const char* Fairy_StringFromDefine(const FairyDefineString* dict, int define); +bool Fairy_StartsWith(const char* string, const char* initial); + +FairyFileHeader* Fairy_ReadFileHeader(FairyFileHeader* header, FILE* file); +FairySecHeader* Fairy_ReadSectionTable(FairySecHeader* sectionTable, FILE* file, size_t tableOffset, size_t number); +char* Fairy_ReadStringTable(char* stringTable, FILE* file, size_t tableOffset, size_t tableSize); +size_t Fairy_ReadSymbolTable(FairySym** symbolTableOut, FILE* file, size_t tableOffset, size_t tableSize); +size_t Fairy_ReadRelocs(FairyRela** relocsOut, FILE* file, int type, size_t offset, size_t size); + +char* Fairy_GetSectionName(FairySecHeader* sectionTable, char* shstrtab, size_t index); +char* Fairy_GetSymbolName(FairySym* symtab, char* strtab, size_t index); + +void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file); +void Fairy_DestroyFile(FairyFileInfo* fileInfo); diff --git a/tools/fado/lib/fairy/fairy_data.inc b/tools/fado/lib/fairy/fairy_data.inc new file mode 100644 index 00000000..5dfecfc2 --- /dev/null +++ b/tools/fado/lib/fairy/fairy_data.inc @@ -0,0 +1,126 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fairy.h" +#include "mips_elf.h" + +// clang-format off +static const FairyDefineString stTypes[] = { + FAIRY_DEF_STRING(STT_, NOTYPE), + FAIRY_DEF_STRING(STT_, OBJECT), + FAIRY_DEF_STRING(STT_, FUNC), + FAIRY_DEF_STRING(STT_, SECTION), + FAIRY_DEF_STRING(STT_, FILE), + FAIRY_DEF_STRING(STT_, COMMON), + FAIRY_DEF_STRING(STT_, TLS), + FAIRY_DEF_STRING(STT_, NUM), + FAIRY_DEF_STRING(STT_, LOOS), + FAIRY_DEF_STRING(STT_, GNU_IFUNC), + FAIRY_DEF_STRING(STT_, HIOS), + FAIRY_DEF_STRING(STT_, LOPROC), + FAIRY_DEF_STRING(STT_, HIPROC), + { 0 }, +}; + +static const FairyDefineString stBinds[] = { + FAIRY_DEF_STRING(STB_, LOCAL), + FAIRY_DEF_STRING(STB_, GLOBAL), + FAIRY_DEF_STRING(STB_, WEAK), + FAIRY_DEF_STRING(STB_, NUM), + FAIRY_DEF_STRING(STB_, LOOS), + FAIRY_DEF_STRING(STB_, GNU_UNIQUE), + FAIRY_DEF_STRING(STB_, HIOS), + FAIRY_DEF_STRING(STB_, LOPROC), + FAIRY_DEF_STRING(STB_, HIPROC), + { 0 }, +}; + +static const FairyDefineString stVisibilities[] = { + FAIRY_DEF_STRING(STV_, DEFAULT), + FAIRY_DEF_STRING(STV_, INTERNAL), + FAIRY_DEF_STRING(STV_, HIDDEN), + FAIRY_DEF_STRING(STV_, PROTECTED), + { 0 }, +}; + +/* TODO: understand this data better: there are several cases with the same number */ +static const FairyDefineString shTypes[] = { + FAIRY_DEF_STRING(SHT_, NULL), + FAIRY_DEF_STRING(SHT_, PROGBITS), + FAIRY_DEF_STRING(SHT_, SYMTAB), + FAIRY_DEF_STRING(SHT_, STRTAB), + FAIRY_DEF_STRING(SHT_, RELA), + FAIRY_DEF_STRING(SHT_, HASH), + FAIRY_DEF_STRING(SHT_, DYNAMIC), + FAIRY_DEF_STRING(SHT_, NOTE), + FAIRY_DEF_STRING(SHT_, NOBITS), + FAIRY_DEF_STRING(SHT_, REL), + FAIRY_DEF_STRING(SHT_, SHLIB), + FAIRY_DEF_STRING(SHT_, DYNSYM), + FAIRY_DEF_STRING(SHT_, INIT_ARRAY), + FAIRY_DEF_STRING(SHT_, FINI_ARRAY), + FAIRY_DEF_STRING(SHT_, PREINIT_ARRAY), + FAIRY_DEF_STRING(SHT_, GROUP), + FAIRY_DEF_STRING(SHT_, SYMTAB_SHNDX), + FAIRY_DEF_STRING(SHT_, NUM), + FAIRY_DEF_STRING(SHT_, LOOS), + FAIRY_DEF_STRING(SHT_, GNU_ATTRIBUTES), + FAIRY_DEF_STRING(SHT_, GNU_HASH), + FAIRY_DEF_STRING(SHT_, GNU_LIBLIST), + FAIRY_DEF_STRING(SHT_, CHECKSUM), + FAIRY_DEF_STRING(SHT_, LOSUNW), + FAIRY_DEF_STRING(SHT_, SUNW_move), + FAIRY_DEF_STRING(SHT_, SUNW_COMDAT), + FAIRY_DEF_STRING(SHT_, SUNW_syminfo), + FAIRY_DEF_STRING(SHT_, GNU_verdef), + FAIRY_DEF_STRING(SHT_, GNU_verneed), + FAIRY_DEF_STRING(SHT_, GNU_versym), + FAIRY_DEF_STRING(SHT_, HISUNW), + FAIRY_DEF_STRING(SHT_, HIOS), + FAIRY_DEF_STRING(SHT_, LOPROC), + FAIRY_DEF_STRING(SHT_, HIPROC), + FAIRY_DEF_STRING(SHT_, LOUSER), + FAIRY_DEF_STRING(SHT_, HIUSER), + FAIRY_DEF_STRING(SHT_, MIPS_LIBLIST), + FAIRY_DEF_STRING(SHT_, MIPS_MSYM), + FAIRY_DEF_STRING(SHT_, MIPS_CONFLICT), + FAIRY_DEF_STRING(SHT_, MIPS_GPTAB), + FAIRY_DEF_STRING(SHT_, MIPS_UCODE), + FAIRY_DEF_STRING(SHT_, MIPS_DEBUG), + FAIRY_DEF_STRING(SHT_, MIPS_REGINFO), + FAIRY_DEF_STRING(SHT_, MIPS_PACKAGE), + FAIRY_DEF_STRING(SHT_, MIPS_PACKSYM), + FAIRY_DEF_STRING(SHT_, MIPS_RELD), + FAIRY_DEF_STRING(SHT_, MIPS_IFACE), + FAIRY_DEF_STRING(SHT_, MIPS_CONTENT), + FAIRY_DEF_STRING(SHT_, MIPS_OPTIONS), + FAIRY_DEF_STRING(SHT_, MIPS_SHDR), + FAIRY_DEF_STRING(SHT_, MIPS_FDESC), + FAIRY_DEF_STRING(SHT_, MIPS_EXTSYM), + FAIRY_DEF_STRING(SHT_, MIPS_DENSE), + FAIRY_DEF_STRING(SHT_, MIPS_PDESC), + FAIRY_DEF_STRING(SHT_, MIPS_LOCSYM), + FAIRY_DEF_STRING(SHT_, MIPS_AUXSYM), + FAIRY_DEF_STRING(SHT_, MIPS_OPTSYM), + FAIRY_DEF_STRING(SHT_, MIPS_LOCSTR), + FAIRY_DEF_STRING(SHT_, MIPS_LINE), + FAIRY_DEF_STRING(SHT_, MIPS_RFDESC), + FAIRY_DEF_STRING(SHT_, MIPS_DELTASYM), + FAIRY_DEF_STRING(SHT_, MIPS_DELTAINST), + FAIRY_DEF_STRING(SHT_, MIPS_DELTACLASS), + FAIRY_DEF_STRING(SHT_, MIPS_DWARF), + FAIRY_DEF_STRING(SHT_, MIPS_DELTADECL), + FAIRY_DEF_STRING(SHT_, MIPS_SYMBOL_LIB), + FAIRY_DEF_STRING(SHT_, MIPS_EVENTS), + FAIRY_DEF_STRING(SHT_, MIPS_TRANSLATE), + FAIRY_DEF_STRING(SHT_, MIPS_PIXIE), + FAIRY_DEF_STRING(SHT_, MIPS_XLATE), + FAIRY_DEF_STRING(SHT_, MIPS_XLATE_DEBUG), + FAIRY_DEF_STRING(SHT_, MIPS_WHIRL), + FAIRY_DEF_STRING(SHT_, MIPS_EH_REGION), + FAIRY_DEF_STRING(SHT_, MIPS_XLATE_OLD), + FAIRY_DEF_STRING(SHT_, MIPS_PDR_EXCEPTION), + // FAIRY_DEF_STRING(SHT_, MIPS_XHASH), /* New in 2019 */ + { 0 }, +}; + +// clang-format on diff --git a/tools/fado/lib/fairy/fairy_print.c b/tools/fado/lib/fairy/fairy_print.c new file mode 100644 index 00000000..80b8fcd9 --- /dev/null +++ b/tools/fado/lib/fairy/fairy_print.c @@ -0,0 +1,463 @@ +/** + * Functions for printing various sections of an N64 ELF file using the functions in Fairy, similarly to readelf + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fairy.h" + +#include +#include +#include +#include +#include +#include + +#include "fairy_data.inc" + +void Fairy_PrintSymbolTable(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + size_t shstrndx; + char* shstrtab; + FairySym* symbolTable = NULL; + size_t symbolTableNum = 0; + char* strtab = NULL; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size); + + { + size_t currentIndex; + size_t strtabndx = 0; + for (currentIndex = 0; currentIndex < fileHeader.e_shnum; currentIndex++) { + FairySecHeader currentHeader = sectionTable[currentIndex]; + + switch (currentHeader.sh_type) { + case SHT_SYMTAB: + if (strcmp(&shstrtab[currentHeader.sh_name], ".symtab") == 0) { + printf("symtab found\n"); + symbolTableNum = Fairy_ReadSymbolTable(&symbolTable, inputFile, currentHeader.sh_offset, + currentHeader.sh_size); + } + break; + + case SHT_STRTAB: + if (strcmp(&shstrtab[currentHeader.sh_name], ".strtab") == 0) { + strtabndx = currentIndex; + } + break; + + default: + break; + } + } + + if (symbolTable == NULL) { + puts("No symtab found."); + free(sectionTable); + return; + } + + if (strtabndx != 0) { + printf("strtab found\n"); + printf("Size: %X bytes\n", sectionTable[strtabndx].sh_size); + strtab = malloc(sectionTable[strtabndx].sh_size); + printf("and mallocked\n"); + fseek(inputFile, sectionTable[strtabndx].sh_offset, SEEK_SET); + printf("file offset sought: %X\n", sectionTable[strtabndx].sh_offset); + assert(fread(strtab, sizeof(char), sectionTable[strtabndx].sh_size, inputFile) == + sectionTable[strtabndx].sh_size); + printf("file read\n"); + } + } + + { + size_t currentIndex; + printf("Symbol table\n"); + printf(" Num: Value Size Type Bind Vis Ndx Name\n"); + for (currentIndex = 0; currentIndex < symbolTableNum; currentIndex++) { + FairySym currentSymbol = symbolTable[currentIndex]; + printf("%4zd: ", currentIndex); + printf("%08X ", currentSymbol.st_value); + printf("%4X ", currentSymbol.st_size); + printf("%-11s ", Fairy_StringFromDefine(stTypes, ELF32_ST_TYPE(currentSymbol.st_info))); + printf("%-10s ", Fairy_StringFromDefine(stBinds, ELF32_ST_BIND(currentSymbol.st_info))); + printf("%-11s ", Fairy_StringFromDefine(stVisibilities, ELF32_ST_VISIBILITY(currentSymbol.st_other))); + + if (currentSymbol.st_shndx != 0) { + printf("%3X ", currentSymbol.st_shndx); + } else { + printf("UND "); + } + + if (strtab != NULL) { + printf("%s", &strtab[currentSymbol.st_name]); + } else { + printf("%4X ", currentSymbol.st_name); + } + putchar('\n'); + } + } + + free(sectionTable); + free(symbolTable); + if (strtab != NULL) { + free(strtab); + } +} + +void Fairy_PrintRelocs(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + FairyRela* relocs; + size_t shstrndx; + char* shstrtab; + size_t currentSection; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size); + + for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) { + size_t nRelocs; + + if (sectionTable[currentSection].sh_type != SHT_REL || sectionTable[currentSection].sh_type != SHT_RELA) { + continue; + } + printf("Section size: %d\n", sectionTable[currentSection].sh_size); + + nRelocs = Fairy_ReadRelocs(&relocs, inputFile, sectionTable[currentSection].sh_type, + sectionTable[currentSection].sh_offset, sectionTable[currentSection].sh_size); + + // fseek(inputFile, sectionTable[currentSection].sh_offset, SEEK_SET); + // assert(fread(relocs, sizeof(char), sectionTable[currentSection].sh_size, inputFile) == + // sectionTable[currentSection].sh_size); + + printf("Relocs in section [%2zd]: %s:\n", currentSection, shstrtab + sectionTable[currentSection].sh_name); + printf("Offset Info Type Symbol\n"); + { + size_t currentReloc; + for (currentReloc = 0; currentReloc < nRelocs; currentReloc++) { + printf("%08X,%08X ", relocs[currentReloc].r_offset, relocs[currentReloc].r_info); + + switch (ELF32_R_TYPE(relocs[currentReloc].r_info)) { + case R_MIPS_NONE: + printf("%-15s", "R_MIPS_NONE"); + break; + case R_MIPS_16: + printf("%-15s", "R_MIPS_16"); + break; + case R_MIPS_32: + printf("%-15s", "R_MIPS_32"); + break; + case R_MIPS_REL32: + printf("%-15s", "R_MIPS_REL32"); + break; + case R_MIPS_26: + printf("%-15s", "R_MIPS_26"); + break; + case R_MIPS_HI16: + printf("%-15s", "R_MIPS_HI16"); + break; + case R_MIPS_LO16: + printf("%-15s", "R_MIPS_LO16"); + break; + default: + break; + } + + printf("%X", ELF32_R_SYM(relocs[currentReloc].r_info)); + + putchar('\n'); + } + putchar('\n'); + } + putchar('\n'); + + free(relocs); + } + free(sectionTable); + free(shstrtab); +} + +void Fairy_PrintSectionTable(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + size_t shstrndx; + char* shstrtab; + size_t currentSection; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size); + + printf("[Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n"); + for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) { + FairySecHeader entry = sectionTable[currentSection]; + printf("[%2zd] ", currentSection); + printf("%-15s", shstrtab + entry.sh_name); + + printf("%-15s", Fairy_StringFromDefine(shTypes, entry.sh_type)); + + // printf("%08X ", entry.sh_type); + printf("%08X ", entry.sh_addr); + printf("%06X ", entry.sh_offset); + printf("%06X ", entry.sh_size); + printf("%02X ", entry.sh_entsize); + // printf("%08X ", entry.sh_flags); + + { + char flagChars[] = { 'W', 'A', 'X', 'M', 'S', 'I', 'L', 'O', 'G', 'T', 'C', 'x', 'o', 'E', 'p' }; + uint32_t flags = entry.sh_flags; + size_t shift; + int pad = 4; + for (shift = 0; shift < sizeof(flagChars); shift++) { + if ((flags >> shift) & 1) { + putchar(flagChars[shift]); + pad--; + } + } + if (pad > 0) { + printf("%*s", pad, ""); + } + } + + printf("%2X ", entry.sh_link); + printf("%3X ", entry.sh_info); + printf("%2X", entry.sh_addralign); + putchar('\n'); + } +} + +typedef enum { REL_SECTION_NONE, REL_SECTION_TEXT, REL_SECTION_DATA, REL_SECTION_RODATA } FairyOverlayRelSection; + +const char* relSectionStrings[] = { + NULL, + ".text", + ".data", + ".rodata", +}; + +static uint32_t Fairy_PackReloc(FairyOverlayRelSection sec, FairyRela rel) { + return (sec << 0x1E) | (ELF32_R_TYPE(rel.r_info) << 0x18) | rel.r_offset; +} + +void Fairy_PrintSectionSizes(FairySecHeader* sectionTable, FILE* inputFile, size_t tableSize, char* shstrtab) { + size_t number = tableSize / sizeof(FairySecHeader); + FairySecHeader currentHeader; + char* sectionName; + size_t relocSectionsCount = 0; + size_t* relocSectionIndices; + int* relocSectionSection; + size_t currentRelocSection = 0; + FairySecHeader symtabHeader; + FairySym* symtab; + FairySecHeader strtabHeader; + char* strtab = NULL; + // size_t symtabSize; + + uint32_t textSize = 0; + uint32_t dataSize = 0; + uint32_t rodataSize = 0; + uint32_t bssSize = 0; + uint32_t relocCount = 0; + + size_t currentSection; + bool symtabFound = false; + bool strtabFound = false; + /* Count the reloc sections */ + for (currentSection = 0; currentSection < number; currentSection++) { + if (sectionTable[currentSection].sh_type == SHT_REL || sectionTable[currentSection].sh_type == SHT_RELA) { + relocSectionsCount++; + } + } + printf("relocSectionsCount: %zd\n", relocSectionsCount); + + relocSectionIndices = malloc(relocSectionsCount * sizeof(int)); + relocSectionSection = malloc(relocSectionsCount * sizeof(int)); + + /* Find the section sizes and the reloc sections */ + for (currentSection = 0; currentSection < number; currentSection++) { + size_t off = 0; + + currentHeader = sectionTable[currentSection]; + sectionName = &shstrtab[currentHeader.sh_name + 1]; /* ignore the initial '.' */ + switch (currentHeader.sh_type) { + case SHT_PROGBITS: + if (Fairy_StartsWith(sectionName, "rodata")) { + printf("rodata\n"); + rodataSize += currentHeader.sh_size; + break; + } + if (Fairy_StartsWith(sectionName, "data")) { + printf("data\n"); + dataSize += currentHeader.sh_size; + break; + } + if (Fairy_StartsWith(sectionName, "text")) { + printf("text\n"); + textSize += currentHeader.sh_size; + break; + } + break; + + case SHT_NOBITS: + if (Fairy_StartsWith(sectionName, "bss")) { + printf("bss\n"); + bssSize += currentHeader.sh_size; + } + break; + + case SHT_RELA: + off += 1; + case SHT_REL: + relocSectionIndices[currentRelocSection] = currentSection; + off += 4; /* ignore the "rel."/"rela." part */ + if (Fairy_StartsWith(§ionName[off], "rodata")) { + printf("%s\n", sectionName); + relocSectionSection[currentRelocSection] = REL_SECTION_RODATA; + } else if (Fairy_StartsWith(§ionName[off], "data")) { + printf("%s\n", sectionName); + relocSectionSection[currentRelocSection] = REL_SECTION_DATA; + } else if (Fairy_StartsWith(§ionName[off], "text")) { + printf("%s\n", sectionName); + relocSectionSection[currentRelocSection] = REL_SECTION_TEXT; + } + + currentRelocSection++; + break; + + case SHT_SYMTAB: + if (Fairy_StartsWith(sectionName, "symtab")) { + symtabHeader = currentHeader; + symtabFound = true; + } + break; + + case SHT_STRTAB: + if (Fairy_StartsWith(sectionName, "strtab")) { + strtabHeader = currentHeader; + strtabFound = true; + } + break; + + default: + break; + } + } + /* Can use symbols here too */ + puts(".section .ovl"); + printf("# OverlayInfo\n"); + printf(".word 0x%08X # .text size\n", textSize); + printf(".word 0x%08X # .data size\n", dataSize); + printf(".word 0x%08X # .rodata size\n", rodataSize); + printf(".word 0x%08X # .bss size\n\n", bssSize); + + if (!symtabFound) { + fprintf(stderr, "Symbol table not found\n"); + return; + } + /* Obtain the symbol table */ + // TODO: Consider replacing this with a lighter-weight read: sufficient to get the name, shndx + Fairy_ReadSymbolTable(&symtab, inputFile, symtabHeader.sh_offset, symtabHeader.sh_size); + + if (!strtabFound) { + fprintf(stderr, "String table not found\n"); + } else { + /* Obtain the string table */ + strtab = malloc(strtabHeader.sh_size); + fseek(inputFile, strtabHeader.sh_offset, SEEK_SET); + assert(fread(strtab, sizeof(char), strtabHeader.sh_size, inputFile) == strtabHeader.sh_size); + } + + /* Do single-file relocs */ + { + FairyRela* relocs; + for (currentSection = 0; currentSection < relocSectionsCount; currentSection++) { + size_t currentReloc; + size_t nRelocs; + + currentHeader = sectionTable[relocSectionIndices[currentSection]]; + nRelocs = Fairy_ReadRelocs(&relocs, inputFile, currentHeader.sh_type, currentHeader.sh_offset, + currentHeader.sh_size); + + for (currentReloc = 0; currentReloc < nRelocs; currentReloc++) { + FairySym symbol = symtab[ELF32_R_SYM(relocs[currentReloc].r_info)]; + if (symbol.st_shndx == SHN_UNDEF) { + continue; // TODO: this is where multifile has to look elsewhere + } + + printf(".word 0x%08X", Fairy_PackReloc(relocSectionSection[currentSection], relocs[currentReloc])); + printf(" # %X (%s), %X, 0x%06X", relocSectionSection[currentSection], &shstrtab[currentHeader.sh_name], + ELF32_R_TYPE(relocs[currentReloc].r_info), relocs[currentReloc].r_offset); + if (strtab != NULL) { + printf(", %s", &strtab[symbol.st_name]); + } + putchar('\n'); + + relocCount++; + } + + free(relocs); + } + } + + printf(".word %d # relocCount\n", relocCount); + + { + uint32_t ovlSectionSize = ((relocCount + 8) & ~0x03) * sizeof(uint32_t); + + printf("\n.word 0x%08X # Overlay section size\n", ovlSectionSize); + } + + free(relocSectionIndices); + free(relocSectionSection); + if (strtab != NULL) { + free(strtab); + } +} + +void PrintZeldaReloc(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + size_t shstrndx; + char* shstrtab; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sizeof(char), sectionTable[shstrndx].sh_size, inputFile) == sectionTable[shstrndx].sh_size); + + Fairy_PrintSectionSizes(sectionTable, inputFile, fileHeader.e_shentsize * fileHeader.e_shnum, shstrtab); + + free(sectionTable); + free(shstrtab); +} diff --git a/tools/fado/lib/fairy/fairy_print.h b/tools/fado/lib/fairy/fairy_print.h new file mode 100644 index 00000000..85061be2 --- /dev/null +++ b/tools/fado/lib/fairy/fairy_print.h @@ -0,0 +1,7 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include + +void Fairy_PrintSymbolTable(FILE* inputFile); +void Fairy_PrintRelocs(FILE* inputFile); +void Fairy_PrintSectionTable(FILE* inputFile); diff --git a/tools/fado/lib/vc_vector/.gitrepo b/tools/fado/lib/vc_vector/.gitrepo new file mode 100644 index 00000000..7ab27b99 --- /dev/null +++ b/tools/fado/lib/vc_vector/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:skogorev/vc_vector.git + branch = master + commit = 39108a4b0aeb904636514b37f418c590084220a7 + parent = 462bee5811d54659236ca51481d01b76c69a37a7 + method = merge + cmdver = 0.4.3 diff --git a/tools/fado/lib/vc_vector/.travis.yml b/tools/fado/lib/vc_vector/.travis.yml new file mode 100644 index 00000000..f30dfb8e --- /dev/null +++ b/tools/fado/lib/vc_vector/.travis.yml @@ -0,0 +1,6 @@ +language: c +compiler: + - gcc + - clang +script: + - make && make test diff --git a/tools/fado/lib/vc_vector/LICENSE.md b/tools/fado/lib/vc_vector/LICENSE.md new file mode 100644 index 00000000..05929e19 --- /dev/null +++ b/tools/fado/lib/vc_vector/LICENSE.md @@ -0,0 +1,21 @@ +#The MIT License (MIT) + +*Copyright (c) 2016 Skogorev Anton* + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/fado/lib/vc_vector/Makefile b/tools/fado/lib/vc_vector/Makefile new file mode 100644 index 00000000..129ee97e --- /dev/null +++ b/tools/fado/lib/vc_vector/Makefile @@ -0,0 +1,33 @@ +OUT_DIR := build +CFLAGS := -O2 -g -std=c99 -Wall -Wextra -Wpedantic -Werror + +SRCS := $(wildcard *.c) +OBJS := $(patsubst %.c,$(OUT_DIR)/%.o,$(SRCS)) + +LIB_NAME := vc-vector +SOBJ := $(OUT_DIR)/lib$(LIB_NAME).so + +.PHONY: all lib test clean + +all: lib + +lib: $(SOBJ) + +test: $(OUT_DIR)/test_runner + $(OUT_DIR)/test_runner + +clean: + rm -rf $(OUT_DIR) + +$(OUT_DIR): + mkdir -p $(OUT_DIR) + +$(SOBJ): vc_vector.c | $(OUT_DIR) + $(CC) $(CFLAGS) -shared -fPIC $< -o $@ + +$(OUT_DIR)/%.o: %.c | $(OUT_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/test_runner: $(OBJS) | $(OUT_DIR) + $(CC) $^ -o $@ + diff --git a/tools/fado/lib/vc_vector/README.md b/tools/fado/lib/vc_vector/README.md new file mode 100644 index 00000000..c8f8b2ae --- /dev/null +++ b/tools/fado/lib/vc_vector/README.md @@ -0,0 +1,92 @@ +# vc_vector +Fast simple C vector implementation + +[![Build Status: make && make test](https://travis-ci.org/skogorev/vc_vector.svg)](https://travis-ci.org/skogorev/vc_vector) + +## Usage + +### Basic +```c +#include "vc_vector.h" + +int main() { + // Creates an empty vector with the default reserved size + // and without custom deleter. Vector will contain 'int' + vc_vector* v = vc_vector_create(0, sizeof(int), NULL); + if (!v) { + return 1; + } + + const int count = 10; + for (int i = 0; i < count; ++i) { + // The function takes a pointer to the elements, + // but the vector will make a copy of the element + vc_vector_push_back(v, &i); + } + + // Print each vector element + for (void* i = vc_vector_begin(v); + i != vc_vector_end(v); + i = vc_vector_next(v, i)) { + printf("%u; ", *(int*)i); + } + + vc_vector_release(v); + return 0; +} +``` + +### Advanced +```c +#include "vc_vector.h" + +struct Item { + int val1; + int val2; +}; + +int main() { + const int n = 10; + + // Creates an empty vector with the reserved size for the 'n' elements + // and with custom deleter 'free'. Vector will contain pointers to 'Item' + vc_vector* v = vc_vector_create(n, sizeof(struct Node*), free); + if (!v) { + return 1; + } + + struct Item* item = NULL; + const int count = n + 1; + // Vector automatically increases the reserved size when 'n + 1' will be added + for (int i = 0; i < count; ++i) { + // Creating item + item = malloc(sizeof(struct Item)); + if (!item) { + continue; + } + + item->val1 = i; + item->val2 = 0; + + // Pushing to the end of the vector + if (!vc_vector_push_back(v, item)) { + // If the item was not pushed, you have to delete it + free(item); + } + } + + // ... + + // Calls custom deleter 'free' for all items + // and releases the vector + vc_vector_release(v); + return 0; +} +``` + +## Projects that use vc_vector +[kraken.io](https://kraken.io/) + +## License + +[MIT License](LICENSE.md) diff --git a/tools/fado/lib/vc_vector/vc_vector.c b/tools/fado/lib/vc_vector/vc_vector.c new file mode 100644 index 00000000..426f1b0c --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector.c @@ -0,0 +1,329 @@ +#include "vc_vector.h" +#include +#include + +#define GROWTH_FACTOR 1.5 +#define DEFAULT_COUNT_OF_ELEMENTS 8 +#define MINIMUM_COUNT_OF_ELEMENTS 2 + +// ---------------------------------------------------------------------------- + +// vc_vector structure + +struct vc_vector { + size_t count; + size_t element_size; + size_t reserved_size; + char* data; + vc_vector_deleter* deleter; +}; + +// ---------------------------------------------------------------------------- + +// Auxiliary methods + +bool vc_vector_realloc(vc_vector* vector, size_t new_count) { + const size_t new_size = new_count * vector->element_size; + char* new_data = (char*)realloc(vector->data, new_size); + if (!new_data) { + return false; + } + + vector->reserved_size = new_size; + vector->data = new_data; + return true; +} + +// [first_index, last_index) +void vc_vector_call_deleter(vc_vector* vector, size_t first_index, size_t last_index) { + for (size_t i = first_index; i < last_index; ++i) { + vector->deleter(vc_vector_at(vector, i)); + } +} + +void vc_vector_call_deleter_all(vc_vector* vector) { + vc_vector_call_deleter(vector, 0, vc_vector_count(vector)); +} + +// ---------------------------------------------------------------------------- + +// Control + +vc_vector* vc_vector_create(size_t count_elements, size_t size_of_element, vc_vector_deleter* deleter) { + vc_vector* v = (vc_vector*)malloc(sizeof(vc_vector)); + if (v != NULL) { + v->data = NULL; + v->count = 0; + v->element_size = size_of_element; + v->deleter = deleter; + + if (count_elements < MINIMUM_COUNT_OF_ELEMENTS) { + count_elements = DEFAULT_COUNT_OF_ELEMENTS; + } + + if (size_of_element < 1 || + !vc_vector_realloc(v, count_elements)) { + free(v); + v = NULL; + } + } + + return v; +} + +vc_vector* vc_vector_create_copy(const vc_vector* vector) { + vc_vector* new_vector = vc_vector_create(vector->reserved_size / vector->count, + vector->element_size, + vector->deleter); + if (!new_vector) { + return new_vector; + } + + if (memcpy(vector->data, + new_vector->data, + new_vector->element_size * vector->count) == NULL) { + vc_vector_release(new_vector); + new_vector = NULL; + return new_vector; + } + + new_vector->count = vector->count; + return new_vector; +} + +void vc_vector_release(vc_vector* vector) { + if (vector->deleter != NULL) { + vc_vector_call_deleter_all(vector); + } + + if (vector->reserved_size != 0) { + free(vector->data); + } + + free(vector); +} + +bool vc_vector_is_equals(vc_vector* vector1, vc_vector* vector2) { + const size_t size_vector1 = vc_vector_size(vector1); + if (size_vector1 != vc_vector_size(vector2)) { + return false; + } + + return memcmp(vector1->data, vector2->data, size_vector1) == 0; +} + +float vc_vector_get_growth_factor(void) { + return GROWTH_FACTOR; +} + +size_t vc_vector_get_default_count_of_elements(void) { + return DEFAULT_COUNT_OF_ELEMENTS; +} + +size_t vc_vector_struct_size(void) { + return sizeof(vc_vector); +} + +// ---------------------------------------------------------------------------- + +// Element access + +void* vc_vector_at(vc_vector* vector, size_t index) { + return vector->data + index * vector->element_size; +} + +void* vc_vector_front(vc_vector* vector) { + return vector->data; +} + +void* vc_vector_back(vc_vector* vector) { + return vector->data + (vector->count - 1) * vector->element_size; +} + +void* vc_vector_data(vc_vector* vector) { + return vector->data; +} + +// ---------------------------------------------------------------------------- + +// Iterators + +void* vc_vector_begin(vc_vector* vector) { + return vector->data; +} + +void* vc_vector_end(vc_vector* vector) { + return vector->data + vector->element_size * vector->count; +} + +void* vc_vector_next(vc_vector* vector, void* i) { + return (char *)i + vector->element_size; +} + +// ---------------------------------------------------------------------------- + +// Capacity + +bool vc_vector_empty(vc_vector* vector) { + return vector->count == 0; +} + +size_t vc_vector_count(const vc_vector* vector) { + return vector->count; +} + +size_t vc_vector_size(const vc_vector* vector) { + return vector->count * vector->element_size; +} + +size_t vc_vector_max_count(const vc_vector* vector) { + return vector->reserved_size / vector->element_size; +} + +size_t vc_vector_max_size(const vc_vector* vector) { + return vector->reserved_size; +} + +bool vc_vector_reserve_count(vc_vector* vector, size_t new_count) { + if (new_count < vector->count) { + return false; + } + + size_t new_size = vector->element_size * new_count; + if (new_size == vector->reserved_size) { + return true; + } + + return vc_vector_realloc(vector, new_count); +} + +bool vc_vector_reserve_size(vc_vector* vector, size_t new_size) { + return vc_vector_reserve_count(vector, new_size / vector->element_size); +} + +// ---------------------------------------------------------------------------- + +// Modifiers + +void vc_vector_clear(vc_vector* vector) { + if (vector->deleter != NULL) { + vc_vector_call_deleter_all(vector); + } + + vector->count = 0; +} + +bool vc_vector_insert(vc_vector* vector, size_t index, const void* value) { + if (vc_vector_max_count(vector) < vector->count + 1) { + if (!vc_vector_realloc(vector, vc_vector_max_count(vector) * GROWTH_FACTOR)) { + return false; + } + } + + if (!memmove(vc_vector_at(vector, index + 1), + vc_vector_at(vector, index), + vector->element_size * (vector->count - index))) { + + return false; + } + + if (memcpy(vc_vector_at(vector, index), + value, + vector->element_size) == NULL) { + return false; + } + + ++vector->count; + return true; +} + +bool vc_vector_erase(vc_vector* vector, size_t index) { + if (vector->deleter != NULL) { + vector->deleter(vc_vector_at(vector, index)); + } + + if (!memmove(vc_vector_at(vector, index), + vc_vector_at(vector, index + 1), + vector->element_size * (vector->count - index))) { + return false; + } + + vector->count--; + return true; +} + +bool vc_vector_erase_range(vc_vector* vector, size_t first_index, size_t last_index) { + if (vector->deleter != NULL) { + vc_vector_call_deleter(vector, first_index, last_index); + } + + if (!memmove(vc_vector_at(vector, first_index), + vc_vector_at(vector, last_index), + vector->element_size * (vector->count - last_index))) { + return false; + } + + vector->count -= last_index - first_index; + return true; +} + +bool vc_vector_append(vc_vector* vector, const void* values, size_t count) { + const size_t count_new = count + vc_vector_count(vector); + + if (vc_vector_max_count(vector) < count_new) { + size_t max_count_to_reserved = vc_vector_max_count(vector) * GROWTH_FACTOR; + while (count_new > max_count_to_reserved) { + max_count_to_reserved *= GROWTH_FACTOR; + } + + if (!vc_vector_realloc(vector, max_count_to_reserved)) { + return false; + } + } + + if (memcpy(vector->data + vector->count * vector->element_size, + values, + vector->element_size * count) == NULL) { + return false; + } + + vector->count = count_new; + return true; +} + +bool vc_vector_push_back(vc_vector* vector, const void* value) { + if (!vc_vector_append(vector, value, 1)) { + return false; + } + + return true; +} + +bool vc_vector_pop_back(vc_vector* vector) { + if (vector->deleter != NULL) { + vector->deleter(vc_vector_back(vector)); + } + + vector->count--; + return true; +} + +bool vc_vector_replace(vc_vector* vector, size_t index, const void* value) { + if (vector->deleter != NULL) { + vector->deleter(vc_vector_at(vector, index)); + } + + return memcpy(vc_vector_at(vector, index), + value, + vector->element_size) != NULL; +} + +bool vc_vector_replace_multiple(vc_vector* vector, size_t index, const void* values, size_t count) { + if (vector->deleter != NULL) { + vc_vector_call_deleter(vector, index, index + count); + } + + return memcpy(vc_vector_at(vector, index), + values, + vector->element_size * count) != NULL; +} diff --git a/tools/fado/lib/vc_vector/vc_vector.h b/tools/fado/lib/vc_vector/vc_vector.h new file mode 100644 index 00000000..e57f8325 --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector.h @@ -0,0 +1,120 @@ +#ifndef VCVECTOR_H +#define VCVECTOR_H + +#include +#include + +typedef struct vc_vector vc_vector; +typedef void (vc_vector_deleter)(void *); + +// ---------------------------------------------------------------------------- +// Control +// ---------------------------------------------------------------------------- + +// Constructs an empty vector with an reserver size for count_elements. +vc_vector* vc_vector_create(size_t count_elements, size_t size_of_element, vc_vector_deleter* deleter); + +// Constructs a copy of an existing vector. +vc_vector* vc_vector_create_copy(const vc_vector* vector); + +// Releases the vector. +void vc_vector_release(vc_vector* vector); + +// Compares vector content +bool vc_vector_is_equals(vc_vector* vector1, vc_vector* vector2); + +// Returns constant value of the vector growth factor. +float vc_vector_get_growth_factor(void); + +// Returns constant value of the vector default count of elements. +size_t vc_vector_get_default_count_of_elements(void); + +// Returns constant value of the vector struct size. +size_t vc_vector_struct_size(void); + +// ---------------------------------------------------------------------------- +// Element access +// ---------------------------------------------------------------------------- + +// Returns the item at index position in the vector. +void* vc_vector_at(vc_vector* vector, size_t index); + +// Returns the first item in the vector. +void* vc_vector_front(vc_vector* vector); + +// Returns the last item in the vector. +void* vc_vector_back(vc_vector* vector); + +// Returns a pointer to the data stored in the vector. The pointer can be used to access and modify the items in the vector. +void* vc_vector_data(vc_vector* vector); + +// ---------------------------------------------------------------------------- +// Iterators +// ---------------------------------------------------------------------------- + +// Returns a pointer to the first item in the vector. +void* vc_vector_begin(vc_vector* vector); + +// Returns a pointer to the imaginary item after the last item in the vector. +void* vc_vector_end(vc_vector* vector); + +// Returns a pointer to the next element of vector after 'i'. +void* vc_vector_next(vc_vector* vector, void* i); + +// ---------------------------------------------------------------------------- +// Capacity +// ---------------------------------------------------------------------------- + +// Returns true if the vector is empty; otherwise returns false. +bool vc_vector_empty(vc_vector* vector); + +// Returns the number of elements in the vector. +size_t vc_vector_count(const vc_vector* vector); + +// Returns the size (in bytes) of occurrences of value in the vector. +size_t vc_vector_size(const vc_vector* vector); + +// Returns the maximum number of elements that the vector can hold. +size_t vc_vector_max_count(const vc_vector* vector); + +// Returns the maximum size (in bytes) that the vector can hold. +size_t vc_vector_max_size(const vc_vector* vector); + +// Resizes the container so that it contains n elements. +bool vc_vector_reserve_count(vc_vector* vector, size_t new_count); + +// Resizes the container so that it contains new_size / element_size elements. +bool vc_vector_reserve_size(vc_vector* vector, size_t new_size); + +// ---------------------------------------------------------------------------- +// Modifiers +// ---------------------------------------------------------------------------- + +// Removes all elements from the vector (without reallocation). +void vc_vector_clear(vc_vector* vector); + +// The container is extended by inserting a new element at position. +bool vc_vector_insert(vc_vector* vector, size_t index, const void* value); + +// Removes from the vector a single element by 'index' +bool vc_vector_erase(vc_vector* vector, size_t index); + +// Removes from the vector a range of elements '[first_index, last_index)'. +bool vc_vector_erase_range(vc_vector* vector, size_t first_index, size_t last_index); + +// Inserts multiple values at the end of the vector. +bool vc_vector_append(vc_vector* vector, const void* values, size_t count); + +// Inserts value at the end of the vector. +bool vc_vector_push_back(vc_vector* vector, const void* value); + +// Removes the last item in the vector. +bool vc_vector_pop_back(vc_vector* vector); + +// Replace value by index in the vector. +bool vc_vector_replace(vc_vector* vector, size_t index, const void* value); + +// Replace multiple values by index in the vector. +bool vc_vector_replace_multiple(vc_vector* vector, size_t index, const void* values, size_t count); + +#endif // VCVECTOR_H diff --git a/tools/fado/lib/vc_vector/vc_vector_test.c b/tools/fado/lib/vc_vector/vc_vector_test.c new file mode 100644 index 00000000..03a05442 --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector_test.c @@ -0,0 +1,353 @@ +#include "vc_vector_test.h" +#include +#include +#include +#include "vc_vector.h" + +#define ASSERT_EQ(expected, actual) \ + do { \ + if ((expected) != (actual)) { \ + fprintf(stderr, \ + "Failed line %u. Expected: %"PRIuMAX". Actual: %"PRIuMAX".\n", \ + __LINE__, (uintmax_t)(expected), (uintmax_t)(actual)); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_NE(not_expected, actual) \ + do { \ + if ((not_expected) == (actual)) { \ + fprintf(stderr, \ + "Failed line %u. Unexpected actual value: %"PRIuMAX".\n", \ + __LINE__, (uintmax_t)(actual)); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_TRUE(actual) ASSERT_EQ(true, (actual)) + +#define ASSERT_FALSE(actual) ASSERT_EQ(false, (actual)) + +#define PRINT_VECTOR(vector, type, format) \ + do { \ + for (void* i = vc_vector_begin(vector); \ + i != vc_vector_end(vector); \ + i = vc_vector_next(vector, i)) { \ + fprintf(stderr, format, *(type*)i); \ + } \ + fprintf(stderr, "\n"); \ + } while (0) + +#define PRINT_VECTOR_INT(vector) PRINT_VECTOR(vector, int, "%d; ") +#define PRINT_VECTOR_STR(vector) PRINT_VECTOR(vector, char *, "%s; ") + +char *mystrdup(const char *s) { + size_t size = strlen(s) + 1; + char *copy = malloc(size); + if (copy != NULL) + memcpy(copy, s, size); + return copy; +} + +// ---------------------------------------------------------------------------- + +void test_vc_vector_create() { + const size_t size_of_type = sizeof(int); + const size_t default_count_of_elements = vc_vector_get_default_count_of_elements(); + + // Creating vector with default count of elements + vc_vector* vector = vc_vector_create(0, size_of_type, NULL); + ASSERT_NE(NULL, vector); + ASSERT_EQ(0, vc_vector_count(vector)); + ASSERT_EQ(0, vc_vector_size(vector)); + ASSERT_EQ(default_count_of_elements, vc_vector_max_count(vector)); + ASSERT_EQ(size_of_type * default_count_of_elements, vc_vector_max_size(vector)); + vc_vector_release(vector); + + // Creating vector with custom count of elements + const size_t test_count_of_elements = 7; + vector = vc_vector_create(test_count_of_elements, size_of_type, NULL); + ASSERT_NE(NULL, vector); + ASSERT_EQ(0, vc_vector_count(vector)); + ASSERT_EQ(0, vc_vector_size(vector)); + ASSERT_EQ(test_count_of_elements, vc_vector_max_count(vector)); + ASSERT_EQ(size_of_type * test_count_of_elements, vc_vector_max_size(vector)); + vc_vector_release(vector); + + // Creating vector with zero size of single element + vector = vc_vector_create(0, 0, NULL); + ASSERT_EQ(NULL, vector); + + // Creating copy of vector + vector = vc_vector_create(0, size_of_type, NULL); + ASSERT_NE(NULL, vector); + for (int i = 0; (size_t)i < test_count_of_elements; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + vc_vector* vector_copy = vc_vector_create_copy(vector); + ASSERT_NE(NULL, vector_copy); + ASSERT_TRUE(vc_vector_is_equals(vector, vector_copy)); + + vc_vector_release(vector_copy); + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_element_access() { + const int test_num_start = 18; + const int test_num_end = 36; + const size_t size_of_type = sizeof(test_num_start); + + vc_vector* vector = vc_vector_create(0, size_of_type, NULL); + ASSERT_NE(0, vector); + for (int i = test_num_start; i <= test_num_end; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + ASSERT_EQ(test_num_start, *(int*)vc_vector_front(vector)); + ASSERT_EQ(test_num_start, *(int*)vc_vector_data(vector)); + ASSERT_EQ(test_num_end, *(int*)vc_vector_back(vector)); + + for (int i = test_num_start, j = 0; i <= test_num_end; ++i, ++j) { + ASSERT_EQ(i, *(int*)vc_vector_at(vector, j)); + } + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_iterators() { + vc_vector* vector = vc_vector_create(0, sizeof(int), NULL); + ASSERT_NE(NULL, vector); + + const size_t test_count_of_elements = 23; + for (int i = 0; (size_t)i < test_count_of_elements; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + int j = 0; + for (void* i = vc_vector_begin(vector); + i != vc_vector_end(vector); + i = vc_vector_next(vector, i), ++j) { + ASSERT_EQ(j, *(int*)i); + } + + ASSERT_EQ(test_count_of_elements, (size_t)j); + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_capacity() { + const size_t size_of_element = sizeof(int); + const float growth_factor = vc_vector_get_growth_factor(); + ASSERT_EQ(1.5, growth_factor); + + const size_t count_of_elements_initialized = 22; + const size_t max_size_of_vector_initialized = count_of_elements_initialized * size_of_element; + const size_t count_of_elements_ended = 23; + const size_t size_of_vector_ended = count_of_elements_ended * size_of_element; + const size_t max_count_of_vector_ended = count_of_elements_initialized * growth_factor; + const size_t max_size_of_vector_ended = max_count_of_vector_ended * size_of_element; + + vc_vector* vector = vc_vector_create(count_of_elements_initialized, size_of_element, NULL); + ASSERT_NE(NULL, vector); + + ASSERT_EQ(0, vc_vector_count(vector)); + ASSERT_TRUE(vc_vector_empty(vector)); + ASSERT_EQ(0, vc_vector_size(vector)); + ASSERT_EQ(count_of_elements_initialized, vc_vector_max_count(vector)); + ASSERT_EQ(max_size_of_vector_initialized, vc_vector_max_size(vector)); + + for (int i = 0; (size_t)i < count_of_elements_ended; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + ASSERT_EQ(count_of_elements_ended, vc_vector_count(vector)); + ASSERT_FALSE(vc_vector_empty(vector)); + ASSERT_EQ(size_of_vector_ended, vc_vector_size(vector)); + ASSERT_EQ(max_count_of_vector_ended, vc_vector_max_count(vector)); + ASSERT_EQ(max_size_of_vector_ended, vc_vector_max_size(vector)); + + const size_t test_reserve_count_fail = 10; + ASSERT_FALSE(vc_vector_reserve_count(vector, test_reserve_count_fail)); + + const size_t test_reserve_count = 35; + ASSERT_TRUE(vc_vector_reserve_count(vector, test_reserve_count)); + ASSERT_EQ(test_reserve_count, vc_vector_max_count(vector)); + ASSERT_EQ(test_reserve_count * size_of_element, vc_vector_max_size(vector)); + + // Second time with the same value + ASSERT_TRUE(vc_vector_reserve_count(vector, test_reserve_count)); + ASSERT_EQ(test_reserve_count, vc_vector_max_count(vector)); + ASSERT_EQ(test_reserve_count * size_of_element, vc_vector_max_size(vector)); + + const size_t test_reserve_size = 123 * size_of_element; + ASSERT_TRUE(vc_vector_reserve_size(vector, test_reserve_size)); + ASSERT_EQ(test_reserve_size / size_of_element, vc_vector_max_count(vector)); + ASSERT_EQ(test_reserve_size, vc_vector_max_size(vector)); + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_modifiers() { + const int begin[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 + }; + const size_t size_of_element = sizeof(begin[0]); + const size_t count_of_elements = sizeof(begin) / size_of_element; + + // After deleting first, last and one middle elements + const int after_deleting_some_elements[] = { + /* 1, */ 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 11, */ 12, 13, 14, 15, 16, 17, 18, 19, /* 20 */ + }; + + // After deleting first 3 elemets from begin, 4 from middle and 3 from end + const int after_deleting_some_ranges[] = { + /* 1, 2, 3, */ 4, 5, 6, 7, 8, /* 9, 10, 11, 12, */ 13, 14, 15, 16, 17, /* 18, 19, 20 */ + }; + + vc_vector* vector = vc_vector_create(0, size_of_element, NULL); + ASSERT_NE(NULL, vector); + + // Append test + + ASSERT_TRUE(vc_vector_append(vector, begin, count_of_elements)); + + ASSERT_EQ(count_of_elements, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(begin[i], *(int*)vc_vector_at(vector, i)); + } + + // Pop back test + + while (vc_vector_count(vector) > 0) { + ASSERT_TRUE(vc_vector_pop_back(vector)); + } + + ASSERT_TRUE(vc_vector_empty(vector)); + + // Push back test + + for (size_t i = 0; i < count_of_elements; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &begin[i])); + } + + ASSERT_EQ(count_of_elements, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(begin[i], *(int*)vc_vector_at(vector, i)); + } + + // Erase test + + vc_vector_clear(vector); + ASSERT_TRUE(vc_vector_append(vector, begin, count_of_elements)); + + ASSERT_TRUE(vc_vector_erase(vector, 0)); + ASSERT_TRUE(vc_vector_erase(vector, vc_vector_count(vector) - 1)); + ASSERT_TRUE(vc_vector_erase(vector, vc_vector_count(vector) / 2)); + + ASSERT_EQ(sizeof(after_deleting_some_elements) / size_of_element, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(after_deleting_some_elements[i], *(int*)vc_vector_at(vector, i)); + } + + // Erase range test + + vc_vector_clear(vector); + ASSERT_TRUE(vc_vector_append(vector, begin, count_of_elements)); + + ASSERT_TRUE(vc_vector_erase_range(vector, 0, 3)); + ASSERT_TRUE(vc_vector_erase_range(vector, vc_vector_count(vector) - 3, vc_vector_count(vector))); + ASSERT_TRUE(vc_vector_erase_range(vector, vc_vector_count(vector) / 2 - 2, vc_vector_count(vector) / 2 + 2)); + + ASSERT_EQ(sizeof(after_deleting_some_ranges) / size_of_element, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(after_deleting_some_ranges[i], *(int*)vc_vector_at(vector, i)); + } + + // Insert test + + vc_vector_clear(vector); + for (size_t i = 1; i < count_of_elements - 1; ++i) { + ASSERT_TRUE(vc_vector_insert(vector, i - 1, &begin[i])); + } + + ASSERT_TRUE(vc_vector_insert(vector, 0, &begin[0])); + ASSERT_TRUE(vc_vector_insert(vector, vc_vector_count(vector), &begin[count_of_elements - 1])); + + ASSERT_EQ(count_of_elements, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(begin[i], *(int*)vc_vector_at(vector, i)); + } + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_strfreefunc(void *data) { + free(*(char **)data); +} + +void test_vc_vector_with_strfreefunc() { + // creates a vector of pointers to char, i.e. a vector of variable sized strings + vc_vector* vector = vc_vector_create(3, sizeof(char *), test_vc_vector_strfreefunc); + ASSERT_NE(NULL, vector); + + char *strs[] = { + mystrdup("abcde"), + mystrdup("edcba"), + mystrdup("1234554321"), + mystrdup("!@#$%"), + mystrdup("not empty string"), + mystrdup(""), + mystrdup("Hello World"), + mystrdup("xxxxx"), + mystrdup("yyyyy") + }; + + for (size_t i = 0; i < 3; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &strs[i])); + } + + ASSERT_EQ(3, vc_vector_count(vector)); + + for (size_t i = 3; i < 6; ++i) { + ASSERT_TRUE(vc_vector_insert(vector, i, &strs[i])); + } + + ASSERT_EQ(6, vc_vector_count(vector)); + vc_vector_clear(vector); // strs[0-6] were freed + ASSERT_EQ(0, vc_vector_count(vector)); + + for (size_t i = 6; i < 9; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &strs[i])); + } + + ASSERT_EQ(3, vc_vector_count(vector)); + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void vc_vector_run_tests() { + test_vc_vector_create(); + test_vc_vector_element_access(); + test_vc_vector_iterators(); + test_vc_vector_capacity(); + test_vc_vector_modifiers(); + test_vc_vector_with_strfreefunc(); +} + +int main() { + vc_vector_run_tests(); + printf("Tests passed.\n"); + return 0; +} diff --git a/tools/fado/lib/vc_vector/vc_vector_test.h b/tools/fado/lib/vc_vector/vc_vector_test.h new file mode 100644 index 00000000..9439ea3c --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector_test.h @@ -0,0 +1,6 @@ +#ifndef VCVECTORTESTS_H +#define VCVECTORTESTS_H + +void vc_vector_run_tests(); + +#endif // VCVECTORTESTS_H diff --git a/tools/fado/ovl_En_Hs_reloc.s b/tools/fado/ovl_En_Hs_reloc.s new file mode 100644 index 00000000..d41d172d --- /dev/null +++ b/tools/fado/ovl_En_Hs_reloc.s @@ -0,0 +1,46 @@ +.section .ovl +# ovl_En_Hs2OverlayInfo +.word _ovl_En_Hs2SegmentTextSize +.word _ovl_En_Hs2SegmentDataSize +.word _ovl_En_Hs2SegmentRoDataSize +.word _ovl_En_Hs2SegmentBssSize + +.word 28 # relocCount + +# TEXT RELOCS +.word 0x45000084 # R_MIPS_HI16 0x000084 .data +.word 0x4600008C # R_MIPS_LO16 0x00008C .data +.word 0x450000B4 # R_MIPS_HI16 0x0000B4 .rodata +.word 0x460000BC # R_MIPS_LO16 0x0000BC .rodata +.word 0x450000C0 # R_MIPS_HI16 0x0000C0 func_80A6F1A4 +.word 0x460000C4 # R_MIPS_LO16 0x0000C4 func_80A6F1A4 +.word 0x450001DC # R_MIPS_HI16 0x0001DC func_80A6F1A4 +.word 0x460001E0 # R_MIPS_LO16 0x0001E0 func_80A6F1A4 +.word 0x4500022C # R_MIPS_HI16 0x00022C func_80A6F164 +.word 0x46000230 # R_MIPS_LO16 0x000230 func_80A6F164 +.word 0x44000238 # R_MIPS_26 0x000238 func_80A6F0B4 +.word 0x450003D0 # R_MIPS_HI16 0x0003D0 .rodata +.word 0x460003D8 # R_MIPS_LO16 0x0003D8 .rodata +.word 0x45000460 # R_MIPS_HI16 0x000460 .data +.word 0x46000464 # R_MIPS_LO16 0x000464 .data +.word 0x4500049C # R_MIPS_HI16 0x00049C EnHs2_OverrideLimbDraw +.word 0x460004B4 # R_MIPS_LO16 0x0004B4 EnHs2_OverrideLimbDraw +.word 0x450004A0 # R_MIPS_HI16 0x0004A0 EnHs2_PostLimbDraw +.word 0x460004B0 # R_MIPS_LO16 0x0004B0 EnHs2_PostLimbDraw + +# DATA RELOCS +.word 0x82000010 # R_MIPS_32 0x000010 EnHs2_Init +.word 0x82000014 # R_MIPS_32 0x000014 EnHs2_Destroy +.word 0x82000018 # R_MIPS_32 0x000018 EnHs2_Update +.word 0x8200001C # R_MIPS_32 0x00001C EnHs2_Draw + +# RODATA RELOCS +.word 0xC2000020 # R_MIPS_32 0x000020 .text +.word 0xC2000024 # R_MIPS_32 0x000024 .text +.word 0xC2000028 # R_MIPS_32 0x000028 .text +.word 0xC200002C # R_MIPS_32 0x00002C .text +.word 0xC2000030 # R_MIPS_32 0x000030 .text +.word 0 +.word 0 + +.word 0x00000090 # ovl_En_Hs2OverlayInfoOffset diff --git a/tools/fado/src/fado.c b/tools/fado/src/fado.c new file mode 100644 index 00000000..464f8855 --- /dev/null +++ b/tools/fado/src/fado.c @@ -0,0 +1,308 @@ +/** + * Code specific to reading and outputting Zelda 64 relocations + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fado.h" + +#include +#include +#include +#include +#include +#include +#include "fairy/fairy.h" +#include "macros.h" +#include "vc_vector/vc_vector.h" + +/* String-finding-related functions */ + +bool Fado_CheckInProgBitsSections(Elf32_Section section, vc_vector* progBitsSections) { + Elf32_Section* i; + VC_FOREACH(i, progBitsSections) { + if (*i == section) { + return true; + } + } + return false; +} + +/** + * For each input file, construct a vector of pointers to the starts of the strings defined in that file. + */ +void Fado_ConstructStringVectors(vc_vector** stringVectors, FairyFileInfo* fileInfo, int numFiles) { + int currentFile; + size_t currentSym; + + for (currentFile = 0; currentFile < numFiles; currentFile++) { + FairySym* symtab = fileInfo[currentFile].symtabInfo.sectionData; + + stringVectors[currentFile] = vc_vector_create(0x40, sizeof(char**), NULL); + + /* Build a vector of pointers to defined symbols' names */ + for (currentSym = 0; currentSym < fileInfo[currentFile].symtabInfo.sectionEntryCount; currentSym++) { + if ((symtab[currentSym].st_shndx != STN_UNDEF) && + Fado_CheckInProgBitsSections(symtab[currentSym].st_shndx, fileInfo[currentFile].progBitsSections)) { + /* Have to pass a double pointer so it copies the pointer instead of the start of the string */ + char* stringPtr = &fileInfo[currentFile].strtab[symtab[currentSym].st_name]; + assert(vc_vector_push_back(stringVectors[currentFile], &stringPtr)); + } + } + } +} + +bool Fado_FindSymbolNameInOtherFiles(const char* name, int thisFile, vc_vector** stringVectors, int numFiles) { + int currentFile; + char** currentString; + + for (currentFile = 0; currentFile < numFiles; currentFile++) { + if (currentFile == thisFile) { + continue; + } + VC_FOREACH(currentString, stringVectors[currentFile]) { + if (strcmp(name, *currentString) == 0) { + FAIRY_DEBUG_PRINTF("Match found for %s\n", name); + return true; + } + } + } + FAIRY_DEBUG_PRINTF("No match found for %s\n", name); + return false; +} + +void Fado_DestroyStringVectors(vc_vector** stringVectors, int numFiles) { + int currentFile; + for (currentFile = 0; currentFile < numFiles; currentFile++) { + vc_vector_release(stringVectors[currentFile]); + } + free(stringVectors); +} + +typedef struct { + size_t symbolIndex; + int file; + uint32_t relocWord; +} FadoRelocInfo; + +/* Construct the Zelda64ovl-compatible reloc word from an ELF reloc */ +FadoRelocInfo Fado_MakeReloc(int file, FairySection section, FairyRela* data) { + FadoRelocInfo relocInfo = { 0 }; + uint32_t sectionPrefix = 0; + + relocInfo.symbolIndex = ELF32_R_SYM(data->r_info); + relocInfo.file = file; + + switch (section) { + case FAIRY_SECTION_TEXT: + sectionPrefix = 1; + break; + + case FAIRY_SECTION_DATA: + sectionPrefix = 2; + break; + + case FAIRY_SECTION_RODATA: + sectionPrefix = 3; + break; + + default: + fprintf(stderr, "warning: Relocation section is invalid.\n"); + break; + } + relocInfo.relocWord = + ((sectionPrefix & 3) << 0x1E) | (ELF32_R_TYPE(data->r_info) << 0x18) | (data->r_offset & 0xFFFFFF); + + return relocInfo; +} + +static const FairyDefineString relSectionNames[] = { + FAIRY_DEF_STRING(FAIRY_SECTION_, TEXT), + FAIRY_DEF_STRING(FAIRY_SECTION_, DATA), + FAIRY_DEF_STRING(FAIRY_SECTION_, RODATA), + { 0 }, +}; + +/* Taken from elf.h/mips_elf.h */ +static const FairyDefineString relTypeNames[] = { + FAIRY_DEF_STRING(, R_MIPS_NONE), /* No reloc */ + FAIRY_DEF_STRING(, R_MIPS_16), /* Direct 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_32), /* Direct 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_REL32), /* PC relative 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_26), /* Direct 26 bit shifted */ + FAIRY_DEF_STRING(, R_MIPS_HI16), /* High 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_LO16), /* Low 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_GPREL16), /* GP relative 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_LITERAL), /* 16 bit literal entry */ + FAIRY_DEF_STRING(, R_MIPS_GOT16), /* 16 bit GOT entry */ + FAIRY_DEF_STRING(, R_MIPS_PC16), /* PC relative 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_CALL16), /* 16 bit GOT entry for function */ + FAIRY_DEF_STRING(, R_MIPS_GPREL32), /* GP relative 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_SHIFT5), + FAIRY_DEF_STRING(, R_MIPS_SHIFT6), + FAIRY_DEF_STRING(, R_MIPS_64), + FAIRY_DEF_STRING(, R_MIPS_GOT_DISP), + FAIRY_DEF_STRING(, R_MIPS_GOT_PAGE), + FAIRY_DEF_STRING(, R_MIPS_GOT_OFST), + FAIRY_DEF_STRING(, R_MIPS_GOT_HI16), + FAIRY_DEF_STRING(, R_MIPS_GOT_LO16), + FAIRY_DEF_STRING(, R_MIPS_SUB), + FAIRY_DEF_STRING(, R_MIPS_INSERT_A), + FAIRY_DEF_STRING(, R_MIPS_INSERT_B), + FAIRY_DEF_STRING(, R_MIPS_DELETE), + FAIRY_DEF_STRING(, R_MIPS_HIGHER), + FAIRY_DEF_STRING(, R_MIPS_HIGHEST), + FAIRY_DEF_STRING(, R_MIPS_CALL_HI16), + FAIRY_DEF_STRING(, R_MIPS_CALL_LO16), + FAIRY_DEF_STRING(, R_MIPS_SCN_DISP), + FAIRY_DEF_STRING(, R_MIPS_REL16), + FAIRY_DEF_STRING(, R_MIPS_ADD_IMMEDIATE), + FAIRY_DEF_STRING(, R_MIPS_PJUMP), + FAIRY_DEF_STRING(, R_MIPS_RELGOT), + FAIRY_DEF_STRING(, R_MIPS_JALR), + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPMOD32), /* Module number 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL32), /* Module-relative offset 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPMOD64), /* Module number 64 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL64), /* Module-relative offset 64 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_GD), /* 16 bit GOT offset for GD */ + FAIRY_DEF_STRING(, R_MIPS_TLS_LDM), /* 16 bit GOT offset for LDM */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL_HI16), /* Module-relative offset, high 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL_LO16), /* Module-relative offset, low 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_TLS_GOTTPREL), /* 16 bit GOT offset for IE */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL32), /* TP-relative offset, 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL64), /* TP-relative offset, 64 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL_HI16), /* TP-relative offset, high 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL_LO16), /* TP-relative offset, low 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_GLOB_DAT), + FAIRY_DEF_STRING(, R_MIPS_COPY), + FAIRY_DEF_STRING(, R_MIPS_JUMP_SLOT), + FAIRY_DEF_STRING(, R_MIPS_NUM), +}; + +/** + * Find all the necessary relocations to retain (those defined in any input file), and print them in the appropriate + * format. + */ +void Fado_Relocs(FILE* outputFile, int inputFilesCount, FILE** inputFiles, const char* ovlName) { + /* General information structs */ + FairyFileInfo* fileInfos = malloc(inputFilesCount * sizeof(FairyFileInfo)); + + /* Symbol tables for each file */ + FairySym** symtabs = malloc(inputFilesCount * sizeof(FairySym*)); + + /* Lists of names of symbols defined in files of the overlay */ + vc_vector** stringVectors = malloc(inputFilesCount * sizeof(vc_vector*)); + + /* The relocs in the format we will print */ + vc_vector* relocList[FAIRY_SECTION_OTHER]; /* Maximum number of reloc sections */ + + /* Offset of current file's current section into the overlay's whole section */ + uint32_t sectionOffset[FAIRY_SECTION_OTHER] = { 0 }; + + /* Total number of relocs */ + uint32_t relocCount = 0; + + /* iterators */ + int currentFile; + FairySection section; + size_t relocIndex; + + for (currentFile = 0; currentFile < inputFilesCount; currentFile++) { + FAIRY_INFO_PRINTF("Begin initialising file %d info.\n", currentFile); + Fairy_InitFile(&fileInfos[currentFile], inputFiles[currentFile]); + FAIRY_INFO_PRINTF("Initialising file %d info complete.\n", currentFile); + + symtabs[currentFile] = fileInfos[currentFile].symtabInfo.sectionData; + } + + Fado_ConstructStringVectors(stringVectors, fileInfos, inputFilesCount); + FAIRY_INFO_PRINTF("%s", "symtabs set\n"); + + /* Construct relocList of all relevant relocs */ + for (section = FAIRY_SECTION_TEXT; section < FAIRY_SECTION_OTHER; section++) { + relocList[section] = vc_vector_create(0x100, sizeof(FadoRelocInfo), NULL); + + for (currentFile = 0; currentFile < inputFilesCount; currentFile++) { + FairyRela* relSection = fileInfos[currentFile].relocTablesInfo[section].sectionData; + + if (relSection != NULL) { + for (relocIndex = 0; relocIndex < fileInfos[currentFile].relocTablesInfo[section].sectionEntryCount; + relocIndex++) { + FadoRelocInfo currentReloc = Fado_MakeReloc(currentFile, section, &relSection[relocIndex]); + + if ((symtabs[currentFile][currentReloc.symbolIndex].st_shndx != STN_UNDEF) || + Fado_FindSymbolNameInOtherFiles( + &fileInfos[currentFile].strtab[symtabs[currentFile][currentReloc.symbolIndex].st_name], + currentFile, stringVectors, inputFilesCount)) { + + currentReloc.relocWord += sectionOffset[section]; + FAIRY_DEBUG_PRINTF("current section offset: %d\n", sectionOffset[section]); + vc_vector_push_back(relocList[section], ¤tReloc); + relocCount++; + } + } + } else { + FAIRY_INFO_PRINTF("%s", "Ignoring empty reloc section\n"); + } + + sectionOffset[section] += fileInfos[currentFile].progBitsSizes[section]; + FAIRY_INFO_PRINTF("section offset: %d\n", sectionOffset[section]); + } + } + + { + /* Write header */ + fprintf(outputFile, ".section .ovl\n"); + fprintf(outputFile, "# %sOverlayInfo\n", ovlName); + fprintf(outputFile, ".word _%sSegmentTextSize\n", ovlName); + fprintf(outputFile, ".word _%sSegmentDataSize\n", ovlName); + fprintf(outputFile, ".word _%sSegmentRoDataSize\n", ovlName); + fprintf(outputFile, ".word _%sSegmentBssSize\n", ovlName); + + fprintf(outputFile, "\n.word %d # relocCount\n", relocCount); + + /* Write reloc table */ + for (section = FAIRY_SECTION_TEXT; section < FAIRY_SECTION_OTHER; section++) { + if (vc_vector_count(relocList[section]) == 0) { + FAIRY_INFO_PRINTF("%s", "Ignoring empty reloc section\n"); + continue; + } + + fprintf(outputFile, "\n# %s RELOCS\n", Fairy_StringFromDefine(relSectionNames, section)); + + { + FadoRelocInfo* currentReloc; + VC_FOREACH(currentReloc, relocList[section]) { + fprintf(outputFile, ".word 0x%X # %-11s 0x%06X %s\n", currentReloc->relocWord, + Fairy_StringFromDefine(relTypeNames, (currentReloc->relocWord >> 0x18) & 0x3F), + currentReloc->relocWord & 0xFFFFFF, + Fairy_GetSymbolName(symtabs[currentReloc->file], fileInfos[currentReloc->file].strtab, + currentReloc->symbolIndex)); + } + } + } + + /* print pads and section size */ + for (relocCount += 5; ((relocCount + 1) & 3) != 0; relocCount++) { + fprintf(outputFile, ".word 0\n"); + } + fprintf(outputFile, "\n.word 0x%08X # %sOverlayInfoOffset\n", 4 * (relocCount + 1), ovlName); + } + + for (currentFile = 0; currentFile < inputFilesCount; currentFile++) { + Fairy_DestroyFile(&fileInfos[currentFile]); + FAIRY_INFO_PRINTF("Freed file %d\n", currentFile); + } + + for (section = FAIRY_SECTION_TEXT; section < FAIRY_SECTION_OTHER; section++) { + if (relocList[section] != NULL) { + vc_vector_release(relocList[section]); + } + FAIRY_INFO_PRINTF("Freed relocList[%d]\n", section); + } + + Fado_DestroyStringVectors(stringVectors, inputFilesCount); + FAIRY_INFO_PRINTF("%s", "Freed string vectors\n"); + free(symtabs); + FAIRY_INFO_PRINTF("%s", "Freed symtabs\n"); + free(fileInfos); +} diff --git a/tools/fado/src/help.c b/tools/fado/src/help.c new file mode 100644 index 00000000..1f058073 --- /dev/null +++ b/tools/fado/src/help.c @@ -0,0 +1,162 @@ +/** + * Getopt-compatible printing of formatted help. + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "help.h" + +#include +#include +#include +#include +#include +#include + +#include "macros.h" + +/* Values of the variables used by Help_PrintHelp. Defaults are taken from common terminal programs like grep */ +size_t helpTextWidth = 80; +size_t helpDtIndent = 2; +size_t helpDdIndent = 25; + +/** + * Prints a paragraph, word wrapped to helpTextWidth, with a hanging indent. initialColumn is used to determine how wide + * the first line should be, while indentFirstLine should be true if there is no previous text on the line (an ordinary + * paragraph), and false if there is (e.g. as a description list description) + */ +void Help_PrintFlowAndIndent(const char* string, size_t initialColumn, size_t textWidth, size_t hangingIndent, + bool indentFirstLine) { + size_t column = initialColumn; + size_t index = 0; + size_t inLength = strlen(string); + size_t lookAhead; + bool shouldBreak; + + assert(initialColumn < textWidth); + assert(hangingIndent < textWidth); + + if (indentFirstLine) { + printf("%*s", (int)initialColumn, ""); + } + + for (; index <= inLength; index++) { + shouldBreak = 0; + + if (column == textWidth) { + printf("%c\n%*s", string[index], (int)hangingIndent, ""); + column = hangingIndent; + continue; + } + + column++; + + switch (string[index]) { + case '\0': + return; + + case ' ': + if (column == hangingIndent) { + continue; + } + + for (lookAhead = 0; lookAhead <= textWidth - column; lookAhead++) { + // printf("%c\n", src[index + lookAhead]); + if (string[index + lookAhead + 1] == ' ' || string[index + lookAhead + 1] == '\0') { + putchar(' '); + shouldBreak = 1; + break; + } + } + if (shouldBreak) { /* Damn shared keywords. */ + break; + } + case '\n': + printf("\n%*s", (int)hangingIndent, ""); + column = hangingIndent; + break; + + default: + putchar(string[index]); + break; + } + } +} + +/** + * Prints help in the form + * ``` + * prologue (word wrapped) + * + * Positional arguments + * arg1 Description (word + * wrapped) + * arg2 Description (word + * wrapped) + * + * Options + * -a --long-name=ARG Description (word + * wrapped) + * + * epilogue (word wrapped) + * ``` + * where the positional arguments are described using the posArgInfo array, and options are fed using the OptInfo array, + * which should both be null-terminated. posArgCount/optCount is the actual number of positional arguments/options: it + * is used to guarantee no garbage is printed even if the user has not null-terminated the array. (optCount is required + * for constructing the getopt option array anyway.) + */ +void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo* posArgInfo, size_t optCount, + const OptInfo* optInfo, const char* epilogue) { + size_t i; + size_t dtLength; + int padding; + + Help_PrintFlowAndIndent(prologue, 0, helpTextWidth, 0, false); + + if (posArgCount != 0) { + printf("\nPositional Argument\n"); + for (i = 0; i < posArgCount; i++) { + if (posArgInfo[i].helpArg == 0) { + break; + } + + dtLength = helpDtIndent + strlen(posArgInfo[i].helpArg); + + padding = helpDdIndent - dtLength - 2; + printf("%*s%s%*s ", (int)helpDtIndent, "", posArgInfo[i].helpArg, CLAMP_MIN(padding, 0), ""); + + Help_PrintFlowAndIndent(posArgInfo[i].helpMsg, CLAMP_MIN(dtLength + 2, helpDdIndent), helpTextWidth, + helpDdIndent, false); + printf("\n"); + } + } + + if (optCount != 0) { + printf("\nOptions\n"); + + for (i = 0; i < optCount; i++) { + if (optInfo[i].longOpt.val == 0) { + break; + } + + dtLength = helpDtIndent + 6 + strlen(optInfo[i].longOpt.name); + + if (optInfo[i].helpArg == NULL) { + padding = helpDdIndent - dtLength - 2; + printf("%*s-%c, --%s%*s ", (int)helpDtIndent, "", optInfo[i].longOpt.val, optInfo[i].longOpt.name, + CLAMP_MIN(padding, 0), ""); + } else { + dtLength += 1 + strlen(optInfo[i].helpArg); + padding = helpDdIndent - dtLength - 2; + printf("%*s-%c, --%s=%s%*s ", (int)helpDtIndent, "", optInfo[i].longOpt.val, optInfo[i].longOpt.name, + optInfo[i].helpArg, CLAMP_MIN(padding, 0), ""); + } + Help_PrintFlowAndIndent(optInfo[i].helpMsg, CLAMP_MIN(dtLength + 2, helpDdIndent), helpTextWidth, + helpDdIndent, false); + printf("\n"); + } + } + + printf("\n"); + Help_PrintFlowAndIndent(epilogue, 0, helpTextWidth, 0, false); + printf("\n"); +} diff --git a/tools/fado/src/main.c b/tools/fado/src/main.c new file mode 100644 index 00000000..e6b7926d --- /dev/null +++ b/tools/fado/src/main.c @@ -0,0 +1,247 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include +#include +#include +#include +#include + +#include "macros.h" +#include "fairy/fairy.h" +#include "fado.h" +#include "help.h" +#include "mido.h" +#include "vc_vector/vc_vector.h" + +#include "version.inc" + +void PrintVersion(void) { + printf("Fado (Fairy-Assisted relocations for Decompiled Overlays), version %s\n", versionNumber); + printf("Copyright (C) 2021 Elliptic Ellipsis\n"); + printf("%s\n", credits); + printf("Repository available at %s.\n", repo); +} + +#if defined _WIN32 || defined __CYGWIN__ +#define PATH_SEPARATOR '\\' +#else +#define PATH_SEPARATOR '/' +#endif + +/** + * (Bad) filename-parsing idea to get the overlay name from the filename. Output must be freed separately. + */ +char* GetOverlayNameFromFilename(const char* src) { + char* ret; + const char* ptr; + const char* start = src; + const char* end = src; + + for (ptr = src; *ptr != '\0'; ptr++) { + if (*ptr == PATH_SEPARATOR) { + start = end + 1; + end = ptr; + } + } + + if (end == src) { + return NULL; + } + + ret = malloc((end - start + 1) * sizeof(char)); + memcpy(ret, start, end - start); + ret[end - start] = '\0'; + + return ret; +} + +#define OPTSTR "M:n:o:v:ahV" +#define USAGE_STRING "Usage: %s [-hV] [-n name] [-o output_file] [-v level] input_files ...\n" + +#define HELP_PROLOGUE \ + "Fado (Fairy-Assisted relocations for Decompiled Overlays\n" \ + "Extract relocations from object files and convert them into the format required by Zelda 64 overlays.\n" +#define HELP_EPILOGUE repo + +// clang-format off +static const PosArgInfo posArgInfo[] = { + { "INPUT_FILE", "Every positional argument is an input file, and there should be at least one input file. All inputs are relocatable .o (object) ELF files" }, + { NULL, NULL } +}; + +static const OptInfo optInfo[] = { + { { "make-dependency", required_argument, NULL, 'M' }, "FILE", "Write the output file's Makefile dependencies to FILE" }, + { { "name", required_argument, NULL, 'n' }, "NAME", "Use NAME as the overlay name. Will use the deepest folder name in the input file's path if not specified" }, + { { "output-file", required_argument, NULL, 'o' }, "FILE", "Output to FILE. Will use stdout if none is specified" }, + { { "verbosity", required_argument, NULL, 'v' }, "N", "Verbosity level, one of 0 (None, default), 1 (Info), 2 (Debug)" }, + + { { "alignment", no_argument, NULL, 'a' }, NULL, "Experimental. Use the alignment declared by each section in the elf file instead of padding to 0x10 bytes. NOTE: It has not been properly tested because the tools we currently have are not compatible non 0x10 alignment" }, + + { { "help", no_argument, NULL, 'h' }, NULL, "Display this message and exit" }, + { { "version", no_argument, NULL, 'V' }, NULL, "Display version information" }, + + { { NULL, 0, NULL, '\0' }, NULL, NULL }, +}; +// clang-format on + +static size_t posArgCount = ARRAY_COUNT(posArgInfo); +static size_t optCount = ARRAY_COUNT(optInfo); +static struct option longOptions[ARRAY_COUNT(optInfo)]; + +void ConstructLongOpts(void) { + size_t i; + + for (i = 0; i < optCount; i++) { + longOptions[i] = optInfo[i].longOpt; + } +} + +int main(int argc, char** argv) { + int opt; + int inputFilesCount; + FILE** inputFiles; + FILE* outputFile = stdout; + char* outputFileName; + char* dependencyFileName = NULL; + char* ovlName = NULL; + + ConstructLongOpts(); + + if (argc < 2) { + printf(USAGE_STRING, argv[0]); + fprintf(stderr, "No input file specified\n"); + return EXIT_FAILURE; + } + + while (true) { + int optionIndex = 0; + + if ((opt = getopt_long(argc, argv, OPTSTR, longOptions, &optionIndex)) == -1) { + break; + } + + switch (opt) { + case 'M': + dependencyFileName = optarg; + break; + + case 'n': + ovlName = optarg; + break; + + case 'o': + outputFileName = optarg; + outputFile = fopen(optarg, "wb"); + if (outputFile == NULL) { + fprintf(stderr, "error: unable to open output file '%s' for writing\n", optarg); + return EXIT_FAILURE; + } + break; + + case 'v': + if (sscanf(optarg, "%u", &gVerbosity) == 0) { + fprintf(stderr, "warning: verbosity argument '%s' should be a nonnegative decimal integer\n", + optarg); + } + break; + + case 'a': +#ifndef EXPERIMENTAL + goto not_experimental_err; +#endif + gUseElfAlignment = true; + break; + + case 'h': + printf(USAGE_STRING, argv[0]); + Help_PrintHelp(HELP_PROLOGUE, posArgCount, posArgInfo, optCount, optInfo, HELP_EPILOGUE); + return EXIT_FAILURE; + + case 'V': + PrintVersion(); + return EXIT_FAILURE; + + default: + fprintf(stderr, "?? getopt returned character code 0x%X ??\n", opt); + break; + } + } + + FAIRY_INFO_PRINTF("%s", "Options processed\n"); + + { + int i; + + inputFilesCount = argc - optind; + if (inputFilesCount == 0) { + fprintf(stderr, "No input files specified. Exiting.\n"); + return EXIT_FAILURE; + } + + inputFiles = malloc(inputFilesCount * sizeof(FILE*)); + for (i = 0; i < inputFilesCount; i++) { + FAIRY_INFO_PRINTF("Using input file %s\n", argv[optind + i]); + inputFiles[i] = fopen(argv[optind + i], "rb"); + if (inputFiles[i] == NULL) { + fprintf(stderr, "error: unable to open input file '%s' for reading\n", argv[optind + i]); + return EXIT_FAILURE; + } + } + + FAIRY_INFO_PRINTF("Found %d input file%s\n", inputFilesCount, (inputFilesCount == 1 ? "" : "s")); + + if (ovlName == NULL) { // If a name has not been set using an arg + ovlName = GetOverlayNameFromFilename(argv[optind]); + Fado_Relocs(outputFile, inputFilesCount, inputFiles, ovlName); + free(ovlName); + } else { + Fado_Relocs(outputFile, inputFilesCount, inputFiles, ovlName); + } + + for (i = 0; i < inputFilesCount; i++) { + fclose(inputFiles[i]); + } + free(inputFiles); + if (outputFile != stdout) { + fclose(outputFile); + } + } + + if (dependencyFileName != NULL) { + int fileNameLength = strlen(outputFileName); + char* objectFile = malloc((strlen(outputFileName) + 1) * sizeof(char)); + vc_vector* inputFilesVector = vc_vector_create(inputFilesCount, sizeof(char*), NULL); + char* extensionStart; + FILE* dependencyFile = fopen(dependencyFileName, "w"); + + if (dependencyFile == NULL) { + fprintf(stderr, "error: unable to open dependency file '%s' for writing\n", dependencyFileName); + return EXIT_FAILURE; + } + + strcpy(objectFile, outputFileName); + extensionStart = strrchr(objectFile, '.'); + if (extensionStart == objectFile + fileNameLength) { + fprintf(stderr, "error: file name should not end in a '.'\n"); + return EXIT_FAILURE; + } + strcpy(extensionStart, ".o"); + vc_vector_append(inputFilesVector, &argv[optind], inputFilesCount); + + Mido_WriteDependencyFile(dependencyFile, objectFile, inputFilesVector); + + free(objectFile); + vc_vector_release(inputFilesVector); + fclose(dependencyFile); + } + + return EXIT_SUCCESS; + + goto not_experimental_err; // silences a warning +not_experimental_err: + fprintf( + stderr, + "Experimental option '-%c' passed in a non-EXPERIMENTAL build. Rebuild with 'make EXPERIMENTAL=1' to enable.\n", + opt); + return EXIT_FAILURE; +} diff --git a/tools/fado/src/mido.c b/tools/fado/src/mido.c new file mode 100644 index 00000000..bc5f3ed8 --- /dev/null +++ b/tools/fado/src/mido.c @@ -0,0 +1,20 @@ +#include "mido.h" + +#include +#include "macros.h" +#include "vc_vector/vc_vector.h" + +int Mido_WriteDependencyFile(FILE* dependencyFile, const char* relocFile, vc_vector* inputFilesVector) { + char** inputFile; + + fprintf(dependencyFile, "%s:", relocFile); + + VC_FOREACH(inputFile, inputFilesVector) { + fprintf(dependencyFile, " %s", *inputFile); + } + fputs("\n\n", dependencyFile); + VC_FOREACH(inputFile, inputFilesVector) { + fprintf(dependencyFile, "%s:\n\n", *inputFile); + } + return 0; +} diff --git a/tools/fado/src/version.inc b/tools/fado/src/version.inc new file mode 100644 index 00000000..9bc9fbf3 --- /dev/null +++ b/tools/fado/src/version.inc @@ -0,0 +1,5 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +const char versionNumber[] = "1.3.1"; +const char credits[] = "Written by Elliptic Ellipsis\nwith additions from AngheloAlf and Tharo"; +const char repo[] = "https://github.com/EllipticEllipsis/fado/"; diff --git a/tools/fado/z64_relocation_section_format.md b/tools/fado/z64_relocation_section_format.md new file mode 100644 index 00000000..c537ff70 --- /dev/null +++ b/tools/fado/z64_relocation_section_format.md @@ -0,0 +1,114 @@ +# Zelda 64 overlay relocation section format + +Both Zelda 64 titles use the same custom dynamic overlay relocation format, which is + + +All elements are 4 bytes in width. + +| Offset | Description | Notes | +| ------- | ------------------------------------------- | ------------------------------------------------------------- | +| 0x00 | Size of overlay .text section | | +| 0x04 | Size of overlay .data section | | +| 0x08 | Size of overlay .rodata section | | +| 0x0C | Size of overlay .bss section | | +| 0x10 | Number of relocation entries | | +| 0x14- | Relocation entries | Must be sorted in increasing order by section, then offset | +| ... | | | +| | (zero padding of section to 0x10 alignment) | | +| End - 4 | Size of overlay .ovl section | Also the offset from the end of the rest of the section sizes | + + +## Relocation entries + +The only element that is not a single number are the relocation entries, which are bitpacked as follows: + +| 0x1F..0x1E | 0x1D..0x18 | 0x17..0x0 | +| ---------- | ---------- | ----------------------------- | +| ss | tttttt | oooo oooo oooo oooo oooo oooo | +| Section | Type | Offset | + + +### Section + +2 bits. Section where the instruction or data to be relocated is. + +| Value | Section | +| ----- | ------- | +| 1 | .text | +| 2 | .data | +| 3 | .rodata | + + +### Type + +6 bits. Four types of standard MIPS relocation are supported. They use the same values as the standard elf formats: + +| Value | Type | Description | +| ----- | ------------- | --------------------------------------------------------------------------------- | +| 2 | `R_MIPS_32` | A full word address (such as a pointer in data or an address in a jumptable) | +| 4 | `R_MIPS_26` | 26-bit direct relocation, for a J-type instruction | +| 5 | `R_MIPS_HI16` | High 16-bit, generally the top half of an address in an `li`/`lui` | +| 6 | `R_MIPS_LO16` | Low 16-bit, the bottom half of an address, such as in an `addiu`,`ori`,`lh`, etc. | + + +### Offset + +0x18 bits. Offset in bytes from the start of the section where the relocation occurs. + + +### Example + +``` +0x82000A30 = 0b1000 0010 0000 0000 0000 1010 0011 0000 +``` + +This splits as + +``` +0b10, 0b000010, 0b0000 0000 0000 1010 0011 0000 = 0x2, 0x2, 0xA30 +``` + +i.e. a full-word (`R_MIPS_32`) relocation at `.data + 0xA30`. + + +## Compiler compatibility + +### HI/LO + +The MIPS ELF format standard specifies that each LO be preceded by a unique HI associated to it (but multiple LOs may associate to the same HI), and the overlay relocation function acts based on this assumption. + +IDO complies with this consistently, but GCC in its wisdom decided that it was appropriate to violate this by default, and allow multiple HIs to associate to the same LO. GCC also likes to reorder relocations in the `.rel.*` sections. + +To prevent these you must pass *both* of the following compiler flags: + +``` +-mno-explicit-relocs -mno-split-addresses +``` + +(GNU do not document this behaviour themselves, although apparently it has been present for many years. It is also not even consistent between versions.) + +### rodata + +It should be clear from the description above that this system expects a single rodata section. Again, IDO will only ever produce one rodata section, but GCC will produce several, albeit only one containing relocatable rodata: the others are for "mergeable" strings and floats/doubles. The cleanest way to deal with this is to pass + +``` +-fno-merge-constants +``` + +which will force GCC to generate a single combined rodata section. If, however, you really think you will benefit from merging constants, to obtain relocations correctly offset from the start of the entire rodata section(s), the actual `.rodata` section must be explicitly linked first. + +For multi-file overlays, the situation is even more complicated, and Fado gets around this by adding up the sizes of all the rodata sections so that we may simply place one files' in one chunk: this means that each individual `.rodata` section should be linked before the others, i.e. + +``` +.text(1) +.text(2) +.data(1) +.data(2) +.rodata(1) +.rodata.cst4(1) +... +.rodata(2) +.rodata.cst4(2) +``` + +or similar. diff --git a/tools/first_diff.py b/tools/first_diff.py new file mode 100755 index 00000000..c0702c89 --- /dev/null +++ b/tools/first_diff.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import mapfile_parser +from pathlib import Path + + +def firstDiffMain(): + parser = argparse.ArgumentParser(description="Find the first difference(s) between the built ROM and the base ROM.") + + parser.add_argument("-c", "--count", type=int, default=5, help="find up to this many instruction difference(s)") + parser.add_argument("-v", "--version", help="Which version should be processed", default="jp") + + args = parser.parse_args() + + buildFolder = Path("build") + + BUILTROM = buildFolder / f"animalforest_uncompressed.{args.version}.z64" + BUILTMAP = buildFolder / f"animalforest.{args.version}.map" + + EXPECTEDROM = "expected" / BUILTROM + EXPECTEDMAP = "expected" / BUILTMAP + + exit(mapfile_parser.frontends.first_diff.doFirstDiff(BUILTMAP, EXPECTEDMAP, BUILTROM, EXPECTEDROM, args.count, mismatchSize=True)) + +if __name__ == "__main__": + firstDiffMain() diff --git a/tools/format.py b/tools/format.py new file mode 100755 index 00000000..4b6a24d8 --- /dev/null +++ b/tools/format.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 + +import argparse +import glob +import multiprocessing +import os +import re +import shutil +import subprocess +import sys +import tempfile +from functools import partial +from typing import List + + +# clang-format, clang-tidy and clang-apply-replacements default version +# Version 11 is used when available for more consistency between contributors +CLANG_VER = 11 + +# Clang-Format options (see .clang-format for rules applied) +FORMAT_OPTS = "-i -style=file" + +# Clang-Tidy options (see .clang-tidy for checks enabled) +TIDY_OPTS = "-p ." +TIDY_FIX_OPTS = "--fix --fix-errors" + +# Clang-Apply-Replacements options (used for multiprocessing) +APPLY_OPTS = "" + +# Compiler options used with Clang-Tidy +# Normal warnings are disabled with -Wno-everything to focus only on tidying +INCLUDES = "-Iinclude -Isrc -Ibuild -I. -Ilib/ultralib/include -Ilib/ultralib/include/PR -Ibin/jp -Ibin/cn" +DEFINES = "-D_LANGUAGE_C -DNON_MATCHING -D_MIPS_SZLONG=32" +COMPILER_OPTS = f"-fno-builtin -std=gnu90 -m32 -Wno-everything {INCLUDES} {DEFINES}" + + +VERBOSE = False + +def get_clang_executable(allowed_executables: List[str]): + for executable in allowed_executables: + try: + subprocess.check_call([executable, "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + return executable + except FileNotFoundError or subprocess.CalledProcessError: + pass + return None + + +def get_tidy_version(tidy_executable: str): + tidy_version_run = subprocess.run([tidy_executable, "--version"], stdout=subprocess.PIPE, universal_newlines=True) + match = re.search(r"LLVM version ([0-9]+)", tidy_version_run.stdout) + return int(match.group(1)) + + +CLANG_FORMAT = get_clang_executable([f"clang-format-{CLANG_VER}"]) +if CLANG_FORMAT is None: + sys.exit(f"Error: clang-format-{CLANG_VER} not found") + +CLANG_TIDY = get_clang_executable([f"clang-tidy-{CLANG_VER}", "clang-tidy"]) +if CLANG_TIDY is None: + sys.exit(f"Error: neither clang-tidy-{CLANG_VER} nor clang-tidy found") + +CLANG_APPLY_REPLACEMENTS = get_clang_executable([f"clang-apply-replacements-{CLANG_VER}", "clang-apply-replacements"]) + +# Try to detect the clang-tidy version and add --fix-notes for version 13+ +# This is used to ensure all fixes are applied properly in recent versions +if get_tidy_version(CLANG_TIDY) >= 13: + TIDY_FIX_OPTS += " --fix-notes" + + +def list_chunks(list: List, chunk_length: int): + for i in range(0, len(list), chunk_length): + yield list[i : i + chunk_length] + + +def run_clang_format(files: List[str]): + exec_str = f"{CLANG_FORMAT} {FORMAT_OPTS} {' '.join(files)}" + subprocess.run(exec_str, shell=True) + + +def run_clang_tidy(files: List[str]): + exec_str = f"{CLANG_TIDY} {TIDY_OPTS} {TIDY_FIX_OPTS} {' '.join(files)} -- {COMPILER_OPTS}" + if VERBOSE: + subprocess.run(exec_str, shell=True) + else: + subprocess.run(exec_str, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def run_clang_tidy_with_export(tmp_dir: str, files: List[str]): + (handle, tmp_file) = tempfile.mkstemp(suffix=".yaml", dir=tmp_dir) + os.close(handle) + + exec_str = f"{CLANG_TIDY} {TIDY_OPTS} --export-fixes={tmp_file} {' '.join(files)} -- {COMPILER_OPTS}" + if VERBOSE: + subprocess.run(exec_str, shell=True) + else: + subprocess.run(exec_str, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def run_clang_apply_replacements(tmp_dir: str): + exec_str = f"{CLANG_APPLY_REPLACEMENTS} {APPLY_OPTS} {tmp_dir}" + subprocess.run(exec_str, shell=True) + + +def add_final_new_line(file: str): + # https://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/index.html + # "gets the last character of the file pipes it into read, which will exit with a nonzero exit + # code if it encounters EOF before newline (so, if the last character of the file isn't a newline). + # If read exits nonzero, then append a newline onto the file using echo (if read exits 0, + # that satisfies the ||, so the echo command isn't run)." (https://stackoverflow.com/a/34865616) + exec_str = f"tail -c1 {file} | read -r _ || echo >> {file}" + subprocess.run(exec_str, shell=True) + + +def format_files(src_files: List[str], extra_files: List[str], nb_jobs: int): + if nb_jobs != 1: + print(f"Formatting files with {nb_jobs} jobs") + else: + print(f"Formatting files with a single job (consider using -j to make this faster)") + + # Format files in chunks to improve performance while still utilizing jobs + file_chunks = list(list_chunks(src_files, (len(src_files) // nb_jobs) + 1)) + + print("Running clang-format...") + # clang-format only applies changes in the given files, so it's safe to run in parallel + with multiprocessing.get_context("fork").Pool(nb_jobs) as pool: + pool.map(run_clang_format, file_chunks) + + print("Running clang-tidy...") + if nb_jobs > 1: + # clang-tidy may apply changes in #included files, so when running it in parallel we use --export-fixes + # then we call clang-apply-replacements to apply all suggested fixes at the end + tmp_dir = tempfile.mkdtemp() + + try: + with multiprocessing.get_context("fork").Pool(nb_jobs) as pool: + pool.map(partial(run_clang_tidy_with_export, tmp_dir), file_chunks) + + run_clang_apply_replacements(tmp_dir) + finally: + shutil.rmtree(tmp_dir) + else: + run_clang_tidy(src_files) + + print("Adding missing final new lines...") + # Adding final new lines is safe to do in parallel and can be applied to all types of files + with multiprocessing.get_context("fork").Pool(nb_jobs) as pool: + pool.map(add_final_new_line, src_files + extra_files) + + print("Done formatting files.") + + +def main(): + parser = argparse.ArgumentParser(description="Format files in the codebase to enforce most style rules") + parser.add_argument("files", metavar="file", nargs="*") + parser.add_argument( + "-j", + dest="jobs", + type=int, + nargs="?", + default=1, + help="number of jobs to run (default: 1 without -j, number of cpus with -j)", + ) + parser.add_argument("-v", "--verbose", action="store_true") + args = parser.parse_args() + + global VERBOSE + VERBOSE = args.verbose + + nb_jobs = args.jobs or multiprocessing.cpu_count() + if nb_jobs > 1: + if CLANG_APPLY_REPLACEMENTS is None: + sys.exit( + f"Error: neither clang-apply-replacements-{CLANG_VER} nor clang-apply-replacements found (required to use -j)" + ) + + if args.files: + files = args.files + extra_files = [] + else: + files = glob.glob("src/**/*.c", recursive=True) + extra_files = glob.glob("assets/**/*.xml", recursive=True) + + format_files(files, extra_files, nb_jobs) + + +if __name__ == "__main__": + main() diff --git a/tools/m2ctx.py b/tools/m2ctx.py new file mode 100755 index 00000000..60cae1a0 --- /dev/null +++ b/tools/m2ctx.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +import argparse +import os +import sys +import subprocess +import tempfile + +script_dir = os.path.dirname(os.path.realpath(__file__)) +root_dir = os.path.abspath(os.path.join(script_dir, "..")) + +# Project-specific +CPP_FLAGS = [ + "-I.", + "-Iinclude", + "-Ibin", + "-Ilib/ultralib/include", + "-Ilib/ultralib/include/PR", + + "-D_LANGUAGE_C", + "-DF3DEX_GBI_2", + "-D__USE_ISOC99", + "-DNDEBUG", + "-D_FINALROM", + "-D_MIPS_SZLONG=32", + "-D__USE_ISOC99", + + "-DM2CTX", + "-DCC_CHECK=1" + "-DNON_MATCHING", + + "-ffreestanding", + "-std=gnu89", +] + +def import_c_file(in_file, version: str) -> str: + in_file = os.path.relpath(in_file, root_dir) + + cpp_command = ["gcc", "-E", "-P", "-undef", "-dM", *CPP_FLAGS, in_file] + cpp_command2 = ["gcc", "-E", "-P", "-undef", *CPP_FLAGS, in_file] + + with tempfile.NamedTemporaryFile(suffix=".c") as tmp: + stock_macros = subprocess.check_output(["gcc", "-E", "-P", "-undef", "-dM", tmp.name], cwd=root_dir, encoding="utf-8") + + out_text = "" + try: + out_text += subprocess.check_output(cpp_command, cwd=root_dir, encoding="utf-8") + out_text += subprocess.check_output(cpp_command2, cwd=root_dir, encoding="utf-8") + except subprocess.CalledProcessError: + print( + "Failed to preprocess input file, when running command:\n" + + " ".join(cpp_command), + file=sys.stderr, + ) + sys.exit(1) + + if not out_text: + print("Output is empty - aborting") + sys.exit(1) + + for line in stock_macros.strip().splitlines(): + out_text = out_text.replace(line + "\n", "") + return out_text + +def main(): + parser = argparse.ArgumentParser( + description="""Create a context file which can be used for m2c""" + ) + parser.add_argument( + "c_file", + help="""File from which to create context""", + ) + parser.add_argument("-v", "--version", help="Which version should be processed", default="us", choices=["us", "cn"]) + args = parser.parse_args() + + output = import_c_file(args.c_file, args.version) + + with open(os.path.join(root_dir, "ctx.c"), "w", encoding="UTF-8") as f: + f.write(output) + + +if __name__ == "__main__": + main() diff --git a/tools/permuter_settings.toml b/tools/permuter_settings.toml new file mode 100644 index 00000000..b08f38f4 --- /dev/null +++ b/tools/permuter_settings.toml @@ -0,0 +1,9 @@ +compiler_type = "ido" + +[preserve_macros] +NULL = "int" +"g[DS]P.*" = "void" +"gs[DS]P.*" = "void" +"gDma.*" = "void" +"G_IM_SIZ_.*" = "int" +"G_[AC]C.*" = "int" diff --git a/tools/pj64_syms.py b/tools/pj64_syms.py new file mode 100755 index 00000000..7ff957ce --- /dev/null +++ b/tools/pj64_syms.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import mapfile_parser +from pathlib import Path + + +def mapToPj64symsMain(): + parser = argparse.ArgumentParser() + parser.add_argument("-v", "--version", help="version to process", default="jp") + parser.add_argument("-o", "--output", default="DOUBUTSUNOMORI.sym", type=Path) + + args = parser.parse_args() + + version: str = args.version + output: Path = args.output + mapPath = Path("build") / f"animalforest.{version}.map" + + exit(mapfile_parser.frontends.pj64_syms.doPj64Syms(mapPath, output)) + +if __name__ == "__main__": + mapToPj64symsMain() diff --git a/tools/splat/.github/workflows/mypy.yml b/tools/splat/.github/workflows/mypy.yml new file mode 100644 index 00000000..d5bb1fa0 --- /dev/null +++ b/tools/splat/.github/workflows/mypy.yml @@ -0,0 +1,26 @@ +name: mypy + +on: + push: + pull_request: + +jobs: + checks: + runs-on: ubuntu-latest + name: mypy + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Install Dependencies + run: | + pip install mypy + pip install black + pip install -r requirements.txt + pip install types-PyYAML + - name: mypy + run: mypy --show-column-numbers --hide-error-context . + - name: black + run: black --check . diff --git a/tools/splat/.gitignore b/tools/splat/.gitignore new file mode 100644 index 00000000..38da5f71 --- /dev/null +++ b/tools/splat/.gitignore @@ -0,0 +1,10 @@ +.idea/ +venv/ +.vscode/ +__pycache__/ +.mypy_cache/ +util/n64/Yay0decompress +*.ld +*.n64 +*.yaml +*.z64 diff --git a/tools/splat/.gitrepo b/tools/splat/.gitrepo new file mode 100644 index 00000000..5899cd25 --- /dev/null +++ b/tools/splat/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@github.com:ethteck/splat.git + branch = master + commit = 4fec014c10aa1fc90d200fe6722000425bf7d43f + parent = 6a5e64cc4c26398cc607bb02cdc12a056ddf42d1 + method = merge + cmdver = 0.4.3 diff --git a/tools/splat/CHANGELOG.md b/tools/splat/CHANGELOG.md new file mode 100644 index 00000000..0fad6fbb --- /dev/null +++ b/tools/splat/CHANGELOG.md @@ -0,0 +1,361 @@ +# splat Release Notes + +### 0.13.5 + +* An error will be produced if a symbol is declared with an unknown type in the symbol_addrs file. + * The current list of known symbols is `'func', 'label', 'jtbl', 'jtbl_label', 's8', 'u8', 's16', 'u16', 's32', 'u32', 's64', 'u64', 'f32', 'f64', 'Vec3f', 'asciz', 'char*', 'char'`. + * Custom types are allowed if they start with a capital letter. + +### 0.13.4 + +* Renamed `follows_vram_symbol` segment option to `vram_of_symbol` to more accurately reflect what it's used for - to set the segment's vram based on a symbol. +* Refactored the `appears_after_overlays_addr` feature so that expressions are written at the latest possible moment in the linker script. This fixes errors and warnings regarding forward references to later symbols. + +### 0.13.3 + +* Added a new symbol_addrs attribute `appears_after_overlays_addr:0x1234` which will modify the linker script such that the symbol's address is equal to the value of the end of the longest overlay starting with address 0x1234. It achieve this by writing a series of sym = MAX(sym, seg_vram_END) statements into the linker script. For some games, it's feasible to manually create such statements, but for games with hundreds of overlays at the same address, this is very tedious and prone to error. The new attribute allows you to have peace of mind that the symbol will end up after all of these overlays. + +### 0.13.2 + +* Actually implemented `ld_use_follows`. Oopz + +### 0.13.1 + +* Added `ld_wildcard_sections` option (disabled by default), which adds a wildcard to the linker script for section linking. This can be helpful for modern GCC, which creates additional rodata sections such as ".rodata.xyz". +* Added `ld_use_follows` option (enabled by default), which, if disabled, makes splat ignore follows_vram and follows_symbols. This helps for fixing matching builds while being able to add infrastructure to the yaml for non-matching builds by just re-enabling the option. + +### 0.13.0 + +* Automatically generate `INCLUDE_RODATA`/`#pragma GLOBAL_ASM` directives for non migrated rodata symbols when creating new C files. +* Non migrated rodata symbols will now only be produced if the C file has a corresponding rodata file with the same name and the C file has a `INCLUDE_RODATA`/`#pragma GLOBAL_ASM` directive referencing the symbol, similar to how functions are disassembled. + * Because of this, the `partial_migration` attribute has lost its purpose and has been removed. +* Rodata symbol files are now included in the autogenerated dependency files too. + +### 0.12.14 + +* New option: `pair_rodata_to_text`. + * If enabled, splat will try to find to which text segment an unpaired rodata segment belongs and it will hint it to the user. + +### 0.12.13 + +* bss segments can now omit the rom offset. + +### 0.12.12 + +* Try to detect and warn to the user if a gap between two migrated rodata symbols is detected and suggest possible solutions to the user. + +### 0.12.11 + +* New disassembly option in the yaml: `allow_data_addends`. + * Allows enabling/disabling using addends on all `.data` symbols. +* Three new options for symbols: `name_end`, `allow_addend` and `dont_allow_addend`. + * `name_end`: allows to provide a closing name for any symbol. Useful for handwritten asm which usually have an "end" name. + * `allow_addend` and `dont_allow_addend`: Allow overriding the global `allow_data_addends` option for allowing addends on data symbols. + +### 0.12.10 + +* Allows passing user-created relocs to the disassembler via the `reloc_addrs.txt` file, allowing to improve the automatic disassembly. +* Multiple reloc_addrs files can be specified in the yaml with the `reloc_addrs_path` option. + +### 0.12.9 + +* Added `format_sym_name()` to the vtx segment so it, too, can be extended + +### 0.12.8 + +* The gfx and vtx segments now have a `data_only` option, which, if enabled, will emit only the plain data for the type and omit the enclosing symbol definition. This mode is useful when you want to manually declare the symbol and then #include the extracted data within the declaration. +* The gfx segment has a method, `format_sym_name()`, which will allow custom overriding of the output of symbol names by extending the `gfx` segment. For example, this can be used to transform context-specific symbol names like mac_01_vtx into N(vtx), where N() is a macro that applies the current "namespace" to the symbol. Paper Mario plans to use this so we can extract an asset once and then #include it in multiple places, while giving each inclusion unique symbol names for each component. + +### 0.12.7 + +* Allow setting a different macro for jumptable labels with `asm_jtbl_label_macro` + * The currently recommended one is `jlabel` instead of `glabel` +* Two new options for symbols: `force_migration` and `force_not_migration` + * Useful for weird cases where the disassembler decided a rodata symbol must (or must not) be migrated when it really shouldn't (or should) +* Fix `str_encoding` defaulting to `False` instead of `None` +* Output empty rules in generated dependency files to avoid issues when the function file does not exist anymore (i.e. when it gets matched) +* Allow changing the `include_macro_inc` option in the yaml + +### 0.12.6 + +* Adds two new N64-specific segments: + * IPL3: Allows setting its correct VRAM address without messing the global segment detection + * RSP: Allows disassembling using the RSP instruction set instead of the default one +* PS2 was added as a new platform option. + * When this is selected the R5900 instruction set will be used when disassembling instead of the default one. + +### 0.12.5 + +* Update minimal spimdisasm version to 1.7.1. +* Fix spimdisasm>=1.7.0 non being able to see symbols which only are referenced by other data symbols. +* An check was added to prevent segments marked with `exclusive_ram_id` have a vram address range which overlaps with segments not marked with said tag. If this happens it will be warned to the user. + +### 0.12.4 + +* Fixed a bug involving the order of attributes in symbol_addrs preventing proper range searching during calls to `get_symbol` + +### 0.12.3: Initial Gamecube Support +Initial support for Gamecube disk images has been set up! Disassembly is not currently supported, and a more comprehensive explanation of Gamecube support will come once that is finished. + +* The Symbol class is now hashable +* Added the ability for segments to specify a file path (`path`) to receive that file's contents as their split input +* The `generated_s_preamble` option now will be applied to data files created by spimdisasm +* Rewrote symbol range check code to be more efficient +* Fixed bug that allowed empty top-level segments of type `code`. +* Fixed progress bars to properly update their descriptions +* Fixed bug pertaining to symbols getting assigned to segments they shouldn't if their segment is given in symbol_addrs (`segment:`) + +### 0.12.2 +* Fixed bug where `given_dir` was possibly not a `Path` + +### 0.12.1 +* The constructor for `Segment` takes far fewer arguments now, which will affect (and hopefully simplify) any custom segments that are implemented. + +* The new option `string_encoding` can be set at the global or segment level and will influence the encoding for strings in rodata during disassembly. The default encoding used is EUC-JP, as it was previously. + +## 0.12.0: Performance Boost + +In this release, we bring many performance improvements, making splat dramatically faster. We have observed speedups of 10-20x, though your results may vary. + +* Linker script `_romPos` alignment statements now take a form that is friendlier to different assemblers. + +* Fixed the default value of `use_legacy_include_asm` to be what it was before 0.11.2 + +### 0.11.2 +* The way options are parsed and accessed has been completely refactored. The following option names have changed: + +`linker_symbol_header_path` -> `ld_symbol_header_path` + +`asm_endlabels` -> `asm_end_label` + +Additionally, any custom segments or code that needs to read options will have to accommodate the new API for doing so. Options are now fields of an object named `opts` within the existing `options` namespace. Because the options are fields, `get_` is no longer necessary. To give an example: + +Before: `options.get_asm_path()` + +After: `options.opts.asm_path` + +The clean_up_path function in linker_entry.py now uses a cache, offering a small performance improvement during the linker script writing phase. + +### 0.11.1 +* The linker script now includes a `_SIZE` symbol for each segment. +* The new `create_asm_dependencies`, if enabled, will cause splat to create `.asmproc.d` files that can inform a build system which asm files a c file depends upon. If your build system is configured correctly, this can allow triggering a rebuild of a C file when its included asm files are modified. +* Splat no longer depends directly on pypng and now instead uses [n64img](https://github.com/decompals/n64img). Currently, all image behavior uses the exact same code. Eventually, n64img will be implemented in C and support rebuilding images as well. + +## 0.11.0: Spimdisasm Returns + +Spimdisasm now handles data (data, rodata, bss) disassembly in splat! This includes a few changes in behavior: + +* Rodata will be migrated to c files' asm function files when a .rodata subsegment is used that corresponds with an identically-named c file. Some symbols may not be automatically migrated to functions when it is not clear if they belong to the function itself (an example of which being const arrays). In this case, the `partial_migration` option can be enabled for the given .rodata subsegment and splat will create .s files for these unmigrated rodata symbols. These files can then be included in your c files, or you can go ahead and migrate these symbols to c and disable the `partial_migration` feature. + +* BSS can now be disassembled as well, and the size of a code segment's bss section can be specified with the `bss_size` option. This option will tell splat how large the bss section is in bytes so BSS can properly be handled during disassembly. For bss subsegments, the rom address will of course not change, but the vram address should still be specified. This currently can only be done in the dict form of segment representation, rather than the list form. + +Thanks again to [AngheloAlf](https://github.com/AngheloAlf) for adding this functionality and continuing to improve splat's disassembler. + +## 0.10.0: The Linker Script Update + +Linker scripts splat produces are now capable of being shift-friendly. Rom addresses will automatically shift, and ram addresses will still be hard-coded unless the new segment option `follows_vram` is specified. The value of this option should be the name of a segment (a) that this segment (b) should follow in memory. If a grows or shrinks, b's start address will also do so to accommodate it. + +The `enable_ld_alignment_hack` option and corresponding behavior has been removed. This proved to add too much complexity to the linker script generation code and was becoming quite a burden to keep dealing with. Apologies for any inconvenience this may cause. But trust me: in the long run, it's good you won't be depending on that madness. + +### 0.9.5 +* Changes have been made to the linker script such that it is more shiftable. Rather than setting the rom position to hard-coded addresses, it increments the position by the size of the previous segment. Some projects may experience some alignment-related issues after this change. If specified, the new segment option `align: n` will add an `ALIGN(n)` directive for that section's linker segment. + +### 0.9.4 +* A new linker script section is now automatically created when the .bss section begins, using NOLOAD as opposed to the previous hacky rom rewinding we were previously doing. Additionally, `ld_section_labels` now includes `.rodata` by default. + +### 0.9.3 +* Added `add_set_gp_64` option (true by default), which allows controlling whether to add ".set gp=64" to asm/hasm files + +### 0.9.2 +* Added "palette" argument to ci4/ci8 segments so that segments' palettes can be manually specified + +### 0.9.1 +* Fixed a bug in which local labels and jump table labels could replace raw words in data blobs during data disassembly + +## 0.9.0: The Big Update +### Introducing [spimdisasm](https://github.com/Decompollaborate/spimdisasm)! +* Thanks to [AngheloAlf](https://github.com/AngheloAlf), we now have a much better MIPS disassembler in splat! spimdisasm has much better hi/lo matching, much lower ram usage, and plenty of other goodies. + +We plan to roll this out in phases. Currently, it only handles actual code disassembly. Later on, we will probably migrate our current data assembly code to use spimdisasm as well. + +**NOTICE**: This integration has been tested on a variety of games and configurations. However, with any giant change to the platform like this, there are bound to be things we didn't catch. Please be patient with us as we handle these remaining issues. Though from what we've seen already, the slight bugs one may come across are totally worth the much improved disassembly. + +### gfx segment type +* A new `gfx` segment type is available, which creates a c file containing a disassembled display list according to the segment's start and end offsets. Thanks to [Glank](https://github.com/glankk) and [Tharo](https://github.com/thar0/) for their work on [libgfxd](https://github.com/glankk/libgfxd) and [pygfxd](https://github.com/thar0/pygfxd/), respectively, for helping make this a possibility in splat. + +### API breaking changes +* Some `Segment()` arguments have changed, which may cause extensions to break. Please see the `__init__` function for `Segment` for more details. + +### symbol_addrs.txt changes +* symbol_addrs now supports the `segment:` attribute, which allows specifying the symbol's top-level segment. This can be helpful for symbol resolution when overlays use overlapping vram ranges. See `exclusive_ram_id` below for more information. + +### Global options changes + +The new `symbol_name_format` option allows specification of how symbols will be named. This can be set as a global option and also changed per-segment. `symbol_name_format_no_rom` is used when the symbol does not have a rom address (BSS). + + The following substitutions are allowed: + +`$ROM` - the rom address of the symbol, hex-formatted and padded to 6 characters (ABCF10, 000030, 123456) (note: only for `symbol_name_format`, usage in `symbol_name_format_no_rom` will cause an error) + +`$VRAM` - the vram address of the symbol, hex-formatted and padded to 8 characters (00030010, 00020015, ABCDEF10) + +`$SEG` - the name of the top-level segment in which the symbol resides + +The default values for these options are as follows + +`symbol_name_format` : `$VRAM` + +`symbol_name_format_no_rom` : `$VRAM_$SEG` + +The appropriate prefix string will still automatically be applied depending on the type of the symbol: `D_` for data, `jtbl_` for jump tables, and `func_` for functions. This functionality may be customizable in the future. + +---- +The `auto_all_sections` option now should be a list of section names (`[".data", ".rodata", ".bss"]` by default) indicating the sections that should be linked from .o files built from source files (.c or asm/hasm .s files), when no subsegment explicitly indicates linking this type of section. + +For example, if any subsegment of a code segment is of segment type `data` or `.data`, the `.data` section from all `c`/`asm`/`hasm` subsegments will not be linked unless explicitly indicated with a relevant `.data` subsegment. + +Previously, this option was a bool, and it enabled this feature for all sections specified in `section_order`. Now, the desired sections must be specified manually. The default value for this option retains previous behavior. + +---- +The new `mips_abi_float_regs` option allows for changing the format of float registers for MIPS disassembly. The default value does not change any prior behavior, but `o32` is heavily encouraged and may become the default option in the future. For more information, see this [great writeup](https://gist.github.com/EllipticEllipsis/27eef11205c7a59d8ea85632bc49224d). + +---- +The new `gfx_ucode` option allows for specifying the target for the graphics macro format, which is used in the gfx segment type. The default is `f3dex2`. + + +### Segment options changes + +The new `exclusive_ram_id` segment option allows specifying an identifer that will prevent the segment from seeing any symbols from other segments with the same identifer. This is useful when multiple segments are mapped to the same vram address at runtime and should never be able to refer to each other's symbols. Setting all of these segments to have the same value for this option will prevent their symbols from clashing / meshing unexpectedly. + +---- + +The `overlay` setting on segments has been removed. Please see `symbol_name_format` above for info on how to influence the names of symbols, which can be applied at the segment level as well as the global level. + +---- +## 0.8.0: Arbitrary Section Order +* You can now use the option `section_order` to define the binary section order for your target binary. By default, this is `[".text", ".data", ".rodata", ".bss"]`. See options.py for more details +* Documented all options in options.py +* Support for SN64 games (thanks Wiseguy!) +* More consistent handling of paths (thanks Mkst!) +* Various other cleanup and fixes across the board + +### 0.7.10: WIP PSX support +* WIP PSX support has been added, thanks to @mkst! (https://github.com/ethteck/splat/pull/99) + * Many segments have moved to a "common" package + * Endianness of the input binary is now a configurable option +* Linker hack restored but is now optional and off by default + +### 0.7.9 +* Finally removed the dumb linker section alignment hack +* Added version number to output on execution + +### 0.7.8 + +* Fixed a bug relating to a linker section alignment hack (thanks Wiseguy!) +* Fixed a bug in linker_entry.py's clean_up_path that should make this function more versatile (thanks Wiseguy!) + +### 0.7.7 + +* Disassembly now reads the `size` property of a function in symbol_addrs.txt to disassemble `size / 4` number of instructions. Feel free to specify the size of your functions in your symbol_addrs file if splat's disassembly is chopping a function too short or making a function too long. + +### 0.7.6 + +* Fixed a bug involving detection of defined functions in c files for GLOBAL_ASM-using projects +* Added options to disable the creation of undefined_funcs/syms_auto.txt files +* Added a Vtx segment type for creating c files containg model vertex data in the n64 libultra Vtx format +* Added a `cpp` segment type which is identical to `c` but looks for a file with the extension ".cpp" instead of ".c". + +### 0.7.5: all_ types and auto_all_sections + +If you have a group segment with multiple c files and want splat to automatically create linker entries at a given position for each code object (c, asm, hasm) in the segment, you can use an `all_` type for that section. For example, you can add `[auto, all_bss]` as the last subsegment in a segment. This will direct splat to create a linker entry for each code object in the segment. This saves a lot of time when it comes to manually adding .bss subsegments for bss support, for example. The same thing can be done for data and rodata sections, but note this should probably be done later into a project when all data / rodata is migrated to c files, as the `all_` types lose the rom positioning information that's necessary for splat to do proper disassembly. + +The `auto_all_sections` option, when set to true, will automatically add `all_` types into every group. This is only done for a section in a group if no other manual declarations for that section exist. For example, if you have 30 c files in a group and a .data later on for one of them, `auto_all_sections` will not interfere with your `.data` subsegment. If you remove this, however, splat will use `auto_all_sections` to implicitly `.data` subsegments for all of your code objects behind the scenes. This feature is again particualrly helpful for bss support, as it will create bss linker entries for every file in your project (assuming you don't have any manual .bss subsegments), which eliminates the need to create dummy .bss subsegments just for the sake of configuring the linker script. + +### 0.7.2 + +* Data disassembly changes: + * String detection has been improved. Please send me false positives / negatives as you see them and I can try to improve it further! + * Symbols in a data segment pointed to by other symbols will now properly be split out as their own symbols + +### 0.7.1 + +* Image segment changes: + * Added `flip_x` and `flip_y` boolean parameters to replace `flip`. + * `flip` is deprecated and will produce a warning when used. + * Fixed flipping of `ci4` and `ci8` images. + * Fixed `extract: false` (and `start: auto`) behaviour. + +## 0.7.0: The Path Update + +* Significantly better performance, especially when using the cache feature (`--use-cache` CLI arg). +* BREAKING: Some cli args for splat have been renamed. Please consult the usage output (-h or no args) for more information. + * `--new` has been renamed to `--use-cache` + * `--modes` arg changes: + * Image modes have been combined into the `img` mode + * Code and ASM modes have been combined into the `code` mode +* BREAKING: The `name` attribute of a segment now should no longer be a subdirectory but rather a meaningful name for the segment which will be used as the name of the linker section. If your `name` was previously a directory, please change it into a `dir`. +* BREAKING: `subsections` has been renamed to `subsegments` +* New `dir` segment attribute specifies a subdirectory into which files will be saved. You can combine `dir` ("foo") with a subsection file name containing a subdirectory ("bar/out"), and the paths will be joined (foo/bar/out.c) + * If the `dir` attribute is specified but the `name` isn't, the `name` becomes `dir` with directory separation slashes replaced with underscores (foo/bar/baz -> foo_bar_baz) +* BREAKING: Many configuration options have been renamed. `_dir` options have been changed to the suffix `_path`. +* BREAKING: Assets (non-code, like `bin` and images) are now placed in the directory `asset_path` (defaults to `assets`). +* Linker symbol header generation. Set the `linker_symbol_header_path` option to use. + * `typedef u8[] Addr;` is recommended in your `common.h` header. +* You can now provide `auto` as the `start` attribute for a segment, e.g. `[auto, c, my_file]`. This causes the segment to not be extracted, but linked. This feature is intended for modding. +* Providing just a ROM address but no type or name for a segment is now valid anywhere in `segments` or `subsegments` rather than just at the end of the ROM. It specifies the end of the previous segment for types that need it (`palette`, `bin`, `Yay0`) and causes the linker to simply write padding until that address. +* The linker script file is left untouched if the contents have not changed since the previous split. +* You can now group together segments with `type: group` (similar to `code`). Note that any ASM or C segments must live under a `type: code` segment, not a basic `group`. + +### 0.6.5: Bugfixes, rodata migration, and made options static + +If you wrote a custom extension, options should be imported and statically referenced +`from util import options` + +see options.py for more info on how to now get and set options + +BREAKING: vram can only be specified on a segment if the segment is defined as a dict in the config + +### 0.6.3: More refactoring +**Breaking Change**: The command line args to split.py have changed. Currently, only the config path is now a required argument to splat. The old `rom` and `outdir` parameters are now optional (`--rom`, `--outdir`). Now, you can add rom and out directory paths in the yaml. + +The `out_dir` option specifies a directory relative to the config file. If your config file is in a subdirectory of the main repo, you can set `out_dir: ../`, for example. + +The `target_path` option spcifies a path to the binary file to split, relative to the `out_dir`. If your `baserom.z64` is in the top-level of the repo, you can set `target_path: baserom.z64`, for example. + +### 0.6.2: subsegments +I've begun a refactor of the code "files" code, which makes everything cleaner and easier to extend. +There's also a new option, `create_new_c_files`, which disables the creation of nonexistent c files. This behavior is on by default, but if you want to disable it for any reason, you now have the option to do so. + +I am also working on adding bss support as well. It should almost be all set, aside from the changes needed in the linker script. + +**Breaking change**: The `files` field in `code` segments should now be renamed to `subsegments`. + +### 0.6.1: `assets_dir` option + +This release adds a new `assets_dir` option in `splat.yaml`s that allows you to override the default `img`, `bin`, and other directories that segments output to. + +Want to interdisperse split assets with your sourcecode? `assets_dir: src`! +Want to have all assets live in a single directory? `assets_dir: assets`! + +## 0.6: The Symbol Update +Internally, there's a new Symbol class which stores information about a symbol and is stored in a couple places during disassembly. Many things should be improved, such as reconciling symbols within overlays, things being named functions vs data symbols, and more. + +**Breaking change**: The format to symbol_addrs.txt has been updated. After specifying the name and address of a symbol (`symbol = addr;`), optional properties of symbols can be set via inline comment, space delimited, in any order. The properties are of the format `name:value` + * `type:` supports `func` mostly right now but will support `label` and `data` later on. Internally, `jtbl` is used as well, for jump tables. Splat uses type information during disassembly to disambiguate symbols with the same addresses. + * `rom:` is for the hex rom address of the symbol, beginning with `0x`. If available, this information is extremely valuable for use in disambiguating symbols. + * `size:` specifies the size of the symbol, which splat will use to generate offsets during disassembly. Uses the same format as `rom:` + +**function example**: `FuncNameHere = 0x80023423; // type:func rom:0x10023` + +**data example**: `gSomeDataVar = 0x80024233; // type:data size:0x100` + +## 0.5 The Rename Update +* n64splat name changed to splat + * Some refactoring was done to support other platforms besides n64 in the future + * New `platform` option, which defaults to `n64` + * This will cause breaking changes in custom segments, so please refer to one of the changes in one of the n64 base segments for details +* Support for custom artifact paths + * New `undefined_syms_auto_path` option + * New `undefined_funcs_auto_path` option + * New `cache_path` option + * (All path-like options' names now end with `_path`) diff --git a/tools/splat/LICENSE b/tools/splat/LICENSE new file mode 100644 index 00000000..42621fb7 --- /dev/null +++ b/tools/splat/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Ethan Roseman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/splat/Makefile b/tools/splat/Makefile new file mode 100644 index 00000000..b72aafec --- /dev/null +++ b/tools/splat/Makefile @@ -0,0 +1,11 @@ +UTIL_DIR := util + +default: all + +all: Yay0decompress + +Yay0decompress: + gcc $(UTIL_DIR)/n64/Yay0decompress.c -fPIC -shared -O3 -Wall -Wextra -o $(UTIL_DIR)/n64/Yay0decompress + +clean: + rm -f $(UTIL_DIR)/n64/Yay0decompress diff --git a/tools/splat/README.md b/tools/splat/README.md new file mode 100644 index 00000000..de7abc7c --- /dev/null +++ b/tools/splat/README.md @@ -0,0 +1,9 @@ +# splat +A binary splitting tool to assist with decompilation and modding projects + +Currently, only N64 and PSX binaries are supported. + +Please check out the [wiki](https://github.com/ethteck/splat/wiki) for more information including [examples](https://github.com/ethteck/splat/wiki/Examples) of projects that use splat. + +### Requirements +splat requires Python 3.8+. Package requirements can be installed via `pip3 install -U -r requirements.txt` diff --git a/tools/splat/create_config.py b/tools/splat/create_config.py new file mode 100755 index 00000000..cf344813 --- /dev/null +++ b/tools/splat/create_config.py @@ -0,0 +1,192 @@ +#! /usr/bin/env python3 + +import argparse +import sys +from pathlib import Path + +from segtypes.gc.rarc import GcSegRarc +from util.gc import gcinfo + +from util.n64 import find_code_length, rominfo + +parser = argparse.ArgumentParser( + description="Create a splat config from an N64 ROM or a GameCube disc image." +) +parser.add_argument("file", help="Path to a .z64/.n64 ROM or .iso/.gcm GameCube image") + + +def main(file_path: Path): + if not file_path.exists(): + sys.exit(f"File {file_path} does not exist ({file_path.absolute()})") + if file_path.is_dir(): + sys.exit(f"Path {file_path} is a directory ({file_path.absolute()})") + + # Check for N64 ROM + if file_path.suffix.lower() == ".n64" or file_path.suffix.lower() == ".z64": + create_n64_config(file_path) + return + + file_bytes = file_path.read_bytes() + + # Check for GC disc image + if int.from_bytes(file_bytes[0x1C:0x20], byteorder="big") == 0xC2339F3D: + create_gc_config(file_path, file_bytes) + + +def create_n64_config(rom_path: Path): + rom_bytes = rominfo.read_rom(rom_path) + + rom = rominfo.get_info(rom_path, rom_bytes) + basename = rom.name.replace(" ", "").lower() + + header = f"""\ +name: {rom.name.title()} ({rom.get_country_name()}) +sha1: {rom.sha1} +options: + basename: {basename} + target_path: {rom_path.with_suffix(".z64")} + base_path: . + compiler: {rom.compiler} + find_file_boundaries: True + header_encoding: {rom.header_encoding} + platform: n64 + # undefined_funcs_auto: True + # undefined_funcs_auto_path: undefined_funcs_auto.txt + # undefined_syms_auto: True + # undefined_syms_auto_path: undefined_syms_auto.txt + # symbol_addrs_path: symbol_addrs.txt + # asm_path: asm + # src_path: src + # build_path: build + # extensions_path: tools/splat_ext + # mips_abi_float_regs: o32 + # section_order: [".text", ".data", ".rodata", ".bss"] + # auto_all_sections: [".data", ".rodata", ".bss"] + # libultra_symbols: True + # hardware_regs: True +""" + + first_section_end = find_code_length.run(rom_bytes, 0x1000, rom.entry_point) + + segments = f"""\ +segments: + - name: header + type: header + start: 0x0 + + - name: boot + type: bin + start: 0x40 + + - name: entry + type: code + start: 0x1000 + vram: 0x{rom.entry_point:X} + subsegments: + - [0x1000, hasm] + + - name: main + type: code + start: 0x{0x1000 + rom.entrypoint_info.entry_size:X} + vram: 0x{rom.entry_point + rom.entrypoint_info.entry_size:X} + follows_vram: entry +""" + + if rom.entrypoint_info.bss_size is not None: + segments += f"""\ + bss_size: 0x{rom.entrypoint_info.bss_size:X} +""" + + segments += f"""\ + subsegments: + - [0x{0x1000 + rom.entrypoint_info.entry_size:X}, asm] +""" + + if ( + rom.entrypoint_info.bss_size is not None + and rom.entrypoint_info.bss_start_address is not None + ): + bss_start = rom.entrypoint_info.bss_start_address - rom.entry_point + 0x1000 + # first_section_end points to the start of data + segments += f"""\ + - [0x{first_section_end:X}, data] + - {{ start: 0x{bss_start:X}, type: bss, vram: 0x{rom.entrypoint_info.bss_start_address:08X} }} +""" + # Point next segment to the detected end of the main one + first_section_end = bss_start + + segments += f"""\ + + - type: bin + start: 0x{first_section_end:X} + follows_vram: main + - [0x{rom.size:X}] +""" + + out_file = f"{basename}.yaml" + with open(out_file, "w", newline="\n") as f: + print(f"Writing config to {out_file}") + f.write(header) + f.write(segments) + + +def create_gc_config(iso_path: Path, iso_bytes: bytes): + gc = gcinfo.get_info(iso_path, iso_bytes) + basename = gc.system_code + gc.game_code + gc.region_code + gc.publisher_code + + header = f"""\ +name: \"{gc.name.title()} ({gc.get_region_name()})\" +system_code: {gc.system_code} +game_code: {gc.game_code} +region_code: {gc.region_code} +publisher_code: {gc.publisher_code} +sha1: {gc.sha1} +options: + filesystem_path: filesystem + basename: {basename} + target_path: {iso_path.with_suffix(".iso")} + base_path: . + compiler: {gc.compiler} + platform: gc + # undefined_funcs_auto: True + # undefined_funcs_auto_path: undefined_funcs_auto.txt + # undefined_syms_auto: True + # undefined_syms_auto_path: undefined_syms_auto.txt + # symbol_addrs_path: symbol_addrs.txt + # asm_path: asm + # src_path: src + # build_path: build + # extensions_path: tools/splat_ext + # section_order: [".text", ".data", ".rodata", ".bss"] + # auto_all_sections: [".data", ".rodata", ".bss"] +""" + + segments = f"""\ +segments: + - name: filesystem + type: fst + path: filesystem/sys/fst.bin + - name: bootinfo + type: bootinfo + path: filesystem/sys/boot.bin + - name: bi2 + type: bi2 + path: filesystem/sys/bi2.bin + - name: apploader + type: apploader + path: filesystem/sys/apploader.img + - name: main + type: dol + path: filesystem/sys/main.dol +""" + + out_file = f"{basename}.yaml" + with open(out_file, "w", newline="\n") as f: + print(f"Writing config to {out_file}") + f.write(header) + f.write(segments) + + +if __name__ == "__main__": + args = parser.parse_args() + main(Path(args.file)) diff --git a/tools/splat/mypy.ini b/tools/splat/mypy.ini new file mode 100644 index 00000000..6e7c2ef4 --- /dev/null +++ b/tools/splat/mypy.ini @@ -0,0 +1,4 @@ +[mypy] +ignore_missing_imports = True +check_untyped_defs = True +mypy_path = stubs diff --git a/tools/splat/platforms/gc.py b/tools/splat/platforms/gc.py new file mode 100644 index 00000000..af08a283 --- /dev/null +++ b/tools/splat/platforms/gc.py @@ -0,0 +1,5 @@ +from util.gc import gcfst + + +def init(target_bytes: bytes): + gcfst.split_iso(target_bytes) diff --git a/tools/splat/platforms/n64.py b/tools/splat/platforms/n64.py new file mode 100644 index 00000000..ed3ee1c3 --- /dev/null +++ b/tools/splat/platforms/n64.py @@ -0,0 +1,10 @@ +from util import compiler, log, options, palettes, symbols + + +def init(target_bytes: bytes): + symbols.spim_context.fillDefaultBannedSymbols() + + if options.opts.libultra_symbols: + symbols.spim_context.globalSegment.fillLibultraSymbols() + if options.opts.hardware_regs: + symbols.spim_context.globalSegment.fillHardwareRegs(True) diff --git a/tools/splat/platforms/psx.py b/tools/splat/platforms/psx.py new file mode 100644 index 00000000..09da192f --- /dev/null +++ b/tools/splat/platforms/psx.py @@ -0,0 +1,2 @@ +def init(target_bytes: bytes): + pass diff --git a/tools/splat/requirements.txt b/tools/splat/requirements.txt new file mode 100644 index 00000000..711d553e --- /dev/null +++ b/tools/splat/requirements.txt @@ -0,0 +1,10 @@ +PyYAML +pylibyaml +tqdm +intervaltree +colorama +# This value should be keep in sync with the version listed on split.py +spimdisasm>=1.12.0 +rabbitizer>=1.4.0 +pygfxd +n64img>=0.1.4 diff --git a/tools/splat/segtypes/__init__.py b/tools/splat/segtypes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/splat/segtypes/address_range.py b/tools/splat/segtypes/address_range.py new file mode 100644 index 00000000..0c57cc0d --- /dev/null +++ b/tools/splat/segtypes/address_range.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass + + +@dataclass +class AddressRange: + start: int + end: int + + def contains(self, addr: int) -> bool: + return self.start <= addr < self.end diff --git a/tools/splat/segtypes/common/__init__.py b/tools/splat/segtypes/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/splat/segtypes/common/asm.py b/tools/splat/segtypes/common/asm.py new file mode 100644 index 00000000..db7a1840 --- /dev/null +++ b/tools/splat/segtypes/common/asm.py @@ -0,0 +1,39 @@ +from pathlib import Path +from typing import Optional + +from util import options + +from segtypes.common.codesubsegment import CommonSegCodeSubsegment + + +class CommonSegAsm(CommonSegCodeSubsegment): + @staticmethod + def is_text() -> bool: + return True + + def out_path(self) -> Optional[Path]: + return options.opts.asm_path / self.dir / f"{self.name}.s" + + def scan(self, rom_bytes: bytes): + if ( + self.rom_start is not None + and self.rom_end is not None + and self.rom_start != self.rom_end + ): + self.scan_code(rom_bytes) + + def get_file_header(self): + return [] + + def split(self, rom_bytes: bytes): + if not self.rom_start == self.rom_end and self.spim_section is not None: + out_path = self.out_path() + if out_path: + out_path.parent.mkdir(parents=True, exist_ok=True) + + self.print_file_boundaries() + + with open(out_path, "w", newline="\n") as f: + for line in self.get_file_header(): + f.write(line + "\n") + f.write(self.spim_section.disassemble()) diff --git a/tools/splat/segtypes/common/bin.py b/tools/splat/segtypes/common/bin.py new file mode 100644 index 00000000..b72a2010 --- /dev/null +++ b/tools/splat/segtypes/common/bin.py @@ -0,0 +1,28 @@ +from pathlib import Path +from typing import Optional + +from util import log, options + +from segtypes.common.segment import CommonSegment + + +class CommonSegBin(CommonSegment): + def out_path(self) -> Optional[Path]: + return options.opts.asset_path / self.dir / f"{self.name}.bin" + + def split(self, rom_bytes): + path = self.out_path() + assert path is not None + path.parent.mkdir(parents=True, exist_ok=True) + + if self.rom_end is None: + log.error( + f"segment {self.name} needs to know where it ends; add a position marker [0xDEADBEEF] after it" + ) + + with open(path, "wb") as f: + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + + f.write(rom_bytes[self.rom_start : self.rom_end]) + self.log(f"Wrote {self.name} to {path}") diff --git a/tools/splat/segtypes/common/bss.py b/tools/splat/segtypes/common/bss.py new file mode 100644 index 00000000..ef79311f --- /dev/null +++ b/tools/splat/segtypes/common/bss.py @@ -0,0 +1,60 @@ +import spimdisasm +from util import options, symbols, log + +from segtypes.common.data import CommonSegData + + +class CommonSegBss(CommonSegData): + def get_linker_section(self) -> str: + return ".bss" + + @staticmethod + def is_noload() -> bool: + return True + + def disassemble_data(self, rom_bytes: bytes): + if not isinstance(self.rom_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a rom_start. Got '{self.rom_start}'" + ) + + # Supposedly logic error, not user error + assert isinstance(self.rom_end, int), f"{self.name} {self.rom_end}" + + # Supposedly logic error, not user error + segment_rom_start = self.get_most_parent().rom_start + assert isinstance(segment_rom_start, int), f"{self.name} {segment_rom_start}" + + if not isinstance(self.vram_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a vram address. Got '{self.vram_start}'" + ) + + next_subsegment = self.parent.get_next_subsegment_for_ram(self.vram_start) + if next_subsegment is None: + bss_end = self.get_most_parent().vram_end + else: + bss_end = next_subsegment.vram_start + assert isinstance(bss_end, int), f"{self.name} {bss_end}" + + self.spim_section = spimdisasm.mips.sections.SectionBss( + symbols.spim_context, + self.rom_start, + self.rom_end, + self.vram_start, + bss_end, + self.name, + segment_rom_start, + self.get_exclusive_ram_id(), + ) + + self.spim_section.analyze() + self.spim_section.setCommentOffset(self.rom_start) + + for spim_sym in self.spim_section.symbolList: + symbols.create_symbol_from_spim_symbol( + self.get_most_parent(), spim_sym.contextSym + ) + + def should_scan(self) -> bool: + return options.opts.is_mode_active("code") and self.vram_start is not None diff --git a/tools/splat/segtypes/common/c.py b/tools/splat/segtypes/common/c.py new file mode 100644 index 00000000..76d6981d --- /dev/null +++ b/tools/splat/segtypes/common/c.py @@ -0,0 +1,428 @@ +import os +import re +from pathlib import Path +from typing import Optional, Set, List, Tuple + +import spimdisasm + +from util import log, options, symbols +from util.compiler import GCC, SN64, IDO +from util.symbols import Symbol + +from segtypes.common.codesubsegment import CommonSegCodeSubsegment +from segtypes.common.group import CommonSegGroup +from segtypes.common.rodata import CommonSegRodata + + +class CommonSegC(CommonSegCodeSubsegment): + defined_funcs: Set[str] = set() + global_asm_funcs: Set[str] = set() + global_asm_rodata_syms: Set[str] = set() + + STRIP_C_COMMENTS_RE = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE, + ) + + C_FUNC_RE = re.compile( + r"^(?:static\s+)?[^\s]+\s+([^\s(]+)\(([^;)]*)\)[^;]+?{", re.MULTILINE + ) + + C_GLOBAL_ASM_IDO_RE = re.compile( + r"GLOBAL_ASM\(\"(\w+\/)*(\w+)\.s\"\)", re.MULTILINE + ) + + @staticmethod + def strip_c_comments(text): + def replacer(match): + s = match.group(0) + if s.startswith("/"): + return " " + else: + return s + + return re.sub(CommonSegC.STRIP_C_COMMENTS_RE, replacer, text) + + @staticmethod + def get_funcs_defined_in_c(c_file: Path) -> Set[str]: + with open(c_file, "r") as f: + text = CommonSegC.strip_c_comments(f.read()) + + return set(m.group(1) for m in CommonSegC.C_FUNC_RE.finditer(text)) + + @staticmethod + def find_all_instances(string: str, sub: str): + start = 0 + while True: + start = string.find(sub, start) + if start == -1: + return + yield start + start += len(sub) + + @staticmethod + def get_close_parenthesis(string: str, pos: int): + paren_count = 0 + while True: + cur_char = string[pos] + if cur_char == "(": + paren_count += 1 + elif cur_char == ")": + if paren_count == 0: + return pos + 1 + else: + paren_count -= 1 + pos += 1 + + @staticmethod + def find_include_macro(text: str, macro_name: str): + for pos in CommonSegC.find_all_instances(text, f"{macro_name}("): + close_paren_pos = CommonSegC.get_close_parenthesis( + text, pos + len(f"{macro_name}(") + ) + macro_contents = text[pos:close_paren_pos] + macro_args = macro_contents.split(",") + if options.opts.use_legacy_include_asm: + if len(macro_args) >= 3: + yield macro_args[2].strip(" )") + else: + if len(macro_args) >= 2: + yield macro_args[1].strip(" )") + + @staticmethod + def find_include_asm(text: str): + return CommonSegC.find_include_macro(text, "INCLUDE_ASM") + + @staticmethod + def find_include_rodata(text: str): + return CommonSegC.find_include_macro(text, "INCLUDE_RODATA") + + @staticmethod + def get_global_asm_funcs(c_file: Path) -> Set[str]: + with c_file.open() as f: + text = CommonSegC.strip_c_comments(f.read()) + if options.opts.compiler in [GCC, SN64]: + return set(CommonSegC.find_include_asm(text)) + else: + return set( + m.group(2) for m in CommonSegC.C_GLOBAL_ASM_IDO_RE.finditer(text) + ) + + @staticmethod + def get_global_asm_rodata_syms(c_file: Path) -> Set[str]: + with c_file.open() as f: + text = CommonSegC.strip_c_comments(f.read()) + if options.opts.compiler in [GCC, SN64]: + return set(CommonSegC.find_include_rodata(text)) + else: + return set( + m.group(2) for m in CommonSegC.C_GLOBAL_ASM_IDO_RE.finditer(text) + ) + + @staticmethod + def is_text() -> bool: + return True + + def out_path(self) -> Optional[Path]: + return options.opts.src_path / self.dir / f"{self.name}.c" + + def scan(self, rom_bytes: bytes): + if ( + self.rom_start is not None + and self.rom_end is not None + and self.rom_start != self.rom_end + ): + path = self.out_path() + if path: + if options.opts.do_c_func_detection and os.path.exists(path): + # TODO run cpp? + self.defined_funcs = self.get_funcs_defined_in_c(path) + self.global_asm_funcs = self.get_global_asm_funcs(path) + self.global_asm_rodata_syms = self.get_global_asm_rodata_syms(path) + symbols.to_mark_as_defined.update(self.defined_funcs) + symbols.to_mark_as_defined.update(self.global_asm_funcs) + symbols.to_mark_as_defined.update(self.global_asm_rodata_syms) + + self.scan_code(rom_bytes) + + def split(self, rom_bytes: bytes): + if self.rom_start != self.rom_end: + asm_out_dir = options.opts.nonmatchings_path / self.dir + asm_out_dir.mkdir(parents=True, exist_ok=True) + + self.print_file_boundaries() + + assert self.spim_section is not None and isinstance( + self.spim_section, spimdisasm.mips.sections.SectionText + ), f"{self.name}, rom_start:{self.rom_start}, rom_end:{self.rom_end}" + + rodata_spim_segment = None + if ( + options.opts.migrate_rodata_to_functions + and self.rodata_sibling is not None + ): + assert isinstance( + self.rodata_sibling, CommonSegRodata + ), self.rodata_sibling.type + if self.rodata_sibling.spim_section is not None: + assert isinstance( + self.rodata_sibling.spim_section, + spimdisasm.mips.sections.SectionRodata, + ) + rodata_spim_segment = self.rodata_sibling.spim_section + + # Precompute function-rodata pairings + symbols_entries = ( + spimdisasm.mips.FunctionRodataEntry.getAllEntriesFromSections( + self.spim_section, rodata_spim_segment + ) + ) + + is_new_c_file = False + + # Check and create the C file + c_path = self.out_path() + if c_path: + if not c_path.exists() and options.opts.create_c_files: + self.create_c_file(asm_out_dir, c_path, symbols_entries) + is_new_c_file = True + + self.create_asm_dependencies_file( + c_path, asm_out_dir, is_new_c_file, symbols_entries + ) + + # Produce the asm files for functions + for entry in symbols_entries: + if entry.function is not None: + if ( + entry.function.getName() in self.global_asm_funcs + or is_new_c_file + ): + func_sym = self.get_symbol( + entry.function.vram, + in_segment=True, + type="func", + local_only=True, + ) + assert func_sym is not None + + self.create_c_asm_file(entry, asm_out_dir, func_sym) + else: + for spim_rodata_sym in entry.rodataSyms: + if ( + spim_rodata_sym.getName() in self.global_asm_rodata_syms + or is_new_c_file + ): + rodata_sym = self.get_symbol( + spim_rodata_sym.vram, in_segment=True, local_only=True + ) + assert rodata_sym is not None + + self.create_unmigrated_rodata_file( + spim_rodata_sym, asm_out_dir, rodata_sym + ) + + def get_c_preamble(self): + ret = [] + + preamble = options.opts.generated_c_preamble + ret.append(preamble) + ret.append("") + + return ret + + def check_gaps_in_migrated_rodata( + self, + func: spimdisasm.mips.symbols.SymbolFunction, + rodata_list: List[spimdisasm.mips.symbols.SymbolBase], + ): + for index in range(len(rodata_list) - 1): + rodata_sym = rodata_list[index] + next_rodata_sym = rodata_list[index + 1] + + if rodata_sym.vramEnd != next_rodata_sym.vram: + log.write( + f"\nA gap was detected in migrated rodata symbols!", status="warn" + ) + log.write( + f"\t In function '{func.getName()}' (0x{func.vram:08X}), gap detected between '{rodata_sym.getName()}' (0x{rodata_sym.vram:08X}) and '{next_rodata_sym.getName()}' (0x{next_rodata_sym.vram:08X})" + ) + log.write( + f"\t The address of the missing rodata symbol is 0x{rodata_sym.vramEnd:08X}" + ) + log.write( + f"\t Try to force the migration of that symbol with `force_migration:True` in the symbol_addrs.txt file; or avoid the migration of symbols around this address with `force:not_migration:True`" + ) + + def create_c_asm_file( + self, + func_rodata_entry: spimdisasm.mips.FunctionRodataEntry, + out_dir: Path, + func_sym: Symbol, + ): + outpath = out_dir / self.name / (func_sym.name + ".s") + + # Skip extraction if the file exists and the symbol is marked as extract=false + if outpath.exists() and not func_sym.extract: + return + + outpath.parent.mkdir(parents=True, exist_ok=True) + + with outpath.open("w", newline="\n") as f: + if options.opts.asm_inc_header: + f.write( + options.opts.c_newline.join(options.opts.asm_inc_header.split("\n")) + ) + + func_rodata_entry.writeToFile(f) + + if func_rodata_entry.function is not None: + self.check_gaps_in_migrated_rodata( + func_rodata_entry.function, func_rodata_entry.rodataSyms + ) + self.check_gaps_in_migrated_rodata( + func_rodata_entry.function, func_rodata_entry.lateRodataSyms + ) + + self.log(f"Disassembled {func_sym.name} to {outpath}") + + def create_unmigrated_rodata_file( + self, + spim_rodata_sym: spimdisasm.mips.symbols.SymbolBase, + out_dir: Path, + rodata_sym: Symbol, + ): + outpath = out_dir / self.name / (rodata_sym.name + ".s") + + # Skip extraction if the file exists and the symbol is marked as extract=false + if outpath.exists() and not rodata_sym.extract: + return + + outpath.parent.mkdir(parents=True, exist_ok=True) + + with outpath.open("w", newline="\n") as f: + if options.opts.include_macro_inc: + f.write('.include "macro.inc"\n\n') + preamble = options.opts.generated_s_preamble + if preamble: + f.write(preamble + "\n") + assert rodata_sym.linker_section is not None, rodata_sym.name + f.write(f".section {rodata_sym.linker_section}\n\n") + f.write(spim_rodata_sym.disassemble()) + + self.log(f"Disassembled {rodata_sym.name} to {outpath}") + + def get_c_line_include_macro( + self, + spim_sym: spimdisasm.mips.symbols.SymbolBase, + asm_out_dir: Path, + macro_name: str, + ) -> str: + if options.opts.compiler == IDO: + # IDO uses the asm processor to embeed assembly and it doesn't require a special directive to include symbols + asm_outpath = Path( + os.path.join(asm_out_dir, self.name, spim_sym.getName() + ".s") + ) + rel_asm_outpath = os.path.relpath(asm_outpath, options.opts.base_path) + return f'#pragma GLOBAL_ASM("{rel_asm_outpath}")' + + if options.opts.use_legacy_include_asm: + rel_asm_out_dir = asm_out_dir.relative_to(options.opts.nonmatchings_path) + return f'{macro_name}(const s32, "{rel_asm_out_dir / self.name}", {spim_sym.getName()});' + + return f'{macro_name}("{asm_out_dir / self.name}", {spim_sym.getName()});' + + def get_c_lines_for_function( + self, func: spimdisasm.mips.symbols.SymbolFunction, asm_out_dir: Path + ) -> List[str]: + c_lines = [] + + # Terrible hack to "auto-decompile" empty functions + if ( + options.opts.auto_decompile_empty_functions + and func.instructions[0].isReturn() + and func.instructions[1].isNop() + ): + c_lines.append("void " + func.getName() + "(void) {") + c_lines.append("}") + else: + c_lines.append( + self.get_c_line_include_macro(func, asm_out_dir, "INCLUDE_ASM") + ) + c_lines.append("") + return c_lines + + def get_c_lines_for_rodata_sym( + self, rodata_sym: spimdisasm.mips.symbols.SymbolBase, asm_out_dir: Path + ): + c_lines = [ + self.get_c_line_include_macro(rodata_sym, asm_out_dir, "INCLUDE_RODATA") + ] + c_lines.append("") + return c_lines + + def create_c_file( + self, + asm_out_dir: Path, + c_path: Path, + symbols_entries: List[spimdisasm.mips.FunctionRodataEntry], + ): + c_lines = self.get_c_preamble() + + for entry in symbols_entries: + if entry.function is not None: + c_lines += self.get_c_lines_for_function(entry.function, asm_out_dir) + else: + for rodata_sym in entry.rodataSyms: + c_lines += self.get_c_lines_for_rodata_sym(rodata_sym, asm_out_dir) + + c_path.parent.mkdir(parents=True, exist_ok=True) + with c_path.open("w") as f: + f.write("\n".join(c_lines)) + log.write(f"Wrote {self.name} to {c_path}") + + def create_asm_dependencies_file( + self, + c_path: Path, + asm_out_dir: Path, + is_new_c_file: bool, + symbols_entries: List[spimdisasm.mips.FunctionRodataEntry], + ): + if not options.opts.create_asm_dependencies: + return + if ( + len(self.global_asm_funcs) + len(self.global_asm_rodata_syms) + ) == 0 and not is_new_c_file: + return + + assert self.spim_section is not None + + build_path = options.opts.build_path + + dep_path = build_path / c_path.with_suffix(".asmproc.d") + dep_path.parent.mkdir(parents=True, exist_ok=True) + with dep_path.open("w") as f: + o_path = build_path / c_path.with_suffix(".o") + f.write(f"{o_path}:") + depend_list = [] + for entry in symbols_entries: + if entry.function is not None: + func_name = entry.function.getName() + + if func_name in self.global_asm_funcs or is_new_c_file: + outpath = asm_out_dir / self.name / (func_name + ".s") + depend_list.append(outpath) + f.write(f" \\\n {outpath}") + else: + for rodata_sym in entry.rodataSyms: + rodata_name = rodata_sym.getName() + + if rodata_name in self.global_asm_rodata_syms or is_new_c_file: + outpath = asm_out_dir / self.name / (rodata_name + ".s") + depend_list.append(outpath) + f.write(f" \\\n {outpath}") + + f.write("\n") + + for depend_file in depend_list: + f.write(f"{depend_file}:\n") diff --git a/tools/splat/segtypes/common/code.py b/tools/splat/segtypes/common/code.py new file mode 100644 index 00000000..dc9a5bce --- /dev/null +++ b/tools/splat/segtypes/common/code.py @@ -0,0 +1,371 @@ +import typing +from collections import OrderedDict +from typing import Dict, List, Optional, Tuple, Set + +from util import log, options +from util.range import Range +from util.symbols import Symbol + +from segtypes.common.group import CommonSegGroup +from segtypes.segment import Segment + +CODE_TYPES = ["c", "asm", "hasm"] + + +def dotless_type(type: str) -> str: + return type[1:] if type[0] == "." else type + + +# code group +class CommonSegCode(CommonSegGroup): + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + ): + self.bss_size: int = yaml.get("bss_size", 0) if isinstance(yaml, dict) else 0 + + super().__init__( + rom_start, + rom_end, + type, + name, + vram_start, + args=args, + yaml=yaml, + ) + + self.reported_file_split = False + self.jtbl_glabels_to_add: Set[int] = set() + self.jumptables: Dict[int, Tuple[int, int]] = {} + self.rodata_syms: Dict[int, List[Symbol]] = {} + self.align = 0x10 + + @property + def needs_symbols(self) -> bool: + return True + + @property + def vram_end(self) -> Optional[int]: + if self.vram_start is not None and self.size is not None: + return self.vram_start + self.size + self.bss_size + else: + return None + + def check_rodata_sym_impl(self, func_addr: int, sym: Symbol, rodata_section: Range): + if rodata_section.is_complete(): + assert rodata_section.start is not None + assert rodata_section.end is not None + + rodata_start: int = rodata_section.start + rodata_end: int = rodata_section.end + if rodata_start <= sym.vram_start < rodata_end: + if func_addr not in self.rodata_syms: + self.rodata_syms[func_addr] = [] + self.rodata_syms[func_addr].append(sym) + + # Prepare symbol for migration to the function + def check_rodata_sym(self, func_addr: int, sym: Symbol): + rodata_section = self.section_boundaries.get(".rodata") + if rodata_section is not None: + self.check_rodata_sym_impl(func_addr, sym, rodata_section) + rodata_section = self.section_boundaries.get(".rdata") + if rodata_section is not None: + self.check_rodata_sym_impl(func_addr, sym, rodata_section) + + def handle_alls(self, segs: List[Segment], base_segs) -> bool: + for i, elem in enumerate(segs): + if elem.type.startswith("all_"): + alls = [] + + rep_type = f"{elem.type[4:]}" + replace_class = Segment.get_class_for_type(rep_type) + + for base in base_segs.items(): + if isinstance(elem.rom_start, int) and isinstance( + self.rom_start, int + ): + # Shoddy rom to ram + assert self.vram_start is not None, self.vram_start + vram_start = elem.rom_start - self.rom_start + self.vram_start + else: + vram_start = None + rep: Segment = replace_class( + rom_start=elem.rom_start, + rom_end=elem.rom_end, + type=rep_type, + name=base[0], + vram_start=vram_start, + args=[], + yaml={}, + ) + rep.extract = False + rep.given_subalign = self.given_subalign + rep.exclusive_ram_id = self.get_exclusive_ram_id() + rep.given_dir = self.given_dir + rep.given_symbol_name_format = self.symbol_name_format + rep.given_symbol_name_format_no_rom = self.symbol_name_format_no_rom + rep.sibling = base[1] + rep.parent = self + if rep.special_vram_segment: + self.special_vram_segment = True + alls.append(rep) + + # Insert alls into segs at i + del segs[i] + segs[i:i] = alls + return True + return False + + # Find places we should automatically add "all_data" / "all_rodata" / "all_bss" + def find_inserts( + self, found_sections: typing.OrderedDict[str, Range] + ) -> "OrderedDict[str, int]": + inserts: OrderedDict[str, int] = OrderedDict() + + section_order = self.section_order.copy() + section_order.remove(".text") + + for i, section in enumerate(section_order): + if section not in options.opts.auto_all_sections: + continue + + if not found_sections[section].has_start(): + search_done = False + for j in range(i - 1, -1, -1): + end = found_sections[section_order[j]].end + if end is not None: + inserts[section] = end + search_done = True + break + if not search_done: + inserts[section] = -1 + pass + + return inserts + + def parse_subsegments(self, segment_yaml) -> List[Segment]: + if "subsegments" not in segment_yaml: + if not self.parent: + raise Exception( + f"No subsegments provided in top-level code segment {self.name}" + ) + return [] + + base_segments: OrderedDict[str, Segment] = OrderedDict() + ret = [] + prev_start: Optional[int] = -1 + inserts: OrderedDict[ + str, int + ] = ( + OrderedDict() + ) # Used to manually add "all_" types for sections not otherwise defined in the yaml + + self.section_boundaries = OrderedDict( + (s_name, Range()) for s_name in options.opts.section_order + ) + + found_sections = OrderedDict( + (s_name, Range()) for s_name in self.section_boundaries + ) # Stores yaml index where a section was first found + found_sections.pop(".text") + + # Mark any manually added dot types + cur_section = None + + for i, subsection_yaml in enumerate(segment_yaml["subsegments"]): + # endpos marker + if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1: + continue + + typ = Segment.parse_segment_type(subsection_yaml) + if typ.startswith("all_"): + typ = typ[4:] + if not typ.startswith("."): + typ = f".{typ}" + + if typ in found_sections: + if cur_section is None: + # Starting point + found_sections[typ].start = i + cur_section = typ + else: + if cur_section != typ: + # We're changing sections + if found_sections[cur_section].has_end(): + log.error( + f"Section {cur_section} end encountered but was already ended earlier!" + ) + if found_sections[typ].has_start(): + log.error( + f"Section {typ} start encounted but has already started earlier!" + ) + + # End the current section + found_sections[cur_section].end = i + + # Start the next section + found_sections[typ].start = i + cur_section = typ + + if cur_section is not None: + found_sections[cur_section].end = -1 + + inserts = self.find_inserts(found_sections) + + last_rom_end = 0 + + for i, subsection_yaml in enumerate(segment_yaml["subsegments"]): + # endpos marker + if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1: + continue + + typ = Segment.parse_segment_type(subsection_yaml) + start = Segment.parse_segment_start(subsection_yaml) + + # Add dummy segments to be expanded later + if typ.startswith("all_"): + dummy_seg = Segment( + rom_start=start, + rom_end=None, + type=typ, + name="", + vram_start=None, + args=[], + yaml={}, + ) + dummy_seg.given_subalign = self.given_subalign + dummy_seg.exclusive_ram_id = self.exclusive_ram_id + dummy_seg.given_dir = self.given_dir + dummy_seg.given_symbol_name_format = self.symbol_name_format + dummy_seg.given_symbol_name_format_no_rom = ( + self.symbol_name_format_no_rom + ) + ret.append(dummy_seg) + continue + + segment_class = Segment.get_class_for_type(typ) + + end = self.get_next_seg_start(i, segment_yaml["subsegments"]) + + if ( + isinstance(start, int) + and isinstance(prev_start, int) + and start < prev_start + ): + log.error( + f"Error: Group segment {self.name} contains subsegments which are out of ascending rom order (0x{prev_start:X} followed by 0x{start:X})" + ) + + vram = None + if start is not None: + assert isinstance(start, int) + vram = self.get_most_parent().rom_to_ram(start) + + if segment_class.is_noload(): + # Pretend bss's rom address is after the last actual rom segment + start = last_rom_end + # and it has a rom size of zero + end = last_rom_end + + segment: Segment = Segment.from_yaml( + segment_class, subsection_yaml, start, end, vram + ) + + segment.sibling = base_segments.get(segment.name, None) + if segment.is_rodata() and segment.sibling is not None: + segment.sibling.rodata_sibling = segment + + segment.parent = self + if segment.special_vram_segment: + self.special_vram_segment = True + + for i, section in enumerate(self.section_order): + if not self.section_boundaries[section].has_start() and dotless_type( + section + ) == dotless_type(segment.type): + if i > 0: + prev_section = self.section_order[i - 1] + self.section_boundaries[prev_section].end = segment.vram_start + self.section_boundaries[section].start = segment.vram_start + + segment.bss_contains_common = self.bss_contains_common + ret.append(segment) + + if segment.is_text(): + base_segments[segment.name] = segment + + prev_start = start + if end is not None: + last_rom_end = end + + # Add the automatic all_ sections + orig_len = len(ret) + for section in reversed(inserts): + idx = inserts[section] + + if idx == -1: + idx = orig_len + + # bss hack TODO maybe rethink + if ( + section == "bss" + and self.vram_start is not None + and self.rom_end is not None + and self.rom_start is not None + ): + rom_start = self.rom_end + vram_start = self.vram_start + self.rom_end - self.rom_start + else: + rom_start = None + vram_start = None + + new_seg = Segment( + rom_start=rom_start, + rom_end=None, + type="all_" + section, + name="", + vram_start=vram_start, + args=[], + yaml={}, + ) + new_seg.given_subalign = self.given_subalign + new_seg.exclusive_ram_id = self.exclusive_ram_id + new_seg.given_dir = self.given_dir + new_seg.given_symbol_name_format = self.symbol_name_format + new_seg.given_symbol_name_format_no_rom = self.symbol_name_format_no_rom + ret.insert(idx, new_seg) + + check = True + while check: + check = self.handle_alls(ret, base_segments) + + # TODO why is this necessary? + rodata_section = self.section_boundaries.get( + ".rodata" + ) or self.section_boundaries.get(".rdata") + if ( + rodata_section is not None + and rodata_section.has_start() + and not rodata_section.has_end() + ): + assert self.vram_end is not None + rodata_section.end = self.vram_end + + return ret + + def scan(self, rom_bytes): + # Always scan code first + for sub in self.subsegments: + if sub.type in CODE_TYPES and sub.should_scan(): + sub.scan(rom_bytes) + + # Scan everyone else + for sub in self.subsegments: + if sub.type not in CODE_TYPES and sub.should_scan(): + sub.scan(rom_bytes) diff --git a/tools/splat/segtypes/common/codesubsegment.py b/tools/splat/segtypes/common/codesubsegment.py new file mode 100644 index 00000000..04237059 --- /dev/null +++ b/tools/splat/segtypes/common/codesubsegment.py @@ -0,0 +1,198 @@ +from typing import Optional + +import spimdisasm +import rabbitizer + +from util import options, symbols, log + +from segtypes import segment +from segtypes.common.code import CommonSegCode + +from segtypes.segment import Segment + + +# abstract class for c, asm, data, etc +class CommonSegCodeSubsegment(Segment): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + vram = segment.parse_segment_vram(self.yaml) + if vram is not None: + self.vram_start = vram + + self.str_encoding: Optional[str] = ( + self.yaml.get("str_encoding", None) if isinstance(self.yaml, dict) else None + ) + + self.spim_section: Optional[spimdisasm.mips.sections.SectionBase] = None + self.instr_category = rabbitizer.InstrCategory.CPU + if options.opts.platform == "ps2": + self.instr_category = rabbitizer.InstrCategory.R5900 + + @property + def needs_symbols(self) -> bool: + return True + + def get_linker_section(self) -> str: + return ".text" + + def scan_code(self, rom_bytes, is_hasm=False): + if not isinstance(self.rom_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a rom_start. Got '{self.rom_start}'" + ) + + # Supposedly logic error, not user error + assert isinstance(self.rom_end, int), self.rom_end + + # Supposedly logic error, not user error + segment_rom_start = self.get_most_parent().rom_start + assert isinstance(segment_rom_start, int), segment_rom_start + + if not isinstance(self.vram_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a vram address. Got '{self.vram_start}'" + ) + + self.spim_section = spimdisasm.mips.sections.SectionText( + symbols.spim_context, + self.rom_start, + self.rom_end, + self.vram_start, + self.name, + rom_bytes, + segment_rom_start, + self.get_exclusive_ram_id(), + ) + + self.spim_section.isHandwritten = is_hasm + self.spim_section.instrCat = self.instr_category + + self.spim_section.analyze() + self.spim_section.setCommentOffset(self.rom_start) + + for func in self.spim_section.symbolList: + assert isinstance(func, spimdisasm.mips.symbols.SymbolFunction) + + self.process_insns(func) + + # Process jumptable labels and pass them to spimdisasm + self.gather_jumptable_labels(rom_bytes) + for jtbl_label_vram in self.parent.jtbl_glabels_to_add: + sym = self.create_symbol( + jtbl_label_vram, True, type="jtbl_label", define=True + ) + sym.type = "jtbl_label" + symbols.add_symbol_to_spim_section(self.spim_section, sym) + + def process_insns( + self, + func_spim: spimdisasm.mips.symbols.SymbolFunction, + ): + assert isinstance(self.parent, CommonSegCode) + assert func_spim.vram is not None + assert func_spim.vramEnd is not None + assert self.spim_section is not None + self.parent: CommonSegCode = self.parent + + symbols.create_symbol_from_spim_symbol( + self.get_most_parent(), func_spim.contextSym + ) + + # Gather symbols found by spimdisasm and create those symbols in splat's side + for referenced_vram in func_spim.instrAnalyzer.referencedVrams: + context_sym = self.spim_section.getSymbol( + referenced_vram, tryPlusOffset=False + ) + if context_sym is not None: + if context_sym.type == spimdisasm.common.SymbolSpecialType.jumptable: + self.parent.jumptables[referenced_vram] = ( + func_spim.vram, + func_spim.vramEnd, + ) + symbols.create_symbol_from_spim_symbol( + self.get_most_parent(), context_sym + ) + + # Main loop + for i, insn in enumerate(func_spim.instructions): + instr_offset = i * 4 + + # update pointer accesses from this function + if instr_offset in func_spim.instrAnalyzer.symbolInstrOffset: + sym_address = func_spim.instrAnalyzer.symbolInstrOffset[instr_offset] + + context_sym = self.spim_section.getSymbol( + sym_address, tryPlusOffset=False + ) + if context_sym is not None: + sym = symbols.create_symbol_from_spim_symbol( + self.get_most_parent(), context_sym + ) + + if self.parent: + self.parent.check_rodata_sym(func_spim.vram, sym) + + def print_file_boundaries(self): + if not options.opts.find_file_boundaries or not self.spim_section: + return + + assert isinstance(self.rom_start, int) + + for in_file_offset in self.spim_section.fileBoundaries: + if (in_file_offset % 16) != 0: + continue + + if not self.parent.reported_file_split: + self.parent.reported_file_split = True + + # Look up for the last symbol in this boundary + sym_addr = 0 + for sym in self.spim_section.symbolList: + symOffset = sym.inFileOffset - self.spim_section.inFileOffset + if in_file_offset == symOffset: + break + sym_addr = sym.vram + + print( + f"\nSegment {self.name}, symbol at vram {sym_addr:X} ends with extra nops, indicating a likely file split." + ) + print( + "File split suggestions for this segment will follow in config yaml format:" + ) + print(f" - [0x{self.rom_start+in_file_offset:X}, {self.type}]") + + def gather_jumptable_labels(self, rom_bytes): + assert isinstance(self.rom_start, int) + assert isinstance(self.vram_start, int) + + # TODO: use the seg_symbols for this + # jumptables = [j.type == "jtbl" for j in self.seg_symbols] + for jumptable in self.parent.jumptables: + start, end = self.parent.jumptables[jumptable] + rom_offset = self.rom_start + jumptable - self.vram_start + + if rom_offset <= 0: + return + + while rom_offset: + word = rom_bytes[rom_offset : rom_offset + 4] + word_int = int.from_bytes(word, options.opts.endianness) + if word_int >= start and word_int <= end: + self.parent.jtbl_glabels_to_add.add(word_int) + else: + break + + rom_offset += 4 + + def should_scan(self) -> bool: + return ( + options.opts.is_mode_active("code") + and self.rom_start is not None + and self.rom_end is not None + ) + + def should_split(self) -> bool: + return ( + self.extract and options.opts.is_mode_active("code") and self.should_scan() + ) # only split if the segment was scanned first diff --git a/tools/splat/segtypes/common/data.py b/tools/splat/segtypes/common/data.py new file mode 100644 index 00000000..e97ce6de --- /dev/null +++ b/tools/splat/segtypes/common/data.py @@ -0,0 +1,124 @@ +from pathlib import Path +from typing import Optional + +import spimdisasm +from util import options, symbols, log + +from segtypes.common.codesubsegment import CommonSegCodeSubsegment +from segtypes.common.group import CommonSegGroup + + +class CommonSegData(CommonSegCodeSubsegment, CommonSegGroup): + def out_path(self) -> Optional[Path]: + if self.type.startswith("."): + if self.sibling: + # C file + return self.sibling.out_path() + else: + # Implied C file + return options.opts.src_path / self.dir / f"{self.name}.c" + else: + # ASM + return options.opts.data_path / self.dir / f"{self.name}.{self.type}.s" + + def scan(self, rom_bytes: bytes): + CommonSegGroup.scan(self, rom_bytes) + + if self.should_scan(): + self.disassemble_data(rom_bytes) + + def split(self, rom_bytes: bytes): + super().split(rom_bytes) + + if ( + not self.type.startswith(".") + and self.spim_section + and self.should_self_split() + ): + path = self.out_path() + + if path: + path.parent.mkdir(parents=True, exist_ok=True) + + self.print_file_boundaries() + + with open(path, "w", newline="\n") as f: + f.write('.include "macro.inc"\n\n') + preamble = options.opts.generated_s_preamble + if preamble: + f.write(preamble + "\n") + f.write(f".section {self.get_linker_section()}\n\n") + + f.write(self.spim_section.disassemble()) + + def should_self_split(self) -> bool: + return options.opts.is_mode_active("data") + + def should_scan(self) -> bool: + # Ensure data segments are scanned even if extract is False so subsegments get scanned too + # Check for not None so we avoid scanning "auto" segments + return self.rom_start is not None and self.rom_end is not None + + def should_split(self) -> bool: + return True + + def cache(self): + return [CommonSegCodeSubsegment.cache(self), CommonSegGroup.cache(self)] + + def get_linker_section(self) -> str: + return ".data" + + def get_linker_entries(self): + return CommonSegCodeSubsegment.get_linker_entries(self) + + def disassemble_data(self, rom_bytes): + if not isinstance(self.rom_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a rom_start. Got '{self.rom_start}'" + ) + + # Supposedly logic error, not user error + assert isinstance(self.rom_end, int), self.rom_end + + # Supposedly logic error, not user error + segment_rom_start = self.get_most_parent().rom_start + assert isinstance(segment_rom_start, int), segment_rom_start + + if not isinstance(self.vram_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a vram address. Got '{self.vram_start}'" + ) + + self.spim_section = spimdisasm.mips.sections.SectionData( + symbols.spim_context, + self.rom_start, + self.rom_end, + self.vram_start, + self.name, + rom_bytes, + segment_rom_start, + self.get_exclusive_ram_id(), + ) + + self.spim_section.analyze() + self.spim_section.setCommentOffset(self.rom_start) + + rodata_encountered = False + + for symbol in self.spim_section.symbolList: + symbols.create_symbol_from_spim_symbol( + self.get_most_parent(), symbol.contextSym + ) + + # Hint to the user that we are now in the .rodata section and no longer in the .data section (assuming rodata follows data) + if not rodata_encountered and self.get_most_parent().rodata_follows_data: + if symbol.contextSym.isJumpTable(): + rodata_encountered = True + print( + f"Data segment {self.name}, symbol at vram {symbol.contextSym.vram:X} is a jumptable, indicating the start of the rodata section _may_ be near here." + ) + print( + "Please note the real start of the rodata section may be way before this point." + ) + if symbol.contextSym.vromAddress is not None: + print(f" - [0x{symbol.contextSym.vromAddress:X}, rodata]") diff --git a/tools/splat/segtypes/common/decompressor.py b/tools/splat/segtypes/common/decompressor.py new file mode 100644 index 00000000..3bdc5ea9 --- /dev/null +++ b/tools/splat/segtypes/common/decompressor.py @@ -0,0 +1,48 @@ +from typing import Optional, Any + +from util import log, options +from util.n64.decompressor import Decompressor + +from segtypes.n64.segment import N64Segment + + +class CommonSegDecompressor(N64Segment): + decompressor: Decompressor + compression_type = "" # "Mio0" -> filename.Mio0.o + + def split(self, rom_bytes): + if self.decompressor is None: + log.error("Decompressor is not a standalone segment type") + + out_dir = options.opts.asset_path / self.dir + out_dir.mkdir(parents=True, exist_ok=True) + + if self.rom_end is None: + log.error( + f"segment {self.name} needs to know where it ends; add a position marker [0xDEADBEEF] after it" + ) + + out_path = out_dir / f"{self.name}.bin" + with open(out_path, "wb") as f: + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + + self.log(f"Decompressing {self.name}") + compressed_bytes = rom_bytes[self.rom_start : self.rom_end] + decompressed_bytes = self.decompressor.decompress(compressed_bytes) + f.write(decompressed_bytes) + self.log(f"Wrote {self.name} to {out_path}") + + def get_linker_entries(self): + from segtypes.linker_entry import LinkerEntry + + return [ + LinkerEntry( + self, + [options.opts.asset_path / self.dir / f"{self.name}.bin"], + options.opts.asset_path + / self.dir + / f"{self.name}.{self.compression_type}", + self.get_linker_section(), + ) + ] diff --git a/tools/splat/segtypes/common/group.py b/tools/splat/segtypes/common/group.py new file mode 100644 index 00000000..fa263de8 --- /dev/null +++ b/tools/splat/segtypes/common/group.py @@ -0,0 +1,146 @@ +from typing import List, Optional + +from util import log + +from segtypes.common.segment import CommonSegment +from segtypes.segment import Segment + + +class CommonSegGroup(CommonSegment): + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + ): + super().__init__( + rom_start, + rom_end, + type, + name, + vram_start, + args=args, + yaml=yaml, + ) + + self.subsegments: List[Segment] = self.parse_subsegments(yaml) + + def get_next_seg_start(self, i, subsegment_yamls): + return ( + self.rom_end + if i == len(subsegment_yamls) - 1 + else Segment.parse_segment_start(subsegment_yamls[i + 1]) + ) + + def parse_subsegments(self, yaml) -> List[Segment]: + ret: List[Segment] = [] + + if not yaml or "subsegments" not in yaml: + return ret + + prev_start: Optional[int] = -1 + last_rom_end = 0 + + for i, subsection_yaml in enumerate(yaml["subsegments"]): + # endpos marker + if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1: + continue + + typ = Segment.parse_segment_type(subsection_yaml) + start = Segment.parse_segment_start(subsection_yaml) + + segment_class = Segment.get_class_for_type(typ) + + end = self.get_next_seg_start(i, yaml["subsegments"]) + + if ( + isinstance(start, int) + and isinstance(prev_start, int) + and start < prev_start + ): + log.error( + f"Error: Group segment {self.name} contains subsegments which are out of ascending rom order (0x{prev_start:X} followed by 0x{start:X})" + ) + + vram = None + if start is not None: + assert isinstance(start, int) + vram = self.get_most_parent().rom_to_ram(start) + + if segment_class.is_noload(): + # Pretend bss's rom address is after the last actual rom segment + start = last_rom_end + # and it has a rom size of zero + end = last_rom_end + + segment: Segment = Segment.from_yaml( + segment_class, subsection_yaml, start, end, vram + ) + segment.parent = self + if segment.special_vram_segment: + self.special_vram_segment = True + + ret.append(segment) + prev_start = start + if end is not None: + last_rom_end = end + + return ret + + @property + def needs_symbols(self) -> bool: + for seg in self.subsegments: + if seg.needs_symbols: + return True + return False + + def get_linker_entries(self): + return [entry for sub in self.subsegments for entry in sub.get_linker_entries()] + + def scan(self, rom_bytes): + for sub in self.subsegments: + if sub.should_scan(): + sub.scan(rom_bytes) + + def split(self, rom_bytes): + for sub in self.subsegments: + if sub.should_split(): + sub.split(rom_bytes) + + def should_split(self) -> bool: + return self.extract + + def should_scan(self) -> bool: + return self.extract + + def cache(self): + c = [] + + for sub in self.subsegments: + c.append(sub.cache()) + + return c + + def get_subsegment_for_ram(self, addr: int) -> Optional[Segment]: + for sub in self.subsegments: + if sub.contains_vram(addr): + return sub + return None + + def get_next_subsegment_for_ram(self, addr: int) -> Optional[Segment]: + """ + Returns the first subsegment which comes after the specified address, + or None in case this address belongs to the last subsegment of this group + """ + + for sub in self.subsegments: + if sub.vram_start is None: + continue + assert isinstance(sub.vram_start, int) + if sub.vram_start > addr: + return sub + return None diff --git a/tools/splat/segtypes/common/hasm.py b/tools/splat/segtypes/common/hasm.py new file mode 100644 index 00000000..de7c54c1 --- /dev/null +++ b/tools/splat/segtypes/common/hasm.py @@ -0,0 +1,24 @@ +from segtypes.common.asm import CommonSegAsm + + +class CommonSegHasm(CommonSegAsm): + def scan(self, rom_bytes: bytes): + if ( + self.rom_start is not None + and self.rom_end is not None + and self.rom_start != self.rom_end + ): + self.scan_code(rom_bytes, is_hasm=True) + + def split(self, rom_bytes: bytes): + if not self.rom_start == self.rom_end and self.spim_section is not None: + out_path = self.out_path() + if out_path and not out_path.exists(): + out_path.parent.mkdir(parents=True, exist_ok=True) + + self.print_file_boundaries() + + with open(out_path, "w", newline="\n") as f: + for line in self.get_file_header(): + f.write(line + "\n") + f.write(self.spim_section.disassemble()) diff --git a/tools/splat/segtypes/common/header.py b/tools/splat/segtypes/common/header.py new file mode 100644 index 00000000..b03b0ae8 --- /dev/null +++ b/tools/splat/segtypes/common/header.py @@ -0,0 +1,42 @@ +from pathlib import Path + +from util import options + +from segtypes.common.segment import CommonSegment + + +class CommonSegHeader(CommonSegment): + def should_split(self): + return self.extract and options.opts.is_mode_active("code") + + @staticmethod + def get_line(typ, data, comment): + if typ == "ascii": + text = data.decode("ASCII").strip() + text = text.replace("\x00", "\\0") # escape NUL chars + dstr = '"' + text + '"' + else: # .word, .byte + dstr = "0x" + data.hex().upper() + + dstr = dstr.ljust(20 - len(typ)) + + return f".{typ} {dstr} /* {comment} */" + + def out_path(self) -> Path: + return options.opts.asm_path / self.dir / f"{self.name}.s" + + def parse_header(self, rom_bytes): + return [] + + def split(self, rom_bytes): + header_lines = self.parse_header(rom_bytes) + + src_path = self.out_path() + src_path.parent.mkdir(parents=True, exist_ok=True) + with open(src_path, "w", newline="\n") as f: + f.write("\n".join(header_lines)) + self.log(f"Wrote {self.name} to {src_path}") + + @staticmethod + def get_default_name(addr): + return "header" diff --git a/tools/splat/segtypes/common/lib.py b/tools/splat/segtypes/common/lib.py new file mode 100644 index 00000000..51371c17 --- /dev/null +++ b/tools/splat/segtypes/common/lib.py @@ -0,0 +1,53 @@ +from pathlib import Path +from typing import Optional + +from util import log, options + +from segtypes.linker_entry import LinkerEntry +from segtypes.n64.segment import N64Segment + + +class CommonSegLib(N64Segment): + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + ): + super().__init__( + rom_start, + rom_end, + type, + name, + vram_start, + args=args, + yaml=yaml, + ) + + if isinstance(yaml, dict): + log.error("Error: 'dict' not currently supported for 'lib' segment") + return + if len(args) < 1: + log.error(f"Error: {self.name} is missing object file") + return + + self.extract = False + + if len(args) > 1: + self.object, self.section = args[0], args[1] + else: + self.object, self.section = args[0], ".text" + + def get_linker_section(self) -> str: + return self.section + + def get_linker_entries(self): + path = options.opts.lib_path / self.name + + object_path = Path(f"{path}.a:{self.object}.o") + + return [LinkerEntry(self, [path], object_path, self.get_linker_section())] diff --git a/tools/splat/segtypes/common/rdata.py b/tools/splat/segtypes/common/rdata.py new file mode 100644 index 00000000..37adbef2 --- /dev/null +++ b/tools/splat/segtypes/common/rdata.py @@ -0,0 +1,6 @@ +from segtypes.common.rodata import CommonSegRodata + + +class CommonSegRdata(CommonSegRodata): + def get_linker_section(self) -> str: + return ".rdata" diff --git a/tools/splat/segtypes/common/rodata.py b/tools/splat/segtypes/common/rodata.py new file mode 100644 index 00000000..a1896717 --- /dev/null +++ b/tools/splat/segtypes/common/rodata.py @@ -0,0 +1,97 @@ +from typing import Optional, Set, Tuple +import spimdisasm +from segtypes.segment import Segment +from util import log, options, symbols + +from segtypes.common.data import CommonSegData + + +class CommonSegRodata(CommonSegData): + def get_linker_section(self) -> str: + return ".rodata" + + @staticmethod + def is_rodata() -> bool: + return True + + def get_possible_text_subsegment_for_symbol( + self, rodata_sym: spimdisasm.mips.symbols.SymbolBase + ) -> Optional[Tuple[Segment, spimdisasm.common.ContextSymbol]]: + # Check if this rodata segment does not have a corresponding code file, try to look for one + + if self.sibling is not None or not options.opts.pair_rodata_to_text: + return None + + if not rodata_sym.shouldMigrate(): + return None + + if len(rodata_sym.contextSym.referenceFunctions) != 1: + return None + + func = list(rodata_sym.contextSym.referenceFunctions)[0] + text_segment = self.parent.get_subsegment_for_ram(func.vram) + + if text_segment is None or not text_segment.is_text(): + return None + return text_segment, func + + def disassemble_data(self, rom_bytes): + if not isinstance(self.rom_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a rom_start. Got '{self.rom_start}'" + ) + + # Supposedly logic error, not user error + assert isinstance(self.rom_end, int), self.rom_end + + # Supposedly logic error, not user error + segment_rom_start = self.get_most_parent().rom_start + assert isinstance(segment_rom_start, int), segment_rom_start + + if not isinstance(self.vram_start, int): + log.error( + f"Segment '{self.name}' (type '{self.type}') requires a vram address. Got '{self.vram_start}'" + ) + + self.spim_section = spimdisasm.mips.sections.SectionRodata( + symbols.spim_context, + self.rom_start, + self.rom_end, + self.vram_start, + self.name, + rom_bytes, + segment_rom_start, + self.get_exclusive_ram_id(), + ) + + # Set rodata string encoding + # First check the global configuration + if options.opts.string_encoding is not None: + self.spim_section.stringEncoding = options.opts.string_encoding + + # Then check the per-segment configuration in case we want to override the global one + if self.str_encoding is not None: + self.spim_section.stringEncoding = self.str_encoding + + self.spim_section.analyze() + self.spim_section.setCommentOffset(self.rom_start) + + possible_text_segments: Set[Segment] = set() + + for symbol in self.spim_section.symbolList: + generated_symbol = symbols.create_symbol_from_spim_symbol( + self.get_most_parent(), symbol.contextSym + ) + generated_symbol.linker_section = self.get_linker_section() + + possible_text = self.get_possible_text_subsegment_for_symbol(symbol) + if possible_text is not None: + text_segment, refenceeFunction = possible_text + if text_segment not in possible_text_segments: + print( + f"\nRodata segment '{self.name}' may belong to the text segment '{text_segment.name}'" + ) + print( + f" Based on the usage from the function {refenceeFunction.getName()} to the symbol {symbol.getName()}" + ) + possible_text_segments.add(text_segment) diff --git a/tools/splat/segtypes/common/sbss.py b/tools/splat/segtypes/common/sbss.py new file mode 100644 index 00000000..cbd00467 --- /dev/null +++ b/tools/splat/segtypes/common/sbss.py @@ -0,0 +1,6 @@ +from segtypes.common.data import CommonSegData + + +class CommonSegSbss(CommonSegData): + def get_linker_section(self) -> str: + return ".sbss" diff --git a/tools/splat/segtypes/common/sdata.py b/tools/splat/segtypes/common/sdata.py new file mode 100644 index 00000000..a3a0e528 --- /dev/null +++ b/tools/splat/segtypes/common/sdata.py @@ -0,0 +1,6 @@ +from segtypes.common.data import CommonSegData + + +class CommonSegSdata(CommonSegData): + def get_linker_section(self) -> str: + return ".sdata" diff --git a/tools/splat/segtypes/common/segment.py b/tools/splat/segtypes/common/segment.py new file mode 100644 index 00000000..10e2b850 --- /dev/null +++ b/tools/splat/segtypes/common/segment.py @@ -0,0 +1,5 @@ +from segtypes.segment import Segment + + +class CommonSegment(Segment): + pass diff --git a/tools/splat/segtypes/gc/apploader.py b/tools/splat/segtypes/gc/apploader.py new file mode 100644 index 00000000..810e8225 --- /dev/null +++ b/tools/splat/segtypes/gc/apploader.py @@ -0,0 +1,8 @@ +import struct +from pathlib import Path + +from segtypes.gc.segment import GCSegment + + +class GcSegApploader(GCSegment): + pass diff --git a/tools/splat/segtypes/gc/bi2.py b/tools/splat/segtypes/gc/bi2.py new file mode 100644 index 00000000..2bf6a978 --- /dev/null +++ b/tools/splat/segtypes/gc/bi2.py @@ -0,0 +1,67 @@ +import struct +from pathlib import Path + +from util import options + +from segtypes.gc.segment import GCSegment + + +class GcSegBi2(GCSegment): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def split(self, bi2_bytes): + lines = [] + + # Gathering variables + debug_monitor_size = struct.unpack_from(">I", bi2_bytes, 0x00)[0] + simulated_memory_size = struct.unpack_from(">I", bi2_bytes, 0x04)[0] + + argument_offset = struct.unpack_from(">I", bi2_bytes, 0x08)[0] + + debug_flag = struct.unpack_from(">I", bi2_bytes, 0x0C)[0] + + track_offset = struct.unpack_from(">I", bi2_bytes, 0x10)[0] + track_size = struct.unpack_from(">I", bi2_bytes, 0x14)[0] + + country_code_bi2 = struct.unpack_from(">I", bi2_bytes, 0x18)[0] + + unk_int = struct.unpack_from(">I", bi2_bytes, 0x1C)[0] + unk_int_2 = struct.unpack_from(">I", bi2_bytes, 0x20)[0] + + # Outputting .s file + lines.append(f"# GameCube disc image bi2 data, located at 0x440 in the disc.\n") + lines.append(f"# Generated by splat.\n\n") + + lines.append(f".section .data\n\n") + + lines.append(f"debug_monitor_size: .long 0x{debug_monitor_size:08X}\n") + lines.append(f"simulated_memory_size: .long 0x{simulated_memory_size:08X}\n\n") + + lines.append(f"argument_offset: .long 0x{argument_offset:08X}\n\n") + + lines.append(f"debug_flag: .long 0x{debug_flag:08X}\n\n") + + lines.append(f"track_offset: .long 0x{track_offset:08X}\n") + lines.append(f"track_size: .long 0x{track_size:08X}\n\n") + + lines.append(f"country_code_bi2: .long 0x{country_code_bi2:08X}\n\n") + + lines.append(f"ukn_int_bi2: .long 0x{unk_int:08X}\n") + lines.append(f"ukn_int_bi2_2: .long 0x{unk_int_2:08X}\n\n") + + lines.append(f".fill 0x00001FDC\n\n") + + out_path = self.out_path() + out_path.parent.mkdir(parents=True, exist_ok=True) + + with open(out_path, "w", encoding="utf-8") as f: + f.writelines(lines) + + return + + def should_split(self) -> bool: + return True + + def out_path(self) -> Path: + return options.opts.asm_path / "sys" / "bi2.s" diff --git a/tools/splat/segtypes/gc/bootinfo.py b/tools/splat/segtypes/gc/bootinfo.py new file mode 100644 index 00000000..28a93fd7 --- /dev/null +++ b/tools/splat/segtypes/gc/bootinfo.py @@ -0,0 +1,117 @@ +import struct +from pathlib import Path + +from util import options + +from segtypes.gc.segment import GCSegment + + +class GcSegBootinfo(GCSegment): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def split(self, iso_bytes): + lines = [] + + gc_dvd_magic = struct.unpack_from(">I", iso_bytes, 0x1C)[0] + assert gc_dvd_magic == 0xC2339F3D + + # Gathering variables + system_code = chr(iso_bytes[0x00]) + game_code = iso_bytes[0x01:0x03].decode("utf-8") + region_code = chr(iso_bytes[0x03]) + publisher_code = iso_bytes[0x04:0x06].decode("utf-8") + + disc_id = iso_bytes[0x06] + game_version = iso_bytes[0x07] + audio_streaming = iso_bytes[0x08] + stream_buffer_size = iso_bytes[0x09] + + name = iso_bytes[0x20:0x400].decode("utf-8").strip("\x00") + name_padding_len = 0x3E0 - len(name) + + # The following is from YAGCD, don't know what they were for: + # https://web.archive.org/web/20220528011846/http://hitmen.c02.at/files/yagcd/yagcd/chap13.html#sec13.1 + apploader_size = struct.unpack_from(">I", iso_bytes, 0x400)[0] + debug_monitor_address = struct.unpack_from(">I", iso_bytes, 0x404)[0] + + # These on the other hand are easy to understand + dol_offset = struct.unpack_from(">I", iso_bytes, 0x420)[0] + fst_offset = struct.unpack_from(">I", iso_bytes, 0x424)[0] + fst_size = struct.unpack_from(">I", iso_bytes, 0x428)[0] + fst_max_size = struct.unpack_from(">I", iso_bytes, 0x42C)[0] + + user_position = struct.unpack_from(">I", iso_bytes, 0x430)[0] + user_length = struct.unpack_from(">I", iso_bytes, 0x434)[0] + unk_int = struct.unpack_from(">I", iso_bytes, 0x438)[0] + + # Outputting .s file + lines.append(f"# GameCube disc image boot data, located at 0x00 in the disc.\n") + lines.append(f"# Generated by splat.\n\n") + + lines.append(f".section .data\n\n") + + # Game ID stuff + lines.append(f'system_code: .ascii "{system_code}"\n') + lines.append(f'game_code: .ascii "{game_code}"\n') + lines.append(f'region_code: .ascii "{region_code}"\n') + lines.append(f'publisher_code: .ascii "{publisher_code}"\n\n') + + lines.append(f"disc_id: .byte {disc_id:X}\n") + lines.append(f"game_version: .byte {game_version:X}\n") + lines.append(f"audio_streaming: .byte {audio_streaming:X}\n") + lines.append(f"stream_buffer_size: .byte {stream_buffer_size:X}\n\n") + + # padding + lines.append(f".fill 0x12\n\n") + + # GC magic number + lines.append(f"gc_magic: .long 0xC2339F3D\n\n") + + # Long game name + lines.append(f'game_name: .ascii "{name}"\n') + lines.append(f".org 0x400\n\n") + + lines.append(f"apploader_size: .long 0x{apploader_size:08X}\n\n") + + # Unknown stuff gleaned from YAGCD + lines.append(f"debug_monitor_address: .long 0x{debug_monitor_address:08X}\n\n") + + # More padding + lines.append(f".fill 0x18\n\n") + + # DOL and FST data + lines.append(f"dol_offset: .long 0x{dol_offset:08X}\n") + lines.append(f"fst_offset: .long 0x{fst_offset:08X}\n\n") + + lines.append( + f"# The FST is only allocated once per game boot, even in games with multiple disks. fst_max_size is used to ensure that\n" + ) + lines.append( + f"# there is enough space allocated for the FST in the event that a game spans multiple disks, and one disk has a larger FST than another.\n" + ) + lines.append(f"fst_size: .long 0x{fst_size:08X}\n") + lines.append(f"fst_max_size: .long 0x{fst_max_size:08X}\n\n") + + # Honestly not sure what this data is for + lines.append(f"# Not even YAGCD knows what these are for.\n") + lines.append(f"user_position: .long 0x{user_position:08X}\n") + lines.append(f"user_length: .long 0x{user_length:08X}\n") + lines.append(f"unk_int: .long 0x{unk_int:08X}\n\n") + + # Final padding + lines.append(f".word 0\n") + out_path = self.out_path() + + out_path.parent.mkdir(parents=True, exist_ok=True) + + with open(out_path, "w", encoding="utf-8") as f: + f.writelines(lines) + + return + + def should_split(self) -> bool: + return True + + def out_path(self) -> Path: + return options.opts.asm_path / "sys" / "boot.s" diff --git a/tools/splat/segtypes/gc/dol.py b/tools/splat/segtypes/gc/dol.py new file mode 100644 index 00000000..3a92bda8 --- /dev/null +++ b/tools/splat/segtypes/gc/dol.py @@ -0,0 +1,8 @@ +import struct +from pathlib import Path + +from segtypes.gc.segment import GCSegment + + +class GcSegDol(GCSegment): + pass diff --git a/tools/splat/segtypes/gc/dolheader.py b/tools/splat/segtypes/gc/dolheader.py new file mode 100644 index 00000000..f8a060a6 --- /dev/null +++ b/tools/splat/segtypes/gc/dolheader.py @@ -0,0 +1,68 @@ +from util import options + +from segtypes.common.header import CommonSegHeader + + +class DolSegHeader(CommonSegHeader): + def parse_header(self, dol_bytes): + header_lines = [] + header_lines.append(".section .data\n") + + # Text file offsets + for i in range(0x00, 0x1C, 4): + header_lines.append( + self.get_line("word", dol_bytes[i : i + 4], f"Text {i / 4} Offset") + ) + # Data file offsets + for i in range(0x1C, 0x48, 4): + header_lines.append( + self.get_line("word", dol_bytes[i : i + 4], f"Data {i / 4} Offset") + ) + + # Text RAM addresses + for i in range(0x48, 0x64, 4): + header_lines.append( + self.get_line( + "word", + dol_bytes[i : i + 4], + f"Text {(i - 0x48) / 4} Address", + ) + ) + # Data RAM addresses + for i in range(0x64, 0x90, 4): + header_lines.append( + self.get_line( + "word", + dol_bytes[i : i + 4], + f"Data {(i - 0x64) / 4} Address", + ) + ) + + # Text file sizes + for i in range(0x90, 0xAC, 4): + header_lines.append( + self.get_line( + "word", + dol_bytes[i : i + 4], + f"Text {(i - 0x90) / 4} Size", + ) + ) + # Data file sizes + for i in range(0xAC, 0xD8, 4): + header_lines.append( + self.get_line( + "word", + dol_bytes[i : i + 4], + f"Data {(i - 0xAC) / 4} Size", + ) + ) + + # BSS RAM address + header_lines.append(self.get_line("word", dol_bytes[0xD8:0xDC], "BSS Address")) + # BSS size + header_lines.append(self.get_line("word", dol_bytes[0xDC:0xE0], "BSS Size")) + + # Entry point + header_lines.append(self.get_line("word", dol_bytes[0xE0:0xE4], "Entry Point")) + + return header_lines diff --git a/tools/splat/segtypes/gc/fst.py b/tools/splat/segtypes/gc/fst.py new file mode 100644 index 00000000..be091fee --- /dev/null +++ b/tools/splat/segtypes/gc/fst.py @@ -0,0 +1,8 @@ +import struct +from pathlib import Path + +from segtypes.gc.segment import GCSegment + + +class GcSegFst(GCSegment): + pass diff --git a/tools/splat/segtypes/gc/rarc.py b/tools/splat/segtypes/gc/rarc.py new file mode 100644 index 00000000..43eda142 --- /dev/null +++ b/tools/splat/segtypes/gc/rarc.py @@ -0,0 +1,321 @@ +import struct +from enum import IntEnum +from pathlib import Path + +from typing import List, Optional + +from util import options +from util.gc.gcutil import read_string_from_bytes +from util.n64.Yay0decompress import Yay0Decompressor + +from segtypes.gc.segment import GCSegment + + +# Represents the RARC archive format used by first-party Nintendo games. +class GcSegRarc(GCSegment): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def split(self, file_bytes): + assert self.file_path is not None + + archive = GCRARCArchive(self.file_path, file_bytes) + archive.build_hierarchy(file_bytes) + + archive.emit(file_bytes) + + def should_split(self) -> bool: + return True + + +class GCRARCArchive: + def __init__(self, file_path: Path, file_bytes): + self.file_path = file_path + self.compression = "none" + file_bytes = self.try_decompress_archive(file_bytes) + + self.magic = struct.unpack_from(">I", file_bytes, 0x0000)[0] + self.file_size = struct.unpack_from(">I", file_bytes, 0x0004)[0] + self.data_header_offset = struct.unpack_from(">I", file_bytes, 0x0008)[0] + self.file_data_offset = struct.unpack_from(">I", file_bytes, 0x000C)[0] + 0x0020 + self.total_file_data_size = struct.unpack_from(">I", file_bytes, 0x0010)[0] + + self.mram_preload_size = struct.unpack_from(">I", file_bytes, 0x0014)[0] + self.aram_preload_size = struct.unpack_from(">I", file_bytes, 0x0018)[0] + + self.data_header = GCRARCDataHeader(self.data_header_offset, file_bytes) + self.nodes: List[GCRARCNode] = [] + + def try_decompress_archive(self, file_bytes): + compression_scheme = struct.unpack_from(">I", file_bytes, 0x0000)[0] + + # Yaz0 + if compression_scheme == 0x59617A30: + self.compression = "yaz0" + return file_bytes + # Yay0 + elif compression_scheme == 0x59617930: + self.compression = "yay0" + return Yay0Decompressor().decompress(file_bytes) + # Not compressed! + else: + return file_bytes + + def build_hierarchy(self, file_bytes): + string_table_offset = self.data_header.string_table_offset + string_table_size = self.data_header.string_table_size + + string_table_bytes = file_bytes[ + string_table_offset : string_table_offset + string_table_size + ] + + # Load the file entries into their corresponding nodes. + for i in range(self.data_header.node_count): + offset = self.data_header.node_offset + i * 0x10 + + new_node = GCRARCNode(offset, file_bytes, string_table_bytes) + new_node.get_entries( + self.data_header.file_entry_offset, file_bytes, string_table_bytes + ) + + self.nodes.append(new_node) + + # Now, organize the nodes into a hierarchy. + for n in self.nodes: + for e in n.entries: + # We're only looking for directory nodes, so ignore files. + if e.flags & int(GCRARCFlags.IS_FILE) != 0x00: + continue + + if e.name == "." or e.name == "..": + continue + + # This is the node that the current entry corresponds to. + dir_node = self.nodes[e.data_offset] + + # Set up hierarchy relationship. + dir_node.parent = n + n.children.append(dir_node) + + def emit(self, file_bytes): + assert options.opts.filesystem_path is not None + + rel_path = self.file_path.relative_to(options.opts.filesystem_path / "files") + arc_root_path = options.opts.asset_path / rel_path.with_suffix("") + + self.nodes[0].emit_to_filesystem_recursive( + arc_root_path, self.file_data_offset, file_bytes + ) + self.emit_config(arc_root_path) + + def emit_config(self, config_path: Path): + lines = [] + + lines.append(f'name: "{self.file_path.name}"\n') + + if self.compression != "none": + lines.append(f"compression: {self.compression}\n") + + lines.append(f"next_file_id: 0x{self.data_header.next_free_file_id:04X}\n") + lines.append( + f"sync_file_ids_to_indices: {self.data_header.sync_file_ids_to_indices}\n" + ) + + root_node = self.nodes[0] + + lines.append("root_dir:\n") + lines.append(f' res_type: "{root_node.resource_type}"\n') + lines.append(f' name: "{root_node.name}"\n') + + if len(root_node.entries) != 0: + lines.append(" entries:\n") + for e in root_node.entries: + entry_config = e.emit_config(2) + if entry_config != None: + lines.extend(entry_config) + + if len(root_node.children) != 0: + lines.append(" subdirs:\n") + for n in root_node.children: + node_config = n.emit_config(2) + if node_config != None: + lines.extend(node_config) + + with open(config_path / "arcinfo.yaml", "w", newline="\n") as f: + f.writelines(lines) + + +class GCRARCDataHeader: + def __init__(self, offset, file_bytes): + self.node_count = struct.unpack_from(">I", file_bytes, offset + 0x0000)[0] + self.node_offset = ( + struct.unpack_from(">I", file_bytes, offset + 0x0004)[0] + 0x0020 + ) + + self.file_entry_count = struct.unpack_from(">I", file_bytes, offset + 0x0008)[0] + self.file_entry_offset = ( + struct.unpack_from(">I", file_bytes, offset + 0x000C)[0] + 0x0020 + ) + + self.string_table_size = struct.unpack_from(">I", file_bytes, offset + 0x0010)[ + 0 + ] + self.string_table_offset = ( + struct.unpack_from(">I", file_bytes, offset + 0x0014)[0] + 0x0020 + ) + + self.next_free_file_id = struct.unpack_from(">H", file_bytes, offset + 0x0018)[ + 0 + ] + self.sync_file_ids_to_indices = bool(file_bytes[offset + 0x001A]) + + +class GCRARCNode: + def __init__(self, offset, file_bytes, string_table_bytes): + self.resource_type = file_bytes[offset + 0x0000 : offset + 0x0004].decode( + "utf-8" + ) + self.name_offset = struct.unpack_from(">I", file_bytes, offset + 0x0004)[0] + self.name_hash = struct.unpack_from(">H", file_bytes, offset + 0x0008)[0] + self.file_entry_count = struct.unpack_from(">H", file_bytes, offset + 0x000A)[0] + self.first_file_entry_index = struct.unpack_from( + ">I", file_bytes, offset + 0x000C + )[0] + + self.name = read_string_from_bytes(self.name_offset, string_table_bytes) + self.entries = [] + + self.parent: Optional[GCRARCNode] = None + self.children = [] + + def get_entries(self, file_entry_offset, file_bytes, string_table_bytes): + for i in range(self.file_entry_count): + entry_offset = file_entry_offset + (self.first_file_entry_index + i) * 0x14 + + new_entry = GCRARCFileEntry(entry_offset, file_bytes, string_table_bytes) + new_entry.parent_node = self + + self.entries.append(new_entry) + + def emit_to_filesystem_recursive( + self, root_path: Path, file_data_offset, file_bytes + ): + dir_path = root_path / self.get_full_directory_path() + dir_path.mkdir(parents=True, exist_ok=True) + + for n in self.children: + n.emit_to_filesystem_recursive(root_path, file_data_offset, file_bytes) + + for e in self.entries: + e.emit_to_filesystem(root_path, file_data_offset, file_bytes) + + def emit_config(self, level): + lines = [] + + lines.append(" " * level + f'- res_type: "{self.resource_type}"\n') + lines.append(" " * level + f' name: "{self.name}"\n') + + if len(self.entries) != 0: + lines.append(" " * level + " entries:\n") + for e in self.entries: + entry_config = e.emit_config(level + 1) + if entry_config != None: + lines.extend(entry_config) + + if len(self.children) != 0: + lines.append(" " * level + " subdirs:\n") + for n in self.children: + node_config = n.emit_config(level + 1) + if node_config != None: + lines.extend(node_config) + + return lines + + def print_recursive(self, level): + print((" " * level) + self.name) + + for n in self.children: + n.print_recursive(level + 1) + + def get_full_directory_path(self): + path_components: List[str] = [] + + node: Optional[GCRARCNode] = self + while node is not None: + path_components.insert(0, node.name) + node = node.parent + + return Path(*path_components) + + +class GCRARCFileEntry: + def __init__(self, offset, file_bytes, string_table_bytes): + self.file_id = struct.unpack_from(">H", file_bytes, offset + 0x0000)[0] + self.name_hash = struct.unpack_from(">H", file_bytes, offset + 0x0002)[0] + self.flags = file_bytes[offset + 0x0004] + self.name_offset = ( + struct.unpack_from(">I", file_bytes, offset + 0x0004)[0] & 0x00FFFFFF + ) + self.data_offset = struct.unpack_from(">I", file_bytes, offset + 0x0008)[0] + self.data_size = struct.unpack_from(">I", file_bytes, offset + 0x000C)[0] + + self.name = read_string_from_bytes(self.name_offset, string_table_bytes) + self.parent_node: Optional[GCRARCNode] = None + + def emit_to_filesystem(self, dir_path: Path, file_data_offset, file_bytes): + if self.flags & int(GCRARCFlags.IS_DIR) != 0x00: + return + + file_path = dir_path / self.get_full_file_path() + + file_data = file_bytes[ + file_data_offset + + self.data_offset : file_data_offset + + self.data_offset + + self.data_size + ] + with open(file_path, "wb") as f: + f.write(file_data) + + def emit_config(self, level): + if self.flags & int(GCRARCFlags.IS_DIR) != 0x00: + return + + lines = [] + + lines.append(" " * level + f' - name: "{self.name}"\n') + lines.append(" " * level + f" file_id: 0x{self.file_id:04X}\n") + + if self.flags & int(GCRARCFlags.IS_COMPRESSED) != 0x00: + if self.flags & int(GCRARCFlags.IS_YAZ0_COMPRESSED) != 0x00: + lines.append(" " * level + f" compression: yaz0\n") + else: + lines.append(" " * level + f" compression: yay0\n") + + if self.flags & int(GCRARCFlags.PRELOAD_TO_MRAM) == 0x00: + if self.flags & int(GCRARCFlags.PRELOAD_TO_ARAM) != 0x00: + lines.append(" " * level + f" preload_type: aram\n") + else: + lines.append(" " * level + f" preload_type: dvd\n") + + return lines + + def get_full_file_path(self): + path_components = [self.name] + + node = self.parent_node + while node is not None: + path_components.insert(0, node.name) + node = node.parent + + return Path("/".join(path_components)) + + +class GCRARCFlags(IntEnum): + IS_FILE = 0x01 + IS_DIR = 0x02 + IS_COMPRESSED = 0x04 + PRELOAD_TO_MRAM = 0x10 + PRELOAD_TO_ARAM = 0x20 + LOAD_FROM_DVD = 0x40 + IS_YAZ0_COMPRESSED = 0x80 diff --git a/tools/splat/segtypes/gc/relheader.py b/tools/splat/segtypes/gc/relheader.py new file mode 100644 index 00000000..e92fc636 --- /dev/null +++ b/tools/splat/segtypes/gc/relheader.py @@ -0,0 +1,114 @@ +from util import options + +from segtypes.common.header import CommonSegHeader + + +class RelSegHeader(CommonSegHeader): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if isinstance(self.yaml, dict): + self.version: int = self.yaml.get("version", 0) + + def parse_header(self, rel_bytes): + header_lines = [] + header_lines.append(".section .data\n") + + # Module ID + header_lines.append(self.get_line("word", rel_bytes[0x00:0x04], "Module ID")) + + # Next module (filled at runtime) + header_lines.append(self.get_line("word", rel_bytes[0x04:0x08], "Next Module")) + # Last module (filled at runtime) + header_lines.append(self.get_line("word", rel_bytes[0x08:0x0C], "Last Module")) + + # Section count + header_lines.append( + self.get_line("word", rel_bytes[0x0C:0x10], "Section Count") + ) + # Section table offset + header_lines.append( + self.get_line("word", rel_bytes[0x10:0x14], "Section Table Offset") + ) + + # Module name offset (might be null) + header_lines.append( + self.get_line("word", rel_bytes[0x14:0x18], "Module Name Offset") + ) + # Module name length + header_lines.append( + self.get_line("word", rel_bytes[0x18:0x1C], "Module Name Length") + ) + + # REL format version + header_lines.append( + self.get_line("word", rel_bytes[0x1C:0x20], "REL Format Version") + ) + + # BSS size + header_lines.append(self.get_line("word", rel_bytes[0x20:0x24], "BSS Size")) + + # Relocation table offset + header_lines.append( + self.get_line("word", rel_bytes[0x24:0x28], "Relocation Table Offset") + ) + # Import table offset + header_lines.append( + self.get_line("word", rel_bytes[0x28:0x2C], "Import Table Offset") + ) + # Import table size + header_lines.append( + self.get_line("word", rel_bytes[0x2C:0x30], "Import Table Size") + ) + + # Prolog section index + header_lines.append( + self.get_line("byte", rel_bytes[0x30:0x31], "Prolog Section Index") + ) + # Epilog section index + header_lines.append( + self.get_line("byte", rel_bytes[0x31:0x32], "Epilog Section Index") + ) + # Unresolved section index + header_lines.append( + self.get_line("byte", rel_bytes[0x32:0x33], "Unresolved Section Index") + ) + # BSS section index (filled at runtime) + header_lines.append( + self.get_line("byte", rel_bytes[0x33:0x34], "BSS Section Index") + ) + + # Prolog function offset + header_lines.append( + self.get_line("word", rel_bytes[0x34:0x38], "Prolog Function Offset") + ) + # Epilog function offset + header_lines.append( + self.get_line("word", rel_bytes[0x38:0x3C], "Epilog Function Offset") + ) + # Unresolved function offset + header_lines.append( + self.get_line("word", rel_bytes[0x3C:0x40], "Unresolved Function Offset") + ) + + # Version 1 is only 0x40 bytes long + if self.version <= 1: + return header_lines + + # Alignment constraint + header_lines.append( + self.get_line("word", rel_bytes[0x40:0x44], "Alignment Constraint") + ) + # BSS alignment constraint + header_lines.append( + self.get_line("word", rel_bytes[0x44:0x48], "BSS Alignment Constraint") + ) + + # Version 2 is only 0x48 bytes long + if self.version <= 2: + return header_lines + + # Fix size + header_lines.append(self.get_line("word", rel_bytes[0x48:0x4C], "Fix Size")) + + return header_lines diff --git a/tools/splat/segtypes/gc/segment.py b/tools/splat/segtypes/gc/segment.py new file mode 100644 index 00000000..8e4d9bca --- /dev/null +++ b/tools/splat/segtypes/gc/segment.py @@ -0,0 +1,5 @@ +from segtypes.segment import Segment + + +class GCSegment(Segment): + pass diff --git a/tools/splat/segtypes/linker_entry.py b/tools/splat/segtypes/linker_entry.py new file mode 100644 index 00000000..3750ae66 --- /dev/null +++ b/tools/splat/segtypes/linker_entry.py @@ -0,0 +1,399 @@ +import os +import re +from dataclasses import dataclass +from functools import lru_cache +from pathlib import Path +from typing import Dict, List, OrderedDict, Set, Tuple, Union +from segtypes.n64.palette import N64SegPalette + +from util import options + +from segtypes.segment import Segment +from util.symbols import to_cname + + +# clean 'foo/../bar' to 'bar' +@lru_cache(maxsize=None) +def clean_up_path(path: Path) -> Path: + path_resolved = path.resolve() + base_resolved = options.opts.base_path.resolve() + try: + return path_resolved.relative_to(base_resolved) + except ValueError: + pass + + # If the path wasn't relative to the splat file, use the working directory instead + cwd = Path(os.getcwd()) + try: + return path_resolved.relative_to(cwd) + except ValueError: + pass + + # If it wasn't relative to that too, then just return the path as-is + return path + + +def path_to_object_path(path: Path) -> Path: + path = clean_up_path(path) + if options.opts.use_o_as_suffix: + full_suffix = ".o" + else: + full_suffix = path.suffix + ".o" + return clean_up_path(options.opts.build_path / path.with_suffix(full_suffix)) + + +def write_file_if_different(path: Path, new_content: str): + if path.exists(): + old_content = path.read_text() + else: + old_content = "" + + if old_content != new_content: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w") as f: + f.write(new_content) + + +def segment_cname(segment: Segment) -> str: + name = segment.name + if segment.parent: + name = segment.parent.name + "_" + name + + if isinstance(segment, N64SegPalette): + name += "_pal" + + return to_cname(name) + + +def get_segment_vram_end_symbol_name(segment: Segment) -> str: + return segment_cname(segment) + "_VRAM_END" + + +@dataclass +class LinkerSection: + name: str + started: bool = False + ended: bool = False + + @property + def section_type(self) -> str: + if self.name == ".rdata": + return ".rodata" + return self.name + + +class LinkerEntry: + def __init__( + self, segment: Segment, src_paths: List[Path], object_path: Path, section: str + ): + self.segment = segment + self.src_paths = [clean_up_path(p) for p in src_paths] + self.section = section + if self.section == "linker" or self.section == "linker_offset": + self.object_path = None + elif self.segment.type == "lib": + self.object_path = object_path + else: + self.object_path = path_to_object_path(object_path) + + @property + def section_type(self) -> str: + if self.section == ".rdata": + return ".rodata" + else: + return self.section + + +class LinkerWriter: + def __init__(self): + self.linker_discard_section: bool = options.opts.ld_discard_section + # Used to store all the linker entries - build tools may want this information + self.entries: List[LinkerEntry] = [] + + self.buffer: List[str] = [] + self.symbols: List[str] = [] + + self._indent_level = 0 + + self._writeln("SECTIONS") + self._begin_block() + self._writeln("__romPos = 0;") + + if options.opts.gp is not None: + self._writeln("_gp = " + f"0x{options.opts.gp:X};") + + # Write a series of statements which compute a symbol that represents the highest address among a list of segments' end addresses + def write_max_vram_end_sym(self, symbol: str, overlays: List[Segment]): + for segment in overlays: + if segment == overlays[0]: + self._writeln( + f"{symbol} = {get_segment_vram_end_symbol_name(segment)};" + ) + else: + self._writeln( + f"{symbol} = MAX({symbol}, {get_segment_vram_end_symbol_name(segment)});" + ) + + # Adds all the entries of a segment to the linker script buffer + def add(self, segment: Segment, max_vram_syms: List[Tuple[str, List[Segment]]]): + entries = segment.get_linker_entries() + self.entries.extend(entries) + + seg_name = segment_cname(segment) + + for sym, segs in max_vram_syms: + self.write_max_vram_end_sym(sym, segs) + + section_labels: OrderedDict[str, LinkerSection] = OrderedDict( + { + l: LinkerSection(l) + for l in options.opts.section_order + if l in options.opts.ld_section_labels + } + ) + + # Start the first linker section + + self._write_symbol(f"{seg_name}_ROM_START", "__romPos") + + if entries[0].section_type == ".bss": + self._begin_bss_segment(segment, is_first=True) + self._write_symbol(f"{seg_name}_BSS_START", ".") + if ".bss" in section_labels: + section_labels[".bss"].started = True + else: + self._begin_segment(segment) + + last_seen_sections: Dict[LinkerEntry, str] = {} + + # Find where sections are last seen + for entry in reversed(entries): + if ( + entry.section_type in section_labels.keys() + and entry.section_type not in last_seen_sections.values() + ): + last_seen_sections[entry] = entry.section_type + + cur_section = None + prev_section = None + for entry in entries: + entering_bss = False + leaving_bss = False + cur_section = entry.section_type + + if cur_section == "linker_offset": + self._write_symbol(f"{segment_cname(entry.segment)}_OFFSET", ".") + continue + + for i, section in enumerate(section_labels.values()): + # If we haven't seen this section yet + if not section.started and section.section_type == entry.section_type: + if prev_section == ".bss": + leaving_bss = True + elif cur_section == ".bss": + entering_bss = True + + if not ( + entering_bss or leaving_bss + ): # Don't write a START symbol if we are about to end the section + self._write_symbol( + f"{seg_name}{entry.section_type.upper()}_START", "." + ) + section_labels[entry.section_type].started = True + + if ( + entry.object_path + and cur_section == ".data" + and entry.segment.type != "lib" + ): + path_cname = re.sub( + r"[^0-9a-zA-Z_]", + "_", + str(entry.segment.dir / entry.segment.name) + + ".".join(entry.object_path.suffixes[:-1]), + ) + self._write_symbol(path_cname, ".") + + wildcard = "*" if options.opts.ld_wildcard_sections else "" + + # Create new linker section for BSS + if entering_bss or leaving_bss: + # If this is the last entry of its type, add the END marker for the section we're ending + if ( + entry in last_seen_sections + and section_labels[entry.section_type].started + ): + seg_name_section = to_cname( + f"{seg_name}{last_seen_sections[entry].upper()}" + ) + self._write_symbol(f"{seg_name_section}_END", ".") + self._write_symbol( + f"{seg_name_section}_SIZE", + f"ABSOLUTE({seg_name_section}_END - {seg_name_section}_START)", + ) + section_labels[last_seen_sections[entry]].ended = True + + self._end_block() + + if entering_bss: + self._begin_bss_segment(segment) + else: + self._begin_segment(segment) + + self._write_symbol(f"{seg_name}{entry.section_type.upper()}_START", ".") + section_labels[cur_section].started = True + + # Write THIS linker entry + self._writeln(f"{entry.object_path}({entry.section}{wildcard});") + else: + # Write THIS linker entry + if entry.section == ".bss" and entry.segment.bss_contains_common: + self._writeln(f"{entry.object_path}(.bss COMMON .scommon);") + else: + self._writeln(f"{entry.object_path}({entry.section}{wildcard});") + + # If this is the last entry of its type, add the END marker for the section we're ending + if entry in last_seen_sections: + seg_name_section = to_cname(f"{seg_name}{cur_section.upper()}") + self._write_symbol(f"{seg_name_section}_END", ".") + self._write_symbol( + f"{seg_name_section}_SIZE", + f"ABSOLUTE({seg_name_section}_END - {seg_name_section}_START)", + ) + section_labels[cur_section].ended = True + + prev_section = cur_section + + # End all un-ended sections + for section in section_labels.values(): + if section.started and not section.ended: + seg_name_section = to_cname(f"{seg_name}{section.name.upper()}") + self._write_symbol(f"{seg_name_section}_END", ".") + self._write_symbol( + f"{seg_name_section}_SIZE", + f"ABSOLUTE({seg_name_section}_END - {seg_name_section}_START)", + ) + + all_bss = all(e.section == ".bss" for e in entries) + self._end_segment(segment, all_bss) + + def save_linker_script(self): + if self.linker_discard_section: + self._writeln("/DISCARD/ :") + self._begin_block() + self._writeln("*(*);") + self._end_block() + + self._end_block() # SECTIONS + + assert self._indent_level == 0 + + write_file_if_different( + options.opts.ld_script_path, "\n".join(self.buffer) + "\n" + ) + + def save_symbol_header(self): + path = options.opts.ld_symbol_header_path + + if path: + write_file_if_different( + path, + "#ifndef _HEADER_SYMBOLS_H_\n" + "#define _HEADER_SYMBOLS_H_\n" + "\n" + '#include "common.h"\n' + "\n" + + "".join(f"extern Addr {symbol};\n" for symbol in self.symbols) + + "\n" + "#endif\n", + ) + + def _writeln(self, line: str): + if len(line) == 0: + self.buffer.append(line) + else: + self.buffer.append(" " * self._indent_level + line) + + def _begin_block(self): + self._writeln("{") + self._indent_level += 1 + + def _end_block(self): + self._indent_level -= 1 + self._writeln("}") + + def _write_symbol(self, symbol: str, value: Union[str, int]): + symbol = to_cname(symbol) + + if isinstance(value, int): + value = f"0x{value:X}" + + self._writeln(f"{symbol} = {value};") + + if symbol not in self.symbols: + self.symbols.append(symbol) + + def _begin_segment(self, segment: Segment): + if options.opts.ld_use_follows and segment.vram_of_symbol: + vram_str = segment.vram_of_symbol + " " + else: + vram_str = ( + f"0x{segment.vram_start:X} " + if isinstance(segment.vram_start, int) + else "" + ) + + name = segment_cname(segment) + + self._write_symbol(f"{name}_VRAM", f"ADDR(.{name})") + + line = f".{name} {vram_str}: AT({name}_ROM_START)" + if segment.subalign != None: + line += f" SUBALIGN({segment.subalign})" + + self._writeln(line) + self._begin_block() + + def _begin_bss_segment(self, segment: Segment, is_first: bool = False): + if options.opts.ld_use_follows and segment.vram_of_symbol: + vram_str = segment.vram_of_symbol + " " + else: + vram_str = ( + f"0x{segment.vram_start:X} " + if isinstance(segment.vram_start, int) + else "" + ) + + name = segment_cname(segment) + "_bss" + + self._write_symbol(f"{name}_VRAM", f"ADDR(.{name})") + + if is_first: + addr_str = vram_str + "(NOLOAD)" + else: + addr_str = "(NOLOAD)" + + line = f".{name} {addr_str} :" + if segment.subalign != None: + line += f" SUBALIGN({segment.subalign})" + + self._writeln(line) + self._begin_block() + + def _end_segment(self, segment: Segment, all_bss=False): + self._end_block() + + name = segment_cname(segment) + + if not all_bss: + self._writeln(f"__romPos += SIZEOF(.{name});") + + # Align directive + if segment.align: + self._writeln(f"__romPos = ALIGN(__romPos, {segment.align});") + + self._write_symbol(f"{name}_ROM_END", "__romPos") + + self._write_symbol(get_segment_vram_end_symbol_name(segment), ".") + + self._writeln("") diff --git a/tools/splat/segtypes/n64/__init__.py b/tools/splat/segtypes/n64/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/splat/segtypes/n64/asm.py b/tools/splat/segtypes/n64/asm.py new file mode 100644 index 00000000..4b93b2c3 --- /dev/null +++ b/tools/splat/segtypes/n64/asm.py @@ -0,0 +1,28 @@ +from util import options + +from segtypes.common.asm import CommonSegAsm + + +class N64SegAsm(CommonSegAsm): + @staticmethod + def get_file_header(): + ret = [] + + ret.append('.include "macro.inc"') + ret.append("") + ret.append("/* assembler directives */") + ret.append(".set noat /* allow manual use of $at */") + ret.append(".set noreorder /* don't insert nops after branches */") + if options.opts.add_set_gp_64: + ret.append( + ".set gp=64 /* allow use of 64-bit general purpose registers */" + ) + ret.append("") + preamble = options.opts.generated_s_preamble + if preamble: + ret.append(preamble) + ret.append("") + ret.append('.section .text, "ax"') + ret.append("") + + return ret diff --git a/tools/splat/segtypes/n64/ci.py b/tools/splat/segtypes/n64/ci.py new file mode 100644 index 00000000..436908fd --- /dev/null +++ b/tools/splat/segtypes/n64/ci.py @@ -0,0 +1,39 @@ +from typing import Optional, TYPE_CHECKING + +from util import log + +from segtypes.n64.img import N64SegImg + +if TYPE_CHECKING: + from segtypes.n64.palette import N64SegPalette + + +# Base class for CI4/CI8 +class N64SegCi(N64SegImg): + def parse_palette_name(self, yaml, args) -> str: + ret = self.name + if isinstance(yaml, dict): + if "palette" in yaml: + ret = yaml["palette"] + elif len(args) > 2: + ret = args[2] + + return ret + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.palette: "Optional[N64SegPalette]" = None + self.palette_name = self.parse_palette_name(self.yaml, self.args) + + def split(self, rom_bytes): + if self.palette is None: + # TODO: output with blank palette + log.error( + f"no palette sibling segment exists\n(hint: add a segment with type 'palette' and name '{self.name}')" + ) + assert self.palette is not None + self.palette.extract = False + self.n64img.palette = self.palette.parse_palette(rom_bytes) + + super().split(rom_bytes) diff --git a/tools/splat/segtypes/n64/ci4.py b/tools/splat/segtypes/n64/ci4.py new file mode 100644 index 00000000..83258816 --- /dev/null +++ b/tools/splat/segtypes/n64/ci4.py @@ -0,0 +1,8 @@ +import n64img.image + +from segtypes.n64.ci import N64SegCi + + +class N64SegCi4(N64SegCi): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs, img_cls=n64img.image.CI4) diff --git a/tools/splat/segtypes/n64/ci8.py b/tools/splat/segtypes/n64/ci8.py new file mode 100644 index 00000000..dbf66cdf --- /dev/null +++ b/tools/splat/segtypes/n64/ci8.py @@ -0,0 +1,8 @@ +import n64img.image + +from segtypes.n64.ci import N64SegCi + + +class N64SegCi8(N64SegCi): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs, img_cls=n64img.image.CI8) diff --git a/tools/splat/segtypes/n64/gfx.py b/tools/splat/segtypes/n64/gfx.py new file mode 100644 index 00000000..62d09659 --- /dev/null +++ b/tools/splat/segtypes/n64/gfx.py @@ -0,0 +1,260 @@ +""" +N64 f3dex display list splitter +Dumps out Gfx[] as a .inc.c file. +""" + +import re +from typing import Optional + +from pathlib import Path + +from pygfxd import ( + gfxd_buffer_to_string, + gfxd_cimg_callback, + gfxd_dl_callback, + gfxd_endian, + gfxd_execute, + gfxd_input_buffer, + gfxd_light_callback, + gfxd_lookat_callback, + gfxd_macro_dflt, + gfxd_macro_fn, + gfxd_mtx_callback, + gfxd_output_buffer, + gfxd_printf, + gfxd_puts, + gfxd_target, + gfxd_timg_callback, + gfxd_tlut_callback, + gfxd_vp_callback, + gfxd_vtx_callback, + gfxd_zimg_callback, + GfxdEndian, + gfxd_f3d, + gfxd_f3db, + gfxd_f3dex, + gfxd_f3dexb, + gfxd_f3dex2, +) + +from util import log, options +from util.log import error + +from segtypes.common.codesubsegment import CommonSegCodeSubsegment + +LIGHTS_RE = re.compile(r"\*\(Lightsn \*\)0x[0-9A-F]{8}") + + +class N64SegGfx(CommonSegCodeSubsegment): + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + ): + super().__init__( + rom_start, + rom_end, + type, + name, + vram_start, + args=args, + yaml=yaml, + ) + self.file_text = None + self.data_only = isinstance(yaml, dict) and yaml.get("data_only", False) + + def format_sym_name(self, sym) -> str: + return sym.name + + def get_linker_section(self) -> str: + return ".data" + + def out_path(self) -> Path: + return options.opts.asset_path / self.dir / f"{self.name}.gfx.inc.c" + + def scan(self, rom_bytes: bytes): + self.file_text = self.disassemble_data(rom_bytes) + + def get_gfxd_target(self): + opt = options.opts.gfx_ucode + + if opt == "f3d": + return gfxd_f3d + elif opt == "f3db": + return gfxd_f3db + elif opt == "f3dex": + return gfxd_f3dex + elif opt == "f3dexb": + return gfxd_f3dexb + elif opt == "f3dex2": + return gfxd_f3dex2 + else: + log.error(f"Unknown target {opt}") + + def tlut_handler(self, addr, idx, count): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def timg_handler(self, addr, fmt, size, width, height, pal): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def cimg_handler(self, addr, fmt, size, width): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def zimg_handler(self, addr): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def dl_handler(self, addr): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def mtx_handler(self, addr): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(f"&{self.format_sym_name(sym)}") + return 1 + + def lookat_handler(self, addr, count): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def light_handler(self, addr, count): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def vtx_handler(self, addr, count): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True, search_ranges=True + ) + index = int((addr - sym.vram_start) / 0x10) + gfxd_printf(f"&{self.format_sym_name(sym)}[{index}]") + return 1 + + def vp_handler(self, addr): + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + gfxd_printf(self.format_sym_name(sym)) + return 1 + + def macro_fn(self): + gfxd_puts(" ") + gfxd_macro_dflt() + gfxd_puts(",\n") + return 0 + + def disassemble_data(self, rom_bytes): + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + assert isinstance(self.vram_start, int) + + gfx_data = rom_bytes[self.rom_start : self.rom_end] + segment_length = len(gfx_data) + if (segment_length) % 8 != 0: + error( + f"Error: gfx segment {self.name} length ({segment_length}) is not a multiple of 8!" + ) + + out_str = "" if self.data_only else options.opts.generated_c_preamble + "\n\n" + + sym = self.create_symbol( + addr=self.vram_start, in_segment=True, type="data", define=True + ) + + gfxd_input_buffer(gfx_data) + + # TODO terrible guess at the size we'll need - improve this + outb = bytes([0] * segment_length * 100) + outbuf = gfxd_output_buffer(outb, len(outb)) + + gfxd_target(self.get_gfxd_target()) + gfxd_endian( + GfxdEndian.big if options.opts.endianness == "big" else GfxdEndian.little, 4 + ) + + # Callbacks + gfxd_macro_fn(self.macro_fn) + + gfxd_tlut_callback(self.tlut_handler) + gfxd_timg_callback(self.timg_handler) + gfxd_cimg_callback(self.cimg_handler) + gfxd_zimg_callback(self.zimg_handler) + gfxd_dl_callback(self.dl_handler) + gfxd_mtx_callback(self.mtx_handler) + gfxd_lookat_callback(self.lookat_handler) + gfxd_light_callback(self.light_handler) + # gfxd_seg_callback ? + gfxd_vtx_callback(self.vtx_handler) + gfxd_vp_callback(self.vp_handler) + # gfxd_uctext_callback ? + # gfxd_ucdata_callback ? + # gfxd_dram_callback ? + + gfxd_execute() + + if self.data_only: + out_str += gfxd_buffer_to_string(outbuf) + else: + out_str += "Gfx " + self.format_sym_name(sym) + "[] = {\n" + out_str += gfxd_buffer_to_string(outbuf) + out_str += "};\n" + + # Poor man's light fix until we get my libgfxd PR merged + def light_sub_func(match): + light = match.group(0) + addr = int(light[12:], 0) + sym = self.create_symbol( + addr=addr, in_segment=True, type="data", reference=True + ) + return self.format_sym_name(sym) + + out_str = re.sub(LIGHTS_RE, light_sub_func, out_str) + + return out_str + + def split(self, rom_bytes: bytes): + if self.file_text and self.out_path(): + self.out_path().parent.mkdir(parents=True, exist_ok=True) + + with open(self.out_path(), "w", newline="\n") as f: + f.write(self.file_text) + + def should_scan(self) -> bool: + return ( + options.opts.is_mode_active("gfx") + and self.rom_start is not None + and self.rom_end is not None + ) + + def should_split(self) -> bool: + return self.extract and options.opts.is_mode_active("gfx") diff --git a/tools/splat/segtypes/n64/hasm.py b/tools/splat/segtypes/n64/hasm.py new file mode 100644 index 00000000..18def923 --- /dev/null +++ b/tools/splat/segtypes/n64/hasm.py @@ -0,0 +1,28 @@ +from util import options + +from segtypes.common.hasm import CommonSegHasm + + +class N64SegHasm(CommonSegHasm): + @staticmethod + def get_file_header(): + ret = [] + + ret.append('.include "macro.inc"') + ret.append("") + ret.append("/* assembler directives */") + ret.append(".set noat /* allow manual use of $at */") + ret.append(".set noreorder /* don't insert nops after branches */") + if options.opts.add_set_gp_64: + ret.append( + ".set gp=64 /* allow use of 64-bit general purpose registers */" + ) + ret.append("") + preamble = options.opts.generated_s_preamble + if preamble: + ret.append(preamble) + ret.append("") + ret.append('.section .text, "ax"') + ret.append("") + + return ret diff --git a/tools/splat/segtypes/n64/header.py b/tools/splat/segtypes/n64/header.py new file mode 100644 index 00000000..96c59d5d --- /dev/null +++ b/tools/splat/segtypes/n64/header.py @@ -0,0 +1,50 @@ +from util import options + +from segtypes.common.header import CommonSegHeader + + +class N64SegHeader(CommonSegHeader): + def parse_header(self, rom_bytes): + encoding = options.opts.header_encoding + + header_lines = [] + header_lines.append(".section .data\n") + header_lines.append( + self.get_line("word", rom_bytes[0x00:0x04], "PI BSB Domain 1 register") + ) + header_lines.append( + self.get_line("word", rom_bytes[0x04:0x08], "Clockrate setting") + ) + header_lines.append( + self.get_line("word", rom_bytes[0x08:0x0C], "Entrypoint address") + ) + header_lines.append(self.get_line("word", rom_bytes[0x0C:0x10], "Revision")) + header_lines.append(self.get_line("word", rom_bytes[0x10:0x14], "Checksum 1")) + header_lines.append(self.get_line("word", rom_bytes[0x14:0x18], "Checksum 2")) + header_lines.append(self.get_line("word", rom_bytes[0x18:0x1C], "Unknown 1")) + header_lines.append(self.get_line("word", rom_bytes[0x1C:0x20], "Unknown 2")) + + if encoding != "word": + header_lines.append( + '.ascii "' + + rom_bytes[0x20:0x34].decode(encoding).strip().ljust(20) + + '" /* Internal name */' + ) + else: + for i in range(0x20, 0x34, 4): + header_lines.append( + self.get_line("word", rom_bytes[i : i + 4], "Internal name") + ) + + header_lines.append(self.get_line("word", rom_bytes[0x34:0x38], "Unknown 3")) + header_lines.append(self.get_line("word", rom_bytes[0x38:0x3C], "Cartridge")) + header_lines.append( + self.get_line("ascii", rom_bytes[0x3C:0x3E], "Cartridge ID") + ) + header_lines.append( + self.get_line("ascii", rom_bytes[0x3E:0x3F], "Country code") + ) + header_lines.append(self.get_line("byte", rom_bytes[0x3F:0x40], "Version")) + header_lines.append("") + + return header_lines diff --git a/tools/splat/segtypes/n64/i1.py b/tools/splat/segtypes/n64/i1.py new file mode 100644 index 00000000..c2930999 --- /dev/null +++ b/tools/splat/segtypes/n64/i1.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegI1(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.I1 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/i4.py b/tools/splat/segtypes/n64/i4.py new file mode 100644 index 00000000..16a68c59 --- /dev/null +++ b/tools/splat/segtypes/n64/i4.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegI4(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.I4 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/i8.py b/tools/splat/segtypes/n64/i8.py new file mode 100644 index 00000000..c2364f2b --- /dev/null +++ b/tools/splat/segtypes/n64/i8.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegI8(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.I8 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/ia16.py b/tools/splat/segtypes/n64/ia16.py new file mode 100644 index 00000000..f2884728 --- /dev/null +++ b/tools/splat/segtypes/n64/ia16.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegIa16(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.IA16 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/ia4.py b/tools/splat/segtypes/n64/ia4.py new file mode 100644 index 00000000..0eef15b3 --- /dev/null +++ b/tools/splat/segtypes/n64/ia4.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegIa4(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.IA4 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/ia8.py b/tools/splat/segtypes/n64/ia8.py new file mode 100644 index 00000000..186be5e1 --- /dev/null +++ b/tools/splat/segtypes/n64/ia8.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegIa8(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.IA8 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/img.py b/tools/splat/segtypes/n64/img.py new file mode 100644 index 00000000..7c4bf807 --- /dev/null +++ b/tools/splat/segtypes/n64/img.py @@ -0,0 +1,83 @@ +from pathlib import Path +from typing import Type, Optional + +from n64img.image import Image +from util import log, options + +from segtypes.n64.segment import N64Segment + + +class N64SegImg(N64Segment): + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + img_cls: Type[Image], + ): + super().__init__( + rom_start, + rom_end, + type, + name, + vram_start, + args=args, + yaml=yaml, + ) + + self.n64img: Image = img_cls(None, 0, 0) + + if isinstance(yaml, dict): + if self.extract: + self.width = yaml["width"] + self.height = yaml["height"] + + self.n64img.flip_h = bool(yaml.get("flip_x", False)) + self.n64img.flip_v = bool(yaml.get("flip_y", False)) + else: + if self.extract: + if len(yaml) < 5: + log.error( + f"Error: {self.name} is missing width and height parameters" + ) + self.width = yaml[3] + self.height = yaml[4] + + self.n64img.width = self.width + self.n64img.height = self.height + + self.check_len() + + def check_len(self) -> None: + if self.extract: + expected_len = int(self.n64img.size()) + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + assert isinstance(self.subalign, int) + actual_len = self.rom_end - self.rom_start + if actual_len > expected_len and actual_len - expected_len > self.subalign: + log.error( + f"Error: {self.name} should end at 0x{self.rom_start + expected_len:X}, but it ends at 0x{self.rom_end:X}\n(hint: add a 'bin' segment after it)" + ) + + def out_path(self) -> Path: + return options.opts.asset_path / self.dir / f"{self.name}.png" + + def should_split(self) -> bool: + return self.extract and options.opts.is_mode_active("img") + + def split(self, rom_bytes): + path = self.out_path() + path.parent.mkdir(parents=True, exist_ok=True) + + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + + self.n64img.data = rom_bytes[self.rom_start : self.rom_end] + self.n64img.write(path) + + self.log(f"Wrote {self.name} to {path}") diff --git a/tools/splat/segtypes/n64/ipl3.py b/tools/splat/segtypes/n64/ipl3.py new file mode 100644 index 00000000..6a76cb34 --- /dev/null +++ b/tools/splat/segtypes/n64/ipl3.py @@ -0,0 +1,9 @@ +from segtypes.common.code import CommonSegCode +from segtypes.common.hasm import CommonSegHasm + + +class N64SegIpl3(CommonSegHasm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.special_vram_segment = True diff --git a/tools/splat/segtypes/n64/linker_offset.py b/tools/splat/segtypes/n64/linker_offset.py new file mode 100644 index 00000000..ac4d9454 --- /dev/null +++ b/tools/splat/segtypes/n64/linker_offset.py @@ -0,0 +1,10 @@ +from pathlib import Path + +from segtypes.n64.segment import N64Segment + + +class N64SegLinker_offset(N64Segment): + def get_linker_entries(self): + from segtypes.linker_entry import LinkerEntry + + return [LinkerEntry(self, [], Path(self.name), "linker_offset")] diff --git a/tools/splat/segtypes/n64/mio0.py b/tools/splat/segtypes/n64/mio0.py new file mode 100644 index 00000000..5ad46355 --- /dev/null +++ b/tools/splat/segtypes/n64/mio0.py @@ -0,0 +1,10 @@ +from util.n64.Mio0decompress import Mio0Decompressor + +from segtypes.common.decompressor import CommonSegDecompressor + + +class N64SegMio0(CommonSegDecompressor): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.decompressor = Mio0Decompressor() + self.compression_type = "Mio0" diff --git a/tools/splat/segtypes/n64/palette.py b/tools/splat/segtypes/n64/palette.py new file mode 100644 index 00000000..eabd472b --- /dev/null +++ b/tools/splat/segtypes/n64/palette.py @@ -0,0 +1,99 @@ +from itertools import zip_longest +from pathlib import Path +from typing import List, Optional, Tuple, TYPE_CHECKING + +from util import log, options +from util.color import unpack_color + +from segtypes.n64.segment import N64Segment + +if TYPE_CHECKING: + from segtypes.n64.ci import N64SegCi as Raster + + +def iter_in_groups(iterable, n, fillvalue=None): + args = [iter(iterable)] * n + return zip_longest(*args, fillvalue=fillvalue) + + +class N64SegPalette(N64Segment): + require_unique_name = False + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.raster: "Optional[Raster]" = None + + # palette segments must be named as one of the following: + # 1) same as the relevant raster segment name (max. 1 palette) + # 2) relevant raster segment name + "." + unique palette name + # 3) unique, referencing the relevant raster segment using `raster_name` + self.raster_name = ( + self.yaml.get("raster_name", self.name.split(".")[0]) + if isinstance(self.yaml, dict) + else self.name.split(".")[0] + ) + + if self.extract: + if self.rom_end is None: + log.error( + f"segment {self.name} needs to know where it ends; add a position marker [0xDEADBEEF] after it" + ) + + if self.max_length() and isinstance(self.rom_end, int): + expected_len = int(self.max_length()) + assert isinstance(self.rom_end, int) + assert isinstance(self.rom_start, int) + assert isinstance(self.subalign, int) + actual_len = self.rom_end - self.rom_start + if ( + actual_len > expected_len + and actual_len - expected_len > self.subalign + ): + log.error( + f"Error: {self.name} should end at 0x{self.rom_start + expected_len:X}, but it ends at 0x{self.rom_end:X}\n(hint: add a 'bin' segment after it)" + ) + + def split(self, rom_bytes): + if self.raster is None: + # TODO: output with no raster + log.error(f"orphaned palette segment: {self.name} lacks ci4/ci8 sibling") + + assert self.raster is not None + self.raster.n64img.palette = self.parse_palette(rom_bytes) # type: ignore + + self.raster.n64img.write(self.out_path()) + self.raster.extract = False + + def parse_palette(self, rom_bytes) -> List[Tuple[int, int, int, int]]: + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + + data = rom_bytes[self.rom_start : self.rom_end] + palette = [] + + for a, b in iter_in_groups(data, 2): + palette.append(unpack_color([a, b])) + + return palette + + def max_length(self): + return 256 * 2 + + def out_path(self) -> Path: + return options.opts.asset_path / self.dir / f"{self.name}.png" + + def should_split(self) -> bool: + return self.extract and options.opts.is_mode_active("img") + + def get_linker_entries(self): + from segtypes.linker_entry import LinkerEntry + + return [ + LinkerEntry( + self, + [options.opts.asset_path / self.dir / f"{self.name}.png"], + options.opts.asset_path / self.dir / f"{self.name}.pal", + self.get_linker_section(), + ) + ] diff --git a/tools/splat/segtypes/n64/rgba16.py b/tools/splat/segtypes/n64/rgba16.py new file mode 100644 index 00000000..4b6f4fde --- /dev/null +++ b/tools/splat/segtypes/n64/rgba16.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegRgba16(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.RGBA16 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/rgba32.py b/tools/splat/segtypes/n64/rgba32.py new file mode 100644 index 00000000..ae3d5383 --- /dev/null +++ b/tools/splat/segtypes/n64/rgba32.py @@ -0,0 +1,9 @@ +import n64img.image + +from segtypes.n64.img import N64SegImg + + +class N64SegRgba32(N64SegImg): + def __init__(self, *args, **kwargs): + kwargs["img_cls"] = n64img.image.RGBA32 + super().__init__(*args, **kwargs) diff --git a/tools/splat/segtypes/n64/rsp.py b/tools/splat/segtypes/n64/rsp.py new file mode 100644 index 00000000..f69123a4 --- /dev/null +++ b/tools/splat/segtypes/n64/rsp.py @@ -0,0 +1,10 @@ +import rabbitizer + +from segtypes.common.hasm import CommonSegHasm + + +class N64SegRsp(CommonSegHasm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.instr_category = rabbitizer.InstrCategory.RSP diff --git a/tools/splat/segtypes/n64/segment.py b/tools/splat/segtypes/n64/segment.py new file mode 100644 index 00000000..8f9c3ccc --- /dev/null +++ b/tools/splat/segtypes/n64/segment.py @@ -0,0 +1,5 @@ +from segtypes.segment import Segment + + +class N64Segment(Segment): + pass diff --git a/tools/splat/segtypes/n64/vtx.py b/tools/splat/segtypes/n64/vtx.py new file mode 100644 index 00000000..8d961b29 --- /dev/null +++ b/tools/splat/segtypes/n64/vtx.py @@ -0,0 +1,106 @@ +""" +N64 Vtx struct splitter +Dumps out Vtx as a .inc.c file. + +Originally written by Mark Street (https://github.com/mkst) +""" + +import struct +from pathlib import Path +from typing import Optional + +from util import options, log + +from segtypes.common.codesubsegment import CommonSegCodeSubsegment + + +class N64SegVtx(CommonSegCodeSubsegment): + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + ): + super().__init__( + rom_start, + rom_end, + type, + name, + vram_start, + args=args, + yaml=yaml, + ) + self.file_text = None + self.data_only = isinstance(yaml, dict) and yaml.get("data_only", False) + + def format_sym_name(self, sym) -> str: + return sym.name + + def get_linker_section(self) -> str: + return ".data" + + def out_path(self) -> Path: + return options.opts.asset_path / self.dir / f"{self.name}.vtx.inc.c" + + def scan(self, rom_bytes: bytes): + self.file_text = self.disassemble_data(rom_bytes) + + def disassemble_data(self, rom_bytes): + assert isinstance(self.rom_start, int) + assert isinstance(self.rom_end, int) + assert isinstance(self.vram_start, int) + + vertex_data = rom_bytes[self.rom_start : self.rom_end] + segment_length = len(vertex_data) + if (segment_length) % 16 != 0: + log.error( + f"Error: Vtx segment {self.name} length ({segment_length}) is not a multiple of 16!" + ) + + lines = [] + if not self.data_only: + lines.append(options.opts.generated_c_preamble) + lines.append("") + + vertex_count = segment_length // 16 + sym = self.create_symbol( + addr=self.vram_start, in_segment=True, type="data", define=True + ) + + if not self.data_only: + lines.append(f"Vtx {self.format_sym_name(sym)}[{vertex_count}] = {{") + + for vtx in struct.iter_unpack(">hhhHhhBBBB", vertex_data): + x, y, z, flg, t, c, r, g, b, a = vtx + vtx_string = f" {{{{{{ {x:5}, {y:5}, {z:5} }}, {flg}, {{ {t:5}, {c:5} }}, {{ {r:3}, {g:3}, {b:3}, {a:3} }}}}}}," + if flg != 0: + self.warn(f"Non-zero flag found in vertex data {self.name}!") + lines.append(vtx_string) + + if not self.data_only: + lines.append("};") + + # enforce newline at end of file + lines.append("") + return "\n".join(lines) + + def split(self, rom_bytes: bytes): + if self.file_text and self.out_path(): + self.out_path().parent.mkdir(parents=True, exist_ok=True) + + with open(self.out_path(), "w", newline="\n") as f: + f.write(self.file_text) + + def should_scan(self) -> bool: + return ( + options.opts.is_mode_active("vtx") + and self.rom_start is not None + and self.rom_end is not None + ) + + def should_split(self) -> bool: + return self.extract and options.opts.is_mode_active("vtx") diff --git a/tools/splat/segtypes/n64/yay0.py b/tools/splat/segtypes/n64/yay0.py new file mode 100644 index 00000000..210f7611 --- /dev/null +++ b/tools/splat/segtypes/n64/yay0.py @@ -0,0 +1,10 @@ +from util.n64.Yay0decompress import Yay0Decompressor + +from segtypes.common.decompressor import CommonSegDecompressor + + +class N64SegYay0(CommonSegDecompressor): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.decompressor = Yay0Decompressor() + self.compression_type = "Yay0" diff --git a/tools/splat/segtypes/psx/__init__.py b/tools/splat/segtypes/psx/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/splat/segtypes/psx/asm.py b/tools/splat/segtypes/psx/asm.py new file mode 100644 index 00000000..2e9ff5ea --- /dev/null +++ b/tools/splat/segtypes/psx/asm.py @@ -0,0 +1,23 @@ +from util import options + +from segtypes.common.asm import CommonSegAsm + + +class PsxSegAsm(CommonSegAsm): + @staticmethod + def get_file_header(): + ret = [] + + ret.append('.include "macro.inc"') + ret.append("") + ret.append(".set noat") + ret.append(".set noreorder") + ret.append("") + preamble = options.opts.generated_s_preamble + if preamble: + ret.append(preamble) + ret.append("") + ret.append('.section .text, "ax"') + ret.append("") + + return ret diff --git a/tools/splat/segtypes/psx/header.py b/tools/splat/segtypes/psx/header.py new file mode 100644 index 00000000..aeda3ee2 --- /dev/null +++ b/tools/splat/segtypes/psx/header.py @@ -0,0 +1,61 @@ +from segtypes.common.header import CommonSegHeader + + +class PsxSegHeader(CommonSegHeader): + # little endian so reverse words, TODO: use struct.unpack(" Optional[int]: + if isinstance(segment, dict) and "vram" in segment: + return int(segment["vram"]) + else: + return None + + +def parse_segment_align(segment: Union[dict, list]) -> Optional[int]: + if isinstance(segment, dict) and "align" in segment: + return int(segment["align"]) + return None + + +def parse_segment_subalign(segment: Union[dict, list]) -> int: + default = options.opts.subalign + if isinstance(segment, dict): + subalign = segment.get("subalign", default) + if subalign != None: + subalign = int(subalign) + return subalign + return default + + +def parse_segment_section_order(segment: Union[dict, list]) -> List[str]: + default = options.opts.section_order + if isinstance(segment, dict): + return segment.get("section_order", default) + return default + + +def parse_segment_follows_vram(segment: Union[dict, list]) -> Optional[str]: + if isinstance(segment, dict): + return segment.get("follows_vram", None) + return None + + +def parse_segment_vram_of_symbol(segment: Union[dict, list]) -> Optional[str]: + if isinstance(segment, dict): + return segment.get("vram_of_symbol", segment.get("follows_vram_symbol", None)) + return None + + +class Segment: + require_unique_name = True + + @staticmethod + def get_class_for_type(seg_type) -> Type["Segment"]: + # so .data loads SegData, for example + if seg_type.startswith("."): + seg_type = seg_type[1:] + + segment_class = Segment.get_base_segment_class(seg_type) + if segment_class == None: + # Look in extensions + segment_class = Segment.get_extension_segment_class(seg_type) + return segment_class + + @staticmethod + def get_base_segment_class(seg_type): + platform = options.opts.platform + is_platform_seg = False + + # heirarchy is platform -> common -> fail + try: + segmodule = importlib.import_module(f"segtypes.{platform}.{seg_type}") + is_platform_seg = True + except ModuleNotFoundError: + try: + segmodule = importlib.import_module(f"segtypes.common.{seg_type}") + except ModuleNotFoundError: + return None + + seg_prefix = platform.capitalize() if is_platform_seg else "Common" + return getattr(segmodule, f"{seg_prefix}Seg{seg_type.capitalize()}") + + @staticmethod + def get_extension_segment_class(seg_type): + platform = options.opts.platform + + ext_path = options.opts.extensions_path + if not ext_path: + log.error( + f"could not load presumed extended segment type '{seg_type}' because no extensions path is configured" + ) + assert ext_path is not None + + try: + ext_spec = importlib.util.spec_from_file_location( + f"{platform}.segtypes.{seg_type}", ext_path / f"{seg_type}.py" + ) + assert ext_spec is not None + ext_mod = importlib.util.module_from_spec(ext_spec) + assert ext_spec.loader is not None + ext_spec.loader.exec_module(ext_mod) + except Exception as err: + log.write(err, status="error") + log.error( + f"could not load segment type '{seg_type}'\n(hint: confirm your extension directory is configured correctly)" + ) + + return getattr( + ext_mod, f"{platform.upper()}Seg{seg_type[0].upper()}{seg_type[1:]}" + ) + + @staticmethod + def parse_segment_start(segment: Union[dict, list]) -> Optional[int]: + if isinstance(segment, dict): + s = segment.get("start", "auto") + else: + s = segment[0] + + if s == "auto": + return None + elif s == "...": + return None + else: + return int(s) + + @staticmethod + def parse_segment_type(segment: Union[dict, list]) -> str: + if isinstance(segment, dict): + return str(segment["type"]) + else: + return str(segment[1]) + + @staticmethod + def parse_segment_name(cls, rom_start, segment: Union[dict, list]) -> str: + if isinstance(segment, dict) and "name" in segment: + return str(segment["name"]) + elif isinstance(segment, dict) and "dir" in segment: + return str(segment["dir"]) + elif isinstance(segment, list) and len(segment) >= 3: + return str(segment[2]) + else: + return str(cls.get_default_name(rom_start)) + + @staticmethod + def parse_segment_symbol_name_format(segment: Union[dict, list]) -> str: + if isinstance(segment, dict) and "symbol_name_format" in segment: + return str(segment["symbol_name_format"]) + else: + return options.opts.symbol_name_format + + @staticmethod + def parse_segment_symbol_name_format_no_rom(segment: Union[dict, list]) -> str: + if isinstance(segment, dict) and "symbol_name_format_no_rom" in segment: + return str(segment["symbol_name_format_no_rom"]) + else: + return options.opts.symbol_name_format_no_rom + + @staticmethod + def parse_segment_file_path(segment: Union[dict, list]) -> Optional[Path]: + if isinstance(segment, dict) and "path" in segment: + return Path(segment["path"]) + return None + + @staticmethod + def parse_segment_bss_contains_common(segment: Union[dict, list]) -> bool: + if isinstance(segment, dict) and "bss_contains_common" in segment: + return bool(segment["bss_contains_common"]) + else: + return False + + def __init__( + self, + rom_start: Optional[int], + rom_end: Optional[int], + type: str, + name: str, + vram_start: Optional[int], + args: list, + yaml, + ): + self.rom_start = rom_start + self.rom_end = rom_end + self.type = type + self.name = name + self.vram_start: Optional[int] = vram_start + + self.align: Optional[int] = None + self.given_subalign: int = options.opts.subalign + self.exclusive_ram_id: Optional[str] = None + self.given_dir: Path = Path() + + # Symbols known to be in this segment + self.given_seg_symbols: Dict[int, List[Symbol]] = {} + + # Ranges for faster symbol lookup + self.symbol_ranges_ram: IntervalTree = IntervalTree() + self.symbol_ranges_rom: IntervalTree = IntervalTree() + + self.given_section_order: List[str] = options.opts.section_order + self.given_follows_vram: Optional[str] = None + self.vram_of_symbol: Optional[str] = None + + self.given_symbol_name_format: str = options.opts.symbol_name_format + self.given_symbol_name_format_no_rom: str = ( + options.opts.symbol_name_format_no_rom + ) + + self.parent: Optional[Segment] = None + self.sibling: Optional[Segment] = None + self.rodata_sibling: Optional[Segment] = None + self.file_path: Optional[Path] = None + + self.args: List[str] = args + self.yaml = yaml + + self.extract: bool = True + if self.rom_start is None: + self.extract = False + elif self.type.startswith("."): + self.extract = False + + self.warnings: List[str] = [] + self.did_run = False + self.bss_contains_common = Segment.parse_segment_bss_contains_common(yaml) + + # For segments which are not in the usual VRAM segment space, like N64's IPL3 which lives in 0xA4... + self.special_vram_segment: bool = False + + if isinstance(self.rom_start, int) and isinstance(self.rom_end, int): + if self.rom_start > self.rom_end: + log.error( + f"Error: segments out of order - ({self.name} starts at 0x{self.rom_start:X}, but next segment starts at 0x{self.rom_end:X})" + ) + + @staticmethod + def from_yaml( + cls: Type["Segment"], + yaml: Union[dict, list], + rom_start: Optional[int], + rom_end: Optional[int], + vram=None, + ): + type = Segment.parse_segment_type(yaml) + name = Segment.parse_segment_name(cls, rom_start, yaml) + vram_start = vram if vram is not None else parse_segment_vram(yaml) + + args: List[str] = [] if isinstance(yaml, dict) else yaml[3:] + + ret = cls( + rom_start=rom_start, + rom_end=rom_end, + type=type, + name=name, + vram_start=vram_start, + args=args, + yaml=yaml, + ) + ret.given_section_order = parse_segment_section_order(yaml) + ret.given_subalign = parse_segment_subalign(yaml) + if isinstance(yaml, dict): + ret.extract = bool(yaml.get("extract", ret.extract)) + ret.exclusive_ram_id = yaml.get("exclusive_ram_id") + ret.given_dir = Path(yaml.get("dir", "")) + ret.given_symbol_name_format = Segment.parse_segment_symbol_name_format(yaml) + ret.given_symbol_name_format_no_rom = ( + Segment.parse_segment_symbol_name_format_no_rom(yaml) + ) + ret.file_path = Segment.parse_segment_file_path(yaml) + + ret.bss_contains_common = Segment.parse_segment_bss_contains_common(yaml) + if not ret.given_follows_vram: + ret.given_follows_vram = parse_segment_follows_vram(yaml) + + if not ret.vram_of_symbol: + ret.vram_of_symbol = parse_segment_vram_of_symbol(yaml) + + if not ret.align: + ret.align = parse_segment_align(yaml) + return ret + + # For executable segments (.text); like c, asm or hasm + @staticmethod + def is_text() -> bool: + return False + + # For readonly segments (.rodata); like rodata or rdata + @staticmethod + def is_rodata() -> bool: + return False + + # For segments which does not take space in ROM; like bss + @staticmethod + def is_noload() -> bool: + return False + + @property + def needs_symbols(self) -> bool: + return False + + @property + def dir(self) -> Path: + if self.parent: + return self.parent.dir / self.given_dir + else: + return self.given_dir + + @property + def symbol_name_format(self) -> str: + return self.given_symbol_name_format + + @property + def symbol_name_format_no_rom(self) -> str: + return self.given_symbol_name_format_no_rom + + @property + def subalign(self) -> int: + if self.parent: + return self.parent.subalign + else: + return self.given_subalign + + def get_exclusive_ram_id(self) -> Optional[str]: + if self.parent: + return self.parent.get_exclusive_ram_id() + return self.exclusive_ram_id + + def add_symbol(self, symbol: Symbol): + if symbol.vram_start not in self.given_seg_symbols: + self.given_seg_symbols[symbol.vram_start] = [] + self.given_seg_symbols[symbol.vram_start].append(symbol) + + # For larger symbols, add their ranges to interval trees for faster lookup + if symbol.size > 4: + self.symbol_ranges_ram.addi(symbol.vram_start, symbol.vram_end, symbol) + if symbol.rom and isinstance(symbol.rom, int): + self.symbol_ranges_rom.addi(symbol.rom, symbol.rom_end, symbol) + + @property + def seg_symbols(self) -> Dict[int, List[Symbol]]: + if self.parent: + return self.parent.seg_symbols + else: + return self.given_seg_symbols + + @property + def size(self) -> Optional[int]: + if isinstance(self.rom_start, int) and isinstance(self.rom_end, int): + return self.rom_end - self.rom_start + else: + return None + + @property + def vram_end(self) -> Optional[int]: + if self.vram_start is not None and self.size is not None: + return self.vram_start + self.size + else: + return None + + @property + def section_order(self) -> List[str]: + return self.given_section_order + + @property + def rodata_follows_data(self) -> bool: + if ".rodata" not in self.section_order or ".data" not in self.section_order: + return False + return ( + self.section_order.index(".rodata") - self.section_order.index(".data") == 1 + ) + + def contains_vram(self, vram: int) -> bool: + if self.vram_start is not None and self.vram_end is not None: + return vram >= self.vram_start and vram < self.vram_end + else: + return False + + def contains_rom(self, rom: int) -> bool: + if isinstance(self.rom_start, int) and isinstance(self.rom_end, int): + return rom >= self.rom_start and rom < self.rom_end + else: + return False + + def rom_to_ram(self, rom_addr: int) -> Optional[int]: + if not self.contains_rom(rom_addr) and rom_addr != self.rom_end: + return None + + if self.vram_start is not None and isinstance(self.rom_start, int): + return self.vram_start + rom_addr - self.rom_start + else: + return None + + def ram_to_rom(self, ram_addr: int) -> Optional[int]: + if not self.contains_vram(ram_addr) and ram_addr != self.vram_end: + return None + + if self.vram_start is not None and isinstance(self.rom_start, int): + return self.rom_start + ram_addr - self.vram_start + else: + return None + + def should_scan(self) -> bool: + return self.should_split() + + def should_split(self) -> bool: + return self.extract and options.opts.is_mode_active(self.type) + + def scan(self, rom_bytes: bytes): + pass + + def split(self, rom_bytes: bytes): + pass + + def cache(self): + return (self.yaml, self.rom_end) + + def get_linker_section(self) -> str: + return ".data" + + def out_path(self) -> Optional[Path]: + return None + + def get_most_parent(self) -> "Segment": + seg = self + + while seg.parent: + seg = seg.parent + + return seg + + def get_linker_entries(self) -> "List[LinkerEntry]": + from segtypes.linker_entry import LinkerEntry + + path = self.out_path() + + if path: + return [LinkerEntry(self, [path], path, self.get_linker_section())] + else: + return [] + + def log(self, msg): + if options.opts.verbose: + log.write(f"{self.type} {self.name}: {msg}") + + def warn(self, msg: str): + self.warnings.append(msg) + + def max_length(self): + return None + + def is_name_default(self): + return self.name == self.get_default_name(self.rom_start) + + def unique_id(self): + if self.parent: + s = self.parent.unique_id() + "_" + else: + s = "" + + return s + self.type + "_" + self.name + + def status(self): + if len(self.warnings) > 0: + return "warn" + elif self.did_run: + return "ok" + else: + return "skip" + + @staticmethod + def get_default_name(addr) -> str: + return f"{addr:X}" + + @staticmethod + def visible_ram(seg1: "Segment", seg2: "Segment") -> bool: + if seg1.get_most_parent() == seg2.get_most_parent(): + return True + if seg1.get_exclusive_ram_id() is None or seg2.get_exclusive_ram_id() is None: + return True + return seg1.get_exclusive_ram_id() != seg2.get_exclusive_ram_id() + + def retrieve_symbol( + self, syms: Dict[int, List[Symbol]], addr: int + ) -> Optional[Symbol]: + if addr not in syms: + return None + + items = syms[addr] + + # Filter out symbols that are in different top-level segments with the same unique_ram_id + items = [ + i + for i in items + if i.segment is None or Segment.visible_ram(self, i.segment) + ] + + if len(items) > 1: + # print(f"Trying to retrieve {addr:X} from symbol dict but there are {len(items)} entries to pick from - picking the first") + pass + if len(items) == 0: + return None + return items[0] + + def get_symbol( + self, + addr: int, + in_segment: bool = False, + type: Optional[str] = None, + create: bool = False, + define: bool = False, + reference: bool = False, + search_ranges: bool = False, + local_only: bool = False, + dead: bool = True, + ) -> Optional[Symbol]: + ret: Optional[Symbol] = None + rom: Optional[int] = None + + most_parent = self.get_most_parent() + + if in_segment: + # If the vram address is within this segment, we can calculate the symbol's rom address + rom = most_parent.ram_to_rom(addr) + ret = most_parent.retrieve_symbol(most_parent.seg_symbols, addr) + + if not ret and search_ranges: + # Search ranges first, starting with rom + if rom is not None: + cands: Set[Interval] = most_parent.symbol_ranges_rom[rom] + if cands: + ret = cands.pop().data + # and then vram if we can't find a rom match + if not ret: + cands = most_parent.symbol_ranges_ram[addr] + if cands: + ret = cands.pop().data + elif not local_only: + ret = most_parent.retrieve_symbol(symbols.all_symbols_dict, addr) + + if not ret and search_ranges: + cands = symbols.all_symbols_ranges[addr] + if cands: + ret = cands.pop().data + + # Reject dead symbols unless we allow them + if not dead and ret and ret.dead: + ret = None + + # Create the symbol if it doesn't exist + if not ret and create: + ret = Symbol(addr, rom=rom, type=type) + symbols.add_symbol(ret) + + if in_segment: + ret.segment = most_parent + if addr not in most_parent.seg_symbols: + most_parent.seg_symbols[addr] = [] + most_parent.seg_symbols[addr].append(ret) + + if ret: + if define: + ret.defined = True + if reference: + ret.referenced = True + if ret.type is None: + ret.type = type + if ret.rom is None: + ret.rom = rom + if in_segment: + if ret.segment is None: + ret.segment = most_parent + + return ret + + def create_symbol( + self, + addr: int, + in_segment: bool, + type: Optional[str] = None, + define: bool = False, + reference: bool = False, + search_ranges: bool = False, + local_only: bool = False, + dead: bool = True, + ) -> Symbol: + ret = self.get_symbol( + addr, + in_segment=in_segment, + type=type, + create=True, + define=define, + reference=reference, + search_ranges=search_ranges, + local_only=local_only, + dead=dead, + ) + assert ret is not None + + return ret + + def get_func_for_addr(self, addr) -> Optional[Symbol]: + for syms in self.seg_symbols.values(): + for sym in syms: + if sym.type == "func" and sym.contains_vram(addr): + return sym + + return None diff --git a/tools/splat/split.py b/tools/splat/split.py new file mode 100755 index 00000000..18ab2c81 --- /dev/null +++ b/tools/splat/split.py @@ -0,0 +1,562 @@ +#! /usr/bin/env python3 + +import argparse +import hashlib +import importlib +import pickle +from typing import Any, Dict, List, Optional, Set, Tuple, Union + +import rabbitizer +import spimdisasm +import tqdm +import yaml +from colorama import Fore, Style +from intervaltree import Interval, IntervalTree + +from segtypes.linker_entry import ( + LinkerWriter, + get_segment_vram_end_symbol_name, + to_cname, +) +from segtypes.segment import Segment +from util import compiler, log, options, palettes, symbols, relocs + +from util.symbols import Symbol + +VERSION = "0.13.5" +# This value should be kept in sync with the version listed on requirements.txt +SPIMDISASM_MIN = (1, 12, 0) + +parser = argparse.ArgumentParser( + description="Split a rom given a rom, a config, and output directory" +) +parser.add_argument("config", help="path to a compatible config .yaml file", nargs="+") +parser.add_argument("--modes", nargs="+", default="all") +parser.add_argument("--verbose", action="store_true", help="Enable debug logging") +parser.add_argument( + "--use-cache", action="store_true", help="Only split changed segments in config" +) +parser.add_argument( + "--skip-version-check", + action="store_true", + help="Skips the disassembler's version check", +) + +linker_writer: LinkerWriter +config: Dict[str, Any] + +segment_roms: IntervalTree = IntervalTree() +segment_rams: IntervalTree = IntervalTree() + + +def fmt_size(size): + if size > 1000000: + return str(size // 1000000) + " MB" + elif size > 1000: + return str(size // 1000) + " KB" + else: + return str(size) + " B" + + +def initialize_segments(config_segments: Union[dict, list]) -> List[Segment]: + global segment_roms + global segment_rams + + segment_roms = IntervalTree() + segment_rams = IntervalTree() + + segments_by_name: Dict[str, Segment] = {} + ret = [] + + last_rom_end = 0 + + for i, seg_yaml in enumerate(config_segments): + # end marker + if isinstance(seg_yaml, list) and len(seg_yaml) == 1: + continue + + seg_type = Segment.parse_segment_type(seg_yaml) + + segment_class = Segment.get_class_for_type(seg_type) + + this_start = Segment.parse_segment_start(seg_yaml) + + if i == len(config_segments) - 1 and Segment.parse_segment_file_path(seg_yaml): + next_start: Optional[int] = 0 + else: + next_start = Segment.parse_segment_start(config_segments[i + 1]) + + if segment_class.is_noload(): + # Pretend bss's rom address is after the last actual rom segment + this_start = last_rom_end + # and it has a rom size of zero + next_start = last_rom_end + + segment: Segment = Segment.from_yaml( + segment_class, seg_yaml, this_start, next_start + ) + + if segment.require_unique_name: + if segment.name in segments_by_name: + log.error(f"segment name '{segment.name}' is not unique") + + segments_by_name[segment.name] = segment + + ret.append(segment) + if ( + isinstance(segment.rom_start, int) + and isinstance(segment.rom_end, int) + and segment.rom_start != segment.rom_end + ): + segment_roms.addi(segment.rom_start, segment.rom_end, segment) + if ( + isinstance(segment.vram_start, int) + and isinstance(segment.vram_end, int) + and segment.vram_start != segment.vram_end + ): + segment_rams.addi(segment.vram_start, segment.vram_end, segment) + + if next_start is not None: + last_rom_end = next_start + + for segment in ret: + if segment.given_follows_vram: + if segment.given_follows_vram not in segments_by_name: + log.error( + f"segment '{segment.given_follows_vram}', the 'follows_vram' value for segment '{segment.name}', does not exist" + ) + segment.vram_of_symbol = get_segment_vram_end_symbol_name( + segments_by_name[segment.given_follows_vram] + ) + + return ret + + +def assign_symbols_to_segments(): + for symbol in symbols.all_symbols: + if symbol.segment: + continue + + if symbol.rom: + cands: Set[Interval] = segment_roms[symbol.rom] + if len(cands) > 1: + log.error("multiple segments rom overlap symbol", symbol) + elif len(cands) == 0: + log.error("no segment rom overlaps symbol", symbol) + else: + cand: Interval = cands.pop() + seg: Segment = cand.data + seg.add_symbol(symbol) + else: + cands = segment_rams[symbol.vram_start] + segs: List[Segment] = [cand.data for cand in cands] + for seg in segs: + if not seg.get_exclusive_ram_id(): + seg.add_symbol(symbol) + + +def do_statistics(seg_sizes, rom_bytes, seg_split, seg_cached): + unk_size = seg_sizes.get("unk", 0) + rest_size = 0 + total_size = len(rom_bytes) + + for typ in seg_sizes: + if typ != "unk": + rest_size += seg_sizes[typ] + + known_ratio = rest_size / total_size + unk_ratio = unk_size / total_size + + log.write(f"Split {fmt_size(rest_size)} ({known_ratio:.2%}) in defined segments") + for typ in seg_sizes: + if typ != "unk": + tmp_size = seg_sizes[typ] + tmp_ratio = tmp_size / total_size + log.write( + f"{typ:>20}: {fmt_size(tmp_size):>8} ({tmp_ratio:.2%}) {Fore.GREEN}{seg_split[typ]} split{Style.RESET_ALL}, {Style.DIM}{seg_cached[typ]} cached" + ) + log.write( + f"{'unknown':>20}: {fmt_size(unk_size):>8} ({unk_ratio:.2%}) from unknown bin files" + ) + + +def merge_configs(main_config, additional_config): + # Merge rules are simple + # For each key in the dictionary + # - If list then append to list + # - If a dictionary then repeat merge on sub dictionary entries + # - Else assume string or number and replace entry + + for curkey in additional_config: + if curkey not in main_config: + main_config[curkey] = additional_config[curkey] + elif type(main_config[curkey]) != type(additional_config[curkey]): + log.error(f"Type for key {curkey} in configs does not match") + else: + # keys exist and match, see if a list to append + if type(main_config[curkey]) == list: + main_config[curkey] += additional_config[curkey] + elif type(main_config[curkey]) == dict: + # need to merge sub areas + main_config[curkey] = merge_configs( + main_config[curkey], additional_config[curkey] + ) + else: + # not a list or dictionary, must be a number or string, overwrite + main_config[curkey] = additional_config[curkey] + + return main_config + + +def configure_disassembler(): + # Configure spimdisasm + spimdisasm.common.GlobalConfig.PRODUCE_SYMBOLS_PLUS_OFFSET = True + spimdisasm.common.GlobalConfig.TRUST_USER_FUNCTIONS = True + spimdisasm.common.GlobalConfig.TRUST_JAL_FUNCTIONS = True + spimdisasm.common.GlobalConfig.GLABEL_ASM_COUNT = False + + if options.opts.rom_address_padding: + spimdisasm.common.GlobalConfig.ASM_COMMENT_OFFSET_WIDTH = 6 + else: + spimdisasm.common.GlobalConfig.ASM_COMMENT_OFFSET_WIDTH = 0 + + # spimdisasm is not performing any analyzis on non-text sections so enabling this options is pointless + spimdisasm.common.GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_SECTION_TYPE = False + spimdisasm.common.GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_DATA_TYPE = False + + spimdisasm.common.GlobalConfig.SYMBOL_FINDER_FILTERED_ADDRESSES_AS_HILO = False + + rabbitizer.config.regNames_userFpcCsr = False + rabbitizer.config.regNames_vr4300Cop0NamedRegisters = False + + rabbitizer.config.misc_opcodeLJust = options.opts.mnemonic_ljust - 1 + + rabbitizer.config.regNames_gprAbiNames = rabbitizer.Abi.fromStr( + options.opts.mips_abi_gpr + ) + rabbitizer.config.regNames_fprAbiNames = rabbitizer.Abi.fromStr( + options.opts.mips_abi_float_regs + ) + + if options.opts.endianness == "big": + spimdisasm.common.GlobalConfig.ENDIAN = spimdisasm.common.InputEndian.BIG + else: + spimdisasm.common.GlobalConfig.ENDIAN = spimdisasm.common.InputEndian.LITTLE + + rabbitizer.config.pseudos_pseudoMove = False + + selected_compiler = options.opts.compiler + if selected_compiler == compiler.SN64: + rabbitizer.config.regNames_namedRegisters = False + rabbitizer.config.toolchainTweaks_sn64DivFix = True + rabbitizer.config.toolchainTweaks_treatJAsUnconditionalBranch = True + spimdisasm.common.GlobalConfig.ASM_COMMENT = False + spimdisasm.common.GlobalConfig.SYMBOL_FINDER_FILTERED_ADDRESSES_AS_HILO = False + spimdisasm.common.GlobalConfig.COMPILER = spimdisasm.common.Compiler.SN64 + elif selected_compiler == compiler.GCC: + rabbitizer.config.toolchainTweaks_treatJAsUnconditionalBranch = True + spimdisasm.common.GlobalConfig.COMPILER = spimdisasm.common.Compiler.GCC + elif selected_compiler == compiler.IDO: + spimdisasm.common.GlobalConfig.COMPILER = spimdisasm.common.Compiler.IDO + + spimdisasm.common.GlobalConfig.GP_VALUE = options.opts.gp + + spimdisasm.common.GlobalConfig.ASM_TEXT_LABEL = options.opts.asm_function_macro + spimdisasm.common.GlobalConfig.ASM_JTBL_LABEL = options.opts.asm_jtbl_label_macro + spimdisasm.common.GlobalConfig.ASM_DATA_LABEL = options.opts.asm_data_macro + spimdisasm.common.GlobalConfig.ASM_TEXT_END_LABEL = options.opts.asm_end_label + + if spimdisasm.common.GlobalConfig.ASM_TEXT_LABEL == ".globl": + spimdisasm.common.GlobalConfig.ASM_TEXT_ENT_LABEL = ".ent" + spimdisasm.common.GlobalConfig.ASM_TEXT_FUNC_AS_LABEL = True + + if spimdisasm.common.GlobalConfig.ASM_DATA_LABEL == ".globl": + spimdisasm.common.GlobalConfig.ASM_DATA_SYM_AS_LABEL = True + + spimdisasm.common.GlobalConfig.LINE_ENDS = options.opts.c_newline + + spimdisasm.common.GlobalConfig.ALLOW_ALL_ADDENDS_ON_DATA = ( + options.opts.allow_data_addends + ) + + +def brief_seg_name(seg: Segment, limit: int, ellipsis="…") -> str: + s = seg.name.strip() + if len(s) > limit: + return s[:limit].strip() + ellipsis + return s + + +def main(config_path, modes, verbose, use_cache=True, skip_version_check=False): + global config + + if not skip_version_check and spimdisasm.__version_info__ < SPIMDISASM_MIN: + log.error( + f"splat {VERSION} requires as minimum spimdisasm {SPIMDISASM_MIN}, but the installed version is {spimdisasm.__version_info__}" + ) + + log.write(f"splat {VERSION} (powered by spimdisasm {spimdisasm.__version__})") + + # Load config + config = {} + for entry in config_path: + with open(entry) as f: + additional_config = yaml.load(f.read(), Loader=yaml.SafeLoader) + config = merge_configs(config, additional_config) + + options.initialize(config, config_path, modes, verbose) + + with options.opts.target_path.open("rb") as f2: + rom_bytes = f2.read() + + if "sha1" in config: + sha1 = hashlib.sha1(rom_bytes).hexdigest() + e_sha1 = config["sha1"].lower() + if e_sha1 != sha1: + log.error(f"sha1 mismatch: expected {e_sha1}, was {sha1}") + + # Create main output dir + options.opts.base_path.mkdir(parents=True, exist_ok=True) + + processed_segments: List[Segment] = [] + + seg_sizes: Dict[str, int] = {} + seg_split: Dict[str, int] = {} + seg_cached: Dict[str, int] = {} + + # Load cache + if use_cache: + try: + with options.opts.cache_path.open("rb") as f3: + cache = pickle.load(f3) + + if verbose: + log.write(f"Loaded cache ({len(cache.keys())} items)") + except Exception: + cache = {} + else: + cache = {} + + # invalidate entire cache if options change + if use_cache and cache.get("__options__") != config.get("options"): + if verbose: + log.write("Options changed, invalidating cache") + + cache = { + "__options__": config.get("options"), + } + + configure_disassembler() + + platform_module = importlib.import_module(f"platforms.{options.opts.platform}") + platform_init = getattr(platform_module, "init") + platform_init(rom_bytes) + + # Initialize segments + all_segments = initialize_segments(config["segments"]) + + # Load and process symbols + symbols.initialize(all_segments) + relocs.initialize() + + # Assign symbols to segments + assign_symbols_to_segments() + + if options.opts.is_mode_active("code"): + symbols.initialize_spim_context(all_segments) + relocs.initialize_spim_context() + + # Resolve raster/palette siblings + if options.opts.is_mode_active("img"): + palettes.initialize(all_segments) + + # Scan + scan_bar = tqdm.tqdm(all_segments, total=len(all_segments)) + for segment in scan_bar: + assert isinstance(segment, Segment) + scan_bar.set_description(f"Scanning {brief_seg_name(segment, 20)}") + typ = segment.type + if segment.type == "bin" and segment.is_name_default(): + typ = "unk" + + if typ not in seg_sizes: + seg_sizes[typ] = 0 + seg_split[typ] = 0 + seg_cached[typ] = 0 + seg_sizes[typ] += 0 if segment.size is None else segment.size + + if segment.should_scan(): + # Check cache but don't write anything + if use_cache: + if segment.cache() == cache.get(segment.unique_id()): + continue + + segment.did_run = True + segment.scan(rom_bytes) + + processed_segments.append(segment) + + seg_split[typ] += 1 + + symbols.mark_c_funcs_as_defined() + + # Split + split_bar = tqdm.tqdm( + all_segments, + total=len(all_segments), + ) + for segment in split_bar: + split_bar.set_description(f"Splitting {brief_seg_name(segment, 20)}") + + if use_cache: + cached = segment.cache() + + if cached == cache.get(segment.unique_id()): + # Cache hit + if segment.type not in seg_cached: + seg_cached[segment.type] = 0 + seg_cached[segment.type] += 1 + continue + else: + # Cache miss; split + cache[segment.unique_id()] = cached + + if segment.should_split(): + segment_bytes = rom_bytes + if segment.file_path: + with open(segment.file_path, "rb") as segment_input_file: + segment_bytes = segment_input_file.read() + segment.split(segment_bytes) + + if ( + options.opts.is_mode_active("ld") and options.opts.platform != "gc" + ): # TODO move this to platform initialization when it gets implemented + # Calculate list of segments for which we need to find the largest so we can safely place the symbol after it + max_vram_end_syms: Dict[str, List[Segment]] = {} + for sym in symbols.appears_after_overlays_syms: + max_vram_end_syms[sym.name] = [ + seg + for seg in all_segments + if isinstance(seg.vram_start, int) + and seg.vram_start == sym.appears_after_overlays_addr + ] + max_vram_end_sym_names: Set[str] = set(max_vram_end_syms.keys()) + + max_vram_end_insertion_points: Dict[ + Segment, List[Tuple[str, List[Segment]]] + ] = {} + # Find the last segment whose vram_of_symbol is one of the max_vram_end_syms + for segment in reversed(all_segments): + vram_of_sym = segment.vram_of_symbol + if vram_of_sym is not None and vram_of_sym in max_vram_end_sym_names: + if segment not in max_vram_end_insertion_points: + max_vram_end_insertion_points[segment] = [] + max_vram_end_insertion_points[segment].append( + (vram_of_sym, max_vram_end_syms[vram_of_sym]) + ) + max_vram_end_sym_names.remove(vram_of_sym) + + global linker_writer + linker_writer = LinkerWriter() + linker_bar = tqdm.tqdm( + all_segments, + total=len(all_segments), + ) + + for segment in linker_bar: + linker_bar.set_description(f"Linker script {brief_seg_name(segment, 20)}") + linker_writer.add(segment, max_vram_end_insertion_points.get(segment, [])) + linker_writer.save_linker_script() + linker_writer.save_symbol_header() + + # write elf_sections.txt - this only lists the generated sections in the elf, not subsections + # that the elf combines into one section + if options.opts.elf_section_list_path: + section_list = "" + for segment in all_segments: + section_list += "." + to_cname(segment.name) + "\n" + with open(options.opts.elf_section_list_path, "w", newline="\n") as f: + f.write(section_list) + + # Write undefined_funcs_auto.txt + if options.opts.create_undefined_funcs_auto: + to_write = [ + s + for s in symbols.all_symbols + if s.referenced and not s.defined and not s.dead and s.type == "func" + ] + to_write.sort(key=lambda x: x.vram_start) + + with open(options.opts.undefined_funcs_auto_path, "w", newline="\n") as f: + for symbol in to_write: + f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") + + # write undefined_syms_auto.txt + if options.opts.create_undefined_syms_auto: + to_write = [ + s + for s in symbols.all_symbols + if s.referenced + and not s.defined + and not s.dead + and s.type not in {"func", "label", "jtbl_label"} + ] + to_write.sort(key=lambda x: x.vram_start) + + with open(options.opts.undefined_syms_auto_path, "w", newline="\n") as f: + for symbol in to_write: + f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") + + # print warnings during split + for segment in all_segments: + if len(segment.warnings) > 0: + log.write( + f"{Style.DIM}0x{segment.rom_start:06X}{Style.RESET_ALL} {segment.type} {Style.BRIGHT}{segment.name}{Style.RESET_ALL}:" + ) + + for warn in segment.warnings: + log.write("warning: " + warn, status="warn") + + log.write("") # empty line + + # Statistics + do_statistics(seg_sizes, rom_bytes, seg_split, seg_cached) + + # Save cache + if cache != {} and use_cache: + if verbose: + log.write("Writing cache") + with open(options.opts.cache_path, "wb") as f4: + pickle.dump(cache, f4) + + if options.opts.dump_symbols and options.opts.is_mode_active("code"): + from pathlib import Path + + splat_hidden_folder = Path(".splat/") + splat_hidden_folder.mkdir(exist_ok=True) + + with open(splat_hidden_folder / "splat_symbols.csv", "w") as f: + f.write( + "vram_start,given_name,name,type,given_size,size,rom,defined,user_declared,referenced,dead,extract\n" + ) + for s in sorted(symbols.all_symbols, key=lambda x: x.vram_start): + f.write(f"{s.vram_start:X},{s.given_name},{s.name},{s.type},") + if s.given_size is not None: + f.write(f"0x{s.given_size:X},") + else: + f.write("None,") + f.write(f"{s.size},") + if s.rom is not None: + f.write(f"0x{s.rom:X},") + else: + f.write("None,") + f.write( + f"{s.defined},{s.user_declared},{s.referenced},{s.dead},{s.extract}\n" + ) + + symbols.spim_context.saveContextToFile(splat_hidden_folder / "spim_context.csv") + + +if __name__ == "__main__": + args = parser.parse_args() + main(args.config, args.modes, args.verbose, args.use_cache, args.skip_version_check) diff --git a/tools/splat/stubs/colorama.pyi b/tools/splat/stubs/colorama.pyi new file mode 100644 index 00000000..5d13e507 --- /dev/null +++ b/tools/splat/stubs/colorama.pyi @@ -0,0 +1,8 @@ +from typing import Any + +def init(**kwargs): ... + +Fore: Any +Back: Any +Style: Any +Cursor: Any diff --git a/tools/splat/util/__init__.py b/tools/splat/util/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/splat/util/color.py b/tools/splat/util/color.py new file mode 100644 index 00000000..6d75cbd7 --- /dev/null +++ b/tools/splat/util/color.py @@ -0,0 +1,19 @@ +from math import ceil + +from util import options + + +# RRRRRGGG GGBBBBBA +def unpack_color(data): + s = int.from_bytes(data[0:2], byteorder=options.opts.endianness) + + r = (s >> 11) & 0x1F + g = (s >> 6) & 0x1F + b = (s >> 1) & 0x1F + a = (s & 1) * 0xFF + + r = ceil(0xFF * (r / 31)) + g = ceil(0xFF * (g / 31)) + b = ceil(0xFF * (b / 31)) + + return r, g, b, a diff --git a/tools/splat/util/compiler.py b/tools/splat/util/compiler.py new file mode 100644 index 00000000..c89c35c0 --- /dev/null +++ b/tools/splat/util/compiler.py @@ -0,0 +1,40 @@ +from dataclasses import dataclass + + +@dataclass +class Compiler: + name: str + asm_function_macro: str = "glabel" + asm_jtbl_label_macro: str = "glabel" + asm_data_macro: str = "glabel" + asm_end_label: str = "" + c_newline: str = "\n" + asm_inc_header: str = "" + include_macro_inc: bool = True + + +GCC = Compiler( + "GCC", + asm_inc_header=".set noat /* allow manual use of $at */\n.set noreorder /* don't insert nops after branches */\n\n", +) + +SN64 = Compiler( + "SN64", + asm_function_macro=".globl", + asm_jtbl_label_macro=".globl", + asm_data_macro=".globl", + asm_end_label=".end", + c_newline="\r\n", + include_macro_inc=False, +) + +IDO = Compiler("IDO") + +compiler_for_name = {"GCC": GCC, "SN64": SN64, "IDO": IDO} + + +def for_name(name: str) -> Compiler: + name = name.upper() + if name in compiler_for_name: + return compiler_for_name[name] + return Compiler(name) diff --git a/tools/splat/util/floats.py b/tools/splat/util/floats.py new file mode 100644 index 00000000..009725e7 --- /dev/null +++ b/tools/splat/util/floats.py @@ -0,0 +1,63 @@ +import math +import struct + + +# From mips_to_c: https://github.com/matt-kempster/mips_to_c/blob/d208400cca045113dada3e16c0d59c50cdac4529/src/translate.py#L2085 +def format_f32_imm(num: int) -> str: + packed = struct.pack(">I", num & (2**32 - 1)) + value = struct.unpack(">f", packed)[0] + + if not value or value == 4294967296.0: + # Zero, negative zero, nan, or INT_MAX. + return str(value) + + # Write values smaller than 1e-7 / greater than 1e7 using scientific notation, + # and values in between using fixed point. + if abs(math.log10(abs(value))) > 6.9: + fmt_char = "e" + elif abs(value) < 1: + fmt_char = "f" + else: + fmt_char = "g" + + def fmt(prec: int) -> str: + """Format 'value' with 'prec' significant digits/decimals, in either scientific + or regular notation depending on 'fmt_char'.""" + ret = ("{:." + str(prec) + fmt_char + "}").format(value) + if fmt_char == "e": + return ret.replace("e+", "e").replace("e0", "e").replace("e-0", "e-") + if "e" in ret: + # The "g" format character can sometimes introduce scientific notation if + # formatting with too few decimals. If this happens, return an incorrect + # value to prevent the result from being used. + # + # Since the value we are formatting is within (1e-7, 1e7) in absolute + # value, it will at least be possible to format with 7 decimals, which is + # less than float precision. Thus, this annoying Python limitation won't + # lead to us outputting numbers with more precision than we really have. + return "0" + return ret + + # 20 decimals is more than enough for a float. Start there, then try to shrink it. + prec = 20 + while prec > 0: + prec -= 1 + value2 = float(fmt(prec)) + if struct.pack(">f", value2) != packed: + prec += 1 + break + + if prec == 20: + # Uh oh, even the original value didn't format correctly. Fall back to str(), + # which ought to work. + return str(value) + + ret = fmt(prec) + if "." not in ret and "e" not in ret: + ret += ".0" + return ret + + +def format_f64_imm(num: int) -> str: + (value,) = struct.unpack(">d", struct.pack(">Q", num & (2**64 - 1))) + return str(value) diff --git a/tools/splat/util/gc/gcfst.py b/tools/splat/util/gc/gcfst.py new file mode 100644 index 00000000..e50420f7 --- /dev/null +++ b/tools/splat/util/gc/gcfst.py @@ -0,0 +1,181 @@ +import struct +from pathlib import Path +from typing import List, Optional + +from segtypes.gc.segment import GCSegment + +from util import options +from util.gc.gcutil import read_string_from_bytes + + +# Represents the info for either a directory or a file within a GameCube disc image's file system. +class GCFSTEntry: + def __init__(self, flags: bool, name_offset, offset, length): + self.flags = flags + self.name_offset = name_offset + self.offset = offset + self.length = length + + self.name = "" + self.parent: Optional[GCFSTEntry] = None + self.children: List[GCFSTEntry] = [] + + def populate_children_recursive( + self, root_dir: "GCFSTEntry", current_node_offset, fst_bytes, string_table_bytes + ): + self.parent = root_dir + self.name = read_string_from_bytes(self.name_offset, string_table_bytes) + + # This node is a file, so we don't do anything but return that we read 1 node. + if self.flags == False: + return 1 + + nodes_read = 1 + next_child_offset = current_node_offset + 0x0C + + # Directory nodes contain the index of the next node that is NOT its child, meaning the index of their next sibling node. + # We can figure out when we're done reading child nodes by comparing the offset of the next node to read to the + # offset of the next sibling node. We stop reading when the next node offset is >= the offset of the next sibling node. + while next_child_offset < self.length * 0x0C: + new_entry = GCFSTEntry( + bool(fst_bytes[next_child_offset + 0x0000]), + struct.unpack_from( + ">I", fst_bytes[next_child_offset : next_child_offset + 0x0004] + )[0] + & 0x00FFFFFF, + struct.unpack_from(">I", fst_bytes, next_child_offset + 0x0004)[0], + struct.unpack_from(">I", fst_bytes, next_child_offset + 0x0008)[0], + ) + + self.children.append(new_entry) + nodes_read += new_entry.populate_children_recursive( + self, next_child_offset, fst_bytes, string_table_bytes + ) + + next_child_offset = current_node_offset + nodes_read * 0x0C + + return nodes_read + + # Builds this entry's full path within the filesystem from its parents' names. + def get_full_name(self): + path_components: List[str] = [] + + entry = self + while entry.parent != None: + path_components.insert(0, entry.name) + + if entry.parent is None: + break + entry = entry.parent + + return Path(*path_components) + + # Emits this entry to the filesystem. + def emit(self, filesystem_dir: Path, iso_bytes): + full_path = filesystem_dir / self.get_full_name() + + # If this is a directory, we just need to make the directory on disk. + if self.flags == True: + full_path.mkdir(parents=True, exist_ok=True) + return + + file_bytes = iso_bytes[self.offset : self.offset + self.length] + with open(full_path, "wb") as f: + f.write(file_bytes) + + def emit_recursive(self, filesystem_dir: Path, iso_bytes): + # Don't emit if this is the root directory. + if self.parent != None: + self.emit(filesystem_dir, iso_bytes) + + for e in self.children: + e.emit_recursive(filesystem_dir, iso_bytes) + + +# Splits the ISO into its component parts - header info, apploader, DOL, FST metadata, and the individual files in the filesystem. +def split_iso(iso_bytes): + split_sys_info(iso_bytes) + split_content(iso_bytes) + + +# Splits the header info, apploader, DOL, and FST metadata from the ISO. +def split_sys_info(iso_bytes): + assert options.opts.filesystem_path is not None + + sys_path = options.opts.filesystem_path / "sys" + sys_path.mkdir(parents=True, exist_ok=True) + + # Split boot.info. Always at 0x0000 and 0x0440 bytes long. + with open(sys_path / "boot.bin", "wb") as f: + f.write(iso_bytes[0x0000:0x0440]) + + # Split bi2.info. Always at 0x0440 and 0x2000 bytes long. + with open(sys_path / "bi2.bin", "wb") as f: + f.write(iso_bytes[0x0440:0x2440]) + + # Split apploader.img. Always at 0x2440 and size is listed at 0x0400. + apploader_size = struct.unpack_from(">I", iso_bytes, 0x0400)[0] + with open(sys_path / "apploader.img", "wb") as f: + f.write(iso_bytes[0x2440 : 0x2440 + apploader_size]) + + # Split main.dol. Offset specified explicitly at 0x0420, but size must be calculated. + dol_offset = struct.unpack_from(">I", iso_bytes, 0x0420)[0] + fst_offset = struct.unpack_from(">I", iso_bytes, 0x0424)[0] + + dol_size = fst_offset - dol_offset + with open(sys_path / "main.dol", "wb") as f: + f.write(iso_bytes[dol_offset : dol_offset + dol_size]) + + # Split fst.bin. Offset specified at 0x0424 and size specified at 0x402C. + fst_size = struct.unpack_from(">I", iso_bytes, 0x0428)[0] + with open(sys_path / "fst.bin", "wb") as f: + f.write(iso_bytes[fst_offset : fst_offset + fst_size]) + + +# Splits the ISO's filesystem into individual files. +def split_content(iso_bytes): + assert options.opts.filesystem_path is not None + + fst_path = options.opts.filesystem_path / "sys" / "fst.bin" + assert fst_path.is_file() + + fst_bytes = fst_path.read_bytes() + fst_root_entry = populate_filesystem(fst_bytes) + + files_path = options.opts.filesystem_path / "files" + files_path.mkdir(parents=True, exist_ok=True) + fst_root_entry.emit_recursive(files_path, iso_bytes) + + +# Loads the FST data needed to split the filesystem. +def populate_filesystem(fst_bytes): + root_dir = GCFSTEntry( + bool(fst_bytes[0x0000]), + struct.unpack_from(">I", fst_bytes, 0x0000)[0] & 0x00FFFFFF, + struct.unpack_from(">I", fst_bytes, 0x0004)[0], + struct.unpack_from(">I", fst_bytes, 0x0008)[0], + ) + + string_table_bytes = fst_bytes[root_dir.length * 0x0C : len(fst_bytes)] + + # Parsing the filesystem is a bit tricky. The root directory's length property is the total number of nodes in the FST. + # So, we initialize nodes_read to 1, since the root is included in the number of nodes. + # We will rely on each directory and file on the root directory to tell us how many nodes were read while parsing them. + # We can stop reading the FST when our total number of nodes read is >= the number of nodes in the FST. + nodes_read = 1 + while nodes_read < root_dir.length: + current_offset = nodes_read * 0x0C + + new_entry = GCFSTEntry( + bool(fst_bytes[current_offset + 0x0000]), + struct.unpack_from(">I", fst_bytes, current_offset)[0] & 0x00FFFFFF, + struct.unpack_from(">I", fst_bytes, current_offset + 0x0004)[0], + struct.unpack_from(">I", fst_bytes, current_offset + 0x0008)[0], + ) + + root_dir.children.append(new_entry) + nodes_read += new_entry.populate_children_recursive( + root_dir, current_offset, fst_bytes, string_table_bytes + ) + + return root_dir diff --git a/tools/splat/util/gc/gcinfo.py b/tools/splat/util/gc/gcinfo.py new file mode 100644 index 00000000..78130df8 --- /dev/null +++ b/tools/splat/util/gc/gcinfo.py @@ -0,0 +1,88 @@ +#! /usr/bin/env python3 + + +import argparse + +import hashlib + +from pathlib import Path +from typing import Optional + +parser = argparse.ArgumentParser( + description="Gives information on GameCube disc images" +) +parser.add_argument("iso", help="path to a GameCube disc image") + +system_codes = { + "D": "GameCube Demo", + "G": "GameCube", + "P": "GameCube Promotional", + "R": "Early Wii", + "S": "Later Wii", +} + +region_codes = {"E": "NTSC-U", "J": "NTSC-J", "P": "PAL"} + +publisher_codes = {"01": "Nintendo", "08": "Capcom", "8P": "Sega", "E9": "Natsume"} + + +def get_info(iso_path: Path, iso_bytes: Optional[bytes] = None): + if iso_bytes is None: + iso_bytes = iso_path.read_bytes() + + return get_info_bytes(iso_bytes) + + +def get_info_bytes(iso_bytes: bytes): + system_code = chr(iso_bytes[0x00]) + game_code = iso_bytes[0x01:0x03].decode("utf-8") + region_code = chr(iso_bytes[0x03]) + publisher_code = iso_bytes[0x04:0x06].decode("utf-8") + + name = str(iso_bytes[0x20:0x400], "utf-8").strip("\x00") + root = "filesystem" + + compiler = "mwcc" + sha1 = hashlib.sha1(iso_bytes).hexdigest() + + return GCIso( + name, + root, + system_code, + game_code, + region_code, + publisher_code, + compiler, + sha1, + ) + + +class GCIso: + def __init__( + self, + name: str, + root: str, + system_code, + game_code, + region_code, + publisher_code, + compiler, + sha1, + ): + self.name = name + self.root = root + self.system_code = system_code + self.game_code = game_code + self.region_code = region_code + self.publisher_code = publisher_code + self.compiler = compiler + self.sha1 = sha1 + + def get_system_name(self): + return system_codes[self.system_code] + + def get_publisher_name(self): + return publisher_codes[self.publisher_code] + + def get_region_name(self): + return region_codes[self.region_code] diff --git a/tools/splat/util/gc/gcutil.py b/tools/splat/util/gc/gcutil.py new file mode 100644 index 00000000..ba78bc2f --- /dev/null +++ b/tools/splat/util/gc/gcutil.py @@ -0,0 +1,11 @@ +def read_string_from_bytes(name_offset, string_table_bytes): + bytes = bytearray() + + for offset in range(len(string_table_bytes) - name_offset): + cur_byte = string_table_bytes[name_offset + offset] + if cur_byte == 0x00: + break + + bytes.append(cur_byte) + + return bytes.decode("shift-jis") diff --git a/tools/splat/util/log.py b/tools/splat/util/log.py new file mode 100644 index 00000000..df6ef53b --- /dev/null +++ b/tools/splat/util/log.py @@ -0,0 +1,45 @@ +import sys +from typing import NoReturn, Optional + +from colorama import Fore, init, Style + +init(autoreset=True) + +newline = True + +Status = Optional[str] + + +def write(*args, status=None, **kwargs): + global newline + + if not newline: + print("") + newline = True + + print(status_to_ansi(status) + str(args[0]), *args[1:], **kwargs) + + +def error(*args, **kwargs) -> NoReturn: + write(*args, **kwargs, status="error") + sys.exit(2) + + +# The line_num is expected to be zero-indexed +def parsing_error_preamble(path, line_num, line): + write("") + write(f"error reading {path}, line {line_num + 1}:", status="error") + write(f"\t{line}") + + +def status_to_ansi(status: Status): + if status == "ok": + return Fore.GREEN + elif status == "warn": + return Fore.YELLOW + Style.BRIGHT + elif status == "error": + return Fore.RED + Style.BRIGHT + elif status == "skip": + return Style.DIM + else: + return "" diff --git a/tools/splat/util/n64/Mio0decompress.py b/tools/splat/util/n64/Mio0decompress.py new file mode 100644 index 00000000..64a059e7 --- /dev/null +++ b/tools/splat/util/n64/Mio0decompress.py @@ -0,0 +1,108 @@ +import argparse +import struct +import sys + +try: + from .. import log + from .decompressor import Decompressor +except ImportError: + print(f"Run as python3 -m util.n64.Miodecompress") + sys.exit(1) + + +class GenericMio0Decompressor(Decompressor): + def __init__( + self, unpacked_offset, compressed_offset, uncompressed_offset, header_length + ): + self.unpacked_offset = unpacked_offset + self.compressed_offset = compressed_offset + self.uncompressed_offset = uncompressed_offset + self.header_length = header_length + + @staticmethod + def read_word(data, offset): + (res,) = struct.unpack(">I", data[offset : offset + 4]) + return res + + @staticmethod + def read_short(data, offset): + (res,) = struct.unpack(">H", data[offset : offset + 2]) + return res + + def decompress(self, in_bytes, byte_order="big") -> bytearray: + magic = in_bytes[0:4] + if magic != b"MIO0": + log.error(f"MIO0 magic is incorrect: {magic}") + + unpacked_size = self.read_word(in_bytes, self.unpacked_offset) + comp_offset = self.read_word(in_bytes, self.compressed_offset) + uncomp_offset = self.read_word(in_bytes, self.uncompressed_offset) + + layout_data = struct.iter_unpack(">I", in_bytes[self.header_length :]) + uncompressed_data = struct.iter_unpack(">B", in_bytes[uncomp_offset:]) + compressed_data = struct.iter_unpack(">H", in_bytes[comp_offset:]) + + idx = 0 + ret = bytearray(unpacked_size) + + mask_bit_counter = 0 + while idx < unpacked_size: + if mask_bit_counter == 0: + (current_mask,) = next(layout_data) + mask_bit_counter = 32 + + if current_mask & 0x80000000: + (ud,) = next(uncompressed_data) + ret[idx] = ud + idx += 1 + else: + (length_offset,) = next(compressed_data) + + length = (length_offset >> 12) + 3 + index = (length_offset & 0xFFF) + 1 + offset = idx - index + + if not (3 <= length <= 18): + log.error(f"Invalid length: {length}, corrupt data?") + + if not (1 <= index <= 4096): + log.error(f"Invalid index: {index}, corrupt data?") + + for i in range(length): + ret[idx] = ret[offset + i] + idx += 1 + + current_mask <<= 1 + mask_bit_counter -= 1 + + return ret + + +class Mio0Decompressor(GenericMio0Decompressor): + def __init__(self): + super().__init__( + unpacked_offset=4, + compressed_offset=8, + uncompressed_offset=12, + header_length=16, + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("infile") + parser.add_argument("outfile") + args = parser.parse_args() + + with open(args.infile, "rb") as f: + raw_bytes = f.read() + + miodecompress = Mio0Decompressor() + decompressed = miodecompress.decompress(raw_bytes) + + with open(args.outfile, "wb") as f: + f.write(decompressed) + + +if __name__ == "__main__": + main() diff --git a/tools/splat/util/n64/Yay0decompress.c b/tools/splat/util/n64/Yay0decompress.c new file mode 100644 index 00000000..250f3476 --- /dev/null +++ b/tools/splat/util/n64/Yay0decompress.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef struct { + uint32_t magic; + uint32_t uncompressedLength; + uint32_t opPtr; + uint32_t dataPtr; +} Yay0Header; + +void decompress(Yay0Header* hdr, uint8_t* srcPtr, uint8_t* dstPtr, bool isBigEndian) { + uint8_t byte = 0, mask = 0; + uint8_t* ctrl, * ops, * data; + uint16_t copy, op; + uint32_t written = 0; + + ctrl = srcPtr + sizeof(Yay0Header); + ops = srcPtr + hdr->opPtr; + data = srcPtr + hdr->dataPtr; + + while (written < hdr->uncompressedLength) { + if ((mask >>= 1) == 0) { + byte = *ctrl++; + mask = 0x80; + } + + if (byte & mask) { + *dstPtr++ = *data++; + written++; + } else { + op = isBigEndian ? (ops[0] << 8) | ops[1] : (ops[1] << 8) | ops[0]; + ops += 2; + + written += copy = (op >> 12) ? (2 + (op >> 12)) : (18 + *data++); + + while (copy--) { + *dstPtr = dstPtr[-(op & 0xfff) - 1]; + dstPtr++; + } + } + } +} diff --git a/tools/splat/util/n64/Yay0decompress.py b/tools/splat/util/n64/Yay0decompress.py new file mode 100644 index 00000000..ca24c236 --- /dev/null +++ b/tools/splat/util/n64/Yay0decompress.py @@ -0,0 +1,162 @@ +import argparse +import os +import sys +from ctypes import * +from struct import pack, unpack_from +from typing import Optional + +try: + from .. import log + from .decompressor import Decompressor +except ImportError: + print(f"Run as python3 -m util.n64.Yay0decompress") + sys.exit(1) + +tried_loading = False +lib: Optional[CDLL] = None + + +def setup_lib(): + global lib + global tried_loading + if lib: + return True + if tried_loading: + return False + try: + tried_loading = True + lib = cdll.LoadLibrary( + os.path.dirname(os.path.realpath(__file__)) + "/Yay0decompress" + ) + return True + except Exception: + log.write( + "Failed to load Yay0 C library; falling back to Python method", + status="warn", + ) + tried_loading = True + return False + + +class Yay0Decompressor(Decompressor): + def decompress(self, in_bytes, byte_order="big") -> bytearray: + # attempt to load the library only once per execution + global lib + if not setup_lib(): + return self.decompress_python(in_bytes, byte_order) + assert lib is not None + + class Yay0(Structure): + _fields_ = [ + ("magic", c_uint32), + ("uncompressedLength", c_uint32), + ("opPtr", c_uint32), + ("dataPtr", c_uint32), + ] + + # read the file header + bigEndian = byte_order == "big" + if bigEndian: + # the struct is only a view, so when passed to C it will keep + # its BigEndian values and crash. Explicitly convert them here to little + hdr = Yay0.from_buffer_copy( + pack("IIII", in_bytes, 0)) + ) + else: + hdr = Yay0.from_buffer_copy(in_bytes, 0) + + magic = getattr(hdr, hdr._fields_[0][0]) + if magic != int.from_bytes(str.encode("Yay0"), byteorder="big"): + log.error(f"Yay0 magic is incorrect: {magic}") + + # create the input/output buffers, copying data to in + src = (c_uint8 * len(in_bytes)).from_buffer_copy(in_bytes, 0) + dst = (c_uint8 * hdr.uncompressedLength)() + + # call decompress, equivilant to, in C: + # decompress(&hdr, &src, &dst, bigEndian) + lib.decompress(byref(hdr), byref(src), byref(dst), c_bool(bigEndian)) + + # other functions want the results back as a non-ctypes type + return bytearray(dst) + + @staticmethod + def decompress_python(in_bytes, byte_order="big"): + if in_bytes[:4] != b"Yay0": + log.error("Input file is not Yay0") + + decompressed_size = int.from_bytes(in_bytes[4:8], byteorder=byte_order) + link_table_offset = int.from_bytes(in_bytes[8:12], byteorder=byte_order) + chunk_offset = int.from_bytes(in_bytes[12:16], byteorder=byte_order) + + link_table_idx = link_table_offset + chunk_idx = chunk_offset + other_idx = 16 + + mask_bit_counter = 0 + current_mask = 0 + + # preallocate result and index into it + idx = 0 + ret = bytearray(decompressed_size) + + while idx < decompressed_size: + # If we're out of bits, get the next mask + if mask_bit_counter == 0: + current_mask = int.from_bytes( + in_bytes[other_idx : other_idx + 4], byteorder=byte_order + ) + other_idx += 4 + mask_bit_counter = 32 + + if current_mask & 0x80000000: + ret[idx] = in_bytes[chunk_idx] + idx += 1 + chunk_idx += 1 + else: + link = int.from_bytes( + in_bytes[link_table_idx : link_table_idx + 2], byteorder=byte_order + ) + link_table_idx += 2 + + offset = idx - (link & 0xFFF) + + count = link >> 12 + + if count == 0: + count_modifier = in_bytes[chunk_idx] + chunk_idx += 1 + count = count_modifier + 18 + else: + count += 2 + + # Copy the block + for i in range(count): + ret[idx] = ret[offset + i - 1] + idx += 1 + + current_mask <<= 1 + mask_bit_counter -= 1 + + return ret + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("infile") + parser.add_argument("outfile") + parser.add_argument("--byte-order", default="big", choices=["big", "little"]) + args = parser.parse_args() + + with open(args.infile, "rb") as f: + raw_bytes = f.read() + + yay0decompressor = Yay0Decompressor() + decompressed = yay0decompressor.decompress(raw_bytes, args.byte_order) + + with open(args.outfile, "wb") as f: + f.write(decompressed) + + +if __name__ == "__main__": + main() diff --git a/tools/splat/util/n64/__init__.py b/tools/splat/util/n64/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/splat/util/n64/decompressor.py b/tools/splat/util/n64/decompressor.py new file mode 100644 index 00000000..cc5ddb8f --- /dev/null +++ b/tools/splat/util/n64/decompressor.py @@ -0,0 +1,7 @@ +from abc import ABC, abstractmethod + + +class Decompressor(ABC): + @abstractmethod + def decompress(self, in_bytes, byte_order="big") -> bytearray: + pass diff --git a/tools/splat/util/n64/find_code_length.py b/tools/splat/util/n64/find_code_length.py new file mode 100755 index 00000000..1f9053ca --- /dev/null +++ b/tools/splat/util/n64/find_code_length.py @@ -0,0 +1,63 @@ +#! /usr/bin/env python3 + +import argparse + +import rabbitizer +import spimdisasm + + +def int_any_base(x): + return int(x, 0) + + +parser = argparse.ArgumentParser( + description="Given a rom and start offset, find where the code ends" +) +parser.add_argument("rom", help="path to a .z64 rom") +parser.add_argument("start", help="start offset", type=int_any_base) +parser.add_argument("--end", help="end offset", default=None, type=int_any_base) +parser.add_argument( + "--vram", + help="vram address to start disassembly at", + default="0x80000000", + type=int_any_base, +) + + +def run(rom_bytes, start_offset, vram, end_offset=None): + rom_addr = start_offset + last_return = rom_addr + + wordList = spimdisasm.common.Utils.bytesToBEWords(rom_bytes[start_offset:]) + for word in wordList: + insn = rabbitizer.Instruction(word) + if not insn.isImplemented(): + break + + if insn.isJrRa(): + last_return = rom_addr + rom_addr += 4 + if end_offset and rom_addr >= end_offset: + break + + # align to next 0x10 boundary + end = last_return + 0x10 + end -= end % 0x10 + return end + + +def main(): + args = parser.parse_args() + + with open(args.rom, "rb") as f: + rom_bytes = f.read() + + start = args.start + end = args.end + vram = args.vram + + print(f"0x{run(rom_bytes, start, vram, end):X}") + + +if __name__ == "__main__": + main() diff --git a/tools/splat/util/n64/rominfo.py b/tools/splat/util/n64/rominfo.py new file mode 100755 index 00000000..fae1fee3 --- /dev/null +++ b/tools/splat/util/n64/rominfo.py @@ -0,0 +1,322 @@ +#! /usr/bin/env python3 + +import argparse + +import hashlib +import itertools +import struct + +import sys +import zlib +from dataclasses import dataclass + +from pathlib import Path +from typing import Optional + +import rabbitizer +import spimdisasm + +parser = argparse.ArgumentParser(description="Gives information on N64 roms") +parser.add_argument("rom", help="path to an N64 rom") +parser.add_argument( + "--header-encoding", + dest="header_encoding", + help=( + "Text encoding the game header is using;" + " see docs.python.org/3/library/codecs.html#standard-encodings for valid encodings" + ), +) + +country_codes = { + 0x00: "Unknown", + 0x37: "Beta", + 0x41: "Asian (NTSC)", + 0x42: "Brazillian", + 0x43: "Chiniese", + 0x44: "German", + 0x45: "North America", + 0x46: "French", + 0x47: "Gateway 64 (NTSC)", + 0x48: "Dutch", + 0x49: "Italian", + 0x4A: "Japanese", + 0x4B: "Korean", + 0x4C: "Gateway 64 (PAL)", + 0x4E: "Canadian", + 0x50: "European (basic spec.)", + 0x53: "Spanish", + 0x55: "Australian", + 0x57: "Scandanavian", + 0x58: "European", + 0x59: "European", +} + + +@dataclass +class CIC: + ntsc_name: str + pal_name: str + offset: int + + +crc_to_cic = { + 0x6170A4A1: CIC("6101", "7102", 0x000000), + 0x90BB6CB5: CIC("6102", "7101", 0x000000), + 0x0B050EE0: CIC("6103", "7103", 0x100000), + 0x98BC2C86: CIC("6105", "7105", 0x000000), + 0xACC8580A: CIC("6106", "7106", 0x200000), +} +unknown_cic = CIC("unknown", "unknown", 0x0000000) + + +@dataclass +class N64EntrypointInfo: + entry_size: int + bss_start_address: Optional[int] + bss_size: Optional[int] + main_address: Optional[int] + stack_top: int + + @staticmethod + def parse_rom_bytes( + rom_bytes, offset: int = 0x1000, size: int = 0x60 + ) -> "N64EntrypointInfo": + word_list = spimdisasm.common.Utils.bytesToWords( + rom_bytes, offset, offset + size + ) + nops_count = 0 + + register_values = [0 for _ in range(32)] + + register_bss_address: Optional[int] = None + register_bss_size: Optional[int] = None + register_main_address: Optional[int] = None + + size = 0 + for word in word_list: + insn = rabbitizer.Instruction(word) + if not insn.isImplemented(): + break + + if insn.isNop(): + nops_count += 1 + elif nops_count >= 3: + break + elif insn.canBeHi(): + register_values[insn.rt.value] = insn.getProcessedImmediate() << 16 + elif insn.canBeLo(): + if insn.isLikelyHandwritten(): + # Try to skip this instructions: + # addi $t0, $t0, 0x8 + # addi $t1, $t1, -0x8 + pass + elif insn.modifiesRt(): + register_values[insn.rt.value] = ( + register_values[insn.rs.value] + insn.getProcessedImmediate() + ) + elif insn.doesStore(): + if insn.rt == rabbitizer.RegGprO32.zero: + # Try to detect the zero-ing bss algorithm + # sw $zero, 0x0($t0) + register_bss_address = insn.rs.value + elif insn.isBranch(): + # lui $t1, 0x2 + # addiu $t1, $t1, -0x7220 + # ... + # addi $t1, $t1, -0x8 + # ... + # bnez $t1, label + register_bss_size = insn.rs.value + + elif insn.isJumptableJump() or insn.isReturn(): + # lui $t2, 0x8000 + # addiu $t2, $t2, 0x494 + # ... + # jr $t2 + register_main_address = insn.rs.value + + # print(f"{word:08X}", insn) + size += 4 + + # for i, val in enumerate(register_values): + # print(i, f"{val:08X}") + + bss_address = ( + register_values[register_bss_address] + if register_bss_address is not None + else None + ) + bss_size = ( + register_values[register_bss_size] + if register_bss_size is not None + else None + ) + main_address = ( + register_values[register_main_address] + if register_main_address is not None + else None + ) + stack_top = register_values[rabbitizer.RegGprO32.sp.value] + return N64EntrypointInfo(size, bss_address, bss_size, main_address, stack_top) + + +@dataclass +class N64Rom: + name: str + header_encoding: str + country_code: int + libultra_version: str + checksum: str + cic: CIC + entry_point: int + size: int + compiler: str + sha1: str + entrypoint_info: N64EntrypointInfo + + def get_country_name(self) -> str: + return country_codes[self.country_code] + + +def swap_bytes(data): + return bytes( + itertools.chain.from_iterable( + struct.pack(">H", x) for (x,) in struct.iter_unpack(" N64Rom: + if rom_bytes is None: + rom_bytes = read_rom(rom_path) + + if header_encoding is None: + header_encoding = guess_header_encoding(rom_bytes) + + return get_info_bytes(rom_bytes, header_encoding) + + +def get_info_bytes(rom_bytes: bytes, header_encoding: str) -> N64Rom: + (program_counter,) = struct.unpack(">I", rom_bytes[0x8:0xC]) + libultra_version = chr(rom_bytes[0xF]) + checksum = rom_bytes[0x10:0x18].hex().upper() + + try: + name = rom_bytes[0x20:0x34].decode(header_encoding).strip() + except: + sys.exit( + "splat could not decode the game name;" + " try using a different encoding by passing the --header-encoding argument" + " (see docs.python.org/3/library/codecs.html#standard-encodings for valid encodings)" + ) + + country_code = rom_bytes[0x3E] + + cic = get_cic(rom_bytes) + entry_point = get_entry_point(program_counter, cic) + + compiler = get_compiler_info(rom_bytes, entry_point, print_result=False) + + sha1 = hashlib.sha1(rom_bytes).hexdigest() + + entrypoint_info = N64EntrypointInfo.parse_rom_bytes(rom_bytes) + + return N64Rom( + name, + header_encoding, + country_code, + libultra_version, + checksum, + cic, + entry_point, + len(rom_bytes), + compiler, + sha1, + entrypoint_info, + ) + + +def get_compiler_info(rom_bytes, entry_point, print_result=True): + jumps = 0 + branches = 0 + + word_list = spimdisasm.common.Utils.bytesToWords(rom_bytes[0x1000:]) + for word in word_list: + insn = rabbitizer.Instruction(word) + if not insn.isImplemented(): + break + + if insn.uniqueId == rabbitizer.InstrId.cpu_j: + jumps += 1 + elif insn.uniqueId == rabbitizer.InstrId.cpu_b: + branches += 1 + + compiler = "IDO" if branches > jumps else "GCC" + if print_result: + print( + f"{branches} branches and {jumps} jumps detected in the first code segment." + f" Compiler is most likely {compiler}" + ) + return compiler + + +def main(): + rabbitizer.config.pseudos_pseudoB = True + + args = parser.parse_args() + rom_bytes = read_rom(Path(args.rom)) + rom = get_info(Path(args.rom), rom_bytes, args.header_encoding) + + print("Image name: " + rom.name) + print("Country code: " + chr(rom.country_code) + " - " + rom.get_country_name()) + print("Libultra version: " + rom.libultra_version) + print("Checksum: " + rom.checksum) + print("CIC: " + rom.cic.ntsc_name + " / " + rom.cic.pal_name) + print("RAM entry point: " + hex(rom.entry_point)) + print("Header encoding: " + rom.header_encoding) + print("") + + get_compiler_info(rom_bytes, rom.entry_point) + + +if __name__ == "__main__": + main() diff --git a/tools/splat/util/options.py b/tools/splat/util/options.py new file mode 100644 index 00000000..a8a3ebad --- /dev/null +++ b/tools/splat/util/options.py @@ -0,0 +1,422 @@ +from dataclasses import dataclass +from pathlib import Path +from typing import cast, Dict, List, Literal, Mapping, Optional, Set, Type, TypeVar + +from util import compiler +from util.compiler import Compiler + + +@dataclass +class SplatOpts: + # Debug / logging + verbose: bool + dump_symbols: bool + modes: List[str] + + # Project configuration + + # Determines the base path of the project. Everything is relative to this path + base_path: Path + # Determines the path to the target binary + target_path: Path + # Determines the platform of the target binary + platform: str + # Determines the compiler used to compile the target binary + compiler: Compiler + # Determines the endianness of the target binary + endianness: Literal["big", "little"] + # Determines the default section order of the target binary + # this can be overridden per-segment + section_order: List[str] + # Determines the code that is inserted by default in generated .c files + generated_c_preamble: str + # Determines the code that is inserted by default in generated .s files + generated_s_preamble: str + # Determines whether to use .o as the suffix for all binary files?... TODO document + use_o_as_suffix: bool + # the value of the $gp register to correctly calculate offset to %gp_rel relocs + gp: Optional[int] + + # Paths + asset_path: Path + # Determines the path to the symbol addresses file(s) + # A symbol_addrs file is to be updated/curated manually and contains addresses of symbols + # as well as optional metadata such as rom address, type, and more + # + # It's possible to use more than one file by supplying a list instead of a string + symbol_addrs_paths: List[Path] + reloc_addrs_paths: List[Path] + # Determines the path to the project build directory + build_path: Path + # Determines the path to the source code directory + src_path: Path + # Determines the path to the asm code directory + asm_path: Path + # Determines the path to the asm data directory + data_path: Path + # Determines the path to the asm nonmatchings directory + nonmatchings_path: Path + # Determines the path to the cache file (used when supplied --use-cache via the CLI) + cache_path: Path + + # Determines whether to create an automatically-generated undefined functions file + # this file stores all functions that are referenced in the code but are not defined as seen by splat + create_undefined_funcs_auto: bool + # Determines the path to the undefined_funcs_auto file + undefined_funcs_auto_path: Path + + # Determines whether to create an automatically-generated undefined symbols file + # this file stores all symbols that are referenced in the code but are not defined as seen by splat + create_undefined_syms_auto: bool + # Determines the path to the undefined_symbols_auto file + undefined_syms_auto_path: Path + + # Determines the path in which to search for custom splat extensions + extensions_path: Optional[Path] + + # Determines the path to library files that are to be linked into the target binary + lib_path: Path + + # TODO document + elf_section_list_path: Optional[Path] + + # Linker script + # Determines the default subalign value to be specified in the generated linker script + subalign: int + # The following option determines whether to automatically configure the linker script to link against + # specified sections for all "base" (asm/c) files when the yaml doesn't have manual configurations + # for these sections. + auto_all_sections: List[str] + # Determines the desired path to the linker script that splat will generate + ld_script_path: Path + # Determines the desired path to the linker symbol header, + # which exposes externed definitions for all segment ram/rom start/end locations + ld_symbol_header_path: Optional[Path] + # Determines whether to add a discard section to the linker script + ld_discard_section: bool + # Determines the list of section labels that are to be added to the linker script + ld_section_labels: List[str] + # Determines whether to add wildcards for section linking in the linker script (.rodata* for example) + ld_wildcard_sections: bool + # Determines whether to use use "follows" settings to determine locations of overlays in the linker script. + # If disabled, this effectively ignores "follows" directives in the yaml. + ld_use_follows: bool + + ################################################################################ + # C file options + ################################################################################ + # Determines whether to create new c files if they don't exist + create_c_files: bool + # Determines whether to "auto-decompile" empty functions + auto_decompile_empty_functions: bool + # Determines whether to detect matched/unmatched functions in existing c files + # so we can avoid creating .s files for already-decompiled functions + do_c_func_detection: bool + # Determines the newline char(s) to be used in c files + c_newline: str + + ################################################################################ + # (Dis)assembly-related options + ################################################################################ + # The following options determine the format that symbols should be named by default + symbol_name_format: str + # Same as above but for symbols with no rom address + symbol_name_format_no_rom: str + # Determines whether to detect and hint to the user about likely file splits when disassembling + find_file_boundaries: bool + # Determines whether to detect and hint to the user about possible rodata sections corresponding to a text section + pair_rodata_to_text: bool + # Determines whether to attempt to automatically migrate rodata into functions + # (only works in certain circumstances) + migrate_rodata_to_functions: bool + # Determines the header to be used in every asm file that's included from c files + asm_inc_header: str + # Determines the macro used to declare functions in asm files + asm_function_macro: str + # Determines the macro used to declare jumptable labels in asm files + asm_jtbl_label_macro: str + # Determines the macro used to declare data symbols in asm files + asm_data_macro: str + # Determines the macro used at the end of a function, such as endlabel or .end + asm_end_label: str + # Determines including the macro.inc file on non-migrated rodata variables + include_macro_inc: bool + # Determines the number of characters to left align before the TODO finish documenting + mnemonic_ljust: int + # Determines whether to pad the rom address + rom_address_padding: bool + # Determines which ABI names to use for general purpose registers + mips_abi_gpr: str + # Determines which ABI names to use for floating point registers + # Valid values: 'numeric', 'o32', 'n32', 'n64' + # o32 is highly recommended, as it provides logically named registers for floating point instructions + # For more info, see https://gist.github.com/EllipticEllipsis/27eef11205c7a59d8ea85632bc49224d + mips_abi_float_regs: str + # Determines whether to ad ".set gp=64 to asm/hasm files" + add_set_gp_64: bool + # Generate .asmproc.d dependency files for each C file which still reference functions in assembly files + create_asm_dependencies: bool + # Global option for rodata string encoding. This can be overriden per segment + string_encoding: Optional[str] + # Global option for allowing data symbols using addends on symbol references. It can be overriden per symbol + allow_data_addends: bool + + ################################################################################ + # N64-specific options + ################################################################################ + # Determines the encoding of the header + header_encoding: str + # Determines the type gfx ucode (used by gfx segments) + # Valid options are ['f3d', 'f3db', 'f3dex', 'f3dexb', 'f3dex2'] + gfx_ucode: str + # Use named libultra symbols by default. Those will need to be added to a linker script manually by the user + libultra_symbols: bool + # Use named hardware register symbols by default. Those will need to be added to a linker script manually by the user + hardware_regs: bool + + ################################################################################ + # Gamecube-specific options + ################################################################################ + # Path where the iso's filesystem will be extracted to + filesystem_path: Optional[Path] + + ################################################################################ + # Compiler-specific options + ################################################################################ + # Determines whether to use a legacy INCLUDE_ASM macro format in c files + # only applies to GCC/SN64 + use_legacy_include_asm: bool + + # Returns whether the given mode is currently enabled + def is_mode_active(self, mode: str) -> bool: + return mode in self.modes or "all" in self.modes + + +opts: SplatOpts + + +T = TypeVar("T") + + +class OptParser: + _read_opts: Set[str] + + def __init__(self, yaml: Mapping[str, object]) -> None: + self._yaml = yaml + self._read_opts = set() + + def parse_opt(self, opt: str, t: Type[T], default: Optional[T] = None) -> T: + if opt not in self._yaml: + if default is not None: + return default + raise ValueError(f"Missing required option {opt}") + self._read_opts.add(opt) + value = self._yaml[opt] + if isinstance(value, t): + return value + if t is float and isinstance(value, int): + return cast(T, float(value)) + raise ValueError(f"Expected {opt} to have type {t}, got {type(value)}") + + def parse_optional_opt(self, opt: str, t: Type[T]) -> Optional[T]: + if opt not in self._yaml: + return None + return self.parse_opt(opt, t) + + def parse_opt_within( + self, opt: str, t: Type[T], within: List[T], default: Optional[T] = None + ) -> T: + value = self.parse_opt(opt, t, default) + if value not in within: + raise ValueError(f"Invalid value for {opt}: {value}") + return value + + def parse_path( + self, base_path: Path, opt: str, default: Optional[str] = None + ) -> Path: + return base_path / Path(self.parse_opt(opt, str, default)) + + def parse_optional_path(self, base_path: Path, opt: str) -> Optional[Path]: + if opt not in self._yaml: + return None + return self.parse_path(base_path, opt) + + def parse_path_list(self, base_path: Path, opt: str, default: str) -> List[Path]: + paths = self.parse_opt(opt, object, default) + + if isinstance(paths, str): + return [base_path / paths] + elif isinstance(paths, list): + return [base_path / path for path in paths] + else: + raise ValueError(f"Expected str or list for '{opt}', got {type(paths)}") + + def check_no_unread_opts(self) -> None: + opts = [opt for opt in self._yaml if opt not in self._read_opts] + if opts: + raise ValueError(f"Unrecognized YAML option(s): {', '.join(opts)}") + + +def _parse_yaml( + yaml: Dict, + config_paths: List[str], + modes: List[str], + verbose: bool = False, +) -> SplatOpts: + p = OptParser(yaml) + + basename = p.parse_opt("basename", str) + platform = p.parse_opt_within("platform", str, ["n64", "psx", "gc", "ps2"]) + comp = compiler.for_name(p.parse_opt("compiler", str, "IDO")) + + base_path = Path(config_paths[0]).parent / p.parse_opt("base_path", str) + asm_path: Path = p.parse_path(base_path, "asm_path", "asm") + + def parse_endianness() -> Literal["big", "little"]: + endianness = p.parse_opt_within( + "endianness", + str, + ["big", "little"], + "little" if platform in ["psx", "ps2"] else "big", + ) + + if endianness == "big": + return "big" + elif endianness == "little": + return "little" + else: + raise ValueError(f"Invalid endianness: {endianness}") + + ret = SplatOpts( + verbose=verbose, + dump_symbols=p.parse_opt("dump_symbols", bool, False), + modes=modes, + base_path=base_path, + target_path=p.parse_path(base_path, "target_path"), + platform=platform, + compiler=comp, + endianness=parse_endianness(), + section_order=p.parse_opt( + "section_order", list, [".text", ".data", ".rodata", ".bss"] + ), + generated_c_preamble=p.parse_opt( + "generated_c_preamble", str, '#include "common.h"' + ), + generated_s_preamble=p.parse_opt("generated_s_preamble", str, ""), + use_o_as_suffix=p.parse_opt("o_as_suffix", bool, False), + gp=p.parse_opt("gp_value", int, 0), + asset_path=p.parse_path(base_path, "asset_path", "assets"), + symbol_addrs_paths=p.parse_path_list( + base_path, "symbol_addrs_path", "symbol_addrs.txt" + ), + reloc_addrs_paths=p.parse_path_list( + base_path, "reloc_addrs_path", "reloc_addrs.txt" + ), + build_path=p.parse_path(base_path, "build_path", "build"), + src_path=p.parse_path(base_path, "src_path", "src"), + asm_path=asm_path, + data_path=p.parse_path(asm_path, "data_path", "data"), + nonmatchings_path=p.parse_path(asm_path, "nonmatchings_path", "nonmatchings"), + cache_path=p.parse_path(base_path, "cache_path", ".splache"), + create_undefined_funcs_auto=p.parse_opt( + "create_undefined_funcs_auto", bool, True + ), + undefined_funcs_auto_path=p.parse_path( + base_path, "undefined_funcs_auto_path", "undefined_funcs_auto.txt" + ), + create_undefined_syms_auto=p.parse_opt( + "create_undefined_syms_auto", bool, True + ), + undefined_syms_auto_path=p.parse_path( + base_path, "undefined_syms_auto_path", "undefined_syms_auto.txt" + ), + extensions_path=p.parse_optional_path(base_path, "extensions_path"), + lib_path=p.parse_path(base_path, "lib_path", "lib"), + elf_section_list_path=p.parse_optional_path(base_path, "elf_section_list_path"), + subalign=p.parse_opt("subalign", int, 16), + auto_all_sections=p.parse_opt( + "auto_all_sections", list, [".data", ".rodata", ".bss"] + ), + ld_script_path=p.parse_path(base_path, "ld_script_path", f"{basename}.ld"), + ld_symbol_header_path=p.parse_optional_path(base_path, "ld_symbol_header_path"), + ld_discard_section=p.parse_opt("ld_discard_section", bool, True), + ld_section_labels=p.parse_opt( + "ld_section_labels", + list, + [".text", ".data", ".rodata", ".bss"], + ), + ld_wildcard_sections=p.parse_opt("ld_wildcard_sections", bool, False), + ld_use_follows=p.parse_opt("ld_use_follows", bool, True), + create_c_files=p.parse_opt("create_c_files", bool, True), + auto_decompile_empty_functions=p.parse_opt( + "auto_decompile_empty_functions", bool, True + ), + do_c_func_detection=p.parse_opt("do_c_func_detection", bool, True), + c_newline=p.parse_opt("c_newline", str, comp.c_newline), + symbol_name_format=p.parse_opt("symbol_name_format", str, "$VRAM"), + symbol_name_format_no_rom=p.parse_opt( + "symbol_name_format_no_rom", str, "$VRAM_$SEG" + ), + find_file_boundaries=p.parse_opt("find_file_boundaries", bool, True), + pair_rodata_to_text=p.parse_opt("pair_rodata_to_text", bool, True), + migrate_rodata_to_functions=p.parse_opt( + "migrate_rodata_to_functions", bool, True + ), + asm_inc_header=p.parse_opt("asm_inc_header", str, comp.asm_inc_header), + asm_function_macro=p.parse_opt( + "asm_function_macro", str, comp.asm_function_macro + ), + asm_jtbl_label_macro=p.parse_opt( + "asm_jtbl_label_macro", str, comp.asm_jtbl_label_macro + ), + asm_data_macro=p.parse_opt("asm_data_macro", str, comp.asm_data_macro), + asm_end_label=p.parse_opt("asm_end_label", str, comp.asm_end_label), + include_macro_inc=p.parse_opt( + "include_macro_inc", bool, comp.include_macro_inc + ), + mnemonic_ljust=p.parse_opt("mnemonic_ljust", int, 11), + rom_address_padding=p.parse_opt("rom_address_padding", bool, False), + mips_abi_gpr=p.parse_opt_within( + "mips_abi_gpr", + str, + ["numeric", "o32", "n32", "n64"], + "o32", + ), + mips_abi_float_regs=p.parse_opt_within( + "mips_abi_float_regs", + str, + ["numeric", "o32", "n32", "n64"], + "numeric", + ), + add_set_gp_64=p.parse_opt("add_set_gp_64", bool, True), + create_asm_dependencies=p.parse_opt("create_asm_dependencies", bool, False), + string_encoding=p.parse_optional_opt("string_encoding", str), + allow_data_addends=p.parse_opt("allow_data_addends", bool, True), + header_encoding=p.parse_opt("header_encoding", str, "ASCII"), + gfx_ucode=p.parse_opt_within( + "gfx_ucode", + str, + ["f3d", "f3db", "f3dex", "f3dexb", "f3dex2"], + "f3dex2", + ), + libultra_symbols=p.parse_opt("libultra_symbols", bool, False), + hardware_regs=p.parse_opt("hardware_regs", bool, False), + use_legacy_include_asm=p.parse_opt("use_legacy_include_asm", bool, True), + filesystem_path=p.parse_optional_path(base_path, "filesystem_path"), + ) + p.check_no_unread_opts() + return ret + + +def initialize( + config: Dict, + config_paths: List[str], + modes: Optional[List[str]] = None, + verbose=False, +): + global opts + + if not modes: + modes = ["all"] + + opts = _parse_yaml(config["options"], config_paths, modes, verbose) diff --git a/tools/splat/util/palettes.py b/tools/splat/util/palettes.py new file mode 100644 index 00000000..8ee1e9a0 --- /dev/null +++ b/tools/splat/util/palettes.py @@ -0,0 +1,34 @@ +from typing import Dict + +from segtypes.common.group import CommonSegGroup +from segtypes.n64.ci import N64SegCi +from segtypes.n64.palette import N64SegPalette as Palette + + +# Resolve Raster#palette and Palette#raster links +def initialize(all_segments): + def process(segments): + raster_map: Dict[str, N64SegCi] = {} + palette_map: Dict[str, Palette] = {} + + for segment in segments: + if isinstance(segment, Palette): + palette_map[segment.name] = segment + + if isinstance(segment, N64SegCi): + raster_map[segment.name] = segment + + if isinstance(segment, CommonSegGroup): + process(segment.subsegments) + + for raster_name in raster_map: + raster = raster_map[raster_name] + # print(f"{raster_name} -> {raster.palette_name}") + raster.palette = palette_map.get(raster.palette_name) + + for palette_name in palette_map: + palette = palette_map[palette_name] + # print(f"{palette_name} -> {palette.raster_name}") + palette.raster = raster_map.get(palette.raster_name) + + process(all_segments) diff --git a/tools/splat/util/range.py b/tools/splat/util/range.py new file mode 100644 index 00000000..04aea6e3 --- /dev/null +++ b/tools/splat/util/range.py @@ -0,0 +1,17 @@ +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class Range: + start: Optional[int] = None + end: Optional[int] = None + + def has_start(self): + return self.start is not None + + def has_end(self): + return self.end is not None + + def is_complete(self): + return self.has_start() and self.has_end() diff --git a/tools/splat/util/relocs.py b/tools/splat/util/relocs.py new file mode 100644 index 00000000..36cdb653 --- /dev/null +++ b/tools/splat/util/relocs.py @@ -0,0 +1,125 @@ +from dataclasses import dataclass +from typing import Dict + +import spimdisasm +import tqdm +from intervaltree import Interval, IntervalTree + +from util import log, options, symbols + + +@dataclass +class Reloc: + rom_address: int + reloc_type: str + symbol_name: str + + addend: int = 0 + + +all_relocs: Dict[int, Reloc] = {} + + +def add_reloc(reloc: Reloc): + all_relocs[reloc.rom_address] = reloc + + +def initialize(): + global all_relocs + + all_relocs = {} + + for path in options.opts.reloc_addrs_paths: + if not path.exists(): + continue + + with path.open() as f: + sym_addrs_lines = f.readlines() + for line_num, line in enumerate( + tqdm.tqdm(sym_addrs_lines, desc=f"Loading relocs ({path.stem})") + ): + line = line.strip() + # Allow comments + line = line.split("//")[0] + line = line.strip() + + if line == "": + continue + + rom_addr = None + reloc_type = None + symbol_name = None + addend = None + + for info in line.split(" "): + if ":" not in info: + continue + + if info.count(":") > 1: + log.parsing_error_preamble(path, line_num, line) + log.write(f"Too many ':'s in '{info}'") + log.error("") + + attr_name, attr_val = info.split(":") + if attr_name == "": + log.parsing_error_preamble(path, line_num, line) + log.write( + f"Missing attribute name in '{info}', is there extra whitespace?" + ) + log.error("") + if attr_val == "": + log.parsing_error_preamble(path, line_num, line) + log.write( + f"Missing attribute value in '{info}', is there extra whitespace?" + ) + log.error("") + + # Non-Boolean attributes + try: + if attr_name == "rom": + rom_addr = int(attr_val, 0) + continue + if attr_name == "reloc": + reloc_type = attr_val + continue + if attr_name == "symbol": + symbol_name = attr_val + continue + if attr_name == "addend": + addend = int(attr_val, 0) + continue + except: + log.parsing_error_preamble(path, line_num, line) + log.write(f"value of attribute '{attr_name}' could not be read:") + log.write("") + raise + + if rom_addr is None: + log.parsing_error_preamble(path, line_num, line) + log.error(f"Missing required 'rom' attribute for reloc") + if reloc_type is None: + log.parsing_error_preamble(path, line_num, line) + log.error(f"Missing required 'reloc' attribute for reloc") + if symbol_name is None: + log.parsing_error_preamble(path, line_num, line) + log.error(f"Missing required 'symbol' attribute for reloc") + + reloc = Reloc(rom_addr, reloc_type, symbol_name) + if addend is not None: + reloc.addend = addend + + add_reloc(reloc) + + +def initialize_spim_context(): + for rom_address, reloc in all_relocs.items(): + reloc_type = spimdisasm.common.RelocType.fromStr(reloc.reloc_type) + + if reloc_type is None: + log.error( + f"Reloc type '{reloc.reloc_type}' is not valid. Rom address: 0x{rom_address:X}" + ) + + symbols.spim_context.addGlobalReloc( + rom_address, reloc_type, reloc.symbol_name, addend=reloc.addend + ) diff --git a/tools/splat/util/symbols.py b/tools/splat/util/symbols.py new file mode 100644 index 00000000..07db03c1 --- /dev/null +++ b/tools/splat/util/symbols.py @@ -0,0 +1,640 @@ +from dataclasses import dataclass +import re +from typing import Dict, List, Optional, Set, TYPE_CHECKING + +import spimdisasm +import tqdm +from intervaltree import IntervalTree + +# circular import +if TYPE_CHECKING: + from segtypes.segment import Segment + +from util import log, options + +all_symbols: List["Symbol"] = [] +all_symbols_dict: Dict[int, List["Symbol"]] = {} +all_symbols_ranges = IntervalTree() +ignored_addresses: Set[int] = set() +to_mark_as_defined: Set[str] = set() +appears_after_overlays_syms: List["Symbol"] = [] + +# Initialize a spimdisasm context, used to store symbols and functions +spim_context = spimdisasm.common.Context() + +TRUEY_VALS = ["true", "on", "yes", "y"] +FALSEY_VALS = ["false", "off", "no", "n"] + +splat_sym_types = {"func", "jtbl", "jtbl_label", "label"} + + +def check_valid_type(typename: str) -> bool: + if typename[0].isupper(): + return True + + if typename in splat_sym_types: + return True + + if typename in spimdisasm.common.gKnownTypes: + return True + + return False + + +def is_truey(str: str) -> bool: + return str.lower() in TRUEY_VALS + + +def is_falsey(str: str) -> bool: + return str.lower() in FALSEY_VALS + + +def add_symbol(sym: "Symbol"): + all_symbols.append(sym) + if sym.vram_start is not None: + if sym.vram_start not in all_symbols_dict: + all_symbols_dict[sym.vram_start] = [] + all_symbols_dict[sym.vram_start].append(sym) + + # For larger symbols, add their ranges to interval trees for faster lookup + if sym.size > 4: + all_symbols_ranges.addi(sym.vram_start, sym.vram_end, sym) + + +def to_cname(symbol_name: str) -> str: + symbol_name = re.sub(r"[^0-9a-zA-Z_]", "_", symbol_name) + + if symbol_name[0] in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]: + symbol_name = "_" + symbol_name + + return symbol_name + + +def initialize(all_segments: "List[Segment]"): + global all_symbols + global all_symbols_dict + global all_symbols_ranges + + all_symbols = [] + all_symbols_dict = {} + all_symbols_ranges = IntervalTree() + + def get_seg_for_name(name: str) -> Optional["Segment"]: + for segment in all_segments: + if segment.name == name: + return segment + return None + + # Manual list of func name / addrs + for path in options.opts.symbol_addrs_paths: + if path.exists(): + with open(path) as f: + sym_addrs_lines = f.readlines() + for line_num, line in enumerate( + tqdm.tqdm(sym_addrs_lines, desc=f"Loading symbols ({path.stem})") + ): + line = line.strip() + if not line == "" and not line.startswith("//"): + comment_loc = line.find("//") + line_main = line + line_ext = "" + + if comment_loc != -1: + line_ext = line[comment_loc + 2 :].strip() + line_main = line[:comment_loc].strip() + + try: + line_split = line_main.split("=") + name = line_split[0].strip() + addr = int(line_split[1].strip()[:-1], 0) + except: + log.parsing_error_preamble(path, line_num, line) + log.write("Line should be of the form") + log.write( + " =

// attr0:val0 attr1:val1 [...]" + ) + log.write("with
in hex preceded by 0x, or dec") + log.write("") + raise + + sym = Symbol(addr, given_name=name) + + ignore_sym = False + if line_ext: + for info in line_ext.split(" "): + if ":" in info: + if info.count(":") > 1: + log.parsing_error_preamble(path, line_num, line) + log.write(f"Too many ':'s in '{info}'") + log.error("") + + attr_name, attr_val = info.split(":") + if attr_name == "": + log.parsing_error_preamble(path, line_num, line) + log.write( + f"Missing attribute name in '{info}', is there extra whitespace?" + ) + log.error("") + if attr_val == "": + log.parsing_error_preamble(path, line_num, line) + log.write( + f"Missing attribute value in '{info}', is there extra whitespace?" + ) + log.error("") + + # Non-Boolean attributes + try: + if attr_name == "type": + if not check_valid_type(attr_val): + log.parsing_error_preamble( + path, line_num, line + ) + log.write( + f"Unrecognized symbol type in '{info}', it should be one of" + ) + log.write( + [ + *splat_sym_types, + *spimdisasm.common.gKnownTypes, + ] + ) + log.write( + "You may use a custom type that starts with a capital letter" + ) + log.error("") + type = attr_val + sym.type = type + continue + if attr_name == "size": + size = int(attr_val, 0) + sym.given_size = size + continue + if attr_name == "rom": + rom_addr = int(attr_val, 0) + sym.rom = rom_addr + continue + if attr_name == "segment": + seg = get_seg_for_name(attr_val) + if seg is None: + log.parsing_error_preamble( + path, line_num, line + ) + log.write( + f"Cannot find segment '{attr_val}'" + ) + log.error("") + else: + # Add segment to symbol + sym.segment = seg + continue + if attr_name == "name_end": + sym.given_name_end = attr_val + continue + if attr_name == "appears_after_overlays_addr": + sym.appears_after_overlays_addr = int( + attr_val, 0 + ) + appears_after_overlays_syms.append(sym) + continue + except: + log.parsing_error_preamble(path, line_num, line) + log.write( + f"value of attribute '{attr_name}' could not be read:" + ) + log.write("") + raise + + # Boolean attributes + tf_val = ( + True + if is_truey(attr_val) + else False + if is_falsey(attr_val) + else None + ) + if tf_val is None: + log.parsing_error_preamble(path, line_num, line) + log.write( + f"Invalid Boolean value '{attr_val}' for attribute '{attr_name}', should be one of" + ) + log.write([*TRUEY_VALS, *FALSEY_VALS]) + log.error("") + else: + if attr_name == "dead": + sym.dead = tf_val + continue + if attr_name == "defined": + sym.defined = tf_val + continue + if attr_name == "extract": + sym.extract = tf_val + continue + if attr_name == "ignore": + ignore_sym = tf_val + continue + if attr_name == "force_migration": + sym.force_migration = tf_val + continue + if attr_name == "force_not_migration": + sym.force_not_migration = tf_val + continue + if attr_name == "allow_addend": + sym.allow_addend = tf_val + continue + if attr_name == "dont_allow_addend": + sym.dont_allow_addend = tf_val + continue + if ignore_sym: + if sym.given_size == None or sym.given_size == 0: + ignored_addresses.add(sym.vram_start) + else: + spim_context.addBannedSymbolRangeBySize( + sym.vram_start, sym.given_size + ) + + ignore_sym = False + continue + + if sym.segment: + sym.segment.add_symbol(sym) + + sym.user_declared = True + add_symbol(sym) + + +def initialize_spim_context(all_segments: "List[Segment]") -> None: + global_vrom_start = None + global_vrom_end = None + global_vram_start = None + global_vram_end = None + overlay_segments: Set[spimdisasm.common.SymbolsSegment] = set() + + spim_context.bannedSymbols |= ignored_addresses + + from segtypes.common.code import CommonSegCode + + for segment in all_segments: + if not isinstance(segment, CommonSegCode): + # We only care about the VRAMs of code segments + continue + + if segment.special_vram_segment: + # Special segments which should not be accounted in the global VRAM calculation, like N64's IPL3 + continue + + if ( + not isinstance(segment.vram_start, int) + or not isinstance(segment.vram_end, int) + or not isinstance(segment.rom_start, int) + or not isinstance(segment.rom_end, int) + ): + continue + + ram_id = segment.get_exclusive_ram_id() + if ram_id is None: + if global_vram_start is None: + global_vram_start = segment.vram_start + elif segment.vram_start < global_vram_start: + global_vram_start = segment.vram_start + + if global_vram_end is None: + global_vram_end = segment.vram_end + elif global_vram_end < segment.vram_end: + global_vram_end = segment.vram_end + + if global_vrom_start is None: + global_vrom_start = segment.rom_start + elif segment.rom_start < global_vrom_start: + global_vrom_start = segment.rom_start + + if global_vrom_end is None: + global_vrom_end = segment.rom_end + elif global_vrom_end < segment.rom_end: + global_vrom_end = segment.rom_end + + else: + spim_segment = spim_context.addOverlaySegment( + ram_id, + segment.rom_start, + segment.rom_end, + segment.vram_start, + segment.vram_end, + ) + # Add the segment-specific symbols first + for symbols_list in segment.seg_symbols.values(): + for sym in symbols_list: + add_symbol_to_spim_segment(spim_segment, sym) + + overlay_segments.add(spim_segment) + + if ( + global_vram_start is not None + and global_vram_end is not None + and global_vrom_start is not None + and global_vrom_end is not None + ): + spim_context.changeGlobalSegmentRanges( + global_vrom_start, global_vrom_end, global_vram_start, global_vram_end + ) + + # Check the vram range of the global segment does not overlap with any overlay segment + for ovl_segment in overlay_segments: + assert ( + ovl_segment.vramStart <= ovl_segment.vramEnd + ), f"{ovl_segment.vramStart:X} {ovl_segment.vramEnd:X}" + if ( + ovl_segment.vramEnd > global_vram_start + and global_vram_end > ovl_segment.vramStart + ): + log.write( + f"Warning: the vram range ([0x{ovl_segment.vramStart:X}, 0x{ovl_segment.vramEnd:X}]) of the non-global segment at rom address 0x{ovl_segment.vromStart:X} overlaps with the global vram range ([0x{global_vram_start:X}, 0x{global_vram_end:X}])", + status="warn", + ) + + # pass the global symbols to spimdisasm + for segment in all_segments: + if not isinstance(segment, CommonSegCode): + # We only care about the VRAMs of code segments + continue + + ram_id = segment.get_exclusive_ram_id() + if ram_id is not None: + continue + + for symbols_list in segment.seg_symbols.values(): + for sym in symbols_list: + add_symbol_to_spim_segment(spim_context.globalSegment, sym) + + +def add_symbol_to_spim_segment( + segment: spimdisasm.common.SymbolsSegment, sym: "Symbol" +) -> spimdisasm.common.ContextSymbol: + if sym.type == "func": + context_sym = segment.addFunction( + sym.vram_start, isAutogenerated=not sym.user_declared, vromAddress=sym.rom + ) + elif sym.type == "jtbl": + context_sym = segment.addJumpTable( + sym.vram_start, isAutogenerated=not sym.user_declared, vromAddress=sym.rom + ) + elif sym.type == "jtbl_label": + context_sym = segment.addJumpTableLabel( + sym.vram_start, isAutogenerated=not sym.user_declared, vromAddress=sym.rom + ) + elif sym.type == "label": + context_sym = segment.addBranchLabel( + sym.vram_start, isAutogenerated=not sym.user_declared, vromAddress=sym.rom + ) + else: + context_sym = segment.addSymbol( + sym.vram_start, isAutogenerated=not sym.user_declared, vromAddress=sym.rom + ) + if sym.type is not None: + context_sym.type = sym.type + + if sym.user_declared: + context_sym.isUserDeclared = True + if sym.defined: + context_sym.isDefined = True + if sym.rom is not None: + context_sym.vromAddress = sym.rom + if sym.given_size is not None: + context_sym.size = sym.size + if sym.force_migration: + context_sym.forceMigration = True + if sym.force_not_migration: + context_sym.forceNotMigration = True + if sym.allow_addend: + context_sym.allowedToReferenceAddends = True + if sym.dont_allow_addend: + context_sym.notAllowedToReferenceAddends = True + context_sym.setNameGetCallbackIfUnset(lambda _: sym.name) + if sym.given_name_end: + context_sym.nameEnd = sym.given_name_end + + return context_sym + + +def add_symbol_to_spim_section( + section: spimdisasm.mips.sections.SectionBase, sym: "Symbol" +) -> spimdisasm.common.ContextSymbol: + if sym.type == "func": + context_sym = section.addFunction( + sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom + ) + elif sym.type == "jtbl": + context_sym = section.addJumpTable( + sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom + ) + elif sym.type == "jtbl_label": + context_sym = section.addJumpTableLabel( + sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom + ) + elif sym.type == "label": + context_sym = section.addBranchLabel( + sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom + ) + else: + context_sym = section.addSymbol( + sym.vram_start, isAutogenerated=not sym.user_declared, symbolVrom=sym.rom + ) + if sym.type is not None: + context_sym.type = sym.type + + if sym.user_declared: + context_sym.isUserDeclared = True + if sym.defined: + context_sym.isDefined = True + if sym.rom is not None: + context_sym.vromAddress = sym.rom + if sym.given_size is not None: + context_sym.size = sym.size + if sym.force_migration: + context_sym.forceMigration = True + if sym.force_not_migration: + context_sym.forceNotMigration = True + context_sym.setNameGetCallbackIfUnset(lambda _: sym.name) + if sym.given_name_end: + context_sym.nameEnd = sym.given_name_end + + return context_sym + + +def create_symbol_from_spim_symbol( + segment: "Segment", context_sym: spimdisasm.common.ContextSymbol +) -> "Symbol": + in_segment = False + + sym_type = None + if context_sym.type == spimdisasm.common.SymbolSpecialType.jumptable: + in_segment = True + sym_type = "jtbl" + elif context_sym.type == spimdisasm.common.SymbolSpecialType.function: + sym_type = "func" + elif context_sym.type == spimdisasm.common.SymbolSpecialType.branchlabel: + in_segment = True + sym_type = "label" + elif context_sym.type == spimdisasm.common.SymbolSpecialType.jumptablelabel: + in_segment = True + sym_type = "jtbl_label" + + if not in_segment: + if ( + context_sym.overlayCategory is None + and segment.get_exclusive_ram_id() is None + ): + in_segment = segment.contains_vram(context_sym.vram) + elif context_sym.overlayCategory == segment.get_exclusive_ram_id(): + if context_sym.vromAddress is not None: + in_segment = segment.contains_rom(context_sym.vromAddress) + else: + in_segment = segment.contains_vram(context_sym.vram) + + sym = segment.create_symbol( + context_sym.vram, in_segment, type=sym_type, reference=True + ) + + if sym.given_name is None and context_sym.name is not None: + sym.given_name = context_sym.name + + # To keep the symbol name in sync between splat and spimdisasm + context_sym.setNameGetCallback(lambda _: sym.name) + + if context_sym.size is not None: + sym.given_size = context_sym.getSize() + if context_sym.vromAddress is not None: + sym.rom = context_sym.getVrom() + if context_sym.isDefined: + sym.defined = True + if context_sym.referenceCounter > 0: + sym.referenced = True + + return sym + + +def mark_c_funcs_as_defined(): + for symbol in all_symbols: + if len(to_mark_as_defined) == 0: + return + sym_name = symbol.name + if sym_name in to_mark_as_defined: + symbol.defined = True + to_mark_as_defined.remove(sym_name) + + +@dataclass +class Symbol: + vram_start: int + + given_name: Optional[str] = None + given_name_end: Optional[str] = None + rom: Optional[int] = None + type: Optional[str] = None + given_size: Optional[int] = None + segment: Optional["Segment"] = None + + defined: bool = False + referenced: bool = False + dead: bool = False + extract: bool = True + user_declared: bool = False + + force_migration: bool = False + force_not_migration: bool = False + + allow_addend: bool = False + dont_allow_addend: bool = False + + linker_section: Optional[str] = None + + _generated_default_name: Optional[str] = None + _last_type: Optional[str] = None + + appears_after_overlays_addr: Optional[int] = None + + def __str__(self): + return self.name + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Symbol): + return False + return self.vram_start == other.vram_start and self.segment == other.segment + + # https://stackoverflow.com/a/56915493/6292472 + def __hash__(self): + return hash((self.vram_start, self.segment)) + + def format_name(self, format: str) -> str: + ret = format + + ret = ret.replace("$VRAM", f"{self.vram_start:08X}") + + if "$ROM" in ret: + if not isinstance(self.rom, int): + log.error( + f"Attempting to rom-name a symbol with no ROM address: {self.vram_start:X} typed {self.type}" + ) + ret = ret.replace("$ROM", f"{self.rom:X}") + + if "$SEG" in ret: + if self.segment is None: + # This probably is fine - we can't expect every symbol to have a segment. Fall back to just the ram address + return f"{self.vram_start:X}" + assert self.segment is not None + ret = ret.replace("$SEG", self.segment.name) + + return ret + + @property + def default_name(self) -> str: + if self._generated_default_name is not None: + if self.type == self._last_type: + return self._generated_default_name + + if self.segment: + if isinstance(self.rom, int): + suffix = self.format_name(self.segment.symbol_name_format) + else: + suffix = self.format_name(self.segment.symbol_name_format_no_rom) + else: + if isinstance(self.rom, int): + suffix = self.format_name(options.opts.symbol_name_format) + else: + suffix = self.format_name(options.opts.symbol_name_format_no_rom) + + if self.type == "func": + prefix = "func" + elif self.type == "jtbl": + prefix = "jtbl" + elif self.type in {"jtbl_label", "label"}: + return f".L{suffix}" + else: + prefix = "D" + + self._last_type = self.type + self._generated_default_name = f"{prefix}_{suffix}" + return self._generated_default_name + + @property + def rom_end(self): + return None if not self.rom else self.rom + self.size + + @property + def vram_end(self): + return self.vram_start + self.size + + @property + def name(self) -> str: + return self.given_name if self.given_name else self.default_name + + @property + def size(self) -> int: + if self.given_size is not None: + return self.given_size + return 4 + + def contains_vram(self, offset): + return offset >= self.vram_start and offset < self.vram_end + + def contains_rom(self, offset): + return offset >= self.rom and offset < self.rom_end diff --git a/tools/sym_info.py b/tools/sym_info.py new file mode 100755 index 00000000..595faf2f --- /dev/null +++ b/tools/sym_info.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import mapfile_parser +from pathlib import Path + + +def symInfoMain(): + parser = argparse.ArgumentParser(description="Display various information about a symbol or address.") + parser.add_argument("symname", help="symbol name or VROM/VRAM address to lookup") + parser.add_argument("-e", "--expected", dest="use_expected", action="store_true", help="use the map file in expected/build/ instead of build/") + parser.add_argument("-v", "--version", help="Which version should be processed", default="jp") + + args = parser.parse_args() + + BUILTMAP = Path(f"build") / f"animalforest.{args.version}.map" + + mapPath = BUILTMAP + if args.use_expected: + mapPath = "expected" / BUILTMAP + + mapfile_parser.frontends.sym_info.doSymInfo(mapPath, args.symname) + +if __name__ == "__main__": + symInfoMain()