+// C0 and B0 overlap (end of C0 is start of B0)
+void (*biosC0[256+128])();
+void (**biosB0)() = biosC0 + 128;
+
+static 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[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 },
+ { 0x49bc, hleop_exc_padcard1 },
+ { 0x4a4c, hleop_exc_padcard2 },
+};
+
+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 the hle traps
+ if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
+ if (handler2) 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);
+}
+
+static const u32 gpu_ctl_def[] = {
+ 0x00000000, 0x01000000, 0x03000000, 0x04000000,
+ 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
+};
+
+static const u32 gpu_data_def[] = {
+ 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
+ 0xe5001000, 0xe6000000,
+ 0x02000000, 0x00000000, 0x01ff03ff
+};
+
+// from 1f801d80
+static const u16 spu_config[] = {
+ 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
+ 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
+ 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
+ 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
+ 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
+};
+
+void psxBiosSetupBootState(void)
+{
+ boolean hle = Config.HLE;
+ u32 *hw = (u32 *)psxH;
+ int i;
+
+ // see also SetBootRegs()
+ if (hle) {
+ v0 = 1; v1 = 4;
+ a0 = 1; a2 = a3 = 0; a3 = 0x2a;
+ t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
+ s0 = 0xa000b870;
+ k0 = 0xbfc0d968; k1 = 0xf1c;
+ ra = 0xf0001234; // just to easily detect attempts to return
+ psxRegs.CP0.n.Cause = 0x20;
+ psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
+
+ hw[0x1000/4] = SWAP32(0x1f000000);
+ hw[0x1004/4] = SWAP32(0x1f802000);
+ hw[0x1008/4] = SWAP32(0x0013243f);
+ hw[0x100c/4] = SWAP32(0x00003022);
+ hw[0x1010/4] = SWAP32(0x0013243f);
+ hw[0x1014/4] = SWAP32(0x200931e1);
+ hw[0x1018/4] = SWAP32(0x00020943);
+ hw[0x101c/4] = SWAP32(0x00070777);
+ hw[0x1020/4] = SWAP32(0x0000132c);
+ hw[0x1060/4] = SWAP32(0x00000b88);
+ hw[0x1070/4] = SWAP32(0x00000001);
+ hw[0x1074/4] = SWAP32(0x0000000c);
+ hw[0x2040/4] = SWAP32(0x00000900);
+ }
+
+ hw[0x10a0/4] = SWAP32(0x00ffffff);
+ hw[0x10a8/4] = SWAP32(0x00000401);
+ hw[0x10b0/4] = SWAP32(0x0008b000);
+ hw[0x10b4/4] = SWAP32(0x00010200);
+ hw[0x10e0/4] = SWAP32(0x000eccf4);
+ hw[0x10e4/4] = SWAP32(0x00000400);
+ hw[0x10e8/4] = SWAP32(0x00000002);
+ hw[0x10f0/4] = SWAP32(0x00009099);
+ hw[0x10f4/4] = SWAP32(0x8c8c0000);
+
+ if (hle) {
+ psxRcntWmode(0, 0);
+ psxRcntWmode(1, 0);
+ psxRcntWmode(2, 0);
+ }
+
+ // gpu
+ for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
+ GPU_writeStatus(gpu_ctl_def[i]);
+ for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
+ GPU_writeData(gpu_data_def[i]);
+ HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
+
+ // spu
+ for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
+ SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
+}