From 1dceadaee482ad3ca6f5ccbef57ea93893f45e82 Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 16 Sep 2007 15:44:18 +0000 Subject: [PATCH] updated EEPROM code, gmv fixed git-svn-id: file:///home/notaz/opt/svn/PicoDrive@249 be3aeb3a-fb24-0410-a615-afba39da0efa --- Pico/Cart.c | 122 ++++++++++++++++++++++++++++++- Pico/Memory.c | 63 ++++++++-------- Pico/Memory.s | 30 ++++++++ Pico/MemoryCmn.c | 3 +- Pico/Misc.c | 134 +++++++++++++++++++---------------- Pico/Pico.c | 63 +++------------- Pico/Pico.h | 1 + Pico/PicoInt.h | 23 ++++-- Pico/VideoPort.c | 2 +- platform/gp2x/Makefile | 7 +- platform/gp2x/emu.c | 20 ++++-- platform/gp2x/port_config.h | 2 +- platform/linux/port_config.h | 2 +- platform/readme.txt | 6 +- 14 files changed, 307 insertions(+), 171 deletions(-) diff --git a/Pico/Cart.c b/Pico/Cart.c index 1cf8dec7..cf335804 100644 --- a/Pico/Cart.c +++ b/Pico/Cart.c @@ -310,10 +310,18 @@ int PicoCartInsert(unsigned char *rom,unsigned int romsize) if(rom != NULL) *(unsigned long *)(rom+romsize) = 0xFFFE4EFA; // 4EFA FFFE byteswapped - SRam.resize=1; Pico.rom=rom; Pico.romsize=romsize; + // setup correct memory map for loaded ROM + if (PicoMCD & 1) + PicoMemSetupCD(); + else PicoMemSetup(); + PicoMemReset(); + + if (!(PicoMCD & 1)) + PicoCartDetect(); + return PicoReset(1); } @@ -323,3 +331,115 @@ int PicoUnloadCart(unsigned char* romdata) return 0; } +static int name_cmp(const char *name) +{ + int i, len = strlen(name); + const char *name_rom = (const char *)Pico.rom+0x150; + for (i = 0; i < len; i++) + if (name[i] != name_rom[i^1]) + return 1; + return 0; +} + +/* various cart-specific things, which can't be handled by generic code */ +void PicoCartDetect(void) +{ + int sram_size = 0, csum; + if(SRam.data) free(SRam.data); SRam.data=0; + Pico.m.sram_reg = 0; + + csum = PicoRead32(0x18c) & 0xffff; + + if (Pico.rom[0x1B1] == 'R' && Pico.rom[0x1B0] == 'A') + { + if (Pico.rom[0x1B2] & 0x40) + { + // EEPROM + SRam.start = PicoRead32(0x1B4) & ~1; // zero address is used for clock by some games + SRam.end = PicoRead32(0x1B8); + sram_size = 0x2000; + Pico.m.sram_reg |= 4; + } else { + // normal SRAM + SRam.start = PicoRead32(0x1B4) & 0xFFFF00; + SRam.end = PicoRead32(0x1B8) | 1; + sram_size = SRam.end - SRam.start + 1; + } + Pico.m.sram_reg |= 0x10; // SRAM was detected + } + if (sram_size <= 0) + { + // some games may have bad headers, like S&K and Sonic3 + // note: majority games use 0x200000 as starting address, but there are some which + // use something else (0x300000 by HardBall '95). Luckily they have good headers. + SRam.start = 0x200000; + SRam.end = 0x203FFF; + sram_size = 0x004000; + } + + if (sram_size) + { + SRam.data = (unsigned char *) calloc(sram_size, 1); + if(!SRam.data) return; + } + SRam.changed = 0; + + // set EEPROM defaults, in case it gets detected + SRam.eeprom_type = 0; // 7bit (24C01) + SRam.eeprom_abits = 3; // eeprom access must be odd addr for: bit0 ~ cl, bit1 ~ in + SRam.eeprom_bit_cl = 1; + SRam.eeprom_bit_in = 0; + SRam.eeprom_bit_out= 0; + + // some known EEPROM data (thanks to EkeEke) + if (name_cmp("COLLEGE SLAM") == 0 || + name_cmp("FRANK THOMAS BIGHURT BASEBAL") == 0) + { + SRam.eeprom_type = 3; + SRam.eeprom_abits = 2; + SRam.eeprom_bit_cl = 0; + } + else if (name_cmp("NBA JAM TOURNAMENT EDITION") == 0 || + name_cmp("NFL QUARTERBACK CLUB") == 0) + { + SRam.eeprom_type = 2; + SRam.eeprom_abits = 2; + SRam.eeprom_bit_cl = 0; + } + else if (name_cmp("NBA JAM") == 0) + { + SRam.eeprom_type = 2; + SRam.eeprom_bit_out = 1; + SRam.eeprom_abits = 0; + } + else if (name_cmp("NHLPA HOCKEY '93") == 0 || + name_cmp("NHLPA Hockey '93") == 0 || + name_cmp("RINGS OF POWER") == 0) + { + SRam.start = SRam.end = 0x200000; + Pico.m.sram_reg = 0x14; + SRam.eeprom_abits = 0; + SRam.eeprom_bit_cl = 6; + SRam.eeprom_bit_in = 7; + SRam.eeprom_bit_out= 7; + } + else if ( name_cmp("MICRO MACHINES II") == 0 || + (name_cmp(" ") == 0 && // Micro Machines {Turbo Tournament '96, Military - It's a Blast!} + (csum == 0x165e || csum == 0x168b || csum == 0xCEE0 || csum == 0x2C41))) + { + SRam.start = 0x300000; + SRam.end = 0x380001; + Pico.m.sram_reg = 0x14; + SRam.eeprom_type = 2; + SRam.eeprom_abits = 0; + SRam.eeprom_bit_cl = 1; + SRam.eeprom_bit_in = 0; + SRam.eeprom_bit_out= 7; + } + + // Some games malfunction if SRAM is not filled with 0xff + if (name_cmp("DINO DINI'S SOCCER") == 0 || + name_cmp("MICRO MACHINES II") == 0) + memset(SRam.data, 0xff, sram_size); +} + diff --git a/Pico/Memory.c b/Pico/Memory.c index e95d1322..7b30e4a3 100644 --- a/Pico/Memory.c +++ b/Pico/Memory.c @@ -153,6 +153,7 @@ u32 SRAMRead(u32 a) { unsigned int sreg = Pico.m.sram_reg; if(!(sreg & 0x10) && (sreg & 1) && a > 0x200001) { // not yet detected SRAM + elprintf(EL_SRAMIO, "normal sram detected."); Pico.m.sram_reg|=0x10; // should be normal SRAM } if(sreg & 4) // EEPROM read @@ -163,24 +164,30 @@ u32 SRAMRead(u32 a) static void SRAMWrite(u32 a, u32 d) { - dprintf("sram_w: %06x, %08x @%06x", a&0xffffff, d, SekPc); unsigned int sreg = Pico.m.sram_reg; if(!(sreg & 0x10)) { // not detected SRAM if((a&~1)==0x200000) { - Pico.m.sram_reg|=4; // this should be a game with EEPROM (like NBA Jam) + elprintf(EL_SRAMIO, "eeprom detected."); + sreg|=4; // this should be a game with EEPROM (like NBA Jam) SRam.start=0x200000; SRam.end=SRam.start+1; - } - Pico.m.sram_reg|=0x10; + } else + elprintf(EL_SRAMIO, "normal sram detected."); + sreg|=0x10; + Pico.m.sram_reg=sreg; } if(sreg & 4) { // EEPROM write - if(SekCyclesDoneT()-lastSSRamWrite < 46) { + // this diff must be at most 16 for NBA Jam to work + if(SekCyclesDoneT()-lastSSRamWrite < 16) { // just update pending state + elprintf(EL_EEPROM, "eeprom: skip because cycles=%i", SekCyclesDoneT()-lastSSRamWrite); SRAMUpdPending(a, d); } else { + int old=sreg; SRAMWriteEEPROM(sreg>>6); // execute pending SRAMUpdPending(a, d); - lastSSRamWrite = SekCyclesDoneT(); + if ((old^Pico.m.sram_reg)&0xc0) // update time only if SDA/SCL changed + lastSSRamWrite = SekCyclesDoneT(); } } else if(!(sreg & 2)) { u8 *pm=(u8 *)(SRam.data-SRam.start+a); @@ -199,8 +206,6 @@ u32 OtherRead16End(u32 a, int realsize) { u32 d=0; - dprintf("strange r%i: %06x @%06x", realsize, a&0xffffff, SekPc); - // for games with simple protection devices, discovered by Haze // some dumb detection is used, but that should be enough to make things work if ((a>>22) == 1 && Pico.romsize >= 512*1024) { @@ -262,7 +267,7 @@ u32 OtherRead16End(u32 a, int realsize) } end: - dprintf("ret = %04x", d); + elprintf(EL_UIO, "strange r%i: [%06x] %04x @%06x", realsize, a&0xffffff, d, SekPc); return d; } @@ -272,9 +277,8 @@ end: static void OtherWrite8End(u32 a,u32 d,int realsize) { // sram - //if(a==0x200000) dprintf("cc : %02x @ %06x [%i|%i]", d, SekPc, SekCyclesDoneT(), SekCyclesDone()); - //if(a==0x200001) dprintf("w8 : %02x @ %06x [%i]", d, SekPc, SekCyclesDoneT()); if(a >= SRam.start && a <= SRam.end) { + elprintf(EL_SRAMIO, "sram w8 [%06x] %02x @ %06x", a, d, SekPc); SRAMWrite(a, d); return; } @@ -288,13 +292,13 @@ static void OtherWrite8End(u32 a,u32 d,int realsize) #else // sram access register if(a == 0xA130F1) { - dprintf("sram reg=%02x", d); + elprintf(EL_SRAMIO, "sram reg=%02x", d); Pico.m.sram_reg &= ~3; Pico.m.sram_reg |= (u8)(d&3); return; } #endif - dprintf("strange w%i: %06x, %08x @%06x", realsize, a&0xffffff, d, SekPc); + elprintf(EL_UIO, "strange w%i: %06x, %08x @%06x", realsize, a&0xffffff, d, SekPc); if(a >= 0xA13004 && a < 0xA13040) { // dumb 12-in-1 or 4-in-1 banking support @@ -332,6 +336,7 @@ PICO_INTERNAL_ASM u32 CPU_CALL PicoRead8(u32 a) // sram if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg&5)) { d = SRAMRead(a); + elprintf(EL_SRAMIO, "sram r8 [%06x] %02x @ %06x", a, d, SekPc); goto end; } #endif @@ -342,15 +347,7 @@ PICO_INTERNAL_ASM u32 CPU_CALL PicoRead8(u32 a) d=OtherRead16(a&~1, 8); if ((a&1)==0) d>>=8; - end: - - //if ((a&0xe0ffff)==0xe0AE57+0x69c) - // dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc); - //if ((a&0xe0ffff)==0xe0a9ba+0x69c) - // dprintf("r8 : %06x, %02x @%06x", a&0xffffff, d, SekPc); - - //if(a==0x200001||a==0x200000) printf("r8 : %02x [%06x] @ %06x [%i]\n", d, a, SekPc, SekCyclesDoneT()); - //dprintf("r8 : %06x, %02x @%06x [%03i]", a&0xffffff, (u8)d, SekPc, Pico.m.scanline); +end: #ifdef __debug_io dprintf("r8 : %06x, %02x @%06x", a&0xffffff, (u8)d, SekPc); #endif @@ -376,6 +373,7 @@ PICO_INTERNAL_ASM u32 CPU_CALL PicoRead16(u32 a) if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg&5)) { d = SRAMRead(a); d |= d<<8; + elprintf(EL_SRAMIO, "sram r16 [%06x] %04x @ %06x", a, d, SekPc); goto end; } #endif @@ -385,11 +383,7 @@ PICO_INTERNAL_ASM u32 CPU_CALL PicoRead16(u32 a) d = OtherRead16(a, 16); - end: - //if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c) - // dprintf("r16: %06x, %04x @%06x", a&0xffffff, d, SekPc); - //if(a==0x200000) printf("r16: %04x @ %06x [%i]\n", d, SekPc, SekCyclesDoneT()); - +end: #ifdef __debug_io dprintf("r16: %06x, %04x @%06x", a&0xffffff, d, SekPc); #endif @@ -414,6 +408,7 @@ PICO_INTERNAL_ASM u32 CPU_CALL PicoRead32(u32 a) if(a >= SRam.start && a <= SRam.end && (Pico.m.sram_reg&5)) { d = (SRAMRead(a)<<16)|SRAMRead(a+2); d |= d<<8; + elprintf(EL_SRAMIO, "sram r32 [%06x] %08x @ %06x", a, d, SekPc); goto end; } @@ -422,8 +417,7 @@ PICO_INTERNAL_ASM u32 CPU_CALL PicoRead32(u32 a) d = (OtherRead16(a, 32)<<16)|OtherRead16(a+2, 32); - end: - //if(a==0x200000) printf("r32: %08x @ %06x [%i]\n", d, SekPc, SekCyclesDoneT()); +end: #ifdef __debug_io dprintf("r32: %06x, %08x @%06x", a&0xffffff, d, SekPc); #endif @@ -469,9 +463,6 @@ void CPU_CALL PicoWrite16(u32 a,u16 d) #if defined(EMU_C68K) && defined(EMU_M68K) lastwrite_cyc_d[lwp_cyc++&15] = d; #endif - //if ((a&0xe0ffff)==0xe0AF0E+0x69c||(a&0xe0ffff)==0xe0A9A8+0x69c||(a&0xe0ffff)==0xe0A9AA+0x69c||(a&0xe0ffff)==0xe0A9AC+0x69c) - // dprintf("w16: %06x, %04x @%06x", a&0xffffff, d, SekPc); - //if(a==0x200000) printf("w16: %04x @ %06x [%i]\n", d, SekPc, SekCyclesDoneT()); if ((a&0xe00000)==0xe00000) { *(u16 *)(Pico.ram+(a&0xfffe))=d; return; } // Ram log_io(a, 16, 1); @@ -488,7 +479,6 @@ static void CPU_CALL PicoWrite32(u32 a,u32 d) #if defined(EMU_C68K) && defined(EMU_M68K) lastwrite_cyc_d[lwp_cyc++&15] = d; #endif - //if(a==0x200000) printf("w32: %08x @ %06x [%i]\n", d, SekPc, SekCyclesDoneT()); if ((a&0xe00000)==0xe00000) { @@ -647,14 +637,17 @@ void PicoWriteCD8w (unsigned int a, unsigned char d); void PicoWriteCD16w(unsigned int a, unsigned short d); void PicoWriteCD32w(unsigned int a, unsigned int d); +/* it appears that Musashi doesn't always mask the unused bits */ unsigned int m68k_read_memory_8(unsigned int address) { - return (PicoMCD&1) ? PicoReadCD8w(address) : PicoRead8(address); + unsigned int d = (PicoMCD&1) ? PicoReadCD8w(address) : PicoRead8(address); + return d&0xff; } unsigned int m68k_read_memory_16(unsigned int address) { - return (PicoMCD&1) ? PicoReadCD16w(address) : PicoRead16(address); + unsigned int d = (PicoMCD&1) ? PicoReadCD16w(address) : PicoRead16(address); + return d&0xffff; } unsigned int m68k_read_memory_32(unsigned int address) diff --git a/Pico/Memory.s b/Pico/Memory.s index 88b8c43e..5555ac31 100644 --- a/Pico/Memory.s +++ b/Pico/Memory.s @@ -435,6 +435,19 @@ m_read8_ram: bx lr m_read8_above_rom: + @ might still be SRam (Micro Machines, HardBall '95) + ldr r2, =(SRam) + ldr r3, =(Pico+0x22200) + ldr r1, [r2, #8] @ SRam.end + cmp r0, r1 + bgt m_read8_ar_nosram + ldr r1, [r2, #4] @ SRam.start + cmp r0, r1 + blt m_read8_ar_nosram + ldrb r1, [r3, #0x11] @ Pico.m.sram_reg + tst r1, #5 + bne SRAMRead +m_read8_ar_nosram: stmfd sp!,{r0,lr} bic r0, r0, #1 mov r1, #8 @@ -566,7 +579,24 @@ m_read16_ram: bx lr m_read16_above_rom: + @ might still be SRam + ldr r2, =(SRam) + ldr r3, =(Pico+0x22200) + ldr r1, [r2, #8] @ SRam.end bic r0, r0, #1 + cmp r0, r1 + bgt m_read16_ar_nosram + ldr r1, [r2, #4] @ SRam.start + cmp r0, r1 + blt m_read16_ar_nosram + ldrb r1, [r3, #0x11] @ Pico.m.sram_reg + tst r1, #5 + beq m_read16_ar_nosram + stmfd sp!,{lr} + bl SRAMRead + orr r0, r0, r0, lsl #8 + ldmfd sp!,{pc} +m_read16_ar_nosram: mov r1, #16 b OtherRead16End diff --git a/Pico/MemoryCmn.c b/Pico/MemoryCmn.c index 33bad700..90b9e2de 100644 --- a/Pico/MemoryCmn.c +++ b/Pico/MemoryCmn.c @@ -221,6 +221,7 @@ void OtherWrite16(u32 a,u32 d) #ifndef _CD_MEMORY_C if (a >= SRam.start && a <= SRam.end) { + elprintf(EL_SRAMIO, "sram w16 [%06x] %04x @ %06x", a, d, SekPc); if ((a&0x16)==0x10) { // detected, not EEPROM, write not disabled u8 *pm=(u8 *)(SRam.data-SRam.start+a); *pm++=d>>8; @@ -228,7 +229,7 @@ void OtherWrite16(u32 a,u32 d) SRam.changed = 1; } else - SRAMWrite(a, d); // ?? + SRAMWrite(a, d); return; } #else diff --git a/Pico/Misc.c b/Pico/Misc.c index 8e89a4f2..38c381dd 100644 --- a/Pico/Misc.c +++ b/Pico/Misc.c @@ -131,54 +131,48 @@ const unsigned short vcounts[] = { // rarely used EEPROM SRAM code // known games which use this: // Wonder Boy in Monster World, Megaman - The Wily Wars (X24C01, 128 bytes) -// NFL Quarterback Club*, Frank Thomas Big Hurt Baseball (X24C04?) -// College Slam, Blockbuster World Video Game Championship II, NBA Jam (X24C04?) -// HardBall '95 -// the above sports games use addr 0x200000 for SCL line (handled in Memory.c) +// (see Genesis Plus for Wii/GC code and docs for info, +// full game list and better code). unsigned int lastSSRamWrite = 0xffff0000; -// sram_reg: LAtd sela (L=pending SCL, A=pending SDA, t=type(1==uses 0x200000 for SCL and 2K bytes), +// sram_reg: LAtd sela (L=pending SCL, A=pending SDA, t=(unused), // d=SRAM was detected (header or by access), s=started, e=save is EEPROM, l=old SCL, a=old SDA) PICO_INTERNAL void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA) { - unsigned int sreg = Pico.m.sram_reg, saddr = Pico.m.sram_addr, scyc = Pico.m.sram_cycle, ssa = Pico.m.sram_slave; + unsigned int sreg = Pico.m.sram_reg, saddr = Pico.m.eeprom_addr, scyc = Pico.m.eeprom_cycle, ssa = Pico.m.eeprom_slave; - //printf("EEPROM write %i\n", d&3); - sreg |= saddr&0xc000; // we store word count in add reg: dw?a aaaa ... (d=word count detected, w=words(0==use 2 words, else 1)) + elprintf(EL_EEPROM, "eeprom: scl/sda: %i/%i -> %i/%i, newtime=%i", (sreg&2)>>1, sreg&1, + (d&2)>>1, d&1, SekCyclesDoneT()-lastSSRamWrite); saddr&=0x1fff; if(sreg & d & 2) { // SCL was and is still high.. if((sreg & 1) && !(d&1)) { // ..and SDA went low, means it's a start command, so clear internal addr reg and clock counter - //dprintf("-start-"); - if(!(sreg&0x8000) && scyc >= 9) { - if(scyc != 28) sreg |= 0x4000; // 1 word - //dprintf("detected word count: %i", scyc==28 ? 2 : 1); - sreg |= 0x8000; - } + elprintf(EL_EEPROM, "eeprom: -start-"); //saddr = 0; scyc = 0; sreg |= 8; } else if(!(sreg & 1) && (d&1)) { // SDA went high == stop command - //dprintf("-stop-"); + elprintf(EL_EEPROM, "eeprom: -stop-"); sreg &= ~8; } } - else if((sreg & 8) && !(sreg & 2) && (d&2)) { + else if((sreg & 8) && !(sreg & 2) && (d&2)) + { // we are started and SCL went high - next cycle scyc++; // pre-increment - if(sreg & 0x20) { + if(SRam.eeprom_type) { // X24C02+ if((ssa&1) && scyc == 18) { scyc = 9; saddr++; // next address in read mode - if(sreg&0x4000) saddr&=0xff; else saddr&=0x1fff; // mask + /*if(SRam.eeprom_type==2) saddr&=0xff; else*/ saddr&=0x1fff; // mask } - else if((sreg&0x4000) && scyc == 27) scyc = 18; + else if(SRam.eeprom_type == 2 && scyc == 27) scyc = 18; else if(scyc == 36) scyc = 27; } else { // X24C01 @@ -187,21 +181,22 @@ PICO_INTERNAL void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA) if(saddr&1) { saddr+=2; saddr&=0xff; } // next addr in read mode } } - //dprintf("scyc: %i", scyc); + elprintf(EL_EEPROM, "eeprom: scyc: %i", scyc); } - else if((sreg & 8) && (sreg & 2) && !(d&2)) { + else if((sreg & 8) && (sreg & 2) && !(d&2)) + { // we are started and SCL went low (falling edge) - if(sreg & 0x20) { + if(SRam.eeprom_type) { // X24C02+ if(scyc == 9 || scyc == 18 || scyc == 27); // ACK cycles - else if( (!(sreg&0x4000) && scyc > 27) || ((sreg&0x4000) && scyc > 18) ) { + else if( (SRam.eeprom_type == 3 && scyc > 27) || (SRam.eeprom_type == 2 && scyc > 18) ) { if(!(ssa&1)) { // data write unsigned char *pm=SRam.data+saddr; *pm <<= 1; *pm |= d&1; if(scyc == 26 || scyc == 35) { saddr=(saddr&~0xf)|((saddr+1)&0xf); // only 4 (?) lowest bits are incremented - //dprintf("w done: %02x; addr inc: %x", *pm, saddr); + elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr, *pm); } SRam.changed = 1; } @@ -209,14 +204,17 @@ PICO_INTERNAL void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA) if(!(ssa&1)) { // we latch another addr bit saddr<<=1; - if(sreg&0x4000) saddr&=0xff; else saddr&=0x1fff; // mask + if(SRam.eeprom_type == 2) saddr&=0xff; else saddr&=0x1fff; // mask saddr|=d&1; - //if(scyc==17||scyc==26) dprintf("addr reg done: %x", saddr); + if(scyc==17||scyc==26) { + elprintf(EL_EEPROM, "eeprom: addr reg done: %x", saddr); + if(scyc==17&&SRam.eeprom_type==2) { saddr&=0xff; saddr|=(ssa<<7)&0x700; } // add device bits too + } } } else { // slave address ssa<<=1; ssa|=d&1; - //if(scyc==8) dprintf("slave done: %x", ssa); + if(scyc==8) elprintf(EL_EEPROM, "eeprom: slave done: %x", ssa); } } else { // X24C01 @@ -228,77 +226,89 @@ PICO_INTERNAL void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA) *pm <<= 1; *pm |= d&1; if(scyc == 17) { saddr=(saddr&0xf9)|((saddr+2)&6); // only 2 lowest bits are incremented - //dprintf("addr inc: %x", saddr>>1); + elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr>>1, *pm); } SRam.changed = 1; } } else { // we latch another addr bit saddr<<=1; saddr|=d&1; saddr&=0xff; - //if(scyc==8) dprintf("addr done: %x", saddr>>1); + if(scyc==8) elprintf(EL_EEPROM, "eeprom: addr done: %x", saddr>>1); } } } sreg &= ~3; sreg |= d&3; // remember SCL and SDA - Pico.m.sram_reg = (unsigned char) sreg; - Pico.m.sram_addr = (unsigned short)(saddr|(sreg&0xc000)); - Pico.m.sram_cycle= (unsigned char) scyc; - Pico.m.sram_slave= (unsigned char) ssa; + Pico.m.sram_reg = (unsigned char) sreg; + Pico.m.eeprom_cycle= (unsigned char) scyc; + Pico.m.eeprom_slave= (unsigned char) ssa; + Pico.m.eeprom_addr = (unsigned short)saddr; } PICO_INTERNAL_ASM unsigned int SRAMReadEEPROM(void) { - unsigned int shift, d=0; - unsigned int sreg, saddr, scyc, ssa; + unsigned int shift, d; + unsigned int sreg, saddr, scyc, ssa, interval; // flush last pending write SRAMWriteEEPROM(Pico.m.sram_reg>>6); - sreg = Pico.m.sram_reg; saddr = Pico.m.sram_addr&0x1fff; scyc = Pico.m.sram_cycle; ssa = Pico.m.sram_slave; -// if(!(sreg & 2) && (sreg&0x80)) scyc++; // take care of raising edge now to compensate lag + sreg = Pico.m.sram_reg; saddr = Pico.m.eeprom_addr&0x1fff; scyc = Pico.m.eeprom_cycle; ssa = Pico.m.eeprom_slave; + interval = SekCyclesDoneT()-lastSSRamWrite; + d = (sreg>>6)&1; // use SDA as "open bus" - if(SekCyclesDoneT()-lastSSRamWrite < 46) { - // data was just written, there was no time to respond (used by sports games) - d = (sreg>>6)&1; - } else if((sreg & 8) && scyc > 9 && scyc != 18 && scyc != 27) { + // NBA Jam is nasty enough to read raising the SCL and starting the new cycle. + // this is probably valid because data changes occur while SCL is low and data can be read + // before it's actual cycle begins. + if (!(sreg&0x80) && interval >= 24) { + elprintf(EL_EEPROM, "eeprom: early read, cycles=%i", interval); + scyc++; + } + + if (!(sreg & 8)); // not started, use open bus + else if (scyc == 9 || scyc == 18 || scyc == 27) { + elprintf(EL_EEPROM, "eeprom: r ack"); + d = 0; + } else if (scyc > 9 && scyc < 18) { // started and first command word received shift = 17-scyc; - if(sreg & 0x20) { + if (SRam.eeprom_type) { // X24C02+ - if(ssa&1) { - //dprintf("read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg); + if (ssa&1) { + elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg); + if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr]); d = (SRam.data[saddr]>>shift)&1; } } else { // X24C01 - if(saddr&1) { + if (saddr&1) { + elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr>>1, scyc, sreg); + if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr>>1]); d = (SRam.data[saddr>>1]>>shift)&1; } } } - //else dprintf("r ack"); - return d; + return (d << SRam.eeprom_bit_out); } PICO_INTERNAL void SRAMUpdPending(unsigned int a, unsigned int d) { - unsigned int sreg = Pico.m.sram_reg; - - if(!(a&1)) sreg|=0x20; - - if(sreg&0x20) { // address through 0x200000 - if(!(a&1)) { - sreg&=~0x80; - sreg|=d<<7; - } else { - sreg&=~0x40; - sreg|=(d<<6)&0x40; - } - } else { - sreg&=~0xc0; - sreg|=d<<6; + unsigned int d1, sreg = Pico.m.sram_reg; + + if (!((SRam.eeprom_abits^a)&1)) + { + // SCL + sreg &= ~0x80; + d1 = (d >> SRam.eeprom_bit_cl) & 1; + sreg |= d1<<7; + } + if (!(((SRam.eeprom_abits>>1)^a)&1)) + { + // SDA in + sreg &= ~0x40; + d1 = (d >> SRam.eeprom_bit_in) & 1; + sreg |= d1<<6; } Pico.m.sram_reg = (unsigned char) sreg; diff --git a/Pico/Pico.c b/Pico/Pico.c index 91d9331f..73321bce 100644 --- a/Pico/Pico.c +++ b/Pico/Pico.c @@ -19,7 +19,7 @@ int PicoAutoRgnOrder = 0; int emustatus = 0; void (*PicoWriteSound)(int len) = 0; // called once per frame at the best time to send sound buffer (PsndOut) to hardware -struct PicoSRAM SRam; +struct PicoSRAM SRam = {0,}; int z80startCycle, z80stopCycle; // in 68k cycles //int z80ExtraCycles = 0; int PicoPad[2]; // Joypads, format is SACB RLDU @@ -39,7 +39,6 @@ int PicoInit(void) PicoInitMCD(); SRam.data=0; - SRam.resize=1; return 0; } @@ -59,13 +58,10 @@ int PicoReset(int hard) unsigned int region=0; int support=0,hw=0,i=0; unsigned char pal=0; + unsigned char sram_reg=Pico.m.sram_reg; // must be preserved if (Pico.romsize<=0) return 1; - // setup correct memory map - if (PicoMCD & 1) - PicoMemSetupCD(); - else PicoMemSetup(); PicoMemReset(); SekReset(); // s68k doesn't have the TAS quirk, so we just globally set normal TAS handler in MCD mode (used by Batman games). @@ -149,56 +145,17 @@ int PicoReset(int hard) return 0; } - if(SRam.resize) { - int sram_size = 0; - if(SRam.data) free(SRam.data); SRam.data=0; - Pico.m.sram_reg = 0; - - if(*(Pico.rom+0x1B1) == 'R' && *(Pico.rom+0x1B0) == 'A') { - if(*(Pico.rom+0x1B2) & 0x40) { - // EEPROM - // what kind of EEPROMs are actually used? X24C02? X24C04? (X24C01 has only 128), but we will support up to 8K - SRam.start = PicoRead32(0x1B4) & ~1; // zero address is used for clock by some games - SRam.end = PicoRead32(0x1B8); - sram_size = 0x2000; - Pico.m.sram_reg = 4; - } else { - // normal SRAM - SRam.start = PicoRead32(0x1B4) & 0xFFFF00; - SRam.end = PicoRead32(0x1B8) | 1; - sram_size = SRam.end - SRam.start + 1; - } - Pico.m.sram_reg |= 0x10; // SRAM was detected - } - if(sram_size <= 0) { - // some games may have bad headers, like S&K and Sonic3 - SRam.start = 0x200000; - SRam.end = 0x203FFF; - sram_size = 0x004000; - } + // reset sram state; enable sram access by default if it doesn't overlap with ROM + Pico.m.sram_reg=sram_reg&0x14; + if (!(Pico.m.sram_reg&4) && Pico.romsize <= SRam.start) Pico.m.sram_reg |= 1; - // enable sram access by default if it doesn't overlap with ROM - if(Pico.romsize <= SRam.start) Pico.m.sram_reg |= 1; - SRam.reg_back = Pico.m.sram_reg; - - if(sram_size) { - SRam.data = (unsigned char *) calloc(sram_size, 1); - if(!SRam.data) return 1; - } - SRam.resize=0; - // Dino Dini's Soccer malfunctions if SRAM is not filled with 0xff - if (strncmp((char *)Pico.rom+0x150, "IDOND NI'I", 10) == 0) - memset(SRam.data, 0xff, sram_size); - elprintf(EL_STATUS, "sram: det: %i; eeprom: %i; start: %06x; end: %06x", - (Pico.m.sram_reg>>4)&1, (Pico.m.sram_reg>>2)&1, SRam.start, SRam.end); - } - - Pico.m.sram_reg = SRam.reg_back; // restore sram_reg - SRam.changed = 0; + elprintf(EL_STATUS, "sram: det: %i; eeprom: %i; start: %06x; end: %06x", + (Pico.m.sram_reg>>4)&1, (Pico.m.sram_reg>>2)&1, SRam.start, SRam.end); return 0; } + // dma2vram settings are just hacks to unglitch Legend of Galahad (needs <= 104 to work) // same for Outrunners (92-121, when active is set to 24) static const int dma_timings[] = { @@ -692,8 +649,8 @@ char *debugString(void) sprintf(dstrp, "mode set 4: %02x\n", (r=reg[0xC])); dstrp+=strlen(dstrp); sprintf(dstrp, "interlace: %i%i, cells: %i, shadow: %i\n", bit(r,2), bit(r,1), (r&0x80) ? 40 : 32, bit(r,3)); dstrp+=strlen(dstrp); - sprintf(dstrp, "scroll size: w: %i, h: %i SRAM: %i; eeprom: %i\n", reg[0x10]&3, (reg[0x10]&0x30)>>4, - bit(Pico.m.sram_reg, 4), bit(Pico.m.sram_reg, 2)); dstrp+=strlen(dstrp); + sprintf(dstrp, "scroll size: w: %i, h: %i SRAM: %i; eeprom: %i (%i)\n", reg[0x10]&3, (reg[0x10]&0x30)>>4, + bit(Pico.m.sram_reg, 4), bit(Pico.m.sram_reg, 2), SRam.eeprom_type); dstrp+=strlen(dstrp); sprintf(dstrp, "sram range: %06x-%06x, reg: %02x\n", SRam.start, SRam.end, Pico.m.sram_reg); dstrp+=strlen(dstrp); sprintf(dstrp, "pend int: v:%i, h:%i, vdp status: %04x\n", bit(pv->pending_ints,5), bit(pv->pending_ints,4), pv->status); dstrp+=strlen(dstrp); diff --git a/Pico/Pico.h b/Pico/Pico.h index 6adb7f55..296c113f 100644 --- a/Pico/Pico.h +++ b/Pico/Pico.h @@ -34,6 +34,7 @@ void mp3_update(int *buffer, int length, int stereo); // alt_renderer, 6button_gamepad, accurate_timing, accurate_sprites, // draw_no_32col_border, external_ym2612, enable_cd_pcm, enable_cd_cdda // enable_cd_gfx, cd_perfect_sync, soft_32col_scaling, enable_cd_ramcart +// disable_vdp_fifo extern int PicoOpt; extern int PicoVer; extern int PicoSkipFrame; // skip rendering frame, but still do sound (if enabled) and emulation stuff diff --git a/Pico/PicoInt.h b/Pico/PicoInt.h index 7af451c0..6105f611 100644 --- a/Pico/PicoInt.h +++ b/Pico/PicoInt.h @@ -171,9 +171,9 @@ struct PicoMisc unsigned char z80_fakeval; unsigned char pad0; unsigned char padDelay[2]; // 10 gamepad phase time outs, so we count a delay - unsigned short sram_addr; // EEPROM address register - unsigned char sram_cycle; // EEPROM SRAM cycle number - unsigned char sram_slave; // EEPROM slave word for X24C02 and better SRAMs + unsigned short eeprom_addr; // EEPROM address register + 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 char pad[2]; @@ -204,10 +204,14 @@ struct PicoSRAM unsigned char *data; // actual data unsigned int start; // start address in 68k address space unsigned int end; - unsigned char resize; // 0c: 1=SRAM size changed and needs to be reallocated on PicoReset - unsigned char reg_back; // copy of Pico.m.sram_reg to set after reset + unsigned char unused1; // 0c: unused + unsigned char unused2; unsigned char changed; - unsigned char pad; + unsigned char eeprom_type; // eeprom type: 0: 7bit (24C01), 2: device with 2 addr words (X24C02+), 3: dev with 3 addr words + unsigned char eeprom_abits; // eeprom access must be odd addr for: bit0 ~ cl, bit1 ~ out + unsigned char eeprom_bit_cl; // bit number for cl + unsigned char eeprom_bit_in; // bit number for in + unsigned char eeprom_bit_out; // bit number for out }; // MCD @@ -291,6 +295,9 @@ PICO_INTERNAL int PicoAreaUnpackCpu(unsigned char *cpu, int is_sub); PICO_INTERNAL int PicoCdSaveState(void *file); PICO_INTERNAL int PicoCdLoadState(void *file); +// Cart.c +PICO_INTERNAL void PicoCartDetect(void); + // Draw.c PICO_INTERNAL int PicoLine(int scan); PICO_INTERNAL void PicoFrameStart(void); @@ -397,6 +404,10 @@ PICO_INTERNAL void z80_exit(void); #define EL_VDPDMA 0x0040 /* VDP DMA transfers and their timing */ #define EL_BUSREQ 0x0080 /* z80 busreq r/w */ #define EL_Z80BNK 0x0100 /* z80 i/o through bank area */ +#define EL_SRAMIO 0x0200 /* sram i/o */ +#define EL_EEPROM 0x0400 /* eeprom debug */ +#define EL_UIO 0x0800 /* unmapped i/o */ +#define EL_IO 0x1000 /* all i/o */ #define EL_STATUS 0x4000 /* status messages */ #define EL_ANOMALY 0x8000 /* some unexpected conditions */ diff --git a/Pico/VideoPort.c b/Pico/VideoPort.c index cc1583a0..6f41dfaa 100644 --- a/Pico/VideoPort.c +++ b/Pico/VideoPort.c @@ -337,7 +337,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d) else { // preliminary FIFO emulation for Chaos Engine, The (E) - if(!(pvid->status&8) && (pvid->reg[1]&0x40) && Pico.m.scanline!=-1) // active display, accurate mode? + if(!(pvid->status&8) && (pvid->reg[1]&0x40) && Pico.m.scanline!=-1 && !(PicoOpt&0x10000)) // active display, accurate mode? { pvid->status&=~0x200; // FIFO no longer empty pvid->lwrite_cnt++; diff --git a/platform/gp2x/Makefile b/platform/gp2x/Makefile index c6f9fe93..1458a34b 100644 --- a/platform/gp2x/Makefile +++ b/platform/gp2x/Makefile @@ -32,7 +32,12 @@ use_cyclone = 1 endif DEFINC = -I../.. -I. -DARM -D__GP2X__ -D_UNZIP_SUPPORT # -DBENCHMARK -COPT_COMMON = -static -Wall -O2 -ftracer -fstrength-reduce -fomit-frame-pointer -fstrict-aliasing -ffast-math -Winline +COPT_COMMON = -static -Wall -Winline +ifeq ($(DEBUG),) +COPT_COMMON += -O2 -ftracer -fstrength-reduce -fomit-frame-pointer -fstrict-aliasing -ffast-math +else +COPT_COMMON += -ggdb +endif ifeq "$(profile)" "1" COPT_COMMON += -fprofile-generate endif diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index adb10a35..3096edd9 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -26,6 +26,7 @@ #include #include +//#define PFRAMES #ifdef BENCHMARK #define OSD_FPS_X 220 @@ -348,11 +349,11 @@ int emu_ReloadRom(void) } // additional movie stuff - if(movie_data) { + if (movie_data) { if(movie_data[0x14] == '6') PicoOpt |= 0x20; // 6 button pad else PicoOpt &= ~0x20; - PicoOpt |= 0x40; // accurate timing + PicoOpt |= 0x10040; // accurate timing, no VDP fifo timing if(movie_data[0xF] >= 'A') { if(movie_data[0x16] & 0x80) { PicoRegionOverride = 8; @@ -367,6 +368,7 @@ int emu_ReloadRom(void) } else { + PicoOpt &= ~0x10000; if(Pico.m.pal) { strcpy(noticeMsg, "PAL SYSTEM / 50 FPS"); } else { @@ -1185,17 +1187,18 @@ void emu_Loop(void) // prepare sound stuff if(currentConfig.EmuOpt & 4) { int snd_excess_add; - if(PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old || crashed_940) { + if (PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old || + ((PicoOpt&0x200) && crashed_940)) { /* if 940 is turned off, we need it to be put back to sleep */ if (!(PicoOpt&0x200) && ((PicoOpt^PicoOpt_old)&0x200)) { Reset940(1, 2); Pause940(1); } - sound_rerate(1); + sound_rerate(Pico.m.frame_count ? 1 : 0); } - //excess_samples = PsndRate - PsndLen*target_fps; snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps; - printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal); + printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", + PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal); gp2x_start_sound(PsndRate, 16, (PicoOpt&8)>>3); gp2x_sound_volume(currentConfig.volume, currentConfig.volume); PicoWriteSound = updateSound; @@ -1307,6 +1310,9 @@ void emu_Loop(void) if (frames_shown > frames_done) frames_shown = frames_done; } } +#ifdef PFRAMES + sprintf(fpsbuff, "%i", Pico.m.frame_count); +#endif lim_time = (frames_done+1) * target_frametime + vsync_offset; if(currentConfig.Frameskip >= 0) { // frameskip enabled @@ -1571,7 +1577,7 @@ int emu_SaveLoadGame(int load, int sram) } } else { sram_size = SRam.end-SRam.start+1; - if(SRam.reg_back & 4) sram_size=0x2000; + if(Pico.m.sram_reg & 4) sram_size=0x2000; sram_data = SRam.data; } if (!sram_data) return 0; // SRam forcefully disabled for this game diff --git a/platform/gp2x/port_config.h b/platform/gp2x/port_config.h index 7bfe2474..02a3706b 100644 --- a/platform/gp2x/port_config.h +++ b/platform/gp2x/port_config.h @@ -13,7 +13,7 @@ #define CAN_HANDLE_240_LINES 1 // logging emu events -#define EL_LOGMASK 0 // (EL_STATUS|EL_ANOMALY) // xffff +#define EL_LOGMASK 0 // (EL_STATUS|EL_ANOMALY|EL_UIO) // xffff //#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__) #define dprintf(x...) diff --git a/platform/linux/port_config.h b/platform/linux/port_config.h index 2e0eb54a..0d439c49 100644 --- a/platform/linux/port_config.h +++ b/platform/linux/port_config.h @@ -13,7 +13,7 @@ // pico.c #define CAN_HANDLE_240_LINES 1 -#define EL_LOGMASK (EL_ANOMALY|EL_STATUS|EL_VDPDMA|EL_ASVDP|EL_SR) // |EL_BUSREQ|EL_Z80BNK) +#define EL_LOGMASK (EL_ANOMALY|EL_STATUS|EL_SRAMIO|EL_EEPROM) // EL_VDPDMA|EL_ASVDP|EL_SR) // |EL_BUSREQ|EL_Z80BNK) //#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__) #define dprintf(x...) diff --git a/platform/readme.txt b/platform/readme.txt index ad49e377..d32eda67 100644 --- a/platform/readme.txt +++ b/platform/readme.txt @@ -227,13 +227,15 @@ Symbian: Changelog --------- -1.332 +1.34 + Some new optimizations in memory handlers, and for shadow/hilight mode. + Added some hacks to make more games work without enabling "accurate timing". - * Fixed hang of NBA Jam (ingame saves do not work though). * Adjusted timing for "accurate timing" mode and added preliminary VDP FIFO emulation. Fixes Double Dragon 2, tearing in Chaos Engine and some other games. * Fixed a few games not having sound at startup. + * Updated serial EEPROM code to support more games. Thanks to EkeEke for + providing info about additional EEPROM types and game mappers. + * The above change fixed hang of NBA Jam. 1.33 * Updated Cyclone core to 0.0088. -- 2.39.5