Browse Source

Backported last irixxxx's changes to my FunKey fork

root 3 years ago
parent
commit
b043a80a70

+ 3 - 0
.gitmodules

@@ -13,3 +13,6 @@
 [submodule "platform/common/minimp3"]
 	path = platform/common/minimp3
 	url = https://github.com/lieff/minimp3
+[submodule "platform/common/dr_libs"]
+	path = platform/common/dr_libs
+	url = https://github.com/mackron/dr_libs

+ 2 - 1
Makefile

@@ -245,7 +245,8 @@ OBJS += platform/common/mp3_helix.o
 else ifeq "$(HAVE_LIBAVCODEC)" "1"
 OBJS += platform/common/mp3_libavcodec.o
 else
-OBJS += platform/common/mp3_minimp3.o
+#OBJS += platform/common/mp3_minimp3.o
+OBJS += platform/common/mp3_drmp3.o
 endif
 endif
 

+ 21 - 4
Makefile.libretro

@@ -160,6 +160,9 @@ else ifeq ($(platform), ps3)
 	CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ -DFAMEC_NO_GOTOS
 	STATIC_LINKING = 1
 	NO_MMAP = 1
+	# PS3 has memory mapped in a way not suitable for DRC
+	use_sh2drc = 0
+	use_svpdrc = 0
 
 # sncps3
 else ifeq ($(platform), sncps3)
@@ -170,6 +173,9 @@ else ifeq ($(platform), sncps3)
 	CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ -DFAMEC_NO_GOTOS
 	STATIC_LINKING = 1
 	NO_MMAP = 1
+	# PS3 has memory mapped in a way not suitable for DRC
+	use_sh2drc = 0
+	use_svpdrc = 0
 
 # Lightweight PS3 Homebrew SDK
 else ifeq ($(platform), psl1ght)
@@ -179,6 +185,9 @@ else ifeq ($(platform), psl1ght)
 	CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ -DFAMEC_NO_GOTOS
 	STATIC_LINKING = 1
 	NO_MMAP = 1
+	# PS3 has memory mapped in a way not suitable for DRC
+	use_sh2drc = 0
+	use_svpdrc = 0
 
 # PSP
 else ifeq ($(platform), psp1)
@@ -253,14 +262,18 @@ else ifeq ($(platform), ngc)
 	TARGET := $(TARGET_NAME)_libretro_$(platform).a
 	CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
 	AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
-	CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__
+	CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST
+	STATIC_LINKING = 1
+	NO_MMAP = 1
 
 # Nintendo Wii
 else ifeq ($(platform), wii)
 	TARGET := $(TARGET_NAME)_libretro_$(platform).a
 	CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
 	AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
-	CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__
+	CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST
+	STATIC_LINKING = 1
+	NO_MMAP = 1
 
 # Nintendo Wii U
 else ifeq ($(platform), wiiu)
@@ -268,8 +281,12 @@ else ifeq ($(platform), wiiu)
 	CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
 	CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
 	AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
-	COMMONFLAGS += -DGEKKO -DWIIU -DHW_RVL -mwup -mcpu=750 -meabi -mhard-float -D__POWERPC__ -D__ppc__ -DMSB_FIRST -DWORDS_BIGENDIAN=1 -I./deps/include/
-	COMMONFLAGS += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int
+	CFLAGS += -DGEKKO -DWIIU -DHW_RVL -mwup -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST
+	STATIC_LINKING = 1
+	NO_MMAP = 1
+	# Wii U has memory mapped in a way not suitable for DRC
+	use_sh2drc = 0
+	use_svpdrc = 0
 
 # Nintendo Switch (libtransistor)
 else ifeq ($(platform), switch)

+ 1 - 1
cpu/drc/emit_arm64.c

@@ -1187,7 +1187,7 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode)
 #define host_instructions_updated(base, end, force) \
 	do { if (force) __builtin___clear_cache(base, end); } while (0)
 #define	emith_update_cache()	/**/
-#define emith_rw_offs_max()	0xff
+#define emith_rw_offs_max()	0x1ff
 #define emith_uext_ptr(r)	/**/
 
 

+ 18 - 11
cpu/drc/emit_ppc.c

@@ -362,6 +362,11 @@ enum { OPS_STD, OPS_STDU /*,OPS_STQ*/ };
 #define	PPC_STB_IMM(rt, ra, offs16) \
 	PPC_OP_IMM(OP_STB,rt,ra,(u16)(offs16))
 
+#define	PPC_STXU_IMM(rt, ra, offs16) \
+	PPC_OP_IMM(OP__ST,rt,ra,((u16)(offs16)&~3)|OPS_STDU)
+#define	PPC_STWU_IMM(rt, ra, offs16) \
+	PPC_OP_IMM(OP_STWU,rt,ra,(u16)(offs16))
+
 // load/store, indexed
 
 #define PPC_LDX_REG(rt, ra, rb) \
@@ -407,6 +412,7 @@ enum { OPS_STD, OPS_STDU /*,OPS_STQ*/ };
 #define PPC_LDP_REG			PPC_LDX_REG
 #define PPC_STP_IMM			PPC_STX_IMM
 #define PPC_STP_REG			PPC_STX_REG
+#define PPC_STPU_IMM			PPC_STXU_IMM
 #define PPC_BFXP_IMM			PPC_BFX_IMM
 
 #define emith_uext_ptr(r)		EMIT(PPC_EXTUW_REG(r, r))
@@ -440,6 +446,7 @@ enum { OPS_STD, OPS_STDU /*,OPS_STQ*/ };
 #define PPC_LDP_REG			PPC_LDW_REG
 #define PPC_STP_IMM			PPC_STW_IMM
 #define PPC_STP_REG			PPC_STW_REG
+#define PPC_STPU_IMM			PPC_STWU_IMM
 #define PPC_BFXP_IMM			PPC_BFXW_IMM
 
 #define emith_uext_ptr(r)		/**/
@@ -1552,10 +1559,11 @@ static int emith_cond_check(int cond)
 static NOINLINE void host_instructions_updated(void *base, void *end, int force)
 {
 	int step = 32, lgstep = 5;
-	char *_base = base, *_end = end;
-	int count = (_end - _base + step-1) >> lgstep;
+	char *_base = (char *)((uptr)base & ~(step-1));
+	int count = (((char *)end - _base) >> lgstep) + 1;
 
 	if (count <= 0) count = 1;	// make sure count is positive
+	base = _base;
 
 	asm volatile(
 	"	mtctr	%1;"
@@ -1587,25 +1595,24 @@ static NOINLINE void host_instructions_updated(void *base, void *end, int force)
 #define emith_sh2_drc_entry() do { \
 	int _c, _z = PTR_SIZE; u32 _m = 0xffffc000; /* r14-r31 */ \
 	if (__builtin_parity(_m) == 1) _m |= 0x1; /* ABI align for SP is 16 */ \
-	int _s = count_bits(_m) * _z, _o = 0; \
-	for (_c = HOST_REGS-1; _m && _c >= 0; _m &= ~(1 << _c), _c--) \
+	int _s = count_bits(_m) * _z, _o = STACK_EXTRA; \
+	EMIT(PPC_STPU_IMM(SP, SP, -_s-STACK_EXTRA)); \
+	EMIT(PPC_MFSP_REG(AT, LR)); \
+	for (_c = 0; _m && _c < HOST_REGS; _m &= ~(1 << _c), _c++) \
 		if (_m & (1 << _c)) \
-			{ _o -= _z; if (_c) emith_write_r_r_offs_ptr(_c, SP, _o); } \
-	EMIT(PPC_MFSP_REG(10, LR)); \
-	emith_write_r_r_offs_ptr(10, SP, 2*PTR_SIZE); \
-	emith_write_r_r_offs_ptr(SP, SP, -_s-STACK_EXTRA); /* XXX stdu */ \
-	emith_add_r_r_ptr_imm(SP, SP, -_s-STACK_EXTRA); \
+			{ if (_c) emith_write_r_r_offs_ptr(_c, SP, _o); _o += _z; } \
+	emith_write_r_r_offs_ptr(AT, SP, _o + _z); \
 } while (0)
 #define emith_sh2_drc_exit() do { \
 	int _c, _z = PTR_SIZE; u32 _m = 0xffffc000; \
 	if (__builtin_parity(_m) == 1) _m |= 0x1; \
 	int _s = count_bits(_m) * _z, _o = STACK_EXTRA; \
+	emith_read_r_r_offs_ptr(AT, SP, _o+_s + _z); \
+	EMIT(PPC_MTSP_REG(AT, LR)); \
 	for (_c = 0; _m && _c < HOST_REGS; _m &= ~(1 << _c), _c++) \
 		if (_m & (1 << _c)) \
 			{ if (_c) emith_read_r_r_offs_ptr(_c, SP, _o); _o += _z; } \
 	emith_add_r_r_ptr_imm(SP, SP, _s+STACK_EXTRA); \
-	emith_read_r_r_offs_ptr(10, SP, 2*PTR_SIZE); \
-	EMIT(PPC_MTSP_REG(10, LR)); \
 	emith_ret(); \
 } while (0)
 

+ 3 - 6
cpu/drc/emit_x86.c

@@ -383,12 +383,9 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI,	// x86-64,i386 common
 
 // _r_imm
 #define emith_move_r_imm(r, imm) do { \
-	if (imm) { \
-		EMIT_REX_IF(0, 0, r); \
-		EMIT_OP(0xb8 + ((r)&7)); \
-		EMIT(imm, u32); \
-	} else \
-		emith_eor_r_r(r, r); \
+	EMIT_REX_IF(0, 0, r); \
+	EMIT_OP(0xb8 + ((r)&7)); \
+	EMIT(imm, u32); \
 } while (0)
 
 #define emith_move_r_ptr_imm(r, imm) do { \

+ 5 - 8
cpu/musashi/m68kcpu.h

@@ -27,14 +27,11 @@
 #define M68KCPU__HEADER
 
 // notaz: something's missing this
-#ifndef UINT64
-#define UINT64 unsigned long long
-#endif
-#ifndef UINT16
-#define UINT32 unsigned int
-#define UINT16 unsigned short
-#define UINT8  unsigned char
-#endif
+#include <stdint.h>
+typedef uint64_t UINT64;
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t  UINT8;
 
 #include "m68k.h"
 #include <limits.h>

