Skip to content

Commit

Permalink
Z80: Fixed emulation of R register (fixes 'Bubble Bobble', 'Hong Kil …
Browse files Browse the repository at this point in the history
…Dong' among others), fixed HALT timing, fixed CPDR [Calindro]
  • Loading branch information
ocornut committed Mar 31, 2015
1 parent 820fafc commit 5768f5a
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 16 deletions.
1 change: 0 additions & 1 deletion meka/TODO.txt
Expand Up @@ -877,7 +877,6 @@ doing them now and some are quick work.
- Out Run: PSG noise leftover in FM mode. - Out Run: PSG noise leftover in FM mode.
- Daffy Duck in Hollywood menus (verify on a real PAL/SECAM system) - 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?) - 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. - Championship Hockey: reset, glitches ? See on real system.
- Fix formula 1 !! ? (any moer problem?) - Fix formula 1 !! ? (any moer problem?)
- 20-em-1 timing problem (currently patched) - 20-em-1 timing problem (currently patched)
Expand Down
3 changes: 3 additions & 0 deletions meka/history.txt
Expand Up @@ -36,6 +36,9 @@ They are usually of 2 kinds:
could be implemented for other systems/countries after we've done more research. [Omar] 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 - 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] 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] - Emu2413: Fixed commands 0x26-0x28 from turning off the drums. [ValleyBell]
- Debugger: - Debugger:
- Added support for setting breakpoint from ROM addresses (perform reverse mapping to validate address). [Omar] - Added support for setting breakpoint from ROM addresses (perform reverse mapping to validate address). [Omar]
Expand Down
3 changes: 1 addition & 2 deletions meka/meka.pat
Expand Up @@ -195,8 +195,7 @@ ROM[0000] = C3
; Disable the first controller port read, done outside of a loop. ; Disable the first controller port read, done outside of a loop.
; Inputs are updated by interrupt, and at the time the value was loaded, ; 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 ; 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 ; programming and timing issues, but I don't know why it doesn't emulate well.
; to do it well.
; Author: Bock ; Author: Bock
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
[crc32: f0f35c22] [crc32: f0f35c22]
Expand Down
2 changes: 1 addition & 1 deletion meka/srcs/datadump.c
Expand Up @@ -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, "DE'", R->DE1.W, NULL);
DataDump_Handler_Ascii_CPURegs_Reg (f_dump, "HL'", R->HL1.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", "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, "IPeriod = %d\n", R->IPeriod);
fprintf(f_dump, "ICount = %d\n", R->ICount); fprintf(f_dump, "ICount = %d\n", R->ICount);
fprintf(f_dump, "IFF1 = %d\nIFF2 = %d\nIM = %d\nEI = %d\nHALT = %d\n", fprintf(f_dump, "IFF1 = %d\nIFF2 = %d\nIM = %d\nEI = %d\nHALT = %d\n",
Expand Down
10 changes: 5 additions & 5 deletions meka/srcs/debugger.c
Expand Up @@ -1046,7 +1046,7 @@ const char * Debugger_BreakPoint_GetTypeName(t_debugger_breakpoin
return ("XXX"); 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]; char addr_string[16];
int bus_size; int bus_size;
Expand Down Expand Up @@ -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); cpu->AF.W, cpu->BC.W, cpu->DE.W, cpu->HL.W, cpu->IX.W, cpu->IY.W);


// Line 2 // Line 2
sprintf(line2, "PC:%04X SP:%04X Flags:[%s] %s%s", sprintf(line2, "PC:%04X SP:%04X Flags:[%s] R:%02X %s%s",
cpu->PC.W, cpu->SP.W, flags, cpu->PC.W, cpu->SP.W, flags, (cpu->R & 0x7F) | (cpu->R7),
(cpu->IFF & IFF_1) ? "EI" : "DI", (cpu->IFF & IFF_HALT) ? " HALT" : ""); (cpu->IFF & IFF_1) ? "EI" : "DI", (cpu->IFF & IFF_HALT) ? " HALT" : "");


return (2); return (2);
Expand All @@ -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); cpu->AF1.W, cpu->BC1.W, cpu->DE1.W, cpu->HL1.W);


// Line 3 // Line 3
sprintf(line3, "PC:%04X SP:%04X Flags:[%s] %s%s", sprintf(line3, "PC:%04X SP:%04X Flags:[%s] R:%02X %s%s",
cpu->PC.W, cpu->SP.W, flags, cpu->PC.W, cpu->SP.W, flags, (cpu->R & 0x7F) | (cpu->R7),
(cpu->IFF & IFF_1) ? "EI" : "DI", (cpu->IFF & IFF_HALT) ? " HALT" : ""); (cpu->IFF & IFF_1) ? "EI" : "DI", (cpu->IFF & IFF_HALT) ? " HALT" : "");


