diff --git a/Lua/inject/beta.asm b/Lua/inject/beta.asm index fad8ed4..421fa5c 100644 --- a/Lua/inject/beta.asm +++ b/Lua/inject/beta.asm @@ -36,6 +36,8 @@ short term: set clock town first time as being watched set deku mask being worn once + add true RNG mode + long term: maybe skip zora/goron mask cutscenes (1C00 FFF3 -> 6890 0000, 1C00 FFF4 -> 9610 0000) skip giants cutscenes; give oath when any mask is acquired (0xCC00 fyi) diff --git a/Lua/inject/crc32.asm b/Lua/inject/crc32.asm index 51c4ae4..51c2a48 100644 --- a/Lua/inject/crc32.asm +++ b/Lua/inject/crc32.asm @@ -30,9 +30,9 @@ crc32: lw t7, (t6) xor v0, t1, t7 // iterate or return - subi a1, a1, 1 // cnt-- + subi a1, 1 // cnt-- bnez a1, - - addi a0, a0, 1 // ptr++ + addi a0, 1 // ptr++ jr nop diff --git a/Lua/inject/dpad control.asm b/Lua/inject/dpad control.asm index 45a3f7c..98b9fe4 100644 --- a/Lua/inject/dpad control.asm +++ b/Lua/inject/dpad control.asm @@ -4,8 +4,8 @@ dpad_control: // v0: number after modifications la t1, dpad_values srl t0, a1, 8 - andi t0, t0, 0xF - add t0, t0, t1 + andi t0, 0xF + add t0, t1 lb t0, 0(t0) jr add v0, a0, t0 diff --git a/Lua/inject/widescreen-either.asm b/Lua/inject/widescreen-either.asm index 85c64b6..75040ac 100644 --- a/Lua/inject/widescreen-either.asm +++ b/Lua/inject/widescreen-either.asm @@ -1,14 +1,3 @@ -/* -.org 0x18F30 -; add an entry to the end of dmatable to hold our extra code -; this actually just crashes the game so don't bother -; (no debug filename associated with it = bad pointer dereference? maybe?) - .word @vstart ; virtual start - .word 0x035E0000 ; virtual end (@vstart + @size) - .word @vstart ; physical start (should be same as virtual start) - .word 0 ; physical end (should be 0 for uncompressed) -*/ - start: push 4, 1, ra diff --git a/patch/code.asm b/patch/code.asm index cc9a2df..f02c849 100644 --- a/patch/code.asm +++ b/patch/code.asm @@ -1,13 +1,17 @@ .include "common.asm" -[starting_exit]: 0x9F87C +[game_main]: 0xCEDE0 ; 0x801748A0 +[dma_overwrite]: 0xC4808 ; 0x8016A2C8 +[tunic_color_overwrite]: 0x80710 +[starting_exit_func]: 0x9F87C +[starting_exit_jr]: 0x9F9A4 [default_save]: 0x120DD8 ; 0x8016A2C8 -> 0xC4808 ; 0x8016A2C8 - 0xC4808 = 0x800A5AC0 ; 0x8016AC0C - 0x8016A2C8 = 0x944 -.org 0xCEDE0 ; 0x801748A0 +.org @game_main ; this appears to be the main game loop function ; we can "make room" for some injected code ; by taking advantage of it never returning under normal circumstances. @@ -21,22 +25,22 @@ li a1, @vstart ; 2 li a2, @size ; 2 jal @DMARomToRam ; 1 - li a0, @start ; 1 (just make sure @start can be a LUI!) + li a0, @start ; 1 (just ensure @start can be a LUI!) -.org 0xC4808 ; 0x8016A2C8 +.org @dma_overwrite j dma_hook ; 1 nop ; 1 -.org 0x9F9A4 ; JR of starting_exit's function - j load_hook ; tail call - -.org 0x80710 +.org @tunic_color_overwrite j tunic_color_hook lhu t1, 0x1DB0(t1); original code -.org @starting_exit - li t8, 0xD800 ; modified code - li t4, 0xD800 ; modified code +.org @starting_exit_func + li t8, @starting_exit ; modified code + li t4, @starting_exit ; modified code + +.org @starting_exit_jr + j load_hook ; tail call .org @default_save .ascii "\0\0\0\0\0\0" ; ZELDA3 diff --git a/patch/common.asm b/patch/common.asm index 39d16e0..f838540 100644 --- a/patch/common.asm +++ b/patch/common.asm @@ -22,3 +22,5 @@ ;[link_object_ptr]: 0x244 [scene_record_size]: 0x14 + +[starting_exit]: 0xD800 diff --git a/patch/common.sh b/patch/common.sh new file mode 100644 index 0000000..69308da --- /dev/null +++ b/patch/common.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +fast=0 +[[ "$1" == "fast" ]] && fast=1 && shift || [[ "$1" == "test" ]] && fast=2 && shift +args="$@" + +inject="$(readlink -f ../Lua/inject)" +lips="$(readlink -f ../Lua/lib/lips)" +YAZ0="$(readlink -f ../z64yaz0)" +DUMP="$(readlink -f ../z64dump.py)" + +#extracted="$(readlink -f "$extracted")" +rom="$(readlink -f "$rom")" + +mkdir -p build +quiet=0 + +[ ! -s "$YAZ0" ] && cc -O3 "${YAZ0}.c" -o "$YAZ0" + +dump() { + (cd "$(dirname "$DUMP")"; ./z64dump.py "$@") +} + +if [ $fast -eq 0 ] || [ ! -d patchme ]; then + if [ -n "$sha1" ]; then + [ -d build/patchme ] && rm -r build/patchme + dump -c "$rom" + mv ../"$sha1" build/patchme + else + cp "$rom" "build/$out" + fi +fi + +ratio() { + local len1="$(wc -c < "$1")" + local len2="$(wc -c < "$2")" + + if [ $len1 -eq 0 ]; then + [ $quiet -le 0 ] && echo emptIy + else + let percent=(len2*100)/len1 + [ $quiet -le 0 ] && echo "ratio: $percent%" + return "$((percent < 100))" + fi +} + +unc() { + local in=patchme/"$1".Yaz0 + local out=patchme/"$1" + + [ -e "$in" ] || return 0 + "$YAZ0" "$in" > "$out" + [ $quiet -le 0 ] && echo "uncompressed $1" + ratio "$out" "$in" || true + rm patchme/"$1".Yaz0 +} + +comp() { + local in=patchme/"$1" + local out=patchme/"$1".Yaz0 + + [ -e "$in" ] || return 0 + "$YAZ0" "$in" > "$out" + [ $quiet -le 0 ] && echo "compressed $1" + ratio "$in" "$out" && { + [ $quiet -le 1 ] && echo "leaving uncompressed $1" + rm "$out" + } || { + rm "$in" + } +} + +copy_rom() { + dd if=patchme.z64 of="$1" bs=$((1024*1024)) count="${2:-32}" status=none +} + +cp *.lua build/ +cp "$inject"/*.asm build/ +cp *.asm build/ +cd build + +# don't copy entire dir; avoid copying dotfiles (.git) +mkdir -p lips +cp "$lips"/* lips diff --git a/patch/dma O EUDB MQ.asm b/patch/dma O EUDB MQ.asm index 3bb6518..b372b1f 100644 --- a/patch/dma O EUDB MQ.asm +++ b/patch/dma O EUDB MQ.asm @@ -1,3 +1,5 @@ +.push pc + [DMARomToRam]: 0x80000BFC [vstart]: 0x035D0000 @@ -15,6 +17,8 @@ .word 0 ; physical end (should be 0 for uncompressed) */ +.base 0x7F588E60 ; code file in memory + .org 0xB3D9E4 ; 0x800C6844 ; this appears to be the main game loop function ; we can "make room" for some injected code @@ -39,3 +43,5 @@ nop nop nop + +.pop pc diff --git a/patch/extra.asm b/patch/extra.asm index de569e5..a30dcd2 100644 --- a/patch/extra.asm +++ b/patch/extra.asm @@ -25,7 +25,7 @@ dma_hook: jal setup_hook nop pop 4, 1, ra - addiu sp, sp, 0xFF58 ; original code + addiu sp, 0xFF58 ; original code j 0x8016A2D0 ; return to scene setup function sw s1, 0x30(sp) ; original code @@ -41,11 +41,11 @@ set_scene_flag: mflo t2 addu t3, t1, t2 sll t4, a1, 2 ; t4 = a1*sizeof(word) - addu t3, t3, t4 + addu t3, t4 lw v0, (t3) ; load scene flag word li t6, 1 - sllv t6, t6, a2 - or v0, v0, t6 ; set flag + sllv t6, a2 + or v0, t6 ; set flag jr sw v0, (t3) ; write it back @@ -59,8 +59,8 @@ get_event_flag: addu t2, t1, a1 lb v0, (t2) li t6, 1 - sllv t6, t6, a2 - and v0, v0, t6 + sllv t6, a2 + and v0, t6 beqz v0, + cl v0 li v0, 1 @@ -78,8 +78,8 @@ set_event_flag: addu t2, t1, a1 lb v0, (t2) li t6, 1 - sllv t6, t6, a2 - or v0, v0, t6 + sllv t6, a2 + or v0, t6 jr sb v0, (t2) @@ -189,7 +189,7 @@ shuffle_all: lhu t4, 0(t0) sh t4, 2(t1) ; iterate - addi s0, s0, 1 + addi s0, 1 bne s0, s1, - nop +: @@ -343,7 +343,7 @@ setup_hook: push 4, a0, ra lw a0, @link_save jal shuffle_exit - andi a0, a0, 0xFFFF + andi a0, 0xFFFF sw v0, @link_save jpop 4, a0, ra diff --git a/patch/mm-bq b/patch/mm-bq index 8b4218f..de8deea 100755 --- a/patch/mm-bq +++ b/patch/mm-bq @@ -1,69 +1,21 @@ #!/usr/bin/env bash set -e -fast=0 -[[ "$1" == "fast" ]] && fast=1 && shift -[[ "$1" == "test" ]] && fast=2 && shift - -args="$@" - -inject=../Lua/inject sha1=d6133ace5afaa0882cf214cf88daba39e266c078 -extracted=../dump/mm-US10-"$sha1" -rom=../roms/everything/"Legend of Zelda, The - Majora's Mask (U) [!].z64" -lips=../Lua/lib/lips +#extracted=../dump/mm-US10-"$sha1" +rom=../../roms/everything/"Legend of Zelda, The - Majora's Mask (U) [!].z64" out=mm-bq.z64 +. common.sh + code="0031 V00B3C000" extra="1552 V02EE7040" -ratio() { - len1="$(wc -c < "$1")" - len2="$(wc -c < "$2")" - let percent=(len2*100)/len1 - echo "ratio: $percent%" -} - -unc() { - [ -e patchme/"$1".Yaz0 ] || return 0 - ../../z64yaz0 patchme/"$1".Yaz0 > patchme/"$1" - echo "uncompressed $1" - ratio patchme/"$1" patchme/"$1".Yaz0 - rm patchme/"$1".Yaz0 -} - -comp() { - [ -e patchme/"$1" ] || return 0 - ../../z64yaz0 patchme/"$1" > patchme/"$1".Yaz0 - echo "compressed $1" - ratio patchme/"$1" patchme/"$1".Yaz0 - rm patchme/"$1" -} - -mkdir -p build -cp *.lua build/ -cd build - -[ ! -s ../../z64yaz0 ] && cc -O3 ../../z64yaz0.c -o ../../z64yaz0 - -if [ $fast -eq 0 ] || [ ! -d patchme ]; then - [ -d patchme ] && rm -r patchme - (cd ../../; ./z64dump.py -c "$rom") - mv ../../"$sha1" patchme -fi - unc "$code" -# don't copy entire dir; avoid copying dotfiles (.git) -mkdir -p lips -cp ../"$lips"/* lips - -cp ../"$inject"/*.asm . -cp ../*.asm . - dd if=/dev/zero of=extra bs=370688 count=1 2>/dev/null -luajit patch.lua -e labels.lua -o 0x80780000 "$@" extra.asm extra +luajit patch.lua -e labels.lua -b 0x80780000 "$@" extra.asm extra luajit patch.lua -i labels.lua "$@" code.asm patchme/"$code" # ensure the file is the proper size (Lua seems to expand it?) @@ -73,6 +25,6 @@ rm extra if [ $fast -ne 2 ]; then comp "$code" comp "$extra" - (cd ../..; ./z64dump.py patch/build/patchme) - dd if=patchme.z64 of="$out" bs=$((1024*1024)) count=32 status=none + dump patch/build/patchme + copy_rom "$out" 32 fi diff --git a/patch/oot-dbg-comp b/patch/oot-dbg-comp new file mode 100644 index 0000000..bbe095a --- /dev/null +++ b/patch/oot-dbg-comp @@ -0,0 +1,313 @@ +#!/usr/bin/env bash +set -e + +sha1=50bebedad9e0f10746a52b07239e47fa6c284d03 +rom=../../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" +out=oot-dbg-comp.z64 +#sha1=bcc07421ead8a2388075f2051eb89c83164a2bfd +#rom=patch/oot-dbg-compressed.z64 +#out=oot-dbg-comp.z64 + +. common.sh + +code="0028 V00A94000 code" +title="0029 V00BCEF30 ovl_title" + +#unc "$code" +#unc "$title" + +#luajit patch.lua -o 0 ass.asm "$out" + +for f in \ + "0013 V00802000 icon_item_ger_static" \ + "0014 V00811000 icon_item_fra_static" \ + "0022 V008FF000 ger_message_data_static" \ + "0023 V0093B000 fra_message_data_static" \ + "1007 V02793000 syotes_scene" \ + "1008 V02795000 syotes_room_0" \ + "1009 V027A2000 syotes2_scene" \ + "1010 V027A5000 syotes2_room_0" \ + "1011 V027AF000 depth_test_scene" \ + "1012 V027B0000 depth_test_room_0" \ + "1305 V02AF6000 testroom_scene" \ + "1306 V02AFB000 testroom_room_0" \ + "1307 V02B00000 testroom_room_1" \ + "1308 V02B03000 testroom_room_2" \ + "1309 V02B07000 testroom_room_3" \ + "1310 V02B0B000 testroom_room_4" \ + "1316 V02B57000 sutaru_scene" \ + "1317 V02B58000 sutaru_room_0" \ + "1352 V02D00000 sasatest_scene" \ + "1353 V02D03000 sasatest_room_0" \ + "1446 V03280000 hairal_niwa2_scene" \ + "1447 V03283000 hairal_niwa2_room_0" \ + "1507 V03544000 besitu_scene" \ + "1508 V03545000 besitu_room_0" \ + "1516 V035B3000 test01_scene" \ + "1517 V035B7000 test01_room_0" \ +; do + rm patchme/"$f" + touch patchme/"$f" + echo "deleted $f" +done + +declare -A raw +# must be uncompressed +raw[0000]=1 +raw[0001]=1 +raw[0002]=1 +raw[0007]=1 +raw[0008]=1 +raw[0009]=1 +raw[0010]=1 +raw[0011]=1 +raw[0012]=1 +raw[0013]=1 +raw[0014]=1 +raw[0015]=1 +raw[0016]=1 +raw[0017]=1 +raw[0018]=1 +raw[0019]=1 +raw[0020]=1 +raw[0021]=1 +raw[0022]=1 +raw[0023]=1 +raw[0024]=1 +raw[0025]=1 +raw[0026]=1 +raw[0027]=1 +raw[0501]=1 +raw[0937]=1 +raw[0938]=1 +raw[0939]=1 +raw[0940]=1 +raw[0941]=1 +raw[0942]=1 +raw[0943]=1 +raw[0944]=1 +raw[0945]=1 +raw[0946]=1 +raw[0947]=1 +raw[0948]=1 +raw[0949]=1 +raw[0950]=1 +raw[0951]=1 +raw[0952]=1 +raw[0953]=1 +raw[0954]=1 +raw[0955]=1 +raw[0956]=1 +raw[0957]=1 +raw[0958]=1 +raw[0959]=1 +raw[0960]=1 +raw[0961]=1 +raw[0962]=1 +raw[0963]=1 +raw[0964]=1 +raw[0965]=1 +raw[0966]=1 +raw[0967]=1 +raw[0968]=1 +raw[0969]=1 +raw[0970]=1 +raw[0971]=1 +raw[0972]=1 +raw[0973]=1 +raw[0974]=1 +raw[0975]=1 +raw[0976]=1 +raw[0977]=1 +raw[0978]=1 +raw[0979]=1 +raw[0980]=1 +raw[0981]=1 +raw[0982]=1 +raw[0983]=1 +raw[0984]=1 +raw[0985]=1 +raw[0986]=1 +raw[0987]=1 +raw[0988]=1 +raw[0989]=1 +raw[0990]=1 +raw[0991]=1 +raw[0992]=1 +raw[0993]=1 +raw[0994]=1 +raw[0995]=1 +raw[0996]=1 +raw[0997]=1 +raw[0998]=1 +raw[0999]=1 +raw[1000]=1 +raw[1001]=1 +raw[1002]=1 +raw[1003]=1 +raw[1004]=1 +raw[1518]=1 +raw[1519]=1 +raw[1520]=1 +raw[1521]=1 +raw[1522]=1 +raw[1523]=1 +raw[1524]=1 +raw[1525]=1 +raw[1526]=1 +raw[1527]=1 +raw[1528]=1 +raw[1529]=1 +raw[1530]=1 +raw[1531]=1 + +# other shit +raw[0003]=1 +raw[0004]=1 +raw[0006]=1 +raw[1509]=1 +raw[1510]=1 +raw[1511]=1 +raw[1512]=1 +raw[1513]=1 +raw[1514]=1 +raw[1515]=1 +raw[1516]=1 +raw[1517]=1 + +# might not actually need to be uncompressed +raw[0010]=0 +raw[0011]=0 +raw[0012]=0 +raw[0013]=0 +raw[0014]=0 +raw[0027]=0 +raw[0501]=0 +raw[0607]=0 +raw[0624]=0 +raw[0648]=0 +raw[0649]=0 +raw[0737]=0 +raw[0841]=0 +raw[0856]=0 +raw[0869]=0 +raw[0937]=0 +raw[0938]=0 +raw[0939]=0 +raw[0940]=0 +raw[0942]=0 +raw[0944]=0 +raw[0946]=0 +raw[0948]=0 +raw[0950]=0 +raw[0952]=0 +raw[0954]=0 +raw[0956]=0 +raw[0958]=0 +raw[0960]=0 +raw[0962]=0 +raw[0964]=0 +raw[0966]=0 +raw[0968]=0 +raw[0970]=0 +raw[0972]=0 +raw[0974]=0 +raw[0976]=0 +raw[0978]=0 +raw[0980]=0 +raw[0982]=0 +raw[0984]=0 +raw[0986]=0 +raw[0988]=0 +raw[0990]=0 +raw[0992]=0 +raw[0994]=0 +raw[0996]=0 +raw[0998]=0 +raw[1000]=0 +raw[1002]=0 +raw[1004]=0 +raw[1005]=0 +raw[1006]=0 +raw[1525]=0 +raw[1526]=0 +raw[1527]=0 +raw[1528]=0 +raw[1529]=0 +raw[1530]=0 +raw[1531]=0 + +# smaller when uncompressed +raw[0005]=1 +raw[0501]=1 +raw[0607]=1 +raw[0624]=1 +raw[0648]=1 +raw[0649]=1 +raw[0737]=1 +raw[0841]=1 +raw[0856]=1 +raw[0869]=1 +raw[0942]=1 +raw[0944]=1 +raw[0946]=1 +raw[0948]=1 +raw[0950]=1 +raw[0952]=1 +raw[0954]=1 +raw[0960]=1 +raw[0962]=1 +raw[0964]=1 +raw[0966]=1 +raw[0968]=1 +raw[0972]=1 +raw[0974]=1 +raw[0976]=1 +raw[0980]=1 +raw[0982]=1 +raw[0984]=1 +raw[0986]=1 +raw[0988]=1 +raw[0990]=1 +raw[0992]=1 +raw[0994]=1 +raw[0996]=1 +raw[0998]=1 +raw[1000]=1 +raw[1002]=1 +raw[1004]=1 +raw[1005]=1 +raw[1006]=1 +raw[1519]=1 +raw[1520]=1 +raw[1521]=1 +raw[1522]=1 +raw[1523]=1 +raw[1524]=1 +raw[1525]=1 +raw[1526]=1 +raw[1527]=1 +raw[1528]=1 +raw[1529]=1 +raw[1530]=1 + +if [ $fast -ne 2 ]; then +# comp "$code" +# comp "$title" + # z64dump.py doesn't have compression support rn + # so we'll do this ourselves + for f in patchme/*; do + ext="${f##*.}" # warning: not robust + dirless="${f##*/}" # warning: not robust + n="${dirless:0:4}" + if [ -n "${raw[$n]}" ] && [ "${raw[$n]}" -eq 1 ]; then + echo "skipping $dirless" + else + quiet=1 + [ "$ext" == 'Yaz0' ] || comp "$dirless" + quiet=0 + fi + done + dump patch/build/patchme + copy_rom "$out" 32 +fi diff --git a/patch/oot-spawner b/patch/oot-spawner index 480a6ed..179548a 100755 --- a/patch/oot-spawner +++ b/patch/oot-spawner @@ -2,25 +2,14 @@ set -e inject=../Lua/inject -rom=../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" +rom=../../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" lips=../Lua/lib/lips out=oot-spawner.z64 -mkdir -p build -cp *.lua build/ -cd build +. common.sh -cp ../../"$rom" "$out" - -# don't copy entire dir; avoid copying dotfiles (.git) -mkdir -p lips -cp ../"$lips"/* lips - -cp ../"$inject/"*.asm . -cp ../*.asm . - -luajit patch.lua -o 0 \ - --extra-rom 0x035D0000 --extra-ram 0x80700000 \ +luajit patch.lua \ + -O 0x035D0000 -b $((0x80700000 - 0x035D0000)) \ 'spawn O EUDB MQ.asm' "$out" -(cd ../../; ./z64dump.py -f patch/build/"$out") +dump -f patch/build/"$out" diff --git a/patch/oot-widescreen b/patch/oot-widescreen index 356deb2..894b316 100755 --- a/patch/oot-widescreen +++ b/patch/oot-widescreen @@ -2,25 +2,14 @@ set -e inject=../Lua/inject -rom=../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" +rom=../../roms/everything/"Legend of Zelda, The - Ocarina of Time - Master Quest (E) (Debug) [f1].z64" lips=../Lua/lib/lips out=oot-widescreen.z64 -mkdir -p build -cp *.lua build/ -cd build +. common.sh -cp ../../"$rom" "$out" - -# don't copy entire dir; avoid copying dotfiles (.git) -mkdir -p lips -cp ../"$lips"/* lips - -cp ../"$inject/"*.asm . -cp ../*.asm . - -luajit patch.lua -o 0 \ - --extra-rom 0x035D0000 --extra-ram 0x80700000 \ +luajit patch.lua \ + -O 0x035D0000 -b $((0x80700000 - 0x035D0000)) \ widescreen-inline.asm "$out" -(cd ../../; ./z64dump.py -f patch/build/"$out") +dump -f patch/build/"$out" diff --git a/patch/patch.lua b/patch/patch.lua index 64ca03d..c35d123 100644 --- a/patch/patch.lua +++ b/patch/patch.lua @@ -1,5 +1,7 @@ +#!/usr/bin/env luajit package.path = package.path..";./?/init.lua" +--require "test.strict" local assemble = require "lips" local cereal = require "serialize" local argparse = require "argparse" @@ -10,6 +12,9 @@ local function lament(...) end local function parsenum(s) + if type(s) == 'number' then + return s + end if s:sub(1, 2) == '0x' then return tonumber(s, 16) elseif s:sub(1, 1) == '0' then @@ -19,15 +24,45 @@ local function parsenum(s) end end +local function make_verbose_writer() + local buff = {} + local max = -1 + return function(pos, b) + if pos then + buff[pos] = b + if pos > max then + max = pos + end + elseif max >= 0 then + for i=0, max, 4 do + local a = buff[i+0] or nil + local b = buff[i+1] or nil + local c = buff[i+2] or nil + local d = buff[i+3] or nil + if a or b or c or d then + a = a and ("%02X"):format(a) or '--' + b = b and ("%02X"):format(b) or '--' + c = c and ("%02X"):format(c) or '--' + d = d and ("%02X"):format(d) or '--' + print(('%08X %s'):format(i, a..b..c..d)) + end + end + end + end +end + local function inject(args) local offset = args.offset and parsenum(args.offset) or 0 local origin = args.origin and parsenum(args.origin) or 0 local base = args.base and parsenum(args.base) or 0x80000000 - local f = io.open(args.output, 'r+b') - if not f then - lament("file not found:", args.output) - return + local f + if args.output then + f = io.open(args.output, 'r+b') + if not f then + lament("file not found:", args.output) + return + end end local state = {} @@ -39,19 +74,23 @@ local function inject(args) end local function write(pos, b) - if args.extra_rom and args.extra_ram and pos >= args.extra_ram then - pos = pos - args.extra_ram + args.extra_rom - elseif pos >= offset then + --if args.extra_rom and args.extra_ram and pos >= args.extra_ram then + -- pos = pos - args.extra_ram + args.extra_rom + --elseif pos >= offset then + if pos >= offset then pos = pos - offset end if pos >= 1024*1024*1024 then - lament("you probably don't want to do this:") - lament(("%08X %02X"):format(pos, b)) + lament(("oops: %08X %02X"):format(pos, b)) return end - f:seek('set', pos) - f:write(string.char(b)) + if f then + f:seek('set', pos) + f:write(string.char(b)) + else + print(("%08X %02X"):format(pos, b)) + end end local options = { @@ -59,7 +98,8 @@ local function inject(args) labels = state, debug_token = args.dump_token, debug_pre = args.dump_pre, - debug_dump = args.dump_asm, + debug_post = args.dump_post, + debug_asm = args.dump_asm, } if args.offset then if args.origin or args.base then @@ -68,39 +108,44 @@ local function inject(args) options.offset = offset else options.origin = origin - if args.origin or args.base then - options.base = base - else - options.base = 0 - end + options.base = base end - assemble(args.input, write, options) + if f then + assemble(args.input, write, options) + else + local vb = make_verbose_writer() + assemble(args.input, vb, options) + vb() + end if args.export then cereal.serialize(args.export, state) end - f:close() + if f then + f:close() + end end local ap = argparse("patch", "patch a binary file with assembly") -- TODO: option to dump hex or gs codes when no output is given ap:argument("input", "input assembly file") -ap:argument("output", "output binary file") +ap:argument("output", "output binary file"):args('?') ap:option("-o --offset", "(deprecated) offset to pass to lips", nil) -ap:option("-O --origin", "origin to pass to lips", nil):convert(parsenum) -ap:option("-b --base", "base to pass to lips", nil):convert(parsenum) +ap:option("-O --origin", "origin to pass to lips", nil) +ap:option("-b --base", "base to pass to lips", nil) ap:option("-i --import", "import state file(s) containing labels"):count("*") ap:option("-e --export", "export state file containing labels") ap:flag("--dump-token", "(debug) dump statements to stdout after lexing") ap:flag("--dump-pre", "(debug) dump statements to stdout after preprocessing") +ap:flag("--dump-post", "(debug) dump statements to stdout after expanding") ap:flag("--dump-asm", "(debug) dump statements to stdout after assembling") --ap:option("-s --state", "--import and --export to this file") --- TODO: replace this with a lua table import of associated addresses -ap:option("--extra-rom", "dumb stuff"):convert(parsenum) -ap:option("--extra-ram", "dumb stuff"):convert(parsenum) +-- use -D defines instead +--ap:option("--extra-rom", "dumb stuff"):convert(parsenum) +--ap:option("--extra-ram", "dumb stuff"):convert(parsenum) local inject_args = ap:parse() diff --git a/patch/spawn O EUDB MQ.asm b/patch/spawn O EUDB MQ.asm index aea3aaf..2e6c790 100644 --- a/patch/spawn O EUDB MQ.asm +++ b/patch/spawn O EUDB MQ.asm @@ -4,10 +4,14 @@ [inject_from]: 0xB3D458 ; 0x800C62B8 [inject_to]: 0x80700000 +.push pc +.base 0x7F588E60 ; code file in memory + .org @inject_from jal @inject_to -.org @inject_to +.pop pc + sw ra, -4(sp) sw a0, 0(sp) sw a1, 4(sp) diff --git a/patch/widescreen-inline.asm b/patch/widescreen-inline.asm index 1298151..e0bce02 100644 --- a/patch/widescreen-inline.asm +++ b/patch/widescreen-inline.asm @@ -6,16 +6,32 @@ [ctxt]: 0x80212020 [dlists]: 0x80168930 -.include "dma O EUDB MQ.asm" - [original]: 0x800C6AC4 [inject_from]: 0xB3D458 ; 0x800C62B8 [inject_to]: 0x80700000 +; set up screen dimensions to render widescreen. +[res2_L]: 0 +[res2_T]: 30 +[res2_R]: 320 +[res2_B]: 210 + +.include "dma O EUDB MQ.asm" + +.push pc +.base 0x7F588E60 ; code file in memory + .org @inject_from jal @inject_to -.org @inject_to +.org 0xB21D30 ; 0x800AAB90 + li t3, @res2_B ; 240B00D2 + li t4, @res2_T ; 240C001E +.org 0xB21D48 ; 0x800AABA8 + li t1, @res2_R ; 24090140 + li t2, @res2_L ; 240A0000 + +.pop pc sw ra, -4(sp) sw a0, 0(sp) sw a1, 4(sp) @@ -32,15 +48,3 @@ addi sp, sp, 24 .include "widescreen-either.asm" - -; set up screen dimensions to render widescreen. -[res2_L]: 0 -[res2_T]: 30 -[res2_R]: 320 -[res2_B]: 210 -.org 0xB21D30 ; 0x800AAB90 - li t3, @res2_B ; 240B00D2 - li t4, @res2_T ; 240C001E -.org 0xB21D48 ; 0x800AABA8 - li t1, @res2_R ; 24090140 - li t2, @res2_L ; 240A0000