--- hatari/src/includes/m68000.h 2019/04/09 08:55:41 1.1.1.17 +++ hatari/src/includes/m68000.h 2019/04/09 08:56:54 1.1.1.18 @@ -157,44 +157,60 @@ static inline void M68000_SetSR(Uint16 v * 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. + * From the 68000's doc, IACK starts after 10 cycles (12 cycles on STF due to 2 cycle + * bus penalty) 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 + * + * As seen wth a custom program on STF that measures HBL's jitter, we get the same results with Hatari + * in CE mode if we use 10 cycles to fetch the vector (step 3), which will also add 2 cycle penalty (step 4b) + * This means we have at max 12+10=22 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 + * Additionally, auto vectored interrupts (HBL and VBL) require to be in sync with E-clock, + * which can add 0 to 8 cycles (step 3a). In that case we have between 22+0 and 22+8 cycles + * to get another interrupt before vector is written on the bus. + * + * The values we use were not entirely measured on real ST hardware, they were guessed/adjusted + * to get the correct behaviour in some games/demos relying on this. + * These values are when running in CE mode (2 cycle precision) ; when CPU runs in prefetch + * mode, values need to be rounded to 4). + * + * Interrupt steps + WinUAE cycles (measured on real A500 HW) + ST specific values : + * + * 1 6 idle cycles + * 1b 2(*) ST bus access penalty (if necessary) + * 2 4 write PC low word + * 3a 0-8(*) wait for E-clock for auto vectored interrupt + * 3 10(*) read exception number + * 4 4 idle cycles + * 4b 2(*) ST bus access penalty + * 5 4 write SR + * 6 4 write PC high word + * 7 4 read exception address high word + * 8 4 read exception address low word + * 9 4 prefetch + * 10 2 idle cycles + * 10b 2(*) ST bus access penalty + * 11 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 */ +/* Values for IACK sequence when running in cycle exact mode */ +#define CPU_IACK_CYCLES_MFP_CE 12 /* vector sent by the MFP (TODO value not measured on real STF) */ +#define CPU_IACK_CYCLES_VIDEO_CE 10 /* auto vectored for HBL/VBL (value measured on real STF) */ + +/* Values for IACK sequence when running in normal/prefetch mode or when using old UAE CPU */ +#define CPU_IACK_CYCLES_START 12 /* number of cycles before starting the IACK when not using CE mode */ + /* (this should be a multiple of 4, else it will be rounded by M68000_AddCycles) */ +#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 { @@ -212,7 +228,7 @@ extern cpu_instruction_t CpuInstruction; extern Uint32 BusErrorAddress; extern bool bBusErrorReadWrite; extern int nCpuFreqShift; -extern int nWaitStateCycles; +extern int WaitStateCycles; extern int BusMode; extern bool CPU_IACK; @@ -231,9 +247,14 @@ extern const char *OpcodeName[]; static inline void M68000_AddCycles(int cycles) { cycles = (cycles + 3) & ~3; +#ifdef OLD_CPU_SHIFT cycles = cycles >> nCpuFreqShift; - PendingInterruptCount -= INT_CONVERT_TO_INTERNAL(cycles, INT_CPU_CYCLE); + PendingInterruptCount -= INT_CONVERT_TO_INTERNAL ( cycles , INT_CPU_CYCLE ); +#else +// PendingInterruptCount -= INT_CONVERT_TO_INTERNAL_NO_FREQSHIFT ( cycles , INT_CPU_CYCLE ); + PendingInterruptCount -= INT_CONVERT_TO_INTERNAL ( cycles , INT_CPU_CYCLE ); +#endif nCyclesMainCounter += cycles; CyclesGlobalClockCounter += cycles; } @@ -324,9 +345,14 @@ static inline void M68000_AddCyclesWithP cycles = (cycles + 3) & ~3; /* no pairing, round current instr to 4 cycles */ } +#ifdef OLD_CPU_SHIFT cycles = cycles >> nCpuFreqShift; PendingInterruptCount -= INT_CONVERT_TO_INTERNAL ( cycles , INT_CPU_CYCLE ); +#else +// PendingInterruptCount -= INT_CONVERT_TO_INTERNAL_NO_FREQSHIFT ( cycles , INT_CPU_CYCLE ); + PendingInterruptCount -= INT_CONVERT_TO_INTERNAL ( cycles , INT_CPU_CYCLE ); +#endif nCyclesMainCounter += cycles; CyclesGlobalClockCounter += cycles; @@ -334,6 +360,33 @@ static inline void M68000_AddCyclesWithP } +/*-----------------------------------------------------------------------*/ +/** + * Add CPU cycles when using WinUAE CPU 'cycle exact' mode. + * In this mode, we should not round cycles to the next nearest 4 cycles + * because all memory accesses will already be aligned to 4 cycles when + * using CE mode. + * The CE mode will also give the correct 'instruction pairing' for all + * opcodes/addressing mode, without requiring tables/heuristics (in the + * same way that it's done in real hardware) + */ +static inline void M68000_AddCycles_CE(int cycles) +{ +#ifdef OLD_CPU_SHIFT + cycles = cycles >> nCpuFreqShift; + + PendingInterruptCount -= INT_CONVERT_TO_INTERNAL(cycles, INT_CPU_CYCLE); +#else +// PendingInterruptCount -= INT_CONVERT_TO_INTERNAL_NO_FREQSHIFT ( cycles , INT_CPU_CYCLE ); + PendingInterruptCount -= INT_CONVERT_TO_INTERNAL ( cycles , INT_CPU_CYCLE ); +#endif + + nCyclesMainCounter += cycles; + CyclesGlobalClockCounter += cycles; +} + + + extern void M68000_Init(void); extern void M68000_Reset(bool bCold); extern void M68000_Start(void); @@ -342,10 +395,14 @@ extern void M68000_MemorySnapShot_Captur 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 void M68000_WaitState(int WaitCycles); extern int M68000_WaitEClock ( void ); +extern void M68000_SyncCpuBus_OnReadAccess ( void ); +extern void M68000_SyncCpuBus_OnWriteAccess ( 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 ); +extern int DMA_MaskAddressHigh ( void ); +extern void M68000_ChangeCpuFreq ( void ); #endif