+ 80 - 34
cpu/sh2/compiler.c

@@ -203,19 +203,35 @@ static char sh2dasm_buff[64];
 		(ulong)(sh2)->poll_addr, (sh2)->poll_cycles, (sh2)->poll_cnt); \
 }
 
-#if (DRC_DEBUG & (8|256|512|1024)) || defined(PDB)
 #if (DRC_DEBUG & (256|512|1024))
 static SH2 csh2[2][8];
 static FILE *trace[2];
 static int topen[2];
 #endif
+#if (DRC_DEBUG & 8)
+static u32 lastpc, lastcnt;
+static void *lastblock;
+#endif
+#if (DRC_DEBUG & (8|256|512|1024)) || defined(PDB)
 static void REGPARM(3) *sh2_drc_log_entry(void *block, SH2 *sh2, u32 sr)
 {
   if (block != NULL) {
-    dbg(8, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
-      sh2->pc, block, (signed int)sr >> 12);
 #if defined PDB
+    dbg(8, "= %csh2 enter %08x %p, c=%d", sh2->is_slave?'s':'m',
+      sh2->pc, block, (signed int)sr >> 12);
     pdb_step(sh2, sh2->pc);
+#elif (DRC_DEBUG & 8)
+    if (lastpc != sh2->pc) {
+      if (lastcnt)
+        dbg(8, "= %csh2 enter %08x %p (%d times), c=%d", sh2->is_slave?'s':'m',
+          lastpc, lastblock, lastcnt, (signed int)sr >> 12);
+      dbg(8, "= %csh2 enter %08x %p, c=%d", sh2->is_slave?'s':'m',
+        sh2->pc, block, (signed int)sr >> 12);
+      lastpc = sh2->pc;
+      lastblock = block;
+      lastcnt = 0;
+    } else
+      lastcnt++;
 #elif (DRC_DEBUG & 256)
   {
     static SH2 fsh2;
@@ -468,7 +484,7 @@ static void rcache_free_tmp(int hr);
 #include "../drc/emit_mips.c"
 #elif defined(__riscv__) || defined(__riscv)
 #include "../drc/emit_riscv.c"
-#elif defined(__powerpc__) || defined(_M_PPC)
+#elif defined(__powerpc__) || defined(__ppc__) || defined(_M_PPC)
 #include "../drc/emit_ppc.c"
 #elif defined(__i386__) || defined(_M_X86)
 #include "../drc/emit_x86.c"
@@ -1339,6 +1355,7 @@ static void rcache_add_vreg_alias(int x, sh2_reg_e r);
 static void rcache_remove_vreg_alias(int x, sh2_reg_e r);
 static void rcache_evict_vreg(int x);
 static void rcache_remap_vreg(int x);
+static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode, int *hr);
 
 static void rcache_set_x16(int hr, int s16_, int u16_)
 {
@@ -1444,7 +1461,6 @@ static int rcache_is_u16(int hr)
   } */ \
 }
 
-#if PROPAGATE_CONSTANTS
 static inline int gconst_alloc(sh2_reg_e r)
 {
   int i, n = -1;
@@ -1481,7 +1497,6 @@ static void gconst_new(sh2_reg_e r, u32 val)
   if (guest_regs[r].vreg >= 0)
     rcache_remove_vreg_alias(guest_regs[r].vreg, r);
 }
-#endif
 
 static int gconst_get(sh2_reg_e r, u32 *val)
 {
@@ -2661,6 +2676,10 @@ static int emit_get_rbase_and_offs(SH2 *sh2, sh2_reg_e r, int rmode, s32 *offs)
   } else {
     // known fixed host address
     la = split_address(la + ((a + *offs) & mask), omask, offs);
+    if (la == 0) {
+      la = *offs;
+      *offs = 0;
+    }
     hr = rcache_get_tmp();
     emith_move_r_ptr_imm(hr, la);
   }
@@ -3014,12 +3033,22 @@ static void emit_do_static_regs(int is_write, int tmpr)
 // divide operation replacement functions, called by compiled code. Only the
 // 32:16 cases and the 64:32 cases described in the SH2 prog man are replaced.
 
-static uint32_t REGPARM(2) sh2_drc_divu32(uint32_t dv, uint32_t ds)
+// This is surprisingly difficult since the SH2 division operation is generating
+// the result in the dividend during the operation, leaving some remainder-like
+// stuff in the bits unused for the result, and leaving the T and Q status bits
+// in a state depending on the operands and the result. Q always reflects the
+// last result bit generated (i.e. bit 0 of the result). For T:
+//	32:16	T = top bit of the 16 bit remainder-like
+//	64:32	T = resulting T of the DIV0U/S operation
+// The remainder-like depends on outcome of the last generated result bit.
+
+static uint32_t REGPARM(3) sh2_drc_divu32(uint32_t dv, uint32_t *dt, uint32_t ds)
 {
-  if (ds && ds >= dv) {
-    // good case: no divide by 0, and no result overflow
+  if (ds > dv && (uint16_t)ds == 0) {
+    // good case: no overflow, divisor not 0, lower 16 bits 0
     uint32_t quot = dv / (ds>>16), rem = dv - (quot * (ds>>16));
     if (~quot&1) rem -= ds>>16;
+    *dt = (rem>>15) & 1;
     return (uint16_t)quot | ((2*rem + (quot>>31)) << 16);
   } else {
     // bad case: use the sh2 algo to get the right result
@@ -3029,20 +3058,21 @@ static uint32_t REGPARM(2) sh2_drc_divu32(uint32_t dv, uint32_t ds)
       dv = (dv<<1) | t;
       t = v;
       v = dv;
-      if (q)  dv += ds, q =   dv < v;
-      else    dv -= ds, q = !(dv < v);
+      if (q)  dv += ds, q = dv < v;
+      else    dv -= ds, q = dv > v;
       q ^= t, t = !q;
     }
+    *dt = dv>>31;
     return (dv<<1) | t;
   }
 }
 
 static uint32_t REGPARM(3) sh2_drc_divu64(uint32_t dh, uint32_t *dl, uint32_t ds)
 {
-  if (ds > 1 && ds >= dh) {
-    // good case: no divide by 0, and no result overflow
+  if (ds > dh) {
+    // good case: no overflow, divisor not 0
     uint64_t dv = *dl | ((uint64_t)dh << 32);
-    uint32_t quot = dv / ds, rem = dv - (quot * ds);
+    uint32_t quot = dv / ds, rem = dv - ((uint64_t)quot * ds);
     if (~quot&1) rem -= ds;
     *dl = quot;
     return rem;
@@ -3055,8 +3085,8 @@ static uint32_t REGPARM(3) sh2_drc_divu64(uint32_t dh, uint32_t *dl, uint32_t ds
       dv = (dv<<1) | t;
       t = v;
       v = dv;
-      if (q)  dv += ((uint64_t)ds << 32), q =   dv < v;
-      else    dv -= ((uint64_t)ds << 32), q = !(dv < v);
+      if (q)  dv += ((uint64_t)ds << 32), q = dv < v;
+      else    dv -= ((uint64_t)ds << 32), q = dv > v;
       q ^= t, t = !q;
     }
     *dl = (dv<<1) | t;
@@ -3064,16 +3094,17 @@ static uint32_t REGPARM(3) sh2_drc_divu64(uint32_t dh, uint32_t *dl, uint32_t ds
   }
 }
 
-static uint32_t REGPARM(2) sh2_drc_divs32(int32_t dv, int32_t ds)
+static uint32_t REGPARM(3) sh2_drc_divs32(int32_t dv, uint32_t *dt, int32_t ds)
 {
   uint32_t adv = abs(dv), ads = abs(ds)>>16;
-  if (ads > 1 && ads > adv>>16 && (int32_t)ads > 0 && !(uint16_t)ds) {
-    // good case: no divide by 0, and no result overflow
+  if (ads > adv>>16 && ds != 0x80000000 && (int16_t)ds == 0) {
+    // good case: no overflow, divisor not 0 and not MIN_INT, lower 16 bits 0
     uint32_t quot = adv / ads, rem = adv - (quot * ads);
     int m1 = (rem ? dv^ds : ds) < 0;
     if (rem && dv < 0)  rem = (quot&1 ? -rem : +ads-rem);
     else                rem = (quot&1 ? +rem : -ads+rem);
     quot = ((dv^ds)<0 ? -quot : +quot) - m1;
+    *dt = (rem>>15) & 1;
     return (uint16_t)quot | ((2*rem + (quot>>31)) << 16);
   } else {
     // bad case: use the sh2 algo to get the right result
@@ -3083,10 +3114,11 @@ static uint32_t REGPARM(2) sh2_drc_divs32(int32_t dv, int32_t ds)
       dv = (dv<<1) | t;
       t = v;
       v = dv;
-      if (m^q)  dv += ds, q =   (uint32_t)dv < v;
-      else      dv -= ds, q = !((uint32_t)dv < v);
+      if (m^q)  dv += ds, q = (uint32_t)dv < v;
+      else      dv -= ds, q = (uint32_t)dv > v;
       q ^= m^t, t = !(m^q);
     }
+    *dt = (uint32_t)dv>>31;
     return (dv<<1) | t;
   }
 }
@@ -3096,8 +3128,8 @@ static uint32_t REGPARM(3) sh2_drc_divs64(int32_t dh, uint32_t *dl, int32_t ds)
   int64_t _dv = *dl | ((int64_t)dh << 32);
   uint64_t adv = (_dv < 0 ? -_dv : _dv); // llabs isn't in older toolchains
   uint32_t ads = abs(ds);
-  if (ads > 1 && ads > adv>>32 && (int64_t)adv > 0) {
-    // good case: no divide by 0, and no result overflow
+  if (ads > adv>>32 && ds != 0x80000000) {
+    // good case: no overflow, divisor not 0 and not MIN_INT
     uint32_t quot = adv / ads, rem = adv - ((uint64_t)quot * ads);
     int m1 = (rem ? dh^ds : ds) < 0;
     if (rem && dh < 0) rem = (quot&1 ? -rem : +ads-rem);
@@ -3110,12 +3142,12 @@ static uint32_t REGPARM(3) sh2_drc_divs64(int32_t dh, uint32_t *dl, int32_t ds)
     uint64_t dv = *dl | ((uint64_t)dh << 32);
     int m = (uint32_t)ds>>31, q = (uint64_t)dv>>63, t = m^q, s = 32;
     while (s--) {
-      int64_t v = (uint64_t)dv>>63;
+      uint64_t v = (uint64_t)dv>>63;
       dv = (dv<<1) | t;
       t = v;
       v = dv;
-      if (m^q)  dv += ((uint64_t)ds << 32), q =   dv < v;
-      else      dv -= ((uint64_t)ds << 32), q = !(dv < v);
+      if (m^q)  dv += ((uint64_t)ds << 32), q = dv < v;
+      else      dv -= ((uint64_t)ds << 32), q = dv > v;
       q ^= m^t, t = !(m^q);
     }
     *dl = (dv<<1) | t;
@@ -3921,8 +3953,10 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
 #if DIV_OPTIMIZER
           if (div(opd).div1 == 16 && div(opd).ro == div(opd).rn) {
             // divide 32/16
+            tmp = rcache_get_tmp_arg(1);
+            emith_add_r_r_ptr_imm(tmp, CONTEXT_REG, offsetof(SH2, drc_tmp));
             rcache_get_reg_arg(0, div(opd).rn, NULL);
-            rcache_get_reg_arg(1, div(opd).rm, NULL);
+            rcache_get_reg_arg(2, div(opd).rm, NULL);
             rcache_invalidate_tmp();
             emith_abicall(sh2_drc_divu32);
             tmp = rcache_get_tmp_ret();
@@ -3934,8 +3968,9 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
             emith_and_r_r_imm(tmp3, tmp2, 1);     // Q = !Rn[0]
             emith_eor_r_r_imm(tmp3, tmp3, 1);
             emith_or_r_r_lsl(sr, tmp3, Q_SHIFT);
+            emith_ctx_read(tmp3, offsetof(SH2, drc_tmp));
+            emith_or_r_r_r(sr, sr, tmp3);         // T
             rcache_free_tmp(tmp3);
-            emith_or_r_r_r_lsr(sr, sr, tmp2, 31); // T = Rn[31]
             skip_op = div(opd).div1 + div(opd).rotcl;
           }
           else if (div(opd).div1 == 32 && div(opd).ro != div(opd).rn) {
@@ -3960,7 +3995,6 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
             emith_eor_r_r_imm(tmp3, tmp3, 1);
             emith_or_r_r_lsl(sr, tmp3, Q_SHIFT);
             rcache_free_tmp(tmp3);
-            emith_or_r_r_r_lsr(sr, sr, tmp4, 31); // T = Ro[31]
             skip_op = div(opd).div1 + div(opd).rotcl;
           }
 #endif
@@ -4035,8 +4069,10 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
 #if DIV_OPTIMIZER
         if (div(opd).div1 == 16 && div(opd).ro == div(opd).rn) {
           // divide 32/16
+          tmp = rcache_get_tmp_arg(1);
+          emith_add_r_r_ptr_imm(tmp, CONTEXT_REG, offsetof(SH2, drc_tmp));
           rcache_get_reg_arg(0, div(opd).rn, NULL);
-          tmp2 = rcache_get_reg_arg(1, div(opd).rm, NULL);
+          tmp2 = rcache_get_reg_arg(2, div(opd).rm, NULL);
           tmp3 = rcache_get_tmp();
           emith_lsr(tmp3, tmp2, 31);
           emith_or_r_r_lsl(sr, tmp3, M_SHIFT);        // M = Rm[31]
@@ -4052,19 +4088,22 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
           emith_and_r_r_imm(tmp3, tmp3, 1);
           emith_eor_r_r_imm(tmp3, tmp3, 1);
           emith_or_r_r_lsl(sr, tmp3, Q_SHIFT);        // Q = !Rn[0]^M
+          emith_ctx_read(tmp3, offsetof(SH2, drc_tmp));
+          emith_or_r_r_r(sr, sr, tmp3);               // T
           rcache_free_tmp(tmp3);
-          emith_or_r_r_r_lsr(sr, sr, tmp2, 31);       // T = Rn[31]
           skip_op = div(opd).div1 + div(opd).rotcl;
         }
         else if (div(opd).div1 == 32 && div(opd).ro != div(opd).rn) {
           // divide 64/32
           tmp4 = rcache_get_reg(div(opd).ro, RC_GR_READ, NULL);
           emith_ctx_write(tmp4, offsetof(SH2, drc_tmp));
-          rcache_get_reg_arg(0, div(opd).rn, NULL);
+          tmp  = rcache_get_reg_arg(0, div(opd).rn, NULL);
           tmp2 = rcache_get_reg_arg(2, div(opd).rm, NULL);
           tmp3 = rcache_get_tmp_arg(1);
           emith_lsr(tmp3, tmp2, 31);
-          emith_or_r_r_lsl(sr, tmp3, M_SHIFT);         // M = Rm[31]
+          emith_or_r_r_lsl(sr, tmp3, M_SHIFT);        // M = Rm[31]
+          emith_eor_r_r_lsr(tmp3, tmp, 31);
+          emith_or_r_r(sr, tmp3);                     // T = Rn[31]^M
           emith_add_r_r_ptr_imm(tmp3, CONTEXT_REG, offsetof(SH2, drc_tmp));
           rcache_invalidate_tmp();
           emith_abicall(sh2_drc_divs64);
@@ -4081,7 +4120,6 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
           emith_eor_r_r_imm(tmp3, tmp3, 1);
           emith_or_r_r_lsl(sr, tmp3, Q_SHIFT);        // Q = !Ro[0]^M
           rcache_free_tmp(tmp3);
-          emith_or_r_r_r_lsr(sr, sr, tmp4, 31);       // T = Ro[31]
           skip_op = div(opd).div1 + div(opd).rotcl;
         } else
 #endif
@@ -5639,6 +5677,9 @@ int sh2_execute_drc(SH2 *sh2c, int cycles)
   // others are usual SH2 flags
   sh2c->sr &= 0x3f3;
   sh2c->sr |= cycles << 12;
+#if (DRC_DEBUG & 8)
+  lastpc = lastcnt = 0;
+#endif
 
   sh2c->state |= SH2_IN_DRC;
   sh2_drc_entry(sh2c);
@@ -5648,6 +5689,11 @@ int sh2_execute_drc(SH2 *sh2c, int cycles)
   ret_cycles = (int32_t)sh2c->sr >> 12;
   if (ret_cycles > 0)
     dbg(1, "warning: drc returned with cycles: %d, pc %08x", ret_cycles, sh2c->pc);
+#if (DRC_DEBUG & 8)
+  if (lastcnt)
+    dbg(8, "= %csh2 enter %08x %p (%d times), c=%d", sh2c->is_slave?'s':'m',
+      lastpc, lastblock, lastcnt, (signed int)sh2c->sr >> 12);
+#endif
 
   sh2c->sr &= 0x3f3;
   return ret_cycles;

+ 1 - 1
cpu/sh2/compiler.h

@@ -47,7 +47,7 @@ u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc,
 #elif defined(__riscv__) || defined(__riscv)
 #define	DRC_SR_REG	"s11"
 #define DRC_REG_LL	0	// no ABI for (__ILP32__ && __riscv_xlen != 32)
-#elif defined(__powerpc__)
+#elif defined(__powerpc__) || defined(__ppc__)
 #define	DRC_SR_REG	"r28"
 #define DRC_REG_LL	0	// no ABI for __ILP32__
 #elif defined(__i386__)

+ 10 - 10
pico/32x/32x.c

@@ -56,14 +56,14 @@ void p32x_update_irls(SH2 *active_sh2, unsigned int m68k_cycles)
   if (mrun) {
     p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, m68k_cycles);
     if (msh2.state & SH2_STATE_RUN)
-      sh2_end_run(&msh2, 1);
+      sh2_end_run(&msh2, 0);
   }
 
   srun = sh2_irl_irq(&ssh2, slvl, ssh2.state & SH2_STATE_RUN);
   if (srun) {
     p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, m68k_cycles);
     if (ssh2.state & SH2_STATE_RUN)
-      sh2_end_run(&ssh2, 1);
+      sh2_end_run(&ssh2, 0);
   }
 
   elprintf(EL_32X, "update_irls: m %d/%d, s %d/%d", mlvl, mrun, slvl, srun);
@@ -142,9 +142,9 @@ void p32x_reset_sh2s(void)
       unsigned int vbr;
 
       // initial data
-      idl_src = CPU_BE2(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000;
-      idl_dst = CPU_BE2(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000;
-      idl_size= CPU_BE2(*(unsigned int *)(Pico.rom + 0x3dc));
+      idl_src = CPU_BE2(*(u32 *)(Pico.rom + 0x3d4)) & ~0xf0000000;
+      idl_dst = CPU_BE2(*(u32 *)(Pico.rom + 0x3d8)) & ~0xf0000000;
+      idl_size= CPU_BE2(*(u32 *)(Pico.rom + 0x3dc));
       if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize ||
           idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) {
         elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x",
@@ -154,11 +154,11 @@ void p32x_reset_sh2s(void)
         memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size);
 
       // VBR
-      vbr = CPU_BE2(*(unsigned int *)(Pico.rom + 0x3e8));
+      vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3e8));
       sh2_set_vbr(0, vbr);
 
       // checksum and M_OK
-      Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e);
+      Pico32x.regs[0x28 / 2] = *(u16 *)(Pico.rom + 0x18e);
     }
     // program will set M_OK
   }
