#include "plat.h"
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/cheat.h"
+#include "../libpcsxcore/sio.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../plugins/cdrcimg/cdrcimg.h"
 #include "../plugins/dfsound/spu_config.h"
 
 
 #include <assert.h>
 #include "cdrom.h"
+#include "misc.h"
 #include "ppf.h"
 #include "psxdma.h"
 #include "arm_features.h"
 
 #include "psxcommon.h"
 #include "r3000a.h"
 #include "psxmem.h"
+#include "misc.h"
 
 #include "cheat.h"
 
 
 #include "mdec.h"
 #include "gpu.h"
 #include "ppf.h"
+#include "psxbios.h"
 #include "database.h"
 #include <zlib.h>
 
 }
 
 int LoadCdrom() {
-       EXE_HEADER tmpHead;
+       union {
+               EXE_HEADER h;
+               u32 d[sizeof(EXE_HEADER) / sizeof(u32)];
+       } tmpHead;
        struct iso_directory_record *dir;
        u8 time[4], *buf;
        u8 mdir[4096];
        u32 cnf_tcb = 4;
        u32 cnf_event = 16;
        u32 cnf_stack = 0;
+       u32 t_addr;
+       u32 t_size;
        u32 sp = 0;
-       int ret;
+       int i, ret;
 
        if (!Config.HLE) {
                if (psxRegs.pc != 0x80030000) // BiosBootBypass'ed or custom BIOS?
        }
 
        memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
+       for (i = 2; i < sizeof(tmpHead.d) / sizeof(tmpHead.d[0]); i++)
+               tmpHead.d[i] = SWAP32(tmpHead.d[i]);
 
-       SysPrintf("manual booting '%s' pc=%x\n", exename, SWAP32(tmpHead.pc0));
-       sp = SWAP32(tmpHead.s_addr);
+       SysPrintf("manual booting '%s' pc=%x\n", exename, tmpHead.h.pc0);
+       sp = tmpHead.h.s_addr;
        if (cnf_stack)
                sp = cnf_stack;
-       SetBootRegs(SWAP32(tmpHead.pc0), SWAP32(tmpHead.gp0), sp);
-
-       tmpHead.t_size = SWAP32(tmpHead.t_size);
-       tmpHead.t_addr = SWAP32(tmpHead.t_addr);
-
-       psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
-       //psxCpu->Reset();
+       SetBootRegs(tmpHead.h.pc0, tmpHead.h.gp0, sp);
 
        // Read the rest of the main executable
-       while (tmpHead.t_size & ~2047) {
-               void *ptr = (void *)PSXM(tmpHead.t_addr);
+       for (t_addr = tmpHead.h.t_addr, t_size = tmpHead.h.t_size; t_size & ~2047; ) {
+               void *ptr = (void *)PSXM(t_addr);
 
                incTime();
                READTRACK();
 
                if (ptr != INVALID_PTR) memcpy(ptr, buf+12, 2048);
 
-               tmpHead.t_size -= 2048;
-               tmpHead.t_addr += 2048;
+               t_addr += 2048;
+               t_size -= 2048;
        }
 
+       psxCpu->Clear(tmpHead.h.t_addr, tmpHead.h.t_size / 4);
+       //psxCpu->Reset();
+
+       if (Config.HLE)
+               psxBiosCheckExe(tmpHead.h.t_addr, tmpHead.h.t_size);
+
        return 0;
 }
 
 }
 
 int LoadState(const char *file) {
+       u32 biosBranchCheckOld = psxRegs.biosBranchCheck;
        void *f;
        GPUFreeze_t *gpufP = NULL;
        SPUFreeze_t *spufP = NULL;
        SaveFuncs.read(f, psxH, 0x00010000);
        SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
        psxRegs.gteBusyCycle = psxRegs.cycle;
+       psxRegs.biosBranchCheck = ~0;
 
        psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
 
        mdecFreeze(f, 0);
        new_dyna_freeze(f, 0);
 
+       if (Config.HLE)
+               psxBiosCheckExe(biosBranchCheckOld, 0x60);
+
        result = 0;
 cleanup:
        SaveFuncs.close(f);
 
 #include "events.h"
 #include "../psxhle.h"
 #include "../psxinterpreter.h"
+#include "../psxcounters.h"
 #include "../r3000a.h"
 #include "../gte_arm.h"
 #include "../gte_neon.h"
 
 
 u32 event_cycles[PSXINT_COUNT];
 
-void schedule_timeslice(void)
+u32 schedule_timeslice(void)
 {
        u32 i, c = psxRegs.cycle;
        u32 irqs = psxRegs.interrupt;
                        min = dif;
        }
        next_interupt = c + min;
+       return next_interupt;
 }
 
 typedef void (irq_func)();
 
