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 = vf->map(vf, size, MAP_READ);
420 }
421 if (!data) {
422 return false;
423 }
424 crc = doCrc32(data, size);
425 if (crc == DS7_BIOS_CHECKSUM) {
426 ds->bios7Vf = vf;
427 ds->memory.bios7 = data;
428 mLOG(DS, INFO, "Official DS ARM7 BIOS detected");
429 } else if (crc == DS9_BIOS_CHECKSUM) {
430 ds->bios9Vf = vf;
431 ds->memory.bios9 = data;
432 mLOG(DS, INFO, "Official DS ARM9 BIOS detected");
433 } else {
434 mLOG(DS, WARN, "BIOS checksum incorrect");
435 vf->unmap(vf, data, size);
436 return false;
437 }
438 return true;
439}
440
441void DSGetGameCode(struct DS* ds, char* out) {
442 memset(out, 0, 8);
443 if (!ds->romVf) {
444 return;
445 }
446
447 struct DSCartridge* cart = ds->romVf->map(ds->romVf, sizeof(*cart), MAP_READ);
448 memcpy(out, "NTR-", 4);
449 memcpy(&out[4], &cart->id, 4);
450 ds->romVf->unmap(ds->romVf, cart, sizeof(*cart));
451}
452
453void DSGetGameTitle(struct DS* ds, char* out) {
454 memset(out, 0, 12);
455 if (!ds->romVf) {
456 return;
457 }
458
459 struct DSCartridge* cart = ds->romVf->map(ds->romVf, sizeof(*cart), MAP_READ);
460 memcpy(out, &cart->title, 4);
461 ds->romVf->unmap(ds->romVf, cart, sizeof(*cart));
462}
463
464void DSHitStub(struct ARMCore* cpu, uint32_t opcode) {
465 struct DS* ds = (struct DS*) cpu->master;
466 if (ds->debugger) {
467 struct mDebuggerEntryInfo info = {
468 .address = _ARMPCAddress(cpu),
469 .opcode = opcode
470 };
471 mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
472 }
473 // TODO: More sensible category?
474 mLOG(DS, ERROR, "Stub opcode: %08x", opcode);
475}
476
477void DSIllegal(struct ARMCore* cpu, uint32_t opcode) {
478 struct DS* ds = (struct DS*) cpu->master;
479 if (ds->debugger) {
480 struct mDebuggerEntryInfo info = {
481 .address = _ARMPCAddress(cpu),
482 .opcode = opcode
483 };
484 mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info);
485 } else {
486 ARMRaiseUndefined(cpu);
487 }
488}
489
490void DSBreakpoint(struct ARMCore* cpu, int immediate) {
491 struct DS* ds = (struct DS*) cpu->master;
492 if (immediate >= CPU_COMPONENT_MAX) {
493 return;
494 }
495 switch (immediate) {
496 case CPU_COMPONENT_DEBUGGER:
497 if (ds->debugger) {
498 struct mDebuggerEntryInfo info = {
499 .address = _ARMPCAddress(cpu)
500 };
501 mDebuggerEnter(ds->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info);
502 }
503 break;
504 default:
505 break;
506 }
507}
508
509void DS7TestIRQ(struct ARMCore* cpu) {
510 struct DS* ds = (struct DS*) cpu->master;
511 if (0) {
512 ds->ds7.springIRQ = 1;
513 cpu->nextEvent = cpu->cycles;
514 }
515}
516
517void DS9TestIRQ(struct ARMCore* cpu) {
518 struct DS* ds = (struct DS*) cpu->master;
519 if (0) {
520 ds->ds9.springIRQ = 1;
521 cpu->nextEvent = cpu->cycles;
522 }
523}
524
525static void _writeSysControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
526 mLOG(DS, STUB, "CP15 system control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
527}
528
529static void _writeCacheControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
530 mLOG(DS, STUB, "CP15 cache control control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
531 switch (opcode2) {
532 case 0:
533 cpu->cp15.r2.d = value;
534 break;
535 case 1:
536 cpu->cp15.r2.i = value;
537 break;
538 default:
539 mLOG(DS, GAME_ERROR, "CP15 cache control control bad op2: %i", opcode2);
540 break;
541 }
542}
543
544static void _writeWriteBufferControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
545 mLOG(DS, STUB, "CP15 write buffer control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
546 switch (opcode2) {
547 case 0:
548 cpu->cp15.r3.d = value;
549 break;
550 default:
551 mLOG(DS, GAME_ERROR, "CP15 cache control control bad op2: %i", opcode2);
552 break;
553 }
554}
555
556static void _writeAccessControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
557 mLOG(DS, STUB, "CP15 access control write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
558}
559
560static void _writeRegionConfiguration(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
561 cpu->cp15.r6.region[crm] = value;
562 uint32_t base = ARMProtectionGetBase(value) << 12;
563 uint32_t size = 2 << ARMProtectionGetSize(value);
564 mLOG(DS, STUB, "CP15 region configuration write: Region: %i, Insn: %i, Base: %08X, Size: %08X", crm, opcode2, base, size);
565}
566
567static void _writeCache(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
568 switch (crm) {
569 case 0:
570 if (opcode2 == 4) {
571 ARMHalt(cpu);
572 return;
573 }
574 break;
575 }
576 mLOG(DS, STUB, "CP15 cache write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value);
577}
578
579static void _writeTCMControl(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) {
580 uint32_t base = ARMTCMControlGetBase(value) << 12;
581 uint32_t size = 512 << ARMTCMControlGetVirtualSize(value);
582 struct DS* ds = (struct DS*) cpu->master;
583 mLOG(DS, DEBUG, "CP15 TCM control write: CRm: %i, Op2: %i, Base: %08X, Size: %08X", crm, opcode2, base, size);
584 switch (opcode2) {
585 case 0:
586 cpu->cp15.r9.d = value;
587 ds->memory.dtcmBase = base;
588 ds->memory.dtcmSize = size;
589 break;
590 case 1:
591 cpu->cp15.r9.i = value;
592 ds->memory.itcmSize = size;
593 break;
594 default:
595 mLOG(DS, GAME_ERROR, "CP15 TCM control bad op2: %i", opcode2);
596 break;
597 }
598}
599
600void DS9WriteCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2, uint32_t value) {
601 switch (crn) {
602 default:
603 mLOG(DS, STUB, "CP15 unknown write: CRn: %i, CRm: %i, Op1: %i, Op2: %i, Value: 0x%08X", crn, crm, opcode1, opcode2, value);
604 break;
605 case 0:
606 mLOG(DS, GAME_ERROR, "Attempted to write to read-only cp15 register");
607 ARMRaiseUndefined(cpu);
608 break;
609 case 1:
610 _writeSysControl(cpu, crm, opcode2, value);
611 break;
612 case 2:
613 _writeCacheControl(cpu, crm, opcode2, value);
614 break;
615 case 3:
616 _writeWriteBufferControl(cpu, crm, opcode2, value);
617 break;
618 case 5:
619 _writeAccessControl(cpu, crm, opcode2, value);
620 break;
621 case 6:
622 _writeRegionConfiguration(cpu, crm, opcode2, value);
623 break;
624 case 7:
625 _writeCache(cpu, crm, opcode2, value);
626 break;
627 case 9:
628 _writeTCMControl(cpu, crm, opcode2, value);
629 break;
630 }
631}
632
633static uint32_t _readTCMControl(struct ARMCore* cpu, int crm, int opcode2) {
634 switch (opcode2) {
635 case 0:
636 return cpu->cp15.r9.d;
637 case 1:
638 return cpu->cp15.r9.i;
639 default:
640 mLOG(DS, GAME_ERROR, "CP15 TCM control bad op2: %i", opcode2);
641 return 0;
642 }
643}
644
645uint32_t DS9ReadCP15(struct ARMCore* cpu, int crn, int crm, int opcode1, int opcode2) {
646 switch (crn) {
647 default:
648 mLOG(DS, STUB, "CP15 unknown read: CRn: %i, CRm: %i, Op1: %i, Op2: %i", crn, crm, opcode1, opcode2);
649 return 0;
650 case 9:
651 return _readTCMControl(cpu, crm, opcode2);
652 }
653}
654
655void DSWriteIE(struct ARMCore* cpu, uint16_t* io, uint32_t value) {
656 if (io[DS_REG_IME >> 1] && (value & io[DS_REG_IF_LO >> 1] || (value >> 16) & io[DS_REG_IF_HI >> 1])) {
657 ARMRaiseIRQ(cpu);
658 }
659}
660void DSWriteIME(struct ARMCore* cpu, uint16_t* io, uint16_t value) {
661 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])) {
662 ARMRaiseIRQ(cpu);
663 }
664}
665
666void DSRaiseIRQ(struct ARMCore* cpu, uint16_t* io, enum DSIRQ irq) {
667 if (irq < 16) {
668 io[DS_REG_IF_LO >> 1] |= 1 << irq;
669 } else {
670 io[DS_REG_IF_HI >> 1] |= 1 << (irq - 16);
671 }
672
673 if ((irq < 16 && (io[DS_REG_IE_LO >> 1] & 1 << irq)) || (io[DS_REG_IE_HI >> 1] & 1 << (irq - 16))) {
674 cpu->halted = 0;
675 if (io[DS_REG_IME >> 1]) {
676 ARMRaiseIRQ(cpu);
677 }
678 }
679}
680
681void DSFrameStarted(struct DS* ds) {
682 struct mCoreCallbacks* callbacks = ds->coreCallbacks;
683 if (callbacks && callbacks->videoFrameStarted) {
684 callbacks->videoFrameStarted(callbacks->context);
685 }
686}
687
688void DSFrameEnded(struct DS* ds) {
689 struct mCoreCallbacks* callbacks = ds->coreCallbacks;
690 if (callbacks && callbacks->videoFrameEnded) {
691 callbacks->videoFrameEnded(callbacks->context);
692 }
693}