- --
 
      Viewing Issue Advanced Details
    
  | ID | Category [?] | Severity [?] | Reproducibility | Date Submitted | Last Update | 
|---|---|---|---|---|---|
| 07558 | Crash/Freeze | Critical (emulation) | Always | Feb 2, 2020, 15:10 | Feb 23, 2022, 07:42 | 
| Tester | kmg | View Status | Public | Platform | MAME (Self-compiled) | 
| Assigned To | Resolution | Open | OS | MacOS X | |
| Status [?] | Confirmed | Driver | |||
| Version | 0.217 | Fixed in Version | Build | 64-bit | |
| Fixed in Git Commit | Github Pull Request # | ||||
| Summary | 
           | 
      ||||
| Description | 
          Here's a list of related Enix games that display similar behavior. I think most of these were working recently except actrais2 and maybe starocn. actrais2 breaks sooner at least. I'll list both for completeness. actraisr and clones: garbled/no sound, freezes on black screen when choosing "fight monsters" to enter level. The one exception is actraisrj still works. actrais2 and clones: freezes on black screen after Enix logo in Jpn/USA versions. Euro version plays demo then freezes. illtime and clones: no sound, freezes on black screen after pressing start at title. Spa version freezes one screen later after selecting save file. Jpn version makes it past this but has no/garbled sound and will freeze upon entering or leaving the portal (save room) one screen north of starting room. robotrek/slapstic: freezes on black screen after Enix logo. soulblzr and clones: Jpn/Euro versions have garbled sound, others no sound. Jpn/USA freeze on black screen after pressing start at title. PAL versions freeze when you return to 1st hub room after getting sword in 2nd room. starocn: freezes on black screen after company logos. terranig and clones: no sound, freezes on black screen after second scene (planet surface) of demo story. (sometimes?) freezes when starting new game after initial "Chapter 1" screen.  | 
      ||||
| Steps To Reproduce | |||||
| Additional Information | |||||
| Github Commit | |||||
| Flags | |||||
| Regression Version | 0.214 | ||||
| Affected Sets / Systems | snes, snespal | ||||
| 
               Attached Files 
             | 
            diff --git a/src/devices/cpu/spc700/spc700.cpp b/src/devices/cpu/spc700/spc700.cpp
index ec6473d19da..8c534818a88 100644
--- a/src/devices/cpu/spc700/spc700.cpp
+++ b/src/devices/cpu/spc700/spc700.cpp
@@ -1226,6 +1226,8 @@ void spc700_device::device_start()
 	save_item(NAME(m_temp3));
 	save_item(NAME(m_spc_int16));
 	save_item(NAME(m_spc_int32));
+	save_item(NAME(m_cycle));
+	save_item(NAME(m_last_ir));
 
 	// Register state for debugger
 	state_add( SPC700_PC, "PC", m_pc            ).formatstr("%04X");
@@ -1306,6 +1308,9 @@ void spc700_device::device_reset()
 	FLAG_I  = IFLAG_CLEAR;
 	FLAG_C  = CFLAG_CLEAR;
 	JUMP(read_16_VEC(VECTOR_RST));
+
+	m_cycle = 0;
+	m_last_ir = -1;
 }
 
 
@@ -1346,6 +1351,171 @@ std::unique_ptr<util::disasm_interface> spc700_device::create_disassembler()
 
 //int dump_flag = 0;
 