+#include "../psxcommon.h"
+
 union psxCP0Regs_;
-void schedule_timeslice(void);
+u32  schedule_timeslice(void);
 void gen_interupt(union psxCP0Regs_ *cp0);
 
 #define LO_psxRegs_subCycle    (LO_muldivBusyCycle + 4)
 #define LO_psxRegs_biuReg      (LO_psxRegs_subCycle + 4*2)
 #define LO_psxRegs_reserved    (LO_psxRegs_biuReg + 4)
-#define LO_psxRegs_end         (LO_psxRegs_reserved + 4*3)
+#define LO_psxRegs_end         (LO_psxRegs_reserved + 4*7)
 #define LO_rcnts               (LO_psxRegs_end)
 #define LO_rcnts_end           (LO_rcnts + 7*4*4)
 #define LO_inv_code_start      (LO_rcnts_end)
 
 #include "new_dynarec_config.h"
 #include "../psxhle.h"
 #include "../psxinterpreter.h"
+#include "../psxcounters.h"
 #include "../gte.h"
 #include "emu_if.h" // emulator interface
 #include "linkage_offsets.h"
 #endif
 }
 
+static void force_intcall(int i)
+{
+  memset(&dops[i], 0, sizeof(dops[i]));
+  dops[i].itype = INTCALL;
+  dops[i].rs1 = CCREG;
+  dops[i].is_exception = 1;
+  cinfo[i].ba = -1;
+}
+
 static int apply_hacks(void)
 {
   int i;
       return 1;
     }
   }
+  if (Config.HLE)
+  {
+    if (start <= psxRegs.biosBranchCheck && psxRegs.biosBranchCheck < start + i*4)
+    {
+      i = (psxRegs.biosBranchCheck - start) / 4u + 23;
+      if (dops[i].is_jump && !dops[i+1].bt)
+      {
+        force_intcall(i);
+        dops[i+1].is_ds = 0;
+      }
+    }
+  }
   return 0;
 }
 
   return op->itype != CJUMP && op->itype != SJUMP;
 }
 
