src/gba/gba-bios.c (view raw)
1#include "gba-bios.h"
2
3#include "gba.h"
4#include "gba-io.h"
5#include "gba-memory.h"
6
7#include <math.h>
8#include <stdlib.h>
9
10const uint32_t GBA_BIOS_CHECKSUM = 0xBAAE187F;
11const uint32_t GBA_DS_BIOS_CHECKSUM = 0xBAAE1880;
12
13static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest);
14static void _unHuffman(struct GBAMemory* memory, uint32_t source, uint32_t* dest);
15static void _unRl(struct GBAMemory* memory, uint32_t source, uint8_t* dest);
16
17static void _RegisterRamReset(struct GBA* gba) {
18 uint32_t registers = gba->cpu.gprs[0];
19 (void)(registers);
20 GBALog(gba, GBA_LOG_STUB, "RegisterRamReset unimplemented");
21}
22
23static void _CpuSet(struct GBA* gba) {
24 uint32_t source = gba->cpu.gprs[0];
25 uint32_t dest = gba->cpu.gprs[1];
26 uint32_t mode = gba->cpu.gprs[2];
27 int count = mode & 0x000FFFFF;
28 int fill = mode & 0x01000000;
29 int wordsize = (mode & 0x04000000) ? 4 : 2;
30 int i;
31 if (fill) {
32 if (wordsize == 4) {
33 source &= 0xFFFFFFFC;
34 dest &= 0xFFFFFFFC;
35 int32_t word = gba->memory.d.load32(&gba->memory.d, source, &gba->cpu.cycles);
36 for (i = 0; i < count; ++i) {
37 gba->memory.d.store32(&gba->memory.d, dest + (i << 2), word, &gba->cpu.cycles);
38 gba->board.d.processEvents(&gba->board.d);
39 }
40 } else {
41 source &= 0xFFFFFFFE;
42 dest &= 0xFFFFFFFE;
43 uint16_t word = gba->memory.d.load16(&gba->memory.d, source, &gba->cpu.cycles);
44 for (i = 0; i < count; ++i) {
45 gba->memory.d.store16(&gba->memory.d, dest + (i << 1), word, &gba->cpu.cycles);
46 gba->board.d.processEvents(&gba->board.d);
47 }
48 }
49 } else {
50 if (wordsize == 4) {
51 source &= 0xFFFFFFFC;
52 dest &= 0xFFFFFFFC;
53 for (i = 0; i < count; ++i) {
54 int32_t word = gba->memory.d.load32(&gba->memory.d, source + (i << 2), &gba->cpu.cycles);
55 gba->memory.d.store32(&gba->memory.d, dest + (i << 2), word, &gba->cpu.cycles);
56 gba->board.d.processEvents(&gba->board.d);
57 }
58 } else {
59 source &= 0xFFFFFFFE;
60 dest &= 0xFFFFFFFE;
61 for (i = 0; i < count; ++i) {
62 uint16_t word = gba->memory.d.load16(&gba->memory.d, source + (i << 1), &gba->cpu.cycles);
63 gba->memory.d.store16(&gba->memory.d, dest + (i << 1), word, &gba->cpu.cycles);
64 gba->board.d.processEvents(&gba->board.d);
65 }
66 }
67 }
68}
69
70static void _FastCpuSet(struct GBA* gba) {
71 uint32_t source = gba->cpu.gprs[0] & 0xFFFFFFFC;
72 uint32_t dest = gba->cpu.gprs[1] & 0xFFFFFFFC;
73 uint32_t mode = gba->cpu.gprs[2];
74 int count = mode & 0x000FFFFF;
75 int storeCycles = gba->memory.d.waitMultiple(&gba->memory.d, dest, 4);
76 count = ((count + 7) >> 3) << 3;
77 int i;
78 if (mode & 0x01000000) {
79 int32_t word = gba->memory.d.load32(&gba->memory.d, source, &gba->cpu.cycles);
80 for (i = 0; i < count; i += 4) {
81 gba->memory.d.store32(&gba->memory.d, dest + ((i + 0) << 2), word, 0);
82 gba->memory.d.store32(&gba->memory.d, dest + ((i + 1) << 2), word, 0);
83 gba->memory.d.store32(&gba->memory.d, dest + ((i + 2) << 2), word, 0);
84 gba->memory.d.store32(&gba->memory.d, dest + ((i + 3) << 2), word, 0);
85 gba->cpu.cycles += storeCycles;
86 gba->board.d.processEvents(&gba->board.d);
87 }
88 } else {
89 int loadCycles = gba->memory.d.waitMultiple(&gba->memory.d, source, 4);
90 for (i = 0; i < count; i += 4) {
91 int32_t word0 = gba->memory.d.load32(&gba->memory.d, source + ((i + 0) << 2), 0);
92 int32_t word1 = gba->memory.d.load32(&gba->memory.d, source + ((i + 1) << 2), 0);
93 int32_t word2 = gba->memory.d.load32(&gba->memory.d, source + ((i + 2) << 2), 0);
94 int32_t word3 = gba->memory.d.load32(&gba->memory.d, source + ((i + 3) << 2), 0);
95 gba->cpu.cycles += loadCycles;
96 gba->board.d.processEvents(&gba->board.d);
97 gba->memory.d.store32(&gba->memory.d, dest + ((i + 0) << 2), word0, 0);
98 gba->memory.d.store32(&gba->memory.d, dest + ((i + 1) << 2), word1, 0);
99 gba->memory.d.store32(&gba->memory.d, dest + ((i + 2) << 2), word2, 0);
100 gba->memory.d.store32(&gba->memory.d, dest + ((i + 3) << 2), word3, 0);
101 gba->cpu.cycles += storeCycles;
102 gba->board.d.processEvents(&gba->board.d);
103 }
104 }
105}
106
107static void _BgAffineSet(struct GBA* gba) {
108 int i = gba->cpu.gprs[2];
109 float ox, oy;
110 float cx, cy;
111 float sx, sy;
112 float theta;
113 int offset = gba->cpu.gprs[0];
114 int destination = gba->cpu.gprs[1];
115 int diff = gba->cpu.gprs[3];
116 (void)(diff); // Are we supposed to use this?
117 float a, b, c, d;
118 float rx, ry;
119 while (i--) {
120 // [ sx 0 0 ] [ cos(theta) -sin(theta) 0 ] [ 1 0 cx - ox ] [ A B rx ]
121 // [ 0 sy 0 ] * [ sin(theta) cos(theta) 0 ] * [ 0 1 cy - oy ] = [ C D ry ]
122 // [ 0 0 1 ] [ 0 0 1 ] [ 0 0 1 ] [ 0 0 1 ]
123 ox = gba->memory.d.load32(&gba->memory.d, offset, 0) / 256.f;
124 oy = gba->memory.d.load32(&gba->memory.d, offset + 4, 0) / 256.f;
125 cx = gba->memory.d.load16(&gba->memory.d, offset + 8, 0);
126 cy = gba->memory.d.load16(&gba->memory.d, offset + 10, 0);
127 sx = gba->memory.d.load16(&gba->memory.d, offset + 12, 0) / 256.f;
128 sy = gba->memory.d.load16(&gba->memory.d, offset + 14, 0) / 256.f;
129 theta = (gba->memory.d.loadU16(&gba->memory.d, offset + 16, 0) >> 8) / 128.f * M_PI;
130 offset += 20;
131 // Rotation
132 a = d = cosf(theta);
133 b = c = sinf(theta);
134 // Scale
135 a *= sx;
136 b *= -sx;
137 c *= sy;
138 d *= sy;
139 // Translate
140 rx = ox - (a * cx + b * cy);
141 ry = oy - (c * cx + d * cy);
142 gba->memory.d.store16(&gba->memory.d, destination, a * 256, 0);
143 gba->memory.d.store16(&gba->memory.d, destination + 2, b * 256, 0);
144 gba->memory.d.store16(&gba->memory.d, destination + 4, c * 256, 0);
145 gba->memory.d.store16(&gba->memory.d, destination + 6, d * 256, 0);
146 gba->memory.d.store32(&gba->memory.d, destination + 8, rx * 256, 0);
147 gba->memory.d.store32(&gba->memory.d, destination + 12, ry * 256, 0);
148 destination += 16;
149 }
150}
151
152static void _ObjAffineSet(struct GBA* gba) {
153 int i = gba->cpu.gprs[2];
154 float sx, sy;
155 float theta;
156 int offset = gba->cpu.gprs[0];
157 int destination = gba->cpu.gprs[1];
158 int diff = gba->cpu.gprs[3];
159 float a, b, c, d;
160 while (i--) {
161 // [ sx 0 ] [ cos(theta) -sin(theta) ] [ A B ]
162 // [ 0 sy ] * [ sin(theta) cos(theta) ] = [ C D ]
163 sx = gba->memory.d.load16(&gba->memory.d, offset, 0) / 256.f;
164 sy = gba->memory.d.load16(&gba->memory.d, offset + 2, 0) / 256.f;
165 theta = (gba->memory.d.loadU16(&gba->memory.d, offset + 4, 0) >> 8) / 128.f * M_PI;
166 offset += 6;
167 // Rotation
168 a = d = cosf(theta);
169 b = c = sinf(theta);
170 // Scale
171 a *= sx;
172 b *= -sx;
173 c *= sy;
174 d *= sy;
175 gba->memory.d.store16(&gba->memory.d, destination, a * 256, 0);
176 gba->memory.d.store16(&gba->memory.d, destination + diff, b * 256, 0);
177 gba->memory.d.store16(&gba->memory.d, destination + diff * 2, c * 256, 0);
178 gba->memory.d.store16(&gba->memory.d, destination + diff * 3, d * 256, 0);
179 destination += diff * 4;
180 }
181}
182
183static void _MidiKey2Freq(struct GBA* gba) {
184 uint32_t key = gba->memory.d.load32(&gba->memory.d, gba->cpu.gprs[0] + 4, 0);
185 gba->cpu.gprs[0] = key / powf(2, (180.f - gba->cpu.gprs[1] - gba->cpu.gprs[2] / 256.f) / 12.f);
186}
187
188void GBASwi16(struct ARMBoard* board, int immediate) {
189 struct GBA* gba = ((struct GBABoard*) board)->p;
190 if (gba->memory.fullBios) {
191 ARMRaiseSWI(&gba->cpu);
192 return;
193 }
194 switch (immediate) {
195 case 0x1:
196 _RegisterRamReset(gba);
197 break;
198 case 0x2:
199 GBAHalt(gba);
200 break;
201 case 0x05:
202 // VBlankIntrWait
203 gba->cpu.gprs[0] = 1;
204 gba->cpu.gprs[1] = 1;
205 // Fall through:
206 case 0x04:
207 // IntrWait
208 gba->memory.io[REG_IME >> 1] = 1;
209 if (!gba->cpu.gprs[0] && gba->memory.io[REG_IF >> 1] & gba->cpu.gprs[1]) {
210 break;
211 }
212 gba->memory.io[REG_IF >> 1] = 0;
213 ARMRaiseSWI(&gba->cpu);
214 break;
215 case 0x6:
216 {
217 div_t result = div(gba->cpu.gprs[0], gba->cpu.gprs[1]);
218 gba->cpu.gprs[0] = result.quot;
219 gba->cpu.gprs[1] = result.rem;
220 gba->cpu.gprs[3] = abs(result.quot);
221 }
222 break;
223 case 0x7:
224 {
225 div_t result = div(gba->cpu.gprs[1], gba->cpu.gprs[0]);
226 gba->cpu.gprs[0] = result.quot;
227 gba->cpu.gprs[1] = result.rem;
228 gba->cpu.gprs[3] = abs(result.quot);
229 }
230 break;
231 case 0x8:
232 gba->cpu.gprs[0] = sqrt(gba->cpu.gprs[0]);
233 break;
234 case 0xA:
235 gba->cpu.gprs[0] = atan2f(gba->cpu.gprs[1] / 16384.f, gba->cpu.gprs[0] / 16384.f) / (2 * M_PI) * 0x10000;
236 break;
237 case 0xB:
238 _CpuSet(gba);
239 break;
240 case 0xC:
241 _FastCpuSet(gba);
242 break;
243 case 0xD:
244 gba->cpu.gprs[0] = GBAChecksum(gba->memory.bios, SIZE_BIOS);
245 case 0xE:
246 _BgAffineSet(gba);
247 break;
248 case 0xF:
249 _ObjAffineSet(gba);
250 break;
251 case 0x11:
252 case 0x12:
253 if (gba->cpu.gprs[0] < BASE_WORKING_RAM) {
254 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 source");
255 break;
256 }
257 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
258 case REGION_WORKING_RAM:
259 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
260 break;
261 case REGION_WORKING_IRAM:
262 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.iwram)[(gba->cpu.gprs[1] & (SIZE_WORKING_IRAM - 1))]);
263 break;
264 case REGION_VRAM:
265 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.renderer->vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
266 break;
267 default:
268 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 destination");
269 break;
270 }
271 break;
272 case 0x13:
273 if (gba->cpu.gprs[0] < BASE_WORKING_RAM) {
274 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman source");
275 break;
276 }
277 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
278 case REGION_WORKING_RAM:
279 _unHuffman(&gba->memory, gba->cpu.gprs[0], &((uint32_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 3)) >> 2]);
280 break;
281 case REGION_WORKING_IRAM:
282 _unHuffman(&gba->memory, gba->cpu.gprs[0], &((uint32_t*) gba->memory.iwram)[(gba->cpu.gprs[1] & (SIZE_WORKING_IRAM - 3)) >> 2]);
283 break;
284 case REGION_VRAM:
285 _unHuffman(&gba->memory, gba->cpu.gprs[0], &((uint32_t*) gba->video.renderer->vram)[(gba->cpu.gprs[1] & 0x0001FFFC) >> 2]);
286 break;
287 default:
288 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman destination");
289 break;
290 }
291 break;
292 case 0x14:
293 case 0x15:
294 if (gba->cpu.gprs[0] < BASE_WORKING_RAM) {
295 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL source");
296 break;
297 }
298 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
299 case REGION_WORKING_RAM:
300 _unRl(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
301 break;
302 case REGION_WORKING_IRAM:
303 _unRl(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.iwram)[(gba->cpu.gprs[1] & (SIZE_WORKING_IRAM - 1))]);
304 break;
305 case REGION_VRAM:
306 _unRl(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.renderer->vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
307 break;
308 default:
309 GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL destination");
310 break;
311 }
312 break;
313 case 0x1F:
314 _MidiKey2Freq(gba);
315 break;
316 default:
317 GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02x", immediate);
318 }
319}
320
321void GBASwi32(struct ARMBoard* board, int immediate) {
322 GBASwi16(board, immediate >> 16);
323}
324
325uint32_t GBAChecksum(uint32_t* memory, size_t size) {
326 size_t i;
327 uint32_t sum = 0;
328 for (i = 0; i < size; i += 4) {
329 sum += memory[i >> 2];
330 }
331 return sum;
332}
333
334static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
335 int remaining = (memory->d.load32(&memory->d, source, 0) & 0xFFFFFF00) >> 8;
336 // We assume the signature byte (0x10) is correct
337 int blockheader;
338 uint32_t sPointer = source + 4;
339 uint8_t* dPointer = dest;
340 int blocksRemaining = 0;
341 int block;
342 uint8_t* disp;
343 int bytes;
344 while (remaining > 0) {
345 if (blocksRemaining) {
346 if (blockheader & 0x80) {
347 // Compressed
348 block = memory->d.loadU8(&memory->d, sPointer, 0) | (memory->d.loadU8(&memory->d, sPointer + 1, 0) << 8);
349 sPointer += 2;
350 disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1;
351 bytes = ((block & 0x00F0) >> 4) + 3;
352 while (bytes-- && remaining) {
353 --remaining;
354 *dPointer = *disp;
355 ++disp;
356 ++dPointer;
357 }
358 } else {
359 // Uncompressed
360 *dPointer = memory->d.loadU8(&memory->d, sPointer++, 0);
361 ++dPointer;
362 --remaining;
363 }
364 blockheader <<= 1;
365 --blocksRemaining;
366 } else {
367 blockheader = memory->d.loadU8(&memory->d, sPointer++, 0);
368 blocksRemaining = 8;
369 }
370 }
371}
372
373static void _unHuffman(struct GBAMemory* memory, uint32_t source, uint32_t* dest) {
374 source = source & 0xFFFFFFFC;
375 uint32_t header = memory->d.load32(&memory->d, source, 0);
376 int remaining = header >> 8;
377 int bits = header & 0xF;
378 if (32 % bits) {
379 GBALog(memory->p, GBA_LOG_STUB, "Unimplemented unaligned Huffman");
380 return;
381 }
382 int padding = (4 - remaining) & 0x3;
383 remaining &= 0xFFFFFFFC;
384 // We assume the signature byte (0x20) is correct
385 //var tree = [];
386 int treesize = (memory->d.loadU8(&memory->d, source + 4, 0) << 1) + 1;
387 int block = 0;
388 uint32_t treeBase = source + 5;
389 uint32_t sPointer = source + 5 + treesize;
390 uint32_t* dPointer = dest;
391 uint32_t nPointer = treeBase;
392 union HuffmanNode {
393 struct {
394 unsigned offset : 6;
395 unsigned rTerm : 1;
396 unsigned lTerm : 1;
397 };
398 uint8_t packed;
399 } node;
400 int bitsRemaining;
401 int readBits;
402 int bitsSeen = 0;
403 node.packed = memory->d.load8(&memory->d, nPointer, 0);
404 while (remaining > 0) {
405 uint32_t bitstream = memory->d.load32(&memory->d, sPointer, 0);
406 sPointer += 4;
407 for (bitsRemaining = 32; bitsRemaining > 0; --bitsRemaining, bitstream <<= 1) {
408 uint32_t next = (nPointer & ~1) + node.offset * 2 + 2;
409 if (bitstream & 0x80000000) {
410 // Go right
411 if (node.rTerm) {
412 readBits = memory->d.load8(&memory->d, next + 1, 0);
413 } else {
414 nPointer = next + 1;
415 node.packed = memory->d.load8(&memory->d, nPointer, 0);
416 continue;
417 }
418 } else {
419 // Go left
420 if (node.lTerm) {
421 readBits = memory->d.load8(&memory->d, next, 0);
422 } else {
423 nPointer = next;
424 node.packed = memory->d.load8(&memory->d, nPointer, 0);
425 continue;
426 }
427 }
428
429 block |= (readBits & ((1 << bits) - 1)) << bitsSeen;
430 bitsSeen += bits;
431 nPointer = treeBase;
432 node.packed = memory->d.load8(&memory->d, nPointer, 0);
433 if (bitsSeen == 32) {
434 bitsSeen = 0;
435 *dPointer = block;
436 ++dPointer;
437 remaining -= 4;
438 block = 0;
439 }
440 }
441
442 }
443 if (padding) {
444 *dPointer = block;
445 }
446}
447
448static void _unRl(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
449 source = source & 0xFFFFFFFC;
450 int remaining = (memory->d.load32(&memory->d, source, 0) & 0xFFFFFF00) >> 8;
451 int padding = (4 - remaining) & 0x3;
452 // We assume the signature byte (0x30) is correct
453 int blockheader;
454 int block;
455 uint32_t sPointer = source + 4;
456 uint8_t* dPointer = dest;
457 while (remaining > 0) {
458 blockheader = memory->d.loadU8(&memory->d, sPointer++, 0);
459 if (blockheader & 0x80) {
460 // Compressed
461 blockheader &= 0x7F;
462 blockheader += 3;
463 block = memory->d.loadU8(&memory->d, sPointer++, 0);
464 while (blockheader-- && remaining) {
465 --remaining;
466 *dPointer = block;
467 ++dPointer;
468 }
469 } else {
470 // Uncompressed
471 blockheader++;
472 while (blockheader-- && remaining) {
473 --remaining;
474 *dPointer = memory->d.loadU8(&memory->d, sPointer++, 0);
475 ++dPointer;
476 }
477 }
478 }
479 while (padding--) {
480 *dPointer = 0;
481 ++dPointer;
482 }
483}