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 _CpuSet(struct GBA* gba) {
13 uint32_t source = gba->cpu.gprs[0];
14 uint32_t dest = gba->cpu.gprs[1];
15 uint32_t mode = gba->cpu.gprs[2];
16 int count = mode & 0x000FFFFF;
17 int fill = mode & 0x01000000;
18 int wordsize = (mode & 0x04000000) ? 4 : 2;
19 int i;
20 if (fill) {
21 if (wordsize == 4) {
22 source &= 0xFFFFFFFC;
23 dest &= 0xFFFFFFFC;
24 int32_t word = GBALoad32(&gba->memory.d, source);
25 for (i = 0; i < count; ++i) {
26 GBAStore32(&gba->memory.d, dest + (i << 2), word);
27 }
28 } else {
29 source &= 0xFFFFFFFE;
30 dest &= 0xFFFFFFFE;
31 uint16_t word = GBALoad16(&gba->memory.d, source);
32 for (i = 0; i < count; ++i) {
33 GBAStore16(&gba->memory.d, dest + (i << 1), word);
34 }
35 }
36 } else {
37 if (wordsize == 4) {
38 source &= 0xFFFFFFFC;
39 dest &= 0xFFFFFFFC;
40 for (i = 0; i < count; ++i) {
41 int32_t word = GBALoad32(&gba->memory.d, source + (i << 2));
42 GBAStore32(&gba->memory.d, dest + (i << 2), word);
43 }
44 } else {
45 source &= 0xFFFFFFFE;
46 dest &= 0xFFFFFFFE;
47 for (i = 0; i < count; ++i) {
48 uint16_t word = GBALoad16(&gba->memory.d, source + (i << 1));
49 GBAStore16(&gba->memory.d, dest + (i << 1), word);
50 }
51 }
52 }
53}
54
55static void _FastCpuSet(struct GBA* gba) {
56 uint32_t source = gba->cpu.gprs[0] & 0xFFFFFFFC;
57 uint32_t dest = gba->cpu.gprs[1] & 0xFFFFFFFC;
58 uint32_t mode = gba->cpu.gprs[2];
59 int count = mode & 0x000FFFFF;
60 count = ((count + 7) >> 3) << 3;
61 int i;
62 if (mode & 0x01000000) {
63 int32_t word = GBALoad32(&gba->memory.d, source);
64 for (i = 0; i < count; ++i) {
65 GBAStore32(&gba->memory.d, dest + (i << 2), word);
66 }
67 } else {
68 for (i = 0; i < count; ++i) {
69 int32_t word = GBALoad32(&gba->memory.d, source + (i << 2));
70 GBAStore32(&gba->memory.d, dest + (i << 2), word);
71 }
72 }
73}
74
75static void _MidiKey2Freq(struct GBA* gba) {
76 uint32_t key = GBALoad32(&gba->memory.d, gba->cpu.gprs[0] + 4);
77 gba->cpu.gprs[0] = key / powf(2, (180.f - gba->cpu.gprs[1] - gba->cpu.gprs[2] / 256.f) / 12.f);
78}
79
80void GBASwi16(struct ARMBoard* board, int immediate) {
81 struct GBA* gba = ((struct GBABoard*) board)->p;
82 switch (immediate) {
83 case 0x2:
84 GBAHalt(gba);
85 break;
86 case 0x05:
87 // VBlankIntrWait
88 gba->cpu.gprs[0] = 1;
89 gba->cpu.gprs[1] = 1;
90 // Fall through:
91 case 0x04:
92 // IntrWait
93 gba->memory.io[REG_IME >> 1] = 1;
94 if (!gba->cpu.gprs[0] && gba->memory.io[REG_IF >> 1] & gba->cpu.gprs[1]) {
95 break;
96 }
97 gba->memory.io[REG_IF >> 1] = 0;
98 ARMRaiseSWI(&gba->cpu);
99 break;
100 case 0x6:
101 {
102 div_t result = div(gba->cpu.gprs[0], gba->cpu.gprs[1]);
103 gba->cpu.gprs[0] = result.quot;
104 gba->cpu.gprs[1] = result.rem;
105 gba->cpu.gprs[2] = abs(result.quot);
106 }
107 break;
108 case 0x7:
109 {
110 div_t result = div(gba->cpu.gprs[1], gba->cpu.gprs[0]);
111 gba->cpu.gprs[0] = result.quot;
112 gba->cpu.gprs[1] = result.rem;
113 gba->cpu.gprs[2] = abs(result.quot);
114 }
115 break;
116 case 0xB:
117 _CpuSet(gba);
118 break;
119 case 0xC:
120 _FastCpuSet(gba);
121 break;
122 case 0x11:
123 case 0x12:
124 switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
125 case REGION_WORKING_RAM:
126 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
127 break;
128 case REGION_VRAM:
129 _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
130 break;
131 default:
132 GBALog(GBA_LOG_WARN, "Bad LZ77 destination");
133 break;
134 }
135 break;
136 case 0x1F:
137 _MidiKey2Freq(gba);
138 break;
139 default:
140 GBALog(GBA_LOG_STUB, "Stub software interrupt: %02x", immediate);
141 }
142}
143
144void GBASwi32(struct ARMBoard* board, int immediate) {
145 GBASwi16(board, immediate >> 16);
146}
147
148static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
149 int remaining = (GBALoad32(&memory->d, source) & 0xFFFFFF00) >> 8;
150 // We assume the signature byte (0x10) is correct
151 int blockheader;
152 uint32_t sPointer = source + 4;
153 uint8_t* dPointer = dest;
154 int blocksRemaining = 0;
155 int block;
156 uint8_t* disp;
157 int bytes;
158 while (remaining > 0) {
159 if (blocksRemaining) {
160 if (blockheader & 0x80) {
161 // Compressed
162 block = GBALoadU8(&memory->d, sPointer) | (GBALoadU8(&memory->d, sPointer + 1) << 8);
163 sPointer += 2;
164 disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1;
165 bytes = ((block & 0x00F0) >> 4) + 3;
166 while (bytes-- && remaining) {
167 --remaining;
168 *dPointer = *disp;
169 ++disp;
170 ++dPointer;
171 }
172 } else {
173 // Uncompressed
174 *dPointer = GBALoadU8(&memory->d, sPointer++);
175 ++dPointer;
176 --remaining;
177 }
178 blockheader <<= 1;
179 --blocksRemaining;
180 } else {
181 blockheader = GBALoadU8(&memory->d, sPointer++);
182 blocksRemaining = 8;
183 }
184 }
185}