--- hatari/src/includes/m68000.h 2019/04/01 07:14:46 1.1.1.11 +++ hatari/src/includes/m68000.h 2019/04/09 08:53:11 1.1.1.16 @@ -1,14 +1,20 @@ /* Hatari - m68000.h - This file is distributed under the GNU Public License, version 2 or at - your option any later version. Read the file gpl.txt for details. + This file is distributed under the GNU General Public License, version 2 + or at your option any later version. Read the file gpl.txt for details. */ /* 2007/11/10 [NP] Add pairing for lsr / dbcc (and all variants */ /* working on register, not on memory). */ /* 2008/01/07 [NP] Use PairingArray to store all valid pairing */ /* combinations (in m68000.c) */ +/* 2010/04/05 [NP] Rework the pairing code to take BusCyclePenalty */ +/* into account when using d8(an,ix). */ +/* 2010/05/07 [NP] Add BusCyclePenalty to LastInstrCycles to detect*/ +/* a possible pairing between add.l (a5,d1.w),d0 */ +/* and move.b 7(a5,d1.w),d5. */ + #ifndef HATARI_M68000_H #define HATARI_M68000_H @@ -17,7 +23,7 @@ #include "sysdeps.h" #include "memory.h" #include "newcpu.h" /* for regs */ -#include "int.h" +#include "cycInt.h" #include "log.h" @@ -38,7 +44,7 @@ enum { REG_A4, REG_A5, REG_A6, - REG_A7, /* ..A7 (also SP) */ + REG_A7 /* ..A7 (also SP) */ }; /* 68000 Condition code's */ @@ -93,13 +99,17 @@ enum { #define SYSINIT_OPCODE 10 /* Free op-code to initialize system (connected drives etc.) */ #define VDI_OPCODE 12 /* Free op-code to call VDI handlers AFTER Trap#2 */ +/* Illegal opcodes used for Native Features emulation: + * http://wiki.aranym.org/natfeats/proposal#special_opcodes + */ +#define NATFEAT_ID_OPCODE 0x7300 +#define NATFEAT_CALL_OPCODE 0x7301 /* Ugly hacks to adapt the main code to the different CPU cores: */ #define Regs regs.regs -#if defined(UAE_NEWCPU_H) # define M68000_GetPC() m68k_getpc() # define M68000_SetPC(val) m68k_setpc(val) @@ -118,41 +128,49 @@ static inline void M68000_SetSR(Uint16 v # define M68000_SetSpecial(flags) set_special(flags) # define M68000_UnsetSpecial(flags) unset_special(flags) -#else /* following code is for WinUAE CPU: */ -# define M68000_GetPC() m68k_getpc(®s) -# define M68000_SetPC(val) m68k_setpc(®s,val) +/* bus error mode */ +#define BUS_ERROR_WRITE 0 +#define BUS_ERROR_READ 1 -static inline Uint16 M68000_GetSR(void) -{ - MakeSR(®s); - return regs.sr; -} -static inline void M68000_SetSR(Uint16 v) -{ - regs.sr = v; - MakeFromSR(®s); -} -# define M68000_SetSpecial(flags) set_special(®s,flags) -# define M68000_UnsetSpecial(flags) unset_special(®s,flags) +/* bus access mode */ +#define BUS_MODE_CPU 0 /* bus is owned by the cpu */ +#define BUS_MODE_BLITTER 1 /* bus is owned by the blitter */ -#endif /* defined(UAE_NEWCPU_H) */ +/* Notes on IACK : + * When an interrupt happens, it's possible a similar interrupt happens again + * between the start of the exception and the IACK sequence. In that case, we + * might have to set pending bit twice and change the interrupt vector. + * From the 68000's doc, IACK start after 12 cycles. Then in an Atari STF, it takes + * 12 extra cycles to fetch the vector number. + * This means we have at max 24 cycles at the start of the exception where some + * changes can happen. The values we use were not measured on real hardware, they + * were adjusted to get the correct behaviour in some games/demos relying on this. + */ +#define CPU_IACK_CYCLES_MFP 12 /* vector sent by the MFP */ +#define CPU_IACK_CYCLES_VIDEO 20 /* auto vectored */ -#define FIND_IPL ((regs.intmask)&0x7) +/* information about current CPU instruction */ +typedef struct { + /* these are provided only by WinUAE CPU core */ + int iCacheMisses; + int iSave_instr_tail; -/* bus error mode */ -#define BUS_ERROR_WRITE 0 -#define BUS_ERROR_READ 1 + /* TODO: move other instruction specific Hatari variables here */ +} cpu_instruction_t; +extern cpu_instruction_t CpuInstruction; extern Uint32 BusErrorAddress; extern Uint32 BusErrorPC; extern bool bBusErrorReadWrite; extern int nCpuFreqShift; extern int nWaitStateCycles; +extern int BusMode; +extern bool CPU_IACK; extern int LastOpcodeFamily; extern int LastInstrCycles; @@ -173,12 +191,37 @@ static inline void M68000_AddCycles(int PendingInterruptCount -= INT_CONVERT_TO_INTERNAL(cycles, INT_CPU_CYCLE); nCyclesMainCounter += cycles; + CyclesGlobalClockCounter += cycles; } /*-----------------------------------------------------------------------*/ /** - * Add CPU cycles, take cycles pairing into account. + * Add CPU cycles, take cycles pairing into account. Pairing will make + * some specific instructions take 4 cycles less when run one after the other. + * Pairing happens when the 2 instructions are "aligned" on different bus accesses. + * Candidates are : + * - 2 instructions taking 4n+2 cycles + * - 1 instruction taking 4n+2 cycles, followed by 1 instruction using d8(an,ix) + * + * Not all the candidate instructions can pair, only the opcodes listed in PairingArray. + * On ST, when using d8(an,ix), we get an extra 2 cycle penalty for misaligned bus access. + * The only instruction that can generate BusCyclePenalty=4 is move d8(an,ix),d8(an,ix) + * and although it takes 4n cycles (24 for .b/.w or 32 for .l) it can pair with + * a previous 4n+2 instruction (but it will still have 1 misaligned bus access in the end). + * + * Verified pairing on an STF : + * - lsl.w #4,d1 + move.w 0(a4,d2.w),d1 motorola=14+14=28 stf=28 + * - lsl.w #4,d1 + move.w 0(a4,d2.w),(a4) motorola=14+18=32 stf=32 + * - lsl.w #4,d1 + move.w 0(a4,d2.w),0(a4,d2.w) motorola=14+24=38 stf=40 + * - add.l (a5,d1.w),d0 + move.b 7(a5,d1.w),d5) motorola=20+14=34 stf=36 + * + * d8(an,ix) timings without pairing (2 cycles penalty) : + * - add.l 0(a4,d2.w),a1 motorola=20 stf=24 + * - move.w 0(a4,d2.w),d1 motorola=14 stf=16 + * - move.w 0(a4,d2.w),(a4) motorola=18 stf=20 + * - move.w 0(a4,d2.w),0(a4,d2.w) motorola=24 stf=28 + * * NOTE: All times are rounded up to nearest 4 cycles. */ static inline void M68000_AddCyclesWithPairing(int cycles) @@ -187,14 +230,16 @@ static inline void M68000_AddCyclesWithP /* Check if number of cycles for current instr and for */ /* the previous one is of the form 4+2n */ /* If so, a pairing could be possible depending on the opcode */ + /* A pairing is also possible if current instr is 4n but with BusCyclePenalty > 0 */ if ( ( PairingArray[ LastOpcodeFamily ][ OpcodeFamily ] == 1 ) - && ( ( cycles & 3 ) == 2 ) && ( ( LastInstrCycles & 3 ) == 2 ) ) + && ( ( LastInstrCycles & 3 ) == 2 ) + && ( ( ( cycles & 3 ) == 2 ) || ( BusCyclePenalty > 0 ) ) ) { Pairing = 1; - HATARI_TRACE( HATARI_TRACE_CPU_PAIRING , - "pairing detected pc=%x family %s/%s cycles %d/%d\n" , - m68k_getpc(), OpcodeName[LastOpcodeFamily] , - OpcodeName[OpcodeFamily], LastInstrCycles, cycles ); + LOG_TRACE(TRACE_CPU_PAIRING, + "cpu pairing detected pc=%x family %s/%s cycles %d/%d\n", + m68k_getpc(), OpcodeName[LastOpcodeFamily], + OpcodeName[OpcodeFamily], LastInstrCycles, cycles); } /* [NP] This part is only needed to track possible pairing instructions, */ @@ -203,42 +248,56 @@ static inline void M68000_AddCyclesWithP if ( (LastOpcodeFamily!=OpcodeFamily) && ( Pairing == 0 ) && ( ( cycles & 3 ) == 2 ) && ( ( LastInstrCycles & 3 ) == 2 ) ) { - HATARI_TRACE( HATARI_TRACE_CPU_PAIRING , - "could pair pc=%x family %s/%s cycles %d/%d\n" , - m68k_getpc(), OpcodeName[LastOpcodeFamily] , - OpcodeName[OpcodeFamily], LastInstrCycles, cycles ); + LOG_TRACE(TRACE_CPU_PAIRING, + "cpu could pair pc=%x family %s/%s cycles %d/%d\n", + m68k_getpc(), OpcodeName[LastOpcodeFamily], + OpcodeName[OpcodeFamily], LastInstrCycles, cycles); } #endif /* Store current instr (not rounded) to check next time */ - LastInstrCycles = cycles; + LastInstrCycles = cycles + BusCyclePenalty; LastOpcodeFamily = OpcodeFamily; - /* If pairing is true, we need to substract 2 cycles for the */ + /* If pairing is true, we need to subtract 2 cycles for the */ /* previous instr which was rounded to 4 cycles while it wasn't */ /* needed (and we don't round the current one) */ /* -> both instr will take 4 cycles less on the ST than if ran */ /* separately. */ if (Pairing == 1) - cycles -= 2; + { + if ( ( cycles & 3 ) == 2 ) /* pairing between 4n+2 and 4n+2 instructions */ + cycles -= 2; /* if we have a pairing, we should not count the misaligned bus access */ + + else /* this is the case of move d8(an,ix),d8(an,ix) where BusCyclePenalty=4 */ + /*do nothing */; /* we gain 2 cycles for the pairing with 1st d8(an,ix) */ + /* and we have 1 remaining misaligned access for the 2nd d8(an,ix). So in the end, we keep */ + /* cycles unmodified as 4n cycles (eg lsl.w #4,d1 + move.w 0(a4,d2.w),0(a4,d2.w) takes 40 cycles) */ + } else - cycles = (cycles + 3) & ~3; /* no pairing, round current instr to 4 cycles */ + { + cycles += BusCyclePenalty; /* >0 if d8(an,ix) was used */ + cycles = (cycles + 3) & ~3; /* no pairing, round current instr to 4 cycles */ + } cycles = cycles >> nCpuFreqShift; PendingInterruptCount -= INT_CONVERT_TO_INTERNAL ( cycles , INT_CPU_CYCLE ); nCyclesMainCounter += cycles; + CyclesGlobalClockCounter += cycles; + BusCyclePenalty = 0; } -extern void M68000_InitPairing(void); +extern void M68000_Init(void); extern void M68000_Reset(bool bCold); extern void M68000_Start(void); -extern void M68000_CheckCpuLevel(void); +extern void M68000_CheckCpuSettings(void); extern void M68000_MemorySnapShot_Capture(bool bSave); extern void M68000_BusError(Uint32 addr, bool bReadWrite); extern void M68000_Exception(Uint32 ExceptionVector , int ExceptionSource); extern void M68000_WaitState(int nCycles); +extern int M68000_WaitEClock ( void ); #endif