Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/game/controller-input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Controller input

`PadState` in `include/rnc/input/pad_state.h` describes the record at
`D_0013C940`. The boot producers are `poll_pad_device_state` (`FUN_002170c8`),
`clear_pad_input` (`FUN_002172c0`) and `process_pad_input` (`FUN_00217328`).

| Offset | Field | Meaning |
|---|---|---|
| `0x100`, `0x140` | `analog`, `analog_prev` | Stick axes and pressure values, then their copy |
| `0x180`, `0x184` | `button_profile`, `vibration_profile` | SDK device profiles |
| `0x1A0`, `0x1A4`, `0x1A8` | `held`, `pressed`, `released` | Button masks including stick directions |
| `0x1B0`–`0x1BC` | `raw_*`, `prev_raw_held` | Button-only masks and previous poll |
| `0x1C0`–`0x1C8` | `*_unmasked` | Masks before mode filtering, with mirror swap undone |
| `0x1E0`, `0x258`, `0x2D0` | `pressed_history`, `angle_history`, `float_history` | Thirty-sample button, angle and magnitude rings |
| `0x348` | `saved_held` | Held mask before mode filtering, used by the next poll |
| `0x34D`–`0x34F` | `repeat_delay`, `repeat_rate`, `repeat_timer` | Button-repeat timing |

`pad_held_words` (`D_0013CAE0`) and `pad_pressed_words` (`D_0013CAE4`) name the two
interior words separately because retail code addresses them directly.
The array declarations preserve the original address formation; the scalar
`pad_held_lui` and `pad_pressed_lui` aliases preserve explicit non-small-data access.
These two deliberate array/scalar declaration variants remain in the declaration audit. The controller record
also retains a `_lui` alias; pyrocitor uses the second name to preserve address
reconstruction between button tests.

Signed and unsigned views are intentional. Some menu/debug/movie paths load
two button words together; their `PadStateWords` member views or explicit `u64`/PS2 `long` accesses
must not become two independent loads. The member views also preserve the
compiler's base-plus-field addressing where a scalar pointer cast does not. Pause-menu entry reads the unmasked pressed
word through a volatile signed view. The save-loading menu reads `raw_pressed`,
not `held`.

These names and layouts follow the existing matching producer and consumer C.
Byte equality qualifies this cleanup; it does not establish native gameplay
or new PS2 runtime coverage.
6 changes: 4 additions & 2 deletions include/rnc/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

#include "types.h"

struct PAD;
struct PadState;

void poll_pad_device_state(struct PAD *) __asm__("FUN_002170c8");
void poll_pad_device_state(struct PadState *) __asm__("FUN_002170c8");
void clear_pad_input(struct PadState *) __asm__("func_002172C0");
void process_pad_input(struct PadState *, u8 *, s32) __asm__("func_00217328");
void reset_pad_history(void) __asm__("func_00217020");

#endif /* LOMBYTE_RNC_INPUT_H */
10 changes: 9 additions & 1 deletion include/rnc/input/pad_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
#define LOMBYTE_RNC_INPUT_PAD_GLOBALS_H

#include "types.h"
#include "sda.h"

extern s32 pad_held[] __asm__("D_0013CAE0");
/* Button words within controller_state, at offsets 0x1A0 and 0x1A4. */
/* Array views preserve address formation in the original array consumers. */
extern s32 pad_held_words[] __asm__("D_0013CAE0");
extern s32 pad_held_words_lui[] __asm__("D_0013CAE0") NOT_SDA;
extern s32 pad_pressed_words[] __asm__("D_0013CAE4");

extern s32 pad_held_lui __asm__("D_0013CAE0") NOT_SDA;
extern s32 pad_pressed_lui __asm__("D_0013CAE4") NOT_SDA;

#endif /* LOMBYTE_RNC_INPUT_PAD_GLOBALS_H */
29 changes: 23 additions & 6 deletions include/rnc/input/pad_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define LOMBYTE_RNC_INPUT_PAD_STATE_H

#include "types.h"
#include "sda.h"

