snes.c: enabled PPU->CPU hdma transfer and moved hdma variables to snes_state [Fabio Priuli]

This commit is contained in:
Fabio Priuli 2010-03-27 14:37:14 +00:00
parent a851662549
commit 923be8ef3f
2 changed files with 190 additions and 138 deletions

View File

@ -402,8 +402,22 @@ public:
emu_timer *mult_timer;
/* DMA/HDMA-related */
int dma_disabled[8]; // used to stop DMA if HDMA is enabled (currently not implemented, see machine/snes.c)
UINT8 hdma_chnl; /* channels enabled for HDMA */
struct
{
UINT8 dmap;
UINT8 dest_addr;
UINT16 src_addr;
UINT16 trans_size;
UINT8 bank;
UINT8 ibank;
UINT16 hdma_addr;
UINT16 hdma_iaddr;
UINT8 hdma_line_counter;
UINT8 unk;
int dma_disabled; // used to stop DMA if HDMA is enabled (currently not implemented, see machine/snes.c)
}dma_channel[8];
UINT8 hdmaen; /* channels enabled for HDMA */
/* input-related */
UINT8 joy1l, joy1h, joy2l, joy2h, joy3l, joy3h, joy4l, joy4h;

View File

@ -232,7 +232,7 @@ static TIMER_CALLBACK( snes_hblank_tick )
if (video_screen_get_vpos(machine->primary_screen) > 0)
{
/* Do HDMA */
if (snes_ram[HDMAEN])
if (state->hdmaen)
snes_hdma(cpu0space);
video_screen_update_partial(machine->primary_screen, (snes_ppu.interlace == 2) ? (snes_ppu.beam.current_vert*snes_ppu.interlace) : snes_ppu.beam.current_vert-1);
@ -305,7 +305,7 @@ static void snes_dynamic_res_change( running_machine *machine )
visarea.max_x = (SNES_SCR_WIDTH * 2) - 1;
// fixme: should compensate for SNES_DBG_video
if (snes_ppu.mode == 5 || snes_ppu.mode == 6 )
if (snes_ppu.mode == 5 || snes_ppu.mode == 6 || snes_ppu.pseudo_hires)
state->htmult = 2;
else
state->htmult = 1;
@ -337,6 +337,22 @@ static READ8_HANDLER( snes_open_bus_r )
return result;
}
/*************************************************
SNES VRAM accesses:
VRAM accesses during active display are invalid.
Unlike OAM and CGRAM, they will not be written
anywhere at all. Thanks to byuu's researches,
the ranges where writes are invalid have been
validated on hardware, as has the edge case where
the S-CPU open bus can be written if the write
occurs during the very last clock cycle of
vblank.
Our implementation could be not 100% accurate
when interlace is active.
*************************************************/
INLINE UINT32 snes_get_vram_address( running_machine *machine )
{
snes_state *state = (snes_state *)machine->driver_data;
@ -352,13 +368,13 @@ INLINE UINT32 snes_get_vram_address( running_machine *machine )
return addr;
}
/* VRAM accesses during active display are invalid. */
static UINT16 snes_vram_read( const address_space *space, UINT32 addr )
static READ8_HANDLER( snes_vram_read )
{
UINT16 res = 0;
UINT8 res = 0;
offset &= 0x1ffff;
if (snes_ppu.screen_disabled)
res = snes_vram[addr & 0x1ffff] | snes_vram[(addr + 1) & 0x1ffff] << 8;
res = snes_vram[offset];
else
{
UINT16 v = video_screen_get_vpos(space->machine->primary_screen);
@ -375,20 +391,22 @@ static UINT16 snes_vram_read( const address_space *space, UINT32 addr )
else if (v == snes_ppu.beam.last_visible_line - 1)
{
if (h == 1362)
res = snes_vram[addr & 0x1ffff] | snes_vram[(addr + 1) & 0x1ffff] << 8;
res = snes_vram[offset];
else
res = 0;
}
else
res = snes_vram[addr & 0x1ffff] | snes_vram[(addr + 1) & 0x1ffff] << 8;
res = snes_vram[offset];
}
return res;
}
static void snes_vram_write( const address_space *space, UINT32 addr, UINT8 data )
static WRITE8_HANDLER( snes_vram_write )
{
offset &= 0x1ffff;
if (snes_ppu.screen_disabled)
snes_vram[addr & 0x1ffff] = data;
snes_vram[offset] = data;
else
{
UINT16 v = video_screen_get_vpos(space->machine->primary_screen);
@ -396,9 +414,9 @@ static void snes_vram_write( const address_space *space, UINT32 addr, UINT8 data
if (v == 0)
{
if (h <= 4)
snes_vram[addr & 0x1ffff] = data;
snes_vram[offset] = data;
else if (h == 6)
snes_vram[addr & 0x1ffff] = snes_open_bus_r(space, 0);
snes_vram[offset] = snes_open_bus_r(space, 0);
else
{
//no write
@ -415,12 +433,11 @@ static void snes_vram_write( const address_space *space, UINT32 addr, UINT8 data
//no write
}
else
snes_vram[addr & 0x1ffff] = data;
snes_vram[offset] = data;
}
else
snes_vram[addr & 0x1ffff] = data;
snes_vram[offset] = data;
}
}
/*
@ -536,7 +553,7 @@ READ8_HANDLER( snes_r_io )
snes_ppu.ppu1_open_bus = (snes_oam[oam_addr] >> (snes_ram[OAMDATA] << 3)) & 0xff;
snes_ram[OAMDATA] = (snes_ram[OAMDATA] + 1) % 2;
if (snes_ram[OAMDATA] == 0)
if (!snes_ram[OAMDATA])
{
snes_ppu.oam.address++;
snes_ppu.oam.address &= 0x1ff;
@ -552,6 +569,7 @@ READ8_HANDLER( snes_r_io )
if (!state->vram_fgr_high)
{
state->vram_read_buffer = snes_vram_read(space, addr);
state->vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8);
addr = ((snes_ram[VMADDH] << 8) | snes_ram[VMADDL]) + state->vram_fgr_increment;
snes_ram[VMADDL] = addr & 0xff;
@ -568,6 +586,7 @@ READ8_HANDLER( snes_r_io )
if (state->vram_fgr_high)
{
state->vram_read_buffer = snes_vram_read(space, addr);
state->vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8);
addr = ((snes_ram[VMADDH] << 8) | snes_ram[VMADDL]) + state->vram_fgr_increment;
snes_ram[VMADDL] = addr & 0xff;
@ -715,29 +734,40 @@ READ8_HANDLER( snes_r_io )
return state->joy4h;
case DMAP0: case DMAP1: case DMAP2: case DMAP3: /*0x43n0*/
case DMAP4: case DMAP5: case DMAP6: case DMAP7:
return state->dma_channel[(offset & 0x70) >> 4].dmap;
case BBAD0: case BBAD1: case BBAD2: case BBAD3: /*0x43n1*/
case BBAD4: case BBAD5: case BBAD6: case BBAD7:
return state->dma_channel[(offset & 0x70) >> 4].dest_addr;
case A1T0L: case A1T1L: case A1T2L: case A1T3L: /*0x43n2*/
case A1T4L: case A1T5L: case A1T6L: case A1T7L:
return state->dma_channel[(offset & 0x70) >> 4].src_addr & 0xff;
case A1T0H: case A1T1H: case A1T2H: case A1T3H: /*0x43n3*/
case A1T4H: case A1T5H: case A1T6H: case A1T7H:
return (state->dma_channel[(offset & 0x70) >> 4].src_addr >> 8) & 0xff;
case A1B0: case A1B1: case A1B2: case A1B3: /*0x43n4*/
case A1B4: case A1B5: case A1B6: case A1B7:
return state->dma_channel[(offset & 0x70) >> 4].bank;
case DAS0L: case DAS1L: case DAS2L: case DAS3L: /*0x43n5*/
case DAS4L: case DAS5L: case DAS6L: case DAS7L:
return state->dma_channel[(offset & 0x70) >> 4].trans_size & 0xff;
case DAS0H: case DAS1H: case DAS2H: case DAS3H: /*0x43n6*/
case DAS4H: case DAS5H: case DAS6H: case DAS7H:
return (state->dma_channel[(offset & 0x70) >> 4].trans_size >> 8) & 0xff;
case DSAB0: case DSAB1: case DSAB2: case DSAB3: /*0x43n7*/
case DSAB4: case DSAB5: case DSAB6: case DSAB7:
return state->dma_channel[(offset & 0x70) >> 4].ibank;
case A2A0L: case A2A1L: case A2A2L: case A2A3L: /*0x43n8*/
case A2A4L: case A2A5L: case A2A6L: case A2A7L:
return state->dma_channel[(offset & 0x70) >> 4].hdma_addr & 0xff;
case A2A0H: case A2A1H: case A2A2H: case A2A3H: /*0x43n9*/
case A2A4H: case A2A5H: case A2A6H: case A2A7H:
return (state->dma_channel[(offset & 0x70) >> 4].hdma_addr >> 8) & 0xff;
case NTRL0: case NTRL1: case NTRL2: case NTRL3: /*0x43na*/
case NTRL4: case NTRL5: case NTRL6: case NTRL7:
return state->dma_channel[(offset & 0x70) >> 4].hdma_line_counter;
case 0x430b: case 0x431b: case 0x432b: case 0x433b: /* according to bsnes, this does not return open_bus (even if its precise effect is unknown) */
case 0x434b: case 0x435b: case 0x436b: case 0x437b:
return snes_ram[offset];
return state->dma_channel[(offset & 0x70) >> 4].unk;
#ifndef MESS
case 0x4100: /* NSS Dip-Switches */
@ -994,6 +1024,7 @@ WRITE8_HANDLER( snes_w_io )
snes_ram[offset] = data;
addr = snes_get_vram_address(space->machine) << 1;
state->vram_read_buffer = snes_vram_read(space, addr);
state->vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8);
}
break;
case VMDATAL: /* 2118: Data for VRAM write (low) */
@ -1178,7 +1209,6 @@ WRITE8_HANDLER( snes_w_io )
snes_ppu.layer[SNES_OAM].sub_window_enabled = BIT(data, 4);
break;
case CGWSEL: /* Initial settings for Fixed colour addition or screen addition */
/* FIXME: We don't support direct select for modes 3 & 4 or subscreen window stuff */
snes_ppu.clip_to_black = (data >> 6) & 0x03;
snes_ppu.prevent_color_math = (data >> 4) & 0x03;
snes_ppu.sub_add_mode = BIT(data, 1);
@ -1305,7 +1335,8 @@ WRITE8_HANDLER( snes_w_io )
data = 0; /* Once DMA is done we need to reset all bits to 0 */
break;
case HDMAEN: /* HDMA channel designation */
if (data) //if a HDMA is enabled, data is inited at the next scanline
state->hdmaen = data;
if (state->hdmaen) //if a HDMA is enabled, data is inited at the next scanline
timer_set(space->machine, video_screen_get_time_until_pos(space->machine->primary_screen, snes_ppu.beam.current_vert + 1, 0), NULL, 0, snes_reset_hdma);
break;
case MEMSEL: /* Access cycle designation in memory (2) area */
@ -1345,28 +1376,51 @@ WRITE8_HANDLER( snes_w_io )
/* Below is all DMA related */
case DMAP0: case DMAP1: case DMAP2: case DMAP3: /*0x43n0*/
case DMAP4: case DMAP5: case DMAP6: case DMAP7:
state->dma_channel[(offset & 0x70) >> 4].dmap = data;
break;
case BBAD0: case BBAD1: case BBAD2: case BBAD3: /*0x43n1*/
case BBAD4: case BBAD5: case BBAD6: case BBAD7:
state->dma_channel[(offset & 0x70) >> 4].dest_addr = data;
break;
case A1T0L: case A1T1L: case A1T2L: case A1T3L: /*0x43n2*/
case A1T4L: case A1T5L: case A1T6L: case A1T7L:
state->dma_channel[(offset & 0x70) >> 4].src_addr = (state->dma_channel[(offset & 0x70) >> 4].src_addr & 0xff00) | (data << 0);
break;
case A1T0H: case A1T1H: case A1T2H: case A1T3H: /*0x43n3*/
case A1T4H: case A1T5H: case A1T6H: case A1T7H:
state->dma_channel[(offset & 0x70) >> 4].src_addr = (state->dma_channel[(offset & 0x70) >> 4].src_addr & 0x00ff) | (data << 8);
break;
case A1B0: case A1B1: case A1B2: case A1B3: /*0x43n4*/
case A1B4: case A1B5: case A1B6: case A1B7:
state->dma_channel[(offset & 0x70) >> 4].bank = data;
break;
case DAS0L: case DAS1L: case DAS2L: case DAS3L: /*0x43n5*/
case DAS4L: case DAS5L: case DAS6L: case DAS7L:
state->dma_channel[(offset & 0x70) >> 4].trans_size = (state->dma_channel[(offset & 0x70) >> 4].trans_size & 0xff00) | (data << 0);
break;
case DAS0H: case DAS1H: case DAS2H: case DAS3H: /*0x43n6*/
case DAS4H: case DAS5H: case DAS6H: case DAS7H:
state->dma_channel[(offset & 0x70) >> 4].trans_size = (state->dma_channel[(offset & 0x70) >> 4].trans_size & 0x00ff) | (data << 8);
break;
case DSAB0: case DSAB1: case DSAB2: case DSAB3: /*0x43n7*/
case DSAB4: case DSAB5: case DSAB6: case DSAB7:
state->dma_channel[(offset & 0x70) >> 4].ibank = data;
break;
case A2A0L: case A2A1L: case A2A2L: case A2A3L: /*0x43n8*/
case A2A4L: case A2A5L: case A2A6L: case A2A7L:
state->dma_channel[(offset & 0x70) >> 4].hdma_addr = (state->dma_channel[(offset & 0x70) >> 4].hdma_addr & 0xff00) | (data << 0);
break;
case A2A0H: case A2A1H: case A2A2H: case A2A3H: /*0x43n9*/
case A2A4H: case A2A5H: case A2A6H: case A2A7H:
state->dma_channel[(offset & 0x70) >> 4].hdma_addr = (state->dma_channel[(offset & 0x70) >> 4].hdma_addr & 0x00ff) | (data << 8);
break;
case NTRL0: case NTRL1: case NTRL2: case NTRL3: /*0x43na*/
case NTRL4: case NTRL5: case NTRL6: case NTRL7:
state->dma_channel[(offset & 0x70) >> 4].hdma_line_counter = data;
break;
case 0x430b: case 0x431b: case 0x432b: case 0x433b:
case 0x434b: case 0x435b: case 0x436b: case 0x437b:
state->dma_channel[(offset & 0x70) >> 4].unk = data;
break;
}
@ -2398,9 +2452,10 @@ static int dma_abus_valid( UINT32 address )
INLINE void snes_dma_transfer( const address_space *space, UINT8 dma, UINT32 abus, UINT16 bbus )
{
snes_state *state = (snes_state *)space->machine->driver_data;
UINT32 src, dst;
if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */
if (state->dma_channel[dma].dmap & 0x80) /* PPU->CPU */
{
if (bbus == 0x2180 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000))
{
@ -2436,121 +2491,122 @@ INLINE void snes_dma_transfer( const address_space *space, UINT8 dma, UINT32 abu
}
#if 0
INLINE void snes_dma_transfer( const address_space *space, UINT8 dma, UINT32 abus, UINT16 bbus )
// FIXME: we need to use snes_state->hdma_iaddr[i] where appropriate (we now still
// use snes_state->trans_size[i] to avoid regressions in this first wip)
// and try to make the addr recovering/updating a bit more abstract
INLINE UINT32 snes_get_hdma_addr( running_machine *machine, int dma )
{
/* TODO: implement open bus access when DMA tries to transfer from not accessible regs */
if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */
memory_write_byte(space, abus, memory_read_byte(space, bbus));
else /* CPU->PPU */
memory_write_byte(space, bbus, memory_read_byte(space, abus));
snes_state *state = (snes_state *)machine->driver_data;
return (state->dma_channel[dma].bank << 16) | (state->dma_channel[dma].hdma_addr++);
}
INLINE UINT32 snes_get_hdma_iaddr( running_machine *machine, int dma )
{
snes_state *state = (snes_state *)machine->driver_data;
return (state->dma_channel[dma].ibank << 16) | (state->dma_channel[dma].hdma_iaddr++);
}
#endif
static void snes_hdma_init( running_machine *machine )
{
snes_state *state = (snes_state *)machine->driver_data;
UINT8 mask = 1, dma = 0, i;
int i;
state->hdma_chnl = snes_ram[HDMAEN];
for (i = 0; i < 8; i++)
{
if (snes_ram[HDMAEN] & mask)
if (BIT(state->hdmaen, i))
{
snes_ram[SNES_DMA_BASE + dma + 8] = snes_ram[SNES_DMA_BASE + dma + 2];
snes_ram[SNES_DMA_BASE + dma + 9] = snes_ram[SNES_DMA_BASE + dma + 3];
snes_ram[SNES_DMA_BASE + dma + 0xa] = 0;
state->dma_channel[i].hdma_addr = state->dma_channel[i].src_addr;
state->dma_channel[i].hdma_line_counter = 0;
}
dma += 0x10;
mask <<= 1;
}
}
static void snes_hdma( const address_space *space )
{
snes_state *state = (snes_state *)space->machine->driver_data;
UINT8 mask = 1, dma = 0, i, contmode;
UINT8 i, contmode;
UINT16 bbus;
UINT32 abus;
/* Assume priority of the 8 DMA channels is 0-7 */
for (i = 0; i < 8; i++)
{
if (state->hdma_chnl & mask)
if (BIT(state->hdmaen, i))
{
/* Check if we need to read a new line from the table */
if (!(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f))
if (!(state->dma_channel[i].hdma_line_counter & 0x7f))
{
abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 9] << 8) + snes_ram[SNES_DMA_BASE + dma + 8];
abus = (state->dma_channel[i].bank << 16) + state->dma_channel[i].hdma_addr;
/* Get the number of lines */
snes_ram[SNES_DMA_BASE + dma + 0xa] = memory_read_byte(space, abus);
if (!snes_ram[SNES_DMA_BASE + dma + 0xa])
state->dma_channel[i].hdma_line_counter = memory_read_byte(space, abus);
if (!state->dma_channel[i].hdma_line_counter)
{
/* No more lines so clear HDMA */
state->hdma_chnl &= ~mask;
state->hdmaen &= ~(1 << i);
continue;
}
abus++;
snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
if (snes_ram[SNES_DMA_BASE + dma] & 0x40)
state->dma_channel[i].hdma_addr = abus;
if (state->dma_channel[i].dmap & 0x40)
{
snes_ram[SNES_DMA_BASE + dma + 5] = memory_read_byte(space, abus++);
snes_ram[SNES_DMA_BASE + dma + 6] = memory_read_byte(space, abus++);
snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
state->dma_channel[i].trans_size = memory_read_byte(space, abus++);
state->dma_channel[i].trans_size |= (memory_read_byte(space, abus++) << 8);
state->dma_channel[i].hdma_addr = abus;
}
}
contmode = (--snes_ram[SNES_DMA_BASE + dma + 0xa]) & 0x80;
contmode = (--state->dma_channel[i].hdma_line_counter) & 0x80;
/* Transfer addresses */
if (snes_ram[SNES_DMA_BASE + dma] & 0x40) /* Indirect */
abus = (snes_ram[SNES_DMA_BASE + dma + 7] << 16) + (snes_ram[SNES_DMA_BASE + dma + 6] << 8) + snes_ram[SNES_DMA_BASE + dma + 5];
if (state->dma_channel[i].dmap & 0x40) /* Indirect */
abus = (state->dma_channel[i].ibank << 16) + state->dma_channel[i].trans_size;
else /* Absolute */
abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 9] << 8) + snes_ram[SNES_DMA_BASE + dma + 8];
bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1];
abus = (state->dma_channel[i].bank << 16) + state->dma_channel[i].hdma_addr;
bbus = state->dma_channel[i].dest_addr + 0x2100;
#ifdef SNES_DBG_HDMA
mame_printf_debug( "HDMA-Ch: %d(%s) abus: %X bbus: %X type: %d(%X %X)\n", i, snes_ram[SNES_DMA_BASE + dma] & 0x40 ? "Indirect" : "Absolute", abus, bbus, snes_ram[SNES_DMA_BASE + dma] & 0x07, snes_ram[SNES_DMA_BASE + dma + 8],snes_ram[SNES_DMA_BASE + dma + 9] );
mame_printf_debug( "HDMA-Ch: %d(%s) abus: %X bbus: %X type: %d(%X)\n", i, state->dma_channel[i].dmap & 0x40 ? "Indirect" : "Absolute", abus, bbus, state->dma_channel[i].dmap & 0x07, state->dma_channel[i].hdma_addr);
#endif
switch (snes_ram[SNES_DMA_BASE + dma] & 0x07)
switch (state->dma_channel[i].dmap & 0x07)
{
case 0: /* 1 register write once (1 byte: p ) */
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
snes_dma_transfer(space, i, abus++, bbus);
break;
case 5: /* 2 registers write twice alternate (4 bytes: p, p+1, p, p+1) */
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++));
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++));
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus + 1);
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus + 1);
break;
case 1: /* 2 registers write once (2 bytes: p, p+1 ) */
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++));
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus + 1);
break;
case 2: /* 1 register write twice (2 bytes: p, p ) */
case 6:
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus);
break;
case 3: /* 2 registers write twice each (4 bytes: p, p, p+1, p+1) */
case 7:
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++));
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus + 1);
snes_dma_transfer(space, i, abus++, bbus + 1);
break;
case 4: /* 4 registers write once (4 bytes: p, p+1, p+2, p+3) */
memory_write_byte(space, bbus, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 2, memory_read_byte(space, abus++));
memory_write_byte(space, bbus + 3, memory_read_byte(space, abus++));
snes_dma_transfer(space, i, abus++, bbus);
snes_dma_transfer(space, i, abus++, bbus + 1);
snes_dma_transfer(space, i, abus++, bbus + 2);
snes_dma_transfer(space, i, abus++, bbus + 3);
break;
default:
#ifdef MAME_DEBUG
mame_printf_debug( " HDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x07);
mame_printf_debug( " HDMA of unsupported type: %d\n", state->dma_channel[i].dmap & 0x07);
#endif
break;
}
@ -2558,39 +2614,28 @@ static void snes_hdma( const address_space *space )
/* Update address */
if (contmode)
{
if (snes_ram[SNES_DMA_BASE + dma] & 0x40) /* Indirect */
{
snes_ram[SNES_DMA_BASE + dma + 5] = abus & 0xff;
snes_ram[SNES_DMA_BASE + dma + 6] = (abus >> 8) & 0xff;
}
if (state->dma_channel[i].dmap & 0x40) /* Indirect */
state->dma_channel[i].trans_size = abus;
else /* Absolute */
{
snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
}
state->dma_channel[i].hdma_addr = abus;
}
if (!(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f))
if (!(state->dma_channel[i].hdma_line_counter & 0x7f))
{
if (!(snes_ram[SNES_DMA_BASE + dma] & 0x40)) /* Absolute */
if (!(state->dma_channel[i].dmap & 0x40)) /* Absolute */
{
if (!contmode)
{
snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
}
state->dma_channel[i].hdma_addr = abus;
}
}
}
dma += 0x10;
mask <<= 1;
}
}
static void snes_dma( const address_space *space, UINT8 channels )
{
snes_state *state = (snes_state *)space->machine->driver_data;
UINT8 mask = 1, dma = 0, i;
int i;
INT8 increment;
UINT16 bbus;
UINT32 abus, abus_bank, length;
@ -2598,121 +2643,114 @@ static void snes_dma( const address_space *space, UINT8 channels )
/* Assume priority of the 8 DMA channels is 0-7 */
for (i = 0; i < 8; i++)
{
if (channels & mask)
if (BIT(channels, i))
{
/* FIXME: the following should be used to stop DMA if the same channel is used by HDMA (being set to 1 in snes_hdma)
However, this cannot be implemented as is atm, because currently DMA transfers always happen as soon as they are enabled... */
state->dma_disabled[i] = 0;
state->dma_channel[i].dma_disabled = 0;
//printf( "Making a transfer on channel %d\n", i );
/* Find transfer addresses */
abus = (snes_ram[SNES_DMA_BASE + dma + 3] << 8) + snes_ram[SNES_DMA_BASE + dma + 2];
abus_bank = (snes_ram[SNES_DMA_BASE + dma + 4] << 16);
bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1];
abus = state->dma_channel[i].src_addr;
abus_bank = state->dma_channel[i].bank << 16;
bbus = state->dma_channel[i].dest_addr + 0x2100;
//printf( "Address: %06x\n", abus | abus_bank );
//printf("Address: %06x\n", abus | abus_bank);
/* Auto increment */
if (snes_ram[SNES_DMA_BASE + dma] & 0x8)
{
if (state->dma_channel[i].dmap & 0x8)
increment = 0;
}
else
{
if (snes_ram[SNES_DMA_BASE + dma] & 0x10)
if (state->dma_channel[i].dmap & 0x10)
increment = -1;
else
increment = 1;
}
/* Number of bytes to transfer */
length = (snes_ram[SNES_DMA_BASE + dma + 6] << 8) + snes_ram[SNES_DMA_BASE + dma + 5];
length = state->dma_channel[i].trans_size;
if (!length)
length = 0x10000; /* 0x0000 really means 0x10000 */
// printf( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, snes_ram[SNES_DMA_BASE + dma] & 0x80 ? "PPU->CPU" : "CPU->PPU", snes_ram[SNES_DMA_BASE + dma] & 0x07);
// printf( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, state->dma_channel[i].dmap & 0x80 ? "PPU->CPU" : "CPU->PPU", state->dma_channel[i].dmap & 0x07);
#ifdef SNES_DBG_DMA
mame_printf_debug( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, snes_ram[SNES_DMA_BASE + dma] & 0x80 ? "PPU->CPU" : "CPU->PPU", snes_ram[SNES_DMA_BASE + dma] & 0x07);
mame_printf_debug( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, state->dma_channel[i].dmap & 0x80 ? "PPU->CPU" : "CPU->PPU", state->dma_channel[i].dmap & 0x07);
#endif
switch (snes_ram[SNES_DMA_BASE + dma] & 0x07)
switch (state->dma_channel[i].dmap & 0x07)
{
case 0: /* 1 register write once */
case 2: /* 1 register write twice */
case 6: /* 1 register write twice */
while (length-- && !state->dma_disabled[i])
while (length-- && !state->dma_channel[i].dma_disabled)
{
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus);
abus += increment;
}
break;
case 1: /* 2 registers write once */
case 5: /* 2 registers write twice alternate */
while (length-- && !state->dma_disabled[i])
while (length-- && !state->dma_channel[i].dma_disabled)
{
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1);
abus += increment;
}
break;
case 3: /* 2 registers write twice each */
case 7: /* 2 registers write twice each */
while (length-- && !state->dma_disabled[i])
while (length-- && !state->dma_channel[i].dma_disabled)
{
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1);
abus += increment;
}
break;
case 4: /* 4 registers write once */
while (length-- && !state->dma_disabled[i])
while (length-- && !state->dma_channel[i].dma_disabled)
{
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 2);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 2);
abus += increment;
if (!(length--) || state->dma_disabled[i])
if (!(length--) || state->dma_channel[i].dma_disabled)
break;
snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 3);
snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 3);
abus += increment;
}
break;
default:
#ifdef MAME_DEBUG
mame_printf_debug( " DMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x07);
mame_printf_debug(" DMA of unsupported type: %d\n", state->dma_channel[i].dmap & 0x07);
#endif
break;
}
/* We're done so write the new abus back to the registers */
snes_w_io(space, SNES_DMA_BASE + dma + 2, abus & 0xff);
snes_w_io(space, SNES_DMA_BASE + dma + 3, (abus >> 8) & 0xff);
snes_w_io(space, SNES_DMA_BASE + dma + 5, 0);
snes_w_io(space, SNES_DMA_BASE + dma + 6, 0);
/* We're done, so write the new abus back to the registers */
state->dma_channel[i].src_addr = abus;
state->dma_channel[i].trans_size = 0;
}
dma += 0x10;
mask <<= 1;
}
}