Browse Source

idle loop detection (Cyclone only, with debug stuff)

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@502 be3aeb3a-fb24-0410-a615-afba39da0efa
notaz 16 years ago
parent
commit
053fd9b42f

+ 1 - 0
Pico/Cart.c

@@ -548,6 +548,7 @@ int PicoCartInsert(unsigned char *rom,unsigned int romsize)
 int PicoCartUnload(void)
 {
   if (Pico.rom != NULL) {
+    SekFinishIdleDet();
     free(Pico.rom);
     Pico.rom=NULL;
   }

+ 24 - 9
Pico/Pico.c

@@ -58,6 +58,8 @@ void PicoPower(void)
 {
   unsigned char sram_reg=Pico.m.sram_reg; // must be preserved
 
+  Pico.m.frame_count = 0;
+
   // clear all memory of the emulated machine
   memset(&Pico.ram,0,(unsigned int)&Pico.rom-(unsigned int)&Pico.ram);
 
@@ -172,6 +174,12 @@ int PicoReset(void)
     PicoResetMCD();
     return 0;
   }
+  else {
+    // reinit, so that checksum checks pass
+    SekFinishIdleDet();
+    if (!(PicoOpt & POPT_DIS_IDLE_DET))
+      SekInitIdleDet();
+  }
 
   // reset sram state; enable sram access by default if it doesn't overlap with ROM
   Pico.m.sram_reg=sram_reg&0x14;
@@ -188,17 +196,17 @@ int PicoReset(void)
 // same for Outrunners (92-121, when active is set to 24)
 // 96 is VR hack
 static const int dma_timings[] = {
-96,  167, 166,  83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy
-102, 205, 204, 102, // vblank: 40cell:
-16,   16,  15,   8, // active: 32cell:
-24,   18,  17,   9  // ...
+  96,  167, 166,  83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy
+  102, 205, 204, 102, // vblank: 40cell:
+  16,   16,  15,   8, // active: 32cell:
+  24,   18,  17,   9  // ...
 };
 
 static const int dma_bsycles[] = {
-(488<<8)/96,  (488<<8)/167, (488<<8)/166, (488<<8)/83,
-(488<<8)/102, (488<<8)/205, (488<<8)/204, (488<<8)/102,
-(488<<8)/16,  (488<<8)/16,  (488<<8)/15,  (488<<8)/8,
-(488<<8)/24,  (488<<8)/18,  (488<<8)/17,  (488<<8)/9
+  (488<<8)/96,  (488<<8)/167, (488<<8)/166, (488<<8)/83,
+  (488<<8)/102, (488<<8)/205, (488<<8)/204, (488<<8)/102,
+  (488<<8)/16,  (488<<8)/16,  (488<<8)/15,  (488<<8)/8,
+  (488<<8)/24,  (488<<8)/18,  (488<<8)/17,  (488<<8)/9
 };
 
 PICO_INTERNAL int CheckDMA(void)
@@ -232,7 +240,7 @@ static __inline void SekRunM68k(int cyc)
 {
   int cyc_do;
   SekCycleAim+=cyc;
-  if((cyc_do=SekCycleAim-SekCycleCnt) <= 0) return;
+  if ((cyc_do=SekCycleAim-SekCycleCnt) <= 0) return;
 #if defined(EMU_CORE_DEBUG)
   // this means we do run-compare
   SekCycleCnt+=CM_compareRun(cyc_do, 0);
@@ -498,10 +506,17 @@ static int PicoFrameSimple(void)
   return 0;
 }
 
+int idle_hit_counter = 0;
+
 int PicoFrame(void)
 {
   int acc;
 
+  if ((Pico.m.frame_count&0x3f) == 0) {
+    elprintf(EL_STATUS, "ihits: %i", idle_hit_counter);
+    idle_hit_counter = 0;
+  }
+
   Pico.m.frame_count++;
 
   if (PicoAHW & PAHW_MCD) {

+ 1 - 0
Pico/Pico.h

@@ -47,6 +47,7 @@ void mp3_update(int *buffer, int length, int stereo);
 #define POPT_DIS_VDP_FIFO   (1<<16) // 0x 0000
 #define POPT_EN_SVP_DRC     (1<<17)
 #define POPT_DIS_SPRITE_LIM (1<<18)
+#define POPT_DIS_IDLE_DET   (1<<19)
 extern int PicoOpt; // bitfield
 #define PAHW_MCD  (1<<0)
 #define PAHW_32X  (1<<1)

+ 5 - 2
Pico/PicoInt.h

@@ -259,9 +259,9 @@ struct PicoMisc
   unsigned char  eeprom_cycle; // EEPROM SRAM cycle number
   unsigned char  eeprom_slave; // EEPROM slave word for X24C02 and better SRAMs
   unsigned char prot_bytes[2]; // simple protection faking
-  unsigned short dma_xfers;
+  unsigned short dma_xfers;    // 18
   unsigned char pad[2];
-  unsigned int  frame_count; // mainly for movies
+  unsigned int  frame_count;   // 1c for movies and idle det
 };
 
 // some assembly stuff depend on these, do not touch!
@@ -461,6 +461,8 @@ PICO_INTERNAL int SekInit(void);
 PICO_INTERNAL int SekReset(void);
 PICO_INTERNAL void SekState(int *data);
 PICO_INTERNAL void SekSetRealTAS(int use_real);
+void SekInitIdleDet(void);
+void SekFinishIdleDet(void);
 
 // cd/Sek.c
 PICO_INTERNAL int SekInitS68k(void);
@@ -557,6 +559,7 @@ extern int PsndDacLine;
 #define EL_CDPOLL  0x00002000 /* MCD: log poll detection */
 #define EL_SVP     0x00004000 /* SVP stuff */
 #define EL_PICOHW  0x00008000 /* Pico stuff */
+#define EL_IDLE    0x00010000 /* idle loop det. */
 
 #define EL_STATUS  0x40000000 /* status messages */
 #define EL_ANOMALY 0x80000000 /* some unexpected conditions (during emulation) */

+ 125 - 0
Pico/Sek.c

@@ -193,6 +193,131 @@ PICO_INTERNAL void SekSetRealTAS(int use_real)
 #endif
 }
 
+/* idle loop detection, not to be used in CD mode */
+#ifdef EMU_C68K
+#include "cpu/Cyclone/tools/idle.h"
+#endif
+
+static int *idledet_addrs = NULL;
+static int idledet_count = 0, idledet_bads = 0;
+int idledet_start_frame = 0;
+
+static int jump_verify[0x10000];
+extern int CycloneJumpTab[];
+static unsigned char *rom_verify = NULL;
+
+void SekInitIdleDet(void)
+{
+  void *tmp = realloc(idledet_addrs, 0x200*4);
+  if (tmp == NULL) {
+    free(idledet_addrs);
+    idledet_addrs = NULL;
+  }
+  else
+    idledet_addrs = tmp;
+  idledet_count = idledet_bads = 0;
+  idledet_start_frame = Pico.m.frame_count + 360;
+
+  memcpy(jump_verify, CycloneJumpTab, 0x10000*4);
+  rom_verify = realloc(rom_verify, Pico.romsize);
+  memcpy(rom_verify, Pico.rom, Pico.romsize);
+#ifdef EMU_C68K
+  CycloneInitIdle();
+#endif
+}
+
+int SekIsIdleCode(unsigned short *dst, int bytes)
+{
+  printf("SekIsIdleCode %04x %i\n", *dst, bytes);
+  switch (bytes)
+  {
+    case 4:
+      if (  (*dst & 0xfff8) == 0x4a10 || // tst.b ($aX)      // where should be no need to wait
+	    (*dst & 0xfff8) == 0x4a28 || // tst.b ($xxxx,a0) // for byte change anywhere
+            (*dst & 0xff3f) == 0x4a38 || // tst.x ($xxxx.w), tas ($xxxx.w)
+            (*dst & 0xc1ff) == 0x0038 || // move.x ($xxxx.w), dX
+            (*dst & 0xf13f) == 0xb038)   // cmp.x ($xxxx.w), dX
+        return 1;
+      break;
+    case 6:
+      if ( ((dst[1] & 0xe0) == 0xe0 && ( // RAM
+            *dst == 0x4a39 ||            // tst.b ($xxxxxxxx)
+            *dst == 0x4a79 ||            // tst.w ($xxxxxxxx)
+            *dst == 0x4ab9)) ||          // tst.l ($xxxxxxxx)
+	    *dst == 0x0838)              // btst $X, ($xxxx.w) [6 byte op]
+        return 1;
+      break;
+    case 8:
+      if ( (dst[2] & 0xe0) == 0xe0 && (  // RAM
+	    *dst == 0x0839 ||            // btst $X, ($xxxxxxxx.w) [8 byte op]
+            (*dst & 0xffbf) == 0x0c39))  // cmpi.{b,w} $X, ($xxxxxxxx)
+        return 1;
+      break;
+    case 12:
+       if ((*dst & 0xf1f8) == 0x3010 && // move.w (aX), dX
+	    (dst[1]&0xf100) == 0x0000 && // arithmetic
+	    (dst[3]&0xf100) == 0x0000)   // arithmetic
+        return 1;
+      break;
+  }
+
+  return 0;
+}
+
+int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop)
+{
+#ifdef EMU_C68K
+  pc -= PicoCpuCM68k.membase;
+#endif
+  pc &= ~0xff000000;
+  elprintf(EL_IDLE, "idle: patch %06x %04x %04x #%i", pc, oldop, newop, idledet_count);
+  if (pc > Pico.romsize) {
+    if (++idledet_bads > 128) return 2; // remove detector
+    return 1; // don't patch
+  }
+
+  if (idledet_count >= 0x200 && (idledet_count & 0x1ff) == 0) {
+    void *tmp = realloc(idledet_addrs, (idledet_count+0x200)*4);
+    if (tmp == NULL) return 1;
+    idledet_addrs = tmp;
+  }
+
+  idledet_addrs[idledet_count++] = pc;
+  return 0;
+}
+
+void SekFinishIdleDet(void)
+{
+	int done_something = idledet_count > 0;
+#ifdef EMU_C68K
+  CycloneFinishIdle();
+#endif
+  while (idledet_count > 0)
+  {
+    unsigned short *op = (unsigned short *)&Pico.rom[idledet_addrs[--idledet_count]];
+    if      ((*op & 0xfd00) == 0x7100)
+      *op &= 0xff, *op |= 0x6600;
+    else if ((*op & 0xfd00) == 0x7500)
+      *op &= 0xff, *op |= 0x6700;
+    else if ((*op & 0xfd00) == 0x7d00)
+      *op &= 0xff, *op |= 0x6000;
+    else
+      elprintf(EL_STATUS|EL_IDLE, "idle: don't know how to restore %04x", *op);
+  }
+
+  if (done_something)
+  {
+    int i;
+    for (i = 0; i < 0x10000; i++)
+      if (jump_verify[i] != CycloneJumpTab[i])
+        printf("jumptab corruption @ %04x!\n", i), exit(1);
+    for (i = 0; i < Pico.romsize; i++)
+      if (rom_verify[i] != Pico.rom[i])
+        printf("ROM corruption @ %06x!\n", i), exit(1);
+  }
+}
+
+
 #if defined(EMU_M68K) && M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER
 static unsigned char op_flags[0x400000/2] = { 0, };
 static int atexit_set = 0;

