src/platform/python/mgba/gba.py (view raw)
1# Copyright (c) 2013-2016 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/.
6from ._pylib import ffi, lib
7from .arm import ARMCore
8from .core import Core, needsReset
9from .tile import Sprite
10from .memory import Memory
11from . import createCallback
12
13class GBA(Core):
14 KEY_A = lib.GBA_KEY_A
15 KEY_B = lib.GBA_KEY_B
16 KEY_SELECT = lib.GBA_KEY_SELECT
17 KEY_START = lib.GBA_KEY_START
18 KEY_DOWN = lib.GBA_KEY_DOWN
19 KEY_UP = lib.GBA_KEY_UP
20 KEY_LEFT = lib.GBA_KEY_LEFT
21 KEY_RIGHT = lib.GBA_KEY_RIGHT
22 KEY_L = lib.GBA_KEY_L
23 KEY_R = lib.GBA_KEY_R
24
25 SIO_NORMAL_8 = lib.SIO_NORMAL_8
26 SIO_NORMAL_32 = lib.SIO_NORMAL_32
27 SIO_MULTI = lib.SIO_MULTI
28 SIO_UART = lib.SIO_UART
29 SIO_JOYBUS = lib.SIO_JOYBUS
30 SIO_GPIO = lib.SIO_GPIO
31
32 def __init__(self, native):
33 super(GBA, self).__init__(native)
34 self._native = ffi.cast("struct GBA*", native.board)
35 self.sprites = GBAObjs(self)
36 self.cpu = ARMCore(self._core.cpu)
37 self._sio = set()
38
39 @needsReset
40 def _initCache(self, cache):
41 lib.GBAVideoCacheInit(cache)
42 lib.GBAVideoCacheAssociate(cache, ffi.addressof(self._native.video))
43
44 def _deinitCache(self, cache):
45 lib.mCacheSetDeinit(cache)
46 if self._wasReset:
47 self._native.video.renderer.cache = ffi.NULL
48
49 def _load(self):
50 super(GBA, self)._load()
51 self.memory = GBAMemory(self._core, self._native.memory.romSize)
52
53 def attachSIO(self, link, mode=lib.SIO_MULTI):
54 self._sio.add(mode)
55 lib.GBASIOSetDriver(ffi.addressof(self._native.sio), link._native, mode)
56
57 def __del__(self):
58 for mode in self._sio:
59 lib.GBASIOSetDriver(ffi.addressof(self._native.sio), ffi.NULL, mode)
60
61createCallback("GBASIOPythonDriver", "init")
62createCallback("GBASIOPythonDriver", "deinit")
63createCallback("GBASIOPythonDriver", "load")
64createCallback("GBASIOPythonDriver", "unload")
65createCallback("GBASIOPythonDriver", "writeRegister")
66
67class GBASIODriver(object):
68 def __init__(self):
69 self._handle = ffi.new_handle(self)
70 self._native = ffi.gc(lib.GBASIOPythonDriverCreate(self._handle), lib.free)
71
72 def init(self):
73 return True
74
75 def deinit(self):
76 pass
77
78 def load(self):
79 return True
80
81 def unload(self):
82 return True
83
84 def writeRegister(self, address, value):
85 return value
86
87class GBASIOJOYDriver(GBASIODriver):
88 RESET = lib.JOY_RESET
89 POLL = lib.JOY_POLL
90 TRANS = lib.JOY_TRANS
91 RECV = lib.JOY_RECV
92
93 def __init__(self):
94 self._handle = ffi.new_handle(self)
95 self._native = ffi.gc(lib.GBASIOJOYPythonDriverCreate(self._handle), lib.free)
96
97 def sendCommand(self, cmd, data):
98 buffer = ffi.new('uint8_t[5]')
99 try:
100 buffer[0] = data[0]
101 buffer[1] = data[1]
102 buffer[2] = data[2]
103 buffer[3] = data[3]
104 buffer[4] = data[4]
105 except IndexError:
106 pass
107
108 outlen = lib.GBASIOJOYSendCommand(self._native, cmd, buffer)
109 if outlen > 0 and outlen <= 5:
110 return bytes(buffer[0:outlen])
111 return None
112
113class GBAMemory(Memory):
114 def __init__(self, core, romSize=lib.SIZE_CART0):
115 super(GBAMemory, self).__init__(core, 0x100000000)
116
117 self.bios = Memory(core, lib.SIZE_BIOS, lib.BASE_BIOS)
118 self.wram = Memory(core, lib.SIZE_WORKING_RAM, lib.BASE_WORKING_RAM)
119 self.iwram = Memory(core, lib.SIZE_WORKING_IRAM, lib.BASE_WORKING_IRAM)
120 self.io = Memory(core, lib.SIZE_IO, lib.BASE_IO)
121 self.palette = Memory(core, lib.SIZE_PALETTE_RAM, lib.BASE_PALETTE_RAM)
122 self.vram = Memory(core, lib.SIZE_VRAM, lib.BASE_VRAM)
123 self.oam = Memory(core, lib.SIZE_OAM, lib.BASE_OAM)
124 self.cart0 = Memory(core, romSize, lib.BASE_CART0)
125 self.cart1 = Memory(core, romSize, lib.BASE_CART1)
126 self.cart2 = Memory(core, romSize, lib.BASE_CART2)
127 self.cart = self.cart0
128 self.rom = self.cart0
129 self.sram = Memory(core, lib.SIZE_CART_SRAM, lib.BASE_CART_SRAM)
130
131class GBASprite(Sprite):
132 TILE_BASE = 0x800, 0x400
133 PALETTE_BASE = 0x10, 1
134
135 def __init__(self, obj):
136 self._a = obj.a
137 self._b = obj.b
138 self._c = obj.c
139 self.x = self._b & 0x1FF
140 self.y = self._a & 0xFF
141 self._shape = self._a >> 14
142 self._size = self._b >> 14
143 self._256Color = bool(self._a & 0x2000)
144 self.width, self.height = lib.GBAVideoObjSizes[self._shape * 4 + self._size]
145 self.tile = self._c & 0x3FF
146 if self._256Color:
147 self.paletteId = 0
148 self.tile >>= 1
149 else:
150 self.paletteId = self._c >> 12
151
152class GBAObjs:
153 def __init__(self, core):
154 self._core = core
155 self._obj = core._native.video.oam.obj
156
157 def __len__(self):
158 return 128
159
160 def __getitem__(self, index):
161 if index >= len(self):
162 raise IndexError()
163 sprite = GBASprite(self._obj[index])
164 tiles = self._core.tiles[3 if sprite._256Color else 2]
165 map1D = bool(self._core._native.memory.io[0] & 0x40)
166 sprite.constitute(tiles, 0 if map1D else 0x20)
167 return sprite