This repository has been archived by the owner on Feb 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
EE.hpp
372 lines (345 loc) · 8.61 KB
/
EE.hpp
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#pragma once
#include <Bus.hpp>
#include <int128.h>
#include <unordered_map>
#include <functional>
#include <intc.hpp>
#include <ee_timers.hpp>
#include <fstream>
union FPR
{
uint32_t uint = 0;
float fint;
};
union FCR0
{
uint32_t value = 0;
struct
{
uint32_t revision : 8;
uint32_t impl : 8;
uint32_t : 16;
};
};
union FCR31
{
uint32_t value = 0;
struct
{
uint32_t round_mode : 2;
uint32_t flags : 5;
uint32_t enable : 5;
uint32_t cause : 6;
uint32_t : 5;
uint32_t condition : 1;
uint32_t flush_denormals : 1;
uint32_t : 7;
};
};
struct Instruction
{
union
{
uint32_t value;
struct
{ /* Used when polling for the opcode */
uint32_t : 26;
uint32_t opcode : 6;
};
struct
{
uint32_t immediate : 16;
uint32_t rt : 5;
uint32_t rs : 5;
uint32_t opcode : 6;
} i_type;
struct
{
uint32_t target : 26;
uint32_t opcode : 6;
} j_type;
struct
{
uint32_t funct : 6;
uint32_t sa : 5;
uint32_t rd : 5;
uint32_t rt : 5;
uint32_t rs : 5;
uint32_t opcode : 6;
} r_type;
};
uint32_t pc;
bool is_delay_slot = false;
};
struct EE_COP1
{
void execute(Instruction instr);
void op_adda(Instruction instr);
void op_madd(Instruction instr);
FPR fpr[32];
FCR0 fcr0;
FCR31 fcr31;
FPR acc;
};
class EmotionEngine
{
private:
void fetch_next()
{
next_instr = {};
next_instr.value = bus->Read32(pc, true);
next_instr.pc = pc;
pc += 4;
}
uint32_t hi0 = 0, hi1 = 0;
uint32_t lo0 = 0, lo1 = 0;
uint32_t pc;
uint32_t sa = 0;
Bus* bus;
Instruction instr, next_instr;
bool skip_branch_delay = false;
bool branch_taken = false;
/* 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 im0 : 1; /* Int[1:0] signals */
uint32_t im1 : 1;
uint32_t bem : 1; /* Bus Error Mask */
uint32_t : 2;
uint32_t im7 : 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 */
};
};
union COP0Cause
{
uint32_t value;
struct
{
uint32_t : 2;
uint32_t exccode : 5;
uint32_t : 3;
uint32_t ip0_pending : 1;
uint32_t ip1_pending : 1;
uint32_t siop : 1;
uint32_t : 2;
uint32_t timer_ip_pending : 1;
uint32_t exc2 : 3;
uint32_t : 9;
uint32_t ce : 2;
uint32_t bd2 : 1;
uint32_t bd : 1;
};
};
enum OperatingMode
{
USER_MODE = 0b10,
SUPERVISOR_MODE = 0b01,
KERNEL_MODE = 0b00
};
/* The COP0 registers */
union COP0
{
COP0() { status.value = 0x400004; /* BEV, ERL = 1 by default */ }
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;
COP0Cause 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;
}
};
uint32_t exception_addr[2] = { 0x80000000, 0xBFC00200 };
enum ExceptionVector
{
V_TLB_REFILL = 0x0,
V_COMMON = 0x180,
V_INTERRUPT = 0x200
};
void special(); // 0x00
void regimm(); // 0x01
void bltz();
void bgez();
void j(); // 0x02
void jal(); // 0x03
void beq(); // 0x04
void bne(); // 0x05
void blez(); // 0x06
void bgtz(); // 0x07
void addiu(); // 0x09
void slti(); // 0x0A
void sltiu(); // 0x0B
void andi(); // 0x0C
void ori(); // 0x0D
void xori(); // 0x0E
void lui(); // 0x0F
void op_cop0(); // 0x10
void op_cop1(); // 0x11
void mtc1();
void ctc1();
void cfc1();
void op_cop2(); // 0x12
void beql(); // 0x14
void bnel(); // 0x15
void daddiu(); // 0x19
void ldl(); // 0x1A
void ldr(); // 0x1B
void mmi(); // 0x1C
void mmi2(); // 0x09 (MMI)
void pand(); // 0x12 (MMI2)
void mflo1();
void mult1();
void div1();
void divu1();
void lq(); // 0x1E
void sq(); // 0x1F
void lb(); // 0x20
void lh(); // 0x21
void lw(); // 0x23
void lbu(); // 0x24
void lhu(); // 0x25
void lwu(); // 0x27
void sb(); // 0x28
void sh(); // 0x29
void sw(); // 0x2B
void sdl(); // 0x2C
void sdr(); // 0x2D
void cache() {} // 0x2F
void ld(); // 0x37
void swc1(); // 0x39
void sd(); // 0x3F
void sll(); // 0x00
void srl(); // 0x02
void sra(); // 0x03
void sllv(); // 0x04
void srlv(); // 0x06
void srav(); // 0x07
void jr(); // 0x08
void jalr(); // 0x09
void movz(); // 0x0A
void movn(); // 0x0B
void sync(); // 0x0F
void mfhi(); // 0x10
void mflo(); // 0x12
void dsllv(); // 0x14
void dsrav(); // 0x17
void mult(); // 0x18
void div(); // 0x1A
void divu(); // 0x1B
void addu(); // 0x21
void subu(); // 0x23
void op_and(); // 0x24
void op_or(); // 0x25
void nor(); // 0x27
void slt(); // 0x2A
void sltu(); // 0x2B
void dadd(); // 0x2C
void daddu(); // 0x2D
void dsll(); // 0x38
void dsrl(); // 0x3A
void dsll32(); // 0x3C
void dsrl32(); // 0x3E
void dsra32(); // 0x3F
INTC intc;
Timers timers;
int cycles_to_execute = 0;
public:
Register regs[32];
enum Exception
{
Interrupt = 0,
TLBModified = 1,
TLBLoad = 2,
TLBStore = 3,
AddrErrorLoad = 4,
AddrErrorStore = 5,
Syscall = 8,
Break = 9,
Reserved = 10,
CopUnusable = 11,
Overflow = 12,
Trap = 13,
};
COP0 cop0;
EE_COP1 cop1;
EmotionEngine(Bus* _bus);
INTC* getIntc() {return &intc;}
Timers* getTimers() {return &timers;}
void Clock(uint32_t cycles);
void exception(Exception exception, bool log)
{
if (log)
{
printf("[EE]: Exception occured of type %d\n", (uint32_t)exception);
}
ExceptionVector vector = ExceptionVector::V_COMMON;
cop0.cause.exccode = (uint32_t)exception;
if (!cop0.status.exl)
{
cop0.epc = instr.pc - 4 * instr.is_delay_slot;
cop0.cause.bd = instr.is_delay_slot;
switch (exception)
{
case Exception::TLBLoad:
case Exception::TLBStore:
vector = ExceptionVector::V_TLB_REFILL;
break;;
case Exception::Interrupt:
vector = ExceptionVector::V_INTERRUPT;
break;;
default:
vector = ExceptionVector::V_COMMON;
break;;
}
cop0.status.exl = true;
}
pc = exception_addr[cop0.status.bev] + vector;
fetch_next();
}
};