-static void force_intcall(int i)
-{
-  memset(&dops[i], 0, sizeof(dops[i]));
-  dops[i].itype = INTCALL;
-  dops[i].rs1 = CCREG;
-  dops[i].is_exception = 1;
-  cinfo[i].ba = -1;
-}
-
 static void disassemble_one(int i, u_int src)
 {
     unsigned int type, op, op2, op3;
 
 
 #include "psxcommon.h"
 #include "ppf.h"
+#include "misc.h"
 #include "cdrom.h"
 
 typedef struct tagPPF_DATA {
 
 #include "sio.h"
 #include "psxhle.h"
 #include "psxinterpreter.h"
+#include "new_dynarec/events.h"
 #include <zlib.h>
 
 #ifndef PSXBIOS_LOG
        int i;
        uLongf len;
 
+       psxRegs.biosBranchCheck = ~0;
+
        memset(psxM, 0, 0x10000);
        for(i = 0; i < 256; i++) {
                biosA0[i] = NULL;
        hleExcPadCard1, hleExcPadCard2,
 };
 
+void psxBiosCheckExe(u32 t_addr, u32 t_size)
+{
+       // lw      $v0, 0x10($sp)
+       // nop
+       // addiu   $v0, -1
+       // sw      $v0, 0x10($sp)
+       // lw      $v0, 0x10($sp)
+       // nop
+       // bne     $v0, $v1, not_timeout
+       // nop
+       // lui     $a0, ...
+       static const u8 pattern[] = {
+               0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
+               0xFF, 0xFF, 0x42, 0x24, 0x10, 0x00, 0xA2, 0xAF,
+               0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
+               0x0C, 0x00, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00,
+       };
+       u32 start = t_addr & 0x1ffffc;
+       u32 end = (start + t_size) & 0x1ffffc;
+       u32 buf[sizeof(pattern) / sizeof(u32)];
+       const u32 *r32 = (u32 *)(psxM + start);
+       u32 i, j;
+
+       if (end <= start)
+               return;
+       if (!Config.HLE)
+               return;
+
+       memcpy(buf, pattern, sizeof(buf));
+       for (i = 0; i < t_size / 4; i += j + 1) {
+               for (j = 0; j < sizeof(buf) / sizeof(buf[0]); j++)
+                       if (r32[i + j] != buf[j])
+                               break;
+               if (j != sizeof(buf) / sizeof(buf[0]))
+                       continue;
+
+               if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui
+                       continue;
+               SysPrintf("HLE vsync @%08x\n", start + i * 4);
+               psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4;
+       }
+}
+
+void psxBiosCheckBranch(void)
+{
+#if 1
+       // vsync HLE hack
+       static u32 cycles_prev, v0_prev;
+       u32 cycles_passed, waste_cycles;
+       u32 loops, v0_expect = v0_prev - 1;
+       if (v0 != 1)
+               return;
+       execI(&psxRegs);
+       cycles_passed = psxRegs.cycle - cycles_prev;
+       cycles_prev = psxRegs.cycle;
+       v0_prev = v0;
+       if (cycles_passed < 10 || cycles_passed > 50 || v0 != v0_expect)
+               return;
+
+       waste_cycles = schedule_timeslice() - psxRegs.cycle;
+       loops = waste_cycles / cycles_passed;
+       if (loops > v0)
+               loops = v0;
+       v0 -= loops;
+       psxRegs.cycle += loops * cycles_passed;
+       //printf("c %4u %d\n", loops, cycles_passed);
+#endif
+}
 
 #define bfreeze(ptr, size) { \
        if (Mode == 1) memcpy(&psxR[base], ptr, size); \
 
 void psxBiosFreeze(int Mode);
 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 sp);
 void psxBiosSetupBootState(void);
+void psxBiosCheckExe(u32 t_addr, u32 t_size);
+void psxBiosCheckBranch(void);
 
 extern void (*biosA0[256])();
 extern void (**biosB0)();
 
 #include "mdec.h"
 #include "gte.h"
 #include "psxinterpreter.h"
+#include "psxbios.h"
 #include "../include/compiler_features.h"
 
 R3000Acpu *psxCpu = NULL;
                psxRegs.CP0.n.Cause |= 0x400;
        if (((psxRegs.CP0.n.Cause | 1) & psxRegs.CP0.n.SR & 0x401) == 0x401)
                psxException(0, 0, &psxRegs.CP0);
+       else if (unlikely(psxRegs.pc == psxRegs.biosBranchCheck))
+               psxBiosCheckBranch();
 }
 
 void psxJumpTest() {
 
 #endif
 
 #include "psxcommon.h"
-#include "psxmem.h"
-#include "psxcounters.h"
-#include "psxbios.h"
 
 enum R3000Aexception {
        R3000E_Int = 0,      // Interrupt
        u8  dloadSel;       /* interp. delay load state */
        u8  dloadReg[2];
        u32 dloadVal[2];
+       u32 biosBranchCheck;
+       u32 reserved[3];
        // warning: changing anything in psxRegisters requires update of all
        // asm in libpcsxcore/new_dynarec/
 } psxRegisters;
 
 * SIO functions.
 */
 
+#include "misc.h"
+#include "psxcounters.h"
 #include "sio.h"
 #include <sys/stat.h>
 
        return BaudReg;
 }
 
-void netError() {
-       ClosePlugins();
-       SysMessage(_("Connection closed!\n"));
-
-       CdromId[0] = '\0';
-       CdromLabel[0] = '\0';
-
-       SysRunGui();
-}
-
 void sioInterrupt() {
 #ifdef PAD_LOG
        PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
 
 unsigned short sioReadCtrl16();
 unsigned short sioReadBaud16();
 
-void netError();
-
 void sioInterrupt();
 int sioFreeze(void *f, int Mode);