/*
* Controller state D_0013C940, polled each frame by poll_pad_device_state
Expand Down Expand Up @@ -33,9 +34,11 @@

struct PadState {
u8 pad_0[0x100] __attribute__((aligned(16)));
f32 analog[16]; /* 0x100: [0..3] stick axes (-1..1), [4..15] pressure (0..1) */
f32 analog_prev[16]; /* 0x140: copy of analog */
u8 pad_180[0x9];
f32 analog[16]; /* 0x100: [0..3] stick axes (-1..1), [4..15] pressure (0..1) */
f32 analog_prev[16]; /* 0x140: copy of analog */
u8 button_profile[4]; /* 0x180: scePad2GetButtonProfile */
u8 vibration_profile[4]; /* 0x184: sceVibGetProfile */
u8 unk188;
u8 unk189; /* 0x189: copied by metal_detector_update on spawn */
u8 pad_18A[0x4];
s16 hist_idx; /* 0x18E: cleared with unk190 by reset_pad_history */
Expand All @@ -60,11 +63,17 @@ struct PadState {
s32 stick_moved; /* 0x1D8: analog[2] or analog[3] nonzero */
s32 unk1DC; /* 0x1DC: 0x79 if the button profile is all ones, else 0; l01 picks pressure input on 0x79 */
u32 pressed_history[30]; /* 0x1E0: ring indexed by hist_idx, searched by pad_pressed_within */
u8 pad_258[0x78];
f32 float_history[30]; /* 0x2D0: ring indexed by hist_idx, read by read_pad_float_history */
f32 angle_history[30]; /* 0x258: left-stick direction history */
f32 float_history[30]; /* 0x2D0: ring indexed by hist_idx, read by read_pad_float_history */
s32 saved_held; /* 0x348: held before mode masking, copied to prev_held on the next poll */
u8 pad_34C;
u8 repeat_delay; /* 0x34D */
u8 repeat_rate; /* 0x34E: zero disables button repeat */
u8 repeat_timer; /* 0x34F */
};

extern struct PadState controller_state __asm__("D_0013C940");
extern struct PadState controller_state_lui __asm__("D_0013C940") NOT_SDA;

/*
* The same pad state as some functions read it: the stick axes, and the held/pressed button words,
Expand All @@ -82,7 +91,15 @@ struct PadStateWords {
s32 pressed; /* 0x1A4 */
} w;
} buttons;
char pad1A8[0x1D8 - 0x1A8];
char pad1A8[0x1C0 - 0x1A8];
union {
long held_pressed; /* PS2 long-width unmasked pair, used by the trespasser */
struct {
s32 held;
s32 pressed;
} w;
} unmasked;
char pad1C8[0x1D8 - 0x1C8];
s32 stick_moved; /* 0x1D8: analog[2] or analog[3] nonzero */
};

Expand Down
1 change: 0 additions & 1 deletion include/rnc/overlay/shared/world/level_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

/* Shared overlay globals whose complete owning layouts are not recovered yet. */

extern u32 D_0013CAE4 __attribute__((section(".data")));
extern s32 D_L10_0015F5C4_vendor __asm__("D_L10_0015F5C4");
extern char D_L12_00167240[];
extern char *D_L12_0015FFD8_p __asm__("D_L12_0015FFD8");
Expand Down
2 changes: 1 addition & 1 deletion scripts/test_public_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ class DataDeclarationTests(unittest.TestCase):
"""No new data label may get a second type or name (scripts/data-decls.py)."""

# Labels that still disagree; lower it when you fix some, never raise it.
KNOWN_CONFLICTS = 420
KNOWN_CONFLICTS = 384

def test_no_new_conflicting_declarations(self):
decls = load_module("rnc_data_decls", ROOT / "scripts" / "data-decls.py")
Expand Down
33 changes: 29 additions & 4 deletions src/check/pad_state_layout_check.c
Original file line number Diff line number Diff line change
@@ -1,24 +1,49 @@
/* Built only by `make layout-check-sys` (never linked). gcc 2.95 has no
_Static_assert: a negative array size fails the compile. */
/* Compiled by make check with the EE compiler; never linked. */
#define OFFSET_CHECK(name, type, field, off) \
typedef char offset_check_##name[((unsigned long)&((type *)0)->field == (off)) ? 1 : -1]

#include "rnc/input/pad_state.h"

