all repos — mgba @ e83936152da8f87ef9e086c71530a5a6cb9e24f4

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