diff --git a/.gitattributes b/.gitattributes index 76f626bb616..723537cb085 100644 --- a/.gitattributes +++ b/.gitattributes @@ -374,6 +374,8 @@ src/emu/cpu/pps4/pps4.h svneol=native#text/plain src/emu/cpu/pps4/pps4dasm.c svneol=native#text/plain src/emu/cpu/psx/dismips.c svneol=native#text/plain src/emu/cpu/psx/dismips.mak svneol=native#text/plain +src/emu/cpu/psx/dma.c svneol=native#text/plain +src/emu/cpu/psx/dma.h svneol=native#text/plain src/emu/cpu/psx/gte.c svneol=native#text/plain src/emu/cpu/psx/gte.h svneol=native#text/plain src/emu/cpu/psx/psx.c svneol=native#text/plain diff --git a/src/emu/addrmap.c b/src/emu/addrmap.c index 419e16b056a..12985a49ba7 100644 --- a/src/emu/addrmap.c +++ b/src/emu/addrmap.c @@ -60,7 +60,7 @@ inline void map_handler_data::set_tag(const device_t &device, const char *tag) m_tag = device.owner()->tag(); } else - m_tag = device.siblingtag(m_derived_tag, tag); + m_tag = device.subtag(m_derived_tag, tag); } @@ -718,7 +718,7 @@ address_map::address_map(const device_t &device, address_spacenum spacenum) // construct the standard map */ if (memintf->address_map(spacenum) != NULL) - (*memintf->address_map(spacenum))(*this, device); + (*memintf->address_map(spacenum))(*this, *device.owner()); // append the default device map (last so it can be overridden) */ if (spaceconfig->m_default_map != NULL) diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index 17dee47524f..ce97d45e165 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -885,17 +885,20 @@ $(CPUOBJ)/mips/mips3drc.o: $(CPUSRC)/mips/mips3drc.c \ ifneq ($(filter PSX,$(CPUS)),) OBJDIRS += $(CPUOBJ)/psx -CPUOBJS += $(CPUOBJ)/psx/psx.o $(CPUOBJ)/psx/gte.o +CPUOBJS += $(CPUOBJ)/psx/psx.o $(CPUOBJ)/psx/gte.o $(CPUOBJ)/psx/dma.o DASMOBJS += $(CPUOBJ)/psx/psxdasm.o endif $(CPUOBJ)/psx/psx.o: $(CPUSRC)/psx/psx.c \ $(CPUSRC)/psx/psx.h \ + $(CPUSRC)/psx/dma.h \ $(CPUSRC)/psx/gte.h \ $(CPUOBJ)/psx/gte.o: $(CPUSRC)/psx/gte.c \ $(CPUSRC)/psx/gte.h +$(CPUOBJ)/psx/dma.o: $(CPUSRC)/psx/dma.c \ + $(CPUSRC)/psx/dma.h #------------------------------------------------- # Mitsubishi M37702 and M37710 (based on 65C816) diff --git a/src/emu/cpu/psx/dma.c b/src/emu/cpu/psx/dma.c new file mode 100644 index 00000000000..f8aa84c2f32 --- /dev/null +++ b/src/emu/cpu/psx/dma.c @@ -0,0 +1,428 @@ +/* + * PlayStation DMA emulator + * + * Copyright 2003-2011 smf + * + */ + +#include "emu.h" +#include "dma.h" +#include "includes/psx.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +const device_type PSX_DMA = &device_creator; + +psxdma_device::psxdma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PSX_DMA, "PSX DMA", tag, owner, clock) +{ + for( int index = 0; index < 7; index++ ) + { + psx_dma_channel *dma = &channel[ index ]; + + dma->fn_read = NULL; + dma->fn_write = NULL; + } +} + +void psxdma_device::device_reset() +{ + int n; + + n_dpcp = 0; + n_dicr = 0; + + for( n = 0; n < 7; n++ ) + { + dma_stop_timer( n ); + } +} + +void psxdma_device::device_post_load() +{ + int n; + + for( n = 0; n < 7; n++ ) + { + dma_timer_adjust( n ); + } +} + +void psxdma_device::device_start() +{ + for( int index = 0; index < 7; index++ ) + { + psx_dma_channel *dma = &channel[ index ]; + + dma->timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psxdma_device::dma_finished_callback), this)); + + machine().save().save_item( "psxdma", tag(), index, NAME(dma->n_base) ); + machine().save().save_item( "psxdma", tag(), index, NAME(dma->n_blockcontrol) ); + machine().save().save_item( "psxdma", tag(), index, NAME(dma->n_channelcontrol) ); + machine().save().save_item( "psxdma", tag(), index, NAME(dma->n_ticks) ); + machine().save().save_item( "psxdma", tag(), index, NAME(dma->b_running) ); + } + + save_item( NAME(n_dpcp) ); + save_item( NAME(n_dicr) ); +} + +void psxdma_device::dma_start_timer( int index, UINT32 n_ticks ) +{ + psx_dma_channel *dma = &channel[ index ]; + + dma->timer->adjust( attotime::from_hz(33868800) * n_ticks, index); + dma->n_ticks = n_ticks; + dma->b_running = 1; +} + +void psxdma_device::dma_stop_timer( int index ) +{ + psx_dma_channel *dma = &channel[ index ]; + + dma->timer->adjust( attotime::never); + dma->b_running = 0; +} + +void psxdma_device::dma_timer_adjust( int index ) +{ + psx_dma_channel *dma = &channel[ index ]; + + if( dma->b_running ) + { + dma_start_timer( index, dma->n_ticks ); + } + else + { + dma_stop_timer( index ); + } +} + +void psxdma_device::dma_interrupt_update() +{ + int n_int; + int n_mask; + + n_int = ( n_dicr >> 24 ) & 0x7f; + n_mask = ( n_dicr >> 16 ) & 0xff; + + if( ( n_mask & 0x80 ) != 0 && ( n_int & n_mask ) != 0 ) + { + verboselog( machine(), 2, "dma_interrupt_update( %02x, %02x ) interrupt triggered\n", n_int, n_mask ); + n_dicr |= 0x80000000; + psx_irq_set( machine(), PSX_IRQ_DMA ); + } + else if( n_int != 0 ) + { + verboselog( machine(), 2, "dma_interrupt_update( %02x, %02x ) interrupt not enabled\n", n_int, n_mask ); + } + n_dicr &= 0x00ffffff | ( n_dicr << 8 ); +} + +void psxdma_device::dma_finished( int index ) +{ + psx_machine *p_psx = machine().driver_data()->m_p_psx; + + UINT32 *p_n_psxram = p_psx->p_n_psxram; + psx_dma_channel *dma = &channel[ index ]; + + if( dma->n_channelcontrol == 0x01000401 && index == 2 ) + { + UINT32 n_size; + UINT32 n_total; + UINT32 n_address = ( dma->n_base & 0xffffff ); + UINT32 n_adrmask = p_psx->n_psxramsize - 1; + UINT32 n_nextaddress; + + if( n_address != 0xffffff ) + { + n_total = 0; + for( ;; ) + { + if( n_address == 0xffffff ) + { + dma->n_base = n_address; + dma_start_timer( index, 19000 ); + return; + } + if( n_total > 65535 ) + { + dma->n_base = n_address; + //FIXME: + // 16000 below is based on try and error. + // Mametesters.org: sfex20103red + //dma_start_timer( index, 16 ); + dma_start_timer( index, 16000 ); + return; + } + n_address &= n_adrmask; + n_nextaddress = p_n_psxram[ n_address / 4 ]; + n_size = n_nextaddress >> 24; + (*dma->fn_write)( machine(), n_address + 4, n_size ); + //FIXME: + // The following conditions will cause an endless loop. + // If stopping the transfer is correct I cannot judge + // The patch is meant as a hint for somebody who knows + // the hardware. + // Mametesters.org: psyforce0105u5red, raystorm0111u1red + if ((n_nextaddress & 0xffffff) != 0xffffff) + if (n_address == p_n_psxram[ (n_nextaddress & 0xffffff) / 4]) + break; + if (n_address == (n_nextaddress & 0xffffff) ) + break; + n_address = ( n_nextaddress & 0xffffff ); + + n_total += ( n_size + 1 ); + } + } + } + + dma->n_channelcontrol &= ~( ( 1L << 0x18 ) | ( 1L << 0x1c ) ); + + n_dicr |= 1 << ( 24 + index ); + dma_interrupt_update(); + dma_stop_timer( index ); +} + +void psxdma_device::dma_finished_callback(void *ptr, int param) +{ + dma_finished(param); +} + +void psxdma_device::install_read_handler( int index, psx_dma_read_handler p_fn_dma_read ) +{ + channel[ index ].fn_read = p_fn_dma_read; +} + +void psxdma_device::install_write_handler( int index, psx_dma_read_handler p_fn_dma_write ) +{ + channel[ index ].fn_write = p_fn_dma_write; +} + +WRITE32_MEMBER( psxdma_device::write ) +{ + psx_machine *p_psx = machine().driver_data()->m_p_psx; + + UINT32 *p_n_psxram = p_psx->p_n_psxram; + int index = offset / 4; + psx_dma_channel *dma = &channel[ index ]; + + if( index < 7 ) + { + switch( offset % 4 ) + { + case 0: + verboselog( machine(), 2, "dmabase( %d ) = %08x\n", index, data ); + dma->n_base = data; + break; + case 1: + verboselog( machine(), 2, "dmablockcontrol( %d ) = %08x\n", index, data ); + dma->n_blockcontrol = data; + break; + case 2: + verboselog( machine(), 2, "dmachannelcontrol( %d ) = %08x\n", index, data ); + dma->n_channelcontrol = data; + if( ( dma->n_channelcontrol & ( 1L << 0x18 ) ) != 0 && ( n_dpcp & ( 1 << ( 3 + ( index * 4 ) ) ) ) != 0 ) + { + INT32 n_size; + UINT32 n_address; + UINT32 n_nextaddress; + UINT32 n_adrmask; + + n_adrmask = p_psx->n_psxramsize - 1; + + n_address = ( dma->n_base & n_adrmask ); + n_size = dma->n_blockcontrol; + if( ( dma->n_channelcontrol & 0x200 ) != 0 ) + { + UINT32 n_ba; + n_ba = dma->n_blockcontrol >> 16; + if( n_ba == 0 ) + { + n_ba = 0x10000; + } + n_size = ( n_size & 0xffff ) * n_ba; + } + + if( dma->n_channelcontrol == 0x01000000 && + dma->fn_read != NULL ) + { + verboselog( machine(), 1, "dma %d read block %08x %08x\n", index, n_address, n_size ); + (*dma->fn_read)( machine(), n_address, n_size ); + dma_finished( index ); + } + else if (dma->n_channelcontrol == 0x11000000 && // CD DMA + dma->fn_read != NULL ) + { + verboselog( machine(), 1, "dma %d read block %08x %08x\n", index, n_address, n_size ); + + // pSX's CD DMA size calc formula + int oursize = (dma->n_blockcontrol>>16); + oursize = (oursize > 1) ? oursize : 1; + oursize *= (dma->n_blockcontrol&0xffff); + + (*dma->fn_read)( machine(), n_address, oursize ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x01000200 && + dma->fn_read != NULL ) + { + verboselog( machine(), 1, "dma %d read block %08x %08x\n", index, n_address, n_size ); + (*dma->fn_read)( machine(), n_address, n_size ); + if( index == 1 ) + { + dma_start_timer( index, 26000 ); + } + else + { + dma_finished( index ); + } + } + else if( dma->n_channelcontrol == 0x01000201 && + dma->fn_write != NULL ) + { + verboselog( machine(), 1, "dma %d write block %08x %08x\n", index, n_address, n_size ); + (*dma->fn_write)( machine(), n_address, n_size ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x11050100 && + dma->fn_write != NULL ) + { + /* todo: check this is a write not a read... */ + verboselog( machine(), 1, "dma %d write block %08x %08x\n", index, n_address, n_size ); + (*dma->fn_write)( machine(), n_address, n_size ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x11150100 && + dma->fn_write != NULL ) + { + /* todo: check this is a write not a read... */ + verboselog( machine(), 1, "dma %d write block %08x %08x\n", index, n_address, n_size ); + (*dma->fn_write)( machine(), n_address, n_size ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x01000401 && + index == 2 && + dma->fn_write != NULL ) + { + verboselog( machine(), 1, "dma %d write linked list %08x\n", + index, dma->n_base ); + + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x11000002 && + index == 6 ) + { + verboselog( machine(), 1, "dma 6 reverse clear %08x %08x\n", + dma->n_base, dma->n_blockcontrol ); + if( n_size > 0 ) + { + n_size--; + while( n_size > 0 ) + { + n_nextaddress = ( n_address - 4 ) & 0xffffff; + p_n_psxram[ n_address / 4 ] = n_nextaddress; + n_address = n_nextaddress; + n_size--; + } + p_n_psxram[ n_address / 4 ] = 0xffffff; + } + dma_start_timer( index, 2150 ); + } + else + { + verboselog( machine(), 1, "dma %d unknown mode %08x\n", index, dma->n_channelcontrol ); + } + } + else if( dma->n_channelcontrol != 0 ) + { + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) channel not enabled\n", offset, dma->n_channelcontrol, mem_mask ); + } + break; + default: + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) Unknown dma channel register\n", offset, data, mem_mask ); + break; + } + } + else + { + switch( offset % 4 ) + { + case 0x0: + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) dpcp\n", offset, data, mem_mask ); + n_dpcp = ( n_dpcp & ~mem_mask ) | data; + break; + case 0x1: + + n_dicr = ( n_dicr & ( 0x80000000 | ~mem_mask ) ) | + ( n_dicr & ~data & 0x7f000000 & mem_mask ) | + ( data & 0x00ffffff & mem_mask ); + + if( ( n_dicr & 0x80000000 ) != 0 && ( n_dicr & 0x7f000000 ) == 0 ) + { + verboselog( machine(), 2, "dma interrupt cleared\n" ); + n_dicr &= ~0x80000000; + } + + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) dicr -> %08x\n", offset, data, mem_mask, n_dicr ); + break; + default: + verboselog( machine(), 0, "psx_dma_w( %04x, %08x, %08x ) Unknown dma control register\n", offset, data, mem_mask ); + break; + } + } +} + +READ32_MEMBER( psxdma_device::read ) +{ + int index = offset / 4; + psx_dma_channel *dma = &channel[ index ]; + + if( index < 7 ) + { + switch( offset % 4 ) + { + case 0: + verboselog( machine(), 1, "psx_dma_r dmabase[ %d ] ( %08x )\n", index, dma->n_base ); + return dma->n_base; + case 1: + verboselog( machine(), 1, "psx_dma_r dmablockcontrol[ %d ] ( %08x )\n", index, dma->n_blockcontrol ); + return dma->n_blockcontrol; + case 2: + verboselog( machine(), 1, "psx_dma_r dmachannelcontrol[ %d ] ( %08x )\n", index, dma->n_channelcontrol ); + return dma->n_channelcontrol; + default: + verboselog( machine(), 0, "psx_dma_r( %08x, %08x ) Unknown dma channel register\n", offset, mem_mask ); + break; + } + } + else + { + switch( offset % 4 ) + { + case 0x0: + verboselog( machine(), 1, "psx_dma_r dpcp ( %08x )\n", n_dpcp ); + return n_dpcp; + case 0x1: + verboselog( machine(), 1, "psx_dma_r dicr ( %08x )\n", n_dicr ); + return n_dicr; + default: + verboselog( machine(), 0, "psx_dma_r( %08x, %08x ) Unknown dma control register\n", offset, mem_mask ); + break; + } + } + return 0; +} diff --git a/src/emu/cpu/psx/dma.h b/src/emu/cpu/psx/dma.h new file mode 100644 index 00000000000..0147712491e --- /dev/null +++ b/src/emu/cpu/psx/dma.h @@ -0,0 +1,63 @@ +/* + * PlayStation DMA emulator + * + * Copyright 2003-2011 smf + * + */ + +#if !defined(PSXDMA_H) + +#define PSXDMA_H (1) + +#include "emu.h" + +extern const device_type PSX_DMA; + +typedef void ( *psx_dma_read_handler )( running_machine &, UINT32, INT32 ); +typedef void ( *psx_dma_write_handler )( running_machine &, UINT32, INT32 ); + +typedef struct _psx_dma_channel psx_dma_channel; +struct _psx_dma_channel +{ + UINT32 n_base; + UINT32 n_blockcontrol; + UINT32 n_channelcontrol; + emu_timer *timer; + psx_dma_read_handler fn_read; + psx_dma_write_handler fn_write; + UINT32 n_ticks; + UINT32 b_running; +}; + +class psxdma_device : public device_t +{ +public: + psxdma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void install_read_handler( int n_channel, psx_dma_read_handler p_fn_dma_read ); + void install_write_handler( int n_channel, psx_dma_read_handler p_fn_dma_write ); + + WRITE32_MEMBER( write ); + READ32_MEMBER( read ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + +private: + void dma_start_timer( int n_channel, UINT32 n_ticks ); + void dma_stop_timer( int n_channel ); + void dma_timer_adjust( int n_channel ); + void dma_interrupt_update(); + void dma_finished( int n_channel ); + void dma_finished_callback(void *ptr, int param); + void write( offs_t offset, UINT32 data, UINT32 mem_mask ); + UINT32 read( offs_t offset, UINT32 mem_mask ); + + psx_dma_channel channel[7]; + UINT32 n_dpcp; + UINT32 n_dicr; +}; + +#endif diff --git a/src/emu/cpu/psx/gte.c b/src/emu/cpu/psx/gte.c index 9701c3c6b06..4b39732a08a 100644 --- a/src/emu/cpu/psx/gte.c +++ b/src/emu/cpu/psx/gte.c @@ -1,5 +1,5 @@ /* - * Geometry Transformation Engine + * PlayStation Geometry Transformation Engine emulator * * Copyright 2003-2011 smf * diff --git a/src/emu/cpu/psx/gte.h b/src/emu/cpu/psx/gte.h index f558e59e3f5..bf38d8dce9a 100644 --- a/src/emu/cpu/psx/gte.h +++ b/src/emu/cpu/psx/gte.h @@ -1,5 +1,5 @@ /* - * Geometry Transformation Engine + * PlayStation Geometry Transformation Engine emulator * * Copyright 2003-2011 smf * @@ -9,10 +9,10 @@ #pragma once -#include "emu.h" +#ifndef __PSXGTE_H__ +#define __PSXGTE_H__ -#ifndef __GTE_H__ -#define __GTE_H__ +#include "emu.h" #define GTE_OP( op ) ( ( op >> 20 ) & 31 ) #define GTE_SF( op ) ( ( op >> 19 ) & 1 ) diff --git a/src/emu/cpu/psx/psx.c b/src/emu/cpu/psx/psx.c index ce0c3727853..f8373605a57 100644 --- a/src/emu/cpu/psx/psx.c +++ b/src/emu/cpu/psx/psx.c @@ -1,7 +1,7 @@ /* - * PlayStation CPU emulator by smf + * PlayStation CPU emulator * - * Licensed to the MAME Team for distribution under the MAME license. + * Copyright 2003-2011 smf * * Known chip id's * CXD8530AQ @@ -64,6 +64,7 @@ #include "emu.h" #include "debugger.h" #include "psx.h" +#include "dma.h" #include "includes/psx.h" #include "sound/spu.h" @@ -186,33 +187,23 @@ static const UINT32 mtc0_writemask[]= 0x00000000 /* PRID */ }; -static READ32_DEVICE_HANDLER( psx_berr_r ) +READ32_MEMBER( psxcpu_device::berr_r ) { - downcast(device)->set_berr(); + m_berr = 1; return 0; } -static WRITE32_DEVICE_HANDLER( psx_berr_w ) +WRITE32_MEMBER( psxcpu_device::berr_w ) { - downcast(device)->set_berr(); + m_berr = 1; } -static READ32_DEVICE_HANDLER( psx_biu_r ) -{ - return downcast(device)->get_biu(); -} - -static WRITE32_DEVICE_HANDLER( psx_biu_w ) -{ - downcast(device)->set_biu( data, mem_mask ); -} - -UINT32 psxcpu_device::get_biu() +READ32_MEMBER( psxcpu_device::biu_r ) { return m_biu; } -void psxcpu_device::set_biu( UINT32 data, UINT32 mem_mask ) +WRITE32_MEMBER( psxcpu_device::biu_w ) { UINT32 old = m_biu; @@ -1244,20 +1235,15 @@ void psxcpu_device::update_address_masks() } } -void psxcpu_device::set_berr() -{ - m_berr = 1; -} - void psxcpu_device::update_scratchpad() { if( ( m_biu & BIU_RAM ) == 0 ) { - m_program->install_legacy_readwrite_handler( *this, 0x1f800000, 0x1f8003ff, FUNC(psx_berr_r), FUNC(psx_berr_w) ); + m_program->install_readwrite_handler( 0x1f800000, 0x1f8003ff, read32_delegate( FUNC(psxcpu_device::berr_r), this ), write32_delegate( FUNC(psxcpu_device::berr_w), this ) ); } else if( ( m_biu & BIU_DS ) == 0 ) { - m_program->install_legacy_read_handler( *this, 0x1f800000, 0x1f8003ff, FUNC(psx_berr_r) ); + m_program->install_read_handler( 0x1f800000, 0x1f8003ff, read32_delegate( FUNC(psxcpu_device::berr_r), this ) ); m_program->nop_write( 0x1f800000, 0x1f8003ff); } else @@ -1534,50 +1520,50 @@ int psxcpu_device::store_data_address_breakpoint( UINT32 address ) // On-board RAM and peripherals static ADDRESS_MAP_START( psxcpu_internal_map, AS_PROGRAM, 32 ) - AM_RANGE(0x00800000, 0x1effffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) + AM_RANGE(0x00800000, 0x1effffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) AM_RANGE(0x1f800000, 0x1f8003ff) AM_NOP /* scratchpad */ - AM_RANGE(0x1f800400, 0x1f800fff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) + AM_RANGE(0x1f800400, 0x1f800fff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) AM_RANGE(0x1f801004, 0x1f80101f) AM_RAM AM_RANGE(0x1f801020, 0x1f801023) AM_READWRITE(psx_com_delay_r, psx_com_delay_w) AM_RANGE(0x1f801024, 0x1f80102f) AM_RAM AM_RANGE(0x1f801040, 0x1f80105f) AM_READWRITE(psx_sio_r, psx_sio_w) AM_RANGE(0x1f801060, 0x1f80106f) AM_RAM AM_RANGE(0x1f801070, 0x1f801077) AM_READWRITE(psx_irq_r, psx_irq_w) - AM_RANGE(0x1f801080, 0x1f8010ff) AM_READWRITE(psx_dma_r, psx_dma_w) + AM_RANGE(0x1f801080, 0x1f8010ff) AM_DEVREADWRITE_MODERN("dma", psxdma_device, read, write) AM_RANGE(0x1f801100, 0x1f80112f) AM_READWRITE(psx_counter_r, psx_counter_w) AM_RANGE(0x1f801810, 0x1f801817) AM_READWRITE(psx_gpu_r, psx_gpu_w) AM_RANGE(0x1f801820, 0x1f801827) AM_READWRITE(psx_mdec_r, psx_mdec_w) AM_RANGE(0x1f801c00, 0x1f801dff) AM_READWRITE16(spu_r, spu_w, 0xffffffff) AM_RANGE(0x1f802020, 0x1f802033) AM_RAM /* ?? */ AM_RANGE(0x1f802040, 0x1f802043) AM_WRITENOP - AM_RANGE(0x20000000, 0x7fffffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0x80800000, 0x9effffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0xa0800000, 0xbeffffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0xc0000000, 0xfffdffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0xfffe0130, 0xfffe0133) AM_DEVREADWRITE(DEVICE_SELF,psx_biu_r, psx_biu_w) + AM_RANGE(0x20000000, 0x7fffffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0x80800000, 0x9effffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0xa0800000, 0xbeffffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0xc0000000, 0xfffdffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0xfffe0130, 0xfffe0133) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, biu_r, biu_w) ADDRESS_MAP_END static ADDRESS_MAP_START( cxd8661r_internal_map, AS_PROGRAM, 32 ) - AM_RANGE(0x01000000, 0x1effffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) + AM_RANGE(0x01000000, 0x1effffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) AM_RANGE(0x1f800000, 0x1f8003ff) AM_NOP /* scratchpad */ - AM_RANGE(0x1f800400, 0x1f800fff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) + AM_RANGE(0x1f800400, 0x1f800fff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) AM_RANGE(0x1f801004, 0x1f80101f) AM_RAM AM_RANGE(0x1f801020, 0x1f801023) AM_READWRITE(psx_com_delay_r, psx_com_delay_w) AM_RANGE(0x1f801024, 0x1f80102f) AM_RAM AM_RANGE(0x1f801040, 0x1f80105f) AM_READWRITE(psx_sio_r, psx_sio_w) AM_RANGE(0x1f801060, 0x1f80106f) AM_RAM AM_RANGE(0x1f801070, 0x1f801077) AM_READWRITE(psx_irq_r, psx_irq_w) - AM_RANGE(0x1f801080, 0x1f8010ff) AM_READWRITE(psx_dma_r, psx_dma_w) + AM_RANGE(0x1f801080, 0x1f8010ff) AM_DEVREADWRITE_MODERN("dma", psxdma_device, read, write) AM_RANGE(0x1f801100, 0x1f80112f) AM_READWRITE(psx_counter_r, psx_counter_w) AM_RANGE(0x1f801810, 0x1f801817) AM_READWRITE(psx_gpu_r, psx_gpu_w) AM_RANGE(0x1f801820, 0x1f801827) AM_READWRITE(psx_mdec_r, psx_mdec_w) AM_RANGE(0x1f801c00, 0x1f801dff) AM_READWRITE16(spu_r, spu_w, 0xffffffff) AM_RANGE(0x1f802040, 0x1f802043) AM_WRITENOP - AM_RANGE(0x20000000, 0x7fffffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0x81000000, 0x9effffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0xa1000000, 0xbeffffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0xc0000000, 0xfffdffff) AM_DEVREADWRITE(DEVICE_SELF,psx_berr_r, psx_berr_w) - AM_RANGE(0xfffe0130, 0xfffe0133) AM_DEVREADWRITE(DEVICE_SELF,psx_biu_r, psx_biu_w) + AM_RANGE(0x20000000, 0x7fffffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0x81000000, 0x9effffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0xa1000000, 0xbeffffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0xc0000000, 0xfffdffff) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, berr_r, berr_w) + AM_RANGE(0xfffe0130, 0xfffe0133) AM_DEVREADWRITE_MODERN(DEVICE_SELF, psxcpu_device, biu_r, biu_w) ADDRESS_MAP_END @@ -3157,3 +3143,27 @@ UINT32 psxcpu_device::getcp3cr( int reg ) void psxcpu_device::setcp3cr( int reg, UINT32 value ) { } + +void psxcpu_device::install_dma_read_handler( device_t &device, int channel, psx_dma_read_handler handler ) +{ + (downcast(device.subdevice("dma")))->install_read_handler( channel, handler ); +} + +void psxcpu_device::install_dma_write_handler( device_t &device, int channel, psx_dma_write_handler handler ) +{ + (downcast(device.subdevice("dma")))->install_write_handler( channel, handler ); +} + +static MACHINE_CONFIG_FRAGMENT( psx ) + MCFG_DEVICE_ADD("dma", PSX_DMA, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor psxcpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( psx ); +} diff --git a/src/emu/cpu/psx/psx.h b/src/emu/cpu/psx/psx.h index 17cd6b37be4..d60a96ae1b7 100644 --- a/src/emu/cpu/psx/psx.h +++ b/src/emu/cpu/psx/psx.h @@ -1,17 +1,18 @@ -/*************************************************************************** - - psx.h - - Sony PlayStation CPU emulator. - -***************************************************************************/ +/* + * PlayStation CPU emulator + * + * Copyright 2003-2011 smf + * + */ #pragma once #ifndef __PSXCPU_H__ #define __PSXCPU_H__ +#include "includes/psx.h" #include "gte.h" +#include "dma.h" //************************************************************************** // CONSTANTS @@ -102,8 +103,11 @@ enum // INTERFACE CONFIGURATION MACROS //************************************************************************** -//#define MCFG_PSXCPU_CONFIG(_config) -// psxcpu_device::static_set_config(*device, _config); +#define MCFG_PSX_DMA_CHANNEL_READ( channel, handler ) \ + psxcpu_device::install_dma_read_handler( *device, channel, handler ); \ + +#define MCFG_PSX_DMA_CHANNEL_WRITE( channel, handler ) \ + psxcpu_device::install_dma_write_handler( *device, channel, handler ); \ @@ -120,9 +124,13 @@ public: psxcpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); // public interfaces - void set_berr(); - void set_biu( UINT32 data, UINT32 mem_mask ); - UINT32 get_biu(); + WRITE32_MEMBER( biu_w ); + READ32_MEMBER( biu_r ); + WRITE32_MEMBER( berr_w ); + READ32_MEMBER( berr_r ); + + static void install_dma_read_handler( device_t &device, int channel, psx_dma_read_handler handler ); + static void install_dma_write_handler( device_t &device, int channel, psx_dma_write_handler handler ); protected: psxcpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map); @@ -131,6 +139,7 @@ protected: virtual void device_start(); virtual void device_reset(); virtual void device_post_load(); + machine_config_constructor device_mconfig_additions() const; // device_execute_interface overrides virtual UINT32 execute_min_cycles() const { return 1; } diff --git a/src/emu/devintrf.c b/src/emu/devintrf.c index 252a0242fa2..46dbb1cc274 100644 --- a/src/emu/devintrf.c +++ b/src/emu/devintrf.c @@ -435,7 +435,7 @@ device_t *device_t::subdevice(const char *_tag) const // build a fully-qualified name astring tempstring; - return machine().device(subtag(tempstring, _tag)); + return mconfig().devicelist().find((const char *)subtag(tempstring, _tag)); } diff --git a/src/emu/mconfig.c b/src/emu/mconfig.c index 5b7e70ba07c..5e90a05b618 100644 --- a/src/emu/mconfig.c +++ b/src/emu/mconfig.c @@ -88,15 +88,6 @@ machine_config::machine_config(const game_driver &gamedrv, emu_options &options) throw emu_fatalerror("Machine configuration missing driver_device"); driver_device::static_set_game(*root, gamedrv); - // process any device-specific machine configurations - for (device_t *device = m_devicelist.first(); device != NULL; device = device->next()) - if (!device->configured()) - { - machine_config_constructor additions = device->machine_config_additions(); - if (additions != NULL) - (*additions)(*this, device); - } - // then notify all devices that their configuration is complete for (device_t *device = m_devicelist.first(); device != NULL; device = device->next()) if (!device->configured()) @@ -124,6 +115,43 @@ screen_device *machine_config::first_screen() const } +//------------------------------------------------- +// device_add_subdevices - helper to add +// devices owned by the device +//------------------------------------------------- + +void machine_config::device_add_subdevices(device_t *device) +{ + machine_config_constructor additions = device->machine_config_additions(); + if (additions != NULL) + (*additions)(*this, device); +} + + +//------------------------------------------------- +// device_remove_subdevices - helper to remove +// devices owned by the device +//------------------------------------------------- + +void machine_config::device_remove_subdevices(const device_t *device) +{ + if (device != NULL) + { + device_t *sub_device = m_devicelist.first(); + while (sub_device != NULL) + { + device_t *next_device = sub_device->next(); + if (sub_device->owner() == device) + { + device_remove_subdevices(sub_device); + m_devicelist.remove(sub_device->tag()); + } + sub_device = next_device; + } + } +} + + //------------------------------------------------- // device_add - configuration helper to add a // new device @@ -133,7 +161,9 @@ device_t *machine_config::device_add(device_t *owner, const char *tag, device_ty { astring tempstring; const char *fulltag = owner->subtag(tempstring, tag); - return &m_devicelist.append(fulltag, *(*type)(*this, fulltag, owner, clock)); + device_t *device = &m_devicelist.append(fulltag, *(*type)(*this, fulltag, owner, clock)); + device_add_subdevices(device); + return device; } @@ -146,7 +176,10 @@ device_t *machine_config::device_replace(device_t *owner, const char *tag, devic { astring tempstring; const char *fulltag = owner->subtag(tempstring, tag); - return &m_devicelist.replace_and_remove(fulltag, *(*type)(*this, fulltag, owner, clock)); + device_remove_subdevices(m_devicelist.find(fulltag)); + device_t *device = &m_devicelist.replace_and_remove(fulltag, *(*type)(*this, fulltag, owner, clock)); + device_add_subdevices(device); + return device; } @@ -159,6 +192,7 @@ device_t *machine_config::device_remove(device_t *owner, const char *tag) { astring tempstring; const char *fulltag = owner->subtag(tempstring, tag); + device_remove_subdevices(m_devicelist.find(fulltag)); m_devicelist.remove(fulltag); return NULL; } diff --git a/src/emu/mconfig.h b/src/emu/mconfig.h index 672c70ea39c..e9f6a5192e0 100644 --- a/src/emu/mconfig.h +++ b/src/emu/mconfig.h @@ -157,6 +157,9 @@ public: device_t *device_find(device_t *owner, const char *tag); private: + void device_add_subdevices(device_t *device); + void device_remove_subdevices(const device_t *device); + const game_driver & m_gamedrv; emu_options & m_options; device_list m_devicelist; // list of device configs diff --git a/src/mame/drivers/konamigq.c b/src/mame/drivers/konamigq.c index 0eab0f8b707..3a48873275d 100644 --- a/src/mame/drivers/konamigq.c +++ b/src/mame/drivers/konamigq.c @@ -350,8 +350,6 @@ static MACHINE_START( konamigq ) /* init the scsi controller and hook up it's DMA */ am53cf96_init(machine, &scsi_intf); machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(konamigq_exit), &machine)); - psx_dma_install_read_handler(machine, 5, scsi_dma_read); - psx_dma_install_write_handler(machine, 5, scsi_dma_write); state->save_pointer(NAME(state->m_p_n_pcmram), 0x380000); state->save_item(NAME(state->m_sndto000)); @@ -367,7 +365,9 @@ static MACHINE_RESET( konamigq ) static MACHINE_CONFIG_START( konamigq, konamigq_state ) /* basic machine hardware */ MCFG_CPU_ADD( "maincpu", CXD8530BQ, XTAL_67_7376MHz ) - MCFG_CPU_PROGRAM_MAP( konamigq_map) + MCFG_PSX_DMA_CHANNEL_READ( 5, scsi_dma_read ) + MCFG_PSX_DMA_CHANNEL_WRITE( 5, scsi_dma_write ) + MCFG_CPU_PROGRAM_MAP( konamigq_map ) MCFG_CPU_VBLANK_INT("screen", psx_vblank) MCFG_CPU_ADD( "soundcpu", M68000, 8000000 ) diff --git a/src/mame/drivers/konamigv.c b/src/mame/drivers/konamigv.c index 923b1a44cee..be4d66f2309 100644 --- a/src/mame/drivers/konamigv.c +++ b/src/mame/drivers/konamigv.c @@ -296,8 +296,6 @@ static DRIVER_INIT( konamigv ) /* init the scsi controller and hook up it's DMA */ am53cf96_init(machine, &scsi_intf); machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(konamigv_exit), &machine)); - psx_dma_install_read_handler(machine, 5, scsi_dma_read); - psx_dma_install_write_handler(machine, 5, scsi_dma_write); } static MACHINE_START( konamigv ) @@ -331,7 +329,9 @@ static void spu_irq(device_t *device, UINT32 data) static MACHINE_CONFIG_START( konamigv, konamigv_state ) /* basic machine hardware */ MCFG_CPU_ADD( "maincpu", CXD8530BQ, XTAL_67_7376MHz ) - MCFG_CPU_PROGRAM_MAP( konamigv_map) + MCFG_PSX_DMA_CHANNEL_READ( 5, scsi_dma_read ) + MCFG_PSX_DMA_CHANNEL_WRITE( 5, scsi_dma_write ) + MCFG_CPU_PROGRAM_MAP( konamigv_map ) MCFG_CPU_VBLANK_INT("screen", psx_vblank) MCFG_MACHINE_START( konamigv ) diff --git a/src/mame/drivers/ksys573.c b/src/mame/drivers/ksys573.c index 12913798ada..e3a211628ef 100644 --- a/src/mame/drivers/ksys573.c +++ b/src/mame/drivers/ksys573.c @@ -1265,8 +1265,6 @@ static DRIVER_INIT( konami573 ) psx_driver_init(machine); atapi_init(machine); - psx_dma_install_read_handler(machine, 5, cdrom_dma_read); - psx_dma_install_write_handler(machine, 5, cdrom_dma_write); state->save_item( NAME(state->m_n_security_control) ); @@ -2963,7 +2961,9 @@ static const adc083x_interface konami573_adc_interface = { static MACHINE_CONFIG_START( konami573, ksys573_state ) /* basic machine hardware */ MCFG_CPU_ADD( "maincpu", CXD8530CQ, XTAL_67_7376MHz ) - MCFG_CPU_PROGRAM_MAP( konami573_map) + MCFG_PSX_DMA_CHANNEL_READ( 5, cdrom_dma_read ) + MCFG_PSX_DMA_CHANNEL_WRITE( 5, cdrom_dma_write ) + MCFG_CPU_PROGRAM_MAP( konami573_map ) MCFG_CPU_VBLANK_INT("screen", sys573_vblank) MCFG_MACHINE_RESET( konami573 ) diff --git a/src/mame/drivers/namcos12.c b/src/mame/drivers/namcos12.c index eb09b6c26be..b2cfc240b36 100644 --- a/src/mame/drivers/namcos12.c +++ b/src/mame/drivers/namcos12.c @@ -1600,8 +1600,6 @@ static DRIVER_INIT( namcos12 ) psx_driver_init(machine); - psx_dma_install_read_handler( machine, 5, namcos12_rom_read ); - memory_configure_bank(machine, "bank1", 0, machine.region( "user2" )->bytes() / 0x200000, machine.region( "user2" )->base(), 0x200000 ); state->m_s12_porta = 0; @@ -1642,6 +1640,8 @@ static DRIVER_INIT( ghlpanic ) static MACHINE_CONFIG_START( coh700, namcos12_state ) /* basic machine hardware */ MCFG_CPU_ADD( "maincpu", CXD8661R, XTAL_100MHz ) + MCFG_PSX_DMA_CHANNEL_READ( 5, namcos12_rom_read ) + MCFG_CPU_PROGRAM_MAP( namcos12_map) MCFG_CPU_VBLANK_INT("screen", psx_vblank) diff --git a/src/mame/drivers/twinkle.c b/src/mame/drivers/twinkle.c index 1519bb0db35..22988895e58 100644 --- a/src/mame/drivers/twinkle.c +++ b/src/mame/drivers/twinkle.c @@ -848,8 +848,6 @@ static DRIVER_INIT( twinkle ) { psx_driver_init(machine); am53cf96_init(machine, &scsi_intf); - psx_dma_install_read_handler(machine, 5, scsi_dma_read); - psx_dma_install_write_handler(machine, 5, scsi_dma_write); device_t *i2cmem = machine.device("security"); i2cmem_e0_write( i2cmem, 0 ); @@ -882,6 +880,8 @@ static const i2cmem_interface i2cmem_interface = static MACHINE_CONFIG_START( twinkle, twinkle_state ) /* basic machine hardware */ MCFG_CPU_ADD( "maincpu", CXD8530CQ, XTAL_67_7376MHz ) + MCFG_PSX_DMA_CHANNEL_READ( 5, scsi_dma_read ) + MCFG_PSX_DMA_CHANNEL_WRITE( 5, scsi_dma_write ) MCFG_CPU_PROGRAM_MAP( main_map ) MCFG_CPU_VBLANK_INT( "mainscreen", psx_vblank ) diff --git a/src/mame/includes/psx.h b/src/mame/includes/psx.h index 0d4afa8b3b1..7dc3ed021b8 100644 --- a/src/mame/includes/psx.h +++ b/src/mame/includes/psx.h @@ -6,6 +6,8 @@ #if !defined( PSX_H ) +#include "cpu/psx/dma.h" + #define PSX_RC_STOP ( 0x01 ) #define PSX_RC_RESET ( 0x04 ) /* guess */ #define PSX_RC_COUNTTARGET ( 0x08 ) @@ -35,11 +37,108 @@ #define PSX_SIO_IN_DSR ( 2 ) /* ACK */ #define PSX_SIO_IN_CTS ( 4 ) -typedef void ( *psx_dma_read_handler )( running_machine &, UINT32, INT32 ); -typedef void ( *psx_dma_write_handler )( running_machine &, UINT32, INT32 ); typedef void ( *psx_sio_handler )( running_machine &, int ); +#define DCTSIZE ( 8 ) +#define DCTSIZE2 ( DCTSIZE * DCTSIZE ) + +#define SIO_BUF_SIZE ( 8 ) + +#define SIO_STATUS_TX_RDY ( 1 << 0 ) +#define SIO_STATUS_RX_RDY ( 1 << 1 ) +#define SIO_STATUS_TX_EMPTY ( 1 << 2 ) +#define SIO_STATUS_OVERRUN ( 1 << 4 ) +#define SIO_STATUS_DSR ( 1 << 7 ) +#define SIO_STATUS_IRQ ( 1 << 9 ) + +#define SIO_CONTROL_TX_ENA ( 1 << 0 ) +#define SIO_CONTROL_IACK ( 1 << 4 ) +#define SIO_CONTROL_RESET ( 1 << 6 ) +#define SIO_CONTROL_TX_IENA ( 1 << 10 ) +#define SIO_CONTROL_RX_IENA ( 1 << 11 ) +#define SIO_CONTROL_DSR_IENA ( 1 << 12 ) +#define SIO_CONTROL_DTR ( 1 << 13 ) + +#define MDEC_COS_PRECALC_BITS ( 21 ) + +typedef struct _psx_root psx_root; +struct _psx_root +{ + emu_timer *timer; + UINT16 n_count; + UINT16 n_mode; + UINT16 n_target; + UINT64 n_start; +}; + +typedef struct _psx_sio psx_sio; +struct _psx_sio +{ + UINT32 n_status; + UINT32 n_mode; + UINT32 n_control; + UINT32 n_baud; + UINT32 n_tx; + UINT32 n_rx; + UINT32 n_tx_prev; + UINT32 n_rx_prev; + UINT32 n_tx_data; + UINT32 n_rx_data; + UINT32 n_tx_shift; + UINT32 n_rx_shift; + UINT32 n_tx_bits; + UINT32 n_rx_bits; + + emu_timer *timer; + psx_sio_handler fn_handler; +}; + +typedef struct _psx_mdec psx_mdec; +struct _psx_mdec +{ + UINT32 n_decoded; + UINT32 n_offset; + UINT16 p_n_output[ 24 * 16 ]; + + INT32 p_n_quantize_y[ DCTSIZE2 ]; + INT32 p_n_quantize_uv[ DCTSIZE2 ]; + INT32 p_n_cos[ DCTSIZE2 ]; + INT32 p_n_cos_precalc[ DCTSIZE2 * DCTSIZE2 ]; + + UINT32 n_0_command; + UINT32 n_0_address; + UINT32 n_0_size; + UINT32 n_1_command; + UINT32 n_1_status; + + UINT16 p_n_clamp8[ 256 * 3 ]; + UINT16 p_n_r5[ 256 * 3 ]; + UINT16 p_n_g5[ 256 * 3 ]; + UINT16 p_n_b5[ 256 * 3 ]; + + INT32 p_n_unpacked[ DCTSIZE2 * 6 * 2 ]; +}; + typedef struct _psx_machine psx_machine; +struct _psx_machine +{ + running_machine &machine() const { assert(m_machine != NULL); return *m_machine; } + + running_machine *m_machine; + UINT32 *p_n_psxram; + size_t n_psxramsize; + + UINT32 n_com_delay; + UINT32 n_irqdata; + UINT32 n_irqmask; + + psx_root root[3]; + + psx_sio sio[2]; + + psx_mdec mdec; +}; + typedef struct _psx_gpu psx_gpu; class psx_state : public driver_device diff --git a/src/mame/machine/psx.c b/src/mame/machine/psx.c index aea6dcd703b..dcc503de709 100644 --- a/src/mame/machine/psx.c +++ b/src/mame/machine/psx.c @@ -12,124 +12,6 @@ #define VERBOSE_LEVEL ( 0 ) -#define DCTSIZE ( 8 ) -#define DCTSIZE2 ( DCTSIZE * DCTSIZE ) - -#define SIO_BUF_SIZE ( 8 ) - -#define SIO_STATUS_TX_RDY ( 1 << 0 ) -#define SIO_STATUS_RX_RDY ( 1 << 1 ) -#define SIO_STATUS_TX_EMPTY ( 1 << 2 ) -#define SIO_STATUS_OVERRUN ( 1 << 4 ) -#define SIO_STATUS_DSR ( 1 << 7 ) -#define SIO_STATUS_IRQ ( 1 << 9 ) - -#define SIO_CONTROL_TX_ENA ( 1 << 0 ) -#define SIO_CONTROL_IACK ( 1 << 4 ) -#define SIO_CONTROL_RESET ( 1 << 6 ) -#define SIO_CONTROL_TX_IENA ( 1 << 10 ) -#define SIO_CONTROL_RX_IENA ( 1 << 11 ) -#define SIO_CONTROL_DSR_IENA ( 1 << 12 ) -#define SIO_CONTROL_DTR ( 1 << 13 ) - -#define MDEC_COS_PRECALC_BITS ( 21 ) - - -typedef struct _psx_dma_channel psx_dma_channel; -struct _psx_dma_channel -{ - UINT32 n_base; - UINT32 n_blockcontrol; - UINT32 n_channelcontrol; - emu_timer *timer; - psx_dma_read_handler fn_read; - psx_dma_write_handler fn_write; - UINT32 n_ticks; - UINT32 b_running; -}; - -typedef struct _psx_root psx_root; -struct _psx_root -{ - emu_timer *timer; - UINT16 n_count; - UINT16 n_mode; - UINT16 n_target; - UINT64 n_start; -}; - -typedef struct _psx_sio psx_sio; -struct _psx_sio -{ - UINT32 n_status; - UINT32 n_mode; - UINT32 n_control; - UINT32 n_baud; - UINT32 n_tx; - UINT32 n_rx; - UINT32 n_tx_prev; - UINT32 n_rx_prev; - UINT32 n_tx_data; - UINT32 n_rx_data; - UINT32 n_tx_shift; - UINT32 n_rx_shift; - UINT32 n_tx_bits; - UINT32 n_rx_bits; - - emu_timer *timer; - psx_sio_handler fn_handler; -}; - -typedef struct _psx_mdec psx_mdec; -struct _psx_mdec -{ - UINT32 n_decoded; - UINT32 n_offset; - UINT16 p_n_output[ 24 * 16 ]; - - INT32 p_n_quantize_y[ DCTSIZE2 ]; - INT32 p_n_quantize_uv[ DCTSIZE2 ]; - INT32 p_n_cos[ DCTSIZE2 ]; - INT32 p_n_cos_precalc[ DCTSIZE2 * DCTSIZE2 ]; - - UINT32 n_0_command; - UINT32 n_0_address; - UINT32 n_0_size; - UINT32 n_1_command; - UINT32 n_1_status; - - UINT16 p_n_clamp8[ 256 * 3 ]; - UINT16 p_n_r5[ 256 * 3 ]; - UINT16 p_n_g5[ 256 * 3 ]; - UINT16 p_n_b5[ 256 * 3 ]; - - INT32 p_n_unpacked[ DCTSIZE2 * 6 * 2 ]; -}; - -struct _psx_machine -{ - running_machine &machine() const { assert(m_machine != NULL); return *m_machine; } - - running_machine *m_machine; - UINT32 *p_n_psxram; - size_t n_psxramsize; - - UINT32 n_com_delay; - UINT32 n_irqdata; - UINT32 n_irqmask; - - UINT32 n_dpcp; - UINT32 n_dicr; - psx_dma_channel channel[7]; - - psx_root root[3]; - - psx_sio sio[2]; - - psx_mdec mdec; -}; - - INLINE void ATTR_PRINTF(3,4) verboselog( psx_machine *p_psx, int n_level, const char *s_fmt, ... ) { if( VERBOSE_LEVEL >= n_level ) @@ -243,355 +125,15 @@ void psx_irq_set( running_machine &machine, UINT32 data ) /* DMA */ -static void dma_start_timer( psx_machine *p_psx, int n_channel, UINT32 n_ticks ) -{ - psx_dma_channel *dma = &p_psx->channel[ n_channel ]; - - dma->timer->adjust( attotime::from_hz(33868800) * n_ticks, n_channel); - dma->n_ticks = n_ticks; - dma->b_running = 1; -} - -static void dma_stop_timer( psx_machine *p_psx, int n_channel ) -{ - psx_dma_channel *dma = &p_psx->channel[ n_channel ]; - - dma->timer->adjust( attotime::never); - dma->b_running = 0; -} - -static void dma_timer_adjust( psx_machine *p_psx, int n_channel ) -{ - psx_dma_channel *dma = &p_psx->channel[ n_channel ]; - - if( dma->b_running ) - { - dma_start_timer( p_psx, n_channel, dma->n_ticks ); - } - else - { - dma_stop_timer( p_psx, n_channel ); - } -} - -static void dma_interrupt_update( psx_machine *p_psx ) -{ - int n_int; - int n_mask; - - n_int = ( p_psx->n_dicr >> 24 ) & 0x7f; - n_mask = ( p_psx->n_dicr >> 16 ) & 0xff; - - if( ( n_mask & 0x80 ) != 0 && ( n_int & n_mask ) != 0 ) - { - verboselog( p_psx, 2, "dma_interrupt_update( %02x, %02x ) interrupt triggered\n", n_int, n_mask ); - p_psx->n_dicr |= 0x80000000; - psx_irq_set( p_psx->machine(), PSX_IRQ_DMA ); - } - else if( n_int != 0 ) - { - verboselog( p_psx, 2, "dma_interrupt_update( %02x, %02x ) interrupt not enabled\n", n_int, n_mask ); - } - p_psx->n_dicr &= 0x00ffffff | ( p_psx->n_dicr << 8 ); -} - -static void dma_finished(psx_machine *p_psx, int n_channel) -{ - UINT32 *p_n_psxram = p_psx->p_n_psxram; - psx_dma_channel *dma = &p_psx->channel[ n_channel ]; - - if( dma->n_channelcontrol == 0x01000401 && n_channel == 2 ) - { - UINT32 n_size; - UINT32 n_total; - UINT32 n_address = ( dma->n_base & 0xffffff ); - UINT32 n_adrmask = p_psx->n_psxramsize - 1; - UINT32 n_nextaddress; - - if( n_address != 0xffffff ) - { - n_total = 0; - for( ;; ) - { - if( n_address == 0xffffff ) - { - dma->n_base = n_address; - dma_start_timer( p_psx, n_channel, 19000 ); - return; - } - if( n_total > 65535 ) - { - dma->n_base = n_address; - //FIXME: - // 16000 below is based on try and error. - // Mametesters.org: sfex20103red - //dma_start_timer( p_psx, n_channel, 16 ); - dma_start_timer( p_psx, n_channel, 16000 ); - return; - } - n_address &= n_adrmask; - n_nextaddress = p_n_psxram[ n_address / 4 ]; - n_size = n_nextaddress >> 24; - (*dma->fn_write)( p_psx->machine(), n_address + 4, n_size ); - //FIXME: - // The following conditions will cause an endless loop. - // If stopping the transfer is correct I cannot judge - // The patch is meant as a hint for somebody who knows - // the hardware. - // Mametesters.org: psyforce0105u5red, raystorm0111u1red - if ((n_nextaddress & 0xffffff) != 0xffffff) - if (n_address == p_n_psxram[ (n_nextaddress & 0xffffff) / 4]) - break; - if (n_address == (n_nextaddress & 0xffffff) ) - break; - n_address = ( n_nextaddress & 0xffffff ); - - n_total += ( n_size + 1 ); - } - } - } - - dma->n_channelcontrol &= ~( ( 1L << 0x18 ) | ( 1L << 0x1c ) ); - - p_psx->n_dicr |= 1 << ( 24 + n_channel ); - dma_interrupt_update(p_psx); - dma_stop_timer( p_psx, n_channel ); -} - -static TIMER_CALLBACK( dma_finished_callback ) -{ - psx_machine *p_psx = machine.driver_data()->m_p_psx; - - dma_finished(p_psx, param); -} - void psx_dma_install_read_handler( running_machine &machine, int n_channel, psx_dma_read_handler p_fn_dma_read ) -{ - psx_machine *p_psx = machine.driver_data()->m_p_psx; - p_psx->channel[ n_channel ].fn_read = p_fn_dma_read; +{ + psxcpu_device::install_dma_read_handler( *machine.device("maincpu"), n_channel, p_fn_dma_read ); } void psx_dma_install_write_handler( running_machine &machine, int n_channel, psx_dma_read_handler p_fn_dma_write ) { - psx_machine *p_psx = machine.driver_data()->m_p_psx; - - p_psx->channel[ n_channel ].fn_write = p_fn_dma_write; -} - -WRITE32_HANDLER( psx_dma_w ) -{ - psx_machine *p_psx = space->machine().driver_data()->m_p_psx; - UINT32 *p_n_psxram = p_psx->p_n_psxram; - int n_channel = offset / 4; - psx_dma_channel *dma = &p_psx->channel[ n_channel ]; - - if( n_channel < 7 ) - { - switch( offset % 4 ) - { - case 0: - verboselog( p_psx, 2, "dmabase( %d ) = %08x\n", n_channel, data ); - dma->n_base = data; - break; - case 1: - verboselog( p_psx, 2, "dmablockcontrol( %d ) = %08x\n", n_channel, data ); - dma->n_blockcontrol = data; - break; - case 2: - verboselog( p_psx, 2, "dmachannelcontrol( %d ) = %08x\n", n_channel, data ); - dma->n_channelcontrol = data; - if( ( dma->n_channelcontrol & ( 1L << 0x18 ) ) != 0 && ( p_psx->n_dpcp & ( 1 << ( 3 + ( n_channel * 4 ) ) ) ) != 0 ) - { - INT32 n_size; - UINT32 n_address; - UINT32 n_nextaddress; - UINT32 n_adrmask; - - n_adrmask = p_psx->n_psxramsize - 1; - - n_address = ( dma->n_base & n_adrmask ); - n_size = dma->n_blockcontrol; - if( ( dma->n_channelcontrol & 0x200 ) != 0 ) - { - UINT32 n_ba; - n_ba = dma->n_blockcontrol >> 16; - if( n_ba == 0 ) - { - n_ba = 0x10000; - } - n_size = ( n_size & 0xffff ) * n_ba; - } - - if( dma->n_channelcontrol == 0x01000000 && - dma->fn_read != NULL ) - { - verboselog( p_psx, 1, "dma %d read block %08x %08x\n", n_channel, n_address, n_size ); - (*dma->fn_read)( space->machine(), n_address, n_size ); - dma_finished( p_psx, n_channel ); - } - else if (dma->n_channelcontrol == 0x11000000 && // CD DMA - dma->fn_read != NULL ) - { - verboselog( p_psx, 1, "dma %d read block %08x %08x\n", n_channel, n_address, n_size ); - - // pSX's CD DMA size calc formula - int oursize = (dma->n_blockcontrol>>16); - oursize = (oursize > 1) ? oursize : 1; - oursize *= (dma->n_blockcontrol&0xffff); - - (*dma->fn_read)( space->machine(), n_address, oursize ); - dma_finished( p_psx, n_channel ); - } - else if( dma->n_channelcontrol == 0x01000200 && - dma->fn_read != NULL ) - { - verboselog( p_psx, 1, "dma %d read block %08x %08x\n", n_channel, n_address, n_size ); - (*dma->fn_read)( space->machine(), n_address, n_size ); - if( n_channel == 1 ) - { - dma_start_timer( p_psx, n_channel, 26000 ); - } - else - { - dma_finished( p_psx, n_channel ); - } - } - else if( dma->n_channelcontrol == 0x01000201 && - dma->fn_write != NULL ) - { - verboselog( p_psx, 1, "dma %d write block %08x %08x\n", n_channel, n_address, n_size ); - (*dma->fn_write)( space->machine(), n_address, n_size ); - dma_finished( p_psx, n_channel ); - } - else if( dma->n_channelcontrol == 0x11050100 && - dma->fn_write != NULL ) - { - /* todo: check this is a write not a read... */ - verboselog( p_psx, 1, "dma %d write block %08x %08x\n", n_channel, n_address, n_size ); - (*dma->fn_write)( space->machine(), n_address, n_size ); - dma_finished( p_psx, n_channel ); - } - else if( dma->n_channelcontrol == 0x11150100 && - dma->fn_write != NULL ) - { - /* todo: check this is a write not a read... */ - verboselog( p_psx, 1, "dma %d write block %08x %08x\n", n_channel, n_address, n_size ); - (*dma->fn_write)( space->machine(), n_address, n_size ); - dma_finished( p_psx, n_channel ); - } - else if( dma->n_channelcontrol == 0x01000401 && - n_channel == 2 && - dma->fn_write != NULL ) - { - verboselog( p_psx, 1, "dma %d write linked list %08x\n", - n_channel, dma->n_base ); - - dma_finished( p_psx, n_channel ); - } - else if( dma->n_channelcontrol == 0x11000002 && - n_channel == 6 ) - { - verboselog( p_psx, 1, "dma 6 reverse clear %08x %08x\n", - dma->n_base, dma->n_blockcontrol ); - if( n_size > 0 ) - { - n_size--; - while( n_size > 0 ) - { - n_nextaddress = ( n_address - 4 ) & 0xffffff; - p_n_psxram[ n_address / 4 ] = n_nextaddress; - n_address = n_nextaddress; - n_size--; - } - p_n_psxram[ n_address / 4 ] = 0xffffff; - } - dma_start_timer( p_psx, n_channel, 2150 ); - } - else - { - verboselog( p_psx, 1, "dma %d unknown mode %08x\n", n_channel, dma->n_channelcontrol ); - } - } - else if( dma->n_channelcontrol != 0 ) - { - verboselog( p_psx, 1, "psx_dma_w( %04x, %08x, %08x ) channel not enabled\n", offset, dma->n_channelcontrol, mem_mask ); - } - break; - default: - verboselog( p_psx, 1, "psx_dma_w( %04x, %08x, %08x ) Unknown dma channel register\n", offset, data, mem_mask ); - break; - } - } - else - { - switch( offset % 4 ) - { - case 0x0: - verboselog( p_psx, 1, "psx_dma_w( %04x, %08x, %08x ) dpcp\n", offset, data, mem_mask ); - p_psx->n_dpcp = ( p_psx->n_dpcp & ~mem_mask ) | data; - break; - case 0x1: - - p_psx->n_dicr = ( p_psx->n_dicr & ( 0x80000000 | ~mem_mask ) ) | - ( p_psx->n_dicr & ~data & 0x7f000000 & mem_mask ) | - ( data & 0x00ffffff & mem_mask ); - - if( ( p_psx->n_dicr & 0x80000000 ) != 0 && ( p_psx->n_dicr & 0x7f000000 ) == 0 ) - { - verboselog( p_psx, 2, "dma interrupt cleared\n" ); - p_psx->n_dicr &= ~0x80000000; - } - - verboselog( p_psx, 1, "psx_dma_w( %04x, %08x, %08x ) dicr -> %08x\n", offset, data, mem_mask, p_psx->n_dicr ); - break; - default: - verboselog( p_psx, 0, "psx_dma_w( %04x, %08x, %08x ) Unknown dma control register\n", offset, data, mem_mask ); - break; - } - } -} - -READ32_HANDLER( psx_dma_r ) -{ - psx_machine *p_psx = space->machine().driver_data()->m_p_psx; - int n_channel = offset / 4; - psx_dma_channel *dma = &p_psx->channel[ n_channel ]; - - if( n_channel < 7 ) - { - switch( offset % 4 ) - { - case 0: - verboselog( p_psx, 1, "psx_dma_r dmabase[ %d ] ( %08x )\n", n_channel, dma->n_base ); - return dma->n_base; - case 1: - verboselog( p_psx, 1, "psx_dma_r dmablockcontrol[ %d ] ( %08x )\n", n_channel, dma->n_blockcontrol ); - return dma->n_blockcontrol; - case 2: - verboselog( p_psx, 1, "psx_dma_r dmachannelcontrol[ %d ] ( %08x )\n", n_channel, dma->n_channelcontrol ); - return dma->n_channelcontrol; - default: - verboselog( p_psx, 0, "psx_dma_r( %08x, %08x ) Unknown dma channel register\n", offset, mem_mask ); - break; - } - } - else - { - switch( offset % 4 ) - { - case 0x0: - verboselog( p_psx, 1, "psx_dma_r dpcp ( %08x )\n", p_psx->n_dpcp ); - return p_psx->n_dpcp; - case 0x1: - verboselog( p_psx, 1, "psx_dma_r dicr ( %08x )\n", p_psx->n_dicr ); - return p_psx->n_dicr; - default: - verboselog( p_psx, 0, "psx_dma_r( %08x, %08x ) Unknown dma control register\n", offset, mem_mask ); - break; - } - } - return 0; + psxcpu_device::install_dma_write_handler( *machine.device("maincpu"), n_channel, p_fn_dma_write ); } /* Root Counters */ @@ -1595,21 +1137,12 @@ void psx_machine_init( running_machine &machine ) p_psx->n_irqdata = 0; p_psx->n_irqmask = 0; - /* dma */ - p_psx->n_dpcp = 0; - p_psx->n_dicr = 0; - p_psx->mdec.n_0_command = 0; p_psx->mdec.n_0_address = 0; p_psx->mdec.n_0_size = 0; p_psx->mdec.n_1_command = 0; p_psx->mdec.n_1_status = 0; - for( n = 0; n < 7; n++ ) - { - dma_stop_timer( p_psx, n ); - } - for( n = 0; n < 2; n++ ) { p_psx->sio[ n ].n_status = SIO_STATUS_TX_EMPTY | SIO_STATUS_TX_RDY; @@ -1637,11 +1170,6 @@ static void psx_postload(psx_machine *p_psx) psx_irq_update(p_psx); - for( n = 0; n < 7; n++ ) - { - dma_timer_adjust( p_psx, n ); - } - for( n = 0; n < 3; n++ ) { root_timer_adjust( p_psx, n ); @@ -1668,13 +1196,6 @@ void psx_driver_init( running_machine &machine ) p_psx->p_n_psxram = state->m_p_n_psxram; p_psx->n_psxramsize = state->m_n_psxramsize; - for( n = 0; n < 7; n++ ) - { - p_psx->channel[ n ].timer = machine.scheduler().timer_alloc( FUNC(dma_finished_callback), &machine ); - p_psx->channel[ n ].fn_read = NULL; - p_psx->channel[ n ].fn_write = NULL; - } - for( n = 0; n < 3; n++ ) { p_psx->root[ n ].timer = machine.scheduler().timer_alloc( FUNC(root_finished )); @@ -1713,17 +1234,6 @@ void psx_driver_init( running_machine &machine ) state_save_register_global( machine, p_psx->n_irqdata ); state_save_register_global( machine, p_psx->n_irqmask ); - for (n = 0; n < 7; n++ ) - { - state_save_register_item( machine, "psxdma", NULL, n, p_psx->channel[n].n_base ); - state_save_register_item( machine, "psxdma", NULL, n, p_psx->channel[n].n_blockcontrol ); - state_save_register_item( machine, "psxdma", NULL, n, p_psx->channel[n].n_channelcontrol ); - state_save_register_item( machine, "psxdma", NULL, n, p_psx->channel[n].n_ticks ); - state_save_register_item( machine, "psxdma", NULL, n, p_psx->channel[n].b_running ); - } - - state_save_register_global( machine, p_psx->n_dpcp ); - state_save_register_global( machine, p_psx->n_dicr ); for ( n = 0; n < 3; n++ ) { state_save_register_item( machine, "psxroot", NULL, n, p_psx->root[n].n_count );