ref: 40fb4a3ae2f05f500cc3e1c0b5fc7031ce02b4ab
dir: /psx/cpu.h/
#ifndef CPU_H
#define CPU_H
#include <stdint.h>
#include <stdio.h>
#include "bus.h"
#define PSX_CPU_CLOCK 33868800 // 33.868800 MHz
#define PSX_CPU_CLOCK_FREQ 33.868800f
struct psx_cpu_t;
typedef struct psx_cpu_t psx_cpu_t;
typedef void (*psx_cpu_kcall_hook_t)(psx_cpu_t*);
/*
Name Alias Common Usage
R0 zero Constant (always 0)
R1 at Assembler temporary (destroyed by some assembler pseudoinstructions!)
R2-R3 v0-v1 Subroutine return values, may be changed by subroutines
R4-R7 a0-a3 Subroutine arguments, may be changed by subroutines
R8-R15 t0-t7 Temporaries, may be changed by subroutines
R16-R23 s0-s7 Static variables, must be saved by subs
R24-R25 t8-t9 Temporaries, may be changed by subroutines
R26-R27 k0-k1 Reserved for kernel (destroyed by some IRQ handlers!)
R28 gp Global pointer (rarely used)
R29 sp Stack pointer
R30 fp(s8) Frame Pointer, or 9th Static variable, must be saved
R31 ra Return address (used so by JAL,BLTZAL,BGEZAL opcodes)
- pc Program counter
- hi,lo Multiply/divide results, may be changed by subroutines
*/
/*
cop0r0 - N/A
cop0r1 - N/A
cop0r2 - N/A
cop0r3 - BPC - Breakpoint on execute (R/W)
cop0r4 - N/A
cop0r5 - BDA - Breakpoint on data access (R/W)
cop0r6 - JUMPDEST - Randomly memorized jump address (R)
cop0r7 - DCIC - Breakpoint control (R/W)
cop0r8 - BadVaddr - Bad Virtual Address (R)
cop0r9 - BDAM - Data Access breakpoint mask (R/W)
cop0r10 - N/A
cop0r11 - BPCM - Execute breakpoint mask (R/W)
cop0r12 - SR - System status register (R/W)
cop0r13 - CAUSE - Describes the most recently recognised exception (R)
cop0r14 - EPC - Return Address from Trap (R)
cop0r15 - PRID - Processor ID (R)
*/
#define COP0_BPC 3
#define COP0_BDA 5
#define COP0_JUMPDEST 6
#define COP0_DCIC 7
#define COP0_BADVADDR 8
#define COP0_BDAM 9
#define COP0_BPCM 11
#define COP0_SR 12
#define COP0_CAUSE 13
#define COP0_EPC 14
#define COP0_PRID 15
struct psx_cpu_t {
uint32_t r[32];
uint32_t buf[2];
uint32_t pc;
uint32_t hi, lo;
uint32_t load_d, load_v;
uint32_t last_cycles;
uint32_t total_cycles;
int branch, delay_slot;
uint32_t cop0_r[16];
psx_bus_t* bus;
psx_cpu_kcall_hook_t a_function_hook;
psx_cpu_kcall_hook_t b_function_hook;
};
/*
0 IEc Current Interrupt Enable (0=Disable, 1=Enable) ;rfe pops IUp here
1 KUc Current Kernel/User Mode (0=Kernel, 1=User) ;rfe pops KUp here
2 IEp Previous Interrupt Disable ;rfe pops IUo here
3 KUp Previous Kernel/User Mode ;rfe pops KUo here
4 IEo Old Interrupt Disable ;left unchanged by rfe
5 KUo Old Kernel/User Mode ;left unchanged by rfe
6-7 - Not used (zero)
8-15 Im 8 bit interrupt mask fields. When set the corresponding
interrupts are allowed to cause an exception.
16 Isc Isolate Cache (0=No, 1=Isolate)
When isolated, all load and store operations are targetted
to the Data cache, and never the main memory.
(Used by PSX Kernel, in combination with Port FFFE0130h)
17 Swc Swapped cache mode (0=Normal, 1=Swapped)
Instruction cache will act as Data cache and vice versa.
Use only with Isc to access & invalidate Instr. cache entries.
(Not used by PSX Kernel)
18 PZ When set cache parity bits are written as 0.
19 CM Shows the result of the last load operation with the D-cache
isolated. It gets set if the cache really contained data
for the addressed memory location.
20 PE Cache parity error (Does not cause exception)
21 TS TLB shutdown. Gets set if a programm address simultaneously
matches 2 TLB entries.
(initial value on reset allows to detect extended CPU version?)
22 BEV Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1)
23-24 - Not used (zero)
25 RE Reverse endianness (0=Normal endianness, 1=Reverse endianness)
Reverses the byte order in which data is stored in
memory. (lo-hi -> hi-lo)
(Affects only user mode, not kernel mode) (?)
(The bit doesn't exist in PSX ?)
26-27 - Not used (zero)
28 CU0 COP0 Enable (0=Enable only in Kernel Mode, 1=Kernel and User Mode)
29 CU1 COP1 Enable (0=Disable, 1=Enable) (none in PSX)
30 CU2 COP2 Enable (0=Disable, 1=Enable) (GTE in PSX)
31 CU3 COP3 Enable (0=Disable, 1=Enable) (none in PSX)
*/
#define SR_IEC 0x00000001
#define SR_KUC 0x00000002
#define SR_IEP 0x00000004
#define SR_KUP 0x00000008
#define SR_IEO 0x00000010
#define SR_KUO 0x00000020
#define SR_IM 0x0000ff00
#define SR_IM0 0x00000100
#define SR_IM1 0x00000200
#define SR_IM2 0x00000400
#define SR_IM3 0x00000800
#define SR_IM4 0x00001000
#define SR_IM5 0x00002000
#define SR_IM6 0x00004000
#define SR_IM7 0x00008000
#define SR_ISC 0x00010000
#define SR_SWC 0x00020000
#define SR_PZ 0x00040000
#define SR_CM 0x00080000
#define SR_PE 0x00100000
#define SR_TS 0x00200000
#define SR_BEV 0x00400000
#define SR_RE 0x02000000
#define SR_CU0 0x10000000
#define SR_CU1 0x20000000
#define SR_CU2 0x40000000
#define SR_CU3 0x80000000
psx_cpu_t* psx_cpu_create();
void psx_cpu_init(psx_cpu_t*, psx_bus_t*);
void psx_cpu_destroy(psx_cpu_t*);
void psx_cpu_cycle(psx_cpu_t*);
void psx_cpu_exception(psx_cpu_t*, uint32_t);
void psx_cpu_irq(psx_cpu_t*, uint32_t);
void psx_cpu_load_state(psx_cpu_t*, FILE*);
void psx_cpu_save_state(psx_cpu_t*, FILE*);
void psx_cpu_fetch(psx_cpu_t*);
void psx_cpu_set_a_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
void psx_cpu_set_b_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
void psx_cpu_check_irq(psx_cpu_t*);
/*
00h INT Interrupt
01h MOD Tlb modification (none such in PSX)
02h TLBL Tlb load (none such in PSX)
03h TLBS Tlb store (none such in PSX)
04h AdEL Address error, Data load or Instruction fetch
05h AdES Address error, Data store
The address errors occur when attempting to read
outside of KUseg in user mode and when the address
is misaligned. (See also: BadVaddr register)
06h IBE Bus error on Instruction fetch
07h DBE Bus error on Data load/store
08h Syscall Generated unconditionally by syscall instruction
09h BP Breakpoint - break instruction
0Ah RI Reserved instruction
0Bh CpU Coprocessor unusable
0Ch Ov Arithmetic overflow
*/
#define CAUSE_INT (0x00 << 2)
#define CAUSE_MOD (0x01 << 2)
#define CAUSE_TLBL (0x02 << 2)
#define CAUSE_TLBS (0x03 << 2)
#define CAUSE_ADEL (0x04 << 2)
#define CAUSE_ADES (0x05 << 2)
#define CAUSE_IBE (0x06 << 2)
#define CAUSE_DBE (0x07 << 2)
#define CAUSE_SYSCALL (0x08 << 2)
#define CAUSE_BP (0x09 << 2)
#define CAUSE_RI (0x0a << 2)
#define CAUSE_CPU (0x0b << 2)
#define CAUSE_OV (0x0c << 2)
void psx_cpu_i_invalid(psx_cpu_t*);
// Primary
void psx_cpu_i_special(psx_cpu_t*);
void psx_cpu_i_bxx(psx_cpu_t*);
void psx_cpu_i_j(psx_cpu_t*);
void psx_cpu_i_jal(psx_cpu_t*);
void psx_cpu_i_beq(psx_cpu_t*);
void psx_cpu_i_bne(psx_cpu_t*);
void psx_cpu_i_blez(psx_cpu_t*);
void psx_cpu_i_bgtz(psx_cpu_t*);
void psx_cpu_i_addi(psx_cpu_t*);
void psx_cpu_i_addiu(psx_cpu_t*);
void psx_cpu_i_slti(psx_cpu_t*);
void psx_cpu_i_sltiu(psx_cpu_t*);
void psx_cpu_i_andi(psx_cpu_t*);
void psx_cpu_i_ori(psx_cpu_t*);
void psx_cpu_i_xori(psx_cpu_t*);
void psx_cpu_i_lui(psx_cpu_t*);
void psx_cpu_i_cop0(psx_cpu_t*);
void psx_cpu_i_cop1(psx_cpu_t*);
void psx_cpu_i_cop2(psx_cpu_t*);
void psx_cpu_i_cop3(psx_cpu_t*);
void psx_cpu_i_lb(psx_cpu_t*);
void psx_cpu_i_lh(psx_cpu_t*);
void psx_cpu_i_lwl(psx_cpu_t*);
void psx_cpu_i_lw(psx_cpu_t*);
void psx_cpu_i_lbu(psx_cpu_t*);
void psx_cpu_i_lhu(psx_cpu_t*);
void psx_cpu_i_lwr(psx_cpu_t*);
void psx_cpu_i_sb(psx_cpu_t*);
void psx_cpu_i_sh(psx_cpu_t*);
void psx_cpu_i_swl(psx_cpu_t*);
void psx_cpu_i_sw(psx_cpu_t*);
void psx_cpu_i_swr(psx_cpu_t*);
void psx_cpu_i_lwc0(psx_cpu_t*);
void psx_cpu_i_lwc1(psx_cpu_t*);
void psx_cpu_i_lwc2(psx_cpu_t*);
void psx_cpu_i_lwc3(psx_cpu_t*);
void psx_cpu_i_swc0(psx_cpu_t*);
void psx_cpu_i_swc1(psx_cpu_t*);
void psx_cpu_i_swc2(psx_cpu_t*);
void psx_cpu_i_swc3(psx_cpu_t*);
// Secondary
void psx_cpu_i_sll(psx_cpu_t*);
void psx_cpu_i_srl(psx_cpu_t*);
void psx_cpu_i_sra(psx_cpu_t*);
void psx_cpu_i_sllv(psx_cpu_t*);
void psx_cpu_i_srlv(psx_cpu_t*);
void psx_cpu_i_srav(psx_cpu_t*);
void psx_cpu_i_jr(psx_cpu_t*);
void psx_cpu_i_jalr(psx_cpu_t*);
void psx_cpu_i_syscall(psx_cpu_t*);
void psx_cpu_i_break(psx_cpu_t*);
void psx_cpu_i_mfhi(psx_cpu_t*);
void psx_cpu_i_mthi(psx_cpu_t*);
void psx_cpu_i_mflo(psx_cpu_t*);
void psx_cpu_i_mtlo(psx_cpu_t*);
void psx_cpu_i_mult(psx_cpu_t*);
void psx_cpu_i_multu(psx_cpu_t*);
void psx_cpu_i_div(psx_cpu_t*);
void psx_cpu_i_divu(psx_cpu_t*);
void psx_cpu_i_add(psx_cpu_t*);
void psx_cpu_i_addu(psx_cpu_t*);
void psx_cpu_i_sub(psx_cpu_t*);
void psx_cpu_i_subu(psx_cpu_t*);
void psx_cpu_i_and(psx_cpu_t*);
void psx_cpu_i_or(psx_cpu_t*);
void psx_cpu_i_xor(psx_cpu_t*);
void psx_cpu_i_nor(psx_cpu_t*);
void psx_cpu_i_slt(psx_cpu_t*);
void psx_cpu_i_sltu(psx_cpu_t*);
// COP0
void psx_cpu_i_mfc0(psx_cpu_t*);
void psx_cpu_i_cfc0(psx_cpu_t*);
void psx_cpu_i_mtc0(psx_cpu_t*);
void psx_cpu_i_ctc0(psx_cpu_t*);
void psx_cpu_i_bc0c(psx_cpu_t*);
// Unimplemented
// void psx_cpu_i_cop0_tlbr(psx_cpu_t*);
// void psx_cpu_i_cop0_tlbwi(psx_cpu_t*);
// void psx_cpu_i_cop0_tlbwr(psx_cpu_t*);
// void psx_cpu_i_cop0_tlbp(psx_cpu_t*);
// COP0-specific
void psx_cpu_i_rfe(psx_cpu_t*);
// BXX
void psx_cpu_i_bltz(psx_cpu_t*);
void psx_cpu_i_bgez(psx_cpu_t*);
void psx_cpu_i_bltzal(psx_cpu_t*);
void psx_cpu_i_bgezal(psx_cpu_t*);
typedef void (*psx_cpu_instruction_t)(psx_cpu_t*);
#endif