1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include <math.h>
20 #include <memory.h>
21 #include <stdlib.h>
22
23 #include "GBA.h"
24 #include "bios.h"
25 #include "GBAinline.h"
26 #include "Globals.h"
27
28 s16 sineTable[256] = {
29 (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1,
30 (s16)0x0C7C, (s16)0x0E05, (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708,
31 (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D,
32 (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, (s16)0x2AFA, (s16)0x2C21,
33 (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453,
34 (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82,
35 (s16)0x3B20, (s16)0x3BB6, (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71,
36 (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB,
37 (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, (s16)0x3F4E, (s16)0x3F0E,
38 (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6,
39 (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612,
40 (s16)0x3536, (s16)0x3453, (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A,
41 (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA,
42 (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, (s16)0x1B5D, (s16)0x19EF,
43 (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05,
44 (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192,
45 (s16)0x0000, (s16)0xFE6E, (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F,
46 (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8,
47 (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, (s16)0xDF19, (s16)0xDDC3,
48 (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF,
49 (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD,
50 (s16)0xCACA, (s16)0xC9EE, (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E,
51 (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F,
52 (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, (s16)0xC014, (s16)0xC005,
53 (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2,
54 (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A,
55 (s16)0xC4E0, (s16)0xC57E, (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE,
56 (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6,
57 (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, (s16)0xD9E1, (s16)0xDB26,
58 (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611,
59 (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB,
60 (s16)0xF384, (s16)0xF50F, (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E
61 };
62
BIOS_ArcTan()63 void BIOS_ArcTan()
64 {
65 #ifdef DEV_VERSION
66 if(systemVerbose & VERBOSE_SWI) {
67 log("ArcTan: %08x (VCOUNT=%2d)\n",
68 reg[0].I,
69 VCOUNT);
70 }
71 #endif
72
73 s32 a = -((s32)(reg[0].I * reg[0].I)) >> 14;
74 s32 b = ((0xA9 * a) >> 14) + 0x390;
75 b = ((b * a) >> 14) + 0x91C;
76 b = ((b * a) >> 14) + 0xFB6;
77 b = ((b * a) >> 14) + 0x16AA;
78 b = ((b * a) >> 14) + 0x2081;
79 b = ((b * a) >> 14) + 0x3651;
80 b = ((b * a) >> 14) + 0xA2F9;
81 reg[0].I = (reg[0].I * b) >> 16;
82
83 #ifdef DEV_VERSION
84 if(systemVerbose & VERBOSE_SWI) {
85 log("ArcTan: return=%08x\n",
86 reg[0].I);
87 }
88 #endif
89 }
90
BIOS_ArcTan2()91 void BIOS_ArcTan2()
92 {
93 #ifdef DEV_VERSION
94 if(systemVerbose & VERBOSE_SWI) {
95 log("ArcTan2: %08x,%08x (VCOUNT=%2d)\n",
96 reg[0].I,
97 reg[1].I,
98 VCOUNT);
99 }
100 #endif
101
102 s16 x = reg[0].I;
103 s16 y = reg[1].I;
104
105 if (y == 0) {
106 reg[0].I = 0x8000 & x;
107 reg[3].I = 0x170;
108 } else {
109 if (x == 0) {
110 reg[0].I = (0x8000 & y) + 0x4000;
111 reg[3].I = 0x170;
112 } else {
113 if (abs(x) > abs(y)) {
114 reg[1].I = x;
115 reg[0].I = y << 14;
116 BIOS_Div();
117 BIOS_ArcTan();
118 if (x < 0)
119 reg[0].I = 0x8000 + reg[0].I;
120 else
121 reg[0].I = ((y & 0x8000) << 1 ) + reg[0].I;
122 reg[3].I = 0x170;
123 } else {
124 reg[0].I = x << 14;
125 BIOS_Div();
126 BIOS_ArcTan();
127 reg[0].I = (0x4000 + (y & 0x8000)) - reg[0].I;
128 reg[3].I = 0x170;
129 }
130 }
131 }
132
133 #ifdef DEV_VERSION
134 if(systemVerbose & VERBOSE_SWI) {
135 log("ArcTan2: return=%08x\n",
136 reg[0].I);
137 }
138 #endif
139 }
140
BIOS_BitUnPack()141 void BIOS_BitUnPack()
142 {
143 #ifdef DEV_VERSION
144 if(systemVerbose & VERBOSE_SWI) {
145 log("BitUnPack: %08x,%08x,%08x (VCOUNT=%2d)\n",
146 reg[0].I,
147 reg[1].I,
148 reg[2].I,
149 VCOUNT);
150 }
151 #endif
152
153 u32 source = reg[0].I;
154 u32 dest = reg[1].I;
155 u32 header = reg[2].I;
156
157 int len = CPUReadHalfWord(header);
158 // check address
159 int bits = CPUReadByte(header+2);
160 int revbits = 8 - bits;
161 // u32 value = 0;
162 u32 base = CPUReadMemory(header+4);
163 bool addBase = (base & 0x80000000) ? true : false;
164 base &= 0x7fffffff;
165 int dataSize = CPUReadByte(header+3);
166
167 int data = 0;
168 int bitwritecount = 0;
169 while(1) {
170 len -= 1;
171 if(len < 0)
172 break;
173 int mask = 0xff >> revbits;
174 u8 b = CPUReadByte(source);
175 source++;
176 int bitcount = 0;
177 while(1) {
178 if(bitcount >= 8)
179 break;
180 u32 d = b & mask;
181 u32 temp = d >> bitcount;
182 if(!temp && addBase) {
183 temp += base;
184 }
185 data |= temp << bitwritecount;
186 bitwritecount += dataSize;
187 if(bitwritecount >= 32) {
188 CPUWriteMemory(dest, data);
189 dest += 4;
190 data = 0;
191 bitwritecount = 0;
192 }
193 mask <<= bits;
194 bitcount += bits;
195 }
196 }
197 }
198
BIOS_BgAffineSet()199 void BIOS_BgAffineSet()
200 {
201 #ifdef DEV_VERSION
202 if(systemVerbose & VERBOSE_SWI) {
203 log("BgAffineSet: %08x,%08x,%08x (VCOUNT=%2d)\n",
204 reg[0].I,
205 reg[1].I,
206 reg[2].I,
207 VCOUNT);
208 }
209 #endif
210
211 u32 src = reg[0].I;
212 u32 dest = reg[1].I;
213 int num = reg[2].I;
214
215 for(int i = 0; i < num; i++) {
216 s32 cx = CPUReadMemory(src);
217 src+=4;
218 s32 cy = CPUReadMemory(src);
219 src+=4;
220 s16 dispx = CPUReadHalfWord(src);
221 src+=2;
222 s16 dispy = CPUReadHalfWord(src);
223 src+=2;
224 s16 rx = CPUReadHalfWord(src);
225 src+=2;
226 s16 ry = CPUReadHalfWord(src);
227 src+=2;
228 u16 theta = CPUReadHalfWord(src)>>8;
229 src+=4; // keep structure alignment
230 s32 a = sineTable[(theta+0x40)&255];
231 s32 b = sineTable[theta];
232
233 s16 dx = (rx * a)>>14;
234 s16 dmx = (rx * b)>>14;
235 s16 dy = (ry * b)>>14;
236 s16 dmy = (ry * a)>>14;
237
238 CPUWriteHalfWord(dest, dx);
239 dest += 2;
240 CPUWriteHalfWord(dest, -dmx);
241 dest += 2;
242 CPUWriteHalfWord(dest, dy);
243 dest += 2;
244 CPUWriteHalfWord(dest, dmy);
245 dest += 2;
246
247 s32 startx = cx - dx * dispx + dmx * dispy;
248 s32 starty = cy - dy * dispx - dmy * dispy;
249
250 CPUWriteMemory(dest, startx);
251 dest += 4;
252 CPUWriteMemory(dest, starty);
253 dest += 4;
254 }
255 }
256
BIOS_CpuSet()257 void BIOS_CpuSet()
258 {
259 #ifdef DEV_VERSION
260 if(systemVerbose & VERBOSE_SWI) {
261 log("CpuSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
262 reg[2].I, VCOUNT);
263 }
264 #endif
265
266 u32 source = reg[0].I;
267 u32 dest = reg[1].I;
268 u32 cnt = reg[2].I;
269
270 if(((source & 0xe000000) == 0) ||
271 ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0)
272 return;
273
274 int count = cnt & 0x1FFFFF;
275
276 // 32-bit ?
277 if((cnt >> 26) & 1) {
278 // needed for 32-bit mode!
279 source &= 0xFFFFFFFC;
280 dest &= 0xFFFFFFFC;
281 // fill ?
282 if((cnt >> 24) & 1) {
283 u32 value = CPUReadMemory(source);
284 while(count) {
285 CPUWriteMemory(dest, value);
286 dest += 4;
287 count--;
288 }
289 } else {
290 // copy
291 while(count) {
292 CPUWriteMemory(dest, CPUReadMemory(source));
293 source += 4;
294 dest += 4;
295 count--;
296 }
297 }
298 } else {
299 // 16-bit fill?
300 if((cnt >> 24) & 1) {
301 u16 value = CPUReadHalfWord(source);
302 while(count) {
303 CPUWriteHalfWord(dest, value);
304 dest += 2;
305 count--;
306 }
307 } else {
308 // copy
309 while(count) {
310 CPUWriteHalfWord(dest, CPUReadHalfWord(source));
311 source += 2;
312 dest += 2;
313 count--;
314 }
315 }
316 }
317 }
318
BIOS_CpuFastSet()319 void BIOS_CpuFastSet()
320 {
321 #ifdef DEV_VERSION
322 if(systemVerbose & VERBOSE_SWI) {
323 log("CpuFastSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
324 reg[2].I, VCOUNT);
325 }
326 #endif
327
328 u32 source = reg[0].I;
329 u32 dest = reg[1].I;
330 u32 cnt = reg[2].I;
331
332 if(((source & 0xe000000) == 0) ||
333 ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0)
334 return;
335
336 // needed for 32-bit mode!
337 source &= 0xFFFFFFFC;
338 dest &= 0xFFFFFFFC;
339
340 int count = cnt & 0x1FFFFF;
341
342 // fill?
343 if((cnt >> 24) & 1) {
344 while(count > 0) {
345 // BIOS always transfers 32 bytes at a time
346 u32 value = CPUReadMemory(source);
347 for(int i = 0; i < 8; i++) {
348 CPUWriteMemory(dest, value);
349 dest += 4;
350 }
351 count -= 8;
352 }
353 } else {
354 // copy
355 while(count > 0) {
356 // BIOS always transfers 32 bytes at a time
357 for(int i = 0; i < 8; i++) {
358 CPUWriteMemory(dest, CPUReadMemory(source));
359 source += 4;
360 dest += 4;
361 }
362 count -= 8;
363 }
364 }
365 }
366
BIOS_Diff8bitUnFilterWram()367 void BIOS_Diff8bitUnFilterWram()
368 {
369 #ifdef DEV_VERSION
370 if(systemVerbose & VERBOSE_SWI) {
371 log("Diff8bitUnFilterWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
372 reg[1].I, VCOUNT);
373 }
374 #endif
375
376 u32 source = reg[0].I;
377 u32 dest = reg[1].I;
378
379 u32 header = CPUReadMemory(source);
380 source += 4;
381
382 if(((source & 0xe000000) == 0) ||
383 ((source + ((header >> 8) & 0x1fffff) & 0xe000000) == 0))
384 return;
385
386 int len = header >> 8;
387
388 u8 data = CPUReadByte(source++);
389 CPUWriteByte(dest++, data);
390 len--;
391
392 while(len > 0) {
393 u8 diff = CPUReadByte(source++);
394 data += diff;
395 CPUWriteByte(dest++, data);
396 len--;
397 }
398 }
399
BIOS_Diff8bitUnFilterVram()400 void BIOS_Diff8bitUnFilterVram()
401 {
402 #ifdef DEV_VERSION
403 if(systemVerbose & VERBOSE_SWI) {
404 log("Diff8bitUnFilterVram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
405 reg[1].I, VCOUNT);
406 }
407 #endif
408
409 u32 source = reg[0].I;
410 u32 dest = reg[1].I;
411
412 u32 header = CPUReadMemory(source);
413 source += 4;
414
415 if(((source & 0xe000000) == 0) ||
416 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
417 return;
418
419 int len = header >> 8;
420
421 u8 data = CPUReadByte(source++);
422 u16 writeData = data;
423 int shift = 8;
424 int bytes = 1;
425
426 while(len >= 2) {
427 u8 diff = CPUReadByte(source++);
428 data += diff;
429 writeData |= (data << shift);
430 bytes++;
431 shift += 8;
432 if(bytes == 2) {
433 CPUWriteHalfWord(dest, writeData);
434 dest += 2;
435 len -= 2;
436 bytes = 0;
437 writeData = 0;
438 shift = 0;
439 }
440 }
441 }
442
BIOS_Diff16bitUnFilter()443 void BIOS_Diff16bitUnFilter()
444 {
445 #ifdef DEV_VERSION
446 if(systemVerbose & VERBOSE_SWI) {
447 log("Diff16bitUnFilter: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
448 reg[1].I, VCOUNT);
449 }
450 #endif
451
452 u32 source = reg[0].I;
453 u32 dest = reg[1].I;
454
455 u32 header = CPUReadMemory(source);
456 source += 4;
457
458 if(((source & 0xe000000) == 0) ||
459 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
460 return;
461
462 int len = header >> 8;
463
464 u16 data = CPUReadHalfWord(source);
465 source += 2;
466 CPUWriteHalfWord(dest, data);
467 dest += 2;
468 len -= 2;
469
470 while(len >= 2) {
471 u16 diff = CPUReadHalfWord(source);
472 source += 2;
473 data += diff;
474 CPUWriteHalfWord(dest, data);
475 dest += 2;
476 len -= 2;
477 }
478 }
479
BIOS_Div()480 void BIOS_Div()
481 {
482 #ifdef DEV_VERSION
483 if(systemVerbose & VERBOSE_SWI) {
484 log("Div: 0x%08x,0x%08x (VCOUNT=%d)\n",
485 reg[0].I,
486 reg[1].I,
487 VCOUNT);
488 }
489 #endif
490
491 int number = reg[0].I;
492 int denom = reg[1].I;
493
494 if(denom != 0) {
495 reg[0].I = number / denom;
496 reg[1].I = number % denom;
497 s32 temp = (s32)reg[0].I;
498 reg[3].I = temp < 0 ? (u32)-temp : (u32)temp;
499 }
500 #ifdef DEV_VERSION
501 if(systemVerbose & VERBOSE_SWI) {
502 log("Div: return=0x%08x,0x%08x,0x%08x\n",
503 reg[0].I,
504 reg[1].I,
505 reg[3].I);
506 }
507 #endif
508 }
509
BIOS_DivARM()510 void BIOS_DivARM()
511 {
512 #ifdef DEV_VERSION
513 if(systemVerbose & VERBOSE_SWI) {
514 log("DivARM: 0x%08x, (VCOUNT=%d)\n",
515 reg[0].I,
516 VCOUNT);
517 }
518 #endif
519
520 u32 temp = reg[0].I;
521 reg[0].I = reg[1].I;
522 reg[1].I = temp;
523 BIOS_Div();
524 }
525
BIOS_HuffUnComp()526 void BIOS_HuffUnComp()
527 {
528 #ifdef DEV_VERSION
529 if(systemVerbose & VERBOSE_SWI) {
530 log("HuffUnComp: 0x%08x,0x%08x (VCOUNT=%d)\n",
531 reg[0].I,
532 reg[1].I,
533 VCOUNT);
534 }
535 #endif
536
537 u32 source = reg[0].I;
538 u32 dest = reg[1].I;
539
540 u32 header = CPUReadMemory(source);
541 source += 4;
542
543 if(((source & 0xe000000) == 0) ||
544 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
545 return;
546
547 u8 treeSize = CPUReadByte(source++);
548
549 u32 treeStart = source;
550
551 source += (treeSize<<1) + 1;
552
553 int len = header >> 8;
554
555 u32 mask = 0x80000000;
556 u32 data = CPUReadMemory(source);
557 source += 4;
558
559 int pos = 0;
560 u8 rootNode = CPUReadByte(treeStart);
561 u8 currentNode = rootNode;
562 bool writeData = false;
563 int byteShift = 0;
564 int byteCount = 0;
565 u32 writeValue = 0;
566
567 if((header & 0x0F) == 8) {
568 while(len > 0) {
569 // take left
570 if(pos == 0)
571 pos++;
572 else
573 pos += (((currentNode & 0x3F)+1)<<1);
574
575 if(data & mask) {
576 // right
577 if(currentNode & 0x40)
578 writeData = true;
579 currentNode = CPUReadByte(treeStart+pos+1);
580 } else {
581 // left
582 if(currentNode & 0x80)
583 writeData = true;
584 currentNode = CPUReadByte(treeStart+pos);
585 }
586
587 if(writeData) {
588 writeValue |= (currentNode << byteShift);
589 byteCount++;
590 byteShift += 8;
591
592 pos = 0;
593 currentNode = rootNode;
594 writeData = false;
595
596 if(byteCount == 4) {
597 byteCount = 0;
598 byteShift = 0;
599 CPUWriteMemory(dest, writeValue);
600 writeValue = 0;
601 dest += 4;
602 len -= 4;
603 }
604 }
605 mask >>= 1;
606 if(mask == 0) {
607 mask = 0x80000000;
608 data = CPUReadMemory(source);
609 source += 4;
610 }
611 }
612 } else {
613 int halfLen = 0;
614 int value = 0;
615 while(len > 0) {
616 // take left
617 if(pos == 0)
618 pos++;
619 else
620 pos += (((currentNode & 0x3F)+1)<<1);
621
622 if((data & mask)) {
623 // right
624 if(currentNode & 0x40)
625 writeData = true;
626 currentNode = CPUReadByte(treeStart+pos+1);
627 } else {
628 // left
629 if(currentNode & 0x80)
630 writeData = true;
631 currentNode = CPUReadByte(treeStart+pos);
632 }
633
634 if(writeData) {
635 if(halfLen == 0)
636 value |= currentNode;
637 else
638 value |= (currentNode<<4);
639
640 halfLen += 4;
641 if(halfLen == 8) {
642 writeValue |= (value << byteShift);
643 byteCount++;
644 byteShift += 8;
645
646 halfLen = 0;
647 value = 0;
648
649 if(byteCount == 4) {
650 byteCount = 0;
651 byteShift = 0;
652 CPUWriteMemory(dest, writeValue);
653 dest += 4;
654 writeValue = 0;
655 len -= 4;
656 }
657 }
658 pos = 0;
659 currentNode = rootNode;
660 writeData = false;
661 }
662 mask >>= 1;
663 if(mask == 0) {
664 mask = 0x80000000;
665 data = CPUReadMemory(source);
666 source += 4;
667 }
668 }
669 }
670 }
671
BIOS_LZ77UnCompVram()672 void BIOS_LZ77UnCompVram()
673 {
674 #ifdef DEV_VERSION
675 if(systemVerbose & VERBOSE_SWI) {
676 log("LZ77UnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n",
677 reg[0].I,
678 reg[1].I,
679 VCOUNT);
680 }
681 #endif
682
683 u32 source = reg[0].I;
684 u32 dest = reg[1].I;
685
686 u32 header = CPUReadMemory(source);
687 source += 4;
688
689 if(((source & 0xe000000) == 0) ||
690 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
691 return;
692
693 int byteCount = 0;
694 int byteShift = 0;
695 u32 writeValue = 0;
696
697 int len = header >> 8;
698
699 while(len > 0) {
700 u8 d = CPUReadByte(source++);
701
702 if(d) {
703 for(int i = 0; i < 8; i++) {
704 if(d & 0x80) {
705 u16 data = CPUReadByte(source++) << 8;
706 data |= CPUReadByte(source++);
707 int length = (data >> 12) + 3;
708 int offset = (data & 0x0FFF);
709 u32 windowOffset = dest + byteCount - offset - 1;
710 for(int i = 0; i < length; i++) {
711 writeValue |= (CPUReadByte(windowOffset++) << byteShift);
712 byteShift += 8;
713 byteCount++;
714
715 if(byteCount == 2) {
716 CPUWriteHalfWord(dest, writeValue);
717 dest += 2;
718 byteCount = 0;
719 byteShift = 0;
720 writeValue = 0;
721 }
722 len--;
723 if(len == 0)
724 return;
725 }
726 } else {
727 writeValue |= (CPUReadByte(source++) << byteShift);
728 byteShift += 8;
729 byteCount++;
730 if(byteCount == 2) {
731 CPUWriteHalfWord(dest, writeValue);
732 dest += 2;
733 byteCount = 0;
734 byteShift = 0;
735 writeValue = 0;
736 }
737 len--;
738 if(len == 0)
739 return;
740 }
741 d <<= 1;
742 }
743 } else {
744 for(int i = 0; i < 8; i++) {
745 writeValue |= (CPUReadByte(source++) << byteShift);
746 byteShift += 8;
747 byteCount++;
748 if(byteCount == 2) {
749 CPUWriteHalfWord(dest, writeValue);
750 dest += 2;
751 byteShift = 0;
752 byteCount = 0;
753 writeValue = 0;
754 }
755 len--;
756 if(len == 0)
757 return;
758 }
759 }
760 }
761 }
762
BIOS_LZ77UnCompWram()763 void BIOS_LZ77UnCompWram()
764 {
765 #ifdef DEV_VERSION
766 if(systemVerbose & VERBOSE_SWI) {
767 log("LZ77UnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
768 VCOUNT);
769 }
770 #endif
771
772 u32 source = reg[0].I;
773 u32 dest = reg[1].I;
774
775 u32 header = CPUReadMemory(source);
776 source += 4;
777
778 if(((source & 0xe000000) == 0) ||
779 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
780 return;
781
782 int len = header >> 8;
783
784 while(len > 0) {
785 u8 d = CPUReadByte(source++);
786
787 if(d) {
788 for(int i = 0; i < 8; i++) {
789 if(d & 0x80) {
790 u16 data = CPUReadByte(source++) << 8;
791 data |= CPUReadByte(source++);
792 int length = (data >> 12) + 3;
793 int offset = (data & 0x0FFF);
794 u32 windowOffset = dest - offset - 1;
795 for(int i = 0; i < length; i++) {
796 CPUWriteByte(dest++, CPUReadByte(windowOffset++));
797 len--;
798 if(len == 0)
799 return;
800 }
801 } else {
802 CPUWriteByte(dest++, CPUReadByte(source++));
803 len--;
804 if(len == 0)
805 return;
806 }
807 d <<= 1;
808 }
809 } else {
810 for(int i = 0; i < 8; i++) {
811 CPUWriteByte(dest++, CPUReadByte(source++));
812 len--;
813 if(len == 0)
814 return;
815 }
816 }
817 }
818 }
819
BIOS_ObjAffineSet()820 void BIOS_ObjAffineSet()
821 {
822 #ifdef DEV_VERSION
823 if(systemVerbose & VERBOSE_SWI) {
824 log("ObjAffineSet: 0x%08x,0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n",
825 reg[0].I,
826 reg[1].I,
827 reg[2].I,
828 reg[3].I,
829 VCOUNT);
830 }
831 #endif
832
833 u32 src = reg[0].I;
834 u32 dest = reg[1].I;
835 int num = reg[2].I;
836 int offset = reg[3].I;
837
838 for(int i = 0; i < num; i++) {
839 s16 rx = CPUReadHalfWord(src);
840 src+=2;
841 s16 ry = CPUReadHalfWord(src);
842 src+=2;
843 u16 theta = CPUReadHalfWord(src)>>8;
844 src+=4; // keep structure alignment
845
846 s32 a = (s32)sineTable[(theta+0x40)&255];
847 s32 b = (s32)sineTable[theta];
848
849 s16 dx = ((s32)rx * a)>>14;
850 s16 dmx = ((s32)rx * b)>>14;
851 s16 dy = ((s32)ry * b)>>14;
852 s16 dmy = ((s32)ry * a)>>14;
853
854 CPUWriteHalfWord(dest, dx);
855 dest += offset;
856 CPUWriteHalfWord(dest, -dmx);
857 dest += offset;
858 CPUWriteHalfWord(dest, dy);
859 dest += offset;
860 CPUWriteHalfWord(dest, dmy);
861 dest += offset;
862 }
863 }
864
BIOS_RegisterRamReset(u32 flags)865 void BIOS_RegisterRamReset(u32 flags)
866 {
867 // no need to trace here. this is only called directly from GBA.cpp
868 // to emulate bios initialization
869
870 if(flags) {
871 if(flags & 0x01) {
872 // clear work RAM
873 memset(workRAM, 0, 0x40000);
874 }
875 if(flags & 0x02) {
876 // clear internal RAM
877 memset(internalRAM, 0, 0x7e00); // don't clear 0x7e00-0x7fff
878 }
879 if(flags & 0x04) {
880 // clear palette RAM
881 memset(paletteRAM, 0, 0x400);
882 }
883 if(flags & 0x08) {
884 // clear VRAM
885 memset(vram, 0, 0x18000);
886 }
887 if(flags & 0x10) {
888 // clean OAM
889 memset(oam, 0, 0x400);
890 }
891
892 if(flags & 0x80) {
893 int i;
894 for(i = 0; i < 8; i++)
895 CPUUpdateRegister(0x200+i*2, 0);
896
897 CPUUpdateRegister(0x202, 0xFFFF);
898
899 for(i = 0; i < 8; i++)
900 CPUUpdateRegister(0x4+i*2, 0);
901
902 for(i = 0; i < 16; i++)
903 CPUUpdateRegister(0x20+i*2, 0);
904
905 for(i = 0; i < 24; i++)
906 CPUUpdateRegister(0xb0+i*2, 0);
907
908 CPUUpdateRegister(0x130, 0);
909 CPUUpdateRegister(0x20, 0x100);
910 CPUUpdateRegister(0x30, 0x100);
911 CPUUpdateRegister(0x26, 0x100);
912 CPUUpdateRegister(0x36, 0x100);
913 }
914
915 if(flags & 0x20) {
916 int i;
917 for(i = 0; i < 8; i++)
918 CPUUpdateRegister(0x110+i*2, 0);
919 CPUUpdateRegister(0x134, 0x8000);
920 for(i = 0; i < 7; i++)
921 CPUUpdateRegister(0x140+i*2, 0);
922 }
923
924 if(flags & 0x40) {
925 int i;
926 CPUWriteByte(0x4000084, 0);
927 CPUWriteByte(0x4000084, 0x80);
928 CPUWriteMemory(0x4000080, 0x880e0000);
929 CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff);
930 CPUWriteByte(0x4000070, 0x70);
931 for(i = 0; i < 8; i++)
932 CPUUpdateRegister(0x90+i*2, 0);
933 CPUWriteByte(0x4000070, 0);
934 for(i = 0; i < 8; i++)
935 CPUUpdateRegister(0x90+i*2, 0);
936 CPUWriteByte(0x4000084, 0);
937 }
938 }
939 }
940
BIOS_RegisterRamReset()941 void BIOS_RegisterRamReset()
942 {
943 #ifdef DEV_VERSION
944 if(systemVerbose & VERBOSE_SWI) {
945 log("RegisterRamReset: 0x%08x (VCOUNT=%d)\n",
946 reg[0].I,
947 VCOUNT);
948 }
949 #endif
950
951 BIOS_RegisterRamReset(reg[0].I);
952 }
953
BIOS_RLUnCompVram()954 void BIOS_RLUnCompVram()
955 {
956 #ifdef DEV_VERSION
957 if(systemVerbose & VERBOSE_SWI) {
958 log("RLUnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n",
959 reg[0].I,
960 reg[1].I,
961 VCOUNT);
962 }
963 #endif
964
965 u32 source = reg[0].I;
966 u32 dest = reg[1].I;
967
968 u32 header = CPUReadMemory(source);
969 source += 4;
970
971 if(((source & 0xe000000) == 0) ||
972 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
973 return;
974
975 int len = header >> 8;
976 int byteCount = 0;
977 int byteShift = 0;
978 u32 writeValue = 0;
979
980 while(len > 0) {
981 u8 d = CPUReadByte(source++);
982 int l = d & 0x7F;
983 if(d & 0x80) {
984 u8 data = CPUReadByte(source++);
985 l += 3;
986 for(int i = 0;i < l; i++) {
987 writeValue |= (data << byteShift);
988 byteShift += 8;
989 byteCount++;
990
991 if(byteCount == 2) {
992 CPUWriteHalfWord(dest, writeValue);
993 dest += 2;
994 byteCount = 0;
995 byteShift = 0;
996 writeValue = 0;
997 }
998 len--;
999 if(len == 0)
1000 return;
1001 }
1002 } else {
1003 l++;
1004 for(int i = 0; i < l; i++) {
1005 writeValue |= (CPUReadByte(source++) << byteShift);
1006 byteShift += 8;
1007 byteCount++;
1008 if(byteCount == 2) {
1009 CPUWriteHalfWord(dest, writeValue);
1010 dest += 2;
1011 byteCount = 0;
1012 byteShift = 0;
1013 writeValue = 0;
1014 }
1015 len--;
1016 if(len == 0)
1017 return;
1018 }
1019 }
1020 }
1021 }
1022
BIOS_RLUnCompWram()1023 void BIOS_RLUnCompWram()
1024 {
1025 #ifdef DEV_VERSION
1026 if(systemVerbose & VERBOSE_SWI) {
1027 log("RLUnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n",
1028 reg[0].I,
1029 reg[1].I,
1030 VCOUNT);
1031 }
1032 #endif
1033
1034 u32 source = reg[0].I;
1035 u32 dest = reg[1].I;
1036
1037 u32 header = CPUReadMemory(source);
1038 source += 4;
1039
1040 if(((source & 0xe000000) == 0) ||
1041 ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
1042 return;
1043
1044 int len = header >> 8;
1045
1046 while(len > 0) {
1047 u8 d = CPUReadByte(source++);
1048 int l = d & 0x7F;
1049 if(d & 0x80) {
1050 u8 data = CPUReadByte(source++);
1051 l += 3;
1052 for(int i = 0;i < l; i++) {
1053 CPUWriteByte(dest++, data);
1054 len--;
1055 if(len == 0)
1056 return;
1057 }
1058 } else {
1059 l++;
1060 for(int i = 0; i < l; i++) {
1061 CPUWriteByte(dest++, CPUReadByte(source++));
1062 len--;
1063 if(len == 0)
1064 return;
1065 }
1066 }
1067 }
1068 }
1069
BIOS_SoftReset()1070 void BIOS_SoftReset()
1071 {
1072 #ifdef DEV_VERSION
1073 if(systemVerbose & VERBOSE_SWI) {
1074 log("SoftReset: (VCOUNT=%d)\n", VCOUNT);
1075 }
1076 #endif
1077
1078 armState = true;
1079 armMode = 0x1F;
1080 armIrqEnable = false;
1081 C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
1082 reg[13].I = 0x03007F00;
1083 reg[14].I = 0x00000000;
1084 reg[16].I = 0x00000000;
1085 reg[R13_IRQ].I = 0x03007FA0;
1086 reg[R14_IRQ].I = 0x00000000;
1087 reg[SPSR_IRQ].I = 0x00000000;
1088 reg[R13_SVC].I = 0x03007FE0;
1089 reg[R14_SVC].I = 0x00000000;
1090 reg[SPSR_SVC].I = 0x00000000;
1091 u8 b = internalRAM[0x7ffa];
1092
1093 memset(&internalRAM[0x7e00], 0, 0x200);
1094
1095 if(b) {
1096 armNextPC = 0x02000000;
1097 reg[15].I = 0x02000004;
1098 } else {
1099 armNextPC = 0x08000000;
1100 reg[15].I = 0x08000004;
1101 }
1102 }
1103
BIOS_Sqrt()1104 void BIOS_Sqrt()
1105 {
1106 #ifdef DEV_VERSION
1107 if(systemVerbose & VERBOSE_SWI) {
1108 log("Sqrt: %08x (VCOUNT=%2d)\n",
1109 reg[0].I,
1110 VCOUNT);
1111 }
1112 #endif
1113 reg[0].I = (u32)sqrt((double)reg[0].I);
1114 #ifdef DEV_VERSION
1115 if(systemVerbose & VERBOSE_SWI) {
1116 log("Sqrt: return=%08x\n",
1117 reg[0].I);
1118 }
1119 #endif
1120 }
1121
BIOS_MidiKey2Freq()1122 void BIOS_MidiKey2Freq()
1123 {
1124 #ifdef DEV_VERSION
1125 if(systemVerbose & VERBOSE_SWI) {
1126 log("MidiKey2Freq: WaveData=%08x mk=%08x fp=%08x\n",
1127 reg[0].I,
1128 reg[1].I,
1129 reg[2].I);
1130 }
1131 #endif
1132 int freq = CPUReadMemory(reg[0].I+4);
1133 double tmp;
1134 tmp = ((double)(180 - reg[1].I)) - ((double)reg[2].I / 256.f);
1135 tmp = pow((double)2.f, tmp / 12.f);
1136 reg[0].I = (int)((double)freq / tmp);
1137
1138 #ifdef DEV_VERSION
1139 if(systemVerbose & VERBOSE_SWI) {
1140 log("MidiKey2Freq: return %08x\n",
1141 reg[0].I);
1142 }
1143 #endif
1144 }
1145
BIOS_SndDriverJmpTableCopy()1146 void BIOS_SndDriverJmpTableCopy()
1147 {
1148 #ifdef DEV_VERSION
1149 if(systemVerbose & VERBOSE_SWI) {
1150 log("SndDriverJmpTableCopy: dest=%08x\n",
1151 reg[0].I);
1152 }
1153 #endif
1154 for(int i = 0; i < 0x24; i++) {
1155 CPUWriteMemory(reg[0].I, 0x9c);
1156 reg[0].I += 4;
1157 }
1158 }
1159