src/ds/ds.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/ds/ds.h>
7
8#include <mgba/core/interface.h>
9#include <mgba/internal/arm/decoder.h>
10#include <mgba/internal/arm/debugger/debugger.h>
11#include <mgba/internal/arm/isa-inlines.h>
12#include <mgba/internal/ds/bios.h>
13
14#include <mgba-util/crc32.h>
15#include <mgba-util/memory.h>
16#include <mgba-util/math.h>
17#include <mgba-util/vfs.h>
18
19#define SLICE_CYCLES 2048
20
21mLOG_DEFINE_CATEGORY(DS, "DS");
22
23const uint32_t DS_ARM946ES_FREQUENCY = 0x1FF61FE;
24const uint32_t DS_ARM7TDMI_FREQUENCY = 0xFFB0FF;
25const uint32_t DS_COMPONENT_MAGIC = 0x1FF61FE;
26
27static const size_t DS_ROM_MAGIC_OFFSET = 0x15C;
28static const uint8_t DS_ROM_MAGIC[] = { 0x56, 0xCF };
29static const uint8_t DS_ROM_MAGIC_2[] = { 0x1A, 0x9E };
30
31enum {
32 DS7_SP_BASE = 0x380FD80,
33 DS7_SP_BASE_IRQ = 0x380FF80,
34 DS7_SP_BASE_SVC = 0x380FFC0,
35
36 DS9_SP_BASE = 0x3002F7C,
37 DS9_SP_BASE_IRQ = 0x3003F80,
38 DS9_SP_BASE_SVC = 0x3003FC0,
39};
40
41static void DSInit(void* cpu, struct mCPUComponent* component);
42
43static void DS7Reset(struct ARMCore* cpu);
44static void DS7TestIRQ(struct ARMCore* cpu);
45static void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh);
46static void DS7ProcessEvents(struct ARMCore* cpu);
47
48static void DS9Reset(struct ARMCore* cpu);
49static void DS9TestIRQ(struct ARMCore* cpu);
50static void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2, uint32_t value);
51static uint32_t DS9ReadCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2);
52static void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh);
53static void DS9ProcessEvents(struct ARMCore* cpu);
54
55static void DSProcessEvents(struct DSCommon* dscore);
56static void DSHitStub(struct ARMCore* cpu, uint32_t opcode);
57static void DSIllegal(struct ARMCore* cpu, uint32_t opcode);
58static void DSBreakpoint(struct ARMCore* cpu, int immediate);
59
60static void _slice(struct mTiming* timing, void* context, uint32_t cyclesLate) {
61 UNUSED(cyclesLate);
62 struct DS* ds = context;
63 uint32_t cycles = mTimingCurrentTime(timing) - ds->sliceStart;
64 if (ds->activeCpu == ds->ds9.cpu) {
65 ds->activeCpu = ds->ds7.cpu;
66 ds->cycleDrift += cycles;
67 cycles = ds->cycleDrift >> 1;
68 timing = &ds->ds7.timing;
69 } else {
70 ds->activeCpu = ds->ds9.cpu;
71 ds->cycleDrift -= cycles << 1;
72 cycles = ds->cycleDrift + SLICE_CYCLES;
73 timing = &ds->ds9.timing;
74 }
75 mTimingSchedule(timing, &ds->slice, cycles);
76 ds->sliceStart = mTimingCurrentTime(timing);
77 ds->earlyExit = true;
78}
79
80void DSCreate(struct DS* ds) {
81 ds->d.id = DS_COMPONENT_MAGIC;
82 ds->d.init = DSInit;
83 ds->d.deinit = NULL;
84 ds->ds7.p = ds;
85 ds->ds9.p = ds;
86 ds->ds7.cpu = NULL;
87 ds->ds9.cpu = NULL;
88 ds->ds7.ipc = &ds->ds9;
89 ds->ds9.ipc = &ds->ds7;
90}
91
92static void DSInit(void* cpu, struct mCPUComponent* component) {
93 struct DS* ds = (struct DS*) component;
94 struct ARMCore* core = cpu;
95 if (!ds->ds7.cpu) {
96 // The ARM7 must get initialized first
97 ds->ds7.cpu = core;
98 ds->debugger = 0;
99 ds->sync = 0;
100 return;
101 }
102 ds->ds9.cpu = cpu;
103 ds->activeCpu = NULL;
104
105 ds->ds9.cpu->cp15.r1.c0 = ARMControlRegFillVE(0);
106
107 ds->slice.name = "DS CPU Time Slicing";
108 ds->slice.callback = _slice;
109 ds->slice.context = ds;
110 ds->slice.priority = UINT_MAX;
111
112 CircleBufferInit(&ds->ds7.fifo, 64);
113 CircleBufferInit(&ds->ds9.fifo, 64);
114
115 DS7InterruptHandlerInit(&ds->ds7.cpu->irqh);
116 DS9InterruptHandlerInit(&ds->ds9.cpu->irqh);
117 DSMemoryInit(ds);
118 DSDMAInit(ds);
119
120 DSVideoInit(&ds->video);
121 ds->video.p = ds;
122
123 ds->ds7.springIRQ = 0;
124 ds->ds9.springIRQ = 0;
125 DSTimerInit(ds);
126 ds->keySource = NULL;
127 ds->rtcSource = NULL;
128 ds->rumble = NULL;
129
130 ds->romVf = NULL;
131
132 ds->keyCallback = NULL;
133
134 mTimingInit(&ds->ds7.timing, &ds->ds7.cpu->cycles, &ds->ds7.cpu->nextEvent);
135 mTimingInit(&ds->ds9.timing, &ds->ds9.cpu->cycles, &ds->ds9.cpu->nextEvent);
136}
137
138void DSUnloadROM(struct DS* ds) {
139 if (ds->romVf) {
140 ds->romVf->close(ds->romVf);
141 ds->romVf = NULL;
142 }
143}
144
145void DSDestroy(struct DS* ds) {
146 CircleBufferDeinit(&ds->ds7.fifo);
147 CircleBufferDeinit(&ds->ds9.fifo);
148 DSUnloadROM(ds);
149 DSMemoryDeinit(ds);
150 mTimingDeinit(&ds->ds7.timing);
151 mTimingDeinit(&ds->ds9.timing);
152}
153
154void DS7InterruptHandlerInit(struct ARMInterruptHandler* irqh) {
155 irqh->reset = DS7Reset;
156 irqh->processEvents = DS7ProcessEvents;
157 irqh->swi16 = DS7Swi16;
158 irqh->swi32 = DS7Swi32;
159 irqh->hitIllegal = DSIllegal;
160 irqh->readCPSR = DS7TestIRQ;
161 irqh->writeCP15 = NULL;
162 irqh->readCP15 = NULL;
163 irqh->hitStub = DSHitStub;
164 irqh->bkpt16 = DSBreakpoint;
165 irqh->bkpt32 = DSBreakpoint;
166}
167
168void DS9InterruptHandlerInit(struct ARMInterruptHandler* irqh) {
169 irqh->reset = DS9Reset;
170 irqh->processEvents = DS9ProcessEvents;
171 irqh->swi16 = DS9Swi16;
172 irqh->swi32 = DS9Swi32;
173 irqh->hitIllegal = DSIllegal;
174 irqh->readCPSR = DS9TestIRQ;
175 irqh->writeCP15 = DS9WriteCP15;
176 irqh->readCP15 = DS9ReadCP15;
177 irqh->hitStub = DSHitStub;
178 irqh->bkpt16 = DSBreakpoint;
179 irqh->bkpt32 = DSBreakpoint;
180}
181
182void DS7Reset(struct ARMCore* cpu) {
183 ARMSetPrivilegeMode(cpu, MODE_IRQ);
184 cpu->gprs[ARM_SP] = DS7_SP_BASE_IRQ;
185 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
186 cpu->gprs[ARM_SP] = DS7_SP_BASE_SVC;
187 ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
188 cpu->gprs[ARM_SP] = DS7_SP_BASE;
189
190 struct DS* ds = (struct DS*) cpu->master;
191 mTimingClear(&ds->ds7.timing);
192 CircleBufferInit(&ds->ds7.fifo, 64);
193 DSMemoryReset(ds);
194 DSDMAReset(&ds->ds7);
195 DS7IOInit(ds);
196
197 struct DSCartridge* header = ds->romVf->map(ds->romVf, sizeof(*header), MAP_READ);
198 if (header) {
199 // TODO: Error check
200 ds->romVf->seek(ds->romVf, header->arm7Offset, SEEK_SET);
201 uint32_t base = header->arm7Base - DS_BASE_RAM;
202 uint32_t* basePointer = &ds->memory.ram[base >> 2];
203 if (base < DS_SIZE_RAM && base + header->arm7Size <= DS_SIZE_RAM) {
204 ds->romVf->read(ds->romVf, basePointer, header->arm7Size);
205 }
206 cpu->gprs[12] = header->arm7Entry;
207 cpu->gprs[ARM_LR] = header->arm7Entry;
208 cpu->gprs[ARM_PC] = header->arm7Entry;
209 int currentCycles = 0;
210 ARM_WRITE_PC;
211
212 ds->romVf->unmap(ds->romVf, header, sizeof(*header));
213 }
214}
215
216void DS9Reset(struct ARMCore* cpu) {
217 ARMSetPrivilegeMode(cpu, MODE_IRQ);
218 cpu->gprs[ARM_SP] = DS9_SP_BASE_IRQ;
219 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
220 cpu->gprs[ARM_SP] = DS9_SP_BASE_SVC;
221 ARMSetPrivilegeMode(cpu, MODE_SYSTEM);
222 cpu->gprs[ARM_SP] = DS9_SP_BASE;
223
224 struct DS* ds = (struct DS*) cpu->master;
225 mTimingClear(&ds->ds9.timing);
226 CircleBufferInit(&ds->ds9.fifo, 64);
227 DSVideoReset(&ds->video);
228 DSDMAReset(&ds->ds9);
229 DS9IOInit(ds);
230
231 ds->activeCpu = cpu;
232 mTimingSchedule(&ds->ds9.timing, &ds->slice, SLICE_CYCLES);
233 ds->cycleDrift = 0;
234 ds->sliceStart = mTimingCurrentTime(&ds->ds9.timing);
235
236 struct DSCartridge* header = ds->romVf->map(ds->romVf, sizeof(*header), MAP_READ);
237 if (header) {
238 // TODO: Error check
239 ds->romVf->seek(ds->romVf, header->arm9Offset, SEEK_SET);
240 uint32_t base = header->arm9Base - DS_BASE_RAM;
241 uint32_t* basePointer = &ds->memory.ram[base >> 2];
242 if (base < DS_SIZE_RAM && base + header->arm9Size <= DS_SIZE_RAM) {
243 ds->romVf->read(ds->romVf, basePointer, header->arm9Size);
244 }
245 cpu->gprs[12] = header->arm9Entry;
246 cpu->gprs[ARM_LR] = header->arm9Entry;
247 cpu->gprs[ARM_PC] = header->arm9Entry;
248 int currentCycles = 0;
249 ARM_WRITE_PC;
250
251 ds->romVf->unmap(ds->romVf, header, sizeof(*header));
252 }
253}
254
255static void DS7ProcessEvents(struct ARMCore* cpu) {
256 struct DS* ds = (struct DS*) cpu->master;
257 DSProcessEvents(&ds->ds7);
258}
259
260static void DS9ProcessEvents(struct ARMCore* cpu) {
261 struct DS* ds = (struct DS*) cpu->master;
262 DSProcessEvents(&ds->ds9);
263}
264
265static void DSProcessEvents(struct DSCommon* dscore) {
266 struct ARMCore* cpu = dscore->cpu;
267 struct DS* ds = dscore->p;
268 if (dscore->springIRQ && !cpu->cpsr.i) {
269 ARMRaiseIRQ(cpu);
270 dscore->springIRQ = 0;
271 }
272
273 int32_t nextEvent = cpu->nextEvent;
274 while (cpu->cycles >= nextEvent) {
275 int32_t cycles = cpu->cycles;
276
277 cpu->cycles = 0;
278 cpu->nextEvent = INT_MAX;
279
280#ifndef NDEBUG
281 if (cycles < 0) {
282 mLOG(DS, FATAL, "Negative cycles passed: %i", cycles);
283 }
284#endif
285 nextEvent = cycles;
286 do {
287 nextEvent = mTimingTick(&dscore->timing, nextEvent);
288 } while (ds->cpuBlocked);
289
290 cpu->nextEvent = nextEvent;
291
292 if (ds->earlyExit) {
293 ds->earlyExit = false;
294 break;
295 }
296 if (cpu->halted) {
297 cpu->cycles = nextEvent;
298 }
299#ifndef NDEBUG
300 else if (nextEvent < 0) {
301 mLOG(DS, FATAL, "Negative cycles will pass: %i", nextEvent);
302 }
303#endif
304 }
305}
306
307void DSRunLoop(struct DS* ds) {
308 if (ds->activeCpu == ds->ds9.cpu) {
309 ARMv5RunLoop(ds->ds9.cpu);
310 } else {
311 ARMv4RunLoop(ds->ds7.cpu);
312 }
313}
314
315void DS7Step(struct DS* ds) {
316 while (ds->activeCpu == ds->ds9.cpu) {
317 ARMv5RunLoop(ds->ds9.cpu);
318 }
319 ARMv4Run(ds->ds7.cpu);
320}
321
322void DS9Step(struct DS* ds) {
323 while (ds->activeCpu == ds->ds7.cpu) {
324 ARMv4RunLoop(ds->ds7.cpu);
325 }
326 ARMv5Run(ds->ds9.cpu);
327}
328
329void DSAttachDebugger(struct DS* ds, struct mDebugger* debugger) {
330 ds->debugger = (struct ARMDebugger*) debugger->platform;
331 ds->ds7.cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
332 ds->ds9.cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d;
333 ARMHotplugAttach(ds->ds7.cpu, CPU_COMPONENT_DEBUGGER);
334 ARMHotplugAttach(ds->ds9.cpu, CPU_COMPONENT_DEBUGGER);
335}
336
337void DSDetachDebugger(struct DS* ds) {
338 ds->debugger = NULL;
339 ARMHotplugDetach(ds->ds7.cpu, CPU_COMPONENT_DEBUGGER);
340 ARMHotplugDetach(ds->ds9.cpu, CPU_COMPONENT_DEBUGGER);
341 ds->ds7.cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
342 ds->ds9.cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;
343}
344
345bool DSLoadROM(struct DS* ds, struct VFile* vf) {
346 DSUnloadROM(ds);
347 ds->romVf = vf;
348 // TODO: error check
349 return true;
350}
351
352bool DSIsROM(struct VFile* vf) {
353 if (vf->seek(vf, DS_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
354 return false;
355 }
356 uint8_t signature[sizeof(DS_ROM_MAGIC)];
357 if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) {
358 return false;
359 }
360 return memcmp(signature, DS_ROM_MAGIC, sizeof(signature)) == 0 || memcmp(signature, DS_ROM_MAGIC_2, sizeof(signature)) == 0;
361}
362
363bool DSLoadBIOS(struct DS* ds, struct VFile* vf) {
364 size_t size = vf->size(vf);
365 void* data = NULL;
366 uint32_t crc;
367 if (size == DS7_SIZE_BIOS) {
368 data = vf->map(vf, size, MAP_READ);
369 } else if (size == 0x1000) {
370 data = vf->map(vf, size, MAP_READ);
371 }
372 if (!data) {
373 return false;
374 }
375 crc = doCrc32(data, size);
376 if (crc == DS7_BIOS_CHECKSUM) {
377 ds->bios7Vf = vf;
378 ds->memory.bios7 = data;
379 mLOG(DS, INFO, "Official DS ARM7 BIOS detected");
380 } else if (crc == DS9_BIOS_CHECKSUM) {
381 ds->bios9Vf = vf;
382 ds->memory.bios9 = data;
383 mLOG(DS, INFO, "Official DS ARM9 BIOS detected");
384 } else {
385 mLOG(DS, WARN, "BIOS checksum incorrect");
386 vf->unmap(vf, data, size);
387 return false;
388 }
389 return true;
390}
391
392void DSGetGameCode(struct DS* ds, char* out) {
393 memset(out, 0, 8);
394 if (!ds->romVf) {
395 return;
396 }
397
398 struct DSCartridge* cart = ds->romVf->map(ds->romVf, sizeof(*cart), MAP_READ);
399 memcpy(out, "NTR-", 4);
400 memcpy(&out[4], &cart->id, 4);
401 ds->romVf->unmap(ds->romVf, cart, sizeof(*cart));
402}
403
404void DSGetGameTitle(struct DS* ds, char* out) {
405 memset(out, 0, 12);
406 if (!ds->romVf) {
407 return;
408 }
409
410 struct DSCartridge* cart = ds->romVf->map(ds->romVf, sizeof(*cart), MAP_READ);
411 memcpy(out, &cart->title, 4);
412 ds->romVf->unmap(ds->romVf, cart, sizeof(*cart));
413}
414
415void DSHitStub(struct ARMCore* cpu, uint32_t opcode) {
416 struct DS* ds = (struct DS*) cpu->master;
417 if (ds->debugger) {
418 struct mDebuggerEntryInfo info = {
419 .address = _ARMPCAddress(cpu),
420 .opcode = opcode
421 };
422 mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
423 }
424 // TODO: More sensible category?
425 mLOG(DS, ERROR, "Stub opcode: %08x", opcode);
426}
427
428void DSIllegal(struct ARMCore* cpu, uint32_t opcode) {
429 struct DS* ds = (struct DS*) cpu->master;
430 if (ds->debugger) {
431 struct mDebuggerEntryInfo info = {
432 .address = _ARMPCAddress(cpu),
433 .opcode = opcode
434 };
435 mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
436 } else {
437 ARMRaiseUndefined(cpu);
438 }
439}
440
441void DSBreakpoint(struct ARMCore* cpu, int immediate) {
442 struct DS* ds = (struct DS*) cpu->master;
443 if (immediate >= CPU_COMPONENT_MAX) {
444 return;
445 }
446 switch (immediate) {
447 case CPU_COMPONENT_DEBUGGER:
448 if (ds->debugger) {
449 struct mDebuggerEntryInfo info = {
450 .address = _ARMPCAddress(cpu)
451 };
452 mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info);
453 }
454 break;
455 default:
456 break;
457 }
458}
459
460void DS7TestIRQ(struct ARMCore* cpu) {
461 struct DS* ds = (struct DS*) cpu->master;
462 if (0) {
463 ds->ds7.springIRQ = 1;
464 cpu->nextEvent = cpu->cycles;
465 }
466}
467
468void DS9TestIRQ(struct ARMCore* cpu) {
469 struct DS* ds = (struct DS*) cpu->master;
470 if (0) {
471 ds->ds9.springIRQ = 1;
472 cpu->nextEvent = cpu->cycles;
473 }
474}
475
476static void _writeSysControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
477 mLOG(DS, STUB, "CP15 system control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
478}
479
480static void _writeCacheControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
481 mLOG(DS, STUB, "CP15 cache control control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
482 switch (opcode2) {
483 case 0:
484 cpu->cp15.r2.d = value;
485 break;
486 case 1:
487 cpu->cp15.r2.i = value;
488 break;
489 default:
490 mLOG(DS, GAME_ERROR, "CP15 cache control control bad op2: %i", opcode2);
491 break;
492 }
493}
494
495static void _writeWriteBufferControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
496 mLOG(DS, STUB, "CP15 write buffer control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
497 switch (opcode2) {
498 case 0:
499 cpu->cp15.r3.d = value;
500 break;
501 default:
502 mLOG(DS, GAME_ERROR, "CP15 cache control control bad op2: %i", opcode2);
503 break;
504 }
505}
506
507static void _writeAccessControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
508 mLOG(DS, STUB, "CP15 access control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
509}
510
511static void _writeRegionConfiguration(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
512 cpu->cp15.r6.region[crm] = value;
513 uint32_t base = ARMProtectionGetBase(value) << 12;
514 uint32_t size = 2 << ARMProtectionGetSize(value);
515 mLOG(DS, STUB, "CP15 region configuration write: Region: %i, Insn: %i, Base: %08X, Size: %08X", crm, opcode2, base, size);
516}
517
518static void _writeCache(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
519 switch (crm) {
520 case 0:
521 if (opcode2 == 4) {
522 ARMHalt(cpu);
523 return;
524 }
525 break;
526 }
527 mLOG(DS, STUB, "CP15 cache write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
528}
529
530static void _writeTCMControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
531 uint32_t base = ARMTCMControlGetBase(value) << 12;
532 uint32_t size = 512 << ARMTCMControlGetVirtualSize(value);
533 struct DS* ds = (struct DS*) cpu->master;
534 mLOG(DS, DEBUG, "CP15 TCM control write: CRm: %i, Op2: %i, Base: %08X, Size: %08X", crm, opcode2, base, size);
535 switch (opcode2) {
536 case 0:
537 cpu->cp15.r9.d = value;
538 ds->memory.dtcmBase = base;
539 ds->memory.dtcmSize = size;
540 break;
541 case 1:
542 cpu->cp15.r9.i = value;
543 ds->memory.itcmSize = size;
544 break;
545 default:
546 mLOG(DS, GAME_ERROR, "CP15 TCM control bad op2: %i", opcode2);
547 break;
548 }
549}
550
551void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2, uint32_t value) {
552 switch (crn) {
553 default:
554 mLOG(DS, STUB, "CP15 unknown write: CRn: %i, CRm: %i, Op1: %i, Op2: %i, Value: 0x%08X", crn, crm, opcode1, opcode2, value);
555 break;
556 case 0:
557 mLOG(DS, GAME_ERROR, "Attempted to write to read-only cp15 register");
558 ARMRaiseUndefined(cpu);
559 break;
560 case 1:
561 _writeSysControl(cpu, crm, opcode2, value);
562 break;
563 case 2:
564 _writeCacheControl(cpu, crm, opcode2, value);
565 break;
566 case 3:
567 _writeWriteBufferControl(cpu, crm, opcode2, value);
568 break;
569 case 5:
570 _writeAccessControl(cpu, crm, opcode2, value);
571 break;
572 case 6:
573 _writeRegionConfiguration(cpu, crm, opcode2, value);
574 break;
575 case 7:
576 _writeCache(cpu, crm, opcode2, value);
577 break;
578 case 9:
579 _writeTCMControl(cpu, crm, opcode2, value);
580 break;
581 }
582}
583
584static uint32_t _readTCMControl(struct ARMCore* cpu, int crm, int opcode2) {
585 switch (opcode2) {
586 case 0:
587 return cpu->cp15.r9.d;
588 case 1:
589 return cpu->cp15.r9.i;
590 default:
591 mLOG(DS, GAME_ERROR, "CP15 TCM control bad op2: %i", opcode2);
592 return 0;
593 }
594}
595
596uint32_t DS9ReadCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2) {
597 switch (crn) {
598 default:
599 mLOG(DS, STUB, "CP15 unknown read: CRn: %i, CRm: %i, Op1: %i, Op2: %i", crn, crm, opcode1, opcode2);
600 return 0;
601 case 9:
602 return _readTCMControl(cpu, crm, opcode2);
603 }
604}
605
606void DSWriteIE(struct ARMCore* cpu, uint16_t* io, uint32_t value) {
607 if (io[DS_REG_IME >> 1] && (value & io[DS_REG_IF_LO >> 1] || (value >> 16) & io[DS_REG_IF_HI >> 1])) {
608 ARMRaiseIRQ(cpu);
609 }
610}
611void DSWriteIME(struct ARMCore* cpu, uint16_t* io, uint16_t value) {
612 if (value && (io[DS_REG_IE_LO >> 1] & io[DS_REG_IF_LO >> 1] || io[DS_REG_IE_HI >> 1] & io[DS_REG_IF_HI >> 1])) {
613 ARMRaiseIRQ(cpu);
614 }
615}
616
617void DSRaiseIRQ(struct ARMCore* cpu, uint16_t* io, enum DSIRQ irq) {
618 if (irq < 16) {
619 io[DS_REG_IF_LO >> 1] |= 1 << irq;
620 } else {
621 io[DS_REG_IF_HI >> 1] |= 1 << (irq - 16);
622 }
623
624 if ((irq < 16 && (io[DS_REG_IE_LO >> 1] & 1 << irq)) || (io[DS_REG_IE_HI >> 1] & 1 << (irq - 16))) {
625 cpu->halted = 0;
626 if (io[DS_REG_IME >> 1]) {
627 ARMRaiseIRQ(cpu);
628 }
629 }
630}
631
632void DSFrameStarted(struct DS* ds) {
633 struct mCoreCallbacks* callbacks = ds->coreCallbacks;
634 if (callbacks && callbacks->videoFrameStarted) {
635 callbacks->videoFrameStarted(callbacks->context);
636 }
637}
638
639void DSFrameEnded(struct DS* ds) {
640 struct mCoreCallbacks* callbacks = ds->coreCallbacks;
641 if (callbacks && callbacks->videoFrameEnded) {
642 callbacks->videoFrameEnded(callbacks->context);
643 }
644}