@@ -168,7 +168,7 @@ void p32x_reset_sh2s(void)
     unsigned int vbr;
 
     // GBR/VBR
-    vbr = CPU_BE2(*(unsigned int *)(Pico.rom + 0x3ec));
+    vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3ec));
     sh2_set_gbr(1, 0x20004000);
     sh2_set_vbr(1, vbr);
     // program will set S_OK
@@ -328,7 +328,7 @@ void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after)
   left_to_next = C_M68K_TO_SH2(sh2, (int)(event_time_next - now));
   if (sh2_cycles_left(sh2) > left_to_next) {
     if (left_to_next < 1)
-      left_to_next = 1;
+      left_to_next = 0;
     sh2_end_run(sh2, left_to_next);
   }
 }
@@ -421,7 +421,7 @@ void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
     left_to_event = C_M68K_TO_SH2(sh2, (int)(event_time_next - m68k_target));
     if (sh2_cycles_left(sh2) > left_to_event) {
       if (left_to_event < 1)
-        left_to_event = 1;
+        left_to_event = 0;
       sh2_end_run(sh2, left_to_event);
     }
   }

+ 1 - 1
pico/32x/draw.c

@@ -10,7 +10,7 @@
 
 // BGR555 to native conversion
 #if defined(USE_BGR555)
