Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/cpu.cpp
2 views
1
// Meteor - A Nintendo Gameboy Advance emulator
2
// Copyright (C) 2009-2011 Philippe Daouadi
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
#include "ameteor/cpu.hpp"
18
#include "ameteor/bios.hpp"
19
#include "globals.hpp"
20
#include "cpu_globals.hpp"
21
#include "ameteor.hpp"
22
23
#include "debug.hpp"
24
25
#include <cstring>
26
27
namespace AMeteor
28
{
29
Cpu::Cpu ()
30
{
31
Reset();
32
}
33
34
void Cpu::Reset ()
35
{
36
std::memset(&m_st, 0, sizeof(m_st));
37
R(15) = 0x00000004;
38
m_st.icpsr.mode = M_SVC;
39
m_st.icpsr.fiq_d = true;
40
m_st.icpsr.irq_d = true;
41
}
42
43
void Cpu::SoftReset ()
44
{
45
std::memset(&m_st, 0, sizeof(m_st));
46
R(13) = 0x03007F00;
47
R(15) = 0x08000004;
48
m_st.irq_r[0] = 0x03007FA0; // R13
49
m_st.svc_r[0] = 0x03007FE0; // R13
50
m_st.icpsr.mode = 0x1F;
51
m_st.icpsr.fiq_d = true;
52
}
53
54
void Cpu::UpdateICpsr ()
55
{
56
m_st.icpsr.mode = m_st.cpsr.b.mode;
57
m_st.icpsr.irq_d = m_st.cpsr.b.irq_d;
58
m_st.icpsr.fiq_d = m_st.cpsr.b.fiq_d;
59
m_st.icpsr.thumb = m_st.cpsr.b.thumb;
60
m_st.icpsr.s_overflow = m_st.cpsr.b.s_overflow;
61
m_st.icpsr.f_overflow = m_st.cpsr.b.f_overflow;
62
m_st.icpsr.f_carry = m_st.cpsr.b.f_carry;
63
m_st.icpsr.f_zero = m_st.cpsr.b.f_zero;
64
m_st.icpsr.f_sign = m_st.cpsr.b.f_sign;
65
}
66
67
void Cpu::UpdateCpsr ()
68
{
69
m_st.cpsr.b.mode = m_st.icpsr.mode;
70
m_st.cpsr.b.irq_d = m_st.icpsr.irq_d;
71
m_st.cpsr.b.fiq_d = m_st.icpsr.fiq_d;
72
m_st.cpsr.b.thumb = m_st.icpsr.thumb;
73
m_st.cpsr.b.s_overflow = m_st.icpsr.s_overflow;
74
m_st.cpsr.b.f_overflow = m_st.icpsr.f_overflow;
75
m_st.cpsr.b.f_carry = m_st.icpsr.f_carry;
76
m_st.cpsr.b.f_zero = m_st.icpsr.f_zero;
77
m_st.cpsr.b.f_sign = m_st.icpsr.f_sign;
78
}
79
80
void Cpu::SwitchToMode (uint8_t newmode)
81
{
82
SaveMode(m_st.icpsr.mode);
83
84
switch (newmode)
85
{
86
case 0x10: // User (non-privileged)
87
case 0x1F: // System (privileged 'User' mode)
88
switch (m_st.icpsr.mode)
89
{
90
case 0x10:
91
case 0x1F:
92
case 0x11:
93
std::memcpy(m_st.r + 8, m_st.usr_r, sizeof(m_st.usr_r));
94
break;
95
default:
96
std::memcpy(m_st.r + 13, m_st.usr_r + 5, 2*4);
97
break;
98
}
99
break;
100
case 0x11: // FIQ
101
std::memcpy(m_st.r + 8, m_st.fiq_r, sizeof(m_st.fiq_r));
102
break;
103
case 0x12: // IRQ
104
std::memcpy(m_st.r + 13, m_st.irq_r, sizeof(m_st.irq_r));
105
break;
106
case 0x13: // Supervisor (SWI)
107
std::memcpy(m_st.r + 13, m_st.svc_r, sizeof(m_st.svc_r));
108
break;
109
case 0x17: // Abort
110
std::memcpy(m_st.r + 13, m_st.abt_r, sizeof(m_st.abt_r));
111
break;
112
case 0x1B: // Undefined
113
std::memcpy(m_st.r + 13, m_st.und_r, sizeof(m_st.und_r));
114
break;
115
default:
116
met_abort("Unknown CPU mode : " << IOS_ADD << (int)newmode);
117
break;
118
}
119
120
UpdateCpsr();
121
m_st.spsr.dw = m_st.cpsr.dw;
122
m_st.icpsr.mode = newmode;
123
}
124
125
void Cpu::SwitchModeBack ()
126
{
127
// oldmode is the mode on which we want to switch back
128
uint8_t oldmode = m_st.spsr.b.mode, curmode = m_st.icpsr.mode;
129
// we don't care if the spsr of the mode we are using is modified
130
SaveMode(curmode);
131
132
m_st.cpsr.dw = m_st.spsr.dw;
133
UpdateICpsr();
134
CheckInterrupt();
135
switch (oldmode)
136
{
137
case 0x10: // User (non-privileged)
138
case 0x1F: // System (privileged 'User' mode)
139
switch (curmode)
140
{
141
case 0x10:
142
case 0x1F:
143
case 0x11:
144
std::memcpy(m_st.r + 8, m_st.usr_r, sizeof(m_st.usr_r));
145
break;
146
default:
147
std::memcpy(m_st.r + 13, m_st.usr_r + 5, 2*4);
148
break;
149
}
150
break;
151
case 0x11: // FIQ
152
std::memcpy(m_st.r + 8, m_st.fiq_r, sizeof(m_st.fiq_r));
153
m_st.spsr.dw = m_st.fiq_spsr.dw;
154
break;
155
case 0x12: // IRQ
156
std::memcpy(m_st.r + 13, m_st.irq_r, sizeof(m_st.irq_r));
157
m_st.spsr.dw = m_st.irq_spsr.dw;
158
break;
159
case 0x13: // Supervisor (SWI)
160
std::memcpy(m_st.r + 13, m_st.svc_r, sizeof(m_st.svc_r));
161
m_st.spsr.dw = m_st.svc_spsr.dw;
162
break;
163
case 0x17: // Abort
164
std::memcpy(m_st.r + 13, m_st.abt_r, sizeof(m_st.abt_r));
165
m_st.spsr.dw = m_st.abt_spsr.dw;
166
break;
167
case 0x1B: // Undefined
168
std::memcpy(m_st.r + 13, m_st.und_r, sizeof(m_st.und_r));
169
m_st.spsr.dw = m_st.und_spsr.dw;
170
break;
171
default:
172
met_abort("Unknown CPU mode : " << IOS_ADD << (int)oldmode);
173
break;
174
}
175
}
176
177
void Cpu::SaveMode (uint8_t mode)
178
{
179
switch (mode)
180
{
181
case 0x10: // User (non-privileged)
182
case 0x1F: // System (privileged 'User' mode)
183
std::memcpy(m_st.usr_r, m_st.r + 8, sizeof(m_st.usr_r));
184
break;
185
case 0x11: // FIQ
186
std::memcpy(m_st.fiq_r, m_st.r + 8, sizeof(m_st.fiq_r));
187
m_st.fiq_spsr.dw = m_st.spsr.dw;
188
break;
189
case 0x12: // IRQ
190
std::memcpy(m_st.irq_r, m_st.r + 13, sizeof(m_st.irq_r));
191
m_st.irq_spsr.dw = m_st.spsr.dw;
192
break;
193
case 0x13: // Supervisor (SWI)
194
std::memcpy(m_st.svc_r, m_st.r + 13, sizeof(m_st.svc_r));
195
m_st.svc_spsr.dw = m_st.spsr.dw;
196
break;
197
case 0x17: // Abort
198
std::memcpy(m_st.abt_r, m_st.r + 13, sizeof(m_st.abt_r));
199
m_st.abt_spsr.dw = m_st.spsr.dw;
200
break;
201
case 0x1B: // Undefined
202
std::memcpy(m_st.und_r, m_st.r + 13, sizeof(m_st.und_r));
203
m_st.und_spsr.dw = m_st.spsr.dw;
204
break;
205
default:
206
met_abort("Unknown CPU mode : " << IOS_ADD << (int)mode);
207
break;
208
}
209
}
210
211
void Cpu::Interrupt ()
212
{
213
// Switch mode
214
SwitchToMode(0x12); // IRQ
215
// Save PC
216
R(14) = R(15);
217
// FIXME : why ? this seems to be USELESS ! (look at bios irq end)
218
if (m_st.icpsr.thumb)
219
R(14) += 2;
220
// Switch to ARM
221
m_st.icpsr.thumb = false;
222
// Disable IRQ
223
m_st.icpsr.irq_d = true;
224
SetInterrupt(false);
225
// Branch on 0x18
226
R(15) = 0x1C;
227
}
228
229
void Cpu::SoftwareInterrupt ()
230
{
231
// Switch mode
232
SwitchToMode(0x13); // Supervisor
233
// Save PC
234
R(14) = R(15) - (m_st.icpsr.thumb ? 2 : 4);
235
// Switch to ARM
236
m_st.icpsr.thumb = false;
237
// Disable IRQ
238
m_st.icpsr.irq_d = true;
239
SetInterrupt(false);
240
// Branch on 0x8
241
R(15) = 0xC;
242
}
243
244
// TODO put this in Bios, no ?
245
void Cpu::SoftwareInterrupt (uint32_t comment)
246
{
247
if (true)
248
{
249
char buff[256];
250
int pos = 0;
251
pos += sprintf (buff + pos, "SWI %02xh : ", comment);
252
switch (comment) // no one cares about the sound driver
253
{
254
case 0x00: pos += sprintf (buff + pos, "SoftReset");
255
break;
256
case 0x01: pos += sprintf (buff + pos, "RegisterRamReset"); // todo: display flags
257
break;
258
case 0x02: pos += sprintf (buff + pos, "Halt");
259
break;
260
case 0x03: pos += sprintf (buff + pos, "Stop");
261
break;
262
case 0x04: pos += sprintf (buff + pos, "IntrWait"); // todo: display flags
263
break;
264
case 0x05: pos += sprintf (buff + pos, "VBlankIntrWait");
265
break;
266
case 0x06: pos += sprintf (buff + pos, "Div: ");
267
pos += sprintf (buff + pos, "%08xh/%08xh", R(0), R(1));
268
break;
269
case 0x07: pos += sprintf (buff + pos, "DivArm: ");
270
pos += sprintf (buff + pos, "%08xh/%08xh", R(1), R(0));
271
break;
272
case 0x08: pos += sprintf (buff + pos, "Sqrt: ");
273
pos += sprintf (buff + pos, "sqrt(%08xh)", R(0));
274
break;
275
case 0x09: pos += sprintf (buff + pos, "ArcTan: ");
276
pos += sprintf (buff + pos, "atan(%04xh)", R(0) & 0xffff);
277
break;
278
case 0x0a: pos += sprintf (buff + pos, "ArcTan2: ");
279
pos += sprintf (buff + pos, "atan2(%04xh,%04xh)", R(1) & 0xffff, R(0) & 0xffff);
280
break;
281
case 0x0b: pos += sprintf (buff + pos, "CpuSet: ");
282
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], wcnt=%xh, fixed=%c, size=%d", R(0), R(1), R(2) & 0x1fffff, R(2) & 0x1000000 ? 'Y' : 'N', R(2) & 0x4000000 ? 32 : 16);
283
break;
284
case 0x0c: pos += sprintf (buff + pos, "CpuFastSet: ");
285
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], wcnt=%xh, fixed=%c", R(0), R(1), R(2) & 0x1fffff, R(2) & 0x1000000 ? 'Y' : 'N');
286
break;
287
case 0x0d: pos += sprintf (buff + pos, "GetBiosChecksum");
288
break;
289
case 0x0e: pos += sprintf (buff + pos, "BgAffineSet: ");
290
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], cnt=%d", R(0), R(1), R(2));
291
break;
292
case 0x0f: pos += sprintf (buff + pos, "ObjAffineSet: ");
293
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], cnt=%d, offs=%d", R(0), R(1), R(2), R(3));
294
break;
295
case 0x10: pos += sprintf (buff + pos, "BitUnPack: ");
296
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh], info=[%08xh]", R(0), R(1), R(2));
297
break;
298
case 0x11: pos += sprintf (buff + pos, "LZ77UnCompWram: ");
299
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
300
break;
301
case 0x12: pos += sprintf (buff + pos, "LZ77UnCompVram: ");
302
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
303
break;
304
case 0x13: pos += sprintf (buff + pos, "HuffUnComp: ");
305
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
306
break;
307
case 0x14: pos += sprintf (buff + pos, "RLUnCompWram: ");
308
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
309
break;
310
case 0x15: pos += sprintf (buff + pos, "RLUnCompVram: ");
311
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
312
break;
313
case 0x16: pos += sprintf (buff + pos, "Diff8bitUnFilterWram: ");
314
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
315
break;
316
case 0x17: pos += sprintf (buff + pos, "Diff8bitUnFilterVram: ");
317
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
318
break;
319
case 0x18: pos += sprintf (buff + pos, "Diff16bitUnFilter: ");
320
pos += sprintf (buff + pos, "src=[%08xh], dst=[%08xh]", R(0), R(1));
321
break;
322
case 0x19: pos += sprintf (buff + pos, "SoundBias");
323
break;
324
case 0x1a: pos += sprintf (buff + pos, "SoundDriverInit");
325
break;
326
case 0x1b: pos += sprintf (buff + pos, "SoundDriverMode");
327
break;
328
case 0x1c: pos += sprintf (buff + pos, "SoundDriverMain");
329
break;
330
case 0x1d: pos += sprintf (buff + pos, "SoundDriverVSync");
331
break;
332
case 0x1e: pos += sprintf (buff + pos, "SoundChannelClear");
333
break;
334
case 0x1f: pos += sprintf (buff + pos, "MidiKey2Freq");
335
break;
336
case 0x20: pos += sprintf (buff + pos, "SoundWhatever0");
337
break;
338
case 0x21: pos += sprintf (buff + pos, "SoundWhatever1");
339
break;
340
case 0x22: pos += sprintf (buff + pos, "SoundWhatever2");
341
break;
342
case 0x23: pos += sprintf (buff + pos, "SoundWhatever3");
343
break;
344
case 0x24: pos += sprintf (buff + pos, "SoundWhatever4");
345
break;
346
case 0x25: pos += sprintf (buff + pos, "MultiBoot: ");
347
pos += sprintf (buff + pos, "mbp=[%08xh], mode=%d", R(0), R(1));
348
break;
349
case 0x26: pos += sprintf (buff + pos, "HardReset");
350
break;
351
case 0x27: pos += sprintf (buff + pos, "CustomHalt: ");
352
pos += sprintf (buff + pos, "val=%02xh", R(2) & 0xff);
353
break;
354
case 0x28: pos += sprintf (buff + pos, "SoundDriverVSyncOff");
355
break;
356
case 0x29: pos += sprintf (buff + pos, "SoundDriverVSyncOnn");
357
break;
358
case 0x2a: pos += sprintf (buff + pos, "SoundGetJumpList");
359
break;
360
default: pos += sprintf (buff + pos, "UNKNOWN");
361
break;
362
}
363
pos += sprintf (buff + pos, "\n");
364
print_bizhawk(buff);
365
}
366
if (MEM.HasBios())
367
SoftwareInterrupt();
368
else
369
switch (comment)
370
{
371
case 0x00:
372
Bios::SoftReset();
373
break;
374
case 0x01:
375
Bios::RegisterRamReset();
376
break;
377
case 0x02:
378
Bios::Halt();
379
break;
380
case 0x04:
381
case 0x05:
382
SoftwareInterrupt();
383
break;
384
case 0x06:
385
Bios::Div();
386
break;
387
case 0x07:
388
Bios::DivArm();
389
break;
390
case 0x08:
391
Bios::Sqrt();
392
break;
393
case 0x09:
394
Bios::ArcTan();
395
break;
396
case 0x0A:
397
Bios::ArcTan2();
398
break;
399
case 0x0B:
400
Bios::CpuSet();
401
break;
402
case 0x0C:
403
Bios::CpuFastSet();
404
break;
405
case 0x0E:
406
Bios::BgAffineSet();
407
break;
408
case 0x0F:
409
Bios::ObjAffineSet();
410
break;
411
case 0x11:
412
Bios::LZ77UnCompWram();
413
break;
414
case 0x12:
415
Bios::LZ77UnCompVram();
416
break;
417
case 0x13:
418
Bios::HuffUnComp();
419
break;
420
case 0x14:
421
Bios::RLUnCompWram();
422
break;
423
case 0x15:
424
Bios::RLUnCompVram();
425
break;
426
default:
427
met_abort("Unknown software interrupt : " << IOS_ADD << comment);
428
break;
429
}
430
}
431
432
bool Cpu::SaveState (std::ostream& stream)
433
{
434
SS_WRITE_VAR(m_st);
435
436
return true;
437
}
438
439
bool Cpu::LoadState (std::istream& stream)
440
{
441
SS_READ_VAR(m_st);
442
443
CheckInterrupt();
444
445
return true;
446
}
447
}
448
449