diff --git a/meka/TODO.txt b/meka/TODO.txt index b2bf9b63..d3fbeb55 100644 --- a/meka/TODO.txt +++ b/meka/TODO.txt @@ -877,7 +877,6 @@ doing them now and some are quick work. - Out Run: PSG noise leftover in FM mode. - Daffy Duck in Hollywood menus (verify on a real PAL/SECAM system) - Sangokushi 3: try to finds why demonstration is not the same as on a real system (R?) - - Bubble Bobble lockups?!! (on level 3/4/5 ?) ARGH - Championship Hockey: reset, glitches ? See on real system. - Fix formula 1 !! ? (any moer problem?) - 20-em-1 timing problem (currently patched) diff --git a/meka/history.txt b/meka/history.txt index 3dace3e7..b1e39645 100644 --- a/meka/history.txt +++ b/meka/history.txt @@ -36,6 +36,9 @@ They are usually of 2 kinds: could be implemented for other systems/countries after we've done more research. [Omar] - Added support for mirrored VDP ports in $80..$BF range, as required by some Korean games such as 'Pooyan', 'Sky Jaguar' or 'E.I.'. [Omar] + - Z80: Fixed emulation of R register (fixes 'Bubble Bobble', 'Hong Kil Dong' among others) [Calindro] + - Z80: Fixed CPDR running fully and ignoring interrupts. [Calindro] + - Z80: Fixed HALT timing. [Calindro] - Emu2413: Fixed commands 0x26-0x28 from turning off the drums. [ValleyBell] - Debugger: - Added support for setting breakpoint from ROM addresses (perform reverse mapping to validate address). [Omar] diff --git a/meka/meka.pat b/meka/meka.pat index c88d516a..b140c09c 100644 --- a/meka/meka.pat +++ b/meka/meka.pat @@ -195,8 +195,7 @@ ROM[0000] = C3 ; Disable the first controller port read, done outside of a loop. ; Inputs are updated by interrupt, and at the time the value was loaded, ; interrupts did not happens. It is very tricky and probably due to bad -; programming and timing issues, but I don't know why no emulator seems -; to do it well. +; programming and timing issues, but I don't know why it doesn't emulate well. ; Author: Bock ;----------------------------------------------------------------------------- [crc32: f0f35c22] diff --git a/meka/srcs/datadump.c b/meka/srcs/datadump.c index 5762bca1..ea3a2c02 100644 --- a/meka/srcs/datadump.c +++ b/meka/srcs/datadump.c @@ -205,7 +205,7 @@ static int DataDump_Handler_Ascii_CPURegs (FILE *f_dump, int pos, const u8 *dat DataDump_Handler_Ascii_CPURegs_Reg (f_dump, "DE'", R->DE1.W, NULL); DataDump_Handler_Ascii_CPURegs_Reg (f_dump, "HL'", R->HL1.W, NULL); fprintf(f_dump, "%-3s = $%02X\n", "I", (byte)(R->I)); - fprintf(f_dump, "%-3s = $%02X\n", "R", (byte)(R->R - R->ICount)); // This is the algorythm to pseudo randomize R in opcode LD_A_R + fprintf(f_dump, "%-3s = $%02X\n", "R", (byte)((R->R & 0x7F)|(R->R7))); fprintf(f_dump, "IPeriod = %d\n", R->IPeriod); fprintf(f_dump, "ICount = %d\n", R->ICount); fprintf(f_dump, "IFF1 = %d\nIFF2 = %d\nIM = %d\nEI = %d\nHALT = %d\n", diff --git a/meka/srcs/debugger.c b/meka/srcs/debugger.c index ca990a8d..a936dc98 100644 --- a/meka/srcs/debugger.c +++ b/meka/srcs/debugger.c @@ -1046,7 +1046,7 @@ const char * Debugger_BreakPoint_GetTypeName(t_debugger_breakpoin return ("XXX"); } -void Debugger_BreakPoint_GetSummaryLine(t_debugger_breakpoint *breakpoint, char *buf) +void Debugger_BreakPoint_GetSummaryLine(t_debugger_breakpoint *breakpoint, char *buf) { char addr_string[16]; int bus_size; @@ -2135,8 +2135,8 @@ static int Debugger_GetZ80SummaryLines(char *** const lines_out, bool simple) cpu->AF.W, cpu->BC.W, cpu->DE.W, cpu->HL.W, cpu->IX.W, cpu->IY.W); // Line 2 - sprintf(line2, "PC:%04X SP:%04X Flags:[%s] %s%s", - cpu->PC.W, cpu->SP.W, flags, + sprintf(line2, "PC:%04X SP:%04X Flags:[%s] R:%02X %s%s", + cpu->PC.W, cpu->SP.W, flags, (cpu->R & 0x7F) | (cpu->R7), (cpu->IFF & IFF_1) ? "EI" : "DI", (cpu->IFF & IFF_HALT) ? " HALT" : ""); return (2); @@ -2152,8 +2152,8 @@ static int Debugger_GetZ80SummaryLines(char *** const lines_out, bool simple) cpu->AF1.W, cpu->BC1.W, cpu->DE1.W, cpu->HL1.W); // Line 3 - sprintf(line3, "PC:%04X SP:%04X Flags:[%s] %s%s", - cpu->PC.W, cpu->SP.W, flags, + sprintf(line3, "PC:%04X SP:%04X Flags:[%s] R:%02X %s%s", + cpu->PC.W, cpu->SP.W, flags, (cpu->R & 0x7F) | (cpu->R7), (cpu->IFF & IFF_1) ? "EI" : "DI", (cpu->IFF & IFF_HALT) ? " HALT" : ""); return (3); diff --git a/meka/srcs/saves.c b/meka/srcs/saves.c index d9138549..94b65827 100644 --- a/meka/srcs/saves.c +++ b/meka/srcs/saves.c @@ -238,7 +238,10 @@ int Save_Game_MSV (FILE *f) fwrite (&g_media_rom.crc32, sizeof (u32), 1, f); // Write 'sms' structure (misc stuff) + sms.R.R = (sms.R.R & 0x7F) | (sms.R.R7); + sms.R.R7 = 0; fwrite (&sms, sizeof (struct SMS_TYPE), 1, f); + sms.R.R7 = (sms.R.R & 0x80); const int mappers_regs_to_save = (g_machine.mapper_regs_count <= 4) ? 4 : g_machine.mapper_regs_count; fwrite (&g_machine.mapper_regs[0], sizeof(u8), mappers_regs_to_save, f); @@ -368,6 +371,7 @@ int Load_Game_MSV(FILE *f) u16 trap = sms.R.Trap; u8 trace = sms.R.Trace; fread (&sms, sizeof(struct SMS_TYPE), 1, f); + sms.R.R7 = (sms.R.R & 0x80); sms.R.Trap = trap; sms.R.Trace = trace; } @@ -575,6 +579,7 @@ int Load_Game_MSD (FILE *f) fread (&sms.R.SP.B.h, 1, 1, f); fread (&sms.R.I, 1, 1, f); fread (&sms.R.R, 1, 1, f); + sms.R.R7 = sms.R.R & 0x80; fread (&sms.R.DE.B.l, 1, 1, f); fread (&sms.R.DE.B.h, 1, 1, f); fread (&sms.R.BC1.B.l, 1, 1, f); diff --git a/meka/srcs/z80marat/Codes.h b/meka/srcs/z80marat/Codes.h index daa8e7e8..9e4635b5 100644 --- a/meka/srcs/z80marat/Codes.h +++ b/meka/srcs/z80marat/Codes.h @@ -220,8 +220,15 @@ case INA: I=RdZ80(R->PC.W++);R->AF.B.h=InZ80(I);break; case HALT: R->PC.W--; R->IFF|=IFF_HALT; - R->IBackup=0; - R->ICount=0; + if (R->ICount > 0) + { + // Update R register + // Avoid % on negative numbers + const int cycles = Cycles[I]; + R->R += R->ICount / cycles; + R->ICount %= cycles; + R->IBackup = R->ICount; + } break; case DI: diff --git a/meka/srcs/z80marat/CodesED.h b/meka/srcs/z80marat/CodesED.h index 34da5ed9..74cb61de 100644 --- a/meka/srcs/z80marat/CodesED.h +++ b/meka/srcs/z80marat/CodesED.h @@ -96,14 +96,16 @@ case LD_A_I: break; case LD_A_R: - R->R++; - R->AF.B.h=(byte)(R->R-R->ICount); + R->AF.B.h = R->R7 | (R->R & 0x7f); // Msg(0, "At PC=%04X: LD A,R, returning %02X", R->PC.W, R->AF.B.h); R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&IFF_2? P_FLAG:0)|ZSTable[R->AF.B.h]; break; case LD_I_A: R->I=R->AF.B.h;break; -case LD_R_A: break; +case LD_R_A: + R->R = R->AF.B.h; // We can do & 0x7f here but we're ignoring 7th bit of this register anyways so it doesn't matter + R->R7 = R->AF.B.h & 0x80; + break; case DB_4E: case DB_66: case DB_6E: // Undocumented case IM_0: R->IFF&=~(IFF_IM1|IFF_IM2);break; @@ -150,6 +152,7 @@ case INI: break; case INIR: + R->R += 2 * (R->ICount / 21); do { WrZ80(R->HL.W++,InZ80(R->BC.B.l)); @@ -167,6 +170,7 @@ case IND: break; case INDR: + R->R += 2 * (R->ICount / 21); do { WrZ80(R->HL.W--,InZ80(R->BC.B.l)); @@ -185,6 +189,7 @@ case OUTI: break; case OTIR: + R->R += 2 * (R->ICount / 21); do { I=RdZ80(R->HL.W++); @@ -213,6 +218,7 @@ case OUTD: break; case OTDR: + R->R += 2 * (R->ICount / 21); do { I=RdZ80(R->HL.W--); @@ -240,6 +246,7 @@ case LDI: break; case LDIR: + R->R += 2 * (R->ICount / 21); do { WrZ80(R->DE.W++, RdZ80(R->HL.W++)); @@ -258,6 +265,7 @@ case LDD: break; case LDDR: + R->R += 2 * (R->ICount / 21); do { WrZ80(R->DE.W--,RdZ80(R->HL.W--)); @@ -279,6 +287,7 @@ case CPI: break; case CPIR: + R->R += 2 * (R->ICount / 21); do { I=RdZ80(R->HL.W++); @@ -302,13 +311,14 @@ case CPD: break; case CPDR: + R->R += 2 * (R->ICount / 21); do { I=RdZ80(R->HL.W--); J.B.l=R->AF.B.h-I; R->BC.W--;R->ICount-=21; } - while(R->BC.W&&J.B.l); + while(R->BC.W&&J.B.l&&(R->ICount>0)); R->AF.B.l = N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]| ((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0); diff --git a/meka/srcs/z80marat/Z80.c b/meka/srcs/z80marat/Z80.c index 5496ced9..a53ae898 100644 --- a/meka/srcs/z80marat/Z80.c +++ b/meka/srcs/z80marat/Z80.c @@ -240,6 +240,7 @@ static void CodesCB(register Z80 *R) register byte I; I = RdZ80(R->PC.W++); + R->R++; R->ICount -= CyclesCB[I]; #ifdef MEKA_Z80_OPCODES_USAGE Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_CB][I]++; @@ -315,6 +316,7 @@ static void CodesED(register Z80 *R) register pair J; I = RdZ80(R->PC.W++); + R->R++; R->ICount -= CyclesED[I]; #ifdef MEKA_Z80_OPCODES_USAGE Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_ED][I]++; @@ -346,6 +348,7 @@ static void CodesDD(register Z80 *R) #define XX IX I = RdZ80(R->PC.W++); + R->R++; R->ICount -= CyclesXX[I]; #ifdef MEKA_Z80_OPCODES_USAGE Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_DD][I]++; @@ -378,6 +381,7 @@ static void CodesFD(register Z80 *R) #define XX IY I = RdZ80(R->PC.W++); + R->R++; R->ICount -= CyclesXX[I]; #ifdef MEKA_Z80_OPCODES_USAGE Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_FD][I]++; @@ -423,6 +427,8 @@ void ResetZ80(Z80 *R) R->IY.W = 0x0000; R->I = 0x00; R->IFF = 0x00; + R->R = 0x00; + R->R7 = 0x00; R->ICount = R->IPeriod; R->IRequest = INT_NONE; } @@ -649,6 +655,7 @@ word RunZ80_Debugging(Z80 *R) // Execute instruction I = RdZ80 (R->PC.W ++); + R->R++; R->ICount -= Cycles[I]; #ifdef MEKA_Z80_OPCODES_USAGE Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_NONE][I]++; diff --git a/meka/srcs/z80marat/Z80.h b/meka/srcs/z80marat/Z80.h index 31b79598..dc411967 100644 --- a/meka/srcs/z80marat/Z80.h +++ b/meka/srcs/z80marat/Z80.h @@ -81,7 +81,7 @@ typedef struct pair AF, BC, DE, HL, IX, IY, PC, SP; /* Main registers */ pair AF1, BC1, DE1, HL1; /* Shadow registers */ byte IFF, I; /* Interrupt registers */ - byte R; /* Refresh register */ + byte R, R7; /* Refresh register */ /* Copy of 7th bit of R assigned by user */ int IPeriod, ICount; /* Set IPeriod to number of CPU cycles */ /* between calls to LoopZ80() */