return (3); return (3);
Expand Down
5 changes: 5 additions & 0 deletions meka/srcs/saves.c
Expand Up @@ -238,7 +238,10 @@ int Save_Game_MSV (FILE *f)
fwrite (&g_media_rom.crc32, sizeof (u32), 1, f); fwrite (&g_media_rom.crc32, sizeof (u32), 1, f);


// Write 'sms' structure (misc stuff) // 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); 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; 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); fwrite (&g_machine.mapper_regs[0], sizeof(u8), mappers_regs_to_save, f);
Expand Down Expand Up @@ -368,6 +371,7 @@ int Load_Game_MSV(FILE *f)
u16 trap = sms.R.Trap; u16 trap = sms.R.Trap;
u8 trace = sms.R.Trace; u8 trace = sms.R.Trace;
fread (&sms, sizeof(struct SMS_TYPE), 1, f); fread (&sms, sizeof(struct SMS_TYPE), 1, f);
sms.R.R7 = (sms.R.R & 0x80);
sms.R.Trap = trap; sms.R.Trap = trap;
sms.R.Trace = trace; sms.R.Trace = trace;
} }
Expand Down Expand Up @@ -575,6 +579,7 @@ int Load_Game_MSD (FILE *f)
fread (&sms.R.SP.B.h, 1, 1, f); fread (&sms.R.SP.B.h, 1, 1, f);
fread (&sms.R.I, 1, 1, f); fread (&sms.R.I, 1, 1, f);
fread (&sms.R.R, 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.l, 1, 1, f);
fread (&sms.R.DE.B.h, 1, 1, f); fread (&sms.R.DE.B.h, 1, 1, f);
fread (&sms.R.BC1.B.l, 1, 1, f); fread (&sms.R.BC1.B.l, 1, 1, f);
Expand Down
11 changes: 9 additions & 2 deletions meka/srcs/z80marat/Codes.h
Expand Up @@ -220,8 +220,15 @@ case INA: I=RdZ80(R->PC.W++);R->AF.B.h=InZ80(I);break;
case HALT: case HALT:
R->PC.W--; R->PC.W--;
R->IFF|=IFF_HALT; R->IFF|=IFF_HALT;
R->IBackup=0; if (R->ICount > 0)
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; break;


case DI: case DI:
Expand Down
18 changes: 14 additions & 4 deletions meka/srcs/z80marat/CodesED.h
Expand Up @@ -96,14 +96,16 @@ case LD_A_I:
break; break;


case LD_A_R: case LD_A_R:
R->R++; R->AF.B.h = R->R7 | (R->R & 0x7f);
R->AF.B.h=(byte)(R->R-R->ICount);
// Msg(0, "At PC=%04X: LD A,R, returning %02X", R->PC.W, R->AF.B.h); // 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]; R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&IFF_2? P_FLAG:0)|ZSTable[R->AF.B.h];
break; break;


case LD_I_A: R->I=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 DB_4E: case DB_66: case DB_6E: // Undocumented
case IM_0: R->IFF&=~(IFF_IM1|IFF_IM2);break; case IM_0: R->IFF&=~(IFF_IM1|IFF_IM2);break;
Expand Down Expand Up @@ -150,6 +152,7 @@ case INI:
break; break;


