dma: should clear both start bits
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
index 85f79fd..c7cbf09 100644 (file)
@@ -181,7 +181,7 @@ char *biosC0n[256] = {
 #define k1 (psxRegs.GPR.n.k1)
 #define gp (psxRegs.GPR.n.gp)
 #define sp (psxRegs.GPR.n.sp)
-#define fp (psxRegs.GPR.n.s8)
+#define fp (psxRegs.GPR.n.fp)
 #define ra (psxRegs.GPR.n.ra)
 #define pc0 (psxRegs.pc)
 
@@ -193,28 +193,21 @@ char *biosC0n[256] = {
 #define Rsp ((char *)PSXM(sp))
 
 typedef struct {
-       u32 desc;
-       s32 status;
-       s32 mode;
+       u32 class;
+       u32 status;
+       u32 spec;
+       u32 mode;
        u32 fhandler;
-} EvCB[32];
-
-#define EvStUNUSED     0x0000
-#define EvStWAIT       0x1000
-#define EvStACTIVE     0x2000
-#define EvStALREADY 0x4000
+       u32 unused[2];
+} EvCB;
 
-#define EvMdINTR       0x1000
-#define EvMdNOINTR     0x2000
+#define EvStUNUSED      0x0000
+#define EvStDISABLED    0x1000
+#define EvStACTIVE      0x2000
+#define EvStALREADY     0x4000
 
-/*
-typedef struct {
-       s32 next;
-       s32 func1;
-       s32 func2;
-       s32 pad;
-} SysRPst;
-*/
+#define EvMdCALL        0x1000
+#define EvMdMARK        0x2000
 
 typedef struct {
        u32 status;
@@ -258,23 +251,9 @@ typedef struct {
 } FileDesc;
 
 static int *pad_buf = NULL;
-static char *pad_buf1 = NULL, *pad_buf2 = NULL;
-static int pad_buf1len, pad_buf2len;
-static int pad_stopped = 0;
-
-static u32 regs[35];
-static EvCB *EventCB;
-static EvCB *HwEV; // 0xf0
-static EvCB *EvEV; // 0xf1
-static EvCB *RcEV; // 0xf2
-static EvCB *UeEV; // 0xf3
-static EvCB *SwEV; // 0xf4
-static EvCB *ThEV; // 0xff
 static u32 heap_size = 0;
 static u32 *heap_addr = NULL;
 static u32 *heap_end = NULL;
-static int CardState = -1;
-static int CurThread = 0;
 static FileDesc FDesc[32];
 static u32 card_active_chan = 0;
 
@@ -282,6 +261,7 @@ static u32 card_active_chan = 0;
 #define A_TT_ExCB       0x0100
 #define A_TT_PCB        0x0108
 #define A_TT_TCB        0x0110
+#define A_TT_EvCB       0x0120
 #define A_A0_TABLE      0x0200
 #define A_B0_TABLE      0x0874
 #define A_C0_TABLE      0x0674
@@ -292,9 +272,18 @@ static u32 card_active_chan = 0;
 #define A_KMALLOC_PTR   0x7460
 #define A_KMALLOC_SIZE  0x7464
 #define A_KMALLOC_END   0x7468
+#define A_PADCRD_CHN_E  0x74a8  // pad/card irq chain entry
+#define A_PAD_IRQR_ENA  0x74b8  // pad read on vint irq (nocash 'pad_enable_flag')
+#define A_CARD_IRQR_ENA 0x74bc  // same for card
+#define A_PAD_INBUF     0x74c8  // 2x buffers for rx pad data
+#define A_PAD_OUTBUF    0x74d0  // 2x buffers for tx pad data
+#define A_PAD_IN_LEN    0x74d8
+#define A_PAD_OUT_LEN   0x74e0
 #define A_EEXIT_PTR     0x75d0
 #define A_EXC_STACK     0x85d8  // exception stack top
 #define A_RCNT_VBL_ACK  0x8600
+#define A_PAD_ACK_VBL   0x8914  // enable vint ack by pad reading code
+#define A_CD_EVENTS     0xb9b8
 #define A_EXC_GP        0xf450
 
 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
@@ -305,17 +294,34 @@ static u32 loadRam32(u32 addr)
        return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
 }
 
+static void *castRam8ptr(u32 addr)
+{
+       assert(!(addr & 0x5f800000));
+       return psxM + (addr & 0x1fffff);
+}
+
 static void *castRam32ptr(u32 addr)
 {
        assert(!(addr & 0x5f800003));
        return psxM + (addr & 0x1ffffc);
 }
 
+static void *loadRam8ptr(u32 addr)
+{
+       return castRam8ptr(loadRam32(addr));
+}
+
 static void *loadRam32ptr(u32 addr)
 {
        return castRam32ptr(loadRam32(addr));
 }
 
+static void storeRam8(u32 addr, u8 d)
+{
+       assert(!(addr & 0x5f800000));
+       *((u8 *)psxM + (addr & 0x1fffff)) = d;
+}
+
 static void storeRam32(u32 addr, u32 d)
 {
        assert(!(addr & 0x5f800000));
@@ -377,14 +383,10 @@ static inline void softCallInException(u32 pc) {
                ra = sra;
 }
 
-static inline void DeliverEvent(u32 ev, u32 spec) {
-       if (EventCB[ev][spec].status != EvStACTIVE) return;
-
-//     EventCB[ev][spec].status = EvStALREADY;
-       if (EventCB[ev][spec].mode == EvMdINTR) {
-               softCall(EventCB[ev][spec].fhandler);
-       } else EventCB[ev][spec].status = EvStALREADY;
-}
+static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
+static u32 DeliverEvent(u32 class, u32 spec);
+static u32 UnDeliverEvent(u32 class, u32 spec);
+static void CloseEvent(u32 ev);
 
 /*                                           *
 //                                           *
@@ -397,8 +399,8 @@ static inline void DeliverEvent(u32 ev, u32 spec) {
        ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
        memcpy(Ra1, ptr, length); \
        if (FDesc[1 + mcd].mode & 0x8000) { \
-       DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
-       DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
+       DeliverEvent(0xf0000011, 0x0004); \
+       DeliverEvent(0xf4000001, 0x0004); \
        v0 = 0; } \
        else v0 = length; \
        FDesc[1 + mcd].offset += v0; \
@@ -412,8 +414,8 @@ static inline void DeliverEvent(u32 ev, u32 spec) {
        FDesc[1 + mcd].offset += length; \
        SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
        if (FDesc[1 + mcd].mode & 0x8000) { \
-       DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
-       DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
+       DeliverEvent(0xf0000011, 0x0004); \
+       DeliverEvent(0xf4000001, 0x0004); \
        v0 = 0; } \
        else v0 = length; \
 }
@@ -1602,8 +1604,8 @@ void psxBios__bu_init() { // 70
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
 #endif
 
-       DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-       DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+       DeliverEvent(0xf0000011, 0x0004);
+       DeliverEvent(0xf4000001, 0x0004);
 
        pc0 = ra;
 }
@@ -1616,13 +1618,13 @@ void psxBios__96_init() { // 71
        pc0 = ra;
 }
 
-static void psxBios_SysDeqIntRP_();
+static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
+static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
+static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
 
 static void psxBios_DequeueCdIntr_() {
-       a0 = 0; a1 = 0x91d0;
-       psxBios_SysDeqIntRP_();
-       a0 = 0; a1 = 0x91e0;
-       psxBios_SysDeqIntRP_();
+       psxBios_SysDeqIntRP_(0, 0x91d0);
+       psxBios_SysDeqIntRP_(0, 0x91e0);
        use_cycles(16);
 }
 
@@ -1634,11 +1636,11 @@ static void psxBios_DequeueCdIntr() { // a3
 static void psxBios_CdRemove() { // 56, 72
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
 
-       // CloseEvent 0xf1000000
-       // CloseEvent 0xf1000001
-       // CloseEvent 0xf1000002
-       // CloseEvent 0xf1000003
-       // CloseEvent 0xf1000004
+       CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
+       CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
+       CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
+       CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
+       CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
        psxBios_DequeueCdIntr_();
 
        // EnterCriticalSection - should be done at the beginning,
@@ -1693,24 +1695,24 @@ void psxBios__card_info() { // ab
        switch (port) {
        case 0x0:
        case 0x1:
-               ret = 0x2;
+               ret = 0x0004;
                if (McdDisable[port & 1])
-                       ret = 0x8;
+                       ret = 0x0100;
                break;
        default:
 #ifdef PSXBIOS_LOG
                PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], card_active_chan);
 #endif
-               ret = 0x11;
+               ret = 0x0302;
                break;
        }
 
        if (McdDisable[0] && McdDisable[1])
-               ret = 0x8;
+               ret = 0x0100;
 
-       DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-//     DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
-       DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
+       DeliverEvent(0xf0000011, 0x0004);
+//     DeliverEvent(0xf4000001, 0x0004);
+       DeliverEvent(0xf4000001, ret);
        v0 = 1; pc0 = ra;
 }
 
@@ -1721,8 +1723,8 @@ void psxBios__card_load() { // ac
 
        card_active_chan = a0;
 
-//     DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-       DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+//     DeliverEvent(0xf0000011, 0x0004);
+       DeliverEvent(0xf4000001, 0x0004);
 
        v0 = 1; pc0 = ra;
 }
@@ -1806,154 +1808,176 @@ void psxBios_ResetRCnt() { // 06
        pc0 = ra;
 }
 
+static u32 DeliverEvent(u32 class, u32 spec) {
+       EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
+       u32 evcb_len = loadRam32(A_TT_EvCB + 4);
+       u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
+       u32 i, lim = evcb_len / 0x1c;
 
-/* gets ev for use with EventCB */
-#define GetEv() \
-       ev = (a0 >> 24) & 0xf; \
-       if (ev == 0xf) ev = 0x5; \
-       ev*= 32; \
-       ev+= a0&0x1f;
-
-/* gets spec for use with EventCB */
-#define GetSpec() \
-       spec = 0; \
-       switch (a1) { \
-               case 0x0301: spec = 16; break; \
-               case 0x0302: spec = 17; break; \
-               default: \
-                       for (i=0; i<16; i++) if (a1 & (1 << i)) { spec = i; break; } \
-                       break; \
+       for (i = 0; i < lim; i++, ev++) {
+               use_cycles(8);
+               if (SWAP32(ev->status) != EvStACTIVE)
+                       continue;
+               use_cycles(4);
+               if (SWAP32(ev->class) != class)
+                       continue;
+               use_cycles(4);
+               if (SWAP32(ev->spec) != spec)
+                       continue;
+               use_cycles(6);
+               ret = SWAP32(ev->mode);
+               if (ret == EvMdMARK) {
+                       ev->status = SWAP32(EvStALREADY);
+                       continue;
+               }
+               use_cycles(8);
+               if (ret == EvMdCALL) {
+                       ret = SWAP32(ev->fhandler);
+                       if (ret) {
+                               v0 = ret;
+                               softCall(ret);
+                               ret = v0;
+                       }
+               }
        }
+       use_cycles(29);
+       return ret;
+}
 
-void psxBios_DeliverEvent() { // 07
-       int ev, spec;
-       int i;
-
-       GetEv();
-       GetSpec();
-
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x07], ev, spec);
-#endif
-
-       DeliverEvent(ev, spec);
+static u32 UnDeliverEvent(u32 class, u32 spec) {
+       EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
+       u32 evcb_len = loadRam32(A_TT_EvCB + 4);
+       u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
+       u32 i, lim = evcb_len / 0x1c;
 
-       pc0 = ra;
+       for (i = 0; i < lim; i++, ev++) {
+               use_cycles(8);
+               if (SWAP32(ev->status) != EvStALREADY)
+                       continue;
+               use_cycles(4);
+               if (SWAP32(ev->class) != class)
+                       continue;
+               use_cycles(4);
+               if (SWAP32(ev->spec) != spec)
+                       continue;
+               use_cycles(6);
+               if (SWAP32(ev->mode) == EvMdMARK)
+                       ev->status = SWAP32(EvStACTIVE);
+       }
+       use_cycles(28);
+       return ret;
 }
 
-void psxBios_OpenEvent() { // 08
-       int ev, spec;
-       int i;
-
-       GetEv();
-       GetSpec();
+static void psxBios_DeliverEvent() { // 07
+       u32 ret;
+       PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x (class:%x, spec:%x, mode:%x, func:%x)\n", biosB0n[0x08], ev, spec, a0, a1, a2, a3);
-#endif
+       ret = DeliverEvent(a0, a1);
+       mips_return(ret);
+}
 
-       EventCB[ev][spec].status = EvStWAIT;
-       EventCB[ev][spec].mode = a2;
-       EventCB[ev][spec].fhandler = a3;
+static s32 get_free_EvCB_slot() {
+       EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
+       u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
 
-       v0 = ev | (spec << 8);
-       pc0 = ra;
+       use_cycles(19);
+       for (i = 0; i < lim; i++, ev++) {
+               use_cycles(8);
+               if (ev->status == SWAP32(EvStUNUSED))
+                       return i;
+       }
+       return -1;
 }
 
-void psxBios_CloseEvent() { // 09
-       int ev, spec;
-
-       ev   = a0 & 0xff;
-       spec = (a0 >> 8) & 0xff;
+static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
+       u32 ret = get_free_EvCB_slot();
+       if ((s32)ret >= 0) {
+               EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
+               ev->class = SWAP32(class);
+               ev->status = SWAP32(EvStDISABLED);
+               ev->spec = SWAP32(spec);
+               ev->mode = SWAP32(mode);
+               ev->fhandler = SWAP32(func);
+               ret |= 0xf1000000u;
+       }
+       return ret;
+}
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x09], ev, spec);
-#endif
+static void psxBios_OpenEvent() { // 08
+       u32 ret = OpenEvent(a0, a1, a2, a3);
+       PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
+               biosB0n[0x08], a0, a1, a2, a3, ret);
+       mips_return_c(ret, 36);
+}
 
