mirror of
https://github.com/Wiimpathy/HatariWii.git
synced 2024-06-02 16:48:43 +02:00
352 lines
12 KiB
C
352 lines
12 KiB
C
/*
|
|
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
|