#pragma once /* All COP0 instructions have this */ constexpr uint8_t COP0_OPCODE = 0b010000; union COP0Instr { uint32_t value; struct { uint32_t input : 11; /* This is used differently depending on the action (look COP0Input) */ uint32_t action : 5; /* Perf or Debug or rd in MFC0 */ uint32_t rt : 5; uint32_t type : 5; uint32_t opcode : 6; }; COP0Instr& operator=(uint32_t val) { value = val; return *this; } }; union COP0Input { uint32_t input; struct { uint32_t id : 3; /* Tells us which MF* instruction to execute */ uint32_t : 8; } debug; struct { uint32_t source : 1; /* 0: MFPS 1: MFPC */ uint32_t reg : 5; /* The index of the PEV (Performance Event Specifier) or PC (Performace Counter) respectively */ uint32_t : 5; } perf; COP0Input& operator=(uint32_t val) { input = val; return *this; } }; /* Instruction types */ constexpr uint8_t COP0_MF0 = 0b00000; constexpr uint8_t COP0_MT0 = 0b00100; constexpr uint8_t COP0_C0 = 0b10000; /* The status register fields */ union COP0Status { uint32_t value; struct { uint32_t ie : 1; /* Interrupt Enable */ uint32_t exl : 1; /* Exception Level */ uint32_t erl : 1; /* Error Level */ uint32_t ksu : 2; /* Kernel/Supervisor/User Mode bits */ uint32_t : 5; uint32_t im : 2; /* Int[1:0] signals */ uint32_t bem : 1; /* Bus Error Mask */ uint32_t : 2; uint32_t im1 : 1; /* Internal timer interrupt */ uint32_t eie : 1; /* Enable IE */ uint32_t edi : 1; /* EI/DI instruction Enable */ uint32_t ch : 1; /* Cache Hit */ uint32_t : 3; uint32_t bev : 1; /* Location of TLB refill */ uint32_t dev : 1; /* Location of Performance counter */ uint32_t : 2; uint32_t fr : 1; /* Additional floating point registers */ uint32_t : 1; uint32_t cu : 4; /* Usability of each of the four coprocessors */ }; }; enum OperatingMode { USER_MODE = 0b10, SUPERVISOR_MODE = 0b01, KERNEL_MODE = 0b00 }; /* The COP0 registers */ union COP0 { uint32_t regs[32]; struct { uint32_t index; uint32_t random; uint32_t entry_lo0; uint32_t entry_lo1; uint32_t context; uint32_t page_mask; uint32_t wired; uint32_t reserved0[1]; uint32_t bad_vaddr; uint32_t count; uint32_t entryhi; uint32_t compare; COP0Status status; uint32_t cause; uint32_t epc; uint32_t prid; uint32_t config; uint32_t reserved1[6]; uint32_t bad_paddr; uint32_t debug; uint32_t perf; uint32_t reserved2[2]; uint32_t tag_lo; uint32_t tag_hi; uint32_t error_epc; uint32_t reserved3[1]; }; OperatingMode get_operating_mode() { if (status.exl || status.erl) /* Setting one of these enforces kernel mode */ return OperatingMode::KERNEL_MODE; else return (OperatingMode)status.ksu; } };