-       EventCB[ev][spec].status = EvStUNUSED;
+static void CloseEvent(u32 ev)
+{
+       u32 base = loadRam32(A_TT_EvCB);
+       storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
+}
 
-       v0 = 1; pc0 = ra;
+static void psxBios_CloseEvent() { // 09
+       PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
+               loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
+       CloseEvent(a0);
+       mips_return_c(1, 10);
 }
 
-void psxBios_WaitEvent() { // 0a
-       int ev, spec;
+static void psxBios_WaitEvent() { // 0a
+       u32 base = loadRam32(A_TT_EvCB);
+       u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
+       PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
 
-       ev   = a0 & 0xff;
-       spec = (a0 >> 8) & 0xff;
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec);
-#endif
-       if (EventCB[ev][spec].status == EvStUNUSED)
-       {
-               v0 = 0;
-               pc0 = ra;
+       use_cycles(15);
+       if (status == EvStALREADY) {
+               storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
+               mips_return(1);
                return;
        }
-
-       if (EventCB[ev][spec].status == EvStALREADY)
+       if (status != EvStACTIVE)
        {
-               /* Callback events (mode=EvMdINTR) do never set the ready flag (and thus WaitEvent would hang forever). */
-               if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
-               v0 = 1;
-               pc0 = ra;
+               mips_return_c(0, 2);
                return;
        }
 
-       v0 = 0;
-       pc0 = ra;
+       // retrigger this hlecall after the next emulation event
+       pc0 -= 4;
+       if ((s32)(next_interupt - psxRegs.cycle) > 0)
+               psxRegs.cycle = next_interupt;
+       psxBranchTest();
 }
 
-void psxBios_TestEvent() { // 0b
-       int ev, spec;
-
-       ev   = a0 & 0xff;
-       spec = (a0 >> 8) & 0xff;
-
-       if (EventCB[ev][spec].status == EvStALREADY)
-       {
-               if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
-               v0 = 1;
-       }
-       else
-       {
-               v0 = 0;
+static void psxBios_TestEvent() { // 0b
+       u32 base = loadRam32(A_TT_EvCB);
+       u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
+       u32 ret = 0;
+       PSXBIOS_LOG("psxBios_%s    %x %x\n", biosB0n[0x0b], a0, status);
+       if (status == EvStALREADY) {
+               storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
+               ret = 1;
        }
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0);
-#endif
-
-       pc0 = ra;
+       mips_return_c(ret, 15);
 }
 
-void psxBios_EnableEvent() { // 0c
-       int ev, spec;
+static void psxBios_EnableEvent() { // 0c
+       u32 base = loadRam32(A_TT_EvCB);
+       u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
+       PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], a0, status);
+       if (status != EvStUNUSED)
+               storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
 
-       ev   = a0 & 0xff;
-       spec = (a0 >> 8) & 0xff;
-
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0c], ev, spec);
-#endif
-
-       EventCB[ev][spec].status = EvStACTIVE;
-
-       v0 = 1; pc0 = ra;
+       mips_return_c(1, 15);
 }
 