OFFSET_CHECK(analog, struct PadState, analog, 0x100);
OFFSET_CHECK(analog_prev, struct PadState, analog_prev, 0x140);
OFFSET_CHECK(button_profile, struct PadState, button_profile, 0x180);
OFFSET_CHECK(vibration_profile, struct PadState, vibration_profile, 0x184);
OFFSET_CHECK(unk188, struct PadState, unk188, 0x188);
OFFSET_CHECK(unk189, struct PadState, unk189, 0x189);
OFFSET_CHECK(hist_idx, struct PadState, hist_idx, 0x18E);
OFFSET_CHECK(hist_count, struct PadState, hist_count, 0x190);
OFFSET_CHECK(socket, struct PadState, socket, 0x194);
OFFSET_CHECK(profile_state, struct PadState, profile_state, 0x198);
OFFSET_CHECK(device_state, struct PadState, device_state, 0x19C);
OFFSET_CHECK(held, struct PadState, held, 0x1A0);
OFFSET_CHECK(pressed, struct PadState, pressed, 0x1A4);
OFFSET_CHECK(released, struct PadState, released, 0x1A8);
OFFSET_CHECK(prev_held, struct PadState, prev_held, 0x1AC);
OFFSET_CHECK(raw_held, struct PadState, raw_held, 0x1B0);
OFFSET_CHECK(raw_pressed, struct PadState, raw_pressed, 0x1B4);
OFFSET_CHECK(profile_state, struct PadState, profile_state, 0x198);
OFFSET_CHECK(device_state, struct PadState, device_state, 0x19C);
OFFSET_CHECK(raw_released, struct PadState, raw_released, 0x1B8);
OFFSET_CHECK(prev_raw_held, struct PadState, prev_raw_held, 0x1BC);
OFFSET_CHECK(held_unmasked, struct PadState, held_unmasked, 0x1C0);
OFFSET_CHECK(pressed_unmasked, struct PadState, pressed_unmasked, 0x1C4);
OFFSET_CHECK(released_unmasked, struct PadState, released_unmasked, 0x1C8);
OFFSET_CHECK(mode, struct PadState, mode, 0x1CC);
OFFSET_CHECK(no_buttons, struct PadState, no_buttons, 0x1D0);
OFFSET_CHECK(no_direction, struct PadState, no_direction, 0x1D4);
OFFSET_CHECK(stick_moved, struct PadState, stick_moved, 0x1D8);
OFFSET_CHECK(unk1DC, struct PadState, unk1DC, 0x1DC);
OFFSET_CHECK(pressed_history, struct PadState, pressed_history, 0x1E0);
OFFSET_CHECK(angle_history, struct PadState, angle_history, 0x258);
OFFSET_CHECK(float_history, struct PadState, float_history, 0x2D0);
OFFSET_CHECK(saved_held, struct PadState, saved_held, 0x348);
OFFSET_CHECK(repeat_delay, struct PadState, repeat_delay, 0x34D);
OFFSET_CHECK(repeat_rate, struct PadState, repeat_rate, 0x34E);
OFFSET_CHECK(repeat_timer, struct PadState, repeat_timer, 0x34F);

typedef char pad_state_size_check[sizeof(struct PadState) == 0x350 ? 1 : -1];

OFFSET_CHECK(words_held_pressed, struct PadStateWords, buttons.held_pressed, 0x1A0);
OFFSET_CHECK(words_unmasked, struct PadStateWords, unmasked.held_pressed, 0x1C0);
OFFSET_CHECK(words_unmasked_pressed, struct PadStateWords, unmasked.w.pressed, 0x1C4);
OFFSET_CHECK(words_stick_moved, struct PadStateWords, stick_moved, 0x1D8);
typedef char pad_unmasked_pair_width_check
[sizeof(((struct PadStateWords *)0)->unmasked.held_pressed) == 8 ? 1 : -1];
50 changes: 16 additions & 34 deletions src/input/clear_pad_input.c
Original file line number Diff line number Diff line change
@@ -1,48 +1,30 @@
#include "types.h"

struct PAD {
u8 pad_0[0x1A0];
s32 unk1A0;
s32 unk1A4;
s32 unk1A8;
u8 pad_1AC[0x4];
s32 unk1B0;
s32 unk1B4;
s32 unk1B8;
u8 pad_1BC[0x4];
s32 unk1C0;
s32 unk1C4;
s32 unk1C8;
u8 pad_1CC[0x4];
s32 unk1D0;
s32 unk1D4;
s32 unk1D8;
};
#include "rnc/input/pad_state.h"

struct WordCell {
s32 unk0;
};

void clear_pad_input(struct PAD *pad_state) __asm__("FUN_002172c0");
void clear_pad_input(struct PadState *pad_state) __asm__("FUN_002172c0");

