/* Hatari - m68000.h 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 #include "cycles.h" /* for nCyclesMainCounter */ #include "sysdeps.h" #include "memory.h" #include "newcpu.h" /* for regs */ #include "cycInt.h" #include "log.h" /* 68000 Register defines */ enum { REG_D0, /* D0.. */ REG_D1, REG_D2, REG_D3, REG_D4, REG_D5, REG_D6, REG_D7, /* ..D7 */ REG_A0, /* A0.. */ REG_A1, REG_A2, REG_A3, REG_A4, REG_A5, REG_A6, REG_A7 /* ..A7 (also SP) */ }; /* 68000 Condition code's */ #define SR_AUX 0x0010 #define SR_NEG 0x0008 #define SR_ZERO 0x0004 #define SR_OVERFLOW 0x0002 #define SR_CARRY 0x0001 #define SR_CLEAR_AUX 0xffef #define SR_CLEAR_NEG 0xfff7 #define SR_CLEAR_ZERO 0xfffb #define SR_CLEAR_OVERFLOW 0xfffd #define SR_CLEAR_CARRY 0xfffe #define SR_CCODE_MASK (SR_AUX|SR_NEG|SR_ZERO|SR_OVERFLOW|SR_CARRY) #define SR_MASK 0xFFE0 #define SR_TRACEMODE 0x8000 #define SR_SUPERMODE 0x2000 #define SR_IPL 0x0700 #define SR_CLEAR_IPL 0xf8ff #define SR_CLEAR_TRACEMODE 0x7fff #define SR_CLEAR_SUPERMODE 0xdfff /* Exception numbers most commonly used in ST */ #define EXCEPTION_NR_BUSERROR 2 #define EXCEPTION_NR_ADDRERROR 3 #define EXCEPTION_NR_ILLEGALINS 4 #define EXCEPTION_NR_DIVZERO 5 #define EXCEPTION_NR_CHK 6 #define EXCEPTION_NR_TRAPV 7 #define EXCEPTION_NR_TRACE 9 #define EXCEPTION_NR_LINE_A 10 #define EXCEPTION_NR_LINE_F 11 #define EXCEPTION_NR_HBLANK 26 /* Level 2 interrupt */ #define EXCEPTION_NR_VBLANK 28 /* Level 4 interrupt */ #define EXCEPTION_NR_MFP_DSP 30 /* Level 6 interrupt */ #define EXCEPTION_NR_TRAP0 32 #define EXCEPTION_NR_TRAP1 33 #define EXCEPTION_NR_TRAP2 34 #define EXCEPTION_NR_TRAP13 45 #define EXCEPTION_NR_TRAP14 46 /* Size of 68000 instructions */ #define MAX_68000_INSTRUCTION_SIZE 10 /* Longest 68000 instruction is 10 bytes(6+4) */ #define MIN_68000_INSTRUCTION_SIZE 2 /* Smallest 68000 instruction is 2 bytes(ie NOP) */ /* Illegal Opcode used to help emulation. eg. free entries are 8 to 15 inc' */ #define GEMDOS_OPCODE 8 /* Free op-code to intercept GemDOS trap */ #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 # define M68000_GetPC() m68k_getpc() # define M68000_SetPC(val) m68k_setpc(val) # define M68000_InstrPC regs.instruction_pc # define M68000_CurrentOpcode regs.opcode static inline Uint16 M68000_GetSR(void) { MakeSR(); return regs.sr; } static inline void M68000_SetSR(Uint16 v) { regs.sr = v; MakeFromSR(); } # define M68000_SetSpecial(flags) set_special(flags) # define M68000_UnsetSpecial(flags) unset_special(flags) /* Some define's for bus error (see newcpu.c) */ /* Bus error read/write mode */ #define BUS_ERROR_WRITE 0 #define BUS_ERROR_READ 1 /* Bus error access size */ #define BUS_ERROR_SIZE_BYTE 1 #define BUS_ERROR_SIZE_WORD 2 #define BUS_ERROR_SIZE_LONG 4 /* Bus error access type */ #define BUS_ERROR_ACCESS_INSTR 0 #define BUS_ERROR_ACCESS_DATA 1 /* 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 */ /* [NP] 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 starts after 10 cycles (12 cycles on STF) and is * supposed to take 4 cycles if the interrupt takes a total of 44 cycles. * * On Atari STF, interrupts take 56 cycles instead of 44, which means it takes * 12 extra cycles to fetch the vector number and to handle non-aligned memory accesses. * From WinUAE's CE mode, we have 2 non-aligned memory accesses to wait for (ie 2+2 cycles), * which leaves a total of 12 cycles to fetch the vector. * This means we have at max 12+12=24 cycles after the start of the exception where some * changes can happen (maybe it's a little less, depending on when the interrupt * vector is written on the bus). * * The values we use were not measured on real ST hardware, they were adjusted * to get the correct behaviour in some games/demos relying on this ; since timings * are rounded to 4 on ST, it's possible the interrupt takes 54 cycles and not 56. * * WinUAE cycles (measured on real A500 HW) : * * 6 idle cycles * 2(*) ST bus access penalty * 4 write PC low word * 12(*) read exception number * 4 idle cycles * 4 write SR * 4 write PC high word * 4 read exception address high word * 4 read exception address low word * 4 prefetch * 2 idle cycles * 2(*) ST bus access penalty * 4 prefetch * TOTAL = 56 * * (*) ST specific timings */ #define CPU_IACK_CYCLES_START 12 /* number of cycles before starting the IACK */ #define CPU_IACK_CYCLES_MFP 12 /* vector sent by the MFP */ #define CPU_IACK_CYCLES_VIDEO 12 /* auto vectored for HBL/VBL */ /* Informations about current CPU instruction */ typedef struct { /* These are provided only by WinUAE CPU core */ int I_Cache_miss; /* Instruction cache for 68020/30/40/60 */ int I_Cache_hit; int D_Cache_miss; /* Data cache for 68030/40/60 */ int D_Cache_hit; /* TODO: move other instruction specific Hatari variables here */ } cpu_instruction_t; extern cpu_instruction_t CpuInstruction; extern Uint32 BusErrorAddress; extern bool bBusErrorReadWrite; extern int nCpuFreqShift; extern int nWaitStateCycles; extern int BusMode; extern bool CPU_IACK; extern int LastOpcodeFamily; extern int LastInstrCycles; extern int Pairing; extern char PairingArray[ MAX_OPCODE_FAMILY ][ MAX_OPCODE_FAMILY ]; extern const char *OpcodeName[]; /*-----------------------------------------------------------------------*/ /** * Add CPU cycles. * NOTE: All times are rounded up to nearest 4 cycles. */ static inline void M68000_AddCycles(int cycles) { cycles = (cycles + 3) & ~3; cycles = cycles >> nCpuFreqShift; PendingInterruptCount -= INT_CONVERT_TO_INTERNAL(cycles, INT_CPU_CYCLE); nCyclesMainCounter += cycles; CyclesGlobalClockCounter += cycles; } /*-----------------------------------------------------------------------*/ /** * 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) { Pairing = 0; /* 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 ) && ( ( LastInstrCycles & 3 ) == 2 ) && ( ( ( cycles & 3 ) == 2 ) || ( BusCyclePenalty > 0 ) ) ) { Pairing = 1; 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, */ /* we can keep it disabled most of the time */ #if 0 if ( (LastOpcodeFamily!=OpcodeFamily) && ( Pairing == 0 ) && ( ( cycles & 3 ) == 2 ) && ( ( LastInstrCycles & 3 ) == 2 ) ) { 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 + BusCyclePenalty; LastOpcodeFamily = OpcodeFamily; /* 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) { 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 += 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_Init(void); extern void M68000_Reset(bool bCold); extern void M68000_Start(void); extern void M68000_CheckCpuSettings(void); extern void M68000_MemorySnapShot_Capture(bool bSave); extern void M68000_BusError ( Uint32 addr , int ReadWrite , int Size , int AccessType ); extern void M68000_Exception(Uint32 ExceptionNr , int ExceptionSource); extern void M68000_Update_intlev ( void ); extern void M68000_WaitState(int nCycles); extern int M68000_WaitEClock ( void ); extern void M68000_Flush_Instr_Cache ( uaecptr addr , int size ); extern void M68000_Flush_Data_Cache ( uaecptr addr , int size ); extern void M68000_Flush_All_Caches ( uaecptr addr , int size ); #endif