From 30ec2aaaa71f1ca4f9245b969a489c4fca8c401d Mon Sep 17 00:00:00 2001 From: tedgreen99 Date: Thu, 14 Apr 2022 15:03:44 -0600 Subject: Fix MT07823: nbagold (vegas) watchdog reset when select other game menu from service menu (#9560) mips3: Add new DRC option to add extra validation to hash jumps vegas: Use new MIPS DRC option atlantis: Use new MIPS DRC option --- src/devices/cpu/drcfe.h | 2 + src/devices/cpu/mips/mips3.h | 9 ++-- src/devices/cpu/mips/mips3drc.cpp | 97 ++++++++++++++++++++++++++++++++++----- src/mame/drivers/atlantis.cpp | 2 +- src/mame/drivers/vegas.cpp | 12 +++-- 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/src/devices/cpu/drcfe.h b/src/devices/cpu/drcfe.h index a781f6d1156..e536ccd2430 100644 --- a/src/devices/cpu/drcfe.h +++ b/src/devices/cpu/drcfe.h @@ -133,6 +133,8 @@ public: // describe a block opcode_desc const *describe_code(offs_t startpc); + // get last opcode of block + opcode_desc const* get_last() { return m_desc_live_list.last(); }; protected: // required overrides diff --git a/src/devices/cpu/mips/mips3.h b/src/devices/cpu/mips/mips3.h index 2f67e6f0be2..3e46300a1e6 100644 --- a/src/devices/cpu/mips/mips3.h +++ b/src/devices/cpu/mips/mips3.h @@ -309,6 +309,7 @@ public: void add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base); void clear_fastram(uint32_t select_start); void mips3drc_set_options(uint32_t options); + uint32_t mips3drc_get_options(); void mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles); protected: @@ -623,7 +624,7 @@ private: void generate_update_mode(drcuml_block &block); void generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception); - void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast, const opcode_desc* codelast); void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); void generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg); @@ -968,8 +969,6 @@ private: /*************************************************************************** COMPILER-SPECIFIC OPTIONS ***************************************************************************/ - -/* fix me -- how do we make this work?? */ #define MIPS3DRC_STRICT_VERIFY 0x0001 /* verify all instructions */ #define MIPS3DRC_STRICT_COP0 0x0002 /* validate all COP0 instructions */ #define MIPS3DRC_STRICT_COP1 0x0004 /* validate all COP1 instructions */ @@ -977,9 +976,13 @@ COMPILER-SPECIFIC OPTIONS #define MIPS3DRC_DISABLE_INTRABLOCK 0x0010 /* disable intrablock branching */ #define MIPS3DRC_CHECK_OVERFLOWS 0x0020 /* actually check overflows on add/sub instructions */ #define MIPS3DRC_ACCURATE_DIVZERO 0x0040 /* load correct values into HI/LO on integer divide-by-zero */ +#define MIPS3DRC_EXTRA_INSTR_CHECK 0x0080 /* adds the last instruction value to all validation entry locations, used with STRICT_VERIFY */ #define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP2) #define MIPS3DRC_FASTEST_OPTIONS (0) +/* Use with STRICT_VERIFY to print debug info to console for extra validation checks */ +/* Set to 1 to activate and use MIPS3DRC_STRICT_VERIFY in the drc options */ +#define DEBUG_STRICT_VERIFY 0 #endif // MAME_CPU_MIPS_MIPS3_H diff --git a/src/devices/cpu/mips/mips3drc.cpp b/src/devices/cpu/mips/mips3drc.cpp index c054f7b6640..9cb8ba9b7d4 100644 --- a/src/devices/cpu/mips/mips3drc.cpp +++ b/src/devices/cpu/mips/mips3drc.cpp @@ -155,6 +155,15 @@ void mips3_device::mips3drc_set_options(uint32_t options) m_drcoptions = options; } +/*------------------------------------------------- + mips3drc_get_options - return current DRC options +-------------------------------------------------*/ + +uint32_t mips3_device::mips3drc_get_options() +{ + return m_drcoptions; +} + /*------------------------------------------------- mips3drc_clears_fastram - clears fastram region starting at index select_start @@ -282,6 +291,7 @@ void mips3_device::code_compile_block(uint8_t mode, offs_t pc) { compiler_state compiler = { 0 }; const opcode_desc *seqhead, *seqlast; + const opcode_desc* codelast; const opcode_desc *desclist; bool override = false; @@ -289,6 +299,8 @@ void mips3_device::code_compile_block(uint8_t mode, offs_t pc) /* get a description of this sequence */ desclist = m_drcfe->describe_code(pc); + /* get last instruction of the code (potentially used in generate_checksum) */ + codelast = m_drcfe->get_last(); if (m_drcuml->logging() || m_drcuml->logging_native()) log_opcode_desc(desclist, 0); @@ -340,7 +352,7 @@ void mips3_device::code_compile_block(uint8_t mode, offs_t pc) /* validate this code block if we're not pointing into ROM */ if (m_program->get_write_ptr(seqhead->physpc) != nullptr) - generate_checksum_block(block, compiler, seqhead, seqlast); + generate_checksum_block(block, compiler, seqhead, seqlast, codelast); /* label this instruction, if it may be jumped to locally */ if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) @@ -1097,7 +1109,7 @@ void mips3_device::generate_update_cycles(drcuml_block &block, compiler_state &c validate a sequence of opcodes -------------------------------------------------*/ -void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) +void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast, const opcode_desc* codelast) { const opcode_desc *curdesc; if (m_drcuml->logging()) @@ -1149,16 +1161,29 @@ void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state & uint32_t low_bits = (seqhead->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1); // load i0,base,0,dword sum += seqhead->opptr.l[0]; + if ((m_drcoptions & MIPS3DRC_EXTRA_INSTR_CHECK) && !(codelast->flags & OPFLAG_VIRTUAL_NOOP) && codelast->physpc != seqhead->physpc) + { + base = m_prptr(codelast->physpc); + assert(base != nullptr); + low_bits = (codelast->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; + UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += codelast->opptr.l[0]; + } for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) { if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { - base = m_prptr(curdesc->physpc); - assert(base != nullptr); - uint32_t low_bits = (curdesc->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; - UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword - UML_ADD(block, I0, I0, I1); // add i0,i0,i1 - sum += curdesc->opptr.l[0]; + // Skip the last if it was already included above + if (!(m_drcoptions & MIPS3DRC_EXTRA_INSTR_CHECK) || curdesc->physpc != codelast->physpc) + { + base = m_prptr(curdesc->physpc); + assert(base != nullptr); + low_bits = (curdesc->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; + UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += curdesc->opptr.l[0]; + } if (curdesc->delay.first() != nullptr && !(curdesc->delay.first()->flags & OPFLAG_VIRTUAL_NOOP) @@ -1166,7 +1191,7 @@ void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state & { base = m_prptr(curdesc->delay.first()->physpc); assert(base != nullptr); - uint32_t low_bits = (curdesc->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; + low_bits = (curdesc->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword UML_ADD(block, I0, I0, I1); // add i0,i0,i1 sum += curdesc->delay.first()->opptr.l[0]; @@ -1175,6 +1200,57 @@ void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state & } UML_CMP(block, I0, sum); // cmp i0,sum UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + if (DEBUG_STRICT_VERIFY) + { + // This code will do additional checks on the last instruction and last delay slot and indicate if the check failed + uml::code_label check_passed, check_failed, check_second; + check_second = compiler.labelnum++; + check_failed = compiler.labelnum++; + check_passed = compiler.labelnum++; + // Check the last instruction + if (!(codelast->flags & OPFLAG_VIRTUAL_NOOP) && codelast->physpc != seqhead->physpc) + { + base = m_prptr(codelast->physpc); + assert(base != nullptr); + low_bits = (codelast->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; + UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword + sum = codelast->opptr.l[0]; + UML_CMP(block, I0, sum); // cmp i0,sum + UML_JMPc(block, COND_E, check_second); + static const char text[] = "Last instr validation fail seq: %08X end: %08x\n"; + UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), seqhead->pc); + UML_MOV(block, mem(&m_core->arg1), codelast->physpc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + //UML_CALLC(block, cfunc_debug_break, this); + // Skip delay slot check + UML_JMP(block, check_failed); + // Check the last instruction delay slot + UML_LABEL(block, check_second); + if (codelast->delay.first() != nullptr && !(codelast->delay.first()->flags & OPFLAG_VIRTUAL_NOOP) + && codelast->physpc != seqhead->physpc) + { + base = m_prptr(codelast->delay.first()->physpc); + assert(base != nullptr); + low_bits = (codelast->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor; + UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1); // load i1,base,dword + sum = codelast->delay.first()->opptr.l[0]; + UML_CMP(block, I0, sum); // cmp i0,sum + UML_JMPc(block, COND_E, check_passed); + static const char text[] = "Last delay slot validation fail seq: %08X end: %08x\n"; + UML_DMOV(block, mem(&m_core->format), (uintptr_t)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), seqhead->pc); + UML_MOV(block, mem(&m_core->arg1), codelast->physpc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + //UML_CALLC(block, cfunc_debug_break, this); + UML_JMP(block, check_failed); + } + } + UML_JMP(block, check_passed); + UML_LABEL(block, check_failed); + UML_EXH(block, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + UML_LABEL(block, check_passed); + } #endif } } @@ -1189,7 +1265,6 @@ void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_s { offs_t expc; int hotnum; - /* add an entry for the log */ if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); @@ -1334,7 +1409,7 @@ void mips3_device::generate_delay_slot_and_branch(drcuml_block &block, compiler_ if (desc->targetpc != BRANCH_TARGET_DYNAMIC) { generate_update_cycles(block, compiler_temp, desc->targetpc, true); // - if (!(m_drcoptions & MIPS3DRC_DISABLE_INTRABLOCK) && desc->flags & OPFLAG_INTRABLOCK_BRANCH) + if (!(m_drcoptions & MIPS3DRC_DISABLE_INTRABLOCK) && (desc->flags & OPFLAG_INTRABLOCK_BRANCH)) { UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000 } diff --git a/src/mame/drivers/atlantis.cpp b/src/mame/drivers/atlantis.cpp index 6a77ce8d71b..4fa450c8350 100644 --- a/src/mame/drivers/atlantis.cpp +++ b/src/mame/drivers/atlantis.cpp @@ -625,7 +625,7 @@ void atlantis_state::a2d_data_w(uint16_t data) void atlantis_state::machine_start() { /* set the fastest DRC options */ - m_maincpu->mips3drc_set_options(MIPS3DRC_FASTEST_OPTIONS); + m_maincpu->mips3drc_set_options(MIPS3DRC_FASTEST_OPTIONS | MIPS3DRC_STRICT_VERIFY | MIPS3DRC_EXTRA_INSTR_CHECK); // Allocate adc timer m_adc_ready_timer = timer_alloc(0); diff --git a/src/mame/drivers/vegas.cpp b/src/mame/drivers/vegas.cpp index 5b8c9dace09..065c736dda1 100644 --- a/src/mame/drivers/vegas.cpp +++ b/src/mame/drivers/vegas.cpp @@ -485,7 +485,10 @@ private: void vegas_state::machine_start() { /* set the fastest DRC options, but strict verification */ - m_maincpu->mips3drc_set_options(MIPS3DRC_FASTEST_OPTIONS + MIPS3DRC_STRICT_VERIFY); + /* need to check the current options since some drivers add options in their init */ + uint32_t new_options = m_maincpu->mips3drc_get_options(); + new_options |= MIPS3DRC_FASTEST_OPTIONS | MIPS3DRC_STRICT_VERIFY; + m_maincpu->mips3drc_set_options(new_options); m_system_led.resolve(); m_wheel_driver.resolve(); @@ -2034,14 +2037,14 @@ void vegas_state::denver(machine_config &config) m_uart2->out_rts_callback().set("ttys02", FUNC(rs232_port_device::write_rts)); m_uart2->out_int_callback().set("duart_irq", FUNC(input_merger_device::in_w<1>)); - rs232_port_device &ttys01(RS232_PORT(config, "ttys01", 0)); + rs232_port_device &ttys01(RS232_PORT(config, "ttys01", default_rs232_devices, nullptr)); ttys01.rxd_handler().set(m_uart1, FUNC(ins8250_uart_device::rx_w)); ttys01.dcd_handler().set(m_uart1, FUNC(ins8250_uart_device::dcd_w)); ttys01.dsr_handler().set(m_uart1, FUNC(ins8250_uart_device::dsr_w)); ttys01.ri_handler().set(m_uart1, FUNC(ins8250_uart_device::ri_w)); ttys01.cts_handler().set(m_uart1, FUNC(ins8250_uart_device::cts_w)); - rs232_port_device &ttys02(RS232_PORT(config, "ttys02", 0)); + rs232_port_device &ttys02(RS232_PORT(config, "ttys02", default_rs232_devices, nullptr)); ttys02.rxd_handler().set(m_uart2, FUNC(ins8250_uart_device::rx_w)); ttys02.dcd_handler().set(m_uart2, FUNC(ins8250_uart_device::dcd_w)); ttys02.dsr_handler().set(m_uart2, FUNC(ins8250_uart_device::dsr_w)); @@ -2621,11 +2624,13 @@ void vegas_state::init_roadburn() void vegas_state::init_nbashowt() { + m_maincpu->mips3drc_set_options(MIPS3DRC_FASTEST_OPTIONS | MIPS3DRC_STRICT_VERIFY | MIPS3DRC_EXTRA_INSTR_CHECK); } void vegas_state::init_nbanfl() { + m_maincpu->mips3drc_set_options(MIPS3DRC_FASTEST_OPTIONS | MIPS3DRC_STRICT_VERIFY | MIPS3DRC_EXTRA_INSTR_CHECK); // The first three bytes of the blitz00_nov30_1999.u27 ROM are FF's which breaks the reset vector. // These bytes are from blitz00_sep22_1999.u27 which allows the other ROM to start. // The last byte which is part of the checksum is also FF. By changing it to 0x01 the 4 byte checksum matches with the other 3 changes. @@ -2639,6 +2644,7 @@ void vegas_state::init_nbanfl() void vegas_state::init_nbagold() { + m_maincpu->mips3drc_set_options(MIPS3DRC_FASTEST_OPTIONS | MIPS3DRC_STRICT_VERIFY | MIPS3DRC_EXTRA_INSTR_CHECK); } -- cgit v1.2.3