Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#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;
}
};