void clear_pad_input(struct PAD *pad_state) {
void clear_pad_input(struct PadState *pad_state) {
s32 remaining;
struct WordCell *slot;

slot = ((u8 *)pad_state + (0x140));
remaining = 0xF;
pad_state->unk1A0 = 0;
pad_state->unk1A4 = 0;
pad_state->unk1A8 = 0;
pad_state->unk1D0 = 1;
pad_state->unk1B4 = 0;
pad_state->unk1B8 = 0;
pad_state->unk1C0 = 0;
pad_state->unk1C4 = 0;
pad_state->unk1C8 = 0;
pad_state->unk1D8 = 0;
pad_state->unk1D4 = 1;
pad_state->unk1B0 = 0;
pad_state->held = 0;
pad_state->pressed = 0;
pad_state->released = 0;
pad_state->no_buttons = 1;
pad_state->raw_pressed = 0;
pad_state->raw_released = 0;
pad_state->held_unmasked = 0;
pad_state->pressed_unmasked = 0;
pad_state->released_unmasked = 0;
pad_state->stick_moved = 0;
pad_state->no_direction = 1;
pad_state->raw_held = 0;
do {
*(s32 *)((u8 *)slot - 0x40) = 0;
remaining -= 1;
Expand All @@ -51,4 +33,4 @@ void clear_pad_input(struct PAD *pad_state) {
} while (remaining >= 0);
}

extern void func_002172C0(struct PAD *pad_state) __attribute__((alias("FUN_002172c0")));
extern void func_002172C0(struct PadState *pad_state) __attribute__((alias("FUN_002172c0")));
66 changes: 18 additions & 48 deletions src/input/poll_pad_device_state.c
Original file line number Diff line number Diff line change
@@ -1,42 +1,12 @@
#include "types.h"
#include "rnc/input/pad_state.h"
#include "rnc/sdk/input.h"

struct PAD {
u8 pad0[0x180];
u8 unk180[4];
u8 unk184[4];
u8 unk188;
u8 unk189;
u8 pad18A[0xA];
s32 socket;
s32 unk198;
s32 unk19C;
s32 unk1A0;
s32 unk1A4;
s32 unk1A8;
s32 unk1AC;
s32 unk1B0;
u8 pad1B4[4];
s32 unk1B8;
s32 unk1BC;
s32 unk1C0;
s32 unk1C4;
s32 unk1C8;
s32 unk1CC;
s32 unk1D0;
s32 unk1D4;
s32 unk1D8;
s32 unk1DC;
u8 pad1E0[0x168];
s32 unk348;
};
#include "rnc/input.h"

extern void clear_pad_input(struct PAD *p) __asm__("func_002172C0");
extern void process_pad_input(struct PAD *p, u8 *buf, s32 len) __asm__("func_00217328");
void poll_pad_device_state(struct PadState *p) __asm__("FUN_002170c8");

void poll_pad_device_state(struct PAD *p) __asm__("FUN_002170c8");

void poll_pad_device_state(struct PAD *pad_state) {
void poll_pad_device_state(struct PadState *pad_state) {
enum {
PAD_PROFILE_INITIALIZATION = 0,
PAD_INPUT_POLLING = 1,
Expand All @@ -48,15 +18,15 @@ void poll_pad_device_state(struct PAD *pad_state) {
s32 i;
u8 pad_response_buffer[0x40];

pad_state->unk1A0 = 0;
saved_pad_value = pad_state->unk1B0;
pad_state->unk1B0 = 0;
pad_state->unk1AC = pad_state->unk348;
pad_state->unk1BC = saved_pad_value;
pad_state->held = 0;
saved_pad_value = pad_state->raw_held;
pad_state->raw_held = 0;
pad_state->prev_held = pad_state->saved_held;
pad_state->prev_raw_held = saved_pad_value;
pad_device_state = scePad2GetState(pad_state->socket);
pad_state->unk19C = pad_device_state;
pad_state->device_state = pad_device_state;
if (pad_device_state == 1) {
switch (pad_state->unk198) {
switch (pad_state->profile_state) {
case PAD_PROFILE_INITIALIZATION: {
byte_count = scePad2GetButtonProfile(pad_state->socket, pad_response_buffer);
if (*(u32 *)pad_response_buffer == 0xFFFFFFFF) {
Expand All @@ -66,26 +36,26 @@ void poll_pad_device_state(struct PAD *pad_state) {
}
if (byte_count < 5) {
for (i = 0; i < byte_count; i++) {
pad_state->unk180[i] = pad_response_buffer[i];
pad_state->button_profile[i] = pad_response_buffer[i];
}
pad_state->unk198 = 1;
pad_state->profile_state = 1;
} else {
pad_state->unk198 = 2;
pad_state->profile_state = 2;
byte_count = 0;
}
for (i = byte_count; i < 4; i++) {
pad_state->unk180[i] = pad_response_buffer[i];
pad_state->button_profile[i] = pad_response_buffer[i];
}
byte_count = sceVibGetProfile(pad_state->socket, pad_response_buffer);
if (byte_count < 5) {
for (i = 0; i < byte_count; i++) {
pad_state->unk184[i] = pad_response_buffer[i];
pad_state->vibration_profile[i] = pad_response_buffer[i];
}
} else {
byte_count = 0;
}
for (i = byte_count; i < 4; i++) {
pad_state->unk184[i] = pad_response_buffer[i];
pad_state->vibration_profile[i] = pad_response_buffer[i];
}
clear_pad_input(pad_state);
break;
Expand All @@ -100,7 +70,7 @@ void poll_pad_device_state(struct PAD *pad_state) {
}
} else {
clear_pad_input(pad_state);
pad_state->unk198 = 0;
pad_state->profile_state = 0;
}
pad_state->unk188 = 0;
pad_state->unk189 = 0;
Expand Down
Loading
Loading