This commit is contained in:
ed
2026-08-02 21:58:57 -04:00
parent 858e57f293
commit 9eb696ece8
4 changed files with 175 additions and 15 deletions
+4 -10
View File
@@ -81,18 +81,12 @@ 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(
// Removed, not needed
/*add_ui( R_SP, R_SP, -MipsStackAlignment)*/ /* Allocate stack space */
/*, store_word( R_RA, R_SP, 0)*/ /* Safely backup $ra to the stack */
asm_words(
load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
, add_ui_self(R_TapePtr, S_(MipsCode)) /* Advance tape */
, call_reg( R_AtomJmp) /* jalr $t9 */
, nop /* Branch delay slot */
load_word( R_AtomJmp, R_TapePtr, 0) /* Bootstrap the first jump */
, add_ui_self(R_TapePtr, S_(MipsCode)) /* Advance tape */
, call_reg( R_AtomJmp) /* jalr $t9 */
, nop /* Branch delay slot */
)
// Removed, not needed
/*, load_word( R_RA, R_SP, 0)* /* Restore $ra from stack */
/*, add_ui_self(R_SP, MipsStackAlignment)*/ /* Deallocate stack space */
asm_rpins, r_use(tape_ptr)
asm_clobber:
rlit(R_AT)
+105
View File
@@ -36,3 +36,108 @@ enum {
void pad_init(U4 mode) asm("PadInit");
U4 pad_read(U4 id) asm("PadRead");
/* ============================================================
* 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)
* ============================================================ */
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 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,
};
/* PadState — per-port runtime state */
typedef Struct_(PadState) {
PadSioStatus status;
U4 buttons;
U1 left_x;
U1 left_y;
U1 right_x;
U1 right_y;
U4 attempt;
};
/* 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 */
#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
};
/* Address of SIO0 block in KSEG1 (the PS1-side uncached mirror) */
enum {
pad_IO_KSEG1_BASE = 0xBF800000,
};
+26
View File
@@ -21,3 +21,29 @@ enum {
};
#define v3s4_fp_one() v3s4(fp_one, fp_one, fp_one)
#ifdef INTELLISENSE_DIRECTIVES
# include "duffle/pad.h"
#endif
/* ============================================================
* Raw SIO0 pad subsystem (raw_sio_pad_poll_20260802)
* ============================================================ */
typedef Struct_(Binds_PadSioStep) {
PadState* state0;
PadState* state1;
U4 sio_base_addr0;
U4 sio_base_addr1;
};
typedef Struct_(Binds_PadApplyInput) {
PadState* state;
V3_S2* cube_rot;
V3_S2* floor_rot;
};
/* Populates smem.pad_sio_init with the two PadState pointers and the
* KSEG1 SIO0 base. The caller (main()) runs this once at boot before
* the first tb_emit(pad_sio_init). */
void pad_sio_init_setup(PadSioInit* init, PadState* s0, PadState* s1);
+40 -5
View File
@@ -199,7 +199,7 @@ internal MipsAtom_(gp_screen_init) atom_info(atom_phase(screen_init), atom_reads
};
enum {
R_PadState = R_T4 atom_reg atom_type(U4),
R_PadInState = R_T4 atom_reg atom_type(U4),
R_PadSignal = R_T0 atom_reg atom_type(U4),
R_CubeRot = R_T1 atom_reg atom_type(V3_S2*),
R_FloorRot = R_T2 atom_reg atom_type(V3_S2*),
@@ -210,15 +210,15 @@ typedef Struct_(Binds_PadInputDemo) {
V3_S2* floor_rot;
};
internal MipsAtom_(pad_input_demo) atom_info(atom_bind(Binds_PadInputDemo)
, atom_reads(R_PadState, R_CubeRot, R_FloorRot)
, atom_reads(R_PadInState, R_CubeRot, R_FloorRot)
, atom_writes(R_CubeRot, R_FloorRot)
) {
load_word(R_PadState, R_TapePtr, O_(Binds_PadInputDemo,pad_state)),
load_word(R_PadInState, R_TapePtr, O_(Binds_PadInputDemo,pad_state)),
load_word(R_CubeRot, R_TapePtr, O_(Binds_PadInputDemo,cube_rot)),
load_word(R_FloorRot, R_TapePtr, O_(Binds_PadInputDemo,floor_rot)),
add_ui_self( R_TapePtr, S_(Binds_PadInputDemo)),
and_i(R_PadSignal, R_PadState, pad0_(Pad_Left)), branch_le_zero(R_PadSignal, atom_offset(pad_left, exit_pad_left)),
and_i(R_PadSignal, R_PadInState, pad0_(Pad_Left)), branch_le_zero(R_PadSignal, atom_offset(pad_left, exit_pad_left)),
load_half( R_T5, R_CubeRot, O_(V3_S2,y)), // BD-Slot occupied
load_half( R_T6, R_FloorRot, O_(V3_S2,y)),
add_si( R_T5, R_T5, 30),
@@ -227,7 +227,7 @@ internal MipsAtom_(pad_input_demo) atom_info(atom_bind(Binds_PadInputDemo)
store_half(R_T6, R_FloorRot, O_(V3_S2,y)),
atom_label(exit_pad_left)
and_i(R_PadSignal, R_PadState, pad0_(Pad_Right)), branch_le_zero(R_PadSignal, atom_offset(pad_right, exit_pad_right)),
and_i(R_PadSignal, R_PadInState, pad0_(Pad_Right)), branch_le_zero(R_PadSignal, atom_offset(pad_right, exit_pad_right)),
load_half( R_T5, R_CubeRot, O_(V3_S2,y)), // BD-Slot occupied
load_half( R_T6, R_FloorRot, O_(V3_S2,y)),
add_si( R_T5, R_T5, -30),
@@ -376,4 +376,39 @@ internal MipsAtom_(sync_primitive_arena) atom_info(atom_bind(Binds_SyncPrimitive
mac_yield()
};
/* ----- pad_sio_init -----
* Boot-time SIO0 init. Caller pins R_T6 = sio_base_addr0.
* Issues SIO CTRL=0x0040 (reset), MODE=0x000D, BAUD=0x0088.
* (Phase 2 fills the body.)
*/
internal MipsAtom_(pad_sio_init) atom_info(atom_phase(pad_init)
, atom_reads(R_T5, R_PadSioBase)
, atom_writes(R_T5)
) {
mac_yield(),
};
/* ----- pad_sio_step -----
* Per-frame bounded raw-SIO transaction. Reads PadState pointers + SIO
* base addresses from Binds_PadSioStep; writes per-port status +
* buttons + axes into smem.pad[0..1]. (Phase 3 fills the body.)
*/
internal MipsAtom_(pad_sio_step) atom_info(atom_bind(Binds_PadSioStep)
, atom_reads(R_TapePtr, R_PadSioBase, R_PadState, R_PadStatus, R_PadCountdown)
, atom_writes(R_PadStatus, R_PadCountdown)
) {
mac_yield(),
};
/* ----- pad_apply_input -----
* Reads pad[0].buttons + pad[0].left_x; applies the input-semantics
* deltas to cube_rot.y + floor_rot.y. (Phase 4 fills the body.)
*/
internal MipsAtom_(pad_apply_input) atom_info(atom_bind(Binds_PadApplyInput)
, atom_reads(R_T0, R_T1, R_T2, R_T5)
, atom_writes(R_T1, R_T2)
) {
mac_yield(),
};
#pragma endregion Baked Atoms