Permalink
Browse files

Z80: Fixed emulation of R register (fixes 'Bubble Bobble', 'Hong Kil …

…Dong' among others), fixed HALT timing, fixed CPDR [Calindro]
  • Loading branch information...
1 parent 820fafc commit 5768f5a36d8f3372dc73a334f07bb4d6d63f82a9 @ocornut committed Mar 31, 2015
View
@@ -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)
View
@@ -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]
View
@@ -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]
@@ -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",
View
@@ -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);
View
@@ -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);
@@ -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:
@@ -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);
@@ -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]++;
@@ -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() */

0 comments on commit 5768f5a

Please sign in to comment.