+ 3 - 0
cpu/Cyclone/tools/idle.h

@@ -0,0 +1,3 @@
+
+void CycloneInitIdle(void);
+void CycloneFinishIdle(void);

+ 180 - 0
cpu/Cyclone/tools/idle.s

@@ -0,0 +1,180 @@
+@ vim:filetype=armasm
+
+@ ranges/opcodes (idle, normal):
+@ 71xx, 73xx  - bne.s (8bit offset)
+@ 75xx, 77xx  - beq.s (8bit offset)
+@ 7dxx, 7fxx  - bra.s (8bit offset)
+
+.data
+.align 2
+
+have_patches:
+  .word 0
+
+.equ patch_desc_table_size, 10
+
+patch_desc_table:
+  .word (0x71fa<<16) | 0x66fa, idle_detector_bcc8, idle_bne, Op6601  @ bne.s
+  .word (0x71f8<<16) | 0x66f8, idle_detector_bcc8, idle_bne, Op6601  @ bne.s
+  .word (0x71f6<<16) | 0x66f6, idle_detector_bcc8, idle_bne, Op6601  @ bne.s
+  .word (0x71f2<<16) | 0x66f2, idle_detector_bcc8, idle_bne, Op6601  @ bne.s
+  .word (0x75fa<<16) | 0x67fa, idle_detector_bcc8, idle_beq, Op6701  @ beq.s
+  .word (0x75f8<<16) | 0x67f8, idle_detector_bcc8, idle_beq, Op6701  @ beq.s
+  .word (0x75f6<<16) | 0x67f6, idle_detector_bcc8, idle_beq, Op6701  @ bne.s
+  .word (0x75f2<<16) | 0x67f2, idle_detector_bcc8, idle_beq, Op6701  @ bne.s
+  .word (0x7dfe<<16) | 0x60fe, idle_detector_dead, idle_bra, Op6001  @ bra.s
+  .word (0x7dfc<<16) | 0x60fc, idle_detector_dead, idle_bra, Op6001  @ bra.s
+
+
+.text
+.align 2
+
+
+.global CycloneInitIdle
+
+CycloneInitIdle:
+    ldr     r3, =CycloneJumpTab
+    ldr     r2, =patch_desc_table
+    mov     r12,#patch_desc_table_size
+
+cii_loop:
+    ldrh    r0, [r2]
+    ldr     r1, [r2, #4]           @ detector
+    str     r1, [r3, r0, lsl #2]
+    ldrh    r0, [r2, #2]
+    ldr     r1, [r2, #8]           @ idle
+    add     r0, r3, r0, lsl #2
+    str     r1, [r0]
+    ldr     r1, [r2, #12]          @ normal
+    str     r1, [r0, #0x800]
+    add     r2, r2, #16
+    subs    r12,r12,#1
+    bgt     cii_loop
+
+    ldr     r0, =have_patches
+    mov     r1, #1
+    str     r1, [r0]
+    bx      lr
+
+
+.global CycloneFinishIdle
+
+CycloneFinishIdle:
+    ldr     r0, =have_patches
+    ldr     r0, [r0]
+    tst     r0, r0
+    bxeq    lr
+
+    ldr     r3, =CycloneJumpTab
+    ldr     r2, =patch_desc_table
+    mov     r12,#patch_desc_table_size
+
+cfi_loop:
+    ldrh    r0, [r2]
+    ldr     r1, [r2, #12]         @ normal
+    str     r1, [r3, r0, lsl #2]
+    ldrh    r0, [r2, #2]
+    ldr     r1, =Op____
+    add     r0, r3, r0, lsl #2
+    str     r1, [r0]
+    str     r1, [r0, #0x800]
+    add     r2, r2, #16
+    subs    r12,r12,#1
+    bgt     cfi_loop
+
+    ldr     r0, =have_patches
+    mov     r1, #0
+    str     r1, [r0]
+    bx      lr
+
+
+
+.macro inc_counter cond
+    ldr     r0, =idle_hit_counter
+    ldr     r1, [r0]
+    add     r1, r1, #1
+    str\cond r1, [r0]
+.endm
+
+idle_bra:
+    mov     r5, #4
+    inc_counter
+    b       Op6001
+
+idle_bne:
+    msr     cpsr_flg, r10 ;@ ARM flags = 68000 flags
+    movne   r5, #4
+    inc_counter ne
+    b       Op6601
+
+idle_beq:
+    msr     cpsr_flg, r10 ;@ ARM flags = 68000 flags
+    moveq   r5, #4
+    inc_counter eq
+    b       Op6701
+
+
+@ @@@ @
+
+idle_detector_bcc8:
+    ldr     r0, =(Pico+0x22208)   @ Pico.m
+    ldr     r1, =idledet_start_frame
+    ldr     r0, [r0, #0x1c]       @ ..frame_count
+    ldr     r1, [r1]
+    cmp     r0, r1
+    blt     exit_detector         @ not yet
+
+    mov     r0, r8, asl #24       @ Shift 8-bit signed offset up...
+    add     r0, r4, r0, asr #24   @ jump dest
+    bic     r0, r0, #1
+
+    mov     r1, #0
+    sub     r1, r1, r8, lsl #24
+    mov     r1, r1, lsr #24
+    sub     r1, r1, #2
+
+    bl      SekIsIdleCode
+    tst     r0, r0
+    and     r2, r8, #0x00ff
+    orr     r2, r2, #0x7100
+    orreq   r2, r2, #0x0200
+    tst     r8, #0x0100           @ 67xx (beq)?
+    orrne   r2, r2, #0x0400
+
+    @ r2 = patch_opcode
+    sub     r0, r4, #2
+    ldrh    r1, [r0]
+    mov     r11,r2
+    bl      SekRegisterIdlePatch
+    cmp     r0, #1                @ 0 - ok to patch, 1 - no patch, 2 - remove detector
+    strlth  r11,[r4, #-2]
+    ble     exit_detector
+
+    @ remove detector from Cyclone
+    tst     r8, #0x0100           @ 67xx (beq)?
+    ldreq   r1, =Op6601
+    ldrne   r1, =Op6701
+
+    ldr     r3, =CycloneJumpTab
+    str     r1, [r3, r8, lsl #2]
+    bx      r1
+
+exit_detector:
+    tst     r8, #0x0100           @ 67xx (beq)?
+    beq     Op6601
+    b       Op6701
+
+
+idle_detector_dead:
+    @ patch without further questions
+    and     r2, r8, #0x00ff
+    orr     r2, r2, #0x7d00
+    sub     r0, r4, #2
+    ldrh    r1, [r0]
+    mov     r11,r2
+    bl      SekRegisterIdlePatch
+    strh    r11,[r4, #-2]
+    b       Op6001
+
+.pool
+

+ 2 - 1
platform/base_readme.txt

@@ -621,6 +621,8 @@ Additional thanks
 * Tasco Deluxe for his reverse engineering work on SVP and some mappers.
 * Bart Trzynadlowski for his SSFII and 68000 docs.
 * Haze for his research (http://haze.mameworld.info).
+* Lordus, Exophase and Rokas for various ideas.
+* Nemesis for his YM2612 research.
 * Mark and Jean-loup for zlib library.
 * ketchupgun for the skin.
 #ifdef GP2X
@@ -632,7 +634,6 @@ Additional thanks
 * A_SN for his gamma code.
 * craigix for supplying the GP2X hardware and making this port possible.
 * Alex for the icon.
-* Exophase, Rokas and Lordus for various ideas.
 * All the people from gp32x boards for their support.
 #endif
 #ifdef GIZ

+ 0 - 2
platform/common/emu.c

@@ -427,8 +427,6 @@ int emu_ReloadRom(void)
 		return 0;
 	}
 
-	Pico.m.frame_count = 0;
-
 	// insert CD if it was detected
 	if (cd_state != CIT_NOT_CD) {
 		ret = Insert_CD(romFileName, cd_state);

+ 1 - 0
platform/common/menu.h

@@ -66,6 +66,7 @@ typedef enum
 	MA_OPT2_NO_FRAME_LIMIT,	/* psp */
 	MA_OPT2_SVP_DYNAREC,
 	MA_OPT2_NO_SPRITE_LIM,
+	MA_OPT2_NO_IDLE_LOOPS,
 	MA_OPT2_DONE,
 	MA_OPT3_SCALE,		/* psp (all OPT3) */
 	MA_OPT3_HSCALE32,

+ 8 - 6
platform/gizmondo/menu.c

@@ -70,7 +70,7 @@ static unsigned long wait_for_input(unsigned int interesting)
 		repeats = 0;
 		wait = 20;
 	}
-	if (wait > 6 && (ret&(BTN_UP|BTN_LEFT|BTN_DOWN|BTN_RIGHT)))
+	if (wait > 6 && (ret&(BTN_UP|BTN_LEFT|BTN_DOWN|BTN_RIGHT|BTN_L|BTN_R)))
 		wait = 6;
 	inp_prev = ret;
 
@@ -1315,7 +1315,7 @@ static int menu_loop_options(void)
 
 static void draw_menu_credits(void)
 {
-	int tl_x = 15, tl_y = 64, y;
+	int tl_x = 15, tl_y = 56, y;
 	menu_draw_begin(1);
 
 	text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006-2008");
@@ -1326,14 +1326,16 @@ static void draw_menu_credits(void)
 	text_out16(tl_x, (y+=10), "      base code of PicoDrive");
 	text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");
 	text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");
-	text_out16(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");
-	text_out16(tl_x, (y+=10), "Stephane Dallongeville:");
-	text_out16(tl_x, (y+=10), "      opensource Gens");
-	text_out16(tl_x, (y+=10), "Haze: Genesis hw info");
 	text_out16(tl_x, (y+=10), "Reesy: kgsdk wrapper, sound code");
 	text_out16(tl_x, (y+=10), "jens.l: gizmondo hardware");
 	text_out16(tl_x, (y+=10), "ketchupgun: skin design");
 
+	text_out16(tl_x, (y+=20), "special thanks (for code, docs, ideas)");
+	text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,");
+	text_out16(tl_x, (y+=10), " Stephane Dallongeville,");
+	text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,");
+	text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe");
+
 	menu_draw_end();
 }
 

+ 1 - 1
platform/gp2x/Makefile

@@ -128,7 +128,7 @@ OBJS += ../../cpu/musashi/m68kops.o ../../cpu/musashi/m68kcpu.o
 endif
 ifeq "$(use_cyclone)" "1"
 DEFINC += -DEMU_C68K
-OBJS += ../../cpu/Cyclone/proj/Cyclone.o
+OBJS += ../../cpu/Cyclone/proj/Cyclone.o ../../cpu/Cyclone/tools/idle.o
 endif
 # drz80/mz80
 ifeq "$(mz80)" "1"

+ 11 - 8
platform/gp2x/menu.c

@@ -25,7 +25,7 @@
 #include <zlib/zlib.h>
 
 #ifndef _DIRENT_HAVE_D_TYPE
-#error "need d_type for file browser
+#error "need d_type for file browser"
 #endif
 
 extern int  mmuhack_status;
@@ -67,7 +67,7 @@ static unsigned long wait_for_input(unsigned long interesting)
 		repeats = 0;
 		wait = 20;
 	}
-	if (wait > 6 && (ret&(GP2X_UP|GP2X_LEFT|GP2X_DOWN|GP2X_RIGHT)))
+	if (wait > 6 && (ret&(GP2X_UP|GP2X_LEFT|GP2X_DOWN|GP2X_RIGHT|GP2X_L|GP2X_R)))
 		wait = 6;
 	inp_prev = ret;
 	inp_prevjoy = 0;
@@ -1075,6 +1075,7 @@ menu_entry opt2_entries[] =
 	{ "craigix's RAM timings",     MB_ONOFF, MA_OPT2_RAMTIMINGS,    &currentConfig.EmuOpt, 0x0100, 0, 0, 1, 1 },
 	{ NULL,                        MB_ONOFF, MA_OPT2_SQUIDGEHACK,   &currentConfig.EmuOpt, 0x0010, 0, 0, 1, 1 },
 	{ "SVP dynarec",               MB_ONOFF, MA_OPT2_SVP_DYNAREC,   &PicoOpt, 0x20000, 0, 0, 1, 1 },
+	{ "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS, &PicoOpt, 0x80000, 0, 0, 1, 1 },
 	{ "done",                      MB_NONE,  MA_OPT2_DONE,          NULL, 0, 0, 0, 1, 0 },
 };
 
@@ -1428,7 +1429,7 @@ static int menu_loop_options(void)
 
 static void draw_menu_credits(void)
 {
-	int tl_x = 15, tl_y = 64, y;
+	int tl_x = 15, tl_y = 56, y;
 	gp2x_pd_clone_buffer2();
 
 	text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006-2008");
@@ -1438,17 +1439,19 @@ static void draw_menu_credits(void)
 	text_out16(tl_x, (y+=10), "      base code of PicoDrive");
 	text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");
 	text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");
-	text_out16(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");
-	text_out16(tl_x, (y+=10), "Stephane Dallongeville:");
-	text_out16(tl_x, (y+=10), "      opensource Gens");
-	text_out16(tl_x, (y+=10), "Haze: Genesis hw info");
 	text_out16(tl_x, (y+=10), "rlyeh and others: minimal SDK");
 	text_out16(tl_x, (y+=10), "Squidge: squidgehack");
 	text_out16(tl_x, (y+=10), "Dzz: ARM940 sample");
-	text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick");
+	text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joy code");
 	text_out16(tl_x, (y+=10), "craigix: GP2X hardware");
 	text_out16(tl_x, (y+=10), "ketchupgun: skin design");
 
+	text_out16(tl_x, (y+=20), "special thanks (for code, docs, ideas)");
+	text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,");
+	text_out16(tl_x, (y+=10), " Stephane Dallongeville,");
+	text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,");
+	text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe");
+
 	menu_flip();
 }
 

+ 1 - 1
platform/gp2x/port_config.h

@@ -19,7 +19,7 @@
 #define CAN_HANDLE_240_LINES	1
 
 // logging emu events
-#define EL_LOGMASK EL_STATUS // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL) // xffff
+#define EL_LOGMASK (EL_STATUS|EL_IDLE) // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL) // xffff
 
 //#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
 #define dprintf(x...)

+ 1 - 1
platform/gp2x/version.h

@@ -1,2 +1,2 @@
-#define VERSION "1.45"
+#define VERSION "1.50"
 

+ 7 - 5
platform/psp/menu.c

@@ -82,7 +82,7 @@ static unsigned long wait_for_input(unsigned int interesting, int is_key_config)
 
 	if (!is_key_config)
 		ret |= (ret & 0xf0000000) >> 24; // use analog as d-pad
-	if (wait > 6 && (ret&(BTN_UP|BTN_LEFT|BTN_DOWN|BTN_RIGHT)))
+	if (wait > 6 && (ret&(BTN_UP|BTN_LEFT|BTN_DOWN|BTN_RIGHT|BTN_L|BTN_R)))
 		wait = 6;
 
 	// we don't need diagonals in menus
@@ -1512,13 +1512,15 @@ static void draw_menu_credits(void)
 	text_out16(tl_x, (y+=10), "Chui: Fame/C");
 	text_out16(tl_x, (y+=10), "NJ: CZ80");
 	text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");
-	text_out16(tl_x, (y+=10), "Stephane Dallongeville:");
-	text_out16(tl_x, (y+=10), "    Gens code, base of Fame/C, CZ80");
-	text_out16(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");
-	text_out16(tl_x, (y+=10), "Haze: Genesis hw info");
 	text_out16(tl_x, (y+=10), "ps2dev.org people: PSP SDK/code");
 	text_out16(tl_x, (y+=10), "ketchupgun: skin design");
 
+	text_out16(tl_x, (y+=20), "special thanks (for code, docs, ideas):");
+	text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,");
+	text_out16(tl_x, (y+=10), " Stephane Dallongeville,");
+	text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,");
+	text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe");
+
 	menu_draw_end();
 }
 

+ 1 - 1
platform/psp/version.h

@@ -1,2 +1,2 @@
-#define VERSION "1.40b"
+#define VERSION "1.50"