Merge branch 'ekeeke:master' into master

This commit is contained in:
ds22x 2024-02-23 18:04:13 +01:00 committed by GitHub
commit b38cdca903
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 308 additions and 129 deletions

View File

@ -53,6 +53,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* fixed BOOT ROM level 4 interrupt vector upper word value (verified on real hardware, cf. Krikzz's mcd-verificator)
* fixed access to "write-only" communication flags (verified on real hardware by Notaz)
* fixed access to Sub-CPU "read-only" communication registers (fixes Round 5 Boss freeze in Streets of Rage / Sega Classics Arcade Collection)
* fixed byte access to word-only registers (verified on real hardware, cf. Krikzz's mcd-verificator)
* fixed byte access to memory mode, timer and font color registers at even address (verified on real hardware, cf. Krikzz's mcd-verificator)
* fixed byte access to font data registers
* fixed memory mode register bits masking when read from MAIN-CPU and SUB-CPU (verified on real hardware, cf. Krikzz's mcd-verificator)
@ -73,12 +74,15 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* added support for some new unlicensed games with copy protection (Thunderbolt II, Tom Clown, Chaoji Puke / Super Poker, Rock Heaven, Rock World)
* added support for Everdrive extended SSF mapper
* added support for MegaSD CD hardware overlay (MD+ hacks) and extended SSF2 / ROM write mappers
* added emulation of Z80 halt when accessing 68k bus during DMA from 68k bus
* added basic emulation of 68k bus access refresh delays (fixes Super Airwolf graphical glitch during intro & some Krikzz's mcd-verificator timing tests)
* added (very basic) emulation of Flashkit MD hardware
* added emulation of Micro Machines USA on-board TMSS bypass logic hardware
* added SRAM support for games larger than 8MB
* improved console region auto-detection for a few PAL-only games (The Smurfs Travel the World & Williams Arcade's Greatest Hits)
* improved I2C EEPROM boards emulation accuracy
* improved SVP memory handlers accuracy (fixes Virtua Racing debug mode)
* improved accuracy of 68k access to Z80 bus delays
* fixed Realtec mapper behavior on soft-reset and with TMSS hardware
* fixed Game Genie / Pro Action Replay lock-on support when Mega CD hardware is enabled
* fixed Game Genie / Pro Action Replay lock-on support with games larger than 8MB
@ -118,7 +122,8 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
[Core/CPU]
---------------
* added Z80 wait-states on 68k bus access (fixes Remute Red Eyes demo)
* improved 68k auto-vectored interrupts acknowledge cycle timing accuracy (Bubsy background color corruption during cutscenes)
* improved 68k auto-vectored interrupts acknowledge cycle timing accuracy (fixes Bubsy background color corruption during cutscenes & Pacman 2 - New Adventures crashes during Pac-Jr minigame levels transitions)
* improved 68k MOVEM instruction accuracy (implements extra read cycle from memory as verified on real hardware)
* fixed 68k undocumented behaviors for ABCD/SBCD/NBCD instructions (thanks to Flamewing for his test ROM)
* fixed 68k timing of BTST Dn,#Imm instruction (verified by Flamewing in original microcode)
* fixed 68k timings of ANDI.L #Imm,Dn, ADDQ.W #Imm,An and TAS instructions (cf. Yacht.txt)
@ -156,6 +161,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* improved H-Counter accuracy in H32 mode
* improved VDP status timing accuracy
* improved HBLANK flag timing accuracy (verified on real hardware by Nemesis)
* improved VINT timing accuracy in H32 mode (verified on real hardware by Nemesis)
* improved DMA timing accuracy during blanking (verified on real hardware by Mask of Destiny)
* improved accuracy of Master System color palette brightness range (verified against real hardware)
* fixed misaligned buffer writes in Mode 4 when -DALIGN_LONG option is used
@ -164,9 +170,9 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* fixed Mode 1 rendering (TMS99xx "text" mode)
* fixed Master System II extended video modes sprite parsing (fixes Mega Man 2 demo)
* fixed Game Gear display rendering regression when left/right borders were disabled
* fixed 68k cycles delay on invalid VRAM writes (fixes "Microcosm" intro loop)
* fixed address/code potential corruption by one-instruction execution delay after HV interrupts activation (fixes Pugsy's Pyramids stage boss)
* optimized tile caching
* reverted FIFO access timings hack when using invalid write code value
[Core/Sound]
---------------

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

View File

@ -444,8 +444,11 @@ void cdc_dma_update(unsigned int cycles)
/* SUB-CPU idle on register $04 polling ? */
if (s68k.stopped & (1<<0x04))
{
/* sync SUB-CPU with CDC DMA */
s68k.cycles = cdc.cycles[0];
/* sync SUB-CPU with CDC DMA (only if not already ahead) */
if (s68k.cycles < cdc.cycles[0])
{
s68k.cycles = cdc.cycles[0];
}
/* restart SUB-CPU */
s68k.stopped = 0;
@ -677,6 +680,16 @@ void cdc_reg_w(unsigned char data)
/* set CRCOK bit only if decoding is enabled */
cdc.stat[0] = data & BIT_DECEN;
/* decoding disabled ? */
if (!(data & BIT_DECEN))
{
/* clear pending decoder interrupt */
cdc.ifstat |= BIT_DECI;
/* update CDC IRQ state */
cdc.irq &= ~BIT_DECI;
}
/* update STAT2 register */
if (data & BIT_AUTORQ)
{

View File

@ -2,7 +2,7 @@
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -683,7 +683,7 @@ void gfx_update(int cycles)
/* update Vdot remaining size */
scd.regs[0x64>>1].byte.l -= lines;
/* increment cycle counter */
/* update cycle counter */
gfx.cycles += lines * gfx.cyclesPerLine;
}
else
@ -694,14 +694,20 @@ void gfx_update(int cycles)
/* clear Vdot remaining size */
scd.regs[0x64>>1].byte.l = 0;
/* update cycle counter */
gfx.cycles += lines * gfx.cyclesPerLine;
/* end of graphics operation */
scd.regs[0x58>>1].byte.h = 0;
/* SUB-CPU idle on register $58 polling ? */
if (s68k.stopped & (1<<0x08))
{
/* sync SUB-CPU with GFX chip */
s68k.cycles = scd.cycles;
/* sync SUB-CPU with GFX chip (only if not already ahead) */
if (s68k.cycles < gfx.cycles)
{
s68k.cycles = gfx.cycles;
}
/* restart SUB-CPU */
s68k.stopped = 0;

View File

@ -2,7 +2,7 @@
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -804,6 +804,8 @@ INLINE void word_ram_switch(uint8 mode)
}
}
static void scd_write_word(unsigned int address, unsigned int data);
static void scd_write_byte(unsigned int address, unsigned int data)
{
/* PCM area (8K) mirrored into $xF0000-$xF7FFF */
@ -1005,9 +1007,9 @@ static void scd_write_byte(unsigned int address, unsigned int data)
/* synchronize CDC DMA with SUB-CPU */
cdc_dma_update(s68k.cycles);
/* halt CDC DMA to 2M Word-RAM */
/* halt CDC DMA to 2M Word-RAM (if still running) */
cdc.halted_dma_w = cdc.dma_w;
cdc.dma_w = 0;
cdc.halted_dma_w = word_ram_2M_dma_w;
}
/* Word-RAM is returned to MAIN-CPU */
@ -1125,29 +1127,40 @@ static void scd_write_byte(unsigned int address, unsigned int data)
default:
{
uint16 reg_16 = address & 0x1fe;
/* SUB-CPU communication words */
if ((address & 0x1f0) == 0x20)
if ((reg_16 >= 0x20) && (reg_16 <= 0x2f))
{
s68k_poll_sync(1 << ((address - 0x10) & 0x1f));
}
/* MAIN-CPU communication words */
else if ((address & 0x1f0) == 0x10)
else if ((reg_16 >= 0x10) && (reg_16 <= 0x1f))
{
/* read-only (Sega Classic Arcade Collection) */
return;
}
/* word-only registers */
else if (((reg_16 >= 0x08) && (reg_16 <= 0x0d)) ||
((reg_16 >= 0x34) && (reg_16 <= 0x35)) ||
((reg_16 >= 0x5a) && (reg_16 <= 0x67)))
{
scd_write_word(address, (data << 8) | (data & 0xff));
return;
}
/* default registers */
if (address & 1)
{
/* register LSB */
scd.regs[(address >> 1) & 0xff].byte.l = data;
scd.regs[reg_16 >> 1].byte.l = data;
return;
}
/* register MSB */
scd.regs[(address >> 1) & 0xff].byte.h = data;
scd.regs[reg_16 >> 1].byte.h = data;
return;
}
}
@ -1343,9 +1356,9 @@ static void scd_write_word(unsigned int address, unsigned int data)
/* synchronize CDC DMA with SUB-CPU */
cdc_dma_update(s68k.cycles);
/* halt CDC DMA to 2M Word-RAM */
/* halt CDC DMA to 2M Word-RAM (if still running) */
cdc.halted_dma_w = cdc.dma_w;
cdc.dma_w = 0;
cdc.halted_dma_w = word_ram_2M_dma_w;
}
/* Word-RAM is returned to MAIN-CPU */
@ -1414,7 +1427,7 @@ static void scd_write_word(unsigned int address, unsigned int data)
return;
}
case 0x0c: /* Stopwatch (word access only) */
case 0x0c: /* Stopwatch */
{
/* synchronize the counter with SUB-CPU */
int ticks = (s68k.cycles - scd.stopwatch) / TIMERS_SCYCLES_RATIO;

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -50,7 +50,7 @@ uint8 boot_rom[0x800]; /* Genesis BOOT ROM */
uint8 work_ram[0x10000]; /* 68K RAM */
uint8 zram[0x2000]; /* Z80 RAM */
uint32 zbank; /* Z80 bank window address */
uint8 zstate; /* Z80 bus state (d0 = /RESET, d1 = BUSACK) */
uint8 zstate; /* Z80 bus state (d0 = /RESET, d1 = BUSREQ, d2 = WAIT) */
uint8 pico_current; /* PICO current page */
static uint8 tmss[4]; /* TMSS security register */

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -238,7 +238,8 @@ typedef struct
cpu_idle_t poll; /* polling detection */
uint cycles; /* current master cycle count */
sint cycles; /* current master cycle count */
sint refresh_cycles; /* external bus refresh cycle */
uint cycle_end; /* aimed master cycle count for current execution frame */
uint dar[16]; /* Data and Address Registers */

View File

@ -299,6 +299,13 @@ void m68k_run(unsigned int cycles)
/* Decode next instruction */
REG_IR = m68ki_read_imm_16();
/* 68K bus access refresh delay (Mega Drive / Genesis specific) */
if (m68k.cycles >= (m68k.refresh_cycles + (128*7)))
{
m68k.refresh_cycles = (m68k.cycles / (128*7)) * (128*7);
m68k.cycles += (2*7);
}
/* Execute instruction */
m68ki_instruction_jump_table[REG_IR]();
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
@ -382,6 +389,9 @@ void m68k_pulse_reset(void)
#endif
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]);
/* Synchronize 68k bus refresh mechanism (Mega Drive / Genesis specific) */
m68k.refresh_cycles = (m68k.cycles / (128*7)) * (128*7);
}
void m68k_pulse_halt(void)

View File

@ -616,13 +616,13 @@ static const uint16 m68ki_exception_cycle_table[256] =
4*MUL, /* 22: RESERVED */
4*MUL, /* 23: RESERVED */
44*MUL, /* 24: Spurious Interrupt */
54*MUL, /* 25: Level 1 Interrupt Autovector */
54*MUL, /* 26: Level 2 Interrupt Autovector */
54*MUL, /* 27: Level 3 Interrupt Autovector */
54*MUL, /* 28: Level 4 Interrupt Autovector */
54*MUL, /* 29: Level 5 Interrupt Autovector */
54*MUL, /* 30: Level 6 Interrupt Autovector */
54*MUL, /* 31: Level 7 Interrupt Autovector */
44*MUL, /* 25: Level 1 Interrupt Autovector */
44*MUL, /* 26: Level 2 Interrupt Autovector */
44*MUL, /* 27: Level 3 Interrupt Autovector */
44*MUL, /* 28: Level 4 Interrupt Autovector */
44*MUL, /* 29: Level 5 Interrupt Autovector */
44*MUL, /* 30: Level 6 Interrupt Autovector */
44*MUL, /* 31: Level 7 Interrupt Autovector */
34*MUL, /* 32: TRAP #0 -- ASG: chanaged from 38 */
34*MUL, /* 33: TRAP #1 */
34*MUL, /* 34: TRAP #2 */
@ -1374,6 +1374,11 @@ INLINE void m68ki_exception_address_error(void)
}
#endif
/* See MC68000 User Manual appendix B for autovectors interrupts processing time */
/* 44 cycles + N wait-state cycles where N depends on CPU clock alignement with internal E clock (corresponding to CPU clock / 10) when interrupt ack cycle starts */
/* N minimal/maximal values are 6..15 cycles according to manual but real hardware measure apparently indicate 5..14 cycles (cf https://gendev.spritesmind.net/forum/viewtopic.php?f=2&t=2202&p=27485) */
static uint m68ki_cycle_interrupts[10] = {50*MUL, 59*MUL, 58*MUL, 57*MUL, 56*MUL, 55*MUL, 54*MUL, 53*MUL, 52*MUL, 51*MUL};
/* Service an interrupt request and start exception processing */
INLINE void m68ki_exception_interrupt(uint int_level)
{
@ -1416,7 +1421,7 @@ INLINE void m68ki_exception_interrupt(uint int_level)
m68ki_jump(new_pc);
/* Update cycle count now */
USE_CYCLES(CYC_EXCEPTION[vector]);
USE_CYCLES(m68ki_cycle_interrupts[(m68ki_cpu.cycles / MUL) % 10]);
}
/* ASG: Check for interrupts */

View File

@ -8,7 +8,7 @@ INLINE void UseDivuCycles(uint32 dst, uint32 src)
int i;
/* minimum cycle time */
uint mcycles = 38 * MUL;
uint mcycles = 76 * MUL;
/* 16-bit divisor */
src <<= 16;
@ -27,27 +27,33 @@ INLINE void UseDivuCycles(uint32 dst, uint32 src)
{
/* shift dividend and add two cycles */
dst <<= 1;
mcycles += (2 * MUL);
mcycles += (4 * MUL);
if (dst >= src)
{
/* apply divisor and remove one cycle */
dst -= src;
mcycles -= 1 * MUL;
mcycles -= 2 * MUL;
}
}
}
USE_CYCLES(mcycles << 1);
USE_CYCLES(mcycles);
/* one 68K bus refresh cycle should be skipped if instruction processing time is longer than refresh period (128 CPU cycles on Mega Drive / Genesis) */
if (mcycles >= (128*MUL))
{
m68ki_cpu.refresh_cycles += (128*MUL);
}
}
INLINE void UseDivsCycles(sint32 dst, sint16 src)
{
/* minimum cycle time */
uint mcycles = 6 * MUL;
uint mcycles = 12 * MUL;
/* negative dividend */
if (dst < 0) mcycles += 1 * MUL;
if (dst < 0) mcycles += 2 * MUL;
if ((abs(dst) >> 16) < abs(src))
{
@ -57,30 +63,36 @@ INLINE void UseDivsCycles(sint32 dst, sint16 src)
uint32 quotient = abs(dst) / abs(src);
/* add default cycle time */
mcycles += (55 * MUL);
mcycles += (110 * MUL);
/* positive divisor */
if (src >= 0)
{
/* check dividend sign */
if (dst >= 0) mcycles -= 1 * MUL;
else mcycles += 1 * MUL;
if (dst >= 0) mcycles -= 2 * MUL;
else mcycles += 2 * MUL;
}
/* check higher 15-bits of quotient */
for (i=0; i<15; i++)
{
quotient >>= 1;
if (!(quotient & 1)) mcycles += 1 * MUL;
if (!(quotient & 1)) mcycles += 2 * MUL;
}
}
else
{
/* absolute overflow */
mcycles += (2 * MUL);
mcycles += (4 * MUL);
}
USE_CYCLES(mcycles << 1);
USE_CYCLES(mcycles);
/* one 68K bus refresh cycle should be skipped if instruction processing time is longer than refresh period (128 CPU cycles on Mega Drive / Genesis) */
if (mcycles >= (128*MUL))
{
m68ki_cpu.refresh_cycles += (128*MUL);
}
}
INLINE void UseMuluCycles(uint16 src)
@ -15231,6 +15243,9 @@ static void m68k_op_movem_16_er_pi(void)
}
AY = ea;
/* MOVEM extra read cycle (can have side effect if target hardware is impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15250,6 +15265,9 @@ static void m68k_op_movem_16_er_pcdi(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if target hardware is impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15269,6 +15287,9 @@ static void m68k_op_movem_16_er_pcix(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15288,6 +15309,9 @@ static void m68k_op_movem_16_er_ai(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15307,6 +15331,9 @@ static void m68k_op_movem_16_er_di(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15326,6 +15353,9 @@ static void m68k_op_movem_16_er_ix(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15345,6 +15375,9 @@ static void m68k_op_movem_16_er_aw(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15364,6 +15397,9 @@ static void m68k_op_movem_16_er_al(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_W);
}
@ -15384,6 +15420,9 @@ static void m68k_op_movem_32_er_pi(void)
}
AY = ea;
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15403,6 +15442,9 @@ static void m68k_op_movem_32_er_pcdi(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15422,6 +15464,9 @@ static void m68k_op_movem_32_er_pcix(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15441,6 +15486,9 @@ static void m68k_op_movem_32_er_ai(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15460,6 +15508,9 @@ static void m68k_op_movem_32_er_di(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15479,6 +15530,9 @@ static void m68k_op_movem_32_er_ix(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15498,6 +15552,9 @@ static void m68k_op_movem_32_er_aw(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -15517,6 +15574,9 @@ static void m68k_op_movem_32_er_al(void)
count++;
}
/* MOVEM extra read cycle (can have side effect if extra address is not mapped or mapped to hardware impacted by read access) */
m68ki_read_16(ea);
USE_CYCLES(count * CYC_MOVEM_L);
}
@ -18644,6 +18704,7 @@ static void m68k_op_reset(void)
{
m68ki_output_reset() /* auto-disable (see m68kcpu.h) */
USE_CYCLES(CYC_RESET);
m68ki_cpu.refresh_cycles += (128*MUL); /* skip one 68K bus refresh cycle as instruction processing time is longer than refresh period (128 CPU cycles on Mega Drive / Genesis) */
return;
}
m68ki_exception_privilege_violation();

