[Core/MD] added emulation of Z80 halt when accessing 68k bus during DMA from 68k bus

This commit is contained in:
ekeeke 2024-02-23 15:40:42 +01:00
parent 9a0a1c2922
commit ed7988f8ca
11 changed files with 97 additions and 53 deletions

View File

@ -74,6 +74,7 @@ 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

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

@ -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

@ -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

@ -662,6 +662,7 @@ void system_frame_gen(int do_skip)
m68k.refresh_cycles -= mcycles_vdp;
m68k.cycles -= mcycles_vdp;
Z80.cycles -= mcycles_vdp;
dma_endCycles = 0;
}
void system_frame_scd(int do_skip)
@ -987,6 +988,7 @@ void system_frame_scd(int do_skip)
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

@ -63,15 +63,17 @@
#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 */
@ -135,23 +137,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 */
@ -630,7 +630,7 @@ void vdp_dma_update(unsigned int cycles)
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 */
@ -645,14 +645,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 */
@ -660,25 +660,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 */
@ -707,6 +717,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;
}
}
}

View File

@ -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;