all repos — mgba @ 80fb86a930f9f97f339f69e0f960863850176b51

mGBA Game Boy Advance Emulator

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