View File

@ -140,6 +140,9 @@ unsigned int m68k_lockup_r_16 (unsigned int address)
unsigned int z80_read_byte(unsigned int address)
{
/* Z80 bus access latency */
m68k.cycles += 1 * 7;
switch ((address >> 13) & 3)
{
case 2: /* YM2612 */
@ -172,6 +175,9 @@ unsigned int z80_read_word(unsigned int address)
void z80_write_byte(unsigned int address, unsigned int data)
{
/* Z80 bus access latency (fixes Pacman 2: New Adventures sound engine crashes & Puyo Puyo 2 crash when exiting option menu) */
m68k.cycles += 1 * 7;
switch ((address >> 13) & 3)
{
case 2: /* YM2612 */
@ -207,7 +213,6 @@ void z80_write_byte(unsigned int address, unsigned int data)
default: /* ZRAM */
{
zram[address & 0x1FFF] = data;
m68k.cycles += 2 * 7; /* ZRAM access latency (fixes Pacman 2: New Adventures & Puyo Puyo 2) */
return;
}
}
@ -763,9 +768,9 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
/* synchronize CDC DMA with MAIN-CPU */
cdc_dma_update((m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE);
/* halt CDC DMA to PRG-RAM */
/* halt CDC DMA to PRG-RAM (if still running) */
cdc.halted_dma_w = cdc.dma_w;
cdc.dma_w = 0;
cdc.halted_dma_w = prg_ram_dma_w;
}
}
else
@ -1092,9 +1097,9 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
/* synchronize CDC DMA with MAIN-CPU */
cdc_dma_update((m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE);
/* halt CDC DMA to PRG-RAM */
/* halt CDC DMA to PRG-RAM (if still running) */
cdc.halted_dma_w = cdc.dma_w;
cdc.dma_w = 0;
cdc.halted_dma_w = prg_ram_dma_w;
}
}
else

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive ports access
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -92,6 +92,26 @@ INLINE unsigned char z80_lockup_r(unsigned int address)
/* Z80 Memory handlers (Genesis mode) */
/*--------------------------------------------------------------------------*/
static void z80_request_68k_bus_access(void)
{
/* check if 68k bus is accessed by VDP DMA */
if ((Z80.cycles < dma_endCycles) && (dma_type < 2))
{
/* force Z80 to wait until end of DMA */
Z80.cycles = dma_endCycles;
/* check if DMA is not finished at the end of current timeframe */
if (dma_length)
{
/* indicate Z80 will still be waiting for 68k bus at the end of current DMA timeframe */
zstate |= 4;
}
}
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
}
unsigned char z80_memory_r(unsigned int address)
{
switch((address >> 13) & 7)
@ -111,8 +131,10 @@ unsigned char z80_memory_r(unsigned int address)
{
if ((address >> 8) == 0x7F)
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
/* request access to 68k bus */
z80_request_68k_bus_access();
/* read from $C00000-$C0FFFF area */
return (*zbank_memory_map[0xc0].read)(address);
}
return z80_unused_r(address);
@ -120,9 +142,10 @@ unsigned char z80_memory_r(unsigned int address)
default: /* $8000-$FFFF: 68k bank (32K) */
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
/* request access to 68k bus */
z80_request_68k_bus_access();
/* read from 68k banked area */
address = zbank | (address & 0x7FFF);
if (zbank_memory_map[address >> 16].read)
{
@ -163,8 +186,10 @@ void z80_memory_w(unsigned int address, unsigned char data)
case 0x7F: /* $7F00-$7FFF: VDP */
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
/* request access to 68k bus */
z80_request_68k_bus_access();
/* write to $C00000-$C0FFFF area */
(*zbank_memory_map[0xc0].write)(address, data);
return;
}
@ -179,9 +204,10 @@ void z80_memory_w(unsigned int address, unsigned char data)
default: /* $8000-$FFFF: 68k bank (32K) */
{
/* average Z80 wait-states when accessing 68k area */
Z80.cycles += 3 * 15;
/* request access to 68k bus */
z80_request_68k_bus_access();
/* write to 68k banked area */
address = zbank | (address & 0x7FFF);
if (zbank_memory_map[address >> 16].write)
{

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive ports access
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -5,7 +5,7 @@
* Support for 16-bit & 8-bit hardware modes
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2021 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -480,14 +480,14 @@ void system_frame_gen(int do_skip)
v_counter = bitmap.viewport.h;
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(788);
m68k_run(vint_cycle);
if (zstate == 1)
{
z80_run(788);
z80_run(vint_cycle);
}
/* set VINT flag */
status |= 0x80;
status |= 0x80;
/* Vertical Interrupt */
vint_pending = 0x20;
@ -677,8 +677,10 @@ void system_frame_gen(int do_skip)
/* adjust timings for next frame */
input_end_frame(mcycles_vdp);
m68k.refresh_cycles -= mcycles_vdp;
m68k.cycles -= mcycles_vdp;
Z80.cycles -= mcycles_vdp;
dma_endCycles = 0;
}
void system_frame_scd(int do_skip)
@ -819,14 +821,14 @@ void system_frame_scd(int do_skip)
v_counter = bitmap.viewport.h;
/* delay between VBLANK flag & Vertical Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(788);
m68k_run(vint_cycle);
if (zstate == 1)
{
z80_run(788);
z80_run(vint_cycle);
}
/* set VINT flag */
status |= 0x80;
status |= 0x80;
/* Vertical Interrupt */
vint_pending = 0x20;
@ -1001,8 +1003,10 @@ void system_frame_scd(int do_skip)
/* adjust timings for next frame */
scd_end_frame(scd.cycles);
input_end_frame(mcycles_vdp);
m68k.refresh_cycles -= mcycles_vdp;
m68k.cycles -= mcycles_vdp;
Z80.cycles -= mcycles_vdp;
dma_endCycles = 0;
}
void system_frame_sms(int do_skip)

View File

@ -5,7 +5,7 @@
* Support for 16-bit & 8-bit hardware modes
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -66,8 +66,8 @@
#define MCYCLES_PER_LINE 3420
/* Horizontal timing offsets when running in Z80 mode */
#define SMS_CYCLE_OFFSET 530
#define PBC_CYCLE_OFFSET 560
#define SMS_CYCLE_OFFSET 530
#define PBC_CYCLE_OFFSET 560
typedef struct
{
@ -98,7 +98,6 @@ typedef struct
int16 cd_last_save[2]; /* For saving and restoring the sound buffer */
} t_snd;
/* Global variables */
extern t_bitmap bitmap;
extern t_snd snd;
@ -122,4 +121,3 @@ extern void system_frame_scd(int do_skip);
extern void system_frame_sms(int do_skip);
#endif /* _SYSTEM_H_ */

View File

@ -5,7 +5,7 @@
* Support for SG-1000 (TMS99xx & 315-5066), Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -57,6 +57,9 @@ static void vdp_set_all_vram(const uint8 *src);
} \
bg_name_dirty[name] |= (1 << ((addr >> 2) & 7)); \
}
/* VINT timings */
#define VINT_H32_MCYCLE (770)
#define VINT_H40_MCYCLE (788)
/* HBLANK flag timings */
#define HBLANK_H32_START_MCYCLE (280)
@ -65,15 +68,17 @@ static void vdp_set_all_vram(const uint8 *src);
#define HBLANK_H40_END_MCYCLE (872)
/* VDP context */
uint8 ALIGNED_(4) sat[0x400]; /* Internal copy of sprite attribute table */
uint8 ALIGNED_(4) vram[0x10000]; /* Video RAM (64K x 8-bit) */
uint8 ALIGNED_(4) cram[0x80]; /* On-chip color RAM (64 x 9-bit) */
uint8 ALIGNED_(4) vsram[0x80]; /* On-chip vertical scroll RAM (40 x 11-bit) */
uint8 reg[0x20]; /* Internal VDP registers (23 x 8-bit) */
uint8 hint_pending; /* 0= Line interrupt is pending */
uint8 vint_pending; /* 1= Frame interrupt is pending */
uint16 status; /* VDP status flags */
uint32 dma_length; /* DMA remaining length */
uint8 ALIGNED_(4) sat[0x400]; /* Internal copy of sprite attribute table */
uint8 ALIGNED_(4) vram[0x10000]; /* Video RAM (64K x 8-bit) */
uint8 ALIGNED_(4) cram[0x80]; /* On-chip color RAM (64 x 9-bit) */
uint8 ALIGNED_(4) vsram[0x80]; /* On-chip vertical scroll RAM (40 x 11-bit) */
uint8 reg[0x20]; /* Internal VDP registers (23 x 8-bit) */
uint8 hint_pending; /* 0= Line interrupt is pending */
uint8 vint_pending; /* 1= Frame interrupt is pending */
uint16 status; /* VDP status flags */
uint32 dma_length; /* DMA remaining length */
uint32 dma_endCycles; /* DMA end cycle */
uint8 dma_type; /* DMA mode */
/* Global variables */
uint16 ntab; /* Name table A base address */
@ -101,6 +106,7 @@ uint16 max_sprite_pixels; /* Max. sprites pixels per line (parsing & ren
int32 fifo_write_cnt; /* VDP FIFO write count */
uint32 fifo_slots; /* VDP FIFO access slot count */
uint32 hvc_latch; /* latched HV counter */
uint32 vint_cycle; /* VINT occurence cycle */
const uint8 *hctab; /* pointer to H Counter table */
/* Function pointers */
@ -136,23 +142,21 @@ static const uint8 shift_table[] = { 6, 7, 0, 8 };
static const uint8 col_mask_table[] = { 0x0F, 0x1F, 0x0F, 0x3F };
static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF };
static uint8 border; /* Border color index */
static uint8 pending; /* Pending write flag */
static uint8 code; /* Code register */
static uint8 dma_type; /* DMA mode */
static uint16 addr; /* Address register */
static uint16 addr_latch; /* Latched A15, A14 of address */
static uint16 sat_base_mask; /* Base bits of SAT */
static uint16 sat_addr_mask; /* Index bits of SAT */
static uint16 dma_src; /* DMA source address */
static uint32 dma_endCycles; /* 68k cycles to DMA end */
static int dmafill; /* DMA Fill pending flag */
static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */
static uint16 fifo[4]; /* FIFO ring-buffer */
static int fifo_idx; /* FIFO write index */
static int fifo_byte_access; /* FIFO byte access flag */
static uint32 fifo_cycles; /* FIFO next access cycle */
static int *fifo_timing; /* FIFO slots timing table */
static uint8 border; /* Border color index */
static uint8 pending; /* Pending write flag */
static uint8 code; /* Code register */
static uint16 addr; /* Address register */
static uint16 addr_latch; /* Latched A15, A14 of address */
static uint16 sat_base_mask; /* Base bits of SAT */
static uint16 sat_addr_mask; /* Index bits of SAT */
static uint16 dma_src; /* DMA source address */
static int dmafill; /* DMA Fill pending flag */
static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */
static uint16 fifo[4]; /* FIFO ring-buffer */
static int fifo_idx; /* FIFO write index */
static int fifo_byte_access; /* FIFO byte access flag */
static uint32 fifo_cycles; /* FIFO next access cycle */
static int *fifo_timing; /* FIFO slots timing table */
static int hblank_start_cycle; /* HBLANK flag set cycle */
static int hblank_end_cycle; /* HBLANK flag clear cycle */
@ -341,6 +345,9 @@ void vdp_reset(void)
/* default FIFO access slots timings */
fifo_timing = (int *)fifo_timing_h32;
/* default VINT timing */
vint_cycle = VINT_H32_MCYCLE;
/* default HBLANK flag timings */
hblank_start_cycle = HBLANK_H32_START_MCYCLE;
hblank_end_cycle = HBLANK_H32_END_MCYCLE;
@ -647,8 +654,15 @@ void vdp_dma_update(unsigned int cycles)
/* Adjust for 68k bus DMA to VRAM (one word = 2 access) or DMA Copy (one read + one write = 2 access) */
rate = rate >> (dma_type & 1);
/* Adjust for 68k bus DMA to CRAM or VSRAM when display is off (one additional access slot is lost for each refresh slot) */
if (dma_type == 0)
{
if (rate == 166) rate = 161; /* 5 refresh slots per line in H32 mode when display is off */
else if (rate == 204) rate = 198; /* 6 refresh slots per line in H40 mode when display is off */
}
/* Remaining DMA cycles */
/* Available DMA cycles */
if (status & 8)
{
/* Process DMA until the end of VBLANK */
@ -663,14 +677,14 @@ void vdp_dma_update(unsigned int cycles)
dma_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - cycles;
}
/* Remaining DMA bytes for that line */
/* Max number of DMA bytes to be processed */
dma_bytes = (dma_cycles * rate) / MCYCLES_PER_LINE;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)(%d cycles left)-> %d access (%d remaining) (%x)\n", v_counter, (v_counter + (cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, cycles, cycles%MCYCLES_PER_LINE,dma_type, rate, dma_cycles, dma_bytes, dma_length, m68k_get_reg(M68K_REG_PC));
#endif
/* Check if DMA can be finished before the end of current line */
/* Check if DMA can be finished within current timeframe */
if (dma_length < dma_bytes)
{
/* Adjust remaining DMA bytes */
@ -678,25 +692,35 @@ void vdp_dma_update(unsigned int cycles)
dma_cycles = (dma_bytes * MCYCLES_PER_LINE) / rate;
}
/* Update DMA timings */
/* Set DMA end cycle */
dma_endCycles = cycles + dma_cycles;
#ifdef LOGVDP
error("-->DMA ends at %d cycles\n", dma_endCycles);
#endif
/* Check if 68k bus is accessed by DMA */
if (dma_type < 2)
{
/* 68K is frozen during DMA from 68k bus */
m68k.cycles = cycles + dma_cycles;
/* 68K is waiting during DMA from 68k bus */
m68k.cycles = dma_endCycles;
#ifdef LOGVDP
error("-->CPU frozen for %d cycles\n", dma_cycles);
error("-->68K CPU waiting for %d cycles\n", dma_cycles);
#endif
/* Check if Z80 is waiting for 68k bus */
if (zstate & 4)
{
/* force Z80 to wait until end of DMA timeframe */
Z80.cycles = dma_endCycles;
#ifdef LOGVDP
error("-->Z80 CPU waiting for %d cycles\n", dma_cycles);
#endif
}
}
else
{
/* Set DMA Busy flag */
/* Set DMA Busy flag only when 68K can read it */
status |= 0x02;
/* 68K is still running, set DMA end cycle */
dma_endCycles = cycles + dma_cycles;
#ifdef LOGVDP
error("-->DMA ends in %d cycles\n", dma_cycles);
#endif
}
/* Process DMA */
@ -725,6 +749,9 @@ void vdp_dma_update(unsigned int cycles)
vdp_68k_ctrl_w(cached_write);
cached_write = -1;
}
/* indicate Z80 is not waiting for 68k bus at the end of DMA timeframe */
zstate &= ~4;
}
}
}
@ -867,18 +894,12 @@ void vdp_68k_ctrl_w(unsigned int data)
/*
FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace)
--------------------------------------------------------------------------
Each VRAM access is byte wide, so one VRAM write (word) need two slot access.
Each VRAM access is byte wide, so one VRAM write (word) need two access slots.
NOTE: Invalid code 0x02 (register write) should not behave the same as VRAM
access, i.e data is ignored and only one access slot is used for each word,
BUT a few games ("Clue", "Microcosm") which accidentally corrupt code value
will have issues when emulating FIFO timings. They likely work fine on real
hardware because of periodical 68k wait-states which have been observed and
would naturaly add some delay between writes. Until those wait-states are
accurately measured and emulated, delay is forced when invalid code value
is being used.
NOTE: Invalid codes 0x00, 0x08 and 0x09 behaves the same as VRAM access (0x01) i.e,
although no data is written, two access slots are required to empty the FIFO entry.
*/
fifo_byte_access = ((code & 0x0F) <= 0x02);
fifo_byte_access = (code & 0x06) ? 0 : 1;
}
/* Mega Drive VDP control port specific (MS compatibility mode) */
@ -1234,9 +1255,9 @@ unsigned int vdp_68k_ctrl_r(unsigned int cycles)
/* Adjust cycle count relatively to start of line */
cycles -= mcycles_vdp;
/* Cycle-accurate VINT flag (Ex-Mutants, Tyrant / Mega-Lo-Mania, Marvel Land) */
/* Cycle-accurate VINT flag (Ex-Mutants, Tyrant / Mega-Lo-Mania, Marvel Land, Pacman 2 - New Adventures / Pac-Jr minigame) */
/* this allows VINT flag to be read just before vertical interrupt is being triggered */
if ((v_counter == bitmap.viewport.h) && (cycles >= 788))
if ((v_counter == bitmap.viewport.h) && (cycles >= vint_cycle))
{
/* check Z80 interrupt state to assure VINT has not already been triggered (and flag cleared) */
if (Z80.irq_state != ASSERT_LINE)
@ -2026,9 +2047,12 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles)
/* FIFO access slots timings */
fifo_timing = (int *)fifo_timing_h40;
/* VINT timing */
vint_cycle = VINT_H40_MCYCLE;
/* HBLANK flag timings */
hblank_start_cycle = HBLANK_H32_START_MCYCLE;
hblank_end_cycle = HBLANK_H32_END_MCYCLE;
hblank_start_cycle = HBLANK_H40_START_MCYCLE;
hblank_end_cycle = HBLANK_H40_END_MCYCLE;
}
else
{
@ -2050,9 +2074,12 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles)
/* FIFO access slots timings */
fifo_timing = (int *)fifo_timing_h32;
/* VINT timing */
vint_cycle = VINT_H32_MCYCLE;
/* HBLANK flag timings */
hblank_start_cycle = HBLANK_H40_START_MCYCLE;
hblank_end_cycle = HBLANK_H40_END_MCYCLE;
hblank_start_cycle = HBLANK_H32_START_MCYCLE;
hblank_end_cycle = HBLANK_H32_END_MCYCLE;
}
/* Active screen width modified during VBLANK will be applied on upcoming frame */
@ -2313,8 +2340,6 @@ static void vdp_bus_w(unsigned int data)
default:
{
/* add some delay until 68k periodical wait-states are accurately emulated ("Clue", "Microcosm") */
m68k.cycles += 2;
#ifdef LOGERROR
error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x write -> 0x%x (%x)\n", v_counter, (v_counter + (m68k.cycles - mcycles_vdp)/MCYCLES_PER_LINE)%lines_per_frame, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
@ -2474,6 +2499,9 @@ static void vdp_68k_data_w_m5(unsigned int data)
dma_length = 0x10000;
}
/* Take into account initial data word processing */
dma_length += 2;
/* Trigger DMA */
vdp_dma_update(m68k.cycles);
}

View File

@ -5,7 +5,7 @@
* Support for SG-1000 (TMS99xx & 315-5066), Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2023 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2024 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -52,6 +52,8 @@ extern uint8 hint_pending;
extern uint8 vint_pending;
extern uint16 status;
extern uint32 dma_length;
extern uint32 dma_endCycles;
extern uint8 dma_type;
/* Global variables */
extern uint16 ntab;
@ -79,6 +81,7 @@ extern uint16 max_sprite_pixels;
extern int32 fifo_write_cnt;
extern uint32 fifo_slots;
extern uint32 hvc_latch;
extern uint32 vint_cycle;
extern const uint8 *hctab;
/* Function pointers */