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
10static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest);
11static void _unRl(struct GBAMemory* memory, uint32_t source, uint8_t* dest);
12
13static void _RegisterRamReset(struct GBA* gba) {
14 uint32_t registers = gba->cpu.gprs[0];
15 (void)(registers);
16 GBALog(gba, GBA_LOG_STUB, "RegisterRamReset unimplemented");
17}
18
19static void _CpuSet(struct GBA* gba) {
20 uint32_t source = gba->cpu.gprs[0];
21 uint32_t dest = gba->cpu.gprs[1];
22 uint32_t mode = gba->cpu.gprs[2];
23 int count = mode & 0x000FFFFF;
24 int fill = mode & 0x01000000;
25 int wordsize = (mode & 0x04000000) ? 4 : 2;
26 int i;
27 if (fill) {
28 if (wordsize == 4) {
29 source &= 0xFFFFFFFC;
30 dest &= 0xFFFFFFFC;
31 int32_t word = gba->memory.d.load32(&gba->memory.d, source, 0);
32 for (i = 0; i < count; ++i) {
33 gba->memory.d.store32(&gba->memory.d, dest + (i << 2), word, 0);
34 }
35 } else {
36 source &= 0xFFFFFFFE;
37 dest &= 0xFFFFFFFE;
38 uint16_t word = gba->memory.d.load16(&gba->memory.d, source, 0);
39 for (i = 0; i < count; ++i) {
40 gba->memory.d.store16(&gba->memory.d, dest + (i << 1), word, 0);
41 }
42 }
43 } else {
44 if (wordsize == 4) {
45 source &= 0xFFFFFFFC;
46 dest &= 0xFFFFFFFC;
47 for (i = 0; i < count; ++i) {
48 int32_t word = gba->memory.d.load32(&gba->memory.d, source + (i << 2), 0);
49 gba->memory.d.store32(&gba->memory.d, dest + (i << 2), word, 0);
50 }
51 } else {
52 source &= 0xFFFFFFFE;
53 dest &= 0xFFFFFFFE;
54 for (i = 0; i < count; ++i) {
55 uint16_t word = gba->memory.d.load16(&gba->memory.d, source + (i << 1), 0);
56 gba->memory.d.store16(&gba->memory.d, dest + (i << 1), word, 0);
57 }
58 }
59 }
60}
61
62static void _FastCpuSet(struct GBA* gba) {
63 uint32_t source = gba->cpu.gprs[0] & 0xFFFFFFFC;
64 uint32_t dest = gba->cpu.gprs[1] & 0xFFFFFFFC;
65 uint32_t mode = gba->cpu.gprs[2];
66 int count = mode & 0x000FFFFF;
67 count = ((count + 7) >> 3) << 3;
68 int i;
69 if (mode & 0x01000000) {
70 int32_t word = gba->memory.d.load32(&gba->memory.d, source, 0);
71 for (i = 0; i < count; ++i) {
72 gba->memory.d.store32(&gba->memory.d, dest + (i << 2), word, 0);
73 }
74 } else {
75 for (i = 0; i < count; ++i) {
76 int32_t word = gba->memory.d.load32(&gba->memory.d, source + (i << 2), 0);
77 gba->memory.d.store32(&gba->memory.d, dest + (i << 2), word, 0);
78 }
79 }
80}
81
82static void _BgAffineSet(struct GBA* gba) {
83 int i = gba->cpu.gprs[2];
84 float ox, oy;
85 float cx, cy;
86 float sx, sy;
87 float theta;
88 int offset = gba->cpu.gprs[0];
89 int destination = gba->cpu.gprs[1];
90 int diff = gba->cpu.gprs[3];
91 (void)(diff); // Are we supposed to use this?
92 float a, b, c, d;
93 float rx, ry;
94 while (i--) {
95 // [ sx 0 0 ] [ cos(theta) -sin(theta) 0 ] [ 1 0 cx - ox ] [ A B rx ]
96 // [ 0 sy 0 ] * [ sin(theta) cos(theta) 0 ] * [ 0 1 cy - oy ] = [ C D ry ]
97 // [ 0 0 1 ] [ 0 0 1 ] [ 0 0 1 ] [ 0 0 1 ]
98 ox = gba->memory.d.load32(&gba->memory.d, offset, 0) / 256.f;
99 oy = gba->memory.d.load32(&gba->memory.d, offset + 4, 0) / 256.f;
100 cx = gba->memory.d.load16(&gba->memory.d, offset + 8, 0);
101 cy = gba->memory.d.load16(&gba->memory.d, offset + 10, 0);
102 sx = gba->memory.d.load16(&gba->memory.d, offset + 12, 0) / 256.f;
103 sy = gba->memory.d.load16(&gba->memory.d, offset + 14, 0) / 256.f;
104 theta = (gba->memory.d.loadU16(&gba->memory.d, offset + 16, 0) >> 8) / 128.f * M_PI;
105 offset += 20;
106 // Rotation
107 a = d = cosf(theta);
108 b = c = sinf(theta);
109 // Scale
110 a *= sx;
111 b *= -sx;
112 c *= sy;
113 d *= sy;
114 // Translate
115 rx = ox - (a * cx + b * cy);
116 ry = oy - (c * cx + d * cy);
117 gba->memory.d.store16(&gba->memory.d, destination, a * 256, 0);
118 gba->memory.d.store16(&gba->memory.d, destination + 2, b * 256, 0);
119 gba->memory.d.store16(&gba->memory.d, destination + 4, c * 256, 0);
120 gba->memory.d.store16(&gba->memory.d, destination + 6, d * 256, 0);
121 gba->memory.d.store32(&gba->memory.d, destination + 8, rx * 256, 0);
122 gba->memory.d.store32(&gba->memory.d, destination + 12, ry * 256, 0);
123 destination += 16;
124 }
125}
126
127static void _ObjAffineSet(struct GBA* gba) {
128 int i = gba->cpu.gprs[2];
129 float sx, sy;
130 float theta;
131 int offset = gba->cpu.gprs[0];
132 int destination = gba->cpu.gprs[1];
133 int diff = gba->cpu.gprs[3];
134 float a, b, c, d;
135 while (i--) {
136 // [ sx 0 ] [ cos(theta) -sin(theta) ] [ A B ]
137 // [ 0 sy ] * [ sin(theta) cos(theta) ] = [ C D ]
138 sx = gba->memory.d.load16(&gba->memory.d, offset, 0) / 256.f;
139 sy = gba->memory.d.load16(&gba->memory.d, offset + 2, 0) / 256.f;
140 theta = (gba->memory.d.loadU16(&gba->memory.d, offset + 4, 0) >> 8) / 128.f * M_PI;
141 offset += 6;
142 // Rotation
143 a = d = cosf(theta);
144 b = c = sinf(theta);
145 // Scale
146 a *= sx;
147 b *= -sx;
148 c *= sy;
149 d *= sy;
150 gba->memory.d.store16(&gba->memory.d, destination, a * 256, 0);
151 gba->memory.d.store16(&gba->memory.d, destination + diff, b * 256, 0);
152 gba->memory.d.store16(&gba->memory.d, destination + diff * 2, c * 256, 0);
153 gba->memory.d.store16(&gba->memory.d, destination + diff * 3, d * 256, 0);
154 destination += diff * 4;
155 }
156}
157
158static void _MidiKey2Freq(struct GBA* gba) {
159 uint32_t key = gba->memory.d.load32(&gba->memory.d, gba->cpu.gprs[0] + 4, 0);
160 gba->cpu.gprs[0] = key / powf(2, (180.f - gba->cpu.gprs[1] - gba->cpu.gprs[2] / 256.f) / 12.f);
161}
162
163void GBASwi16(struct ARMBoard* board, int immediate) {
164 struct GBA* gba = ((struct GBABoard*) board)->p;
165 if (gba->memory.fullBios) {
166 ARMRaiseSWI(&gba->cpu);
167 return;
168 }
169 switch (immediate) {
170 case 0x1:
171 _RegisterRamReset(gba);
172 break;
173 case 0x2:
174 GBAHalt(gba);
175 break;
176 case 0x05:
177 // VBlankIntrWait
178 gba->cpu.gprs[0] = 1;
179 gba->cpu.gprs[1] = 1;
180 // Fall through:
181 case 0x04:
182 // IntrWait
183 gba->memory.io[REG_IME >> 1] = 1;
184 if (!gba->cpu.gprs[0] && gba->memory.io[REG_IF >> 1] & gba->cpu.gprs[1]) {
185 break;
186 }
187 gba->memory.io[REG_IF >> 1] = 0;
188 ARMRaiseSWI(&gba->cpu);
189 break;
190 case 0x6:
191 {
192 div_t result = div(gba->cpu.gprs[0], gba->cpu.gprs[1]);
193 gba->cpu.gprs[0] = result.quot;
194 gba->cpu.gprs[1] = result.rem;
195 gba->cpu.gprs[3] = abs(result.quot);
196 }
197 break;
198 case 0x7:
199 {
200 div_t result = div(gba->cpu.gprs[1], gba->cpu.gprs[0]);
201 gba->cpu.gprs[0] = result.quot;
202 gba->cpu.gprs[1] = result.rem;
203 gba->cpu.gprs[3] = abs(result.quot);
204 }
205 break;
206 case 0x8:
207 gba->cpu.gprs[0] = sqrt(gba->cpu.gprs[0]);
208 break;
209 case 0xA:
210 gba->cpu.gprs[0] = atan2f(gba->cpu.gprs[1] / 16384.f, gba->cpu.gprs[0] / 16384.f) / (2 * M_PI) * 0x10000;
211 break;
212 case 0xB:
213 _CpuSet(gba);
214 break;
215 case 0xC:
216 _FastCpuSet(gba);
217 break;
218 case 0xE:
219 _BgAffineSet(gba);
220 break;
221 case 0xF:
222 _ObjAffineSet(gba);
223 break;
224 case 0x11:
225 case 0x12:
226 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
227 case REGION_WORKING_RAM:
228 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
229 break;
230 case REGION_WORKING_IRAM:
231 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.iwram)[(gba->cpu.gprs[1] & (SIZE_WORKING_IRAM - 1))]);
232 break;
233 case REGION_VRAM:
234 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.renderer->vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
235 break;
236 default:
237 GBALog(gba, GBA_LOG_WARN, "Bad LZ77 destination");
238 break;
239 }
240 break;
241 case 0x14:
242 case 0x15:
243 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
244 case REGION_WORKING_RAM:
245 _unRl(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
246 break;
247 case REGION_WORKING_IRAM:
248 _unRl(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.iwram)[(gba->cpu.gprs[1] & (SIZE_WORKING_IRAM - 1))]);
249 break;
250 case REGION_VRAM:
251 _unRl(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.renderer->vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
252 break;
253 default:
254 GBALog(gba, GBA_LOG_WARN, "Bad RL destination");
255 break;
256 }
257 break;
258 case 0x1F:
259 _MidiKey2Freq(gba);
260 break;
261 default:
262 GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02x", immediate);
263 }
264}
265
266void GBASwi32(struct ARMBoard* board, int immediate) {
267 GBASwi16(board, immediate >> 16);
268}
269
270static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
271 int remaining = (memory->d.load32(&memory->d, source, 0) & 0xFFFFFF00) >> 8;
272 // We assume the signature byte (0x10) is correct
273 int blockheader;
274 uint32_t sPointer = source + 4;
275 uint8_t* dPointer = dest;
276 int blocksRemaining = 0;
277 int block;
278 uint8_t* disp;
279 int bytes;
280 while (remaining > 0) {
281 if (blocksRemaining) {
282 if (blockheader & 0x80) {
283 // Compressed
284 block = memory->d.loadU8(&memory->d, sPointer, 0) | (memory->d.loadU8(&memory->d, sPointer + 1, 0) << 8);
285 sPointer += 2;
286 disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1;
287 bytes = ((block & 0x00F0) >> 4) + 3;
288 while (bytes-- && remaining) {
289 --remaining;
290 *dPointer = *disp;
291 ++disp;
292 ++dPointer;
293 }
294 } else {
295 // Uncompressed
296 *dPointer = memory->d.loadU8(&memory->d, sPointer++, 0);
297 ++dPointer;
298 --remaining;
299 }
300 blockheader <<= 1;
301 --blocksRemaining;
302 } else {
303 blockheader = memory->d.loadU8(&memory->d, sPointer++, 0);
304 blocksRemaining = 8;
305 }
306 }
307}
308
309static void _unRl(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
310 source = source & 0xFFFFFFFC;
311 int remaining = (memory->d.load32(&memory->d, source, 0) & 0xFFFFFF00) >> 8;
312 int padding = (4 - remaining) & 0x3;
313 // We assume the signature byte (0x30) is correct
314 int blockheader;
315 int block;
316 uint32_t sPointer = source + 4;
317 uint8_t* dPointer = dest;
318 while (remaining > 0) {
319 blockheader = memory->d.loadU8(&memory->d, sPointer++, 0);
320 if (blockheader & 0x80) {
321 // Compressed
322 blockheader &= 0x7F;
323 blockheader += 3;
324 block = memory->d.loadU8(&memory->d, sPointer++, 0);
325 while (blockheader-- && remaining) {
326 --remaining;
327 *dPointer = block;
328 ++dPointer;
329 }
330 } else {
331 // Uncompressed
332 blockheader++;
333 while (blockheader-- && remaining) {
334 --remaining;
335 *dPointer = memory->d.loadU8(&memory->d, sPointer++, 0);
336 ++dPointer;
337 }
338 }
339 }
340 while (padding--) {
341 *dPointer = 0;
342 ++dPointer;
343 }
344}