X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=Pico%2FPico.c;h=66b27c2ad3edc74bf19d3b87a5fd543492f17410;hb=c060a9ab9c428e1ed9c4159b56529a2a36031e44;hp=93d04e77f53774c888b811a9d48f133e298aeb26;hpb=4b9c58882616c5205a5ad5c9350f20a3d22bd7e1;p=picodrive.git diff --git a/Pico/Pico.c b/Pico/Pico.c index 93d04e7..66b27c2 100644 --- a/Pico/Pico.c +++ b/Pico/Pico.c @@ -1,7 +1,7 @@ -// This is part of Pico Library +// PicoDrive // (c) Copyright 2004 Dave, All rights reserved. -// (c) Copyright 2006 notaz, All rights reserved. +// (c) Copyright 2006-2008 notaz, All rights reserved. // Free for non-commercial use. // For commercial use, separate licencing terms must be obtained. @@ -23,10 +23,10 @@ struct PicoSRAM SRam = {0,}; void (*PicoWriteSound)(int len) = NULL; // called at the best time to send sound buffer (PsndOut) to hardware void (*PicoResetHook)(void) = NULL; -void (*PicoLineHook)(int count) = NULL; +void (*PicoLineHook)(void) = NULL; // to be called once on emu init -int PicoInit(void) +void PicoInit(void) { // Blank space for state: memset(&Pico,0,sizeof(Pico)); @@ -40,8 +40,6 @@ int PicoInit(void) PicoSVPInit(); SRam.data=0; - - return 0; } // to be called once on emu exit @@ -58,6 +56,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); @@ -156,8 +156,11 @@ int PicoReset(void) Pico.m.dirtyPal = 1; + Pico.m.z80_bank68k = 0; + memset(Pico.zram, 0, sizeof(Pico.zram)); // ?? + PicoDetectRegion(); - Pico.video.status = 0x3408 | Pico.m.pal; // 'always set' bits | vblank | pal + Pico.video.status = 0x3428 | Pico.m.pal; // 'always set' bits | vblank | collision | pal PsndReset(); // pal must be known here @@ -169,6 +172,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; @@ -185,17 +194,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) @@ -209,7 +218,8 @@ PICO_INTERNAL int CheckDMA(void) if(Pico.video.reg[12] & 1) dma_op |= 4; // 40 cell mode? if(!(Pico.video.status&8)&&(Pico.video.reg[1]&0x40)) dma_op|=8; // active display? xfers_can = dma_timings[dma_op]; - if(xfers <= xfers_can) { + if(xfers <= xfers_can) + { if(dma_op&2) Pico.video.status&=~2; // dma no longer busy else { burn = xfers * dma_bsycles[dma_op] >> 8; // have to be approximate because can't afford division.. @@ -229,7 +239,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); @@ -240,40 +250,10 @@ static __inline void SekRunM68k(int cyc) #elif defined(EMU_M68K) SekCycleCnt+=m68k_execute(cyc_do); #elif defined(EMU_F68K) - SekCycleCnt+=fm68k_emulate(cyc_do+1, 0); + SekCycleCnt+=fm68k_emulate(cyc_do+1, 0, 0); #endif } -static __inline void SekStep(void) -{ - // this is required for timing sensitive stuff to work - int realaim=SekCycleAim; SekCycleAim=SekCycleCnt+1; -#if defined(EMU_CORE_DEBUG) - SekCycleCnt+=CM_compareRun(1, 0); -#elif defined(EMU_C68K) - PicoCpuCM68k.cycles=1; - CycloneRun(&PicoCpuCM68k); - SekCycleCnt+=1-PicoCpuCM68k.cycles; -#elif defined(EMU_M68K) - SekCycleCnt+=m68k_execute(1); -#elif defined(EMU_F68K) - SekCycleCnt+=fm68k_emulate(1, 0); -#endif - SekCycleAim=realaim; -} - -static int CheckIdle(void) -{ - int i, state[0x24]; - - // See if the state is the same after 2 steps: - SekState(state); SekStep(); SekStep(); SekState(state+0x12); - for (i = 0x11; i >= 0; i--) - if (state[i] != state[i+0x12]) return 0; - - return 1; -} - // to be called on 224 or line_sample scanlines only static __inline void getSamples(int y) @@ -320,7 +300,7 @@ PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done) z80_cycle_aim = cycles_68k_to_z80(m68k_cycles_done); cnt = z80_cycle_aim - z80_cycle_cnt; - elprintf(EL_ANOMALY, "z80 sync %i (%i|%i -> %i|%i)", cnt, z80_cycle_cnt, z80_cycle_cnt / 228, + elprintf(EL_BUSREQ, "z80 sync %i (%i|%i -> %i|%i)", cnt, z80_cycle_cnt, z80_cycle_cnt / 228, z80_cycle_aim, z80_cycle_aim / 228); if (cnt > 0) @@ -328,206 +308,37 @@ PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done) } -// Simple frame without H-Ints -static int PicoFrameSimple(void) -{ - struct PicoVideo *pv=&Pico.video; - int y=0,lines_step=0,sects,line_last; - int cycles_68k_vblock,cycles_68k_block; - - // split to 16 run calls for active scan, for vblank split to 2 (ntsc), 3 (pal 240), 4 (pal 224) - if (Pico.m.pal) - { - if(pv->reg[1]&8) { // 240 lines - cycles_68k_block = 7308; - cycles_68k_vblock = 11694; - lines_step = 15; - } else { - cycles_68k_block = 6821; - cycles_68k_vblock = 10719; - lines_step = 14; - } - line_last = 312-1; - } else { - // M68k cycles/frame: 127840.71 - cycles_68k_block = 6841; // (488*224+148)/16.0, -4 - cycles_68k_vblock = 9164; // (38*488-148-68)/2.0, 0 - lines_step = 14; - line_last = 262-1; - } - - // a hack for VR, to get it running in fast mode - if (PicoAHW & PAHW_SVP) - Pico.ram[0xd864^1] = 0x1a; - - // we don't emulate DMA timing in this mode - if (Pico.m.dma_xfers) { - Pico.m.dma_xfers=0; - Pico.video.status&=~2; - } - - // VDP FIFO too - pv->lwrite_cnt = 0; - Pico.video.status|=0x200; - - Pico.m.scanline=-1; - PsndDacLine = 0; - - SekCyclesReset(); - z80_resetCycles(); - timers_cycle(); - - // 6 button pad: let's just say it timed out now - Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0; - - // ---- Active Scan ---- - pv->status&=~0x88; // clear V-Int, come out of vblank - - // Run in sections: - for (sects=16; sects; sects--) - { - if (CheckIdle()) break; - - SekRunM68k(cycles_68k_block); - if (PicoLineHook) PicoLineHook(lines_step); - } - - // do remaining sections without 68k - if (sects) { - SekCycleCnt += sects * cycles_68k_block; - SekCycleAim += sects * cycles_68k_block; - - if (PicoLineHook) PicoLineHook(sects*lines_step); - } +// TODO: rm from Sek.c+asm too +int idle_hit_counter = 0; - // another hack for VR (it needs hints to work) - if (PicoAHW & PAHW_SVP) { - Pico.ram[0xd864^1] = 1; - pv->pending_ints|=0x10; - if (pv->reg[0]&0x10) SekInterrupt(4); - SekRunM68k(160); +void PicoFrame(void) +{ +#if 1 + if ((Pico.m.frame_count&0x3f) == 0) { + elprintf(EL_STATUS, "ihits: %i", idle_hit_counter); + idle_hit_counter = 0; } - - // render screen - if (!PicoSkipFrame) - { - if (!(PicoOpt&POPT_ALT_RENDERER)) - { - // Draw the screen -#if CAN_HANDLE_240_LINES - if (pv->reg[1]&8) { - for (y=0;y<240;y++) PicoLine(y); - } else { - for (y=0;y<224;y++) PicoLine(y); - } -#else - for (y=0;y<224;y++) PicoLine(y); #endif - } - else PicoFrameFull(); -#ifdef DRAW_FINISH_FUNC - DRAW_FINISH_FUNC(); -#endif - } - - // a gap between flags set and vint - pv->pending_ints|=0x20; - pv->status|=8; // go into vblank - SekRunM68k(68+4); - - if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) - PicoSyncZ80(SekCycleCnt); - - // render sound - if (PsndOut) - { - int len; - if (ym2612.dacen && PsndDacLine <= lines_step*16) - PsndDoDAC(lines_step*16); - len = PsndRender(0, PsndLen); - if (PicoWriteSound) PicoWriteSound(len); - // clear sound buffer - PsndClear(); - } - - // ---- V-Blanking period ---- - // fix line counts - if(Pico.m.pal) { - if(pv->reg[1]&8) { // 240 lines - sects = 3; - lines_step = 24; - } else { - sects = 4; - lines_step = 22; - } - } else { - sects = 2; - lines_step = 19; - } - - if (pv->reg[1]&0x20) SekInterrupt(6); // Set IRQ - if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) - z80_int(); - - while (1) - { - SekRunM68k(cycles_68k_vblock); - if (PicoLineHook) PicoLineHook(lines_step); - - sects--; - if (sects == 0) break; - if (CheckIdle()) break; - } - - if (sects) { - SekCycleCnt += sects * cycles_68k_vblock; - SekCycleAim += sects * cycles_68k_vblock; - if (PicoLineHook) PicoLineHook(sects*lines_step); - } - - // must sync z80 before return, and extend last DAC sample - if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) - PicoSyncZ80(SekCycleCnt); - if (PsndOut && ym2612.dacen && PsndDacLine <= line_last) - PsndDoDAC(line_last); - - return 0; -} - -int PicoFrame(void) -{ - int acc; Pico.m.frame_count++; if (PicoAHW & PAHW_MCD) { PicoFrameMCD(); - return 0; + return; } - // be accurate if we are asked for this - if (PicoOpt&POPT_ACC_TIMING) acc=1; - // don't be accurate in alternative render mode, as hint effects will not be rendered anyway - else if (PicoOpt&POPT_ALT_RENDERER) acc = 0; - else acc=Pico.video.reg[0]&0x10; // be accurate if hints are used - //if(Pico.video.reg[12]&0x2) Pico.video.status ^= 0x10; // change odd bit in interlace mode if (!(PicoOpt&POPT_ALT_RENDERER)) PicoFrameStart(); - if (acc) - PicoFrameHints(); - else PicoFrameSimple(); - - return 0; + PicoFrameHints(); } void PicoFrameDrawOnly(void) { - int y; PicoFrameStart(); - for (y=0;y<224;y++) PicoLine(y); + PicoDrawSync(223, 0); } void PicoGetInternal(pint_t which, pint_ret_t *r) @@ -553,13 +364,22 @@ char *debugString(void) static char dstr[1024]; struct PicoVideo *pv=&Pico.video; unsigned char *reg=pv->reg, r; + extern int HighPreSpr[]; + int i, sprites_lo, sprites_hi; char *dstrp; + sprites_lo = sprites_hi = 0; + for (i = 0; HighPreSpr[i] != 0; i+=2) + if (HighPreSpr[i+1] & 0x8000) + sprites_hi++; + else sprites_lo++; + dstrp = dstr; - sprintf(dstrp, "mode set 1: %02x\n", (r=reg[0])); dstrp+=strlen(dstrp); + sprintf(dstrp, "mode set 1: %02x spr lo: %2i, spr hi: %2i\n", (r=reg[0]), sprites_lo, sprites_hi); + dstrp+=strlen(dstrp); sprintf(dstrp, "display_disable: %i, M3: %i, palette: %i, ?, hints: %i\n", bit(r,0), bit(r,1), bit(r,2), bit(r,4)); dstrp+=strlen(dstrp); - sprintf(dstrp, "mode set 2: %02x\n", (r=reg[1])); dstrp+=strlen(dstrp); + sprintf(dstrp, "mode set 2: %02x hcnt: %i\n", (r=reg[1]), pv->reg[10]); dstrp+=strlen(dstrp); sprintf(dstrp, "SMS/gen: %i, pal: %i, dma: %i, vints: %i, disp: %i, TMS: %i\n", bit(r,2), bit(r,3), bit(r,4), bit(r,5), bit(r,6), bit(r,7)); dstrp+=strlen(dstrp); sprintf(dstrp, "mode set 3: %02x\n", (r=reg[0xB])); dstrp+=strlen(dstrp);