-void psxBios_DisableEvent() { // 0d
-       int ev, spec;
-
-       ev   = a0 & 0xff;
-       spec = (a0 >> 8) & 0xff;
-
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0d], ev, spec);
-#endif
-
-       EventCB[ev][spec].status = EvStWAIT;
+static void psxBios_DisableEvent() { // 0d
+       u32 base = loadRam32(A_TT_EvCB);
+       u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
+       PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
+       if (status != EvStUNUSED)
+               storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
 
-       v0 = 1; pc0 = ra;
+       mips_return_c(1, 15);
 }
 
 /*
@@ -2032,36 +2056,55 @@ void psxBios_ChangeTh() { // 10
 }
 
 void psxBios_InitPAD() { // 0x12
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x12]);
-#endif
+       u32 i, *ram32 = (u32 *)psxM;
+       PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
 
-       pad_buf1 = (char*)Ra0;
-       pad_buf1len = a1;
-       pad_buf2 = (char*)Ra2;
-       pad_buf2len = a3;
+       // printf("%s", "PS-X Control PAD Driver  Ver 3.0");
+       // PAD_dr_enable = 0;
+       ram32[A_PAD_OUTBUF/4 + 0] = 0;
+       ram32[A_PAD_OUTBUF/4 + 1] = 0;
+       ram32[A_PAD_OUT_LEN/4 + 0] = 0;
+       ram32[A_PAD_OUT_LEN/4 + 1] = 0;
+       ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
+       ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
+       ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
+       ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
 
-       v0 = 1; pc0 = ra;
+       for (i = 0; i < a1; i++) {
+               use_cycles(4);
+               storeRam8(a0 + i, 0);
+       }
+       for (i = 0; i < a3; i++) {
+               use_cycles(4);
+               storeRam8(a2 + i, 0);
+       }
+       write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
+
+       ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
+
+       mips_return_c(1, 200);
 }
 
 void psxBios_StartPAD() { // 13
-#ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
-#endif
-       pad_stopped = 0;
-       psxHwWrite16(0x1f801074, (unsigned short)(psxHwRead16(0x1f801074) | 0x1));
+
+       psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
+       psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
+       psxHwWrite16(0x1f801070, ~1);
+       psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
+       storeRam32(A_PAD_ACK_VBL, 1);
+       storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
        psxRegs.CP0.n.SR |= 0x401;
-       pc0 = ra;
+
+       mips_return_c(1, 300);
 }
 
 void psxBios_StopPAD() { // 14
-#ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
-#endif
-       pad_stopped = 1;
-       pad_buf1 = NULL;
-       pad_buf2 = NULL;
-       pc0 = ra;
+       storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
+       psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
+       psxRegs.CP0.n.SR |= 0x401;
+       mips_return_void_c(200);
 }
 
 void psxBios_PAD_init() { // 15
@@ -2123,22 +2166,12 @@ void psxBios_HookEntryInt() { // 19
        mips_return_void_c(3);
 }
 
-void psxBios_UnDeliverEvent() { // 0x20
-       int ev, spec;
-       int i;
-
-       GetEv();
-       GetSpec();
-
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x20], ev, spec);
-#endif
-
-       if (EventCB[ev][spec].status == EvStALREADY &&
-               EventCB[ev][spec].mode == EvMdNOINTR)
-               EventCB[ev][spec].status = EvStACTIVE;
+static void psxBios_UnDeliverEvent() { // 0x20
+       u32 ret;
+       PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
 
-       pc0 = ra;
+       ret = UnDeliverEvent(a0, a1);
+       mips_return(ret);
 }
 
 char ffile[64], *pfile;
@@ -2246,8 +2279,8 @@ void psxBios_lseek() { // 0x33
                case 0: // SEEK_SET
                        FDesc[a0].offset = a1;
                        v0 = a1;
-//                     DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-//                     DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+//                     DeliverEvent(0xf0000011, 0x0004);
+//                     DeliverEvent(0xf4000001, 0x0004);
                        break;
 
                case 1: // SEEK_CUR
@@ -2426,11 +2459,11 @@ void psxBios_firstfile() { // 42
                nfile = 0;
                if (!strncmp(pa0, "bu00", 4)) {
                        // firstfile() calls _card_read() internally, so deliver it's event
-                       DeliverEvent(0x11, 0x2);
+                       DeliverEvent(0xf0000011, 0x0004);
                        bufile(1);
                } else if (!strncmp(pa0, "bu10", 4)) {
                        // firstfile() calls _card_read() internally, so deliver it's event
-                       DeliverEvent(0x11, 0x2);
+                       DeliverEvent(0xf0000011, 0x0004);
                        bufile(2);
                }
        }
@@ -2554,33 +2587,37 @@ void psxBios_delete() { // 45
 }
 
 void psxBios_InitCARD() { // 4a
-#ifdef PSXBIOS_LOG
+       u32 *ram32 = (u32 *)psxM;
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
-#endif
+       write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
+       // (maybe) todo: early_card_irq, FlushCache etc
 
-       CardState = 0;
+       ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
 
-       pc0 = ra;
+       mips_return_c(0, 300);
 }
 
 void psxBios_StartCARD() { // 4b
-#ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
-#endif
+       psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
+       psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
 
-       if (CardState == 0) CardState = 1;
+       psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
+       storeRam32(A_PAD_ACK_VBL, 1);
+       storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
+       storeRam32(A_CARD_IRQR_ENA, 1);
+       psxRegs.CP0.n.SR |= 0x401;
 
-       pc0 = ra;
+       mips_return_c(1, 200);
 }
 
 void psxBios_StopCARD() { // 4c
-#ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
-#endif
-
-       if (CardState == 1) CardState = 0;
-
-       pc0 = ra;
+       storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
+       psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
+       storeRam32(A_CARD_IRQR_ENA, 0);
+       psxRegs.CP0.n.SR |= 0x401;
+       mips_return_void_c(200);
 }
 
 void psxBios__card_write() { // 0x4e
@@ -2613,8 +2650,8 @@ void psxBios__card_write() { // 0x4e
                }
        }
 
-       DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-//     DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+       DeliverEvent(0xf0000011, 0x0004);
+//     DeliverEvent(0xf4000001, 0x0004);
 
        v0 = 1; pc0 = ra;
 }
@@ -2647,8 +2684,8 @@ void psxBios__card_read() { // 0x4f
                }
        }
 
-       DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-//     DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+       DeliverEvent(0xf0000011, 0x0004);
+//     DeliverEvent(0xf4000001, 0x0004);
 
        v0 = 1; pc0 = ra;
 }
@@ -2736,12 +2773,13 @@ void psxBios__card_chan() { // 0x58
        pc0 = ra;
 }
 
-void psxBios_ChangeClearPad() { // 5b
-#ifdef PSXBIOS_LOG
+static void psxBios_ChangeClearPad() { // 5b
+       u32 ret;
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
-#endif
+       ret = loadRam32(A_PAD_ACK_VBL);
+       storeRam32(A_PAD_ACK_VBL, a0);
 
-       pc0 = ra;
+       mips_return_c(ret, 6);
 }
 
 void psxBios__card_status() { // 5c
@@ -2764,8 +2802,6 @@ void psxBios__card_wait() { // 5d
 
 /* System calls C0 */
 