case INIR: case INIR:
R->R += 2 * (R->ICount / 21);
do do
{ {
WrZ80(R->HL.W++,InZ80(R->BC.B.l)); WrZ80(R->HL.W++,InZ80(R->BC.B.l));
Expand All @@ -167,6 +170,7 @@ case IND:
break; break;


case INDR: case INDR:
R->R += 2 * (R->ICount / 21);
do do
{ {
WrZ80(R->HL.W--,InZ80(R->BC.B.l)); WrZ80(R->HL.W--,InZ80(R->BC.B.l));
Expand All @@ -185,6 +189,7 @@ case OUTI:
break; break;


case OTIR: case OTIR:
R->R += 2 * (R->ICount / 21);
do do
{ {
I=RdZ80(R->HL.W++); I=RdZ80(R->HL.W++);
Expand Down Expand Up @@ -213,6 +218,7 @@ case OUTD:
break; break;


case OTDR: case OTDR:
R->R += 2 * (R->ICount / 21);
do do
{ {
I=RdZ80(R->HL.W--); I=RdZ80(R->HL.W--);
Expand Down Expand Up @@ -240,6 +246,7 @@ case LDI:
break; break;


case LDIR: case LDIR:
R->R += 2 * (R->ICount / 21);
do do
{ {
WrZ80(R->DE.W++, RdZ80(R->HL.W++)); WrZ80(R->DE.W++, RdZ80(R->HL.W++));
Expand All @@ -258,6 +265,7 @@ case LDD:
break; break;


case LDDR: case LDDR:
R->R += 2 * (R->ICount / 21);
do do
{ {
WrZ80(R->DE.W--,RdZ80(R->HL.W--)); WrZ80(R->DE.W--,RdZ80(R->HL.W--));
Expand All @@ -279,6 +287,7 @@ case CPI:
break; break;


case CPIR: case CPIR:
R->R += 2 * (R->ICount / 21);
do do
{ {
I=RdZ80(R->HL.W++); I=RdZ80(R->HL.W++);
Expand All @@ -302,13 +311,14 @@ case CPD:
break; break;


case CPDR: case CPDR:
R->R += 2 * (R->ICount / 21);
do do
{ {
I=RdZ80(R->HL.W--); I=RdZ80(R->HL.W--);
J.B.l=R->AF.B.h-I; J.B.l=R->AF.B.h-I;
R->BC.W--;R->ICount-=21; 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 = R->AF.B.l =
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.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); ((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0);
Expand Down
7 changes: 7 additions & 0 deletions meka/srcs/z80marat/Z80.c
Expand Up @@ -240,6 +240,7 @@ static void CodesCB(register Z80 *R)
register byte I; register byte I;


I = RdZ80(R->PC.W++); I = RdZ80(R->PC.W++);
R->R++;
R->ICount -= CyclesCB[I]; R->ICount -= CyclesCB[I];
#ifdef MEKA_Z80_OPCODES_USAGE #ifdef MEKA_Z80_OPCODES_USAGE
Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_CB][I]++; Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_CB][I]++;
Expand Down Expand Up @@ -315,6 +316,7 @@ static void CodesED(register Z80 *R)
register pair J; register pair J;


I = RdZ80(R->PC.W++); I = RdZ80(R->PC.W++);
R->R++;
R->ICount -= CyclesED[I]; R->ICount -= CyclesED[I];
#ifdef MEKA_Z80_OPCODES_USAGE #ifdef MEKA_Z80_OPCODES_USAGE
Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_ED][I]++; Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_ED][I]++;
Expand Down Expand Up @@ -346,6 +348,7 @@ static void CodesDD(register Z80 *R)


#define XX IX #define XX IX
I = RdZ80(R->PC.W++); I = RdZ80(R->PC.W++);
R->R++;
R->ICount -= CyclesXX[I]; R->ICount -= CyclesXX[I];
#ifdef MEKA_Z80_OPCODES_USAGE #ifdef MEKA_Z80_OPCODES_USAGE
Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_DD][I]++; Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_DD][I]++;
Expand Down Expand Up @@ -378,6 +381,7 @@ static void CodesFD(register Z80 *R)


#define XX IY #define XX IY
I = RdZ80(R->PC.W++); I = RdZ80(R->PC.W++);
R->R++;
R->ICount -= CyclesXX[I]; R->ICount -= CyclesXX[I];
#ifdef MEKA_Z80_OPCODES_USAGE #ifdef MEKA_Z80_OPCODES_USAGE
Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_FD][I]++; Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_FD][I]++;
Expand Down Expand Up @@ -423,6 +427,8 @@ void ResetZ80(Z80 *R)
R->IY.W = 0x0000; R->IY.W = 0x0000;
R->I = 0x00; R->I = 0x00;
R->IFF = 0x00; R->IFF = 0x00;
R->R = 0x00;
R->R7 = 0x00;
R->ICount = R->IPeriod; R->ICount = R->IPeriod;
R->IRequest = INT_NONE; R->IRequest = INT_NONE;
} }
Expand Down Expand Up @@ -649,6 +655,7 @@ word RunZ80_Debugging(Z80 *R)


// Execute instruction // Execute instruction
I = RdZ80 (R->PC.W ++); I = RdZ80 (R->PC.W ++);
R->R++;
R->ICount -= Cycles[I]; R->ICount -= Cycles[I];
#ifdef MEKA_Z80_OPCODES_USAGE #ifdef MEKA_Z80_OPCODES_USAGE
Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_NONE][I]++; Z80_Opcodes_Usage [MEKA_Z80_OPCODE_PREFIX_NONE][I]++;
Expand Down
2 changes: 1 addition & 1 deletion meka/srcs/z80marat/Z80.h
Expand Up @@ -81,7 +81,7 @@ typedef struct
pair AF, BC, DE, HL, IX, IY, PC, SP; /* Main registers */ pair AF, BC, DE, HL, IX, IY, PC, SP; /* Main registers */
pair AF1, BC1, DE1, HL1; /* Shadow registers */ pair AF1, BC1, DE1, HL1; /* Shadow registers */
byte IFF, I; /* Interrupt 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 */ int IPeriod, ICount; /* Set IPeriod to number of CPU cycles */
/* between calls to LoopZ80() */ /* between calls to LoopZ80() */
Expand Down

0 comments on commit 5768f5a

Please sign in to comment.