shithub: psxe

ref: d2929aa1b3b41c3124b258091d01d74625366817
dir: /psx/cpu.h/

View raw version
#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