idle loops adjusted

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@549 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2008-07-15 17:04:43 +00:00
parent 1413b9a118
commit 5ed2a20eaa
5 changed files with 89 additions and 52 deletions

View file

@ -171,16 +171,16 @@ int PicoReset(void)
if (Pico.m.dma_xfers == 0 && !(PicoOpt&POPT_DIS_VDP_FIFO)) if (Pico.m.dma_xfers == 0 && !(PicoOpt&POPT_DIS_VDP_FIFO))
Pico.m.dma_xfers = rand() & 0x1fff; Pico.m.dma_xfers = rand() & 0x1fff;
SekFinishIdleDet();
if (PicoAHW & PAHW_MCD) { if (PicoAHW & PAHW_MCD) {
PicoResetMCD(); PicoResetMCD();
return 0; return 0;
} }
else {
// reinit, so that checksum checks pass // reinit, so that checksum checks pass
SekFinishIdleDet();
if (!(PicoOpt & POPT_DIS_IDLE_DET)) if (!(PicoOpt & POPT_DIS_IDLE_DET))
SekInitIdleDet(); SekInitIdleDet();
}
// reset sram state; enable sram access by default if it doesn't overlap with ROM // reset sram state; enable sram access by default if it doesn't overlap with ROM
Pico.m.sram_reg=sram_reg&0x14; Pico.m.sram_reg=sram_reg&0x14;
@ -315,6 +315,21 @@ void PicoFrame(void)
{ {
Pico.m.frame_count++; Pico.m.frame_count++;
#if 0
if ((Pico.m.frame_count & 0x3f) == 0)
{
extern int idlehit_addrs[], idlehit_counts[];
int i;
printf("--\n");
for (i = 0; i < 128 && idlehit_addrs[i] != 0; i++) {
if (idlehit_counts[i] != 0) {
printf("%06x %i %i\n", idlehit_addrs[i], idlehit_counts[i], idlehit_counts[i] >> 6);
idlehit_counts[i] = 0;
}
}
}
#endif
if (PicoAHW & PAHW_MCD) { if (PicoAHW & PAHW_MCD) {
PicoFrameMCD(); PicoFrameMCD();
return; return;

View file

@ -199,6 +199,25 @@ static int *idledet_addrs = NULL;
static int idledet_count = 0, idledet_bads = 0; static int idledet_count = 0, idledet_bads = 0;
int idledet_start_frame = 0; int idledet_start_frame = 0;
#if 0
#define IDLE_STATS 1
unsigned int idlehit_addrs[128], idlehit_counts[128];
void SekRegisterIdleHit(unsigned int pc)
{
int i;
for (i = 0; i < 127 && idlehit_addrs[i]; i++) {
if (idlehit_addrs[i] == pc) {
idlehit_counts[i]++;
return;
}
}
idlehit_addrs[i] = pc;
idlehit_counts[i] = 1;
idlehit_addrs[i+1] = 0;
}
#endif
void SekInitIdleDet(void) void SekInitIdleDet(void)
{ {
void *tmp = realloc(idledet_addrs, 0x200*4); void *tmp = realloc(idledet_addrs, 0x200*4);
@ -210,6 +229,9 @@ void SekInitIdleDet(void)
idledet_addrs = tmp; idledet_addrs = tmp;
idledet_count = idledet_bads = 0; idledet_count = idledet_bads = 0;
idledet_start_frame = Pico.m.frame_count + 360; idledet_start_frame = Pico.m.frame_count + 360;
#ifdef IDLE_STATS
idlehit_addrs[0] = 0;
#endif
#ifdef EMU_C68K #ifdef EMU_C68K
CycloneInitIdle(); CycloneInitIdle();
@ -224,6 +246,10 @@ int SekIsIdleCode(unsigned short *dst, int bytes)
// printf("SekIsIdleCode %04x %i\n", *dst, bytes); // printf("SekIsIdleCode %04x %i\n", *dst, bytes);
switch (bytes) switch (bytes)
{ {
case 2:
if ((*dst & 0xf000) != 0x6000) // not another branch
return 1;
break;
case 4: case 4:
if ( (*dst & 0xfff8) == 0x4a10 || // tst.b ($aX) // there should be no need to wait if ( (*dst & 0xfff8) == 0x4a10 || // tst.b ($aX) // there should be no need to wait
(*dst & 0xfff8) == 0x4a28 || // tst.b ($xxxx,a0) // for byte change anywhere (*dst & 0xfff8) == 0x4a28 || // tst.b ($xxxx,a0) // for byte change anywhere
@ -261,13 +287,20 @@ int SekIsIdleCode(unsigned short *dst, int bytes)
return 0; return 0;
} }
int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop) int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop, void *ctx)
{ {
#ifdef EMU_C68K int is_main68k = 1;
pc -= PicoCpuCM68k.membase; #if defined(EMU_C68K)
struct Cyclone *cyc = ctx;
is_main68k = cyc == &PicoCpuCM68k;
pc -= cyc->membase;
#elif defined(EMU_F68K)
is_main68k = ctx == &PicoCpuFM68k;
#endif #endif
pc &= ~0xff000000; pc &= ~0xff000000;
elprintf(EL_IDLE, "idle: patch %06x %04x %04x #%i", pc, oldop, newop, idledet_count); elprintf(EL_IDLE, "idle: patch %06x %04x %04x %c %c #%i", pc, oldop, newop,
(newop&0x200)?'n':'y', is_main68k?'m':'s', idledet_count);
if (pc > Pico.romsize && !(PicoAHW & PAHW_SVP)) { if (pc > Pico.romsize && !(PicoAHW & PAHW_SVP)) {
if (++idledet_bads > 128) return 2; // remove detector if (++idledet_bads > 128) return 2; // remove detector
return 1; // don't patch return 1; // don't patch

View file

@ -22,8 +22,8 @@ patch_desc_table:
.word (0x75f8<<16) | 0x67f8, 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 @ beq.s .word (0x75f6<<16) | 0x67f6, idle_detector_bcc8, idle_beq, Op6701 @ beq.s
.word (0x75f2<<16) | 0x67f2, idle_detector_bcc8, idle_beq, Op6701 @ beq.s .word (0x75f2<<16) | 0x67f2, idle_detector_bcc8, idle_beq, Op6701 @ beq.s
.word (0x7dfe<<16) | 0x60fe, idle_detector_dead, idle_bra, Op6001 @ bra.s .word (0x7dfe<<16) | 0x60fe, idle_detector_bcc8, idle_bra, Op6001 @ bra.s
.word (0x7dfc<<16) | 0x60fc, idle_detector_dead, idle_bra, Op6001 @ bra.s .word (0x7dfc<<16) | 0x60fc, idle_detector_bcc8, idle_bra, Op6001 @ bra.s
.text .text
@ -90,10 +90,12 @@ cfi_loop:
.macro inc_counter cond .macro inc_counter cond
@ ldr r0, =idle_hit_counter @ ldr\cond r0, [r7, #0x60]
@ ldr r1, [r0] @ mov r11,lr
@ add r1, r1, #1 @ sub r0, r4, r0
@ str\cond r1, [r0] @ sub r0, r0, #2
@ bl\cond SekRegisterIdleHit
@ mov lr, r11
.endm .endm
idle_bra: idle_bra:
@ -139,43 +141,36 @@ idle_detector_bcc8:
and r2, r8, #0x00ff and r2, r8, #0x00ff
orr r2, r2, #0x7100 orr r2, r2, #0x7100
orreq r2, r2, #0x0200 orreq r2, r2, #0x0200
tst r8, #0x0100 @ 67xx (beq)? mov r0, r8, lsr #8
orrne r2, r2, #0x0400 cmp r0, #0x66
orrgt r2, r2, #0x0400 @ 67xx (beq)
orrlt r2, r2, #0x0c00 @ 60xx (bra)
@ r2 = patch_opcode @ r2 = patch_opcode
sub r0, r4, #2 sub r0, r4, #2
ldrh r1, [r0] ldrh r1, [r0]
mov r11,r2 mov r11,r2
mov r3, r7
bl SekRegisterIdlePatch bl SekRegisterIdlePatch
cmp r0, #1 @ 0 - ok to patch, 1 - no patch, 2 - remove detector cmp r0, #1 @ 0 - ok to patch, 1 - no patch, 2 - remove detector
strlth r11,[r4, #-2] strlth r11,[r4, #-2]
ble exit_detector ble exit_detector
@ remove detector from Cyclone @ remove detector from Cyclone
tst r8, #0x0100 @ 67xx (beq)? mov r0, r8, lsr #8
cmp r0, #0x66
ldrlt r1, =Op6001
ldreq r1, =Op6601 ldreq r1, =Op6601
ldrne r1, =Op6701 ldrgt r1, =Op6701
ldr r3, =CycloneJumpTab ldr r3, =CycloneJumpTab
str r1, [r3, r8, lsl #2] str r1, [r3, r8, lsl #2]
bx r1 bx r1
exit_detector: exit_detector:
tst r8, #0x0100 @ 67xx (beq)? mov r0, r8, lsr #8
cmp r0, #0x66
blt Op6001
beq Op6601 beq Op6601
b Op6701 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

View file

@ -5041,8 +5041,8 @@ idle_install:
INSTALL_IDLE(0x75f8, 0x67f8, idle_detector_bcc8, 0x6701_idle, 0x6701); INSTALL_IDLE(0x75f8, 0x67f8, idle_detector_bcc8, 0x6701_idle, 0x6701);
INSTALL_IDLE(0x75f6, 0x67f6, idle_detector_bcc8, 0x6701_idle, 0x6701); INSTALL_IDLE(0x75f6, 0x67f6, idle_detector_bcc8, 0x6701_idle, 0x6701);
INSTALL_IDLE(0x75f2, 0x67f2, idle_detector_bcc8, 0x6701_idle, 0x6701); INSTALL_IDLE(0x75f2, 0x67f2, idle_detector_bcc8, 0x6701_idle, 0x6701);
INSTALL_IDLE(0x7dfe, 0x60fe, idle_detector_dead, 0x6001_idle, 0x6001); INSTALL_IDLE(0x7dfe, 0x60fe, idle_detector_bcc8, 0x6001_idle, 0x6001);
INSTALL_IDLE(0x7dfc, 0x60fc, idle_detector_dead, 0x6001_idle, 0x6001); INSTALL_IDLE(0x7dfc, 0x60fc, idle_detector_bcc8, 0x6001_idle, 0x6001);
return 0; return 0;
idle_remove: idle_remove:

View file

@ -40013,7 +40013,7 @@ RET(8)
extern int SekIsIdleCode(unsigned short *dst, int bytes); extern int SekIsIdleCode(unsigned short *dst, int bytes);
extern int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop); extern int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop, void *ctx);
OPCODE(idle_detector_bcc8) OPCODE(idle_detector_bcc8)
{ {
@ -40032,18 +40032,22 @@ OPCODE(idle_detector_bcc8)
ret = SekIsIdleCode(dest_pc, bytes); ret = SekIsIdleCode(dest_pc, bytes);
newop = (Opcode & 0xfe) | 0x7100; newop = (Opcode & 0xfe) | 0x7100;
if (!ret) newop |= 0x200; if (!ret) newop |= 0x200;
if (Opcode & 0x0100) newop |= 0x400; // beq if ( Opcode & 0x0100) newop |= 0x400; // beq
if (!(Opcode & 0x0f00)) newop |= 0xc00; // bra
ret = SekRegisterIdlePatch(GET_PC - 2, Opcode, newop); ret = SekRegisterIdlePatch(GET_PC - 2, Opcode, newop, &m68kcontext);
switch (ret) switch (ret)
{ {
case 0: PC[-1] = newop; break; case 0: PC[-1] = newop; break;
case 1: break; case 1: break;
case 2: JumpTable[Opcode] = (Opcode & 0x0100) ? CAST_OP(0x6701) : CAST_OP(0x6601); break; case 2: JumpTable[Opcode] = (Opcode & 0x0f00) ?
((Opcode & 0x0100) ? CAST_OP(0x6701) : CAST_OP(0x6601)) :
CAST_OP(0x6001); break;
} }
end: end:
cond_true = (Opcode & 0x0100) ? !flag_NotZ : flag_NotZ; // beq? if ((Opcode & 0xff00) == 0x6000) cond_true = 1;
else cond_true = (Opcode & 0x0100) ? !flag_NotZ : flag_NotZ; // beq?
if (cond_true) if (cond_true)
{ {
PC = dest_pc; PC = dest_pc;
@ -40052,14 +40056,4 @@ end:
RET(8) RET(8)
} }
OPCODE(idle_detector_dead)
{
// patch without further questions
int newop = 0x7d00 | (Opcode & 0xff);
PC[-1] = newop;
SekRegisterIdlePatch(GET_PC - 2, Opcode, newop);
PC += ((s8)(Opcode & 0xFE)) >> 1;
RET(10)
}
#endif // PICODRIVE_HACK #endif // PICODRIVE_HACK