+bool spc700_device::execute_next_cycle(int cycles)
+{
+	CLK(cycles);
+	++m_cycle;
+
+	return (CLOCKS > 0);
+}
+
+void spc700_device::execute_last_cycle(int cycles)
+{
+	CLK(cycles);
+	m_cycle = 0;
+	m_last_ir = -1;
+}
+
+void spc700_device::continue_last_instruction()
+{
+	switch(m_last_ir)
+	{
+		case 0x8f:
+		{
+			if (m_cycle == 1)
+			{
+				m_source = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 2)
+			{
+				m_destination = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 3)
+			{
+				write_8_direct(m_destination, m_source);
+				execute_last_cycle(2);
+			}
+			break;
+		}
+
+		case 0xc4:
+		{
+			if (m_cycle == 1)
+			{
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 2)
+			{
+				write_8_direct(m_temp1, m_a);
+				execute_last_cycle(2);
+			}
+			break;
+		}
+
+		case 0xc5:
+		{
+			if (m_cycle == 1)
+			{
+				m_pc += 2;
+				m_temp1 = read_16_immediate(m_pc-2);
+				if (!execute_next_cycle(2))
+					break;
+			}
+			if (m_cycle == 2)
+			{
+				write_8_normal(m_temp1, m_a);
+				execute_last_cycle(2);
+			}
+			break;
+		}
+
+		case 0xcb:
+		{
+			if (m_cycle == 1)
+			{
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 2)
+			{
+				write_8_direct(m_temp1, m_y);
+				execute_last_cycle(2);
+			}
+			break;
+		}
+
+
+		case 0xd8:
+		{
+			if (m_cycle == 1)
+			{
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 2)
+			{
+				write_8_direct(m_temp1, m_x);
+				execute_last_cycle(2);
+			}
+			break;
+		}
+
+		case 0xfa:
+		{
+			if (m_cycle == 1)
+			{
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+
+			if (m_cycle == 2)
+			{
+				m_source = read_8_direct(m_temp1);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 3)
+			{
+				m_destination = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 4)
+			{
+				write_8_direct(m_destination, m_source);
+				execute_last_cycle(1);
+
+			}
+			break;
+		}
+
+		case 0xfe:
+		{
+			if (m_cycle == 1)
+			{
+				m_y = ((m_y - 1)&0xff);
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 2)
+			{
+				m_destination = m_pc++;
+				if (!execute_next_cycle(1))
+					break;
+			}
+			if (m_cycle == 3)
+			{
+				if(m_y != 0)
+				{
+					CLK(1);
+					BRANCH(read_8_immediate(m_destination));
+				}
+				execute_last_cycle(1);
+			}
+			break;
+		}
+	}
+}
+
 /* Execute instructions for <clocks> cycles */
 void spc700_device::execute_run()
 {
@@ -1354,6 +1524,10 @@ void spc700_device::execute_run()
 		CLOCKS = 0;
 		return;
 	}
+
+	if (m_last_ir > -1)
+		continue_last_instruction();
+
 	while(CLOCKS > 0)
 	{
 		REG_PPC = REG_PC;
@@ -1539,7 +1713,27 @@ void spc700_device::execute_run()
 			case 0x8c: OP_DECM  ( 5, ABS          ); break; /* DEC abs       */
 			case 0x8d: OP_MOVMR ( 2, IMM, REG_Y   ); break; /* MOV Y, imm    */
 			case 0x8e: OP_PLP   ( 4               ); break; /* POP PSW       */
-			case 0x8f: OP_MOVMM ( 5, IMM, DP      ); break; /* MOV dp, imm   */
+			//case 0x8f: OP_MOVMM ( 5, IMM, DP      ); break; /* MOV dp, imm   */
+
+			case 0x8f:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_source = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				m_destination = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				write_8_direct(m_destination, m_source);
+				execute_last_cycle(2);
+
+				break;
+			}
 
 			case 0x90: OP_BCC   ( 2, COND_CC()    ); break; /* BCC           */
 			case 0x91: OP_TCALL ( 8, 9            ); break; /* TCALL 9       */
@@ -1605,15 +1799,67 @@ void spc700_device::execute_run()
 			case 0xc1: OP_TCALL ( 8, 12           ); break; /* TCALL 12      */
 			case 0xc2: OP_SET   ( 4, BIT_6        ); break; /* SET 6         */
 			case 0xc3: OP_BBS   ( 5, BIT_6        ); break; /* BBS 6         */
-			case 0xc4: OP_MOVRM ( 4, REG_A, DP    ); break; /* MOV dp, A     */
-			case 0xc5: OP_MOVRM ( 5, REG_A, ABS   ); break; /* MOV abs, A    */
+
+			//case 0xc4: OP_MOVRM ( 4, REG_A, DP    ); break; /* MOV dp, A     */
+
+			case 0xc4:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				write_8_direct(m_temp1, m_a);
+				execute_last_cycle(2);
+
+				break;
+			}
+
+			//case 0xc5: OP_MOVRM ( 5, REG_A, ABS   ); break; /* MOV abs, A    */
+
+			case 0xc5:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_pc += 2;
+				m_temp1 = read_16_immediate(m_pc-2);
+				if (!execute_next_cycle(2))
+					return;
+
+				write_8_normal(m_temp1, m_a);
+				execute_last_cycle(2);
+
+				break;
+			}
+
 			case 0xc6: OP_MOVRM ( 4, REG_A, XI    ); break; /* MOV xi, A     */
 			case 0xc7: OP_MOVRM ( 7, REG_A, DXI   ); break; /* MOV dxi, A    */
 
 			case 0xc8: OP_CMPR  ( 2, REG_X, IMM   ); break; /* CMP X, imm    */
 			case 0xc9: OP_MOVRM ( 5, REG_X, ABS   ); break; /* MOV abs, X    */
 			case 0xca: OP_MOV1M ( 6               ); break; /* MOV1 C->bit   */
