+void setup_mips_code()
+{
+ u32 *ptr;
+ ptr = (u32 *)&psxM[A_SYSCALL];
+ ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
+ ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
+ ptr[0x08/4] = SWAPu32(0x00000000); // nop
+
+ ptr = (u32 *)&psxM[A_EXCEPTION];
+ memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
+ ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
+ ptr[0x14/4] = SWAPu32(0x00000000); // nop
+ ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
+ ptr[0x1c/4] = SWAPu32(0x00000000); // nop
+ ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
+ ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
+ ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
+ ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
+ ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
+
+ ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
+ ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
+ ptr[0x68/4] = SWAPu32(0x24630004); // addiu $v1, $v1, 4
+ ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
+
+ ptr[0xb0/4] = HLEOP(hleop_exception);
+}
+
+static const struct {
+ u32 addr;
+ enum hle_op op;
+} chainfns[] = {
+ { 0xbfc050a4, hleop_exc0_0_1 },
+ { 0xbfc04fbc, hleop_exc0_0_2 },
+ { 0xbfc0506c, hleop_exc0_1_1 },
+ { 0xbfc04dec, hleop_exc0_1_2 },
+ { 0x1a00, hleop_exc0_2_2 },
+ { 0x19c8, hleop_exc1_0_1 },
+ { 0x18bc, hleop_exc1_0_2 },
+ { 0x1990, hleop_exc1_1_1 },
+ { 0x1858, hleop_exc1_1_2 },
+ { 0x1958, hleop_exc1_2_1 },
+ { 0x17f4, hleop_exc1_2_2 },
+ { 0x1920, hleop_exc1_3_1 },
+ { 0x1794, hleop_exc1_3_2 },
+ { 0x2458, hleop_exc3_0_2 },
+};
+
+static int chain_hle_op(u32 handler)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
+ if (chainfns[i].addr == handler)
+ return chainfns[i].op;
+ return hleop_dummy;
+}
+
+static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
+{
+ d[0] = SWAPu32(next);
+ d[1] = SWAPu32(handler1);
+ d[2] = SWAPu32(handler2);
+
+ // install hle traps
+ PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
+ PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
+}
+
+static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
+{
+ u32 *ram32 = (u32 *)psxM;
+ u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
+ u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
+ u32 p_excb, p_evcb, p_pcb, p_tcb;
+
+ memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
+ psxBios_SysInitMemory_(0xa000e000, 0x2000);
+ p_excb = psxBios_SysMalloc_(s_excb);
+ p_evcb = psxBios_SysMalloc_(s_evcb);
+ p_pcb = psxBios_SysMalloc_(s_pcb);
+ p_tcb = psxBios_SysMalloc_(s_tcb);
+
+ // "table of tables". Some games modify it
+ assert(A_TT_ExCB == 0x0100);
+ ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
+ ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
+ ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
+ ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
+ ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
+ ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
+ ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
+ ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
+ ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
+ ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
+ ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
+ ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
+
+ storeRam32(p_excb + 0*4, 0x91e0); // chain0
+ storeRam32(p_excb + 2*4, 0x6d88); // chain1
+ storeRam32(p_excb + 4*4, 0x0000); // chain2
+ storeRam32(p_excb + 6*4, 0x6d98); // chain3
+
+ storeRam32(p_pcb, p_tcb);
+ storeRam32(p_tcb, 0x4000); // first TCB
+
+ // default events
+ storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
+ storeRam32(A_CD_EVENTS + 0x04, OpenEvent(0xf0000003, 0x0020, EvMdMARK, 0));
+ storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
+ storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
+ storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
+ DeliverEvent(0xf0000003, 0x0010);
+}
+