-#define PXCONV(t)   (t)
+#define PXCONV(t)   ((t)&(mr|mg|mb|mp))
 #define PXPRIO      0x8000  // prio in MSB
 #elif defined(USE_BGR565)
 #define PXCONV(t)   (((t)&mr)  | (((t)&(mg|mb)) << 1) | (((t)&mp) >> 10))

+ 52 - 17
pico/32x/draw_arm.S

@@ -101,10 +101,46 @@
     mov     r6, #320
     add     r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
 
+    ldrh    r7, [r5], #2
 2: @ loop_inner:
-    ldrh    r8, [r5], #2
+    mov     r8, r7
     subs    lr, r6, #1
     blt     0b @ loop_outer
+    beq     7f @ single_pix
+    ldrh    r7, [r5], #2     @ 32x pixel
+    cmp     r7, r8           @ do RLE only if we have at least 2 px
+@    ldreqh  r7, [r5]
+@    cmpeq   r7, r8
+    subeq   lr, lr, #1
+    beq     3f @ loop_innermost
+
+7: @ single_pix:
+    mov     r6, lr
+
+    eor     r12,r8, r10
+    tst     r12, #0x8000     @ !((t ^ inv) & 0x8000)
+    addeq   r11,r11,#1
+    beq     8f @ single_pix_32x
+
+    ldrb    r12,[r11], #1    @ MD pixel
+    cmp     r3, r12,lsl #26  @ MD has bg pixel?
+.if \do_md
+    movne   r12,r12,lsl #1
+    ldrneh  r12,[r9, r12]
+    strneh  r12,[r0], #2     @ *dst++ = palmd[*pmd]
+.else
+    addne   r0, r0, #2
+.endif
+    bne     2b @ loop_inner
+
+8: @ single_pix_32x:
+    and     r12,r8, #0x03e0
+    mov     r8, r8, lsl #11
+    orr     r8, r8, r8, lsr #(10+11)
+    orr     r8, r8, r12,lsl #1
+    bic     r8, r8, #0x0020  @ kill prio bit
+    strh    r8, [r0], #2
+    b       2b @ loop_inner
 
 3: @ loop_innermost:
     ldrh    r7, [r5], #2     @ 32x pixel
@@ -112,7 +148,6 @@
     cmpge   r7, r8
     beq     3b @ loop_innermost
 
-    sub     r5, r5, #2
     add     lr, lr, #1
     sub     lr, r6, lr
     sub     r6, r6, lr
@@ -121,10 +156,10 @@
     tst     r12, #0x8000     @ !((t ^ inv) & 0x8000)
     bne     5f @ draw_md
 
-    and     r7 ,r8, #0x03e0
+    and     r12,r8, #0x03e0
     mov     r8, r8, lsl #11
     orr     r8, r8, r8, lsr #(10+11)
-    orr     r8, r8, r7 ,lsl #1
+    orr     r8, r8, r12,lsl #1
     bic     r8, r8, #0x0020  @ kill prio bit
 
     add     r11,r11,lr
@@ -148,35 +183,35 @@
 
 5: @ draw_md:
     subs    lr, lr, #1
-    ldrgeb  r7, [r11], #1    @ MD pixel
+    ldrgeb  r12,[r11], #1    @ MD pixel
     blt     2b @ loop_inner
-    cmp     r3, r7, lsl #26  @ MD has bg pixel?
+    cmp     r3, r12,lsl #26  @ MD has bg pixel?
 .if \do_md
-    mov     r7, r7, lsl #1
-    ldrneh  r7 ,[r9, r7]
-    strneh  r7 ,[r0], #2     @ *dst++ = palmd[*pmd]
+    mov     r12,r12,lsl #1
+    ldrneh  r12,[r9, r12]
+    strneh  r12,[r0], #2     @ *dst++ = palmd[*pmd]
 .else
     addne   r0, r0, #2
 .endif
     bne     5b @ draw_md
 
-    and     r7 ,r8, #0x03e0
+    and     r12,r8, #0x03e0
     mov     r8, r8, lsl #11
     orr     r8, r8, r8, lsr #(10+11)
-    orr     r8, r8, r7 ,lsl #1
+    orr     r8, r8, r12,lsl #1
     bic     r8, r8, #0x0020  @ kill prio bit
     strh    r8, [r0], #2     @ *dst++ = bgr2rgb(*p32x++)
 
 6: @ draw_md_32x:
     subs    lr, lr, #1
-    ldrgeb  r7, [r11], #1    @ MD pixel
+    ldrgeb  r12,[r11], #1    @ MD pixel
     blt     2b @ loop_inner
-    cmp     r3, r7, lsl #26  @ MD has bg pixel?
+    cmp     r3, r12,lsl #26  @ MD has bg pixel?
 .if \do_md
-    mov     r7, r7, lsl #1
-    ldrneh  r7 ,[r9, r7]     @ *dst++ = palmd[*pmd]
-    moveq   r7 ,r8           @ *dst++ = bgr2rgb(*p32x++)
-    strh    r7 ,[r0], #2
+    mov     r12,r12,lsl #1
+    ldrneh  r12,[r9, r12]    @ *dst++ = palmd[*pmd]
+    moveq   r12,r8           @ *dst++ = bgr2rgb(*p32x++)
+    strh    r12,[r0], #2
 .else
     streqh  r8, [r0]         @ *dst++ = bgr2rgb(*p32x++)
     add     r0, r0, #2

+ 17 - 12
pico/32x/memory.c

@@ -126,7 +126,7 @@ void NOINLINE p32x_sh2_poll_detect(u32 a, SH2 *sh2, u32 flags, int maxcnt)
           sh2->state, sh2->state | flags);
 
       sh2->state |= flags;
-      sh2_end_run(sh2, 1);
+      sh2_end_run(sh2, 0);
       pevt_log_sh2(sh2, EVT_POLL_START);
 #ifdef DRC_SH2
       // mark this as an address used for polling if SDRAM
@@ -324,7 +324,7 @@ static u32 sh2_comm_faker(u32 a)
   static int f = 0;
   if (a == 0x28 && !p32x_csum_faked) {
     p32x_csum_faked = 1;
-    return *(unsigned short *)(Pico.rom + 0x18e);
+    return *(u16 *)(Pico.rom + 0x18e);
   }
   if (f >= sizeof(comm_fakevals) / sizeof(comm_fakevals[0]))
     f = 0;
@@ -855,7 +855,7 @@ static void p32x_sh2reg_write8(u32 a, u32 d, SH2 *sh2)
         p32x_m68k_poll_event(P32XF_68KCPOLL);
         p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL, cycles);
         if (p32x_sh2_ready(sh2->other_sh2, cycles+8))
-          sh2_end_run(sh2, 1);
+          sh2_end_run(sh2, 0);
         sh2_poll_write(a & ~1, r[a / 2], cycles, sh2);
       }
       return;
@@ -948,7 +948,7 @@ static void p32x_sh2reg_write16(u32 a, u32 d, SH2 *sh2)
         p32x_m68k_poll_event(P32XF_68KCPOLL);
         p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_CPOLL, cycles);
         if (p32x_sh2_ready(sh2->other_sh2, cycles+8))
-          sh2_end_run(sh2, 1);
+          sh2_end_run(sh2, 0);
         sh2_poll_write(a, d, cycles, sh2);
       }
       return;
@@ -1583,7 +1583,7 @@ static void sh2_sdram_poll(u32 a, u32 d, SH2 *sh2)
   sh2_poll_write(a, d, cycles, sh2);
   p32x_sh2_poll_event(sh2->other_sh2, SH2_STATE_RPOLL, cycles);
   if (p32x_sh2_ready(sh2->other_sh2, cycles+8))
-    sh2_end_run(sh2, 1);
+    sh2_end_run(sh2, 0);
   DRC_RESTORE_SR(sh2);
 }
 
@@ -1690,16 +1690,21 @@ static void REGPARM(3) sh2_write8_da(u32 a, u32 d, SH2 *sh2)
 }
 #endif
 
+static NOINLINE void REGPARM(3) sh2_write8_sdram_sync(u32 a, u32 d, SH2 *sh2)
+{
+  DRC_SAVE_SR(sh2);
+  sh2_end_run(sh2, 32);
+  DRC_RESTORE_SR(sh2);
+  sh2_write8_sdram(a, d, sh2);
+}
+
 static void REGPARM(3) sh2_write8_sdram_wt(u32 a, u32 d, SH2 *sh2)
 {
   // xmen sync hack..
-  if (a < 0x26000200) {
-    DRC_SAVE_SR(sh2);
-    sh2_end_run(sh2, 32);
-    DRC_RESTORE_SR(sh2);
-  }
-
-  sh2_write8_sdram(a, d, sh2);
+  if ((a << 8) >> 17) // ((a & 0x00ffffff) < 0x200)
+    sh2_write8_sdram(a, d, sh2);
+  else
+    sh2_write8_sdram_sync(a, d, sh2);
 }
 
 // write16

+ 9 - 7
pico/cart.c

@@ -187,7 +187,7 @@ zip_failed:
   else if (strcasecmp(ext, "cso") == 0)
   {
     cso_struct *cso = NULL, *tmp = NULL;
-    int size;
+    int i, size;
     f = fopen(path, "rb");
     if (f == NULL)
       goto cso_failed;
@@ -229,6 +229,8 @@ zip_failed:
       elprintf(EL_STATUS, "cso: premature EOF");
       goto cso_failed;
     }
