wip: input was working... messed it up (bios snapshot reads)

This commit is contained in:
ed
2026-08-04 00:50:12 -04:00
parent 8282f8e902
commit f17fa9165e
20 changed files with 1259 additions and 1219 deletions
+2 -2
View File
@@ -61,7 +61,7 @@ WORD_COUNT(mac_gte_load_tri_verts, 18)
, load_word( R_AT, R_T1, O_(PolyTag,code)) /* AT = old_ot_head */ \
, load_upper_i(R_V0, (S_(Poly_F3)/S_(U4) - S_(PolyTag)/S_(U4)) << PolyTag_len_bits) /* V0 = (5 - 1) << 24 = 4 << 24 */ \
, mask_upper( R_AT, R_AT, S_(PolyTag_len_bits)) /* Strip upper 8 bits (length from prev cell) → keep only low 24 */ \
, or( R_AT, R_AT, R_V0) /* Merge length */ \
, or_u( R_AT, R_AT, R_V0) /* Merge length */ \
, store_word( R_AT, R_PrimCursor, O_(PolyTag,code)) /* prim->tag = packed(prim_length, old_addr) */ \
, shift_lleft( R_AT, R_PrimCursor, S_(PolyTag_len_bits)) /* AT = (prim_length << 24) | old_addr */ \
, shift_lright(R_AT, R_AT, S_(PolyTag_len_bits)) \
@@ -76,7 +76,7 @@ WORD_COUNT(mac_insert_ot_tag_f3, 11)
, load_word( R_AT, R_T1, O_(PolyTag,code)) /* AT = old_ot_head */ \
, load_upper_i(R_V0, (S_(Poly_G4)/S_(U4) - S_(PolyTag)/S_(U4)) << PolyTag_len_bits) /* V0 = (9 - 1) << 24 = 8 << 24 */ \
, mask_upper( R_AT, R_AT, S_(PolyTag_len_bits)) /* Strip upper 8 bits (length from prev cell) → keep only low 24 */ \
, or( R_AT, R_AT, R_V0) /* Merge length */ \
, or_u( R_AT, R_AT, R_V0) /* Merge length */ \
, store_word( R_AT, R_PrimCursor, O_(PolyTag,code)) /* prim->tag = packed(prim_length, old_addr) */ \
, shift_lleft( R_AT, R_PrimCursor, S_(PolyTag_len_bits)) /* AT = (prim_length << 24) | old_addr */ \
, shift_lright(R_AT, R_AT, S_(PolyTag_len_bits)) \
View File
View File
+27 -86
View File
@@ -10,10 +10,10 @@
# include "gen/duffle.offsets.h"
#endif
typedef U4 const MipsCode;
typedef U4 const MipsCode; // Underlying type to mips asm words.
typedef Slice_(MipsCode);
typedef Slice_MipsCode MipsAtom;
typedef U4 const MipsAtom; // Underlying type to an array of mips asm words that must terminate with an ac_yield.
#define MipsAtom_(sym) MipsCode sym [] align_(4) =
// Used for components with no args (e.g., ac_load_tri_indices) or identifier-args (hardcoded register names).
@@ -23,9 +23,9 @@ typedef Slice_MipsCode MipsAtom;
#define MipsAtomComp_(sym) MipsCode sym [] align_(4) =
// Used for components with value-args (e.g., ac_format_f3_color).
// FI_ MipsAtom ac_X(args) MipsAtomComp_Proc_(ac_X, { body })
// FI_ Slice_MipsCode ac_X(args) MipsAtomComp_Proc_(ac_X, { body })
// expands to:
// FI_ MipsAtom ac_X(args) { MipsCode ac_X[] align_(4) = { body }; return slice_from_array(MipsCode, ac_X); }
// FI_ Slice_MipsCode ac_X(args) { MipsCode ac_X[] align_(4) = { body }; return slice_from_array(MipsCode, ac_X); }
#define MipsAtomComp_Proc_(sym, ...) { MipsCode sym [] align_(4) = __VA_ARGS__; return slice_from_array(MipsCode, sym); }
// Auto-generated component macros (<module>/gen/<dir>/<dir>.macs.h) are included manually by the unity build.
@@ -59,12 +59,12 @@ enum {
R_TScratch6 = R_T6,
R_TScratch7 = R_T7,
R_TScratch8 = R_T8,
R_TScratch10 = R_V0,
R_TScratch11 = R_V1,
// Note(Ed): We can technically clobber these, but don't unless we hit a bottleneck.
// R_TScratch10 = R_V0,
// R_TScratch10 = R_V1,
// R_TScratch11 = R_A0,
// R_TScratch12 = R_A1,
// R_TScratch13 = R_A3,
// R_TScratch12 = R_A0,
// R_TScratch13 = R_A1,
// R_TScratch14 = R_A3,
// TODO(Ed): Review S0-S7, they are technically avaialble, we just have to snapshot them at the ABI boundary.
// TODO(Ed): This is technically a waste of cycles for most work? so maybe only do this for expensive atoms on-demand or atom phases.
// TODO(Ed): Sort out the other available registers... (Not sure how much is left avail)
@@ -74,25 +74,27 @@ enum {
/* ---------------------------------------------------------------------------
* TAPE DRIVE ABI & REGISTER ALIASES (the enum moved earlier; see below)
* ---------------------------------------------------------------------------*/
typedef Slice_(MipsAtom); typedef Slice_MipsAtom Tape;
/* The 'Exit' Atom */
atom_dbg_skip MipsAtom_(tape_exit) { jump_reg(rret_addr), nop };
//TODO(Ed): Do we backup R_S0-7 here? Have it in a heavier tape run as a opt-in? Same with V0-1 and A0-3?
/* Generalized Tape Engine Runner */
FI_ void tape_run(Slice_MipsCode tape) { register U4* tape_ptr rgcc(R_TapePtr) = u4_r(tape.ptr); asm volatile(
FI_ void tape_run(Tape tape) { register U4* tape_ptr rgcc(R_TapePtr) = u4_r(tape.ptr); asm volatile(
asm_words(
load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
, add_ui_self(R_TapePtr, S_(MipsCode)) /* Advance tape */
, add_ui_self(R_TapePtr, S_(MipsAtom)) /* Advance tape */
, call_reg( R_AtomJmp) /* jalr $t9 */
, nop /* Branch delay slot */
)
asm_rpins, r_use(tape_ptr)
asm_clobber:
rlit(R_AT)
, rlit(R_T0), rlit(R_T1), rlit(R_T2), rlit(R_T3), rlit(R_T4)
, rlit(R_T5), rlit(R_T6), rlit(R_T7), rlit(R_T8)
, clb_mem_drain
rlit(R_AT),
rlit(R_V0), rlit(R_V1),
rlit(R_T0), rlit(R_T1), rlit(R_T2), rlit(R_T3), rlit(R_T4),
rlit(R_T5), rlit(R_T6), rlit(R_T7), rlit(R_T8),
clb_mem_drain
); }
typedef Relative_(FArena) Struct_(TapeBuilder) { U4 ptr; U4 capacity; U4 used; };
@@ -100,12 +102,13 @@ FI_ void tb_init(TapeBuilder* tb, FArena* arena) { tb->ptr = arena->start
FI_ TapeBuilder tb_make_old( FArena* arena) { return (TapeBuilder){ arena->start, 0 }; }
FI_ TapeBuilder tb_make(Slice mem) { return (TapeBuilder){ mem.ptr, mem.len, 0 }; }
#define tb_emit_(tb, atom) tb_emit(tb, atom)
FI_ void tb_emit(TapeBuilder* tb, MipsCode* atom) { u4_r(tb->ptr)[tb->used] = u4_(atom); ++ tb->used; }
FI_ void tb_data(TapeBuilder* tb, U4 data) { u4_r(tb->ptr)[tb->used] = u4_(data); ++ tb->used; }
#define tb_emit_(atom) tb_emit(& tb, atom)
#define tb_data_(field, data) tb_data(& tb, u4_(data))
FI_ Slice_MipsCode tb_end (TapeBuilder* tb) { tb_emit(tb,tape_exit); return (Slice_MipsCode){ C_(U4*,tb->ptr), tb->used }; }
FI_ Slice_MipsCode tb_slice(TapeBuilder tb) { return (Slice_MipsCode){ C_(U4*,tb.ptr), tb.used }; }
FI_ Tape tb_end (TapeBuilder* tb) { tb_emit(tb,tape_exit); return (Tape){ C_(U4*,tb->ptr), tb->used }; }
FI_ Tape tb_slice(TapeBuilder tb) { return (Tape){ C_(U4*,tb.ptr), tb.used }; }
#define tb_scope(tb) for(U4 tbs_once=0;tbs_once==0;++tbs_once,tb_emit(tb,tape_exit))
FI_ void tb_scope_run_end(TapeBuilder* tb) { tb_emit(tb,tape_exit); tape_run(tb_slice(tb[0])); }
@@ -159,7 +162,7 @@ MipsAtomComp_(ac_insert_ot_tag_f3) {
load_word( R_AT, R_T1, O_(PolyTag,code)), // AT = old_ot_head
load_upper_i(R_V0, (S_(Poly_F3)/S_(U4) - S_(PolyTag)/S_(U4)) << PolyTag_len_bits), // V0 = (5 - 1) << 24 = 4 << 24
mask_upper( R_AT, R_AT, S_(PolyTag_len_bits)), // Strip upper 8 bits (length from prev cell) → keep only low 24
or( R_AT, R_AT, R_V0), // Merge length
or_u( R_AT, R_AT, R_V0), // Merge length
store_word( R_AT, R_PrimCursor, O_(PolyTag,code)), // prim->tag = packed(prim_length, old_addr)
shift_lleft( R_AT, R_PrimCursor, S_(PolyTag_len_bits)), // AT = (prim_length << 24) | old_addr
shift_lright(R_AT, R_AT, S_(PolyTag_len_bits)),
@@ -174,7 +177,7 @@ MipsAtomComp_(ac_insert_ot_tag_g4) {
load_word( R_AT, R_T1, O_(PolyTag,code)), // AT = old_ot_head
load_upper_i(R_V0, (S_(Poly_G4)/S_(U4) - S_(PolyTag)/S_(U4)) << PolyTag_len_bits), // V0 = (9 - 1) << 24 = 8 << 24
mask_upper( R_AT, R_AT, S_(PolyTag_len_bits)), // Strip upper 8 bits (length from prev cell) → keep only low 24
or( R_AT, R_AT, R_V0), // Merge length
or_u( R_AT, R_AT, R_V0), // Merge length
store_word( R_AT, R_PrimCursor, O_(PolyTag,code)), // prim->tag = packed(prim_length, old_addr)
shift_lleft( R_AT, R_PrimCursor, S_(PolyTag_len_bits)), // AT = (prim_length << 24) | old_addr
shift_lright(R_AT, R_AT, S_(PolyTag_len_bits)),
@@ -183,7 +186,7 @@ MipsAtomComp_(ac_insert_ot_tag_g4) {
/* Words: 3; Emits one (cmd|color) word to R_PrimCursor at the given
* byte offset. Internal helper used by the *_format_*_color macros. */
FI_ MipsAtom ac_pack_color_word(U4 off, U4 cmd, U1 r, U1 g, U1 b)
FI_ Slice_MipsCode ac_pack_color_word(U4 off, U4 cmd, U1 r, U1 g, U1 b)
atom_dbg_skip MipsAtomComp_Proc_(ac_pack_color_word, {
load_upper_i(R_AT, (cmd) << 8 | (b)),
or_i_self( R_AT, ((g) << 8) | (r)),
@@ -192,7 +195,7 @@ atom_dbg_skip MipsAtomComp_Proc_(ac_pack_color_word, {
/* Words: 3; Emits the F3 command+color word (cmd byte | BLUE | GREEN | RED)
* Args: _r, _g, _b are 8-bit RGB byte values (not raw 16-bit fields). */
FI_ MipsAtom ac_format_f3_color(U1 r, U1 g, U1 b)
FI_ Slice_MipsCode ac_format_f3_color(U1 r, U1 g, U1 b)
atom_dbg_skip MipsAtomComp_Proc_(ac_format_f3_color, { mac_pack_color_word(O_(Poly_F3,color), gp0_cmd_poly_f3, r, g, b) })
/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3.
@@ -205,7 +208,7 @@ atom_dbg_skip MipsAtomComp_(ac_gte_store_f3) {
/* Words: 12; Emits the four (code|color) words of a Poly_G4.
* Args: rN,gN,bN are 8-bit RGB byte values for each of the 4 vertices. */
FI_ MipsAtom ac_format_g4_color(
FI_ Slice_MipsCode ac_format_g4_color(
U1 r0, U1 g0, U1 b0,
U1 r1, U1 g1, U1 b1,
U1 r2, U1 g2, U1 b2,
@@ -259,7 +262,7 @@ FI_ void atombuilder_end(MipsAtomBuilder_R ab) {
mem_bump(ab->start, ab->capacity, & ab->used, S_(ac_yield));
}
#define mipsatom_from_builder(ab) (MipsAtom){ab.start, ab.used}
#define mipsatom_from_builder(ab) (Slice_MipsCode){ab.start, ab.used}
#pragma endregion Mips Atom Builder
@@ -313,66 +316,4 @@ internal MipsAtom_(set_gte_world) atom_info(
mac_yield()
};
/* DIAGNOSTIC 1: Pure tape loop test */
internal MipsAtom_(diag_yield) { mac_yield() };
/* DIAGNOSTIC 2: Pure memory test (No GTE). Draws a fixed cyan triangle. */
internal MipsAtom_(diag_color) {
store_word( R_0, R_T7, 0),
load_upper_i(R_AT, gp0_cmd_poly_f3 << 8 | 0xFF), /* High: MipsCode Poly_F3(0x20) + Color B:FF */
or_i_self( R_AT, 0xFF00), /* Low: Color G:FF, R:00 (Cyan) */
store_word( R_AT, R_T7, 4),
/* Fake coordinates - Swapped winding order to prevent GPU culling! */
load_upper_i(R_AT, 0x0010), or_i_self(R_AT, 0x0010), store_word(R_AT, R_T7, 8), /* (16, 16) */
load_upper_i(R_AT, 0x0050), or_i_self(R_AT, 0x0010), store_word(R_AT, R_T7, 12), /* (80, 16) */
load_upper_i(R_AT, 0x0010), or_i_self(R_AT, 0x0050), store_word(R_AT, R_T7, 16), /* (16, 80) */
add_ui( R_T1, R_0, 10),
shift_lleft_self(R_T1, S_(U4)/2),
add_u_self( R_T1, R_T6),
load_word( R_AT, R_T1, 0),
load_upper_i(R_V0, (S_(Poly_F3)/S_(U4) - S_(PolyTag)/S_(U4)) << PolyTag_len_bits),
store_word( R_AT, R_T7, 0),
shift_lleft(R_AT, R_T7, S_(PolyTag_len_bits)), shift_lright(R_AT, R_AT, S_(PolyTag_len_bits)),
or_u_self( R_AT, R_V0),
store_word( R_AT, R_T1, 0),
add_ui(R_T7, R_T7, 20),
mac_yield()
};
/* DIAGNOSTIC 3: Pure GTE test (No Memory Writes) */
internal MipsAtom_(diag_gte) {
/* Load 3 indices */
load_half_u(R_T0, R_T4, 0),
load_half_u(R_T1, R_T4, 2),
load_half_u(R_T2, R_T4, 4),
/* Load Vertices into GTE */
shift_lleft( R_AT, R_T0, 3), add_u( R_AT, R_AT, R_T5),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0),
shift_lleft( R_AT, R_T1, 3), add_u(R_AT, R_AT, R_T5),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mv_to_data_r(R_V0, C2_VXY1), gte_mv_to_data_r(R_V1, C2_VZ1),
shift_lleft(R_AT, R_T2, 3), add_u(R_AT, R_AT, R_T5),
load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4),
gte_mv_to_data_r(R_V0, C2_VXY2), gte_mv_to_data_r(R_V1, C2_VZ2),
/* Run Math */
nop2, gte_cmdw_rtpt,
nop2, gte_cmdw_nclip,
nop2,
/* Advance Face Cursor and Yield */
add_ui(R_T4, R_T4, 8),
mac_yield()
};
#pragma endregion Baked Mips Atoms
+2
View File
@@ -11,6 +11,7 @@ enum {
v3s2_byteoff = 3, // log2(8), used with shift_left_logical op for index via byte offset.
};
typedef Array_(U1, 2);
typedef Array_(U4, 2);
typedef Array_(S2, 2);
typedef Array_(S2, 3);
@@ -22,6 +23,7 @@ typedef S2 A3x3_S2[3][3];
typedef Struct_(Extent2_S2) { S2 width; S2 height; };
typedef Struct_(Extent2_S4) { S4 width; S4 height; };
typedef Struct_(V2_U1) { U1 x; U1 y; };
typedef Struct_(V2_S2) { S2 x; S2 y; };
typedef Struct_(V2_S4) { S4 x; S4 y; };
typedef Struct_(V3_S2) { S2 x; S2 y; S2 z; S2 pad; };
+2 -2
View File
@@ -67,8 +67,8 @@ typedef Slice_(B1);
#define slice_end(slice) ((slice).ptr + (slice).len)
#define S_slice(s) ((s).len * S_((s).ptr[0]))
#define slice_ut(ptr,len) slice_ut_(u4_(ptr), u4_(len))
#define slice_ut_arr(a) slice_ut_(u4_(a), S_(a))
#define slice_ut(ptr,len) slice_ut_(u4_(ptr), u4_(len))
#define slice_ut_arr(a) slice_ut_(u4_(a), S_(a))
#define slice_to_ut(s) slice_ut_(u4_((s).ptr), S_slice(s))
#define slice_iter(container, iter) (T_((container).ptr) iter = (container).ptr; iter != slice_end(container); ++ iter)
+4 -4
View File
@@ -336,10 +336,10 @@ enum { _BitOffsets = 0
/* Logic Opcodes */
#define and(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_and)
#define or(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_or)
#define xor(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_xor)
#define nor(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_nor)
#define and_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_and)
#define or_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_or)
#define xor_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_xor)
#define nor_u(rd, rs, rt) enc_r(op_special, (rs), (rt), (rd), 0, fc_nor)
#define or_u_self(rd_rs, rt) enc_r(op_special, (rd_rs), (rt), (rd_rs), 0, fc_or)
+45 -115
View File
@@ -3,24 +3,26 @@
# include "dsl.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; the active-low-to-active-high inversion is applied bit-by-bit. */
enum {
Bit_(Pad_L2, 0),
Bit_(Pad_R2, 1),
Bit_(Pad_L1, 2),
Bit_(Pad_R1, 3),
Bit_(Pad_Triangle, 4),
Bit_(Pad_Circle, 5),
Bit_(Pad_Cross, 6),
Bit_(Pad_Square, 7),
Bit_(Pad_Select, 8),
Bit_(Unused_PadI, 9),
Bit_(Unused_PadJ, 10),
Bit_(Pad_Start, 11),
Bit_(Pad_Up, 12),
Bit_(Pad_Right, 13),
Bit_(Pad_Down, 14),
Bit_(Pad_Left, 15),
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 {
@@ -33,111 +35,39 @@ enum {
#define pad0_(btn_id) (btn_id << Pad0)
#define pad1_(btn_id) (btn_id << Pad1)
/* ============================================================
* SIO0 raw controller polling surface (Phase 1 scaffolding)
* Source of truth: docs/psx-spx/docs/serialinterfacessio.md
* docs/psx-spx/docs/controllersandmemorycards.md
* https://github.com/Lameguy64/PSn00bSDK (spi.c)
* BIOS pad-buffer subsystem: docs/psx-spx/docs/kernelbios.md (B(12h) + B(13h))
* ============================================================ */
enum {
/* SIO0 register offsets relative to IOBASE 0xBF800000 */
pad_SIO_DATA_OFFSET = 0x1040, /* 8-bit data (TX write / RX read) */
pad_SIO_STAT_OFFSET = 0x1044, /* 16-bit status */
pad_SIO_MODE_OFFSET = 0x1048, /* 16-bit mode */
pad_SIO_CTRL_OFFSET = 0x104A, /* 16-bit control */
pad_SIO_BAUD_OFFSET = 0x104E, /* 16-bit baud */
/* SIO_CTRL bit flags */
pad_SIO_CTRL_RESET = 0x0040, /* reset most SIO registers */
pad_SIO_CTRL_TX_ENABLE = 0x0001, /* TX enable */
pad_SIO_CTRL_DTR_CS = 0x0002, /* DTR drives /CS on controller */
pad_SIO_CTRL_ACK = 0x0010, /* acknowledge / clear status */
pad_SIO_CTRL_DSR_IRQ = 0x1000, /* enable /ACK IRQ (unused; polling) */
/* SIO_STAT bit flags */
pad_SIO_STAT_TX_READY = 0x0001,
pad_SIO_STAT_RX_NOT_EMPTY = 0x0002,
pad_SIO_STAT_TX_IDLE = 0x0004,
pad_SIO_STAT_DSR_ACK = 0x0080,
/* SIO init values (per docs/psx-spx/docs/serialinterfacessio.md) */
pad_SIO_MODE_INIT = 0x000D, /* MUL1, 8-bit, no parity, idle-high */
pad_SIO_BAUD_INIT = 0x0088, /* ~250 kHz standard rate */
pad_SIO_CTRL_CLEANUP = 0x0010, /* raise /CS + clear stale status */
/* Controller protocol bytes (per docs/psx-spx/docs/controllersandmemorycards.md) */
pad_PROTO_ADDR = 0x01,
pad_PROTO_CMD_READ = 0x42,
pad_PROTO_CMD_ENTERCFG = 0x43,
pad_PROTO_CMD_SETLED = 0x44,
pad_PROTO_PREFIX = 0x5A,
pad_PROTO_PREFIX_QUIRK = 0x00, /* DualShock: Analog-button swap after cfg */
/* Controller response ID nibble (low 4 bits of ID byte) */
pad_PROTO_ID_DIGITAL = 0x41,
pad_PROTO_ID_ANALOG_STK = 0x53,
pad_PROTO_ID_ANALOG = 0x73,
pad_PROTO_ID_CONFIG = 0xF3,
/* Per-state constants */
pad_SIO_SETTLE_BEFORE_TX = 1000, /* iterations after CTRL=0x0010 */
pad_SIO_SETTLE_AFTER_TX = 2000, /* iterations after CTRL=port_select */
pad_SIO_WAIT_BUDGET = 4096, /* max iterations per /ACK or RX wait */
pad_SIO_CFG_MAX_ATTEMPTS = 3, /* DualShock config retries before reject */
PAD_BIOS_RAW_SIZE = 0x22,
};
typedef Struct_(PadBiosRaw) {
U1 bytes[PAD_BIOS_RAW_SIZE];
};
/* Pad status enum (per-port outcome) */
typedef Enum_(U4, PadSioStatus) {
PadSioStatus_Disconnected,
PadSioStatus_Digital,
PadSioStatus_AnalogStick,
PadSioStatus_Analog,
PadSioStatus_ConfigRejected,
PadSioStatus_Invalid,
PadSioStatus_TxTimeout,
PadSioStatus_RxTimeout,
PadSioStatus_AckTimeout,
typedef Enum_(U4, PadStatus) {
PadStatus_Disconnected,
PadStatus_Digital,
PadStatus_AnalogStick,
PadStatus_AnalogPad,
PadStatus_Unsupported,
PadStatus_Pending,
PadStatus_Invalid,
};
/* PadState — per-port runtime state */
/* PadState — per-port normalized runtime state.
* 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.
* The struct size stays 12 bytes (unchanged from the prior order,
* which left the C compiler to insert 1 byte of trailing pad to reach the 4-byte struct alignment). */
typedef Struct_(PadState) {
PadSioStatus status;
U4 buttons;
U1 left_x;
U1 left_y;
U1 right_x;
U1 right_y;
U4 attempt;
PadStatus status; /* offset 0, size 4 (U4) */
U2 buttons; /* offset 4, size 2 */
U1 id; /* offset 6, size 1 */
U1 pad; /* offset 7, size 1 — explicit pad to align the axes block */
U1 left_x; /* offset 8, size 1 — store_word target (4-byte aligned) */
U1 left_y; /* offset 9, size 1 */
U1 right_x; /* offset 10, size 1 */
U1 right_y; /* offset 11, size 1 */
};
/* PadSioInit — boot-time C-side pointer table passed into the tape */
typedef Struct_(PadSioInit) {
U4 sio_base_addr[2];
PadState* pad_state_ptr[2];
};
/* Register aliases for the new atoms (post-2026-07-10 ABI) */
#ifndef atom_reg
#define atom_reg /* atom_reg: opt the preceding enum entry into the DWARF registry */
#endif
enum {
R_PadSioBase = R_T6 atom_reg, /* caller-pinned IO_BASE_ADDR */
R_PadState = R_T7 atom_reg, /* caller-pinned PadState* */
R_PadStatus = R_T4 atom_reg, /* scratch for status reads */
R_PadCountdown = R_T5 atom_reg, /* scratch for countdown budget */
R_DiagPinScratch = R_T3 atom_reg, /* raw_sio_pad_poll_20260802 — diag scratch address */
#define R_PadSioBase_Code R_T6_Code
#define R_PadState_Code R_T7_Code
#define R_PadStatus_Code R_T4_Code
#define R_PadCountdown_Code R_T5_Code
#define R_DiagPinScratch_Code R_T3_Code
};
/* Address of SIO0 block in KSEG1 (the PS1-side uncached mirror) */
enum {
pad_IO_KSEG1_BASE = 0xBF800000,
};
View File
+1
View File
@@ -40,6 +40,7 @@ WORD_COUNT(or_i, 1)
WORD_COUNT(or_i_self, 1)
WORD_COUNT(or_u, 1)
WORD_COUNT(or_u_self, 1)
WORD_COUNT(nor_u, 1)
WORD_COUNT(shift_lleft, 1)
WORD_COUNT(shift_lleft_self, 1)
WORD_COUNT(shift_lright, 1)