fixed bus error handling for real this time (save registers before every instruction and push the saved registers if a bus error occurs, since the instruction may have changed registers before the bus error, and also stop the instruction immediately with longjmp so it won't change memory after the bus error)

Wed, 16 Apr 2014 02:20:43 -0600

author
andrew@localhost
date
Wed, 16 Apr 2014 02:20:43 -0600
changeset 147
ad888290cdff
parent 146
fb6a37a266da
child 148
b0eac383e342

fixed bus error handling for real this time (save registers before every instruction and push the saved registers if a bus error occurs, since the instruction may have changed registers before the bus error, and also stop the instruction immediately with longjmp so it won't change memory after the bus error)

This isn't actually what a real 68k does, but it is a good enough approximation. A real 68k will jump back into the middle of the faulted instruction and resume it from the memory access that faulted as opposed to restarting from the beginning like this CPU emulation does. It would be a lot harder to do that with the way this CPU library is designed. Newer versions of MESS basically do the same thing (they use a newer version of this library).

src/musashi/m68kcpu.c file | annotate | diff | revisions
src/musashi/m68kcpu.h file | annotate | diff | revisions
     1.1 --- a/src/musashi/m68kcpu.c	Wed Apr 16 02:07:24 2014 -0600
     1.2 +++ b/src/musashi/m68kcpu.c	Wed Apr 16 02:20:43 2014 -0600
     1.3 @@ -66,6 +66,9 @@
     1.4  jmp_buf m68ki_address_error_trap;
     1.5  #endif /* M68K_EMULATE_ADDRESS_ERROR */
     1.6  
     1.7 +jmp_buf m68ki_bus_error_jmp_buf;
     1.8 +jmp_buf m68ki_bus_error_return_jmp_buf;
     1.9 +
    1.10  /* Used by shift & rotate instructions */
    1.11  uint8 m68ki_shift_8_table[65] =
    1.12  {
    1.13 @@ -638,9 +641,12 @@
    1.14  		/* Return point if we had an address error */
    1.15  		m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
    1.16  
    1.17 +		m68ki_check_bus_error_trap();
    1.18 +
    1.19  		/* Main loop.  Keep going until we run out of clock cycles */
    1.20  		do
    1.21  		{
    1.22 +			int i;
    1.23  			/* Set tracing accodring to T1. (T0 is done inside instruction) */
    1.24  			m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
    1.25  
    1.26 @@ -653,20 +659,16 @@
    1.27  			/* Record previous program counter */
    1.28  			REG_PPC = REG_PC;
    1.29  
    1.30 +			for (i = 15; i >= 0; i--){
    1.31 +				REG_DA_SAVE[i] = REG_DA[i];
    1.32 +			}
    1.33  			/* Read an instruction and call its handler */
    1.34  			REG_IR = m68ki_read_imm_16();
    1.35 -			if (!BUS_ERROR_OCCURRED){
    1.36 -				m68ki_instruction_jump_table[REG_IR]();
    1.37 -			}
    1.38 +			m68ki_instruction_jump_table[REG_IR]();
    1.39  			USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
    1.40 -
    1.41  			/* Trace m68k_exception, if necessary */
    1.42  			m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
    1.43 -
    1.44 -			if (BUS_ERROR_OCCURRED){
    1.45 -				m68ki_jump_bus_error_vector();
    1.46 -				BUS_ERROR_OCCURRED = 0;
    1.47 -			}
    1.48 +	
    1.49  		} while(GET_CYCLES() > 0);
    1.50  
    1.51  		/* set previous PC to current PC for the next entry into the loop */
     2.1 --- a/src/musashi/m68kcpu.h	Wed Apr 16 02:07:24 2014 -0600
     2.2 +++ b/src/musashi/m68kcpu.h	Wed Apr 16 02:20:43 2014 -0600
     2.3 @@ -28,10 +28,9 @@
     2.4  
     2.5  #include "m68k.h"
     2.6  #include <limits.h>
     2.7 +#include <string.h>
     2.8  
     2.9 -#if M68K_EMULATE_ADDRESS_ERROR
    2.10  #include <setjmp.h>
    2.11 -#endif /* M68K_EMULATE_ADDRESS_ERROR */
    2.12  
    2.13  /* ======================================================================== */
    2.14  /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
    2.15 @@ -287,6 +286,7 @@
    2.16  #define CPU_TYPE         m68ki_cpu.cpu_type
    2.17  
    2.18  #define REG_DA           m68ki_cpu.dar /* easy access to data and address regs */
    2.19 +#define REG_DA_SAVE           m68ki_cpu.dar_save
    2.20  #define REG_D            m68ki_cpu.dar
    2.21  #define REG_A            (m68ki_cpu.dar+8)
    2.22  #define REG_PPC 		 m68ki_cpu.ppc
    2.23 @@ -751,6 +751,8 @@
    2.24  {
    2.25  	uint cpu_type;     /* CPU Type: 68000, 68010, 68EC020, or 68020 */
    2.26  	uint dar[16];      /* Data and Address Registers */
    2.27 +	uint dar_save[16];  /* Saved Data and Address Registers (pushed onto the
    2.28 +						   stack when a bus error occurs)*/
    2.29  	uint ppc;		   /* Previous program counter */
    2.30  	uint pc;           /* Program Counter */
    2.31  	uint sp[7];        /* User, Interrupt, and Master Stack Pointers */
    2.32 @@ -1689,20 +1691,31 @@
    2.33  	USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION[REG_IR]);
    2.34  }
    2.35  
    2.36 +extern jmp_buf m68ki_bus_error_jmp_buf;
    2.37 +extern jmp_buf m68ki_bus_error_return_jmp_buf;
    2.38 +
    2.39 +#define m68ki_check_bus_error_trap() setjmp(m68ki_bus_error_jmp_buf)
    2.40 +
    2.41  /* Exception for bus error */
    2.42  INLINE void m68ki_exception_bus_error(void)
    2.43  {
    2.44 +	int i;
    2.45  	BUS_ERROR_OCCURRED = 1;
    2.46  	/* Use up some clock cycles and undo the instruction's cycles */
    2.47  	USE_CYCLES(CYC_EXCEPTION[EXCEPTION_BUS_ERROR] - CYC_INSTRUCTION[REG_IR]);
    2.48 +
    2.49 +	for (i = 15; i >= 0; i--){
    2.50 +		REG_DA[i] = REG_DA_SAVE[i];
    2.51 +	}
    2.52 +
    2.53 +	uint sr = m68ki_init_exception();
    2.54 +	m68ki_stack_frame_1000(REG_PPC, sr, EXCEPTION_BUS_ERROR);
    2.55 +
    2.56 +	m68ki_jump_vector(EXCEPTION_BUS_ERROR);
    2.57 +	longjmp(m68ki_bus_error_jmp_buf, 1);
    2.58  }
    2.59  
    2.60 -INLINE void m68ki_jump_bus_error_vector(void)
    2.61 -{
    2.62 -	uint sr = m68ki_init_exception();
    2.63 -	m68ki_stack_frame_1000(REG_PPC, sr, EXCEPTION_BUS_ERROR);
    2.64 -	m68ki_jump_vector(EXCEPTION_BUS_ERROR);
    2.65 -}
    2.66 +extern int cpu_log_enabled;
    2.67  
    2.68  /* Exception for A-Line instructions */
    2.69  INLINE void m68ki_exception_1010(void)