all repos — mgba @ f7c935f217370c86078e3c5a7603f65cb87c092c

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
  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_GPIO = lib.SIO_GPIO
 30
 31    def __init__(self, native):
 32        super(GBA, self).__init__(native)
 33        self._native = ffi.cast("struct GBA*", native.board)
 34        self.sprites = GBAObjs(self)
 35        self.cpu = ARMCore(self._core.cpu)
 36
 37    @needsReset
 38    def _initCache(self, cache):
 39        lib.GBAVideoCacheInit(cache)
 40        lib.GBAVideoCacheAssociate(cache, ffi.addressof(self._native.video))
 41
 42    def _deinitCache(self, cache):
 43        lib.mCacheSetDeinit(cache)
 44        if self._wasReset:
 45            self._native.video.renderer.cache = ffi.NULL
 46
 47    def reset(self):
 48        super(GBA, self).reset()
 49        self.memory = GBAMemory(self._core, self._native.memory.romSize)
 50
 51    def attachSIO(self, link, mode=lib.SIO_MULTI):
 52        lib.GBASIOSetDriver(ffi.addressof(self._native.sio), link._native, mode)
 53
 54createCallback("GBASIOPythonDriver", "init")
 55createCallback("GBASIOPythonDriver", "deinit")
 56createCallback("GBASIOPythonDriver", "load")
 57createCallback("GBASIOPythonDriver", "unload")
 58createCallback("GBASIOPythonDriver", "writeRegister")
 59
 60class GBASIODriver(object):
 61    def __init__(self):
 62        self._handle = ffi.new_handle(self)
 63        self._native = ffi.gc(lib.GBASIOPythonDriverCreate(self._handle), lib.free)
 64
 65    def init(self):
 66        return True
 67
 68    def deinit(self):
 69        pass
 70
 71    def load(self):
 72        return True
 73
 74    def unload(self):
 75        return True
 76
 77    def writeRegister(self, address, value):
 78        return value
 79
 80class GBAMemory(Memory):
 81    def __init__(self, core, romSize=lib.SIZE_CART0):
 82        super(GBAMemory, self).__init__(core, 0x100000000)
 83
 84        self.bios = Memory(core, lib.SIZE_BIOS, lib.BASE_BIOS)
 85        self.wram = Memory(core, lib.SIZE_WORKING_RAM, lib.BASE_WORKING_RAM)
 86        self.iwram = Memory(core, lib.SIZE_WORKING_IRAM, lib.BASE_WORKING_IRAM)
 87        self.io = Memory(core, lib.SIZE_IO, lib.BASE_IO)
 88        self.palette = Memory(core, lib.SIZE_PALETTE_RAM, lib.BASE_PALETTE_RAM)
 89        self.vram = Memory(core, lib.SIZE_VRAM, lib.BASE_VRAM)
 90        self.oam = Memory(core, lib.SIZE_OAM, lib.BASE_OAM)
 91        self.cart0 = Memory(core, romSize, lib.BASE_CART0)
 92        self.cart1 = Memory(core, romSize, lib.BASE_CART1)
 93        self.cart2 = Memory(core, romSize, lib.BASE_CART2)
 94        self.cart = self.cart0
 95        self.rom = self.cart0
 96        self.sram = Memory(core, lib.SIZE_CART_SRAM, lib.BASE_CART_SRAM)
 97
 98class GBASprite(Sprite):
 99    TILE_BASE = 0x800, 0x400
100    PALETTE_BASE = 0x10, 1
101
102    def __init__(self, obj):
103        self._a = obj.a
104        self._b = obj.b
105        self._c = obj.c
106        self.x = self._b & 0x1FF
107        self.y = self._a & 0xFF
108        self._shape = self._a >> 14
109        self._size = self._b >> 14
110        self._256Color = bool(self._a & 0x2000)
111        self.width, self.height = lib.GBAVideoObjSizes[self._shape * 4 + self._size]
112        self.tile = self._c & 0x3FF
113        if self._256Color:
114            self.paletteId = 0
115            self.tile >>= 1
116        else:
117            self.paletteId = self._c >> 12
118
119class GBAObjs:
120    def __init__(self, core):
121        self._core = core
122        self._obj = core._native.video.oam.obj
123
124    def __len__(self):
125        return 128
126
127    def __getitem__(self, index):
128        if index >= len(self):
129            raise IndexError()
130        sprite = GBASprite(self._obj[index])
131        tiles = self._core.tiles[3 if sprite._256Color else 2]
132        map1D = bool(self._core._native.memory.io[0] & 0x40)
133        sprite.constitute(tiles, 0 if map1D else 0x20)
134        return sprite