-static void psxBios_SysEnqIntRP();
-
 static void psxBios_InitRCnt() { // 00
        int i;
        PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
@@ -2775,15 +2811,13 @@ static void psxBios_InitRCnt() { // 00
                psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
                psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
        }
-       a1 = 0x6d88;
-       psxBios_SysEnqIntRP();
+       psxBios_SysEnqIntRP_(a0, 0x6d88);
        mips_return_c(0, 9);
 }
 
 static void psxBios_InitException() { // 01
        PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
-       a1 = 0x6da8;
-       psxBios_SysEnqIntRP();
+       psxBios_SysEnqIntRP_(a0, 0x6da8);
        mips_return_c(0, 9);
 }
 
@@ -2791,40 +2825,44 @@ static void psxBios_InitException() { // 01
  * int SysEnqIntRP(int index , long *queue);
  */
 
-static void psxBios_SysEnqIntRP() { // 02
+static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
        u32 old, base = loadRam32(A_TT_ExCB);
-       PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
 
-       old = loadRam32(base + (a0 << 3));
-       storeRam32(base + (a0 << 3), a1);
-       storeRam32(a1, old);
+       old = loadRam32(base + (priority << 3));
+       storeRam32(base + (priority << 3), chain_eptr);
+       storeRam32(chain_eptr, old);
        mips_return_c(0, 9);
 }
 
+static void psxBios_SysEnqIntRP() { // 02
+       PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
+       psxBios_SysEnqIntRP_(a0, a1);
+}
+
 /*
  * int SysDeqIntRP(int index , long *queue);
  */
 
-static void psxBios_SysDeqIntRP_() { // 03
+static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
        u32 ptr, next, base = loadRam32(A_TT_ExCB);
        u32 lim = 0, ret = 0;
 
        // as in original: no arg checks of any kind, bug if a1 == 0
-       ptr = loadRam32(base + (a0 << 3));
+       ptr = loadRam32(base + (priority << 3));
        while (ptr) {
                next = loadRam32(ptr);
-               if (ptr == a1) {
-                       storeRam32(base + (a0 << 3), next);
+               if (ptr == chain_rm_eptr) {
+                       storeRam32(base + (priority << 3), next);
                        ret = ptr;
                        use_cycles(6);
                        break;
                }
-               while (next && next != a1 && lim++ < 100) {
+               while (next && next != chain_rm_eptr && lim++ < 100) {
                        ptr = next;
                        next = loadRam32(ptr);
                        use_cycles(8);
                }
-               if (next == a1) {
+               if (next == chain_rm_eptr) {
                        next = loadRam32(next);
                        storeRam32(ptr, next);
                        ret = ptr;
@@ -2833,16 +2871,22 @@ static void psxBios_SysDeqIntRP_() { // 03
                break;
        }
        if (lim == 100)
-               PSXBIOS_LOG("bad chain %u %x\n", a0, base);
+               PSXBIOS_LOG("bad chain %u %x\n", priority, base);
 
        mips_return_c(ret, 12);
 }
 
 static void psxBios_SysDeqIntRP() { // 03
        PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
-       psxBios_SysDeqIntRP_();
+       psxBios_SysDeqIntRP_(a0, a1);
 }
 
+static void psxBios_get_free_EvCB_slot() { // 04
+       PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
+       s32 ret = get_free_EvCB_slot();
+       mips_return_c(ret, 0);
+}
+       
 static void psxBios_SysInitMemory_(u32 base, u32 size) {
        storeRam32(base, 0);
        storeRam32(A_KMALLOC_PTR, base);
@@ -2880,8 +2924,7 @@ static void psxBios_ChangeClearRCnt() { // 0a
 static void psxBios_InitDefInt() { // 0c
        PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
        // should also clear the autoack table
-       a1 = 0x6d98;
-       psxBios_SysEnqIntRP();
+       psxBios_SysEnqIntRP_(a0, 0x6d98);
        mips_return_c(0, 20 + 6*2);
 }
 
@@ -2900,9 +2943,7 @@ void (*biosA0[256])();
 void (*biosC0[256+128])();
 void (**biosB0)() = biosC0 + 128;
 
-#include "sjisfont.h"
-
-void setup_mips_code()
+static void setup_mips_code()
 {
        u32 *ptr;
        ptr = (u32 *)&psxM[A_SYSCALL];
@@ -2924,7 +2965,6 @@ void setup_mips_code()
 
        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);
@@ -2948,6 +2988,8 @@ static const struct {
        {     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)
@@ -2966,7 +3008,7 @@ static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
        d[1] = SWAPu32(handler1);
        d[2] = SWAPu32(handler2);
 
-       // install hle traps
+       // install the hle traps
        PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
        PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
 }
@@ -3007,11 +3049,103 @@ static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
 
        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);
+}
+
+#include "sjisfont.h"
+
 void psxBiosInit() {
-       u32 base, size;
-       u32 *ptr, *ram32;
+       u32 *ptr, *ram32, *rom32;
        int i;
        uLongf len;
 
@@ -3311,7 +3445,7 @@ void psxBiosInit() {
        biosC0[0x01] = psxBios_InitException;
        biosC0[0x02] = psxBios_SysEnqIntRP;
        biosC0[0x03] = psxBios_SysDeqIntRP;
-       //biosC0[0x04] = psxBios_get_free_EvCB_slot;
+       biosC0[0x04] = psxBios_get_free_EvCB_slot;
        //biosC0[0x05] = psxBios_get_free_TCB_slot;
        //biosC0[0x06] = psxBios_ExceptionHandler;
        //biosC0[0x07] = psxBios_InstallExeptionHandler;
@@ -3338,42 +3472,29 @@ void psxBiosInit() {
        //biosC0[0x1c] = psxBios_PatchAOTable;
 //************** THE END ***************************************
 /**/
-       base = 0x1000;
-       size = sizeof(EvCB) * 32;
-       EventCB = (void *)&psxR[base]; base += size * 6;
-       memset(EventCB, 0, size * 6);
-       HwEV = EventCB;
-       EvEV = EventCB + 32;
-       RcEV = EventCB + 32 * 2;
-       UeEV = EventCB + 32 * 3;
-       SwEV = EventCB + 32 * 4;
-       ThEV = EventCB + 32 * 5;
-
-       pad_stopped = 1;
+
        pad_buf = NULL;
-       pad_buf1 = NULL;
-       pad_buf2 = NULL;
-       pad_buf1len = pad_buf2len = 0;
        heap_addr = NULL;
        heap_end = NULL;
        heap_size = 0;
-       CardState = -1;
-       CurThread = 0;
        memset(FDesc, 0, sizeof(FDesc));
        card_active_chan = 0;
 
        // initial RNG seed
        psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
 
+       rom32 = (u32 *)psxR;
+       rom32[0x100/4] = SWAP32(0x19951204);
+       rom32[0x104/4] = SWAP32(3);
+       strcpy(psxR + 0x108, "PCSX authors");
+       strcpy(psxR + 0x12c, "PCSX HLE");
+
        // fonts
        len = 0x80000 - 0x66000;
        uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
        len = 0x80000 - 0x69d68;
        uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
 
-       // memory size 2 MB
-       psxHu32ref(0x1060) = SWAPu32(0x00000b88);
-
        /*      Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
                See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
                Here are some examples of games not working with this fix in place :
@@ -3430,9 +3551,14 @@ void psxBiosInit() {
        //  patch: +3d8, +4dc, +594, +62c, +9c8, +1988
        //  call:  +7a0=4b70, +884=4c54, +894=4c64
        ptr[0x5b] = SWAP32(0x43d0);
-       ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra
-       ram32[0x4c54/4] = SWAP32(0x03e00008); // jr $ra
+       ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
+
+       ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
+       ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
+       ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
+
        ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
+       ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
 
        ptr = (u32 *)&psxM[A_C0_TABLE];
        for (i = 0; i < 256/2; i++)
@@ -3479,8 +3605,6 @@ void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
 }
 
 static void biosPadHLE() {
-       int i, bufcount;
-
        if (pad_buf != NULL) {
                u32 *buf = (u32*)pad_buf;
 
@@ -3512,15 +3636,6 @@ static void biosPadHLE() {
                        *buf |= PAD2_poll(0) << 16;
                }
        }
-       if (!pad_stopped)  {
-               if (pad_buf1) {
-                       psxBios_PADpoll(1);
-               }
-
-               if (pad_buf2) {
-                       psxBios_PADpoll(2);
-               }
-       }
 }
 
 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
@@ -3550,7 +3665,7 @@ void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
        if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
                psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
                //if (--cdrom_irq_counter == 0) // 0xa0009180
-               //      DeliverEvent();         // 0xf0000003, 0x10
+               //      DeliverEvent(0xf0000003, 0x10);
                use_cycles(22);
                ret = 1;
        }
@@ -3581,7 +3696,7 @@ void hleExc0_2_2_syscall() // not in any A/B/C table
 
        if (code != R3000E_Syscall) {
                if (code != 0) {
-                       // DeliverEvent(); // 0xf0000010, 0x1000
+                       DeliverEvent(0xf0000010, 0x1000);
                        psxBios_SystemErrorUnresolvedException();
                }
                mips_return_c(0, 17);
@@ -3610,7 +3725,7 @@ void hleExc0_2_2_syscall() // not in any A/B/C table
                        break;
                }
                default:
-                       // DeliverEvent(); // 0xf0000010, 0x4000
+                       DeliverEvent(0xf0000010, 0x4000);
                        break;
        }
        use_cycles(30);
@@ -3627,10 +3742,7 @@ static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
 {
        u32 ret = 0;
        if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
-               // DeliverEvent 0xf2000000 + ev_index, 2
-               if (RcEV[ev_index][1].status == EvStACTIVE) {
-                       softCall(RcEV[ev_index][1].fhandler);
-               }
+               DeliverEvent(0xf2000000 + ev_index, 0x0002);
                ret = 1;
        }
        mips_return_c(ret, 22);
@@ -3694,7 +3806,7 @@ void hleExc3_0_2_defint(void)
        size_t i;
        for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
                if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
-                       // DeliverEvent 0xf0000000 + ev, 0x1000
+                       DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
                        use_cycles(7);
                }
 
@@ -3702,6 +3814,33 @@ void hleExc3_0_2_defint(void)
        mips_return_c(0, 11 + 7*11 + 7*11 + 12);
 }
 
+void hleExcPadCard1(void)
+{
+       if (loadRam32(A_PAD_IRQR_ENA)) {
+               u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
+               u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
+               int i, bufcount;
+
+               psxBios_PADpoll(1);
+               psxBios_PADpoll(2);
+               biosPadHLE();
+               use_cycles(100);
+       }
+       if (loadRam32(A_PAD_ACK_VBL))
+               psxHwWrite16(0x1f801070, ~1);
+       if (loadRam32(A_CARD_IRQR_ENA)) {
+               // todo, maybe
+       }
+
+       mips_return_c(0, 18);
+}
+
+void hleExcPadCard2(void)
+{
+       u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
+       mips_return_c(ret, 15);
+}
+
 void psxBiosException() {
        u32 tcbPtr = loadRam32(A_TT_PCB);
        u32 *chains = loadRam32ptr(A_TT_ExCB);
@@ -3719,7 +3858,7 @@ void psxBiosException() {
        }
        tcb->lo = SWAP32(psxRegs.GPR.n.lo);
        tcb->hi = SWAP32(psxRegs.GPR.n.hi);
-       tcb->epc = SWAP32(psxRegs.CP0.n.EPC);
+       //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
        tcb->sr = SWAP32(psxRegs.CP0.n.SR);
        tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
        sp = fp = loadRam32(A_EXC_SP);
@@ -3750,10 +3889,6 @@ void psxBiosException() {
        }
        assert(lim < 100);
 
-       // TODO make this a chain entry
-       if (psxHu32(0x1070) & 1)
-               biosPadHLE();
-
        // return from exception (custom or default)
        use_cycles(23);
        ptr = loadRam32(A_EEXIT_PTR);
@@ -3791,16 +3926,8 @@ void psxBiosFreeze(int Mode) {
        u32 base = 0x40000;
 
        bfreezepsxMptr(pad_buf, int);
-       bfreezepsxMptr(pad_buf1, char);
-       bfreezepsxMptr(pad_buf2, char);
        bfreezepsxMptr(heap_addr, u32);
-       bfreezel(&pad_buf1len);
-       bfreezel(&pad_buf2len);
-       bfreezes(regs);
-       bfreezel(&CardState);
-       bfreezel(&CurThread);
        bfreezes(FDesc);
        bfreezel(&card_active_chan);
-       bfreezel(&pad_stopped);
        bfreezel(&heap_size);
 }