Repository navigation
decomp: clarify parameter and local names (batch 19) - #213
Merged
mateuszklysz merged 135 commits intoOct 17, 2026
Merged
Conversation
arg0 -> unused_arg0: The SHA-256-bound C snapshot explicitly discards s32 arg0 with (void)arg0. Retail incoming a0 is first written at 0x0012059c by ori a0,v0,0x2, before any read of a0, then overwritten by cfc2 at 0x001205b0. The original Ghidra signature is int FUN_00120558(void); no incoming argument value feeds the polling loop or zero return. arg1 -> unused_arg1: The SHA-256-bound C snapshot explicitly discards s32 arg1 with (void)arg1. Retail incoming a1 is first overwritten at 0x00120588 by lw a1,0x0(t1), reading GIF DMA CHCR at 0x1000a000, before andi a1,a1,0x100 at 0x00120598. Ghidra decompiles the routine with no parameters; its polling and return consume no incoming a1 value.
arg1 -> indexed_textures: In the bound source, arg1 is the second s32 parameter and is forwarded unchanged as argument 2 of prepare_resident_class_render_data(moby, arg1, arg2, oclass). Retail 0x002036a4 saves incoming a1 in s2; 0x002036f8 restores s2 to a1 before jal 0x00203338 at 0x00203708. The supplied original Ghidra signature identifies that parameter as ResidentRenderTextureDefinition *pIndexedTextures and documents optional indexed texture definitions. arg2 -> material_map: In the bound source, arg2 is the third s32 parameter and is forwarded unchanged as argument 3 of prepare_resident_class_render_data(moby, arg1, arg2, oclass). Retail 0x002036a8 saves incoming a2 in s3; 0x002036fc restores s3 to a2 before jal 0x00203338 at 0x00203708. The supplied original Ghidra signature identifies it as ResidentClassMaterialMap *pMaterialMap and documents the resource's 16-byte material map.
arg3 -> height: Authoritative source src/ui/frames/draw_stretchable_ui_frame.c (SHA-256 ee40cbd02c5169f84a9c3f8ee165900d2662e0dc848d83237d4112518d90bf02) forwards s32 arg3 as sprite argument five. Retail 0x00201150 saves a3 in s2, and 0x0020118c/0x002011ac forward s2 in t0 to 0x001ffc30. Helper 0x001ffcac saves t0 in s7; 0x001ffd90 adds s7 to the y value in s3, and 0x001ffd98 shifts the sum by four before packing the second vertex. This proves the pixel-space height. arg4 -> alpha: The source forwards s32 arg4 as sprite argument six. Retail 0x0020114c saves incoming t0 in s3; 0x00201190 and 0x002011b4 forward that value in t1 to 0x001ffc30. Helper 0x001ffcb4 saves t1 in s0, 0x001ffd24 shifts s0 left by 24, 0x001ffd2c ORs it with fixed RGB 0x7f7f7f, and 0x001ffd34 stores the color packet value. The supplied helper decompilation identifies this RGBAQ component as alpha, independently supported by the bit placement.
arg0 -> destination: The source void *arg0 is used only as the destination of fast_vec_scale(arg0, &loc, scale). Retail 0x00214be0 saves incoming a0 in s0; 0x00214c20 restores it to a0 before the scale_vector_xyz call at 0x00214c28, with the stack vector in a1. The original Ghidra decompilation likewise passes float *param_1 as the scale output. arg1 -> packed_chars_source: The source s32 *arg1 is dereferenced once as fast_vector_from_packed_chars(&loc, *arg1). Retail 0x00214bf8 loads a1 from 0(a1) in the delay slot of the conversion call at 0x00214bf4, while a0 points to the stack vector. Original Ghidra shows FUN_001f9d50(afStack_50,*param_2), proving this parameter points to the packed input word.
a3 -> material_control_base: Source src/rendering/set_up_vis_gif_viewer.c (SHA-256 d759fae7076bab1eebde0cd9daa5ef255bede82fdbb4d06f1cb16976a991e86f) declares a3 as s32 and ORs it unshifted with ((u64)t0 << 2) and ((u64)mode << 24). Retail 0x0020304c ORs incoming a3 into v0; 0x00203058 adds the shifted material index and 0x0020305c stores the result at original packet offset 0x10. Original Ghidra identifies this word as qwMaterialControl and the argument as dwMaterialBase, proving the base contribution. t0 -> material_control_shift2: The authoritative source declares t0 as s32 and uses ((u64)t0 << 2) in the material-control expression only for mode >= 0. Retail 0x00203038 moves incoming t0 to v0, 0x00203040 shifts v0 left by 2, 0x0020304c ORs it with a3, and 0x00203058/0x0020305c combine the mode shifted by 24 and store the material-control word at packet offset 0x10. Original Ghidra likewise names this input lMaterialShift2; the precise bit meaning remains unresolved.
t0 -> first_vector_scratch: Source declares t0 as f32[4] and passes it with &s->a after packing first_vector there. Retail 0x00218994 sets s0=object+0x20; 0x002189d8-0x002189e0 packs first_vector into s0, then 0x002189f0-0x002189f8 passes sp as the first argument and s0 as the second to FUN_00214bc0. Ghidra identifies the corresponding 16-byte local as auStack_e0; no subsequent use occurs. t1 -> second_vector_scratch: Source declares t1 as f32[4] and passes it with &s->b after packing second_vector there. Retail 0x002189a4 sets s1=object+0x24; 0x002189e4-0x002189ec packs second_vector into s1, then 0x002189fc-0x00218a04 passes sp+0x10 as the first argument and s1 as the second to FUN_00214bc0. Ghidra identifies this distinct 16-byte local as auStack_d0; no subsequent use occurs.
arg0 -> source_address: Retail 0x0020d33c saves incoming a0 in s1; 0x0020d374 restores it unchanged to a0 for moby_proc at 0x0020d378, separate from moby_anim_head in a1. The supplied original Ghidra signature identifies this uint input as source_address. Checked caller 0x00225a7c forms an array at its input + 0x44, loads each 32-bit entry into a0 at 0x00225a80, skips null entries at 0x00225a84 and passes each nonzero source address to draw_moby_list at 0x00225a8c. This supports source_address without claiming the source layout or changing the existing s32 type.
a6 -> callback_address: In the SHA-256-bound source src/audio/voices/snd_set_sound_params_cb.c (dbbb1ceefea2bf7de84c4880c01feba809647c94ccf889d7251b2d71a73036cb), s32 a6 is the fourth argument to snd_send_iop_command_no_wait(0x21, 0x18, buf, a6, a7). Retail 0x0012e4cc moves incoming t2 (seventh parameter) into a3 before jal 0x0012e6e0 at 0x0012e4f4. The prepared original Ghidra decompilation calls this parameter dwCallbackAddress and forwards it in that same position, establishing callback_address without changing its type. a7 -> callback_context_address: The bound source forwards s32 a7 as the fifth argument to snd_send_iop_command_no_wait after a6. Retail 0x0012e4dc moves incoming t3 (eighth parameter) to t0, the fifth call argument, before jal 0x0012e6e0 at 0x0012e4f4. The original Ghidra decompilation identifies it as dwContextAddress, describes a guest callback context address, and passes (long)(int)dwContextAddress in the same slot. This proves the callback context address role while preserving s32.
a0 -> request_word_0: Retail 0x0012e310 stores incoming a0 at sp+0x00; the bound source assigns it to buf[0]. At 0x0012e334 the stack payload becomes the third argument, submitted at 0x0012e33c with command 0x11 and size 0x18. The original decompilation calls this dwWord0. a1 -> request_word_1: Retail 0x0012e320 stores incoming a1 at sp+0x04 before a1 is replaced by size 0x18 at 0x0012e32c. The bound source assigns it to buf[1], proving the second 32-bit request word, matching original dwWord1. a2 -> request_word_2: Retail 0x0012e328 stores incoming a2 at sp+0x08 before a2 becomes the payload pointer at 0x0012e334. The bound source assigns it to buf[2], proving the third 32-bit request word, matching original dwWord2. a3 -> request_word_3: Retail 0x0012e30c preserves incoming a3 in v0, then 0x0012e338 stores v0 at sp+0x0c. The bound source assigns a3 to buf[3], proving the fourth 32-bit request word, matching original dwWord3. a4 -> request_word_4: Retail 0x0012e318 stores incoming t0 (the fifth argument, source a4) at sp+0x10 before t0 receives callback context at 0x0012e324. Source buf[4] and original dwWord4 establish the fifth 32-bit request word. a5 -> request_word_5: Retail 0x0012e340 stores incoming t1 (the sixth argument, source a5) at sp+0x14 in the call delay slot. Source buf[5] and original dwWord5 establish the sixth 32-bit word of the 0x18-byte payload sent at 0x0012e33c.
v1 -> viewport_dimension: In the SHA-256 fa223ffceaf9d3a833d2d3db0eebb57ff65f2e80b67acf0402e5046419f2b832 source, s32 v1 loads pause_state->w and supplies cx before conditional replacement by viewport_height. Retail 0x00220b6c loads v1 from +0x20; 0x00220b88-0x00220b90 preserves its original width as float for the half-width center at 0x00220bb4. The slt/movz at 0x00220b94-0x00220b98 replaces v1 with height when width >= height. At 0x00220ba4-0x00220bc4 the selected dimension is converted, halved, and reduced by 40 for radius. Prepared Ghidra independently expresses this as iVar1=width and iVar6=min(width,height). Thus viewport_dimension describes both phases without falsely asserting v1 always holds width or always the minimum.
arg1 -> mpeg_work_area: At 0x0023cafc video_dec_create calls 0x0012b7d8 without modifying incoming a1 (original Ghidra param_2 is void *). Helper 0x0012b7f0 saves a1 in s0; 0x0012b7f8-0x0012b804 passes it as fill_bytes destination with zero fill. Instructions 0x0012b808-0x0012b810 align that address to four bytes; 0x0012b840 stores the aligned decoder state in context+0x40. This proves MPEG decoder work-area storage. arg2 -> mpeg_work_area_size: At 0x0023cafc incoming a2 (original Ghidra uint param_3) reaches initialize_mpeg_video_decoder unchanged. Helper 0x0012b7ec saves a2 in s1 while the same a2 supplies fill_bytes length at 0x0012b800. Instructions 0x0012b814-0x0012b81c subtract the work-area alignment padding from s1 and compare remaining bytes against 0x10c0; 0x0012b844-0x0012b850 passes the remaining capacity minus 0x10c0 to initialize_mpeg_work_area. This proves the supplied work-area size in bytes.
arg0 -> movie_source: In the SHA-256 a7e7456d26ba60de5d21ded34dad3a7450ddb7e2b5d995d6f04e4f50912f8fe0 source snapshot, s32 arg0 is the first init_all input. Retail 0x0023a3d8 saves incoming a0 in s0 and 0x0023a3f4 restores it as a0 for init_all at 0x0023a3fc. Checked helper 0x0023a7ec saves that input in s2; 0x0023a9b4 passes it as a1 to 0x0023ba48 with the decoder_state+0xd9040 object as a0. Failure of that operation triggers the 'Can't Open movie' diagnostic at 0x0023a9cc-0x0023a9d8. The supplied original retail decompilation identifies the input as source_start and describes an explicit source descriptor. This supports movie_source without claiming its address/offset units.
v0 -> texture_v0: In the bound source src/ui/hud/draw_hud_sprite_rect.c (SHA-256 e82909f4ccf5ab14677f2d235d6cb9c57fecfd77cd4731a355d6942b7479ee28), s32 v0 is packed as q[5] = u0 | ((u64)v0 << 16), immediately before the x0/y0 vertex in q[6]. Retail 0x002009cc preserves argument 7 (t2) in s0; 0x00200a28 shifts it by 16, 0x00200a2c combines it with u0 in s8, and 0x00200a3c stores the packed coordinate. Original Ghidra likewise packs param_6 | param_7 << 0x10. This proves the first endpoint's vertical texture coordinate. v1 -> texture_v1: In the bound source, s32 v1 is packed as q[7] = u1 | ((u64)v1 << 16), immediately before the x1/y1 vertex in q[8]. Retail 0x002009c0 loads argument 9 from 0xb0(sp) into s7; 0x00200a54 shifts it by 16, 0x00200a60 loads the saved u1, 0x00200a6c combines them, and 0x00200a90 stores the pair at 0x38(s1). Original Ghidra expresses the same pair as param_8 | param_9 << 0x10. This proves the second endpoint's vertical texture coordinate.
arg1 -> compressed_data_base: In decode_map_mask, incoming a1 is saved in s5 at 0x0020672c and forwarded as helper a2 at 0x00206760. In decode_map_rle_row, 0x00206880 forms a2+0x200 for the first row; 0x0020687c and 0x0020689c add signed table offsets to a2 for subsequent starts and row ends. The resulting start feeds byte loads at 0x002068d0/0x002068d8 and nibble/run expansion, proving this s32 is the compressed-data base address. arg2 -> row_end_offsets: Incoming s16 *arg2 is saved from a2 into s4 at 0x00206734 and passed as helper a3 in the 0x0020676c delay slot, with row index i in a1. Helper 0x0020686c-0x00206874 indexes a3 by row*2 and loads the previous signed halfword to obtain the row start relative to the compressed base. The current signed halfword at 0x00206890 is added to that base at 0x0020689c to form the row end; end minus start controls the run count at 0x002068a0-0x002068ac. Thus the pointer supplies per-row end offsets.
v0 -> texture_v_top: In the bound source, float v0 fills uv[0].f.v and uv[1].f.v; these pairs precede the (x0,y0) and (x1,y0) vertices. Retail 0x00231704 and 0x0023173c store f14 to sp+0xc and sp+4; loads/stores at 0x00231800/0x0023180c and 0x0023181c/0x0023182c emit those pairs with the y0 row. Original Ghidra names the same component v_min in CONCAT44(v_min,u_min/u_max). Thus this is the top row texture V coordinate. v1 -> texture_v_bottom: In the bound source, float v1 fills uv[2].f.v and uv[3].f.v; these pairs precede the (x0,y1) and (x1,y1) vertices. Retail 0x0023171c and 0x0023174c store f15 to sp+0x1c and sp+0x14; loads/stores at 0x00231838/0x00231844 and 0x00231848/0x00231850 emit these pairs with the y1 row formed from y+h. Original Ghidra identifies these components as v_max. Thus this is the bottom row texture V coordinate.
arg0 -> output_quaternion: In source snapshot src/math/rotations/matrix_to_quaternion.c (SHA-256 182b3f8118adcac2608b8ede9e0aba91448828e8c1a68922143ad0a2a1e94eed), arg0 initializes float *q and receives q[0..3]. Retail 0x00214270 saves a0 in s5; 0x002142fc stores half sqrt(trace+1) at s5+0xc, and 0x00214310/0x00214324/0x0021433c store the scaled antisymmetric matrix differences at s5+0/4/8. Original Ghidra param_1 has the same writes, proving the quaternion output buffer. arg1 -> rotation_matrix: The authoritative source initializes float (*m)[4] from arg1 and reads its upper-left 3x3 block to form the quaternion. Retail 0x00214278 saves a1 in s0; 0x00214298/0x0021429c/0x002142a0 load s0+0/0x14/0x28 and sum them as the trace. Reads at 0x00214300..0x00214330 form off-diagonal differences. Original Ghidra param_2[0], [5], [10] and [9]-[6] confirm four-float row stride and the rotation-matrix input role.
arg0 -> unused_arg0: The authoritative src/ui/map/pick_map_slot_to_evict.c snapshot (SHA-256 22f8de2ad0591909b223dedad364c5a16f763623301b5391956eb9ea34a9bd0d) never references s32 arg0 in its body. Retail 0x002052c0 assigns a0=4 on the level-zero path before use; the other path loads a0 from level_map_selection.level at 0x00205308 before the helper call. No incoming a0 value is read or saved. The original Ghidra decompilation declares FUN_00205278(void), corroborating non-use. arg1 -> unused_arg1: The authoritative C body never references s32 arg1. Retail 0x002052bc overwrites a1 with the global-state base before using it on the level-zero path. The alternate path never consumes incoming a1; 0x00205398 assigns a1=-1 before the slot_id store at 0x002053a8. No incoming a1 value is read or saved anywhere in the supplied instruction table. Original Ghidra FUN_00205278(void) corroborates that no input parameter is consumed.
arg0 -> resource: In src/runtime/state/check_state_range.c (SHA-256 554daa1f84149263fc8439897ee924c934fc4c50e08bbe4657bdaaf5a0363333), s32 arg0 is forwarded as the first argument to call_global_state_resource, whose existing declaration names that s32 parameter resource. Original Ghidra decompilation likewise calls FUN_00116c70(param_1,0,10). Retail 0x00112384 zeros a1 and 0x00112390 sets a2 to 10 for the jal at 0x0011238c, while a0 is untouched; thus the incoming argument supplies the resource operand unchanged.
arg0 -> unused_arg: In the authoritative src/audio/rpc/snd_reset_state_and_flush_commands.c snapshot (SHA-256 37d624f251db1be2d5ea61c1ea12f70c91d06b9abfb61c686717342eae547ca7), s32 arg0 occurs in declarations but is never referenced by the function body: it stores zero to GlobalTableStatus and calls snd_flush_sound_commands() without arguments. The complete retail body at 0x0012eb00-0x0012eb1c contains no explicit read of a0; 0x0012eb04 stores zero and 0x0012eb0c calls 0x0012dc80. The supplied original Ghidra decompilation likewise declares continue_sound_rpc_submissions(void). These establish unused_arg as a bounded description of this wrapper parameter.
arg0 -> unused_arg: In src/audio/decoder/audio_dec_delete.c (SHA-256 e861985c1a74277ad106be0f00655cb59023b00b23edb9aa270dee3a0483f4e9), s32 arg0 is never referenced: audio_dec_delete calls snd_close_movie_sound() then returns 1. Retail 0x0023ac90-0x0023acac only saves/restores ra and sp, calls 0x0012f0e0 at 0x0023ac98, and sets v0=1 at 0x0023aca4; no instruction explicitly reads a0. The original Ghidra decompilation likewise has a void argument list and only stop_mpeg_audio_rpc_driver(); return 1. This proves unused_arg within the assigned function.
arg0 -> destination: The current void *arg0 is cast to char *p solely to address stores. Retail a0 is the base for sw zero at 0x0021df40 (+0x48), swc1 f0 at 0x0021df44 (+0x38, bits 0x40490fdb), sw zero at 0x0021df48 (+0x34), and the delay-slot sw at 0x0021df50 (+0x44). The original Ghidra param_1 likewise supplies all four store addresses, proving it is the destination of initialization writes.
arg0 -> projected_velocity: In src/audio/snd_get_doppler_pitch_mod.c (SHA-256 51bb60a6e29e9c60038578bf8fb808e6ae7beb0b622701954c86db966a55f335), int arg0 is the only input to (arg0 * 0x5F4) / 0x2E5. Retail 0x0012f1a8 multiplies incoming a0 by 1524, 0x0012f1b4 divides the signed product by 741, and 0x0012f1b8 returns the quotient. The supplied original Ghidra decompilation names this input projected_velocity and records that sound_update (call at 0x0022d5b0) derives it from a source/listener velocity projection multiplied by 300, supporting the projected_velocity role.
arg0 -> unused_mpeg: In the supplied source snapshot (SHA-256 0b4b210e9d3e21833a79b02d42c01322b5ace133d26f6e6a26a53f9bd6440aeb), mpeg_error's s32 arg0 is never referenced. The recovered mpegError__FP7sceMpegP18sceMpegCbDataErrorPv alias identifies the first callback argument as the MPEG object. Retail 0x0023d084 overwrites incoming a0 with lui a0,0x16, and 0x0023d08c forms the diagnostic string address without any read of incoming a0. Only cb_data in a1 is read at 0x0023d094 (+4). Original Ghidra likewise leaves param_1 unused. Thus unused_mpeg documents its callback role and proven non-use without changing its s32 type.
arg0 -> payload_word: Authoritative src/audio/streaming/snd_stream_safe_check_cd_idle.c (SHA-256 647d5fbad72f46d827ad9cde1de31fcfd2fc2202b9ce4a85517e02267910dc5c) copies s32 arg0 unchanged into *(s32 *)sp_slot and passes sp_slot with byte length 4 to snd_send_iop_command_and_wait(0x36, 4, sp_slot). Retail 0x0012ed38 stores incoming a0 at 0(sp); 0x0012ed34 sets a1=4, 0x0012ed3c sets a2=sp, and 0x0012ed44/48 calls 0x0012e548 with a0=0x36. Original Ghidra likewise copies dwWord into auStack_20[0] before snd_SendIOPCommand(0x36,4,auStack_20), proving the sole 32-bit payload word role.
arg0 -> playback_mode: In src/audio/mixer/snd_set_playback_mode.c (SHA-256 a17801aeb6bb33d8d17a3c839bbc969792c4965c7b14faaa69be0e0583552d96), s32 arg0 is copied unchanged into *(s32 *)sp_slot. Retail 0x0012e248 stores incoming a0 at sp+0; 0x0012e244 sets payload size 4, 0x0012e24c passes sp as a2, and 0x0012e254/0x0012e25c send command 11 to 0x0012e6e0. The established snd_set_playback_mode name and original snd_SetPlaybackMode(int nMode) decompilation identify this word as the playback mode.
arg0 -> sound_handle: The authoritative src/audio/voices/snd_stop_sound.c snapshot (SHA-256 2f01065bc59ff43c4c67ffa15aaf57d0eb179f5414dc8e6035daed18b4ed09d5) assigns s32 arg0 directly to buf[0]. Retail 0x0012e370 stores incoming a0 at sp+0; 0x0012e374 passes that stack payload in a2, with four-byte length at 0x0012e36c and command 0x15 at 0x0012e37c to snd_SendIOPCommandNoWait at 0x0012e384. The supplied original Ghidra signature names this exact 32-bit input nSoundHandle and describes command 21 as continuing one sound handle, supporting sound_handle without changing the established C function name.
arg0 -> point_light_index: At 0x00201f68 the retail wrapper saves incoming a0 in s0 across detach_point_light (jal 0x00201f88 at 0x00201f64), then restores it into a0 at 0x00201f70 for create_point_light (jal 0x00201ba8 at 0x00201f6c). Source and original Ghidra both show unchanged forwarding. In the checked helper, 0x00201bb8 saves that argument in s4; 0x00201bc0 multiplies it by 0x30 to select the record at 0x0019c3c0, while 0x00201bdc shifts it by 5 and 0x00201bec-0x00201c08 load the corresponding point-light position/radius at 0x0019c1c0 + index*0x20 + 0x10. Ghidra identifies this as g_abObjectRenderPointLights[param_1].vPosition_and_radius. Instructions 0x00201c50-0x00201ce8 shift the same index by 4/8/12 and insert it into packed point-light indices. These uses prove point_light_index rather than a pointer or count.
arg0 -> destination: In src/ui/menus/fun_0021ca98.c (SHA-256 f4f46a25bf611698e17229cbc0c2bcf7640df59aa1c7cec8c0f062334b999d0e), void *arg0 is used only as the base of the pointer store at byte offset 0x34. Retail Ghidra shows *(undefined4 *)(param_1 + 0x34) = uVar1; retail instruction 0x0021cab8 is sw v0,0x34(a0). Instructions 0x0021ca9c through 0x0021cab4 select 0x001d06d0 or 0x001d0708 according to the byte at 0x0013d4c2, proving a0/arg0 is the destination base.
arg0 -> bank_handle: The original retail snd_UnloadBank decompilation identifies nBankHandle. At 0x0012e1e0 sw a0,0(sp) copies this incoming s32 unchanged into the stack payload; 0x0012e1dc sets its size to 4, 0x0012e1e4 passes sp as the buffer, and 0x0012e1ec/0x0012e1f4 submit command 6 to snd_SendIOPCommandNoWait. The bound C mirrors this as *(s32 *)sp_slot = arg0 and snd_send_iop_command_no_wait(6, 4, sp_slot, 0, 0), proving the bank handle parameter role.
arg0 -> payload_word: Retail 0x0012e3f0 stores incoming a0 unchanged as one 32-bit word at sp+0; 0x0012e3ec sets size a1=4 and 0x0012e3f4 passes sp as a2. At 0x0012e3fc command a0 becomes 0x16 before the 0x0012e404 call to 0x0012e6e0. The source likewise copies s32 arg0 into sp_slot and submits (22,4,sp_slot,0,0); original Ghidra copies dwWord to auStack_20[0]. Thus the parameter is the command payload word.
arg0 -> channel_control: In src/sdk/dma/set_d3_chcr.c (SHA-256 6b226c67cd02d6669c107651bfe644adf65dd9305c02ecf349dcf65dd9305c02ecf349dcf69b4e351d6d), arg0 is assigned directly to volatile u32 MMIO 0x1000B000. Retail 0x0012cb60 preserves incoming a0 in s0, 0x0012cb7c/0x0012cb88 construct 0x1000B000 in v1, and 0x0012cb94 stores s0 there without modifying the value. The supplied original Ghidra decompilation identifies this destination as REG_DMAC_3_IPU_FROM_CHCR and the argument as the complete CHCR control word; surrounding writes set and clear DMAC freeze bit 16.
arg0 -> slot_index: Retail 0x0011b504 copies a0 to s0; 0x0011b51c checks it unsigned against 0x20, returning null on failure. At 0x0011b538 it is shifted left four bits and at 0x0011b548 added to table base 0x00157D80, then returned at 0x0011b54c. Source equivalently bounds arg0 < 32 and returns &D_00157D80[arg0 << 4]. The original Ghidra decompilation identifies the argument as slot_index and the result as g_sif_file_slots + slot_index.
arg4 -> motion_vector_state: In src/sdk/library/_decMB0.c (SHA-256 7edd251a39836906af8132c640c5cb26c8fed107346c4f1ef00b2699fe31a9b7), struct MpegMbState *arg4 is the state passed to _motionVectors and _motionVector. Retail 0x00127c3c saves incoming t0 in s1; 0x00127e04 and 0x00127e44 pass s1 as a1 to those helpers, while 0x00127ed8 passes s1+8 for backward single-vector decoding. Retail 0x00127ff4-0x00128010 clears its eight words for intra macroblocks without concealment vectors; 0x00128034-0x00128044 clears the forward subset for P-picture macroblocks lacking intra/forward flags. Original Ghidra param_5/puVar4 follows the same helper and reset data flow, proving motion-vector state storage.
arg0 -> decoder: In src/sdk/library/cpr8.c (SHA-256 fc553539a63c03c769910e0f78f04b0c81fa872161c4130bb1ddc234b6fe34ec), arg0 has type struct MpegDecoder *. Retail 0x001298c0 preserves a0; 0x001298ec loads its +0xd8 destination base, which reaches SPR_FROM_MADR at 0x00129a3c. Its +0x174 and +0xe0 fields select copy layout at 0x001298f0-0x00129978, and +0xe4 advances the destination between passes at 0x00129ae4-0x00129b04. Thus decoder names the decoder object supplying destination and frame layout. arg1 -> copy_params: The bound C declares arg1 as struct MpegCopyParams *. Retail 0x001298bc preserves it in s6; 0x001298e8 loads offset 0, masks it at 0x001298f4, and writes the resulting source address to SPR_TO_MADR at 0x001299c0. Offset +0x10 determines transfer bytes and QWC at 0x00129924-0x00129934 or 0x00129954-0x00129978, while +0xc bounds the copy loop at 0x00129988 and 0x00129a6c-0x00129ac4. These uses prove copy_params describes the copy configuration object.
arg0 -> decoder_state: Retail 0x001282dc preserves a0 in s3, subsequently passed to decode_ipu_vlc at 0x0012831c/0x00128374 and read_mpeg_bits at 0x00128334/0x0012838c. Original Ghidra explicitly casts this parameter to MpegVideoDecoderState *pState; source arg0 follows the same _ipuVdec/_nextBit data flow. arg1 -> motion_vector: Source types arg1 as struct MotionVector *. Retail 0x001282e4 preserves it in s2, passes s2 to component decoder FUN_001280a8 at 0x00128354, then s2+4 at 0x001283bc/0x001283c0. Loads/stores at 0x001283a8-0x001283b0 and 0x001283cc-0x001283d4 operate on its second component. arg3 -> first_component_bit_count: Retail 0x00128314 saves a3 in s1; when both s1 and the first VLC result are nonzero, 0x00128334/0x00128338 passes s1 as the bit count to read_mpeg_bits. 0x00128348 then supplies the same value to FUN_001280a8 with the base motion-vector address. Source _nextBit(arg0,arg3) and decode_motion_vector(arg1,arg3,code,bits,arg7) agree. arg4 -> second_component_bit_count: Retail 0x0012830c saves the fifth argument in s4; 0x0012838c/0x00128390 passes s4 as read_mpeg_bits bit count for the second VLC result. 0x001283a4 and 0x001283bc/0x001283c0 pass that count with motion_vector+4 to FUN_001280a8, matching source _nextBit(arg0,arg4) and the second decode_motion_vector call. arg6 -> halve_second_component_for_decode: Retail 0x001282fc preserves the seventh argument in s6. Its nonzero branch at 0x001283a0 enables arithmetic right shift of the second component at 0x001283a8-0x001283b0 before FUN_001280a8; the same flag at 0x001283c4 enables left shift at 0x001283cc-0x001283d4 afterward. Source arg6 gates exactly these pre-decode halving and post-decode doubling operations.
arg2 -> skip_threshold: In source src/sdk/library/_decodeOrSkip.c (SHA-256 e20026601bc46ff804cf5c11db635261b98978159960333de1c39976863e76eb), arg2 is the third s32 parameter forwarded to both helpers. Root instructions 0x0012bf38/0x0012bf48 preserve a2. Frame helper 0x0012be24 bypasses comparison for a2 == -1; 0x0012be2c performs signed slt a1,a2, and 0x0012be30 selects 0x0012be74 when a1 >= a2, omitting 0x001293f0 and requesting MPEG input at 0x0012be84. Field helper 0x0012bf8c/0x0012bf94 applies the same sentinel/comparison; s3 remains zero for a1 >= a2, gating out 0x001293f0 at 0x0012bfcc and 0x0012c03c and selecting the input request at 0x0012c090. Thus this is the skip decision threshold, with -1 disabling that threshold.
arg0 -> decoder_state: At 0x00128a70 the incoming a0 pointer is saved in s0, then used by _waitIpuIdle at 0x00128a78 and restored into a0 at 0x00128aa4, 0x00128ab8 and 0x00128ac4 for _flushBuf and _peepBit. The source passes this same s32 * to the wait, alignment advance, 24-bit peek and eight-bit advance operations. Original retail Ghidra identifies the parameter as MpegVideoDecoderState *pState in this MPEG start-code search, proving decoder_state as its role without changing its type.
arg0 -> media_mode: In sceCdMmode, source mode = arg0 feeds *(s32 *)D_00132900 = mode. Retail 0x0012139c saves incoming a0 to s0; 0x001213b4 stores s0 at 0x00132900 after command acquisition. Instructions 0x001213c0-0x001213c8 write back four bytes, and 0x001213dc-0x001213f8 pass that address and size 4 as the synchronous RPC 0x22 request. The prepared original Ghidra decompilation identifies this same parameter as media_mode and the request as the native CD media selector.
arg0 -> destination_address: Retail 0x0012a140 saves a0 in s0; 0x0012a154 masks it with 0x0FFFFFFF, 0x0012a15c sets 0x80000000, and 0x0012a164 writes it to 0x1000B010, identified by the original decompilation as REG_DMAC_3_IPU_FROM_MADR. In receiveDataFromIPU this is the memory destination address of the from-IPU transfer, exactly matching the source arg0 expression. arg1 -> byte_count: Retail 0x0012a134 saves a1 in s1; 0x0012a16c shifts s1 right by 4 and 0x0012a174 stores it to 0x1000B020, identified by the original decompilation as REG_DMAC_3_IPU_FROM_QWC. The source arg1 >> 4 thus converts the supplied byte count to 16-byte quadword count before the transfer starts at 0x0012a180.
arg0 -> decoder: In src/sdk/library/update_temp_track_data.c (SHA-256 82088aa86a94502612f3351ae69130bd6e1cf63b0b67c545600870e32cc3daae), arg0 has type struct MpegDecoder * and owns every state access. Retail 0x00129088 copies the first parameter a0 into a2; 0x00129090 reads picture_coding_type at a2+0x150, 0x001290c0 reads state at +0x84c, and 0x001290cc/0x001290e0 and 0x001290f8 write state at +0x1ac and +0x850. The supplied original Ghidra decompilation identifies this same base as MpegVideoDecoderState *pState. These type and base-pointer flows establish decoder as its role.
arg0 -> enable_dma: In sceDmaReset(s32 arg0), the source uses arg0 only in if (arg0 == 1) before ORing 1 into volatile u32 at 0x1000E000. Retail 0x00123028 preserves incoming a0 in s0; 0x001230ac loads 1 and 0x001230b0 compares s0 with it. The equal path reads DMAC CTRL at 0x001230c0, ORs bit 0 at 0x001230c4, and stores it at 0x001230c8. Original Ghidra reset_dmac(int enable) shows the same conditional enable operation.
arg0 -> dependency_index: In src/sdk/library/sceDbcGetDepNumber.c (SHA-256 b630d7e6b05a0d04eaf4530e5c9cd42730d6afddfb3665069cd3c0e4504af448), s32 arg0 indexes ((s32 *)D_0015B500)[arg0] and is copied to RpcReceiveData.unk0. Retail 0x001247ec preserves a0 in s2; 0x001248a4 scales s2 by four, 0x001248ac adds the snapshot base, and 0x001248b0 loads the selected word for comparison to one. At 0x001248cc the same s2 is stored to request word zero at 0x0015B080 before RPC 0x80000903 at 0x001248f0. The original Ghidra decompilation identifies the array as the dependency snapshot and the parameter as dependency, supporting dependency_index.
arg0 -> request: In the bound source, arg0 has type struct RpcRdataRequest *. Retail 0x0011aea0 saves incoming a0 in s0; 0x0011aeb0 and 0x0011aeb8 load its +0x14/+0x1c fields and 0x0011aec0/0x0011aec8 copy them into the newly allocated reply packet. At 0x0011aee0/0x0011aee4/0x0011aee8 its +0x28/+0x20/+0x24 fields become transfer arguments to isceSifSendCmd. The original Ghidra decompilation likewise reads these values from its incoming packet parameter, proving request as its role.
arg1 -> initial_bit_pointer: In src/sdk/system/sysbit_init.c (SHA-256 41ad116bb624b3cf42566c86394cdc2488be32530b4aa6a84c1c61d7a20a2206), the s32 arg1 is assigned directly to ctx->bit_pointer and ctx->field8. Retail 0x0012a934 saves incoming a1 in t0; 0x0012a93c stores t0 to context offset 0xc (bit_pointer), and 0x0012a94c stores the same value to offset 0x8. Original Ghidra param_2 has precisely these two stores. Thus this parameter is the initial bit_pointer value; 0x0012a948 then sets a1 to zero for _sysbitFlush, independently of the saved incoming value.
arg1 -> ref_image: In the authoritative src/sdk/library/_dispRefImage.c snapshot (SHA-256 b2eb7f40a609f6ca86bc8cd08c8e00edf6e1c65a1633e22d4c66c1e98c4dfc4b), arg1 has type struct MpegRefImage *. Retail 0x00129cfc saves a1 in s1; 0x00129d4c through 0x00129d98 copy fields at s1+0x5c/0x60/0x44..0x58 into decoder display state. Retail 0x00129da4 checks its status at +0x28 against 1, and 0x00129db8 forwards s1 as a1 into _csc_storeRefImage or _cpr8. The original Ghidra param_2 data flow agrees, proving this is the reference image processed by _dispRefImage.
arg0 -> channel_control: In SetD4Chcr, retail 0x0012cbc8 copies incoming a0 into s0 across DIntr; 0x0012cbf0 forms MMIO 0x1000b400 and 0x0012cbfc stores s0 there unchanged. The source assigns arg0 directly to *(volatile u32 *)0x1000B400. Original Ghidra identifies this destination as REG_DMAC_4_IPU_TO_CHCR and the parameter as the complete CHCR value. Thus arg0 is the channel control word, not a pointer or a single flag.
arg0 -> reent_context: In authoritative src/sdk/library/sinit.c (SHA-256 054328bc65eb6d5bd5ac315d15907eb0557109994cf94f2081b688c68ac1141e), __sinit takes struct Reent *arg0. Retail 0x00113af0 retains a0 in s0; 0x00113b04/0x00113b08 write context offsets 0x3c/0x38. The original decompilation derives all three helper destinations from this same base (+0x1e4, +0x23c, +0x294), and instructions 0x00113b10, 0x00113b24 and 0x00113b38 pass s0 as a3 to each std call. Final stores at 0x00113b4c-0x00113b54 initialize offsets 0x1e0, 0x1dc and 0x1d8 of the same object. These uses prove reent_context as the typed initialization context.
arg0 -> callback: In src/sdk/library/sceCdCallback.c (SHA-256 ca81bd6ba8174ac851f1f6a9242ad48521865563be6170ca331e4e5e3f98f84b), s32 arg0 is assigned to D_00159740[0] after sceCdSync(1) succeeds. Retail 0x00120680 preserves a0 in s1; 0x001206a8 loads the previous registration into s0, and 0x001206b0 stores s1 into the same slot before 0x001206bc returns s0. The original Ghidra decompilation identifies this slot as g_pNativeCdCallback and the incoming value as callback, proving the replacement callback role.
arg0 -> chcr_value: At 0x0012ced0 incoming a0 is preserved in s0 across DIntr; 0x0012ceec/0x0012cef8 form MMIO address 0x1000B400, and 0x0012cf04 stores s0 there unchanged. The authoritative C assigns s32 arg0 directly to *(volatile u32 *)0x1000B400. Original Ghidra identifies this as REG_DMAC_4_IPU_TO_CHCR = dwControl, proving a complete CHCR value rather than a mask or address.
arg0 -> sync_mode: In the authoritative sceIpuSync source (SHA-256 7a2d2f2611c3db1c84d4e1757a1fa5a39cd0eef31be225ac8d57912cde5819a2), s32 arg0 controls the switch. Retail 0x0012ce58 tests a0 against zero to select the signed CTRL read loop at 0x0012ce80/0x0012ce94; 0x0012ce60-0x0012ce64 compares it with one to select the single CTRL read and bit-31 extraction at 0x0012ceac-0x0012ceb0. Other values return zero without reading CTRL. Original Ghidra nMode has the same flow, proving this parameter is the synchronization mode.
arg0 -> port_index: In the authoritative src/sdk/input/sce_pad2_get_side.c snapshot (SHA-256 d225444d3c7b16471756a3f9f1bb66ac6572d871ea0fd34c1816fd519f127065), s32 arg0 is used as D_0015B540[arg0].unkC. Retail 0x00124f38 loads the PadPort stride 0x330, 0x00124f40 multiplies incoming a0 by it, 0x00124f44-0x00124f50 add the table base 0x0015B540, and 0x00124f54 loads the selected entry's pointer at offset 0xC. The supplied original Ghidra decompilation likewise indexes g_aPad2Sockets[socket].pDouble_buffer. This proves the argument is the pad-port table index.
arg0 -> socket_index: In the authoritative source src/sdk/input/sce_pad2_check_dma.c (SHA-256 ce91e037f304cf547934e94ac343a08d02f24dbfcb608d7eeb56a1de2e5d305d), s32 arg0 indexes D_0015B540[arg0].unkC. Retail 0x00124fa0 loads stride 0x330, 0x00124fa8 multiplies incoming a0 by that stride, 0x00124fb4 adds the array base, and 0x00124fb8 loads the selected record's buffer pointer at +0xC. Prepared Ghidra expresses the same flow as g_aPad2Sockets[socket].pDouble_buffer. Thus the argument is a socket record index; subsequent +0x7C sequence reads and +0x80 bank selection operate on its chosen buffer.
arg0 -> decoder: In the authoritative C, arg0 has type struct MpegDecoder * and owns frame_count, second_field, picture_structure and ref_images. Retail 0x0012c144 preserves incoming a0 in s0; 0x0012c148/150/168 read decoder fields at +0x120/+0x118/+0x174, and 0x0012c178/190/194 load its reference-image pointers. At 0x0012c184 and 0x0012c19c this same pointer is passed as a0 to _dispRefImage and _dispRefImageField; the error path passes it to _Error and every path clears its +0x120 field. Original Ghidra likewise casts param_1 to MpegVideoDecoderState *pState. These uses prove the decoder role.
arg0 -> work_address: In the bound source src/sdk/library/sceDbcSetWorkAddr.c (SHA-256 06ed92f4316d0b5bf9785b55227612a99865a76638ee76bb50000415095f8e9f), s32 arg0 is assigned directly to RpcReceiveData.unk4. Retail 0x001246c0 forms the shared buffer pointer in a3 and 0x001246c8 stores incoming a0 to 4(a3); 0x001246e4 submits that buffer to sceSifCallRpc with command 0x80000904 and 0x400-byte send/receive sizes. The established function sceDbcSetWorkAddr and supplied original Ghidra decompilation identify this unchanged request word as work_address. Thus work_address describes the parameter's address payload without changing its s32 type.
arg1 -> bit_count: In the authoritative C, s32 arg1 flows unchanged through value into command = value | 0x40000000. Retail 0x00128850 preserves a1 in s1; 0x001288b8 loads the FDEC opcode 0x40000000, 0x001288c0 ORs s1 into it, and 0x001288c8 writes it to IPU_CMD at 0x10002000. The original retail decompilation identifies this operand as nBitCount, the number of bits advanced; the completed result becomes the refreshed bit window at 0x001288fc with 32 available bits at 0x001288f8. Thus bit_count describes the second parameter's proven bit-advance role.
arg0 -> iop_address: Retail 0x0011cb84 saves first parameter a0 in s3; 0x0011cbd8 stores s3 into the request word at 0x00158200, matching source SIFCMD->unk0 = arg0. At 0x0011cd14/0x0011cd1c/0x0011cd2c this request is sent through sceSifCallRpc operation 6. The supplied original Ghidra signature calls this uint iop_address and its plate identifies loading a module already resident in IOP memory. The parameter is forwarded as the module's IOP address, while the separate src/size parameters supply argument bytes at request offset 0x104.
Decompilation progress
No function changed its match state compared with main (d893976). Compared with main (d893976). C_FUZZY uses main's last measurement. |
pezzadev
marked this pull request as ready for review
October 17, 2026 22:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before
Existing resident C used generic parameter and local names, including argument numbers and register-like temporaries, even where their roles were identifiable from retail instructions and data flow.
After
Clarify 181 parameters and locals across 135 existing functions. Examples include audio bank/stream handles and callbacks, decoder state and buffers, matrix/quaternion inputs and outputs, DMA channel controls, menu screens, texture coordinates, and loader tables.
Changes are limited to scoped C identifiers. Function names, types, parameter order, expressions, constants, globals, linked symbols, source paths, and build ownership are preserved. Unresolved roles retain their existing names.
This is readability cleanup, with no new exact-C promotions or claimed increase in matched-byte coverage. The batch is rebased onto main after batch 18 was merged; it does not reintroduce that earlier batch's changes.
Verification
make elfreproduces the retail ELF SHA-256.make overlayspasses the official placed-byte checks.make checkpasses.Draft for review.