void GBAIOWrite()

in cores/gba/src/gba/io.c [344:585]


void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
	if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address == REG_DISPCNT)) {
		value = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value);
	} else {
		switch (address) {
		// Video
		case REG_DISPSTAT:
			value &= 0xFFF8;
			GBAVideoWriteDISPSTAT(&gba->video, value);
			return;

		case REG_VCOUNT:
			mLOG(GBA_IO, GAME_ERROR, "Write to read-only I/O register: %03X", address);
			return;

		// Audio
		case REG_SOUND1CNT_LO:
			GBAAudioWriteSOUND1CNT_LO(&gba->audio, value);
			value &= 0x007F;
			break;
		case REG_SOUND1CNT_HI:
			GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);
			break;
		case REG_SOUND1CNT_X:
			GBAAudioWriteSOUND1CNT_X(&gba->audio, value);
			value &= 0x47FF;
			break;
		case REG_SOUND2CNT_LO:
			GBAAudioWriteSOUND2CNT_LO(&gba->audio, value);
			break;
		case REG_SOUND2CNT_HI:
			GBAAudioWriteSOUND2CNT_HI(&gba->audio, value);
			value &= 0x47FF;
			break;
		case REG_SOUND3CNT_LO:
			GBAAudioWriteSOUND3CNT_LO(&gba->audio, value);
			value &= 0x00E0;
			break;
		case REG_SOUND3CNT_HI:
			GBAAudioWriteSOUND3CNT_HI(&gba->audio, value);
			value &= 0xE03F;
			break;
		case REG_SOUND3CNT_X:
			GBAAudioWriteSOUND3CNT_X(&gba->audio, value);
			// TODO: The low bits need to not be readable, but still 8-bit writable
			value &= 0x47FF;
			break;
		case REG_SOUND4CNT_LO:
			GBAAudioWriteSOUND4CNT_LO(&gba->audio, value);
			value &= 0xFF3F;
			break;
		case REG_SOUND4CNT_HI:
			GBAAudioWriteSOUND4CNT_HI(&gba->audio, value);
			value &= 0x40FF;
			break;
		case REG_SOUNDCNT_LO:
			GBAAudioWriteSOUNDCNT_LO(&gba->audio, value);
			value &= 0xFF77;
			break;
		case REG_SOUNDCNT_HI:
			GBAAudioWriteSOUNDCNT_HI(&gba->audio, value);
			value &= 0x770F;
			break;
		case REG_SOUNDCNT_X:
			GBAAudioWriteSOUNDCNT_X(&gba->audio, value);
			value &= 0x0080;
			value |= gba->memory.io[REG_SOUNDCNT_X >> 1] & 0xF;
			break;
		case REG_SOUNDBIAS:
			GBAAudioWriteSOUNDBIAS(&gba->audio, value);
			break;

		case REG_WAVE_RAM0_LO:
		case REG_WAVE_RAM1_LO:
		case REG_WAVE_RAM2_LO:
		case REG_WAVE_RAM3_LO:
			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
			break;

		case REG_WAVE_RAM0_HI:
		case REG_WAVE_RAM1_HI:
		case REG_WAVE_RAM2_HI:
		case REG_WAVE_RAM3_HI:
			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
			break;

		case REG_FIFO_A_LO:
		case REG_FIFO_B_LO:
			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
			break;

		case REG_FIFO_A_HI:
		case REG_FIFO_B_HI:
			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
			break;

		// DMA
		case REG_DMA0SAD_LO:
		case REG_DMA0DAD_LO:
		case REG_DMA1SAD_LO:
		case REG_DMA1DAD_LO:
		case REG_DMA2SAD_LO:
		case REG_DMA2DAD_LO:
		case REG_DMA3SAD_LO:
		case REG_DMA3DAD_LO:
			GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value);
			break;

		case REG_DMA0SAD_HI:
		case REG_DMA0DAD_HI:
		case REG_DMA1SAD_HI:
		case REG_DMA1DAD_HI:
		case REG_DMA2SAD_HI:
		case REG_DMA2DAD_HI:
		case REG_DMA3SAD_HI:
		case REG_DMA3DAD_HI:
			GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16));
			break;

		case REG_DMA0CNT_LO:
			GBADMAWriteCNT_LO(gba, 0, value);
			break;
		case REG_DMA0CNT_HI:
			value = GBADMAWriteCNT_HI(gba, 0, value);
			break;
		case REG_DMA1CNT_LO:
			GBADMAWriteCNT_LO(gba, 1, value);
			break;
		case REG_DMA1CNT_HI:
			value = GBADMAWriteCNT_HI(gba, 1, value);
			break;
		case REG_DMA2CNT_LO:
			GBADMAWriteCNT_LO(gba, 2, value);
			break;
		case REG_DMA2CNT_HI:
			value = GBADMAWriteCNT_HI(gba, 2, value);
			break;
		case REG_DMA3CNT_LO:
			GBADMAWriteCNT_LO(gba, 3, value);
			break;
		case REG_DMA3CNT_HI:
			value = GBADMAWriteCNT_HI(gba, 3, value);
			break;

		// Timers
		case REG_TM0CNT_LO:
			GBATimerWriteTMCNT_LO(gba, 0, value);
			return;
		case REG_TM1CNT_LO:
			GBATimerWriteTMCNT_LO(gba, 1, value);
			return;
		case REG_TM2CNT_LO:
			GBATimerWriteTMCNT_LO(gba, 2, value);
			return;
		case REG_TM3CNT_LO:
			GBATimerWriteTMCNT_LO(gba, 3, value);
			return;

		case REG_TM0CNT_HI:
			value &= 0x00C7;
			GBATimerWriteTMCNT_HI(gba, 0, value);
			break;
		case REG_TM1CNT_HI:
			value &= 0x00C7;
			GBATimerWriteTMCNT_HI(gba, 1, value);
			break;
		case REG_TM2CNT_HI:
			value &= 0x00C7;
			GBATimerWriteTMCNT_HI(gba, 2, value);
			break;
		case REG_TM3CNT_HI:
			value &= 0x00C7;
			GBATimerWriteTMCNT_HI(gba, 3, value);
			break;

		// SIO
		case REG_SIOCNT:
			GBASIOWriteSIOCNT(&gba->sio, value);
			break;
		case REG_RCNT:
			value &= 0xC1FF;
			GBASIOWriteRCNT(&gba->sio, value);
			break;
		case REG_JOY_TRANS_LO:
		case REG_JOY_TRANS_HI:
			gba->memory.io[REG_JOYSTAT >> 1] |= JOYSTAT_TRANS_BIT;
			// Fall through
		case REG_SIOMLT_SEND:
		case REG_JOYCNT:
		case REG_JOYSTAT:
		case REG_JOY_RECV_LO:
		case REG_JOY_RECV_HI:
			value = GBASIOWriteRegister(&gba->sio, address, value);
			break;

		// Interrupts and misc
		case REG_KEYCNT:
			value &= 0xC3FF;
			gba->memory.io[address >> 1] = value;
			GBATestKeypadIRQ(gba);
			return;
		case REG_WAITCNT:
			value &= 0x5FFF;
			GBAAdjustWaitstates(gba, value);
			break;
		case REG_IE:
			GBAWriteIE(gba, value);
			break;
		case REG_IF:
			gba->springIRQ &= ~value;
			value = gba->memory.io[REG_IF >> 1] & ~value;
			break;
		case REG_IME:
			GBAWriteIME(gba, value);
			break;
		case REG_MAX:
			// Some bad interrupt libraries will write to this
			break;
		case REG_DEBUG_ENABLE:
			gba->debug = value == 0xC0DE;
			return;
		case REG_DEBUG_FLAGS:
			if (gba->debug) {
				GBADebug(gba, value);
				return;
			}
			// Fall through
		default:
			if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) {
				STORE_16LE(value, address - REG_DEBUG_STRING, gba->debugString);
				return;
			}
			mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address);
			if (address >= REG_MAX) {
				mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address);
				return;
			}
			break;
		}
	}
	gba->memory.io[address >> 1] = value;
}