mirror of
https://github.com/libretro/Genesis-Plus-GX.git
synced 2024-11-23 00:09:43 +00:00
Merge branch 'ekeeke:master' into master
This commit is contained in:
commit
b38cdca903
10
HISTORY.txt
10
HISTORY.txt
@ -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 |
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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_ */
|
||||
|
||||
|
146
core/vdp_ctrl.c
146
core/vdp_ctrl.c
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user