#ifdef INTELLISENSE_DIRECTIVES
#	pragma once
#	include "dsl.h"
#	include "math.h"
#endif

/* PSX button bit positions — 1:1 with PSX-SPX docs at docs/psx-spx/docs/controllersandmemorycards.md:405-421.
 * Wire is active-low (0 = pressed).
 * The decoder atom computes buttons = (~raw_buttons) & 0xFFFF; 
 * active-low-to-active-high inversion is applied bit-by-bit. */
typedef Enum_(U2, PadBtns) {
	Bit_(Pad_Select,    0),
	Bit_(Pad_L3,        1),
	Bit_(Pad_R3,        2),
	Bit_(Pad_Start,     3),
	Bit_(Pad_Up,        4),
	Bit_(Pad_Right,     5),
	Bit_(Pad_Down,      6),
	Bit_(Pad_Left,      7),
	Bit_(Pad_L2,        8),
	Bit_(Pad_R2,        9),
	Bit_(Pad_L1,       10),
	Bit_(Pad_R1,       11),
	Bit_(Pad_Triangle, 12),
	Bit_(Pad_Circle,   13),
	Bit_(Pad_Cross,    14),
	Bit_(Pad_Square,   15),
};

enum {
	PadId_Offset = 4,

	Pad0 = 0 << PadId_Offset,
	Pad1 = 1 << PadId_Offset,
};

/* =============================================================================
 * BIOS pad-buffer subsystem: docs/psx-spx/docs/kernelbios.md (B(12h) + B(13h))
 * ============================================================================= */

enum {
	PAD_BIOS_RAW_SIZE = 0x22,
};
// BIOS pad buffer layout (docs/psx-spx/docs/kernelbios.md (InitPAD2 returns 0x22 = 34 bytes per port)).
// Bytes 0..7 are the named snapshot region; bytes 8..33 are reserved (the BIOS writes the buffer raw; we only read bytes 0..7 via O_(PadBiosRaw, ...)).
typedef Struct_(PadBiosRaw) {
	U1    status;  /* offset 0   (PadRawStatus_Ok / PadRawStatus_Timeout) */
	U1    id;      /* offset 1   (PadRawId_Digital / PadRawId_AnalogStick / 0x7x AnalogPad) */
	U2    buttons; /* offset 2-3 (active-low 16-bit button map) */
	V2_U1 right;   /* offset 4-5 (right stick x, y) */
	V2_U1 left;    /* offset 6-7 (left  stick x, y) */
	U1    reserved[PAD_BIOS_RAW_SIZE - 8]; /* offset 8..33 */
};

typedef Enum_(U4, PadStatus) {
	PadStatus_Disconnected,
	PadStatus_Digital,
	PadStatus_AnalogStick,
	PadStatus_AnalogPad,
	PadStatus_Unsupported,
	PadStatus_Pending,
	PadStatus_Invalid,
};

/* Distinct from the game-facing PadStatus enum: PadRawStatus_Ok and PadRawStatus_Timeout are raw BIOS values;
 * PadStatus_* are game-facing post-decode states. PadUnknownId_Sentinel is written by the decoder 
 * when the controller id does not match any known controller type.
 * PadAxisCentered_Word: Four-byte 0x80 pattern used to clear / center 
 * four byte axes at PadState.left_x through PadState.right_y. */
typedef Enum_(U1, PadRawStatus) {
	PadRawStatus_Ok      = 0x00,
	PadRawStatus_Timeout = 0xFF,
};
typedef Enum_(U1, PadRawId) {
	PadRawId_Digital           = 0x41,
	PadRawId_AnalogStick       = 0x53,
	PadRawId_AnalogPadMask     = 0xF0,
	PadRawId_AnalogPadValue    = 0x70,
};
typedef Enum_(U1, PadUnknownId) {
	PadUnknownId_Sentinel      = 0xFF,
};
typedef Enum_(U4, PadAxisCentered) {
	PadAxis_Centered_Hi   = 0x8080,
	PadAxis_Centered_Lo   = 0x8080,
	PadAxis_Centered_Word = 0x80808080U,
};
typedef Enum_(U1, PadDeadZone) {
	PadDeadZone_LowBound  = 0x70,  /* left_x <  LowBound  → active;  delta = 0x80 - left_x > 0 (rightward pull) */
	PadDeadZone_Center    = 0x80,  /* analog rest position; left_x == Center → delta = 0 (no rotation) */
	PadDeadZone_HighBound = 0x90,  /* left_x >  HighBound → active;  delta = 0x80 - left_x < 0 (leftward pull) */
};


typedef Struct_(PadAxes) {
	V2_U1  left;  /* offset 8-9 */
	V2_U1  right; /* offset 10-11 */
};
// Field order is chosen so that the 4 axes (left_x, left_y, right_x, right_y)
// form a contiguous 4-byte block at offset 8, allowing a single `store_word` to clear-or-write all 4 axes in one MIPS instruction.
typedef Struct_(PadState) {
	PadStatus status;   /* offset 0,    (U4) */
	PadBtns   buttons;  /* offset 4,    */
	U1        id;       /* offset 6,    */
	byte_pad(1);        /* offset 7,  explicit pad to align the axes block */
	union {
		A2_V2_U1 axes;    /* offset 8-11 store_target (4-byte aligned)*/
		struct {
			V2_U1  left;    /* offset 8-9 */
			V2_U1  right;   /* offset 10-11 */
		};
	};
};

internal void pad_bios_init_start(PadBiosRaw* raw0, PadBiosRaw* raw1);