+    for (i = 0; i < size/4; i++)
+      cso->index[i] = CPU_LE4(cso->index[i]);
 
     // all ok
     cso->fpos_in = ftell(f);
@@ -280,7 +282,7 @@ cso_failed:
     chd->file.file = chd;
     chd->file.type = PMT_CHD;
     // subchannel data is skipped, remove it from total size
-    chd->file.size = chd_get_header(cf)->logicalbytes / CD_FRAME_SIZE * CD_MAX_SECTOR_DATA;
+    chd->file.size = head->logicalbytes / CD_FRAME_SIZE * CD_MAX_SECTOR_DATA;
     strncpy(chd->file.ext, ext, sizeof(chd->file.ext) - 1);
     return &chd->file;
 
@@ -359,7 +361,7 @@ static size_t _pm_read_chd(void *ptr, size_t bytes, pm_file *stream, int is_audi
       if (len > bytes)
         len = bytes;
 
-#ifdef CPU_IS_LE
+#if CPU_IS_LE
       if (is_audio) {
         // convert big endian audio samples
         u16 *dst = ptr, v;
@@ -821,7 +823,7 @@ int PicoCartInsert(unsigned char *rom, unsigned int romsize, const char *carthw_
   // This will hang the emu, but will prevent nasty crashes.
   // note: 4 bytes are padded to every ROM
   if (rom != NULL)
-    *(unsigned long *)(rom+romsize) = CPU_BE2(0x4EFAFFFE);
+    *(u32 *)(rom+romsize) = CPU_BE2(0x4EFAFFFE);
 
   Pico.rom=rom;
   Pico.romsize=romsize;
@@ -1254,11 +1256,11 @@ static void PicoCartDetect(const char *carthw_cfg)
   int fill_sram = 0;
 
   memset(&Pico.sv, 0, sizeof(Pico.sv));
-  if (Pico.rom[0x1B1] == 'R' && Pico.rom[0x1B0] == 'A')
+  if (Pico.rom[MEM_BE2(0x1B0)] == 'R' && Pico.rom[MEM_BE2(0x1B1)] == 'A')
   {
     Pico.sv.start =  rom_read32(0x1B4) & ~0xff000001; // align
     Pico.sv.end   = (rom_read32(0x1B8) & ~0xff000000) | 1;
-    if (Pico.rom[0x1B2] & 0x40)
+    if (Pico.rom[MEM_BE2(0x1B3)] & 0x40)
       // EEPROM
       Pico.sv.flags |= SRF_EEPROM;
     Pico.sv.flags |= SRF_ENABLED;
@@ -1309,7 +1311,7 @@ static void PicoCartDetect(const char *carthw_cfg)
 
   // Unusual region 'code'
   if (rom_strcmp(0x1f0, "EUROPE") == 0 || rom_strcmp(0x1f0, "Europe") == 0)
-    *(int *) (Pico.rom + 0x1f0) = 0x20204520;
+    *(u32 *) (Pico.rom + 0x1f0) = CPU_LE4(0x20204520);
 }
 
 // vim:shiftwidth=2:expandtab

+ 7 - 7
pico/cd/cdc.c

@@ -367,7 +367,7 @@ void cdc_dma_update(void)
       {
         /* update IRQ level */
         elprintf(EL_INTS, "cdc DTE irq 5");
-        SekInterruptS68k(5);
+        pcd_irq_s68k(5, 1);
       }
     }
 
@@ -411,7 +411,7 @@ int cdc_decoder_update(uint8 header[4])
       {
         /* update IRQ level */
         elprintf(EL_INTS, "cdc DEC irq 5");
-        SekInterruptS68k(5);
+        pcd_irq_s68k(5, 1);
       }
     }
 
@@ -469,13 +469,13 @@ void cdc_reg_w(unsigned char data)
         {
           /* update IRQ level */
           elprintf(EL_INTS, "cdc pending irq 5");
-          SekInterruptS68k(5);
+          pcd_irq_s68k(5, 1);
         }
       }
       else // if (scd.pending & (1 << 5))
       {
         /* clear pending level 5 interrupts */
-        SekInterruptClearS68k(5);
+        pcd_irq_s68k(5, 0);
       }
 
       /* abort any data transfer if data output is disabled */
@@ -614,7 +614,7 @@ void cdc_reg_w(unsigned char data)
       if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
       {
         /* clear pending level 5 interrupt */
-        SekInterruptClearS68k(5);
+        pcd_irq_s68k(5, 0);
       }
 #endif
       Pico_mcd->s68k_regs[0x04+1] = 0x08;
@@ -774,7 +774,7 @@ unsigned char cdc_reg_r(void)
       if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
       {
         /* clear pending level 5 interrupt */
-        SekInterruptClearS68k(5);
+        pcd_irq_s68k(5, 0);
       }
 #endif
 
@@ -826,7 +826,7 @@ unsigned short cdc_host_r(void)
         {
           /* update IRQ level */
           elprintf(EL_INTS, "cdc DTE irq 5");
-          SekInterruptS68k(5);
+          pcd_irq_s68k(5, 1);
         }
       }
 

+ 3 - 0
pico/cd/cdd.c

@@ -444,6 +444,9 @@ int cdd_unload(void)
   {
     int i;
 
+    /* stop audio streaming */
+    Pico_mcd->cdda_stream = NULL;
+
     /* close CD tracks */
     if (cdd.toc.tracks[0].fd)
     {

+ 1 - 1
pico/cd/gfx.c

@@ -421,7 +421,7 @@ void gfx_update(unsigned int cycles)
 
     if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
       elprintf(EL_INTS|EL_CD, "s68k: gfx_cd irq 1");
-      SekInterruptS68k(1);
+      pcd_irq_s68k(1, 1);
     }
   }
   else {

+ 34 - 16
pico/cd/mcd.c

@@ -124,9 +124,6 @@ static void SekRunS68k(unsigned int to)
   if ((cyc_do = SekCycleAimS68k - SekCycleCntS68k) <= 0)
     return;
 
-  if (SekShouldInterrupt())
-    Pico_mcd->m.s68k_poll_a = 0;
-
   pprof_start(s68k);
   SekCycleCntS68k += cyc_do;
 #if defined(EMU_C68K)
@@ -177,7 +174,7 @@ static void pcd_cdc_event(unsigned int now)
 
     if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
       elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
-      SekInterruptS68k(4);
+      pcd_irq_s68k(4, 1);
     }
   }
 
@@ -188,7 +185,7 @@ static void pcd_int3_timer_event(unsigned int now)
 {
   if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN3) {
     elprintf(EL_INTS|EL_CD, "s68k: timer irq 3");
-    SekInterruptS68k(3);
+    pcd_irq_s68k(3, 1);
   }
 
   if (Pico_mcd->s68k_regs[0x31] != 0)
@@ -280,6 +277,16 @@ static void pcd_run_events(unsigned int until)
       oldest, event_time_next);
 }
 
+void pcd_irq_s68k(int irq, int state)
+{
+  if (state) {
+    SekInterruptS68k(irq);
+    SekSetStopS68k(0);
+    Pico_mcd->m.s68k_poll_a = 0;
+  } else
+    SekInterruptClearS68k(irq);
+}
+
 int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
 {
   #define now SekCycleCntS68k
@@ -307,7 +314,11 @@ int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
     if (event_time_next && CYCLES_GT(target, event_time_next))
       target = event_time_next;
 
-    SekRunS68k(target);
+    if (SekIsStoppedS68k())
+      SekCycleCntS68k = SekCycleAimS68k = target;
+    else
+      SekRunS68k(target);
+
     if (m68k_poll_sync && Pico_mcd->m.m68k_poll_cnt == 0)
       break;
   }
@@ -324,20 +335,27 @@ static void SekSyncM68k(void);
 void pcd_run_cpus_normal(int m68k_cycles)
 {
   Pico.t.m68c_aim += m68k_cycles;
-  if (SekShouldInterrupt() || Pico_mcd->m.m68k_poll_cnt < 12)
-    Pico_mcd->m.m68k_poll_cnt = 0;
-  else if (Pico_mcd->m.m68k_poll_cnt >= 16) {
-    int s68k_left = pcd_sync_s68k(Pico.t.m68c_aim, 1);
-    if (s68k_left <= 0) {
+
+  while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) {
+    if (SekShouldInterrupt())
+      Pico_mcd->m.m68k_poll_cnt = 0;
+
+#ifdef USE_POLL_DETECT
+    if (Pico_mcd->m.m68k_poll_cnt >= 16) {
+      // main CPU is polling, (wake and) run sub only
+      SekSetStopS68k(0);
+      pcd_sync_s68k(Pico.t.m68c_aim, 1);
+
+      Pico.t.m68c_cnt = Pico.t.m68c_aim;
+      if (SekIsStoppedS68k()) {
+        // slave has stopped, wake master to avoid lockups
+        Pico_mcd->m.m68k_poll_cnt = 0;
+      }
       elprintf(EL_CDPOLL, "m68k poll [%02x] x%d @%06x",
         Pico_mcd->m.m68k_poll_a, Pico_mcd->m.m68k_poll_cnt, SekPc);
-      Pico.t.m68c_cnt = Pico.t.m68c_aim;
-      return;
     }
-    Pico.t.m68c_cnt = Pico.t.m68c_aim - (s68k_left * mcd_s68k_cycle_mult >> 16);
-  }
+#endif
 
-  while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) {
     SekRunM68kOnce();
     if (Pico_mcd->m.need_sync) {
       Pico_mcd->m.need_sync = 0;

+ 8 - 8
pico/cd/memory.c

@@ -150,7 +150,7 @@ void m68k_reg_write8(u32 a, u32 d)
       if (d && (Pico_mcd->s68k_regs[0x33] & PCDS_IEN2)) {
         elprintf(EL_INTS, "m68k: s68k irq 2");
         pcd_sync_s68k(SekCyclesDone(), 0);
-        SekInterruptS68k(2);
+        pcd_irq_s68k(2, 1);
       }
       return;
     case 1:
@@ -205,10 +205,10 @@ void m68k_reg_write8(u32 a, u32 d)
 
       goto write_comm;
     case 6:
-      Pico_mcd->bios[0x72 + 1] = d; // simple hint vector changer
+      Pico_mcd->bios[MEM_BE2(0x72)] = d; // simple hint vector changer
       return;
     case 7:
-      Pico_mcd->bios[0x72] = d;
+      Pico_mcd->bios[MEM_BE2(0x73)] = d;
       elprintf(EL_CDREGS, "hint vector set to %04x%04x",
         ((u16 *)Pico_mcd->bios)[0x70/2], ((u16 *)Pico_mcd->bios)[0x72/2]);
       return;
@@ -277,7 +277,7 @@ u32 s68k_poll_detect(u32 a, u32 d)
 
 #define READ_FONT_DATA(basemask) \
 { \
-      unsigned int fnt = *(unsigned int *)(Pico_mcd->s68k_regs + 0x4c); \
+      unsigned int fnt = CPU_LE4(*(u32 *)(Pico_mcd->s68k_regs + 0x4c)); \
       unsigned int col0 = (fnt >> 8) & 0x0f, col1 = (fnt >> 12) & 0x0f;   \
       if (fnt & (basemask << 0)) d  = col1      ; else d  = col0;       \
       if (fnt & (basemask << 1)) d |= col1 <<  4; else d |= col0 <<  4; \
@@ -331,7 +331,7 @@ u32 s68k_reg_read16(u32 a)
 
   d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];
 
-  if (a >= 0x0e && a < 0x30)
+  if (a >= 0x0e && a < 0x20)
     return s68k_poll_detect(a, d);
 
   return d;
@@ -425,7 +425,7 @@ void s68k_reg_write8(u32 a, u32 d)
         // XXX: emulate pending irq instead?
         if (Pico_mcd->s68k_regs[0x37] & 4) {
           elprintf(EL_INTS, "cdd export irq 4 (unmask)");
-          SekInterruptS68k(4);
+          pcd_irq_s68k(4, 1);
         }
       }
       break;
@@ -443,7 +443,7 @@ void s68k_reg_write8(u32 a, u32 d)
 
         if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
           elprintf(EL_INTS, "cdd export irq 4");
-          SekInterruptS68k(4);
+          pcd_irq_s68k(4, 1);
         }
       }
       return;