-			case 0xcb: OP_MOVRM ( 4, REG_Y, DP    ); break; /* MOV dp, Y     */
+			//case 0xcb: OP_MOVRM ( 4, REG_Y, DP    ); break; /* MOV dp, Y     */
+
+			case 0xcb:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				write_8_direct(m_temp1, m_y);
+				execute_last_cycle(2);
+
+				break;
+			}
 
 			case 0xcc: OP_MOVRM ( 5, REG_Y, ABS   ); break; /* MOV abs, Y    */
 			case 0xcd: OP_MOVMR ( 2, IMM, REG_X   ); break; /* MOV X, imm    */
@@ -1630,7 +1876,24 @@ void spc700_device::execute_run()
 			case 0xd6: OP_MOVRM ( 6, REG_A, ABY   ); break; /* MOV aby, A    */
 			case 0xd7: OP_MOVRM ( 7, REG_A, DIY   ); break; /* MOV diy, A    */
 
-			case 0xd8: OP_MOVRM ( 4, REG_X, DP    ); break; /* MOV dp, X     */
+			//case 0xd8: OP_MOVRM ( 4, REG_X, DP    ); break; /* MOV dp, X     */
+
+			case 0xd8:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				write_8_direct(m_temp1, m_x);
+				execute_last_cycle(2);
+
+				break;
+			}
+
 			case 0xd9: OP_MOVRM ( 5, REG_X, DPY   ); break; /* MOV dpy, X    */
 			case 0xda: OP_MOVWRM( 5               ); break; /* MOVW dp, YA   */
 			case 0xdb: OP_MOVRM ( 5, REG_Y, DPX   ); break; /* MOV dpx, Y    */
@@ -1672,11 +1935,61 @@ void spc700_device::execute_run()
 
 			case 0xf8: OP_MOVMR ( 3, DP, REG_X    ); break; /* MOV X, dp     */
 			case 0xf9: OP_MOVMR ( 4, DPY, REG_X   ); break; /* MOV X, dpy    */
