From 7b87813ea9f3cf04775b4e0baadd8a2bd830e574 Mon Sep 17 00:00:00 2001 From: smf- Date: Fri, 22 Sep 2017 20:32:54 +0100 Subject: Implemented program counter break point to PlayStation CPU & re-added PlayStation EXE, CPE & PSF loading. [smf] --- scripts/target/mame/mess.lua | 4 + src/devices/cpu/psx/psx.cpp | 1536 +++++++++++++++++++++-------------------- src/devices/cpu/psx/psx.h | 26 +- src/devices/cpu/psx/psxdefs.h | 3 - src/mame/drivers/psx.cpp | 411 ++++++++++- 5 files changed, 1211 insertions(+), 769 deletions(-) diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 34736df7456..4c4663dd2f3 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -1150,6 +1150,10 @@ function createMESSProjects(_target, _subtarget, _name) GEN_DIR .. "mess/layout", GEN_DIR .. "mame/layout", } + + includedirs { + ext_includedir("zlib") + } end function createProjects_mame_mess(_target, _subtarget) diff --git a/src/devices/cpu/psx/psx.cpp b/src/devices/cpu/psx/psx.cpp index 6ce8ed7a7b1..36d7c1742f4 100644 --- a/src/devices/cpu/psx/psx.cpp +++ b/src/devices/cpu/psx/psx.cpp @@ -29,7 +29,7 @@ * * Known limitations of the emulation: * - * Only read & write break points are emulated, trace and program counter breakpoints are not. + * Program counter, read data & write data break points are emulated, trace break points are not. * * Load/Store timings are based on load scheduling turned off & no write cache. This affects when * bus error exceptions occur and also when the read & write handlers are called. A scheduled @@ -61,7 +61,7 @@ * * Wait states are not emulated. * - * Bus errors caused by instruction fetches are not supported. + * Bus errors caused by instruction burst fetches are not supported. * */ @@ -105,15 +105,22 @@ #define CP0_EPC ( 14 ) #define CP0_PRID ( 15 ) -#define DCIC_STATUS ( 0x3f ) #define DCIC_DB ( 1L << 0 ) +#define DCIC_PC ( 1L << 1 ) #define DCIC_DA ( 1L << 2 ) #define DCIC_R ( 1L << 3 ) #define DCIC_W ( 1L << 4 ) +#define DCIC_T ( 1L << 5 ) // not emulated +// unknown ( 1L << 12 ) +// unknown ( 1L << 13 ) +// unknown ( 1L << 14 ) +// unknown ( 1L << 15 ) #define DCIC_DE ( 1L << 23 ) +#define DCIC_PCE ( 1L << 24 ) #define DCIC_DAE ( 1L << 25 ) #define DCIC_DR ( 1L << 26 ) #define DCIC_DW ( 1L << 27 ) +#define DCIC_TE ( 1L << 28 ) // not emulated #define DCIC_KD ( 1L << 29 ) #define DCIC_UD ( 1L << 30 ) #define DCIC_TR ( 1L << 31 ) @@ -1445,12 +1452,6 @@ void psxcpu_device::update_cop0( int reg ) execute_unstoppable_instructions( 1 ); exception( EXC_INT ); } - else if( reg == CP0_SR && - m_delayr != PSXCPU_DELAYR_PC && - ( m_pc & m_bad_word_address_mask ) != 0 ) - { - load_bad_address( m_pc ); - } } void psxcpu_device::commit_delayed_load() @@ -1482,19 +1483,13 @@ void psxcpu_device::fetch_next_op() } } -int psxcpu_device::advance_pc() +void psxcpu_device::advance_pc() { if( m_delayr == PSXCPU_DELAYR_PC ) { m_pc = m_delayv; m_delayr = 0; m_delayv = 0; - - if( ( m_pc & m_bad_word_address_mask ) != 0 ) - { - load_bad_address( m_pc ); - return 0; - } } else if( m_delayr == PSXCPU_DELAYR_NOTPC ) { @@ -1507,8 +1502,6 @@ int psxcpu_device::advance_pc() commit_delayed_load(); m_pc += 4; } - - return 1; } void psxcpu_device::load( uint32_t reg, uint32_t value ) @@ -1648,8 +1641,11 @@ void psxcpu_device::store_bus_error_exception() if( execute_unstoppable_instructions( 1 ) ) { - if( !advance_pc() ) + advance_pc(); + + if( ( m_pc & m_bad_word_address_mask ) != 0 ) { + load_bad_address( m_pc ); return; } @@ -1677,13 +1673,13 @@ int psxcpu_device::data_address_breakpoint( int dcic_rw, int dcic_status, uint32 if( address < 0x1f000000 || address > 0x1fffffff ) { if( ( m_cp0r[ CP0_DCIC ] & DCIC_DE ) != 0 && - ( ( ( m_cp0r[ CP0_DCIC ] & DCIC_KD ) != 0 && ( m_cp0r[ CP0_SR ] & SR_KUC ) == 0 ) || - ( ( m_cp0r[ CP0_DCIC ] & DCIC_UD ) != 0 && ( m_cp0r[ CP0_SR ] & SR_KUC ) != 0 ) ) ) + ( m_cp0r[ CP0_DCIC ] & dcic_rw ) == dcic_rw && + ( ( ( m_cp0r[ CP0_DCIC ] & DCIC_KD ) != 0 && ( m_pc & 0x80000000 ) != 0 ) || + ( ( m_cp0r[ CP0_DCIC ] & DCIC_UD ) != 0 && ( m_pc & 0x80000000 ) == 0 ) ) ) { - if( ( m_cp0r[ CP0_DCIC ] & dcic_rw ) == dcic_rw && - ( address & m_cp0r[ CP0_BDAM ] ) == ( m_cp0r[ CP0_BDA ] & m_cp0r[ CP0_BDAM ] ) ) + if( ( address & m_cp0r[ CP0_BDAM ] ) == ( m_cp0r[ CP0_BDA ] & m_cp0r[ CP0_BDAM ] ) ) { - m_cp0r[ CP0_DCIC ] = ( m_cp0r[ CP0_DCIC ] & ~DCIC_STATUS ) | dcic_status; + m_cp0r[ CP0_DCIC ] |= dcic_status; if( ( m_cp0r[ CP0_DCIC ] & DCIC_TR ) != 0 ) { @@ -1696,6 +1692,27 @@ int psxcpu_device::data_address_breakpoint( int dcic_rw, int dcic_status, uint32 return 0; } +int psxcpu_device::program_counter_breakpoint() +{ + if( ( m_cp0r[ CP0_DCIC ] & DCIC_DE ) != 0 && + ( m_cp0r[ CP0_DCIC ] & DCIC_PCE ) != 0 && + ( ( ( m_cp0r[ CP0_DCIC ] & DCIC_KD ) != 0 && ( m_pc & 0x80000000 ) != 0 ) || + ( ( m_cp0r[ CP0_DCIC ] & DCIC_UD ) != 0 && ( m_pc & 0x80000000 ) == 0 ) ) ) + { + if( ( m_pc & m_cp0r[ CP0_BPCM ] ) == ( m_cp0r[ CP0_BPC ] & m_cp0r[ CP0_BPCM ] ) ) + { + m_cp0r[ CP0_DCIC ] |= DCIC_PC | DCIC_DB; + + if( ( m_cp0r[ CP0_DCIC ] & DCIC_TR ) != 0 ) + { + return 1; + } + } + } + + return 0; +} + int psxcpu_device::load_data_address_breakpoint( uint32_t address ) { return data_address_breakpoint( DCIC_DR | DCIC_DAE, DCIC_DB | DCIC_DA | DCIC_R, address ); @@ -2295,402 +2312,337 @@ void psxcpu_device::execute_run() if( LOG_BIOSCALL ) log_bioscall(); debugger_instruction_hook( this, m_pc ); - m_op = m_direct->read_dword( m_pc ); + int breakpoint = program_counter_breakpoint(); - if( m_berr ) + if( ( m_pc & m_bad_word_address_mask ) != 0 ) + { + load_bad_address( m_pc ); + } + else if( breakpoint ) { - fetch_bus_error_exception(); + breakpoint_exception(); } else { - switch( INS_OP( m_op ) ) + m_op = m_direct->read_dword(m_pc); + + if( m_berr ) { - case OP_SPECIAL: - switch( INS_FUNCT( m_op ) ) + fetch_bus_error_exception(); + } + else + { + switch( INS_OP( m_op ) ) { - case FUNCT_SLL: - load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] << INS_SHAMT( m_op ) ); - break; + case OP_SPECIAL: + switch( INS_FUNCT( m_op ) ) + { + case FUNCT_SLL: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] << INS_SHAMT( m_op ) ); + break; - case FUNCT_SRL: - load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] >> INS_SHAMT( m_op ) ); - break; + case FUNCT_SRL: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] >> INS_SHAMT( m_op ) ); + break; - case FUNCT_SRA: - load( INS_RD( m_op ), (int32_t)m_r[ INS_RT( m_op ) ] >> INS_SHAMT( m_op ) ); - break; + case FUNCT_SRA: + load( INS_RD( m_op ), (int32_t)m_r[ INS_RT( m_op ) ] >> INS_SHAMT( m_op ) ); + break; - case FUNCT_SLLV: - load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] << ( m_r[ INS_RS( m_op ) ] & 31 ) ); - break; + case FUNCT_SLLV: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] << ( m_r[ INS_RS( m_op ) ] & 31 ) ); + break; - case FUNCT_SRLV: - load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] >> ( m_r[ INS_RS( m_op ) ] & 31 ) ); - break; + case FUNCT_SRLV: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] >> ( m_r[ INS_RS( m_op ) ] & 31 ) ); + break; - case FUNCT_SRAV: - load( INS_RD( m_op ), (int32_t)m_r[ INS_RT( m_op ) ] >> ( m_r[ INS_RS( m_op ) ] & 31 ) ); - break; + case FUNCT_SRAV: + load( INS_RD( m_op ), (int32_t)m_r[ INS_RT( m_op ) ] >> ( m_r[ INS_RS( m_op ) ] & 31 ) ); + break; - case FUNCT_JR: - branch( m_r[ INS_RS( m_op ) ] ); - break; + case FUNCT_JR: + branch( m_r[ INS_RS( m_op ) ] ); + break; - case FUNCT_JALR: - branch( m_r[ INS_RS( m_op ) ] ); - if( INS_RD( m_op ) != 0 ) - { - m_r[ INS_RD( m_op ) ] = m_pc + 4; - } - break; + case FUNCT_JALR: + branch( m_r[ INS_RS( m_op ) ] ); + if( INS_RD( m_op ) != 0 ) + { + m_r[ INS_RD( m_op ) ] = m_pc + 4; + } + break; - case FUNCT_SYSCALL: - if( LOG_BIOSCALL ) log_syscall(); - exception( EXC_SYS ); - break; + case FUNCT_SYSCALL: + if( LOG_BIOSCALL ) log_syscall(); + exception( EXC_SYS ); + break; - case FUNCT_BREAK: - exception( EXC_BP ); - break; + case FUNCT_BREAK: + exception( EXC_BP ); + break; - case FUNCT_MFHI: - load( INS_RD( m_op ), get_hi() ); - break; + case FUNCT_MFHI: + load( INS_RD( m_op ), get_hi() ); + break; - case FUNCT_MTHI: - funct_mthi(); - advance_pc(); - break; + case FUNCT_MTHI: + funct_mthi(); + advance_pc(); + break; - case FUNCT_MFLO: - load( INS_RD( m_op ), get_lo() ); - break; + case FUNCT_MFLO: + load( INS_RD( m_op ), get_lo() ); + break; - case FUNCT_MTLO: - funct_mtlo(); - advance_pc(); - break; + case FUNCT_MTLO: + funct_mtlo(); + advance_pc(); + break; - case FUNCT_MULT: - funct_mult(); - advance_pc(); - break; + case FUNCT_MULT: + funct_mult(); + advance_pc(); + break; - case FUNCT_MULTU: - funct_multu(); - advance_pc(); - break; + case FUNCT_MULTU: + funct_multu(); + advance_pc(); + break; - case FUNCT_DIV: - funct_div(); - advance_pc(); - break; + case FUNCT_DIV: + funct_div(); + advance_pc(); + break; - case FUNCT_DIVU: - funct_divu(); - advance_pc(); - break; + case FUNCT_DIVU: + funct_divu(); + advance_pc(); + break; - case FUNCT_ADD: - { - uint32_t result = m_r[ INS_RS( m_op ) ] + m_r[ INS_RT( m_op ) ]; - if( (int32_t)( ~( m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) - { - exception( EXC_OVF ); - } - else + case FUNCT_ADD: { - load( INS_RD( m_op ), result ); + uint32_t result = m_r[ INS_RS( m_op ) ] + m_r[ INS_RT( m_op ) ]; + if( (int32_t)( ~( m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) + { + exception( EXC_OVF ); + } + else + { + load( INS_RD( m_op ), result ); + } } - } - break; + break; - case FUNCT_ADDU: - load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] + m_r[ INS_RT( m_op ) ] ); - break; + case FUNCT_ADDU: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] + m_r[ INS_RT( m_op ) ] ); + break; - case FUNCT_SUB: - { - uint32_t result = m_r[ INS_RS( m_op ) ] - m_r[ INS_RT( m_op ) ]; - if( (int32_t)( ( m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) - { - exception( EXC_OVF ); - } - else + case FUNCT_SUB: { - load( INS_RD( m_op ), result ); + uint32_t result = m_r[ INS_RS( m_op ) ] - m_r[ INS_RT( m_op ) ]; + if( (int32_t)( ( m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) + { + exception( EXC_OVF ); + } + else + { + load( INS_RD( m_op ), result ); + } } - } - break; - - case FUNCT_SUBU: - load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] - m_r[ INS_RT( m_op ) ] ); - break; - - case FUNCT_AND: - load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] & m_r[ INS_RT( m_op ) ] ); - break; + break; - case FUNCT_OR: - load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] | m_r[ INS_RT( m_op ) ] ); - break; + case FUNCT_SUBU: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] - m_r[ INS_RT( m_op ) ] ); + break; - case FUNCT_XOR: - load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ); - break; + case FUNCT_AND: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] & m_r[ INS_RT( m_op ) ] ); + break; - case FUNCT_NOR: - load( INS_RD( m_op ), ~( m_r[ INS_RS( m_op ) ] | m_r[ INS_RT( m_op ) ] ) ); - break; + case FUNCT_OR: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] | m_r[ INS_RT( m_op ) ] ); + break; - case FUNCT_SLT: - load( INS_RD( m_op ), (int32_t)m_r[ INS_RS( m_op ) ] < (int32_t)m_r[ INS_RT( m_op ) ] ); - break; + case FUNCT_XOR: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ); + break; - case FUNCT_SLTU: - load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] < m_r[ INS_RT( m_op ) ] ); - break; + case FUNCT_NOR: + load( INS_RD( m_op ), ~( m_r[ INS_RS( m_op ) ] | m_r[ INS_RT( m_op ) ] ) ); + break; - default: - exception( EXC_RI ); - break; - } - break; + case FUNCT_SLT: + load( INS_RD( m_op ), (int32_t)m_r[ INS_RS( m_op ) ] < (int32_t)m_r[ INS_RT( m_op ) ] ); + break; - case OP_REGIMM: - switch( INS_RT_REGIMM( m_op ) ) - { - case RT_BLTZ: - conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] < 0 ); + case FUNCT_SLTU: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] < m_r[ INS_RT( m_op ) ] ); + break; - if( INS_RT( m_op ) == RT_BLTZAL ) - { - m_r[ 31 ] = m_pc + 4; + default: + exception( EXC_RI ); + break; } break; - case RT_BGEZ: - conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] >= 0 ); - - if( INS_RT( m_op ) == RT_BGEZAL ) + case OP_REGIMM: + switch( INS_RT_REGIMM( m_op ) ) { - m_r[ 31 ] = m_pc + 4; - } - break; - } - break; - - case OP_J: - unconditional_branch(); - break; - - case OP_JAL: - unconditional_branch(); - m_r[ 31 ] = m_pc + 4; - break; - - case OP_BEQ: - conditional_branch( m_r[ INS_RS( m_op ) ] == m_r[ INS_RT( m_op ) ] ); - break; + case RT_BLTZ: + conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] < 0 ); - case OP_BNE: - conditional_branch( m_r[ INS_RS( m_op ) ] != m_r[ INS_RT( m_op ) ] ); - break; - - case OP_BLEZ: - conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] < 0 || m_r[ INS_RS( m_op ) ] == m_r[ INS_RT( m_op ) ] ); - break; + if( INS_RT( m_op ) == RT_BLTZAL ) + { + m_r[ 31 ] = m_pc + 4; + } + break; - case OP_BGTZ: - conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] >= 0 && m_r[ INS_RS( m_op ) ] != m_r[ INS_RT( m_op ) ] ); - break; + case RT_BGEZ: + conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] >= 0 ); - case OP_ADDI: - { - uint32_t immediate = PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - uint32_t result = m_r[ INS_RS( m_op ) ] + immediate; - if( (int32_t)( ~( m_r[ INS_RS( m_op ) ] ^ immediate ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) - { - exception( EXC_OVF ); - } - else - { - load( INS_RT( m_op ), result ); + if( INS_RT( m_op ) == RT_BGEZAL ) + { + m_r[ 31 ] = m_pc + 4; + } + break; } - } - break; - - case OP_ADDIU: - load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); - break; + break; - case OP_SLTI: - load( INS_RT( m_op ), (int32_t)m_r[ INS_RS( m_op ) ] < PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); - break; + case OP_J: + unconditional_branch(); + break; - case OP_SLTIU: - load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] < (uint32_t)PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); - break; + case OP_JAL: + unconditional_branch(); + m_r[ 31 ] = m_pc + 4; + break; - case OP_ANDI: - load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] & INS_IMMEDIATE( m_op ) ); - break; + case OP_BEQ: + conditional_branch( m_r[ INS_RS( m_op ) ] == m_r[ INS_RT( m_op ) ] ); + break; - case OP_ORI: - load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] | INS_IMMEDIATE( m_op ) ); - break; + case OP_BNE: + conditional_branch( m_r[ INS_RS( m_op ) ] != m_r[ INS_RT( m_op ) ] ); + break; - case OP_XORI: - load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] ^ INS_IMMEDIATE( m_op ) ); - break; + case OP_BLEZ: + conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] < 0 || m_r[ INS_RS( m_op ) ] == m_r[ INS_RT( m_op ) ] ); + break; - case OP_LUI: - load( INS_RT( m_op ), INS_IMMEDIATE( m_op ) << 16 ); - break; + case OP_BGTZ: + conditional_branch( (int32_t)m_r[ INS_RS( m_op ) ] >= 0 && m_r[ INS_RS( m_op ) ] != m_r[ INS_RT( m_op ) ] ); + break; - case OP_COP0: - switch( INS_RS( m_op ) ) - { - case RS_MFC: + case OP_ADDI: { - int reg = INS_RD( m_op ); - - if( reg == CP0_INDEX || - reg == CP0_RANDOM || - reg == CP0_ENTRYLO || - reg == CP0_CONTEXT || - reg == CP0_ENTRYHI ) - { - exception( EXC_RI ); - } - else if( reg < 16 ) + uint32_t immediate = PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + uint32_t result = m_r[ INS_RS( m_op ) ] + immediate; + if( (int32_t)( ~( m_r[ INS_RS( m_op ) ] ^ immediate ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) { - if( cop0_usable() ) - { - delayed_load( INS_RT( m_op ), m_cp0r[ reg ] ); - } + exception( EXC_OVF ); } else { - advance_pc(); + load( INS_RT( m_op ), result ); } } break; - case RS_CFC: - exception( EXC_RI ); + case OP_ADDIU: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); break; - case RS_MTC: - { - int reg = INS_RD( m_op ); + case OP_SLTI: + load( INS_RT( m_op ), (int32_t)m_r[ INS_RS( m_op ) ] < PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); + break; - if( reg == CP0_INDEX || - reg == CP0_RANDOM || - reg == CP0_ENTRYLO || - reg == CP0_CONTEXT || - reg == CP0_ENTRYHI ) - { - exception( EXC_RI ); - } - else if( reg < 16 ) - { - if( cop0_usable() ) - { - uint32_t data = ( m_cp0r[ reg ] & ~mtc0_writemask[ reg ] ) | - ( m_r[ INS_RT( m_op ) ] & mtc0_writemask[ reg ] ); - advance_pc(); + case OP_SLTIU: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] < (uint32_t)PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); + break; - m_cp0r[ reg ] = data; - update_cop0( reg ); - } - } - else - { - advance_pc(); - } - } + case OP_ANDI: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] & INS_IMMEDIATE( m_op ) ); break; - case RS_CTC: - exception( EXC_RI ); + case OP_ORI: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] | INS_IMMEDIATE( m_op ) ); break; - case RS_BC: - case RS_BC_ALT: - switch( INS_BC( m_op ) ) - { - case BC_BCF: - bc( 0, SR_CU0, 0 ); - break; + case OP_XORI: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] ^ INS_IMMEDIATE( m_op ) ); + break; - case BC_BCT: - bc( 0, SR_CU0, 1 ); - break; - } + case OP_LUI: + load( INS_RT( m_op ), INS_IMMEDIATE( m_op ) << 16 ); break; - default: - switch( INS_CO( m_op ) ) + case OP_COP0: + switch( INS_RS( m_op ) ) { - case 1: - switch( INS_CF( m_op ) ) + case RS_MFC: { - case CF_TLBR: - case CF_TLBWI: - case CF_TLBWR: - case CF_TLBP: - exception( EXC_RI ); - break; + int reg = INS_RD( m_op ); - case CF_RFE: - if( cop0_usable() ) + if( reg == CP0_INDEX || + reg == CP0_RANDOM || + reg == CP0_ENTRYLO || + reg == CP0_CONTEXT || + reg == CP0_ENTRYHI ) + { + exception( EXC_RI ); + } + else if( reg < 16 ) + { + if( cop0_usable() ) + { + delayed_load( INS_RT( m_op ), m_cp0r[ reg ] ); + } + } + else { advance_pc(); - m_cp0r[ CP0_SR ] = ( m_cp0r[ CP0_SR ] & ~0xf ) | ( ( m_cp0r[ CP0_SR ] >> 2 ) & 0xf ); - update_cop0( CP0_SR ); } - break; - - default: - advance_pc(); - break; } break; - default: - advance_pc(); - break; - } - break; - } - break; - - case OP_COP1: - if( ( m_cp0r[ CP0_SR ] & SR_CU1 ) == 0 ) - { - exception( EXC_CPU ); - } - else - { - switch( INS_RS( m_op ) ) - { - case RS_MFC: - delayed_load( INS_RT( m_op ), getcp1dr( INS_RD( m_op ) ) ); - break; - case RS_CFC: - delayed_load( INS_RT( m_op ), getcp1cr( INS_RD( m_op ) ) ); + exception( EXC_RI ); break; case RS_MTC: - setcp1dr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); - advance_pc(); + { + int reg = INS_RD( m_op ); + + if( reg == CP0_INDEX || + reg == CP0_RANDOM || + reg == CP0_ENTRYLO || + reg == CP0_CONTEXT || + reg == CP0_ENTRYHI ) + { + exception( EXC_RI ); + } + else if( reg < 16 ) + { + if( cop0_usable() ) + { + uint32_t data = ( m_cp0r[ reg ] & ~mtc0_writemask[ reg ] ) | + ( m_r[ INS_RT( m_op ) ] & mtc0_writemask[ reg ] ); + advance_pc(); + + m_cp0r[ reg ] = data; + update_cop0( reg ); + } + } + else + { + advance_pc(); + } + } break; case RS_CTC: - setcp1cr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); - advance_pc(); + exception( EXC_RI ); break; case RS_BC: @@ -2698,59 +2650,11 @@ void psxcpu_device::execute_run() switch( INS_BC( m_op ) ) { case BC_BCF: - bc( 1, SR_CU1, 0 ); + bc( 0, SR_CU0, 0 ); break; case BC_BCT: - bc( 1, SR_CU1, 1 ); - break; - } - break; - - default: - advance_pc(); - break; - } - } - break; - - case OP_COP2: - if( ( m_cp0r[ CP0_SR ] & SR_CU2 ) == 0 ) - { - exception( EXC_CPU ); - } - else - { - switch( INS_RS( m_op ) ) - { - case RS_MFC: - delayed_load( INS_RT( m_op ), m_gte.getcp2dr( m_pc, INS_RD( m_op ) ) ); - break; - - case RS_CFC: - delayed_load( INS_RT( m_op ), m_gte.getcp2cr( m_pc, INS_RD( m_op ) ) ); - break; - - case RS_MTC: - m_gte.setcp2dr( m_pc, INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); - advance_pc(); - break; - - case RS_CTC: - m_gte.setcp2cr( m_pc, INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); - advance_pc(); - break; - - case RS_BC: - case RS_BC_ALT: - switch( INS_BC( m_op ) ) - { - case BC_BCF: - bc( 2, SR_CU2, 0 ); - break; - - case BC_BCT: - bc( 2, SR_CU2, 1 ); + bc( 0, SR_CU0, 1 ); break; } break; @@ -2759,12 +2663,28 @@ void psxcpu_device::execute_run() switch( INS_CO( m_op ) ) { case 1: - if( !m_gte.docop2( m_pc, INS_COFUN( m_op ) ) ) + switch( INS_CF( m_op ) ) { - stop(); - } + case CF_TLBR: + case CF_TLBWI: + case CF_TLBWR: + case CF_TLBP: + exception( EXC_RI ); + break; + + case CF_RFE: + if( cop0_usable() ) + { + advance_pc(); + m_cp0r[ CP0_SR ] = ( m_cp0r[ CP0_SR ] & ~0xf ) | ( ( m_cp0r[ CP0_SR ] >> 2 ) & 0xf ); + update_cop0( CP0_SR ); + } + break; - advance_pc(); + default: + advance_pc(); + break; + } break; default: @@ -2773,524 +2693,634 @@ void psxcpu_device::execute_run() } break; } - } - break; + break; - case OP_COP3: - if( ( m_cp0r[ CP0_SR ] & SR_CU3 ) == 0 ) - { - exception( EXC_CPU ); - } - else - { - switch( INS_RS( m_op ) ) + case OP_COP1: + if( ( m_cp0r[ CP0_SR ] & SR_CU1 ) == 0 ) { - case RS_MFC: - delayed_load( INS_RT( m_op ), getcp3dr( INS_RD( m_op ) ) ); - break; + exception( EXC_CPU ); + } + else + { + switch( INS_RS( m_op ) ) + { + case RS_MFC: + delayed_load( INS_RT( m_op ), getcp1dr( INS_RD( m_op ) ) ); + break; - case RS_CFC: - delayed_load( INS_RT( m_op ), getcp3cr( INS_RD( m_op ) ) ); - break; + case RS_CFC: + delayed_load( INS_RT( m_op ), getcp1cr( INS_RD( m_op ) ) ); + break; - case RS_MTC: - setcp3dr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); - advance_pc(); - break; + case RS_MTC: + setcp1dr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; - case RS_CTC: - setcp3cr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); - advance_pc(); - break; + case RS_CTC: + setcp1cr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; - case RS_BC: - case RS_BC_ALT: - switch( INS_BC( m_op ) ) - { - case BC_BCF: - bc( 3, SR_CU3, 0 ); + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 1, SR_CU1, 0 ); + break; + + case BC_BCT: + bc( 1, SR_CU1, 1 ); + break; + } break; - case BC_BCT: - bc( 3, SR_CU3, 1 ); + default: + advance_pc(); break; } - break; - - default: - advance_pc(); - break; } - } - break; - - case OP_LB: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = load_data_address_breakpoint( address ); + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) - { - load_bad_address( address ); - } - else if( breakpoint ) + case OP_COP2: + if( ( m_cp0r[ CP0_SR ] & SR_CU2 ) == 0 ) { - breakpoint_exception(); + exception( EXC_CPU ); } else { - uint32_t data = PSXCPU_BYTE_EXTEND( readbyte( address ) ); - - if( m_berr ) - { - load_bus_error_exception(); - } - else + switch( INS_RS( m_op ) ) { - delayed_load( INS_RT( m_op ), data ); - } - } - } - break; + case RS_MFC: + delayed_load( INS_RT( m_op ), m_gte.getcp2dr( m_pc, INS_RD( m_op ) ) ); + break; - case OP_LH: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = load_data_address_breakpoint( address ); + case RS_CFC: + delayed_load( INS_RT( m_op ), m_gte.getcp2cr( m_pc, INS_RD( m_op ) ) ); + break; - if( ( address & m_bad_half_address_mask ) != 0 ) - { - load_bad_address( address ); - } - else if( breakpoint ) - { - breakpoint_exception(); - } - else - { - uint32_t data = PSXCPU_WORD_EXTEND( readhalf( address ) ); + case RS_MTC: + m_gte.setcp2dr( m_pc, INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; - if( m_berr ) - { - load_bus_error_exception(); - } - else - { - delayed_load( INS_RT( m_op ), data ); - } - } - } - break; + case RS_CTC: + m_gte.setcp2cr( m_pc, INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; - case OP_LWL: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int load_type = address & 3; - int breakpoint; + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 2, SR_CU2, 0 ); + break; - address &= ~3; - breakpoint = load_data_address_breakpoint( address ); + case BC_BCT: + bc( 2, SR_CU2, 1 ); + break; + } + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) - { - load_bad_address( address ); + default: + switch( INS_CO( m_op ) ) + { + case 1: + if( !m_gte.docop2( m_pc, INS_COFUN( m_op ) ) ) + { + stop(); + } + + advance_pc(); + break; + + default: + advance_pc(); + break; + } + break; + } } - else if( breakpoint ) + break; + + case OP_COP3: + if( ( m_cp0r[ CP0_SR ] & SR_CU3 ) == 0 ) { - breakpoint_exception(); + exception( EXC_CPU ); } else { - uint32_t data = get_register_from_pipeline( INS_RT( m_op ) ); - - switch( load_type ) + switch( INS_RS( m_op ) ) { - case 0: - data = ( data & 0x00ffffff ) | ( readword_masked( address, 0x000000ff ) << 24 ); + case RS_MFC: + delayed_load( INS_RT( m_op ), getcp3dr( INS_RD( m_op ) ) ); break; - case 1: - data = ( data & 0x0000ffff ) | ( readword_masked( address, 0x0000ffff ) << 16 ); + case RS_CFC: + delayed_load( INS_RT( m_op ), getcp3cr( INS_RD( m_op ) ) ); break; - case 2: - data = ( data & 0x000000ff ) | ( readword_masked( address, 0x00ffffff ) << 8 ); + case RS_MTC: + setcp3dr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); break; - case 3: - data = readword( address ); + case RS_CTC: + setcp3cr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 3, SR_CU3, 0 ); + break; + + case BC_BCT: + bc( 3, SR_CU3, 1 ); + break; + } + break; + + default: + advance_pc(); break; } + } + break; + + case OP_LB: + { + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); - if( m_berr ) + if( ( address & m_bad_byte_address_mask ) != 0 ) { - load_bus_error_exception(); + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); } else { - delayed_load( INS_RT( m_op ), data ); + uint32_t data = PSXCPU_BYTE_EXTEND( readbyte( address ) ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } } } - } - break; - - case OP_LW: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = load_data_address_breakpoint( address ); + break; - if( ( address & m_bad_word_address_mask ) != 0 ) + case OP_LH: { - load_bad_address( address ); - } - else if( breakpoint ) - { - breakpoint_exception(); - } - else - { - uint32_t data = readword( address ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); - if( m_berr ) + if( ( address & m_bad_half_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) { - load_bus_error_exception(); + breakpoint_exception(); } else { - delayed_load( INS_RT( m_op ), data ); + uint32_t data = PSXCPU_WORD_EXTEND( readhalf( address ) ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } } } - } - break; - - case OP_LBU: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = load_data_address_breakpoint( address ); + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) - { - load_bad_address( address ); - } - else if( breakpoint ) + case OP_LWL: { - breakpoint_exception(); - } - else - { - uint32_t data = readbyte( address ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int load_type = address & 3; + int breakpoint; + + address &= ~3; + breakpoint = load_data_address_breakpoint( address ); - if( m_berr ) + if( ( address & m_bad_byte_address_mask ) != 0 ) { - load_bus_error_exception(); + load_bad_address( address ); } - else + else if( breakpoint ) { - delayed_load( INS_RT( m_op ), data ); + breakpoint_exception(); } - } - } - break; + else + { + uint32_t data = get_register_from_pipeline( INS_RT( m_op ) ); - case OP_LHU: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = load_data_address_breakpoint( address ); + switch( load_type ) + { + case 0: + data = ( data & 0x00ffffff ) | ( readword_masked( address, 0x000000ff ) << 24 ); + break; - if( ( address & m_bad_half_address_mask ) != 0 ) - { - load_bad_address( address ); - } - else if( breakpoint ) - { - breakpoint_exception(); + case 1: + data = ( data & 0x0000ffff ) | ( readword_masked( address, 0x0000ffff ) << 16 ); + break; + + case 2: + data = ( data & 0x000000ff ) | ( readword_masked( address, 0x00ffffff ) << 8 ); + break; + + case 3: + data = readword( address ); + break; + } + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } } - else + break; + + case OP_LW: { - uint32_t data = readhalf( address ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); - if( m_berr ) + if( ( address & m_bad_word_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) { - load_bus_error_exception(); + breakpoint_exception(); } else { - delayed_load( INS_RT( m_op ), data ); + uint32_t data = readword( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } } } - } - break; - - case OP_LWR: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = load_data_address_breakpoint( address ); + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) + case OP_LBU: { - load_bad_address( address ); - } - else if( breakpoint ) - { - breakpoint_exception(); - } - else - { - uint32_t data = get_register_from_pipeline( INS_RT( m_op ) ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); - switch( address & 3 ) + if( ( address & m_bad_byte_address_mask ) != 0 ) { - case 0: - data = readword( address ); - break; - - case 1: - data = ( data & 0xff000000 ) | ( readword_masked( address, 0xffffff00 ) >> 8 ); - break; - - case 2: - data = ( data & 0xffff0000 ) | ( readword_masked( address, 0xffff0000 ) >> 16 ); - break; - - case 3: - data = ( data & 0xffffff00 ) | ( readword_masked( address, 0xff000000 ) >> 24 ); - break; + load_bad_address( address ); } - - if( m_berr ) + else if( breakpoint ) { - load_bus_error_exception(); + breakpoint_exception(); } else { - delayed_load( INS_RT( m_op ), data ); + uint32_t data = readbyte( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } } } - } - break; - - case OP_SB: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = store_data_address_breakpoint( address ); + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) + case OP_LHU: { - store_bad_address( address ); - } - else - { - int shift = 8 * ( address & 3 ); - writeword_masked( address, m_r[ INS_RT( m_op ) ] << shift, 0xff << shift ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); - if( breakpoint ) + if( ( address & m_bad_half_address_mask ) != 0 ) { - breakpoint_exception(); + load_bad_address( address ); } - else if( m_berr ) + else if( breakpoint ) { - store_bus_error_exception(); + breakpoint_exception(); } else { - advance_pc(); + uint32_t data = readhalf( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } } } - } - break; - - case OP_SH: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = store_data_address_breakpoint( address ); + break; - if( ( address & m_bad_half_address_mask ) != 0 ) - { - store_bad_address( address ); - } - else + case OP_LWR: { - int shift = 8 * ( address & 2 ); - writeword_masked( address, m_r[ INS_RT( m_op ) ] << shift, 0xffff << shift ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); - if( breakpoint ) + if( ( address & m_bad_byte_address_mask ) != 0 ) { - breakpoint_exception(); + load_bad_address( address ); } - else if( m_berr ) + else if( breakpoint ) { - store_bus_error_exception(); + breakpoint_exception(); } else { - advance_pc(); - } - } - } - break; + uint32_t data = get_register_from_pipeline( INS_RT( m_op ) ); - case OP_SWL: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int save_type = address & 3; - int breakpoint; + switch( address & 3 ) + { + case 0: + data = readword( address ); + break; - address &= ~3; - breakpoint = store_data_address_breakpoint( address ); + case 1: + data = ( data & 0xff000000 ) | ( readword_masked( address, 0xffffff00 ) >> 8 ); + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) - { - store_bad_address( address ); - } - else - { - switch( save_type ) - { - case 0: - writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 24, 0x000000ff ); - break; - - case 1: - writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 16, 0x0000ffff ); - break; + case 2: + data = ( data & 0xffff0000 ) | ( readword_masked( address, 0xffff0000 ) >> 16 ); + break; - case 2: - writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 8, 0x00ffffff ); - break; + case 3: + data = ( data & 0xffffff00 ) | ( readword_masked( address, 0xff000000 ) >> 24 ); + break; + } - case 3: - writeword( address, m_r[ INS_RT( m_op ) ] ); - break; + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } } + } + break; - if( breakpoint ) - { - breakpoint_exception(); - } - else if( m_berr ) + case OP_SB: + { + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) { - store_bus_error_exception(); + store_bad_address( address ); } else { - advance_pc(); + int shift = 8 * ( address & 3 ); + writeword_masked( address, m_r[ INS_RT( m_op ) ] << shift, 0xff << shift ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } } } - } - break; - - case OP_SW: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = store_data_address_breakpoint( address ); + break; - if( ( address & m_bad_word_address_mask ) != 0 ) + case OP_SH: { - store_bad_address( address ); - } - else - { - writeword( address, m_r[ INS_RT( m_op ) ] ); + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); - if( breakpoint ) - { - breakpoint_exception(); - } - else if( m_berr ) + if( ( address & m_bad_half_address_mask ) != 0 ) { - store_bus_error_exception(); + store_bad_address( address ); } else { - advance_pc(); + int shift = 8 * ( address & 2 ); + writeword_masked( address, m_r[ INS_RT( m_op ) ] << shift, 0xffff << shift ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } } } - } - break; - - case OP_SWR: - { - uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); - int breakpoint = store_data_address_breakpoint( address ); + break; - if( ( address & m_bad_byte_address_mask ) != 0 ) - { - store_bad_address( address ); - } - else + case OP_SWL: { - switch( address & 3 ) + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int save_type = address & 3; + int breakpoint; + + address &= ~3; + breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) { - case 0: - writeword( address, m_r[ INS_RT( m_op ) ] ); - break; + store_bad_address( address ); + } + else + { + switch( save_type ) + { + case 0: + writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 24, 0x000000ff ); + break; - case 1: - writeword_masked( address, m_r[ INS_RT( m_op ) ] << 8, 0xffffff00 ); - break; + case 1: + writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 16, 0x0000ffff ); + break; - case 2: - writeword_masked( address, m_r[ INS_RT( m_op ) ] << 16, 0xffff0000 ); - break; + case 2: + writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 8, 0x00ffffff ); + break; - case 3: - writeword_masked( address, m_r[ INS_RT( m_op ) ] << 24, 0xff000000 ); - break; + case 3: + writeword( address, m_r[ INS_RT( m_op ) ] ); + break; + } + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } } + } + break; - if( breakpoint ) + case OP_SW: + { + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_word_address_mask ) != 0 ) { - breakpoint_exception(); + store_bad_address( address ); } - else if( m_berr ) + else { - store_bus_error_exception(); + writeword( address, m_r[ INS_RT( m_op ) ] ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } + } + break; + + case OP_SWR: + { + uint32_t address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + store_bad_address( address ); } else { - advance_pc(); + switch( address & 3 ) + { + case 0: + writeword( address, m_r[ INS_RT( m_op ) ] ); + break; + + case 1: + writeword_masked( address, m_r[ INS_RT( m_op ) ] << 8, 0xffffff00 ); + break; + + case 2: + writeword_masked( address, m_r[ INS_RT( m_op ) ] << 16, 0xffff0000 ); + break; + + case 3: + writeword_masked( address, m_r[ INS_RT( m_op ) ] << 24, 0xff000000 ); + break; + } + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } } } - } - break; + break; - case OP_LWC0: - lwc( 0, SR_CU0 ); - break; + case OP_LWC0: + lwc( 0, SR_CU0 ); + break; - case OP_LWC1: - lwc( 1, SR_CU1 ); - break; + case OP_LWC1: + lwc( 1, SR_CU1 ); + break; - case OP_LWC2: - lwc( 2, SR_CU2 ); - break; + case OP_LWC2: + lwc( 2, SR_CU2 ); + break; - case OP_LWC3: - lwc( 3, SR_CU3 ); - break; + case OP_LWC3: + lwc( 3, SR_CU3 ); + break; - case OP_SWC0: - swc( 0, SR_CU0 ); - break; + case OP_SWC0: + swc( 0, SR_CU0 ); + break; - case OP_SWC1: - swc( 1, SR_CU1 ); - break; + case OP_SWC1: + swc( 1, SR_CU1 ); + break; - case OP_SWC2: - swc( 2, SR_CU2 ); - break; + case OP_SWC2: + swc( 2, SR_CU2 ); + break; - case OP_SWC3: - swc( 3, SR_CU3 ); - break; + case OP_SWC3: + swc( 3, SR_CU3 ); + break; - default: - logerror( "%08x: unknown opcode %08x\n", m_pc, m_op ); - stop(); - exception( EXC_RI ); - break; + default: + logerror( "%08x: unknown opcode %08x\n", m_pc, m_op ); + stop(); + exception( EXC_RI ); + break; + } } } diff --git a/src/devices/cpu/psx/psx.h b/src/devices/cpu/psx/psx.h index 7b4793fc3bd..da70d2c300c 100644 --- a/src/devices/cpu/psx/psx.h +++ b/src/devices/cpu/psx/psx.h @@ -24,12 +24,15 @@ // interrupts -#define PSXCPU_IRQ0 ( 0 ) -#define PSXCPU_IRQ1 ( 1 ) -#define PSXCPU_IRQ2 ( 2 ) -#define PSXCPU_IRQ3 ( 3 ) -#define PSXCPU_IRQ4 ( 4 ) -#define PSXCPU_IRQ5 ( 5 ) +enum +{ + PSXCPU_IRQ0 = 0, + PSXCPU_IRQ1, + PSXCPU_IRQ2, + PSXCPU_IRQ3, + PSXCPU_IRQ4, + PSXCPU_IRQ5, +}; // register enumeration @@ -97,6 +100,14 @@ enum PSXCPU_CP2CR30, PSXCPU_CP2CR31 }; +// delay slot sentinels + +enum +{ + PSXCPU_DELAYR_PC = 32, + PSXCPU_DELAYR_NOTPC = 33 +}; + //************************************************************************** // INTERFACE CONFIGURATION MACROS @@ -293,7 +304,7 @@ protected: void commit_delayed_load(); void set_pc( unsigned pc ); void fetch_next_op(); - int advance_pc(); + void advance_pc(); void load( uint32_t reg, uint32_t value ); void delayed_load( uint32_t reg, uint32_t value ); void branch( uint32_t address ); @@ -307,6 +318,7 @@ protected: void store_bus_error_exception(); void load_bad_address( uint32_t address ); void store_bad_address( uint32_t address ); + int program_counter_breakpoint(); int data_address_breakpoint( int dcic_rw, int dcic_status, uint32_t address ); int load_data_address_breakpoint( uint32_t address ); int store_data_address_breakpoint( uint32_t address ); diff --git a/src/devices/cpu/psx/psxdefs.h b/src/devices/cpu/psx/psxdefs.h index fde2456b515..3939254ac50 100644 --- a/src/devices/cpu/psx/psxdefs.h +++ b/src/devices/cpu/psx/psxdefs.h @@ -6,9 +6,6 @@ #pragma once -#define PSXCPU_DELAYR_PC ( 32 ) -#define PSXCPU_DELAYR_NOTPC ( 33 ) - #define PSXCPU_BYTE_EXTEND( a ) ( (int32_t)(int8_t)a ) #define PSXCPU_WORD_EXTEND( a ) ( (int32_t)(int16_t)a ) diff --git a/src/mame/drivers/psx.cpp b/src/mame/drivers/psx.cpp index 453b030ce6f..b1e07a4c460 100644 --- a/src/mame/drivers/psx.cpp +++ b/src/mame/drivers/psx.cpp @@ -1,9 +1,9 @@ -// license:BSD-3-Clause +// license:GPL-2.0+ // copyright-holders:smf, pSXAuthor, R. Belmont /*************************************************************************** - Sony Playstaion - =============== + Sony PlayStation + ================ Preliminary driver by smf Additional development by pSXAuthor and R. Belmont @@ -25,6 +25,7 @@ #include "softlist.h" #include "speaker.h" +#include #define PSXCD_TAG "psxcd" @@ -32,14 +33,13 @@ class psx1_state : public driver_device { public: psx1_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) , + : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_ram(*this, "maincpu:ram") { } - uint8_t *m_exe_buffer; - int m_exe_size; + std::vector m_exe_buffer; int m_cd_param_p; int m_cd_result_p; int m_cd_result_c; @@ -51,6 +51,14 @@ public: uint8_t m_cd_result[8]; DECLARE_MACHINE_RESET(psx); inline void ATTR_PRINTF(3,4) verboselog( int n_level, const char *s_fmt, ... ); + void psxexe_conv32(uint32_t *uint32); + int load_psxexe(std::vector buffer); + void cpe_set_register(int r, int v); + int load_cpe(std::vector buffer); + int load_psf(std::vector buffer); + DECLARE_READ16_MEMBER(parallel_r); + DECLARE_WRITE16_MEMBER(parallel_w); + DECLARE_QUICKLOAD_LOAD_MEMBER(psx_exe_load); void cd_dma_read( uint32_t *p_n_psxram, uint32_t n_address, int32_t n_size ); void cd_dma_write( uint32_t *p_n_psxram, uint32_t n_address, int32_t n_size ); required_device m_maincpu; @@ -73,6 +81,392 @@ inline void ATTR_PRINTF(3,4) psx1_state::verboselog( int n_level, const char *s } } +void psx1_state::psxexe_conv32(uint32_t *uint32) +{ + uint8_t *uint8 = (uint8_t *)uint32; + + *(uint32) = uint8[0] | (uint8[1] << 8) | (uint8[2] << 16) | (uint8[3] << 24); +} + +int psx1_state::load_psxexe(std::vector buffer) +{ + struct PSXEXE_HEADER + { + uint8_t id[8]; + uint32_t text; /* SCE only */ + uint32_t data; /* SCE only */ + uint32_t pc0; + uint32_t gp0; /* SCE only */ + uint32_t t_addr; + uint32_t t_size; + uint32_t d_addr; /* SCE only */ + uint32_t d_size; /* SCE only */ + uint32_t b_addr; /* SCE only */ + uint32_t b_size; /* SCE only */ + uint32_t s_addr; + uint32_t s_size; + uint32_t SavedSP; + uint32_t SavedFP; + uint32_t SavedGP; + uint32_t SavedRA; + uint32_t SavedS0; + uint8_t dummy[0x800 - 76]; + }; + + struct PSXEXE_HEADER *psxexe_header = reinterpret_cast(&buffer[0]); + + if (buffer.size() >= sizeof(struct PSXEXE_HEADER) && + memcmp(psxexe_header->id, "PS-X EXE", 8) == 0) + { + psxexe_conv32(&psxexe_header->text); + psxexe_conv32(&psxexe_header->data); + psxexe_conv32(&psxexe_header->pc0); + psxexe_conv32(&psxexe_header->gp0); + psxexe_conv32(&psxexe_header->t_addr); + psxexe_conv32(&psxexe_header->t_size); + psxexe_conv32(&psxexe_header->d_addr); + psxexe_conv32(&psxexe_header->d_size); + psxexe_conv32(&psxexe_header->b_addr); + psxexe_conv32(&psxexe_header->b_size); + psxexe_conv32(&psxexe_header->s_addr); + psxexe_conv32(&psxexe_header->s_size); + psxexe_conv32(&psxexe_header->SavedSP); + psxexe_conv32(&psxexe_header->SavedFP); + psxexe_conv32(&psxexe_header->SavedGP); + psxexe_conv32(&psxexe_header->SavedRA); + psxexe_conv32(&psxexe_header->SavedS0); + + /* todo: check size.. */ + + logerror("psx_exe_load: pc %08x\n", psxexe_header->pc0); + logerror("psx_exe_load: org %08x\n", psxexe_header->t_addr); + logerror("psx_exe_load: len %08x\n", psxexe_header->t_size); + logerror("psx_exe_load: sp %08x\n", psxexe_header->s_addr); + logerror("psx_exe_load: len %08x\n", psxexe_header->s_size); + + uint8_t *ram_pointer = m_ram->pointer(); + uint32_t ram_size = m_ram->size(); + + uint8_t *text = reinterpret_cast(&buffer[sizeof(struct PSXEXE_HEADER)]); + + uint32_t address = psxexe_header->t_addr; + uint32_t size = psxexe_header->t_size; + while (size != 0) + { + ram_pointer[BYTE4_XOR_LE(address++) % ram_size] = *(text++); + size--; + } + + m_maincpu->set_state_int(PSXCPU_PC, psxexe_header->pc0); + m_maincpu->set_state_int(PSXCPU_R28, psxexe_header->gp0); + uint32_t stack = psxexe_header->s_addr + psxexe_header->s_size; + if (stack != 0) + { + m_maincpu->set_state_int(PSXCPU_R29, stack); + m_maincpu->set_state_int(PSXCPU_R30, stack); + } + + return 1; + } + return 0; +} + +void psx1_state::cpe_set_register(int r, int v) +{ + if (r < 0x80 && (r % 4) == 0) + { + logerror("psx_exe_load: r%-2d %08x\n", r / 4, v); + m_maincpu->set_state_int(PSXCPU_R0 + (r / 4), v); + } + else if (r == 0x80) + { + logerror("psx_exe_load: lo %08x\n", v); + m_maincpu->set_state_int(PSXCPU_LO, v); + } + else if (r == 0x84) + { + logerror("psx_exe_load: hi %08x\n", v); + m_maincpu->set_state_int(PSXCPU_HI, v); + } + else if (r == 0x88) + { + logerror("psx_exe_load: sr %08x\n", v); + m_maincpu->set_state_int(PSXCPU_CP0R12, v); + } + else if (r == 0x8c) + { + logerror("psx_exe_load: cause %08x\n", v); + m_maincpu->set_state_int(PSXCPU_CP0R13, v); + } + else if (r == 0x90) + { + logerror("psx_exe_load: pc %08x\n", v); + m_maincpu->set_state_int(PSXCPU_PC, v); + } + else if (r == 0x94) + { + logerror("psx_exe_load: prid %08x\n", v); + m_maincpu->set_state_int(PSXCPU_CP0R15, v); + } + else + { + logerror("psx_exe_load: invalid register %04x/%08x\n", r, v); + } +} + +int psx1_state::load_cpe(std::vector buffer) +{ + if (buffer.size() >= 4 && + memcmp(reinterpret_cast(&buffer[0]), "CPE\001", 4) == 0) + { + int offset = 4; + + for (;;) + { + if (offset >= buffer.size() || buffer[offset] > 8) + { + break; + } + + switch (buffer[offset++]) + { + case 0: + /* end of file */ + return 1; + + case 1: + /* read bytes */ + { + unsigned int address = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24); + unsigned int size = buffer[offset + 4] | (buffer[offset + 5] << 8) | (buffer[offset + 6] << 16) | (buffer[offset + 7] << 24); + + uint8_t *ram_pointer = m_ram->pointer(); + uint32_t ram_size = m_ram->size(); + + offset += 8; + + logerror("psx_exe_load: org %08x\n", address); + logerror("psx_exe_load: len %08x\n", size); + + while (size > 0) + { + ram_pointer[BYTE4_XOR_LE(address) % ram_size] = buffer[offset++]; + address++; + size--; + } + } + break; + + case 2: + /* run address: not tested */ + { + unsigned int v = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24); + + offset += 4; + + cpe_set_register(0x90, v); + } + break; + + case 3: + /* set reg to longword */ + { + unsigned int r = buffer[offset] | (buffer[offset + 1] << 8); + unsigned int v = buffer[offset + 2] | (buffer[offset + 3] << 8) | (buffer[offset + 4] << 16) | (buffer[offset + 5] << 24); + + offset += 6; + + cpe_set_register(r, v); + } + break; + + case 4: + /* set reg to word: not tested */ + { + unsigned int r = buffer[offset] | (buffer[offset + 1] << 8); + unsigned int v = buffer[offset + 2] | (buffer[offset + 3] << 8); + + offset += 4; + + cpe_set_register(r, v); + } + break; + + case 5: + /* set reg to byte: not tested */ + { + unsigned int r = buffer[offset] | (buffer[offset + 1] << 8); + unsigned int v = buffer[offset + 2]; + + offset += 3; + + cpe_set_register(r, v); + } + break; + + case 6: + /* set reg to 3-byte: not tested */ + { + unsigned int r = buffer[offset] | (buffer[offset + 1] << 8); + unsigned int v = buffer[offset + 2] | (buffer[offset + 3] << 8) | (buffer[offset + 4] << 16); + + offset += 5; + + cpe_set_register(r, v); + } + break; + + case 7: + /* workspace: not tested */ + offset += 4; + break; + + case 8: + /* unit */ + { + int unit = buffer[offset + 0]; + + offset++; + + logerror("psx_exe_load: unit %08x\n", unit); + } + break; + } + } + } + + return 0; +} + +int psx1_state::load_psf(std::vector buffer) +{ + unsigned long crc; + unsigned long compressed_size; + unsigned char *compressed_buffer; + unsigned long uncompressed_size; + std::vector uncompressed_buffer; + + struct PSF_HEADER + { + unsigned char id[4]; + uint32_t reserved_size; + uint32_t exe_size; + uint32_t exe_crc; + }; + + struct PSF_HEADER *psf_header = reinterpret_cast(&buffer[0]); + + if (buffer.size() >= sizeof(struct PSF_HEADER) && + memcmp(reinterpret_cast(&buffer[0]), "PSF", 3) == 0) + { + psxexe_conv32(&psf_header->reserved_size); + psxexe_conv32(&psf_header->exe_size); + psxexe_conv32(&psf_header->exe_crc); + + logerror("psx_exe_load: reserved_size %08x\n", psf_header->reserved_size); + logerror("psx_exe_load: exe_size %08x\n", psf_header->exe_size); + logerror("psx_exe_load: exe_crc %08x\n", psf_header->exe_crc); + + compressed_size = psf_header->exe_size; + compressed_buffer = reinterpret_cast(&buffer[sizeof(struct PSF_HEADER) + psf_header->reserved_size]); + + crc = crc32(crc32(0L, Z_NULL, 0), compressed_buffer, compressed_size); + if (crc != psf_header->exe_crc) + { + logerror("psx_exe_load: psf invalid crc\n"); + return 0; + } + + uncompressed_size = 0x200000; + uncompressed_buffer.resize(uncompressed_size); + + if (uncompress(reinterpret_cast(&uncompressed_buffer[0]), &uncompressed_size, compressed_buffer, compressed_size) != Z_OK) + { + logerror("psx_exe_load: psf uncompress failed\n"); + } + else + { + uncompressed_buffer.resize(uncompressed_size); + + if (!load_psxexe(uncompressed_buffer)) + { + logerror("psx_exe_load: psf load failed\n"); + } + else + { + return 1; + } + } + } + + return 0; +} + +READ16_MEMBER(psx1_state::parallel_r) +{ + const uint16_t bootloader[] = + { + 0x00b0, 0x1f00, 0x694c, 0x6563, 0x736e, 0x6465, 0x6220, 0x2079, + 0x6f53, 0x796e, 0x4320, 0x6d6f, 0x7570, 0x6574, 0x2072, 0x6e45, + 0x6574, 0x7472, 0x6961, 0x6d6e, 0x6e65, 0x2074, 0x6e49, 0x2e63, + 0x1f00, 0x3c08, 0x8000, 0x3c09, 0x000c, 0x3529, 0x00fc, 0x8d0a, + 0xfffc, 0x2529, 0x0044, 0xad2a, 0xfffc, 0x0520, 0xfffc, 0x2508, + 0x8003, 0x3c08, 0x1800, 0x4088, 0xffff, 0x3c08, 0xffff, 0x3508, + 0x5800, 0x4088, 0xa180, 0x3c08, 0x0008, 0x03e0, 0x3800, 0x4088, + 0x1f00, 0x3c1a, 0x0100, 0x275a, 0x0008, 0x0340, 0x0010, 0x4200, + 0x3800, 0x4080, 0x1800, 0x4080, 0x5800, 0x4080, 0x1f00, 0x3c08, + 0x0000, 0xad00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + + if (m_exe_buffer.size() != 0 && offset >= 0x40 && offset <= 0x8f) + { + return bootloader[offset - 0x40]; + } + + return 0; +} + +WRITE16_MEMBER(psx1_state::parallel_w) +{ + if (m_exe_buffer.size() != 0) + { + if (load_psxexe(m_exe_buffer) || + load_cpe(m_exe_buffer) || + load_psf(m_exe_buffer)) + { + // stop the cpu from advancing to the next instruction, otherwise it would skip the exe's first instruction + m_maincpu->set_state_int(PSXCPU_DELAYR, PSXCPU_DELAYR_PC); + m_maincpu->set_state_int(PSXCPU_DELAYV, m_maincpu->state_int(PSXCPU_PC)); + + // workround to fix controller in amidog tests that do not initialise the sio registers + m_maincpu->space(AS_PROGRAM).write_word(0x1f80104e, 0x0088); + m_maincpu->space(AS_PROGRAM).write_word(0x1f801048, 0x000d); + + // stop on the first instruction of the exe if the debugger is active + machine().debug_break(); + } + else + { + logerror("psx_exe_load: invalid exe\n"); + m_maincpu->reset(); + } + + m_exe_buffer.resize(0); + } +} + +QUICKLOAD_LOAD_MEMBER(psx1_state, psx_exe_load) +{ + m_exe_buffer.resize(quickload_size); + + if (image.fread(reinterpret_cast(&m_exe_buffer[0]), quickload_size) != quickload_size) + { + m_exe_buffer.resize(0); + return image_init_result::FAIL; + } + + return image_init_result::PASS; +} void psx1_state::cd_dma_read( uint32_t *p_n_psxram, uint32_t n_address, int32_t n_size ) { @@ -87,6 +481,7 @@ void psx1_state::cd_dma_write( uint32_t *p_n_psxram, uint32_t n_address, int32_t } static ADDRESS_MAP_START( psx_map, AS_PROGRAM, 32, psx1_state ) + AM_RANGE(0x1f000000, 0x1f0001ff) AM_READWRITE16(parallel_r, parallel_w, 0xffffffff) ADDRESS_MAP_END static ADDRESS_MAP_START( subcpu_map, AS_PROGRAM, 8, psx1_state ) @@ -121,6 +516,8 @@ static MACHINE_CONFIG_START( psj ) MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) + MCFG_QUICKLOAD_ADD("quickload", psx1_state, psx_exe_load, "cpe,exe,psf,psx", 0) + MCFG_SOFTWARE_LIST_ADD("cd_list","psx") MCFG_DEVICE_MODIFY( "maincpu" ) @@ -167,6 +564,8 @@ static MACHINE_CONFIG_START( pse ) MCFG_SOUND_ROUTE( 0, "lspeaker", 1.00 ) MCFG_SOUND_ROUTE( 1, "rspeaker", 1.00 ) + MCFG_QUICKLOAD_ADD("quickload", psx1_state, psx_exe_load, "cpe,exe,psf,psx", 0) + MCFG_SOFTWARE_LIST_ADD("cd_list","psx") MCFG_DEVICE_MODIFY( "maincpu" ) -- cgit v1.2.3