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