all repos — mgba @ 7c895f6091fe282f53d2f54d3e90ed5588955e2a

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