@@ -1094,7 +1094,7 @@ void pcd_state_loaded_mem(void)
   Pico_mcd->m.dmna_ret_2m &= 3;
 
   // restore hint vector
-  *(unsigned short *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;
+  *(u16 *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;
 }
 
 #ifdef EMU_M68K

+ 3 - 3
pico/cd/pcm.c

@@ -88,7 +88,7 @@ void pcd_pcm_sync(unsigned int to)
     }
 
     addr = ch->addr;
-    inc = *(unsigned short *)&ch->regs[2];
+    inc = ch->regs[2] + (ch->regs[3]<<8);
     mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1); 
     mul_r = ((int)ch->regs[0] * (ch->regs[1] >>  4)) >> (5+1);
 
@@ -99,7 +99,7 @@ void pcd_pcm_sync(unsigned int to)
       // test for loop signal
       if (smp == 0xff)
       {
-        addr = *(unsigned short *)&ch->regs[4]; // loop_addr
+        addr = ch->regs[4] + (ch->regs[5]<<8); // loop_addr
         smp = Pico_mcd->pcm_ram[addr];
         addr <<= PCM_STEP_SHIFT;
         if (smp == 0xff)
@@ -120,7 +120,7 @@ end:
   Pico_mcd->pcm_mixpos += steps;
 }
 
-void pcd_pcm_update(int *buf32, int length, int stereo)
+void pcd_pcm_update(s32 *buf32, int length, int stereo)
 {
   int step, *pcm;
   int p = 0;

+ 2 - 2
pico/m68kif_cyclone.s

@@ -81,9 +81,9 @@ cyclone_fetch32:
     ldr     r1, [r1, r2, lsl #2]
     bic     r0, r0, #1
     movs    r1, r1, lsl #1
-    ldrcch  r0, [r1, r0]!
+    ldrcch  r2, [r1, r0]!
     ldrcch  r1, [r1, #2]
-    orrcc   r0, r1, r0, lsl #16
+    orrcc   r0, r1, r2, lsl #16
     bxcc    lr
 
     stmfd   sp!,{r0,r1,r2,lr}

+ 5 - 5
pico/patch.c

@@ -446,11 +446,11 @@ void PicoPatchPrepare(void)
       addr=PicoPatches[i].addr;
       addr &= ~1;
       if (addr < Pico.romsize)
-         PicoPatches[i].data_old = *(unsigned short *)(Pico.rom + addr);
+         PicoPatches[i].data_old = *(u16 *)(Pico.rom + addr);
       else
       {
          if(!(PicoIn.AHW & PAHW_SMS))
-            PicoPatches[i].data_old = (unsigned short) m68k_read16(addr);
+            PicoPatches[i].data_old = (u16) m68k_read16(addr);
          else
             ;// wrong: PicoPatches[i].data_old = (unsigned char) PicoRead8_z80(addr);
       }
@@ -473,7 +473,7 @@ void PicoPatchApply(void)
          if (PicoPatches[i].active)
          {
             if (!(PicoIn.AHW & PAHW_SMS))
-               *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data;
+               *(u16 *)(Pico.rom + addr) = PicoPatches[i].data;
             else if (!PicoPatches[i].comp || PicoPatches[i].comp == *(char *)(Pico.rom + addr))
                *(char *)(Pico.rom + addr) = (char) PicoPatches[i].data;
          }
@@ -485,13 +485,13 @@ void PicoPatchApply(void)
             if (u == i)
             {
                if (!(PicoIn.AHW & PAHW_SMS))
-                  *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data_old;
+                  *(u16 *)(Pico.rom + addr) = PicoPatches[i].data_old;
                else
                   *(char *)(Pico.rom + addr) = (char) PicoPatches[i].data_old;
             }
          }
       // fprintf(stderr, "patched %i: %06x:%04x\n", PicoPatches[i].active, addr,
-      // *(unsigned short *)(Pico.rom + addr));
+      // *(u16 *)(Pico.rom + addr));
       }
       else
       {

+ 2 - 1
pico/pico_cmn.c

@@ -67,7 +67,8 @@ static void do_hint(struct PicoVideo *pv)
   pv->pending_ints |= 0x10;
   if (pv->reg[0] & 0x10) {
     elprintf(EL_INTS, "hint: @ %06x [%u]", SekPc, SekCyclesDone());
-    SekInterrupt(4);
+    if (SekIrqLevel < 4)
+      SekInterrupt(4);
   }
 }
 

+ 2 - 1
pico/pico_int.h

@@ -773,6 +773,7 @@ void pcd_event_schedule(unsigned int now, enum pcd_event event, int after);
 void pcd_event_schedule_s68k(enum pcd_event event, int after);
 void pcd_prepare_frame(void);
 unsigned int pcd_cycles_m68k_to_s68k(unsigned int c);
+void pcd_irq_s68k(int irq, int state);
 int  pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync);
 void pcd_run_cpus(int m68k_cycles);
 void pcd_soft_reset(void);
@@ -780,7 +781,7 @@ void pcd_state_loaded(void);
 
 // cd/pcm.c
 void pcd_pcm_sync(unsigned int to);
-void pcd_pcm_update(int *buffer, int length, int stereo);
+void pcd_pcm_update(s32 *buffer, int length, int stereo);
 void pcd_pcm_write(unsigned int a, unsigned int d);
 unsigned int pcd_pcm_read(unsigned int a);
 

+ 2 - 2
pico/pico_port.h

@@ -57,7 +57,7 @@
 #define MEM_LE2(a)	(a)
 #define MEM_LE4(a)	(a)
 // swapping
-#define CPU_BE2(v)	((u32)((u64)(v)<<16)|((v)>>16))
+#define CPU_BE2(v)	((u32)((u64)(v)<<16)|((u32)(v)>>16))
 #define CPU_BE4(v)	(((u32)(v)>>24)|(((v)>>8)&0x00ff00)| \
 			(((v)<<8)&0xff0000)|(u32)((v)<<24))
 #define CPU_LE2(v)	(v)		// swap of 2*u16 in u32
@@ -71,7 +71,7 @@
 // swapping
 #define CPU_BE2(v)	(v)
 #define CPU_BE4(v)	(v)
-#define CPU_LE2(v)	((u32)((u64)(v)<<16)|((v)>>16))
+#define CPU_LE2(v)	((u32)((u64)(v)<<16)|((u32)(v)>>16))
 #define CPU_LE4(v)	(((u32)(v)>>24)|(((v)>>8)&0x00ff00)| \
 			(((v)<<8)&0xff0000)|(u32)((v)<<24))
 #endif

+ 20 - 20
pico/sek.c

@@ -192,14 +192,14 @@ PICO_INTERNAL void SekSetRealTAS(int use_real)
 // XXX: rename
 PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub)
 {
-  unsigned int pc=0;
+  u32 pc=0;
 
 #if defined(EMU_C68K)
   struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
   memcpy(cpu,context->d,0x40);
   pc=context->pc-context->membase;
-  *(unsigned int *)(cpu+0x44)=CycloneGetSr(context);
-  *(unsigned int *)(cpu+0x48)=context->osp;
+  *(u32 *)(cpu+0x44)=CycloneGetSr(context);
+  *(u32 *)(cpu+0x48)=context->osp;
   cpu[0x4c] = context->irq;
   cpu[0x4d] = context->state_flags & 1;
 #elif defined(EMU_M68K)
@@ -207,8 +207,8 @@ PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub)
   m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
   memcpy(cpu,m68ki_cpu_p->dar,0x40);
   pc=m68ki_cpu_p->pc;
-  *(unsigned int  *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
-  *(unsigned int  *)(cpu+0x48)=m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET];
+  *(u32  *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
+  *(u32  *)(cpu+0x48)=m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET];
   cpu[0x4c] = CPU_INT_LEVEL>>8;
   cpu[0x4d] = CPU_STOPPED;
   m68k_set_context(oldcontext);
@@ -216,14 +216,14 @@ PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub)
   M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
   memcpy(cpu,context->dreg,0x40);
   pc=context->pc;
