#pragma once
#define NOCASE()
#define ENABLE_CONOUT true
#define NOPRINT(...)
#define DPRINT(...) { fprintf(__VA_ARGS__); }
#define DEBUG(...) { DPRINT(stdout,__VA_ARGS__); }
#define DEBUG_PRINT(...) { NOPRINT(stderr,__VA_ARGS__); }
#define DEBUG_LOAD(...) { NOPRINT(stdout,__VA_ARGS__); }
#define DEBUG_STORE(...) { NOPRINT(stdout,__VA_ARGS__); }
#define DEBUG_TRACE(...) { DPRINT(stdout,__VA_ARGS__); }
#define DEBUG_HWREG(...) { DPRINT(stdout,__VA_ARGS__); }
#define DEBUG_SIO(...) { DPRINT(stdout,__VA_ARGS__); }
#define PSX_CLOCK 33868800
#include "types.h"
enum eOp
{
eOP_NULLIFIED,
eOP_ILL,
eOP_SLL, eOP_SRL, eOP_SRA, eOP_SLLV,
eOP_SRLV, eOP_SRAV,
eOP_JR, eOP_JALR,
eOP_SYSCALL, eOP_BREAK,
eOP_MFHI, eOP_MTHI, eOP_MFLO, eOP_MTLO,
eOP_MULT, eOP_MULTU, eOP_DIV, eOP_DIVU,
eOP_ADD, eOP_ADDU,
eOP_SUB, eOP_SUBU,
eOP_AND, eOP_OR,
eOP_XOR, eOP_NOR,
eOP_SLT, eOP_SLTU,
eOP_NULL,
eOP_BCOND,
eOP_J, eOP_JAL,
eOP_BEQ, eOP_BNE, eOP_BLEZ, eOP_BGTZ,
eOP_ADDI, eOP_ADDIU,
eOP_SLTI, eOP_SLTIU,
eOP_ANDI, eOP_ORI,
eOP_XORI, eOP_LUI,
eOP_COPROC,
eOP_LB, eOP_LH, eOP_LWL, eOP_LW, eOP_LBU, eOP_LHU, eOP_LWR, eOP_SB, eOP_SH, eOP_SWL, eOP_SW, eOP_SWR,
eOP_LWC0, eOP_LWC1, eOP_LWC2, eOP_LWC3,
eOP_SWC0, eOP_SWC1, eOP_SWC2, eOP_SWC3
};
#pragma pack(push,1)
struct PSX_EXE_Header
{
char magic[8];
u32 text_exe_offset;
u32 data_exe_offset;
u32 init_pc;
u32 init_gp;
u32 text_load_addr;
u32 text_size;
u32 data_load_addr;
u32 data_size;
u32 b_addr, b_size;
u32 stack_load_addr;
u32 stack_size;
u32 saved_sp, saved_fp, saved_gp, saved_ra, saved_so;
};
#pragma pack(pop)
#define RAM_SIZE (8*1024*1024)
#define RAM_MASK (RAM_SIZE-1)
#define VRAM_SIZE (1024*1024)
#define VRAM_MASK (VRAM_SIZE-1)
#define BIOS_SIZE (512*1024)
#define BIOS_MASK (BIOS_SIZE-1)
#define SCRATCH_SIZE (1024)
#define SCRATCH_MASK (SCRATCH_SIZE-1)
#define PIO_SIZE (65536)
#define PIO_MASK (PIO_SIZE-1)
class __declspec(dllexport) PSX
{
public:
u8 vram[VRAM_SIZE];
u8 bios[BIOS_SIZE];
u8 scratch[SCRATCH_SIZE];
u8 pio[PIO_SIZE];
u8 ram[RAM_SIZE];
enum eScheduleItemType
{
eScheduleItemType_NIL,
eScheduleItemType_null,
eScheduleItemType_test,
eScheduleItemType_sio0,
eScheduleItemType_sio1,
eScheduleItemType_gpu,
eScheduleItemType_NUM
};
struct SCHED
{
struct IScheduleItem
{
u32 time;
eScheduleItemType next, prev;
};
union
{
IScheduleItem items[eScheduleItemType_NUM];
struct
{
IScheduleItem NIL, null, test;
IScheduleItem sio[2];
IScheduleItem gpu;
};
};
eScheduleItemType head;
u32 nextTime;
void escape() { nextTime = 0; }
eScheduleItemType dequeue();
void remove(eScheduleItemType todoType);
void insert(eScheduleItemType todoType);
} sched;
struct IRQ
{
static const u16 WIRE_MASK = 0x3FD;
union
{
struct
{
u16 vsync:1, gpu:1, cd:1, dma:1, rcnt0:1, rcnt1:1, rcnt2:1, sio0:1, sio1:1, spu:1, extcd:1;
u16 unknown2:6;
};
u16 value;
} flags;
union
{
struct
{
u16 vsync:1, gpu:1, cd:1, dma:1, rcnt0:1, rcnt1:1, rcnt2:1, sio0:1, sio1:1, spu:1, extcd:1;
u16 unknown2:6;
};
u16 value;
} mask;
} irq;
struct SystemRegs
{
u32 biosInit[9];
} sysregs;
struct SioController
{
union
{
struct
{
u16 prescaler_type:2;
};
u16 value;
} mode;
union StatusReg
{
struct
{
u16 TX_RDY:1;
u16 RX_RDY:1;
u16 TX_EMPTY:1;
u16 nothing:1;
u16 OVERRUN:1;
u16 nothing2:2;
u16 DSR:1;
u16 nothing3:1;
u16 IRQ:1;
};
u16 value;
};
union ControlReg
{
struct
{
u16 TX_ENA:1;
u16 DTR:1;
u16 nothing:2;
u16 IACK:1;
u16 nothing2:1;
u16 RESET:1;
u16 nothing3:3;
u16 TX_IENA:1;
u16 RX_IENA:1;
u16 DSR_IENA:1;
u16 PORT_SEL:1;
};
u16 value;
};
StatusReg status;
ControlReg control;
u16 baud_reg;
float CalculateBaud();
void Reset();
} sio[2];
struct CPU
{
enum eException
{
eException_INT = 0,
eException_MOD = 1,
eException_TLBL = 2,
eException_TLBS = 3,
eException_ADEL = 4,
eException_ADES = 5,
eException_IBE = 6,
eException_DBE = 7,
eException_SYSCALL = 8,
eException_BP = 9,
eException_RI = 10,
eException_COPU = 11,
eException_OV = 12,
eException_None = 16
};
union
{
struct
{
u32 r0,
at, v0, v1, a0, a1, a2, a3,
t0, t1, t2, t3, t4, t5, t6, t7,
s0, s1, s2, s3, s4, s5, s6, s7,
t8, t9, k0, k1, gp,
sp,
s8,
ra,
lo, hi;
};
u32 r[34];
} regs;
union SR_REG
{
static const int ZERO_MASK = 0x8D8000C0;
struct
{
u32
IEc:1,
KUc:1,
IEp:1,
KUp:1,
IEo:1,
KUo:1,
zeros:2,
IM:8,
IsC:1,
SwC:1,
PZ:1,
CM:1,
PE:1,
TS:1,
BEV:1,
zeros_2:2,
RE:1,
zeros_3:2,
CU0:1,
CU1:1,
CU2:1,
zeros_4:1;
};
u32 value;
};
union CAUSE_REG
{
struct
{
u32 zeros_1:2;
u32 ExcCode:4;
u32 zeros_2:2;
u32 Sw:2;
u32 IP:6;
u32 zeros_3:12;
u32 CE:2;
u32 zeros_4:1;
u32 BD:1;
};
u32 value;
};
union
{
struct
{
u32
Index, Random, EntryLo0, EntryLo1,
Context, PageMask, Wired, Reserved0,
BadVAddr, Count, EntryHi, Compare;
SR_REG SR;
CAUSE_REG Cause;
u32 EPC;
u32 PRid;
u32
Config, LLAddr, WatchLO, WatchHI,
XContext, Reserved1, Reserved2, Reserved3,
Reserved4, Reserved5, ECC, CacheErr,
TagLo, TagHi, ErrorEPC, Reserved6;
};
u32 r[32];
} cp0;
enum eFormat
{
eFormat_IType, eFormat_RType, eFormat_JType_J, eFormat_JType_JAL, eFormat_CType, eFormat_Other
};
struct Instruction_ITYPE
{
u32 immediate:16;
s32 signed_offset() const { return (s16)immediate; }
s32 signed_target() const { return (signed_offset()<<2) + 4; }
u32 rt:5;
u32 rs:5;
u32 base() const { return rs; }
u32 opcode:6;
};
struct Instruction_CTYPE
{
u32 function:6;
u32 zeros:5;
u32 rd:5;
u32 rt:5;
u32 format:5;
u32 cpnum:2;
u32 opcode_hi:4;
};
union Instruction_RTYPE
{
struct
{
u32 function:6;
u32 sa:5;
u32 rd:5;
u32 rt:5;
u32 rs:5;
u32 opcode:6;
};
u32 value;
u32 break_code() const { return (value>>6)&0xFFFFF; }
};
struct Instruction_JTYPE
{
u32 target:26;
u32 opcode:6;
};
union Instruction
{
Instruction_ITYPE ITYPE;
Instruction_RTYPE RTYPE;
Instruction_JTYPE JTYPE;
Instruction_CTYPE CTYPE;
u32 value;
};
struct DecodedInstruction
{
Instruction instr;
eOp op;
};
struct {
bool IsRunning() const { return timer>0; }
u32 timer;
u32 lo, hi;
} unit_muldiv;
struct
{
u32 in_fetch_addr;
DecodedInstruction decode;
} p_fetch;
struct
{
u32 instr;
u32 regs[3];
} p_rd;
enum eMemOp
{
eMemOp_Unset, eMemOp_None,
eMemOp_StoreWord, eMemOp_StoreHalfword, eMemOp_StoreByte,
eMemOp_LoadWord, eMemOp_LoadHalfwordSigned, eMemOp_LoadHalfwordUnsigned, eMemOp_LoadByteSigned, eMemOp_LoadByteUnsigned,
eMemOp_MTC, eMemOp_MFC,
};
struct ALU_OUTPUT
{
union
{
u32 addr;
};
union {
u32 value;
u32 rt;
};
eMemOp op;
};
struct ALU_PC_OUTPUT
{
u32 pc;
bool enabled;
};
struct P_ALU
{
DecodedInstruction decode;
ALU_OUTPUT out_mem;
ALU_PC_OUTPUT out_pc;
u32 in_pc;
CPU::eException exception;
} p_alu;
enum eStall
{
eStall_None=0,
eStall_MulDiv=1,
};
u32 stall_depends;
u32 stall_user;
struct
{
DecodedInstruction decode;
ALU_OUTPUT in_from_alu;
} p_mem;
enum eDelayState
{
eDelayState_None,
eDelayState_Branch,
eDelayState_BranchRelative,
eDelayState_StoreWord,
eDelayState_StoreHalfword,
eDelayState_StoreByte,
eDelayState_SetGPR,
eDelayState_MTCz,
};
struct DelayState
{
eDelayState state;
u32 arg,arg2;
} delay;
} cpu;
enum eConsoleType
{
eConsoleType_Normal,
eConsoleType_DTL
};
struct
{
u32 ram_size;
u32 ram_mask;
} config;
void poweron(eConsoleType type);
void reset();
void exec_cycle();
void exec_shed(eScheduleItemType type);
static CPU::eFormat util_decode_format(u32 opcode);
void TraceALU();
void cpu_break(const u32 code);
void cpu_run_alu_bioshack();
void cpu_run_alu_bioshack_putchar(const u32 regval);
void patch(const u32 addr, const u32 val);
void cpu_exec_cycle();
void cpu_run_fetch();
void cpu_run_muldiv();
void cpu_run_alu();
void cpu_run_mem();
void cpu_run_wb();
void cpu_exception(CPU::eException ex, u32 pc_victim);
void cpu_copz_mtc(const u32 z, const u32 rd, const u32 value);
void cpu_cop0_mtc(const u32 rd, const u32 value);
u32 cpu_copz_mfc(const u32 z, const u32 rd);
u32 cpu_cop0_mfc(const u32 rd);
u32 cpu_fetch(const u32 addr);
template<int size> u32 cpu_rdmem(const u32 addr);
template<int size, bool POKE> void cpu_wrmem(const u32 addr, const u32 val);
template<int size> void cpu_wrmem(const u32 addr, const u32 val);
void cpu_wr_ram(const int size, const u32 addr, const u32 val);
u32 cpu_rd_ram(const int size, const u32 addr);
void cpu_wr_scratch(const int size, const u32 addr, const u32 val);
u32 cpu_rd_scratch(const int size, const u32 addr);
void cpu_wr_bios(const int size, const u32 addr, const u32 val);
u32 cpu_rd_bios(const int size, const u32 addr);
void cpu_wr_pio(const int size, const u32 addr, const u32 val);
u32 cpu_rd_pio(const int size, const u32 addr);
void cpu_wr_quick(u8* const buf, const int size, const u32 addr, const u32 val);
u32 cpu_rd_quick(const u8* const buf, const int size, const u32 addr);
void cpu_wr_hwreg(const int size, const u32 addr, const u32 val);
u32 cpu_rd_hwreg(const int size, const u32 addr);
void spu_wr(const int size, const u32 addr, const u32 val);
u32 spu_rd(const int size, const u32 addr);
void sio_wr(const int size, const u32 addr, const u32 val);
u32 sio_rd(const int size, const u32 addr);
void sio_dtr(const u32 port);
u32 irq_rd(const int size, const u32 addr);
void irq_wr(const int size, const u32 addr, const u32 val);
void irq_update();
u32 counter;
u64 abscounter;
PSX_EXE_Header exeBootHeader;
enum eFakeBreakOp
{
eFakeBreakOp_None=0,
eFakeBreakOp_BootEXE=1,
eFakeBreakOp_BiosHack=2,
};
void RunForever();
void vblank_trigger();
};