all repos — mgba @ 2e78381e55e6335f305c085a143d5b68098a134f

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 0xB:
109		_CpuSet(gba);
110		break;
111	case 0xC:
112		_FastCpuSet(gba);
113		break;
114	case 0x11:
115	case 0x12:
116		switch (gba->cpu.gprs[1] >> BASE_OFFSET) {
117			case REGION_WORKING_RAM:
118				_unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]);
119				break;
120			case REGION_VRAM:
121				_unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.vram)[(gba->cpu.gprs[1] & 0x0001FFFF)]);
122				break;
123			default:
124				GBALog(GBA_LOG_WARN, "Bad LZ77 destination");
125				break;
126		}
127		break;
128	case 0x1F:
129		_MidiKey2Freq(gba);
130		break;
131	default:
132		GBALog(GBA_LOG_STUB, "Stub software interrupt: %02x", immediate);
133	}
134}
135
136void GBASwi32(struct ARMBoard* board, int immediate) {
137	GBASwi16(board, immediate >> 16);
138}
139
140static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest) {
141	int remaining = (GBALoad32(&memory->d, source) & 0xFFFFFF00) >> 8;
142	// We assume the signature byte (0x10) is correct
143	int blockheader;
144	uint32_t sPointer = source + 4;
145	uint8_t* dPointer = dest;
146	int blocksRemaining = 0;
147	int block;
148	uint8_t* disp;
149	int bytes;
150	while (remaining > 0) {
151		if (blocksRemaining) {
152			if (blockheader & 0x80) {
153				// Compressed
154				block = GBALoadU8(&memory->d, sPointer) | (GBALoadU8(&memory->d, sPointer + 1) << 8);
155				sPointer += 2;
156				disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1;
157				bytes = ((block & 0x00F0) >> 4) + 3;
158				while (bytes-- && remaining) {
159					--remaining;
160					*dPointer = *disp;
161					++disp;
162					++dPointer;
163				}
164			} else {
165				// Uncompressed
166				*dPointer = GBALoadU8(&memory->d, sPointer++);
167				++dPointer;
168				--remaining;
169			}
170			blockheader <<= 1;
171			--blocksRemaining;
172		} else {
173			blockheader = GBALoadU8(&memory->d, sPointer++);
174			blocksRemaining = 8;
175		}
176	}
177}