-  *(unsigned int  *)(cpu+0x44)=context->sr;
-  *(unsigned int  *)(cpu+0x48)=context->asp;
+  *(u32  *)(cpu+0x44)=context->sr;
+  *(u32  *)(cpu+0x48)=context->asp;
   cpu[0x4c] = context->interrupts[0];
   cpu[0x4d] = (context->execinfo & FM68K_HALTED) ? 1 : 0;
 #endif
 
-  *(unsigned int *)(cpu+0x40) = pc;
-  *(unsigned int *)(cpu+0x50) =
+  *(u32 *)(cpu+0x40) = pc;
+  *(u32 *)(cpu+0x50) =
     is_sub ? SekCycleCntS68k : Pico.t.m68c_cnt;
 }
 
@@ -231,11 +231,11 @@ PICO_INTERNAL void SekUnpackCpu(const unsigned char *cpu, int is_sub)
 {
 #if defined(EMU_C68K)
   struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
-  CycloneSetSr(context, *(unsigned int *)(cpu+0x44));
-  context->osp=*(unsigned int *)(cpu+0x48);
+  CycloneSetSr(context, *(u32 *)(cpu+0x44));
+  context->osp=*(u32 *)(cpu+0x48);
   memcpy(context->d,cpu,0x40);
   context->membase = 0;
-  context->pc = *(unsigned int *)(cpu+0x40);
+  context->pc = *(u32 *)(cpu+0x40);
   CycloneUnpack(context, NULL); // rebase PC
   context->irq = cpu[0x4c];
   context->state_flags = 0;
@@ -244,27 +244,27 @@ PICO_INTERNAL void SekUnpackCpu(const unsigned char *cpu, int is_sub)
 #elif defined(EMU_M68K)
   void *oldcontext = m68ki_cpu_p;
   m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
-  m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44));
+  m68k_set_reg(M68K_REG_SR, *(u32 *)(cpu+0x44));
   memcpy(m68ki_cpu_p->dar,cpu,0x40);
-  m68ki_cpu_p->pc=*(unsigned int *)(cpu+0x40);
-  m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET]=*(unsigned int *)(cpu+0x48);
+  m68ki_cpu_p->pc=*(u32 *)(cpu+0x40);
+  m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET]=*(u32 *)(cpu+0x48);
   CPU_INT_LEVEL = cpu[0x4c] << 8;
   CPU_STOPPED = cpu[0x4d];
   m68k_set_context(oldcontext);
 #elif defined(EMU_F68K)
   M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
   memcpy(context->dreg,cpu,0x40);
-  context->pc =*(unsigned int *)(cpu+0x40);
-  context->sr =*(unsigned int *)(cpu+0x44);
-  context->asp=*(unsigned int *)(cpu+0x48);
+  context->pc =*(u32 *)(cpu+0x40);
+  context->sr =*(u32 *)(cpu+0x44);
+  context->asp=*(u32 *)(cpu+0x48);
   context->interrupts[0] = cpu[0x4c];
   context->execinfo &= ~FM68K_HALTED;
   if (cpu[0x4d]&1) context->execinfo |= FM68K_HALTED;
 #endif
   if (is_sub)
-    SekCycleCntS68k = *(unsigned int *)(cpu+0x50);
+    SekCycleCntS68k = *(u32 *)(cpu+0x50);
   else
-    Pico.t.m68c_cnt = *(unsigned int *)(cpu+0x50);
+    Pico.t.m68c_cnt = *(u32 *)(cpu+0x50);
 }
 
 

+ 3 - 3
pico/sound/sound.c

@@ -17,10 +17,10 @@
 void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_stereo;
 
 // master int buffer to mix to
-static int PsndBuffer[2*(44100+100)/50];
+static s32 PsndBuffer[2*(44100+100)/50];
 
 // cdda output buffer
-short cdda_out_buffer[2*1152];
+s16 cdda_out_buffer[2*1152];
 
 // sn76496
 extern int *sn76496_regs;
@@ -236,7 +236,7 @@ PICO_INTERNAL void PsndDoFM(int cyc_to)
   // Q16, number of samples since last call
   len = (cyc_to * Pico.snd.clkl_mult) - Pico.snd.fm_pos;
 
-  // don't do this too often (about once every canline)
+  // don't do this too often (about once every scanline)
   if (len >> 16 <= PicoIn.sndRate >> 10)
     return;
 

+ 1 - 1
platform/common/config_file.c

@@ -280,7 +280,7 @@ static int custom_read(menu_entry *me, const char *var, const char *val)
 			return 1;
 
 		case MA_OPT_SOUND_ALPHA:
-			if (strcasecmp(var, "Filter strength (alpha)") != 0) return 0;
+			if (strcasecmp(var, "Filter strength") != 0) return 0;
 			PicoIn.sndFilterAlpha = 0x10000 * atof(val);
 			return 1;
 

+ 1 - 0
platform/common/dr_libs

@@ -0,0 +1 @@
+Subproject commit 343aa923439e59e7a9f7726f70edc77a4500bdec

+ 27 - 2
platform/common/host_dasm.c

@@ -7,10 +7,10 @@
 #include <stdint.h>
 #include <string.h>
 
-#ifdef __mips__
+#if defined __mips__
 #include "dismips.c"
 #define disasm dismips
-#else
+#elif defined __arm__
 #include "disarm.c"
 #define disasm disarm
 #endif
@@ -36,6 +36,7 @@ static const char *lookup_name(void *addr)
   return NULL;
 }
 
+#ifdef disasm
 void host_dasm(void *addr, int len)
 {
   void *end = (char *)addr + len;
@@ -65,6 +66,30 @@ void host_dasm(void *addr, int len)
     addr = (char *)addr + sizeof(long);
   }
 }
+#else
+void host_dasm(void *addr, int len)
+{
+  uint8_t *end = (uint8_t *)addr + len;
+  char buf[64];
+  uint8_t *p = addr;
+  int i = 0, o = 0;
+
+  o = snprintf(buf, sizeof(buf), "%p:	", p);
+  while (p < end) {
+    o += snprintf(buf+o, sizeof(buf)-o, "%02x ", *p++);
+    if (++i >= 16) {
+      buf[o] = '\0';
+      printf("%s\n", buf);
+      o = snprintf(buf, sizeof(buf), "%p:	", p);
+      i = 0;
+    }
+  }
+  if (i) {
+    buf[o] = '\0';
+    printf("%s\n", buf);
+  }
+}
+#endif
 
 void host_dasm_new_symbol_(void *addr, const char *name)
 {

+ 1 - 2
platform/common/menu_pico.c

@@ -84,8 +84,7 @@ static const char *men_dummy[] = { NULL };
 #elif defined(PANDORA)
 #include <platform/pandora/menu.c>
 #else
-#define MENU_OPTIONS_GFX
-#define MENU_OPTIONS_ADV
+#include <platform/linux/menu.c>
 #endif
 
 

+ 65 - 0
platform/common/mp3_drmp3.c

@@ -0,0 +1,65 @@
+/*
+ * MP3 decoding using dr_mp3
+ * (C) kub, 2020
+ *
+ * This work is licensed under the terms of MAME license.
+ * See COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+
+#include <pico/pico_int.h>
+#define DR_MP3_IMPLEMENTATION
+#include "dr_libs/dr_mp3.h"
+#include "mp3.h"
+
+static drmp3dec mp3dec;
+static unsigned char mp3_input_buffer[2 * 1024];
+
+int mp3dec_start(FILE *f, int fpos_start)
+{
+	drmp3dec_init(&mp3dec);
+	return 0;
+}
+
+int mp3dec_decode(FILE *f, int *file_pos, int file_len)
+{
+	drmp3dec_frame_info info;
+	unsigned char *readPtr;
+	int bytesLeft;
+	int offset; // mp3 frame offset from readPtr
+	int len;
+	int retry = 3;
+
+	do
+	{
+		if (*file_pos >= file_len)
+			return 1; /* EOF, nothing to do */
+
+		fseek(f, *file_pos, SEEK_SET);
+		bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f);
+
+		offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft);
+		if (offset < 0) {
+			lprintf("find_sync_word (%i/%i) err %i\n",
+				*file_pos, file_len, offset);
+			*file_pos = file_len;
+			return 1; // EOF
+		}
+		*file_pos += offset;
+		readPtr = mp3_input_buffer + offset;
+		bytesLeft -= offset;
+
+		len = drmp3dec_decode_frame(&mp3dec, readPtr, bytesLeft, cdda_out_buffer, &info);
+		if (len > 0)			// retrieved decoded data
+			*file_pos += info.frame_bytes;
+		else if (info.frame_bytes > 0)	// no output but input consumed?
+			*file_pos += 1;			// try to skip frame
+		else if (offset == 0)		// bad frame?
+			*file_pos += 1;			// try resyncing
+		// else				// truncated frame, try more data
+	}
+	while (len <= 0 && --retry > 0);
+
+	return len <= 0;
+}

+ 1 - 1
platform/common/plat_sdl.c

@@ -1726,7 +1726,7 @@ void plat_video_loop_prepare(void)
 	// take over any new vout settings XXX ask plat_sdl for scaling instead!
 	plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 0);
 	// switch over to scaled output if available
