all repos — mgba @ 4380ec0260036841fda2b4e539286553a7601ef2

mGBA Game Boy Advance Emulator

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}