.fixed SUB-CPU access to unmapped areas using PC-relative instructions (Final Fight CD first boss crash)

.fixed SUB-CPU idle loop false detection when using BSET/BCLR on memory mode register (Pugsy CD first boss slowdowns)
.fixed Word-RAM default mode switching on soft reset
.optimized VDP DMA processing
This commit is contained in:
EkeEke 2012-07-15 17:26:21 +02:00
parent e53d6e8aa4
commit 2b8656c27f
2 changed files with 188 additions and 188 deletions

View File

@ -412,6 +412,7 @@ INLINE void word_ram_switch(uint8 mode)
if (mode & 0x04)
{
/* 2M -> 1M mode */
for (i=0; i<0x10000; i++)
{
*ptr2++=*ptr1++;
@ -420,11 +421,43 @@ INLINE void word_ram_switch(uint8 mode)
}
else
{
/* 1M -> 2M mode */
for (i=0; i<0x10000; i++)
{
*ptr1++=*ptr2++;
*ptr1++=*ptr3++;
}
/* allow Word-RAM access from both CPU in 2M mode (fixes sync issues in Mortal Kombat) */
for (i=scd.cartridge.boot+0x20; i<scd.cartridge.boot+0x24; i++)
{
/* MAIN-CPU: $200000-$23FFFF is mapped to 256K Word-RAM */
m68k.memory_map[i].base = scd.word_ram_2M + ((i & 0x03) << 16);
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
m68k.memory_map[i].write8 = NULL;
m68k.memory_map[i].write16 = NULL;
zbank_memory_map[i].read = NULL;
zbank_memory_map[i].write = NULL;
}
for (i=0x08; i<0x0c; i++)
{
/* SUB-CPU: $080000-$0BFFFF is mapped to 256K Word-RAM */
s68k.memory_map[i].read8 = NULL;
s68k.memory_map[i].read16 = NULL;
s68k.memory_map[i].write8 = NULL;
s68k.memory_map[i].write16 = NULL;
}
for (i=0x0c; i<0x0e; i++)
{
/* SUB-CPU: $0C0000-$0DFFFF is unmapped */
s68k.memory_map[i].read8 = s68k_read_bus_8;
s68k.memory_map[i].read16 = s68k_read_bus_16;
s68k.memory_map[i].write8 = s68k_unused_8_w;
s68k.memory_map[i].write16 = s68k_unused_16_w;
}
}
}
@ -471,12 +504,12 @@ static void scd_write_byte(unsigned int address, unsigned int data)
case 0x03: /* Memory Mode */
{
s68k_poll_sync(0x02);
/* detect MODE & RET bits modifications */
if ((data ^ scd.regs[0x03 >> 1].byte.l) & 0x05)
{
int i;
s68k_poll_sync(0x02);
/* MODE bit */
if (data & 0x04)
@ -485,7 +518,7 @@ static void scd_write_byte(unsigned int address, unsigned int data)
if (!(scd.regs[0x03 >> 1].byte.l & 0x04))
{
/* re-arrange Word-RAM banks */
word_ram_switch(data);
word_ram_switch(0x04);
}
/* RET bit in 1M Mode */
@ -501,7 +534,6 @@ static void scd_write_byte(unsigned int address, unsigned int data)
for (i=scd.cartridge.boot+0x22; i<scd.cartridge.boot+0x24; i++)
{
/* VRAM cell image mapped at $220000-$23FFFF */
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cell_ram_1_read8;
m68k.memory_map[i].read16 = cell_ram_1_read16;
m68k.memory_map[i].write8 = cell_ram_1_write8;
@ -545,7 +577,6 @@ static void scd_write_byte(unsigned int address, unsigned int data)
for (i=scd.cartridge.boot+0x22; i<scd.cartridge.boot+0x24; i++)
{
/* VRAM cell image mapped at $220000-$23FFFF */
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cell_ram_0_read8;
m68k.memory_map[i].read16 = cell_ram_0_read16;
m68k.memory_map[i].write8 = cell_ram_0_write8;
@ -585,38 +616,7 @@ static void scd_write_byte(unsigned int address, unsigned int data)
if (scd.regs[0x02 >> 1].byte.l & 0x04)
{
/* re-arrange Word-RAM banks */
word_ram_switch(data);
/* allow Word-RAM access from both CPU in 2M mode (fixes sync issues in Mortal Kombat) */
for (i=scd.cartridge.boot+0x20; i<scd.cartridge.boot+0x24; i++)
{
/* MAIN-CPU: $200000-$23FFFF is mapped to 256K Word-RAM */
m68k.memory_map[i].base = scd.word_ram_2M + ((i & 0x03) << 16);
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
m68k.memory_map[i].write8 = NULL;
m68k.memory_map[i].write16 = NULL;
zbank_memory_map[i].read = NULL;
zbank_memory_map[i].write = NULL;
}
for (i=0x08; i<0x0c; i++)
{
/* SUB-CPU: $080000-$0BFFFF is mapped to 256K Word-RAM */
s68k.memory_map[i].read8 = NULL;
s68k.memory_map[i].read16 = NULL;
s68k.memory_map[i].write8 = NULL;
s68k.memory_map[i].write16 = NULL;
}
for (i=0x0c; i<0x0e; i++)
{
/* SUB-CPU: $0C0000-$0DFFFF is unmapped */
s68k.memory_map[i].read8 = s68k_read_bus_8;
s68k.memory_map[i].read16 = s68k_read_bus_16;
s68k.memory_map[i].write8 = s68k_unused_8_w;
s68k.memory_map[i].write16 = s68k_unused_16_w;
}
word_ram_switch(0x00);
/* RET bit set during 1M mode ? */
data |= ~scd.dmna & 0x01;
@ -777,12 +777,12 @@ static void scd_write_word(unsigned int address, unsigned int data)
case 0x02: /* Memory Mode */
{
s68k_poll_sync(0x02);
/* detect MODE & RET bits modifications */
if ((data ^ scd.regs[0x03>>1].byte.l) & 0x05)
{
int i;
s68k_poll_sync(0x02);
/* MODE bit */
if (data & 0x04)
@ -791,7 +791,7 @@ static void scd_write_word(unsigned int address, unsigned int data)
if (!(scd.regs[0x03 >> 1].byte.l & 0x04))
{
/* re-arrange Word-RAM banks */
word_ram_switch(data);
word_ram_switch(0x04);
}
/* RET bit in 1M Mode */
@ -807,7 +807,6 @@ static void scd_write_word(unsigned int address, unsigned int data)
for (i=scd.cartridge.boot+0x22; i<scd.cartridge.boot+0x24; i++)
{
/* VRAM cell image mapped at $220000-$23FFFF */
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cell_ram_1_read8;
m68k.memory_map[i].read16 = cell_ram_1_read16;
m68k.memory_map[i].write8 = cell_ram_1_write8;
@ -851,7 +850,6 @@ static void scd_write_word(unsigned int address, unsigned int data)
for (i=scd.cartridge.boot+0x22; i<scd.cartridge.boot+0x24; i++)
{
/* VRAM cell image mapped at $220000-$23FFFF */
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cell_ram_0_read8;
m68k.memory_map[i].read16 = cell_ram_0_read16;
m68k.memory_map[i].write8 = cell_ram_0_write8;
@ -891,38 +889,7 @@ static void scd_write_word(unsigned int address, unsigned int data)
if (scd.regs[0x03>>1].byte.l & 0x04)
{
/* re-arrange Word-RAM banks */
word_ram_switch(data);
/* allow Word-RAM access from both CPU in 2M mode (fixes sync issues in Mortal Kombat) */
for (i=scd.cartridge.boot+0x20; i<scd.cartridge.boot+0x24; i++)
{
/* MAIN-CPU: $200000-$23FFFF is mapped to 256K Word-RAM */
m68k.memory_map[i].base = scd.word_ram_2M + ((i & 0x03) << 16);
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
m68k.memory_map[i].write8 = NULL;
m68k.memory_map[i].write16 = NULL;
zbank_memory_map[i].read = NULL;
zbank_memory_map[i].write = NULL;
}
for (i=0x08; i<0x0c; i++)
{
/* SUB-CPU: $080000-$0BFFFF is mapped to 256K Word-RAM */
s68k.memory_map[i].read8 = NULL;
s68k.memory_map[i].read16 = NULL;
s68k.memory_map[i].write8 = NULL;
s68k.memory_map[i].write16 = NULL;
}
for (i=0x0c; i<0x0e; i++)
{
/* SUB-CPU: $0C0000-$0DFFFF is unmapped */
s68k.memory_map[i].read8 = s68k_read_bus_8;
s68k.memory_map[i].read16 = s68k_read_bus_16;
s68k.memory_map[i].write8 = s68k_unused_8_w;
s68k.memory_map[i].write16 = s68k_unused_16_w;
}
word_ram_switch(0x00);
/* RET bit set during 1M mode ? */
data |= ~scd.dmna & 0x01;
@ -1104,7 +1071,7 @@ void scd_init(void)
/* $240000-$3FFFFF (resp. $400000-$7FFFFF): unused area (Word-RAM mirrored ?) */
for (i=base+0x24; i<base+0x40; i++)
{
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].base = scd.word_ram_2M + ((i & 3) << 16);
m68k.memory_map[i].read8 = m68k_read_bus_8;
m68k.memory_map[i].read16 = m68k_read_bus_16;
m68k.memory_map[i].write8 = m68k_unused_8_w;
@ -1143,10 +1110,10 @@ void scd_init(void)
s68k.memory_map[i].write16 = NULL;
}
/* $0C0000-$FD0000: Unused area */
/* $0C0000-$FD0000: Unused area (Word-RAM mirrored ?) */
for (i=0x0c; i<0xfd; i++)
{
s68k.memory_map[i].base = NULL;
s68k.memory_map[i].base = scd.word_ram_2M + ((i & 3) << 16);
s68k.memory_map[i].read8 = s68k_read_bus_8;
s68k.memory_map[i].read16 = s68k_read_bus_16;
s68k.memory_map[i].write8 = s68k_unused_8_w;
@ -1205,6 +1172,9 @@ void scd_reset(int hard)
/* Power ON initial values (MAIN-CPU side) */
scd.regs[0x00>>1].w = 0x0002;
scd.regs[0x02>>1].w = 0x0001;
/* 2M mode */
word_ram_switch(0);
}
else
{

View File

@ -96,6 +96,27 @@ void (*vdp_z80_data_w)(unsigned int data);
unsigned int (*vdp_68k_data_r)(void);
unsigned int (*vdp_z80_data_r)(void);
/* Function prototypes */
static void vdp_68k_data_w_m4(unsigned int data);
static void vdp_68k_data_w_m5(unsigned int data);
static unsigned int vdp_68k_data_r_m4(void);
static unsigned int vdp_68k_data_r_m5(void);
static void vdp_z80_data_w_m4(unsigned int data);
static void vdp_z80_data_w_m5(unsigned int data);
static unsigned int vdp_z80_data_r_m4(void);
static unsigned int vdp_z80_data_r_m5(void);
static void vdp_z80_data_w_ms(unsigned int data);
static void vdp_z80_data_w_gg(unsigned int data);
static void vdp_z80_data_w_sg(unsigned int data);
static void vdp_bus_w(unsigned int data);
static void vdp_fifo_update(unsigned int cycles);
static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles);
static void vdp_dma_68k_ext(unsigned int length);
static void vdp_dma_68k_ram(unsigned int length);
static void vdp_dma_68k_io(unsigned int length);
static void vdp_dma_copy(unsigned int length);
static void vdp_dma_fill(unsigned int length);
/* Tables that define the playfield layout */
static const uint8 hscroll_mask_table[] = { 0x00, 0x07, 0xF8, 0xFF };
static const uint8 shift_table[] = { 6, 7, 0, 8 };
@ -121,14 +142,6 @@ static uint16 fifo[4]; /* FIFO buffer */
static void (*set_irq_line)(unsigned int level);
static void (*set_irq_line_delay)(unsigned int level);
/* DMA Timings */
static const uint8 dma_timing[2][2] =
{
/* H32, H40 */
{16 , 18}, /* active display */
{167, 205} /* blank display */
};
/* Vertical counter overflow values (see hvc.h) */
static const uint16 vc_table[4][2] =
{
@ -139,27 +152,30 @@ static const uint16 vc_table[4][2] =
{0x106, 0x10A} /* Mode 5 (240 lines) */
};
/*--------------------------------------------------------------------------*/
/* Function prototypes */
/*--------------------------------------------------------------------------*/
/* DMA Timings (number of access slots per line) */
static const uint8 dma_timing[2][2] =
{
/* H32, H40 */
{16 , 18}, /* active display */
{167, 205} /* blank display */
};
/* DMA processing functions (set by VDP register 23 high nibble) */
static void (*const dma_func[16])(unsigned int length) =
{
/* 0x0-0x3 : DMA from 68k bus $000000-$7FFFFF (external area) */
vdp_dma_68k_ext,vdp_dma_68k_ext,vdp_dma_68k_ext,vdp_dma_68k_ext,
/* 0x4-0x7 : DMA from 68k bus $800000-$FFFFFF (internal RAM & I/O) */
vdp_dma_68k_ram, vdp_dma_68k_io,vdp_dma_68k_ram,vdp_dma_68k_ram,
/* 0x8-0xB : DMA Fill */
vdp_dma_fill,vdp_dma_fill,vdp_dma_fill,vdp_dma_fill,
/* 0xC-0xF : DMA Copy */
vdp_dma_copy,vdp_dma_copy,vdp_dma_copy,vdp_dma_copy
};
static void vdp_68k_data_w_m4(unsigned int data);
static void vdp_68k_data_w_m5(unsigned int data);
static unsigned int vdp_68k_data_r_m4(void);
static unsigned int vdp_68k_data_r_m5(void);
static void vdp_z80_data_w_m4(unsigned int data);
static void vdp_z80_data_w_m5(unsigned int data);
static unsigned int vdp_z80_data_r_m4(void);
static unsigned int vdp_z80_data_r_m5(void);
static void vdp_z80_data_w_ms(unsigned int data);
static void vdp_z80_data_w_gg(unsigned int data);
static void vdp_z80_data_w_sg(unsigned int data);
static void vdp_bus_w(unsigned int data);
static void vdp_fifo_update(unsigned int cycles);
static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles);
static void vdp_dma_copy(unsigned int length);
static void vdp_dma_vbus(unsigned int length);
static void vdp_dma_fill(unsigned char data, unsigned int length);
/*--------------------------------------------------------------------------*/
/* Init, reset, context functions */
@ -608,30 +624,8 @@ void vdp_dma_update(unsigned int cycles)
/* Update DMA length */
dma_length -= dma_bytes;
/* Select DMA operation */
switch (dma_type)
{
case 2:
{
/* VRAM Fill */
vdp_dma_fill(dmafill, dma_bytes);
break;
}
case 3:
{
/* VRAM Copy */
vdp_dma_copy(dma_bytes);
break;
}
default:
{
/* 68K bus to VRAM, CRAM or VSRAM */
vdp_dma_vbus(dma_bytes);
break;
}
}
/* Process DMA operation */
dma_func[reg[23] >> 4](dma_bytes);
/* Check if DMA is finished */
if (!dma_length)
@ -2868,78 +2862,112 @@ static void vdp_z80_data_w_sg(unsigned int data)
/* DMA operations */
/*--------------------------------------------------------------------------*/
/* 68K bus to VRAM, VSRAM or CRAM */
static void vdp_dma_vbus(unsigned int length)
/* DMA from 68K bus: $000000-$7FFFFF (external area) */
static void vdp_dma_68k_ext(unsigned int length)
{
uint16 data;
/* 68k bus source address */
uint32 source = (reg[23] << 17) | (dma_src << 1);
/* Z80 & I/O area ($A00000-$A1FFFF) specific */
if (reg[23] == 0x50)
do
{
do
/* Read data word from 68k bus */
if (m68k.memory_map[source>>16].read16)
{
/* Z80 area */
if (source <= 0xA0FFFF)
{
/* Return $FFFF only when the Z80 isn't hogging the Z-bus.
(e.g. Z80 isn't reset and 68000 has the bus) */
data = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xFFFF)) : 0xFFFF);
}
/* The I/O chip and work RAM try to drive the data bus which results
in both values being combined in random ways when read.
We return the I/O chip values which seem to have precedence, */
else if (source <= 0xA1001F)
{
data = io_68k_read((source >> 1) & 0x0F);
data = (data << 8 | data);
}
/* All remaining locations access work RAM */
else
{
data = *(uint16 *)(work_ram + (source & 0xFFFF));
}
/* Increment source address */
source += 2;
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* Write data to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
data = m68k.memory_map[source>>16].read16(source);
}
while (--length);
}
else
{
do
else
{
/* Read data word from 68k bus */
if (m68k.memory_map[source>>16].base)
{
data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF));
}
else
{
data = m68k.memory_map[source>>16].read16(source);
}
data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF));
}
/* Increment source address */
source += 2;
/* Increment source address */
source += 2;
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* Write data word to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
}
while (--length);
/* Write data word to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
}
while (--length);
/* Update DMA source address */
dma_src = (source >> 1) & 0xffff;
}
/* DMA from 68K bus: $800000-$FFFFFF (internal area) except I/O area */
static void vdp_dma_68k_ram(unsigned int length)
{
uint16 data;
/* 68k bus source address */
uint32 source = (reg[23] << 17) | (dma_src << 1);
do
{
/* access Work-RAM by default */
data = *(uint16 *)(work_ram + (source & 0xFFFF));
/* Increment source address */
source += 2;
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* Write data word to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
}
while (--length);
/* Update DMA source address */
dma_src = (source >> 1) & 0xffff;
}
/* DMA from 68K bus: $A00000-$A1FFFF (I/O area) specific */
static void vdp_dma_68k_io(unsigned int length)
{
uint16 data;
/* 68k bus source address */
uint32 source = (reg[23] << 17) | (dma_src << 1);
do
{
/* Z80 area */
if (source <= 0xA0FFFF)
{
/* Return $FFFF only when the Z80 isn't hogging the Z-bus.
(e.g. Z80 isn't reset and 68000 has the bus) */
data = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xFFFF)) : 0xFFFF);
}
/* The I/O chip and work RAM try to drive the data bus which results
in both values being combined in random ways when read.
We return the I/O chip values which seem to have precedence, */
else if (source <= 0xA1001F)
{
data = io_68k_read((source >> 1) & 0x0F);
data = (data << 8 | data);
}
/* All remaining locations access work RAM */
else
{
data = *(uint16 *)(work_ram + (source & 0xFFFF));
}
/* Increment source address */
source += 2;
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* Write data to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
}
while (--length);
/* Update DMA source address */
dma_src = (source >> 1) & 0xffff;
@ -2989,12 +3017,14 @@ static void vdp_dma_copy(unsigned int length)
}
/* VRAM Fill (TODO: check if CRAM or VSRAM fill is possible) */
static void vdp_dma_fill(unsigned char data, unsigned int length)
static void vdp_dma_fill(unsigned int length)
{
/* VRAM write operation only (Williams Greatest Hits after soft reset) */
if ((code & 0x1F) == 0x01)
{
int name;
uint8 data = dmafill;
do
{
/* Intercept writes to Sprite Attribute Table */