-	if (plat_sdl_overlay != NULL || plat_sdl_gl_active) {
+	if (plat_sdl_overlay != NULL || plat_sdl_gl_active || currentConfig.scaling != EOPT_SCALE_NONE) {
 		g_screen_width = 320;
 		g_screen_height = 240;
 		g_screen_ppitch = g_screen_width;

+ 21 - 5
platform/libretro/libretro.c

@@ -353,7 +353,7 @@ static void munmap(void *addr, size_t length)
 
 void* mmap(void *desired_addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off)
 {
-   return malloc(len);
+   return calloc(1, len);
 }
 
 void munmap(void *base_addr, size_t len)
@@ -706,6 +706,8 @@ void lprintf(const char *fmt, ...)
 }
 
 /* libretro */
+bool libretro_supports_bitmasks = false;
+
 void retro_set_environment(retro_environment_t cb)
 {
 #ifdef USE_LIBRETRO_VFS
@@ -1638,6 +1640,7 @@ void retro_run(void)
    bool updated = false;
    int pad, i;
    static void *buff;
+   int16_t input;
 
    PicoIn.skipFrame = 0;
 
@@ -1647,10 +1650,18 @@ void retro_run(void)
    input_poll_cb();
 
    PicoIn.pad[0] = PicoIn.pad[1] = 0;
-   for (pad = 0; pad < 2; pad++)
-      for (i = 0; i < RETRO_PICO_MAP_LEN; i++)
-         if (input_state_cb(pad, RETRO_DEVICE_JOYPAD, 0, i))
-            PicoIn.pad[pad] |= retro_pico_map[i];
+   for (pad = 0; pad < 2; pad++) {
+      if (libretro_supports_bitmasks) {
+         input = input_state_cb(pad, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
+         for (i = 0; i < RETRO_PICO_MAP_LEN; i++)
+            if (input & (1 << i))
+               PicoIn.pad[pad] |= retro_pico_map[i];
+      } else {
+         for (i = 0; i < RETRO_PICO_MAP_LEN; i++)
+            if (input_state_cb(pad, RETRO_DEVICE_JOYPAD, 0, i))
+               PicoIn.pad[pad] |= retro_pico_map[i];
+      }
+   }
 
    if (PicoPatches)
       PicoPatchApply();
@@ -1785,6 +1796,9 @@ void retro_init(void)
 
    environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control);
 
+   if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
+      libretro_supports_bitmasks = true;
+
 #ifdef _3DS
    ctr_svchack_successful = ctr_svchack_init();
    check_rosalina();
@@ -1853,4 +1867,6 @@ void retro_deinit(void)
 #endif
    vout_buf = NULL;
    PicoExit();
+
+   libretro_supports_bitmasks = false;
 }

+ 1 - 1
platform/linux/emu.c

@@ -32,7 +32,7 @@ void pemu_prep_defconfig(void)
 
 void pemu_validate_config(void)
 {
-#if !defined(__arm__) && !defined(__aarch64__) && !defined(__mips__) && !defined(__riscv__) &&  !defined(__riscv) && !defined(__powerpc__) && !defined(__i386__) && !defined(__x86_64__)
+#if !defined(__arm__) && !defined(__aarch64__) && !defined(__mips__) && !defined(__riscv__) &&  !defined(__riscv) && !defined(__powerpc__) && !defined(__ppc__) && !defined(__i386__) && !defined(__x86_64__)
 	PicoIn.opt &= ~POPT_EN_DRC;
 #endif
 }

+ 16 - 0
platform/linux/menu.c

@@ -0,0 +1,16 @@
+#include "../libpicofe/gp2x/plat_gp2x.h"
+
+// ------------ gfx options menu ------------
+
+
+const char *men_scaling_opts[] = { "OFF", "ON", NULL };
+
+#define MENU_OPTIONS_GFX \
+	// mee_enum      ("screen scaling",           MA_OPT_SCALING,        currentConfig.scaling, men_scaling_opts), \
+
+#define MENU_OPTIONS_ADV
+
+void linux_menu_init(void)
+{
+}
+

+ 1 - 1
platform/opendingux/data/default.gcw0.desktop

@@ -6,4 +6,4 @@ Exec=PicoDrive %f
 Icon=megadrive
 Terminal=false
 Categories=emulators;
-MimeType=.md;.smd;.bin;.sms;.cue;.32x;.zip;.7z
+MimeType=.md;.smd;.bin;.sms;.cue;.chd;.32x;.zip;.7z

+ 2 - 2
platform/opendingux/data/default.retrofw.desktop

@@ -3,10 +3,10 @@ Name=Picodrive
 Comment=A megadrive/genesis emulator
 Exec=PicoDrive %f
 Icon=megadrive
-Categories=games;
+Categories=emulators;
 X-OD-Manual=
 X-OD-Selector=
-X-OD-Filter=.md,.smd,.bin,.sms,.cue,.32x,.zip,.7z
+X-OD-Filter=.md,.smd,.bin,.sms,.cue,.chd,.32x,.zip,.7z
 Terminal=true
 Type=Application
 StartupNotify=true

+ 7 - 7
tools/release.sh

@@ -15,7 +15,7 @@
 #	rg350:		rg350-toolchain (+ mips-toolchain for newer gcc)
 #	psp:		pspdev
 
-mkdir -p release
+mkdir -p release-$1
 trap "exit" ERR
 
 # GPH devices: gp2x, wiz, caanoo, with ubuntu arm gcc 4.7
@@ -23,18 +23,18 @@ trap "exit" ERR
 TC=$HOME/opt/open2x/gcc-4.1.1-glibc-2.3.6 CROSS_COMPILE=arm-linux-gnueabi- CFLAGS="-I$TC/arm-open2x-linux/include -I$HOME/src/gp2x/armroot/include -U_FORTIFY_SOURCE" LDFLAGS="-B$TC/lib/gcc/arm-open2x-linux/4.1.1 -B$TC/arm-open2x-linux/lib -L$TC/arm-open2x-linux/lib -L$HOME/src/gp2x/armroot/lib" ./configure --platform=gp2x
 make clean all
 make -C platform/gp2x rel VER=$1
-mv PicoDrive_$1.zip release/PicoDrive-gph_$1.zip
+mv PicoDrive_$1.zip release-$1/PicoDrive-gph_$1.zip
 
 # dingux: dingoo a320, ritmix rzx-50, JZ4755 or older (mips32r1 w/o fpu)
 # NB works for legacy dingux and possibly opendingux before gcw0
 TC=$HOME/opt/opendingux-toolchain PATH=$TC/usr/bin:$PATH CROSS_COMPILE=mipsel-linux- CFLAGS="-I $TC/usr/include -I $TC/usr/include/SDL -Wno-unused-result -mabicalls" LDFLAGS="--sysroot $TC" ./configure --platform=dingux
 TC=$HOME/opt/opendingux-toolchain PATH=$TC/usr/bin:$PATH make clean all
-mv PicoDrive-dge.zip release/PicoDrive-dge_$1.zip
+mv PicoDrive-dge.zip release-$1/PicoDrive-dge_$1.zip
 
 # retrofw: rs-97 and similar, JZ4760 (mips32r1 with fpu)
 TC=$HOME/opt/mipsel-linux-uclibc PATH=$TC/bin:$PATH CROSS_COMPILE=mipsel-linux- CFLAGS="-I $TC/include -I $TC/include/SDL -Wno-unused-result" LDFLAGS="--sysroot $TC/mipsel-buildroot-linux-uclibc/sysroot" ./configure --platform=retrofw
 TC=$HOME/opt/mipsel-linux-uclibc PATH=$TC/bin:$PATH make clean all
-mv PicoDrive.opk release/PicoDrive-retrofw_$1.opk
+mv PicoDrive.opk release-$1/PicoDrive-retrofw_$1.opk
 
 # gcw0: JZ4770 (mips32r2 with fpu), swapped X/Y buttons, SDK toolchain
 #TC=$HOME/opt/gcw0-toolchain PATH=$TC/usr/bin:$PATH CROSS_COMPILE=mipsel-linux- TS=$TC/usr/mipsel-gcw0-linux-uclibc/sysroot CFLAGS="-I$TS/usr/include -I$TS/usr/include/SDL" LDFLAGS="--sysroot $TS" ./configure --platform=gcw0
@@ -43,7 +43,7 @@ mv PicoDrive.opk release/PicoDrive-retrofw_$1.opk
 # gcw0: JZ4770 (mips32r2 with fpu), swapped X/Y buttons, newer generic gcc
 TC=$HOME/opt/gcw0-toolchain PATH=$HOME/opt/mips-toolchain/bin:$PATH CROSS_COMPILE=mipsel-linux- TS=$TC/usr/mipsel-gcw0-linux-uclibc/sysroot CFLAGS="-I$TS/usr/include -I$TS/usr/include/SDL -mabicalls" LDFLAGS="--sysroot $TS -Wl,--dynamic-linker=/lib/ld-uClibc.so.0" ./configure --platform=gcw0
 PATH=$HOME/opt/mips-toolchain/usr/bin:$PATH make clean all
-mv PicoDrive.opk release/PicoDrive-gcw0_$1.opk
+mv PicoDrive.opk release-$1/PicoDrive-gcw0_$1.opk
 
 # rg350: JZ4770, SDK toolchain
 #TC=$HOME/opt/rg350-toolchain PATH=$TC/usr/bin:$PATH CROSS_COMPILE=mipsel-linux- TS=$TC/usr/mipsel-gcw0-linux-uclibc/sysroot CFLAGS="-I$TS/usr/include -I$TS/usr/include/SDL" LDFLAGS="--sysroot $TS" ./configure --platform=rg350
@@ -53,10 +53,10 @@ mv PicoDrive.opk release/PicoDrive-gcw0_$1.opk
 # NB this may or may not work on the newer opendingux beta
 TC=$HOME/opt/rg350-toolchain PATH=$HOME/opt/mips-toolchain/bin:$PATH CROSS_COMPILE=mipsel-linux- TS=$TC/usr/mipsel-gcw0-linux-uclibc/sysroot CFLAGS="-I$TS/usr/include -I$TS/usr/include/SDL -mabicalls" LDFLAGS="--sysroot $TS -Wl,--dynamic-linker=/lib/ld-uClibc.so.0" ./configure --platform=opendingux
 PATH=$HOME/opt/mips-toolchain/usr/bin:$PATH make clean all
-mv PicoDrive.opk release/PicoDrive-opendingux_$1.opk
+mv PicoDrive.opk release-$1/PicoDrive-opendingux_$1.opk
 
 # psp (experimental), pspdev SDK toolchain
 TC=$HOME/opt/pspdev PATH=$TC/bin:$PATH CROSS_COMPILE=psp- CFLAGS="-I$TC/psp/sdk/include -D_POSIX_C_SOURCE=199506L" LDFLAGS="-L$TC/psp/sdk/lib" ./configure --platform=psp
 TC=$HOME/opt/pspdev PATH=$TC/bin:$PATH make clean all
 make -C platform/psp rel VER=$1
-mv PicoDrive_psp_$1.zip release/PicoDrive-psp_$1.zip
+mv PicoDrive_psp_$1.zip release-$1/PicoDrive-psp_$1.zip