-			case 0xfa: OP_MOVMM ( 5, DP, DP       ); break; /* MOV dp, dp    */
+			//case 0xfa: OP_MOVMM ( 5, DP, DP       ); break; /* MOV dp, dp    */
+
+			case 0xfa:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_temp1 = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				m_source = read_8_direct(m_temp1);
+				if (!execute_next_cycle(1))
+					return;
+
+				m_destination = read_8_immediate(m_pc++);
+				if (!execute_next_cycle(1))
+					return;
+
+				write_8_direct(m_destination, m_source);
+				execute_last_cycle(1);
+
+				break;
+			}
+
 			case 0xfb: OP_MOVMR ( 4, DPX, REG_Y   ); break; /* MOV Y, DPX    */
 			case 0xfc: OP_INCR  ( 2, REG_Y        ); break; /* INC Y         */
 			case 0xfd: OP_MOVRR ( 2, REG_A, REG_Y ); break; /* MOV Y, A      */
-			case 0xfe: OP_DBNZR ( 4               ); break; /* DBNZ Y        */
+			//case 0xfe: OP_DBNZR ( 4               ); break; /* DBNZ Y        */
+
+			case 0xfe:
+			{
+				m_last_ir = REG_IR;
+				if (!execute_next_cycle(1))
+					return;
+
+				m_y = ((m_y - 1)&0xff);
+				if (!execute_next_cycle(1))
+					return;
+
+				m_destination = m_pc++;
+				if (!execute_next_cycle(1))
+					return;
+
+				if(m_y != 0)
+				{
+					CLK(1);
+					BRANCH(read_8_immediate(m_destination));
+				}
+				execute_last_cycle(1);
+
+				break;
+			}
+
 			case 0xff: OP_STOP  ( 1               ); break; /* STOP          */
 		}
 	}
diff --git a/src/devices/cpu/spc700/spc700.h b/src/devices/cpu/spc700/spc700.h
index 33e3190ac10..7317c2006c4 100644
--- a/src/devices/cpu/spc700/spc700.h
+++ b/src/devices/cpu/spc700/spc700.h
@@ -21,8 +21,8 @@ protected:
 	virtual void device_reset() override;
 
 	// device_execute_interface overrides
-	virtual uint32_t execute_min_cycles() const noexcept override { return 2; }
-	virtual uint32_t execute_max_cycles() const noexcept override { return 8; }
+	virtual uint32_t execute_min_cycles() const noexcept override { return 4; }
+	virtual uint32_t execute_max_cycles() const noexcept override { return 24; }
 	virtual uint32_t execute_input_lines() const noexcept override { return 1; }
 	virtual bool execute_input_edge_triggered(int inputnum) const noexcept override { return inputnum == INPUT_LINE_NMI; }
 	virtual void execute_run() override;
@@ -70,6 +70,9 @@ private:
 	short m_spc_int16;
 	int m_spc_int32;
 
+	uint8_t m_cycle;
+	int16_t m_last_ir;
+
 	uint32_t m_debugger_temp;
 
 	inline uint32_t read_8_normal(uint32_t address);
@@ -107,6 +110,10 @@ private:
 	inline void CHECK_IRQ();
 	inline void SET_FLAG_I(uint32_t value);
 	void SERVICE_IRQ();
+
+	bool execute_next_cycle(int cycles);
+	void execute_last_cycle(int cycles);
+	void continue_last_instruction();
 };
 
 
 | ||||
      Relationships
		
    
  | There are no relationship linked to this issue. | 
      Notes
      
    
  3
    | 
             No.17384 
            Tafoid             Administrator 
            
            Feb 2, 2020, 15:20 
                         | 
          
            All part of my local regression list for the driver, but never logged here. If you want working games, you need to roll back to 0.213  | 
        
|---|---|
| 
             No.19225 
            thankyoumame             Tester 
            
            Sep 4, 2021, 20:43 
                         | 
          Can you please mark these as "not supported" until this problem is fixed? | 
| 
             No.19780 
            AmatCoder             Tester 
            
            Feb 11, 2022, 08:19 
                         | 
          
            I have uploaded a patch as an example of how to fix this issue just in case someone wants to test it. It implements a minimal cycle acurate (only 7 opcodes) for spc700 cpu but that is enough to fix all games reported here.  |