334 lines
10 KiB
C++
334 lines
10 KiB
C++
////////////////////////////////////////////////////////////////
|
|
// Defines for the V810 CPU
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
typedef int32 v810_timestamp_t;
|
|
|
|
#define V810_FAST_MAP_SHIFT 16
|
|
#define V810_FAST_MAP_PSIZE (1 << V810_FAST_MAP_SHIFT)
|
|
#define V810_FAST_MAP_TRAMPOLINE_SIZE 1024
|
|
|
|
// Exception codes
|
|
enum
|
|
{
|
|
ECODE_TRAP_BASE = 0xFFA0,
|
|
ECODE_INVALID_OP = 0xFF90,
|
|
ECODE_ZERO_DIV = 0xFF80, // Integer divide by 0
|
|
ECODE_FIV = 0xFF70, // Floating point invalid operation
|
|
ECODE_FZD = 0xFF68, // Floating point zero division
|
|
ECODE_FOV = 0xFF64, // Floating point overflow
|
|
//#define ECODE_FUD 0xFF62 // Floating point underflow(unused on V810)
|
|
//#define ECODE_FPR 0xFF61 // Floating point precision degradation(unused on V810)
|
|
ECODE_FRO = 0xFF60 // Floating point reserved operand
|
|
};
|
|
|
|
enum
|
|
{
|
|
INVALID_OP_HANDLER_ADDR = 0xFFFFFF90, // Invalid opcode/instruction code!
|
|
ZERO_DIV_HANDLER_ADDR = 0xFFFFFF80, // Integer divide by 0 exception
|
|
FPU_HANDLER_ADDR = 0xFFFFFF60, // FPU exception
|
|
TRAP_HANDLER_BASE = 0xFFFFFFA0 // TRAP instruction
|
|
};
|
|
|
|
//System Register Defines (these are the only valid system registers!)
|
|
#define EIPC 0 //Exeption/Interupt PC
|
|
#define EIPSW 1 //Exeption/Interupt PSW
|
|
|
|
#define FEPC 2 //Fatal Error PC
|
|
#define FEPSW 3 //Fatal Error PSW
|
|
|
|
#define ECR 4 //Exception Cause Register
|
|
#define PSW 5 //Program Status Word
|
|
#define PIR 6 //Processor ID Register
|
|
#define TKCW 7 //Task Controll Word
|
|
#define CHCW 24 //Cashe Controll Word
|
|
#define ADDTRE 25 //ADDTRE
|
|
|
|
//PSW Specifics
|
|
#define PSW_IA 0xF0000 // All Interupt bits...
|
|
#define PSW_I3 0x80000
|
|
#define PSW_I2 0x40000
|
|
#define PSW_I1 0x20000
|
|
#define PSW_I0 0x10000
|
|
|
|
#define PSW_NP 0x08000
|
|
#define PSW_EP 0x04000
|
|
|
|
#define PSW_AE 0x02000
|
|
|
|
#define PSW_ID 0x01000
|
|
|
|
#define PSW_FRO 0x00200 // Floating point reserved operand(set on denormal, NaN, or indefinite)
|
|
#define PSW_FIV 0x00100 // Floating point invalid operation(set when trying to convert a number too large to an (un)signed integer)
|
|
|
|
#define PSW_FZD 0x00080 // Floating point divide by zero
|
|
#define PSW_FOV 0x00040 // Floating point overflow
|
|
#define PSW_FUD 0x00020 // Floating point underflow
|
|
#define PSW_FPR 0x00010 // Floating point precision degradation
|
|
|
|
#define PSW_CY 0x00008
|
|
#define PSW_OV 0x00004
|
|
#define PSW_S 0x00002
|
|
#define PSW_Z 0x00001
|
|
|
|
//condition codes
|
|
#define COND_V 0
|
|
#define COND_C 1
|
|
#define COND_Z 2
|
|
#define COND_NH 3
|
|
#define COND_S 4
|
|
#define COND_T 5
|
|
#define COND_LT 6
|
|
#define COND_LE 7
|
|
#define COND_NV 8
|
|
#define COND_NC 9
|
|
#define COND_NZ 10
|
|
#define COND_H 11
|
|
#define COND_NS 12
|
|
#define COND_F 13
|
|
#define COND_GE 14
|
|
#define COND_GT 15
|
|
|
|
#define TESTCOND_V (S_REG[PSW] & PSW_OV)
|
|
|
|
#define TESTCOND_L (S_REG[PSW] & PSW_CY)
|
|
#define TESTCOND_C TESTCOND_L
|
|
|
|
#define TESTCOND_E (S_REG[PSW] & PSW_Z)
|
|
#define TESTCOND_Z TESTCOND_E
|
|
|
|
#define TESTCOND_NH ((S_REG[PSW] & PSW_Z) || (S_REG[PSW] & PSW_CY))
|
|
#define TESTCOND_N (S_REG[PSW] & PSW_S)
|
|
#define TESTCOND_S TESTCOND_N
|
|
|
|
#define TESTCOND_LT ((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV)))
|
|
#define TESTCOND_LE (((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV))) || (S_REG[PSW] & PSW_Z))
|
|
#define TESTCOND_NV (!(S_REG[PSW] & PSW_OV))
|
|
|
|
#define TESTCOND_NL (!(S_REG[PSW] & PSW_CY))
|
|
#define TESTCOND_NC TESTCOND_NL
|
|
|
|
#define TESTCOND_NE (!(S_REG[PSW] & PSW_Z))
|
|
#define TESTCOND_NZ TESTCOND_NE
|
|
|
|
#define TESTCOND_H (!((S_REG[PSW] & PSW_Z) || (S_REG[PSW] & PSW_CY)))
|
|
#define TESTCOND_P (!(S_REG[PSW] & PSW_S))
|
|
#define TESTCOND_NS TESTCOND_P
|
|
|
|
#define TESTCOND_GE (!((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV))))
|
|
#define TESTCOND_GT (!(((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV))) || (S_REG[PSW] & PSW_Z)))
|
|
|
|
// Tag layout
|
|
// Bit 0-21: TAG31-TAG10
|
|
// Bit 22-23: Validity bits(one for each 4-byte subblock)
|
|
// Bit 24-27: NECRV("Reserved")
|
|
// Bit 28-31: 0
|
|
|
|
typedef enum {
|
|
V810_EMU_MODE_FAST = 0,
|
|
V810_EMU_MODE_ACCURATE = 1,
|
|
_V810_EMU_MODE_COUNT
|
|
} V810_Emu_Mode;
|
|
|
|
class V810
|
|
{
|
|
public:
|
|
V810()
|
|
MDFN_COLD;
|
|
~V810() MDFN_COLD;
|
|
|
|
// Pass TRUE for vb_mode if we're emulating a VB-specific enhanced V810 CPU core
|
|
bool Init(V810_Emu_Mode mode, bool vb_mode) MDFN_COLD;
|
|
|
|
void SetInt(int level);
|
|
|
|
void SetMemWriteBus32(uint8 A, bool value) MDFN_COLD;
|
|
void SetMemReadBus32(uint8 A, bool value) MDFN_COLD;
|
|
|
|
void SetMemReadHandlers(uint8 MDFN_FASTCALL (*read8)(v810_timestamp_t &, uint32), uint16 MDFN_FASTCALL (*read16)(v810_timestamp_t &, uint32), uint32 MDFN_FASTCALL (*read32)(v810_timestamp_t &, uint32)) MDFN_COLD;
|
|
void SetMemWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
|
|
|
|
void SetIOReadHandlers(uint8 MDFN_FASTCALL (*read8)(v810_timestamp_t &, uint32), uint16 MDFN_FASTCALL (*read16)(v810_timestamp_t &, uint32), uint32 MDFN_FASTCALL (*read32)(v810_timestamp_t &, uint32)) MDFN_COLD;
|
|
void SetIOWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
|
|
|
|
// Length specifies the number of bytes to map in, at each location specified by addresses[] (for mirroring)
|
|
uint8 *SetFastMap(void *(*allocator)(size_t size), uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name) MDFN_COLD;
|
|
|
|
INLINE void ResetTS(v810_timestamp_t new_base_timestamp)
|
|
{
|
|
assert(next_event_ts > v810_timestamp);
|
|
|
|
next_event_ts -= (v810_timestamp - new_base_timestamp);
|
|
v810_timestamp = new_base_timestamp;
|
|
}
|
|
|
|
INLINE void SetEventNT(const v810_timestamp_t timestamp)
|
|
{
|
|
next_event_ts = timestamp;
|
|
}
|
|
|
|
INLINE v810_timestamp_t GetEventNT(void)
|
|
{
|
|
return (next_event_ts);
|
|
}
|
|
|
|
v810_timestamp_t Run(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp));
|
|
void Exit(void);
|
|
|
|
void Reset(void) MDFN_COLD;
|
|
|
|
enum
|
|
{
|
|
GSREG_PR = 0,
|
|
GSREG_SR = 32,
|
|
GSREG_PC = 64,
|
|
GSREG_TIMESTAMP
|
|
};
|
|
|
|
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
|
|
void SetRegister(unsigned int which, uint32 value);
|
|
|
|
uint32 GetPC(void);
|
|
void SetPC(uint32);
|
|
|
|
INLINE uint32 GetPR(unsigned int which)
|
|
{
|
|
return which ? P_REG[which] : 0;
|
|
}
|
|
|
|
private:
|
|
// Make sure P_REG[] is the first variable/array in this class, so non-zerfo offset encoding(at assembly level) isn't necessary to access it.
|
|
uint32 P_REG[32]; // Program registers pr0-pr31
|
|
uint32 S_REG[32]; // System registers sr0-sr31
|
|
uint32 PC;
|
|
uint8 *PC_ptr;
|
|
uint8 *PC_base;
|
|
|
|
uint32 IPendingCache;
|
|
void RecalcIPendingCache(void);
|
|
|
|
public:
|
|
v810_timestamp_t v810_timestamp; // Will never be less than 0.
|
|
|
|
private:
|
|
v810_timestamp_t next_event_ts;
|
|
|
|
enum
|
|
{
|
|
LASTOP_NORMAL = 0,
|
|
LASTOP_LOAD = 1,
|
|
LASTOP_STORE = 2,
|
|
LASTOP_IN = 3,
|
|
LASTOP_OUT = 4,
|
|
LASTOP_HEAVY_MATH = 5
|
|
};
|
|
|
|
V810_Emu_Mode EmuMode;
|
|
bool VBMode;
|
|
|
|
void Run_Fast(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
|
|
void Run_Accurate(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
|
|
|
|
uint8 MDFN_FASTCALL (*MemRead8)(v810_timestamp_t ×tamp, uint32 A);
|
|
uint16 MDFN_FASTCALL (*MemRead16)(v810_timestamp_t ×tamp, uint32 A);
|
|
uint32 MDFN_FASTCALL (*MemRead32)(v810_timestamp_t ×tamp, uint32 A);
|
|
|
|
void MDFN_FASTCALL (*MemWrite8)(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
void MDFN_FASTCALL (*MemWrite16)(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
|
void MDFN_FASTCALL (*MemWrite32)(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
|
|
uint8 MDFN_FASTCALL (*IORead8)(v810_timestamp_t ×tamp, uint32 A);
|
|
uint16 MDFN_FASTCALL (*IORead16)(v810_timestamp_t ×tamp, uint32 A);
|
|
uint32 MDFN_FASTCALL (*IORead32)(v810_timestamp_t ×tamp, uint32 A);
|
|
|
|
void MDFN_FASTCALL (*IOWrite8)(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
void MDFN_FASTCALL (*IOWrite16)(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
|
void MDFN_FASTCALL (*IOWrite32)(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
|
|
bool MemReadBus32[256]; // Corresponding to the upper 8 bits of the memory address map.
|
|
bool MemWriteBus32[256];
|
|
|
|
int32 lastop; // Set to -1 on FP/MUL/DIV, 0x100 on LD, 0x200 on ST, 0x400 on in, 0x800 on out, and the actual opcode * 2(or >= 0) on everything else.
|
|
|
|
#define LASTOP_LD 0x100
|
|
#define LASTOP_ST 0x200
|
|
#define LASTOP_IN 0x400
|
|
#define LASTOP_OUT 0x800
|
|
|
|
enum
|
|
{
|
|
HALT_NONE = 0,
|
|
HALT_HALT = 1,
|
|
HALT_FATAL_EXCEPTION = 2
|
|
};
|
|
|
|
uint8 Halted;
|
|
|
|
bool Running;
|
|
|
|
int ilevel;
|
|
|
|
bool in_bstr;
|
|
uint16 in_bstr_to;
|
|
|
|
bool bstr_subop(v810_timestamp_t ×tamp, int sub_op, int arg1);
|
|
void fpu_subop(v810_timestamp_t ×tamp, int sub_op, int arg1, int arg2);
|
|
|
|
void Exception(uint32 handler, uint16 eCode);
|
|
|
|
// Caching-related:
|
|
typedef struct
|
|
{
|
|
uint32 tag;
|
|
uint32 data[2];
|
|
bool data_valid[2];
|
|
} V810_CacheEntry_t;
|
|
|
|
V810_CacheEntry_t Cache[128];
|
|
|
|
// Bitstring variables.
|
|
uint32 src_cache;
|
|
uint32 dst_cache;
|
|
bool have_src_cache, have_dst_cache;
|
|
|
|
uint8** FastMap;
|
|
|
|
// For CacheDump and CacheRestore
|
|
void CacheOpMemStore(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
uint32 CacheOpMemLoad(v810_timestamp_t ×tamp, uint32 A);
|
|
|
|
void CacheClear(v810_timestamp_t ×tamp, uint32 start, uint32 count);
|
|
void CacheDump(v810_timestamp_t ×tamp, const uint32 SA);
|
|
void CacheRestore(v810_timestamp_t ×tamp, const uint32 SA);
|
|
|
|
uint32 RDCACHE(v810_timestamp_t ×tamp, uint32 addr);
|
|
//
|
|
// End caching related
|
|
//
|
|
|
|
uint16 RDOP(v810_timestamp_t ×tamp, uint32 addr, uint32 meow = 2);
|
|
void SetFlag(uint32 n, bool condition);
|
|
void SetSZ(uint32 value);
|
|
|
|
void SetSREG(v810_timestamp_t ×tamp, unsigned int which, uint32 value);
|
|
uint32 GetSREG(unsigned int which);
|
|
|
|
bool IsSubnormal(uint32 fpval);
|
|
void FPU_Math_Template(uint32 (V810_FP_Ops::*func)(uint32, uint32), uint32 arg1, uint32 arg2);
|
|
void FPU_DoException(void);
|
|
bool CheckFPInputException(uint32 fpval);
|
|
bool FPU_DoesExceptionKillResult(void);
|
|
void SetFPUOPNonFPUFlags(uint32 result);
|
|
|
|
uint32 BSTR_RWORD(v810_timestamp_t ×tamp, uint32 A);
|
|
void BSTR_WWORD(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
bool Do_BSTR_Search(v810_timestamp_t ×tamp, const int inc_mul, unsigned int bit_test);
|
|
|
|
V810_FP_Ops fpo;
|
|
|
|
uint8 DummyRegion[V810_FAST_MAP_PSIZE + V810_FAST_MAP_TRAMPOLINE_SIZE];
|
|
};
|