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);
11
12static void _RegisterRamReset(struct GBA* gba) {
13 uint32_t registers = gba->cpu.gprs[0];
14 (void)(registers);
15 GBALog(GBA_LOG_STUB, "RegisterRamReset unimplemented");
16}
17
18static void _CpuSet(struct GBA* gba) {
19 uint32_t source = gba->cpu.gprs[0];
20 uint32_t dest = gba->cpu.gprs[1];
21 uint32_t mode = gba->cpu.gprs[2];
22 int count = mode & 0x000FFFFF;
23 int fill = mode & 0x01000000;
24 int wordsize = (mode & 0x04000000) ? 4 : 2;
25 int i;
26 if (fill) {
27 if (wordsize == 4) {
28 source &= 0xFFFFFFFC;
29 dest &= 0xFFFFFFFC;
30 int32_t word = GBALoad32(&gba->memory.d, source);
31 for (i = 0; i < count; ++i) {
32 GBAStore32(&gba->memory.d, dest + (i << 2), word);
33 }
34 } else {
35 source &= 0xFFFFFFFE;
36 dest &= 0xFFFFFFFE;
37 uint16_t word = GBALoad16(&gba->memory.d, source);
38 for (i = 0; i < count; ++i) {
39 GBAStore16(&gba->memory.d, dest + (i << 1), word);
40 }
41 }
42 } else {
43 if (wordsize == 4) {
44 source &= 0xFFFFFFFC;
45 dest &= 0xFFFFFFFC;
46 for (i = 0; i < count; ++i) {
47 int32_t word = GBALoad32(&gba->memory.d, source + (i << 2));
48 GBAStore32(&gba->memory.d, dest + (i << 2), word);
49 }
50 } else {
51 source &= 0xFFFFFFFE;
52 dest &= 0xFFFFFFFE;
53 for (i = 0; i < count; ++i) {
54 uint16_t word = GBALoad16(&gba->memory.d, source + (i << 1));
55 GBAStore16(&gba->memory.d, dest + (i << 1), word);
56 }
57 }
58 }
59}
60
61static void _FastCpuSet(struct GBA* gba) {
62 uint32_t source = gba->cpu.gprs[0] & 0xFFFFFFFC;
63 uint32_t dest = gba->cpu.gprs[1] & 0xFFFFFFFC;
64 uint32_t mode = gba->cpu.gprs[2];
65 int count = mode & 0x000FFFFF;
66 count = ((count + 7) >> 3) << 3;
67 int i;
68 if (mode & 0x01000000) {
69 int32_t word = GBALoad32(&gba->memory.d, source);
70 for (i = 0; i < count; ++i) {
71 GBAStore32(&gba->memory.d, dest + (i << 2), word);
72 }
73 } else {
74 for (i = 0; i < count; ++i) {
75 int32_t word = GBALoad32(&gba->memory.d, source + (i << 2));
76 GBAStore32(&gba->memory.d, dest + (i << 2), word);
77 }
78 }
79}
80
81static void _ObjAffineSet(struct GBA* gba) {
82 int i = gba->cpu.gprs[2];
83 float sx, sy;
84 float theta;
85 int offset = gba->cpu.gprs[0];
86 int destination = gba->cpu.gprs[1];
87 int diff = gba->cpu.gprs[3];
88 float a, b, c, d;
89 while (i--) {
90 // [ sx 0 ] [ cos(theta) -sin(theta) ] [ A B ]
91 // [ 0 sy ] * [ sin(theta) cos(theta) ] = [ C D ]
92 sx = GBALoad16(&gba->memory.d, offset) / 256.f;
93 sy = GBALoad16(&gba->memory.d, offset + 2) / 256.f;
94 theta = (GBALoadU16(&gba->memory.d, offset + 4) >> 8) / 128.f * M_PI;
95 offset += 6;
96 // Rotation
97 a = d = cosf(theta);
98 b = c = sinf(theta);
99 // Scale
100 a *= sx;
101 b *= -sx;
102 c *= sy;
103 d *= sy;
104 GBAStore16(&gba->memory.d, destination, a * 256);
105 GBAStore16(&gba->memory.d, destination + diff, b * 256);
106 GBAStore16(&gba->memory.d, destination + diff * 2, c * 256);
107 GBAStore16(&gba->memory.d, destination + diff * 3, d * 256);
108 destination += diff * 4;
109 }
110}
111
112static void _MidiKey2Freq(struct GBA* gba) {
113 uint32_t key = GBALoad32(&gba->memory.d, gba->cpu.gprs[0] + 4);
114 gba->cpu.gprs[0] = key / powf(2, (180.f - gba->cpu.gprs[1] - gba->cpu.gprs[2] / 256.f) / 12.f);
115}
116
117void GBASwi16(struct ARMBoard* board, int immediate) {
118 struct GBA* gba = ((struct GBABoard*) board)->p;
119 switch (immediate) {
120 case 0x1:
121 _RegisterRamReset(gba);
122 break;
123 case 0x2:
124 GBAHalt(gba);
125 break;
126 case 0x05:
127 // VBlankIntrWait
128 gba->cpu.gprs[0] = 1;
129 gba->cpu.gprs[1] = 1;
130 // Fall through:
131 case 0x04:
132 // IntrWait
133 gba->memory.io[REG_IME >> 1] = 1;
134 if (!gba->cpu.gprs[0] && gba->memory.io[REG_IF >> 1] & gba->cpu.gprs[1]) {
135 break;
136 }
137 gba->memory.io[REG_IF >> 1] = 0;
138 ARMRaiseSWI(&gba->cpu);
139 break;
140 case 0x6:
141 {
142 div_t result = div(gba->cpu.gprs[0], gba->cpu.gprs[1]);
143 gba->cpu.gprs[0] = result.quot;
144 gba->cpu.gprs[1] = result.rem;
145 gba->cpu.gprs[3] = abs(result.quot);
146 }
147 break;
148 case 0x7:
149 {
150 div_t result = div(gba->cpu.gprs[1], gba->cpu.gprs[0]);
151 gba->cpu.gprs[0] = result.quot;
152 gba->cpu.gprs[1] = result.rem;
153 gba->cpu.gprs[3] = abs(result.quot);
154 }
155 break;
156 case 0x8:
157 gba->cpu.gprs[0] = sqrt(gba->cpu.gprs[0]);
158 break;
159 case 0xB:
160 _CpuSet(gba);
161 break;
162 case 0xC:
163 _FastCpuSet(gba);
164 break;
165 case 0xF:
166 _ObjAffineSet(gba);
167 break;
168 case 0x11:
169 case 0x12:
170 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
171 case REGION_WORKING_RAM:
172 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
173 break;
174 case REGION_WORKING_IRAM:
175 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.iwram)[(gba->cpu.gprs[1] & (SIZE_WORKING_IRAM - 1))]);
176 break;
177 case REGION_VRAM:
178 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
179 break;
180 default:
181 GBALog(GBA_LOG_WARN, "Bad LZ77 destination");
182 break;
183 }
184 break;
185 case 0x1F:
186 _MidiKey2Freq(gba);
187 break;
188 default:
189 GBALog(GBA_LOG_STUB, "Stub software interrupt: %02x", immediate);
190 }
191}
192
193void GBASwi32(struct ARMBoard* board, int immediate) {
194 GBASwi16(board, immediate >> 16);
195}
196
197static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
198 int remaining = (GBALoad32(&memory->d, source) & 0xFFFFFF00) >> 8;
199 // We assume the signature byte (0x10) is correct
200 int blockheader;
201 uint32_t sPointer = source + 4;
202 uint8_t* dPointer = dest;
203 int blocksRemaining = 0;
204 int block;
205 uint8_t* disp;
206 int bytes;
207 while (remaining > 0) {
208 if (blocksRemaining) {
209 if (blockheader & 0x80) {
210 // Compressed
211 block = GBALoadU8(&memory->d, sPointer) | (GBALoadU8(&memory->d, sPointer + 1) << 8);
212 sPointer += 2;
213 disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1;
214 bytes = ((block & 0x00F0) >> 4) + 3;
215 while (bytes-- && remaining) {
216 --remaining;
217 *dPointer = *disp;
218 ++disp;
219 ++dPointer;
220 }
221 } else {
222 // Uncompressed
223 *dPointer = GBALoadU8(&memory->d, sPointer++);
224 ++dPointer;
225 --remaining;
226 }
227 blockheader <<= 1;
228 --blocksRemaining;
229 } else {
230 blockheader = GBALoadU8(&memory->d, sPointer++);
231 blocksRemaining = 8;
232 }
233 }
234}