all repos — mgba @ 3cd5e8d093a84fee62d1832d90a37e0bbc1870d9

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