all repos — mgba @ f6755a6e1b7b0cf2b944cd8ca842746f11d6bf82

mGBA Game Boy Advance Emulator

src/gba/sio/joybus.c (view raw)

 1/* Copyright (c) 2013-2017 Jeffrey Pfau
 2 *
 3 * This Source Code Form is subject to the terms of the Mozilla Public
 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 6#include <mgba/internal/gba/sio.h>
 7
 8#include <mgba/internal/gba/gba.h>
 9#include <mgba/internal/gba/io.h>
10
11static uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value);
12
13void GBASIOJOYCreate(struct GBASIODriver* sio) {
14	sio->init = NULL;
15	sio->deinit = NULL;
16	sio->load = NULL;
17	sio->unload = NULL;
18	sio->writeRegister = GBASIOJOYWriteRegister;
19}
20
21uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value) {
22	switch (address) {
23	case REG_JOYCNT:
24		return (value & 0x0040) | (sio->p->p->memory.io[REG_JOYCNT >> 1] & ~(value & 0x7) & ~0x0040);
25	case REG_JOYSTAT:
26		return (value & 0x0030) | (sio->p->p->memory.io[REG_JOYSTAT >> 1] & ~0x30);
27	case REG_JOY_TRANS_LO:
28	case REG_JOY_TRANS_HI:
29		sio->p->p->memory.io[REG_JOYSTAT >> 1] |= 8;
30		break;
31	}
32	return value;
33}
34
35int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data) {
36	switch (command) {
37	case JOY_RESET:
38		sio->p->p->memory.io[REG_JOYCNT >> 1] |= 1;
39		if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
40			GBARaiseIRQ(sio->p->p, IRQ_SIO, 0);
41		}
42		// Fall through
43	case JOY_POLL:
44		data[0] = 0x00;
45		data[1] = 0x04;
46		data[2] = sio->p->p->memory.io[REG_JOYSTAT >> 1];
47		return 3;
48	case JOY_RECV:
49		sio->p->p->memory.io[REG_JOYCNT >> 1] |= 2;
50		sio->p->p->memory.io[REG_JOYSTAT >> 1] |= 2;
51
52		sio->p->p->memory.io[REG_JOY_RECV_LO >> 1] = data[0] | (data[1] << 8);
53		sio->p->p->memory.io[REG_JOY_RECV_HI >> 1] = data[2] | (data[3] << 8);
54
55		data[0] = sio->p->p->memory.io[REG_JOYSTAT >> 1];
56
57		if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
58			GBARaiseIRQ(sio->p->p, IRQ_SIO, 0);
59		}
60		return 1;
61	case JOY_TRANS:
62		sio->p->p->memory.io[REG_JOYCNT >> 1] |= 4;
63		sio->p->p->memory.io[REG_JOYSTAT >> 1] &= ~8;
64		data[0] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1];
65		data[1] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1] >> 8;
66		data[2] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1];
67		data[3] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8;
68		data[4] = sio->p->p->memory.io[REG_JOYSTAT >> 1];
69
70		if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) {
71			GBARaiseIRQ(sio->p->p, IRQ_SIO, 0);
72		}
73		return 5;
74	}
75	return 0;
76}