all repos — mgba @ 779296058787683b46550bd44538c5293eb1eb1e

mGBA Game Boy Advance Emulator

src/platform/python/mgba/gb.py (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/.
  6from ._pylib import ffi, lib
  7from .lr35902 import LR35902Core
  8from .core import Core, needsReset
  9from .memory import Memory
 10from .tile import Sprite
 11from . import createCallback
 12
 13class GB(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
 23    def __init__(self, native):
 24        super(GB, self).__init__(native)
 25        self._native = ffi.cast("struct GB*", native.board)
 26        self.sprites = GBObjs(self)
 27        self.cpu = LR35902Core(self._core.cpu)
 28
 29    @needsReset
 30    def _initCache(self, cache):
 31        lib.GBVideoCacheInit(cache)
 32        lib.GBVideoCacheAssociate(cache, ffi.addressof(self._native.video))
 33
 34    def _deinitCache(self, cache):
 35        lib.mCacheSetDeinit(cache)
 36        if self._wasReset:
 37            self._native.video.renderer.cache = ffi.NULL
 38
 39    def _load(self):
 40        super(GB, self)._load()
 41        self.memory = GBMemory(self._core)
 42
 43    def attachSIO(self, link):
 44        lib.GBSIOSetDriver(ffi.addressof(self._native.sio), link._native)
 45
 46    def __del__(self):
 47        lib.GBSIOSetDriver(ffi.addressof(self._native.sio), ffi.NULL)
 48
 49createCallback("GBSIOPythonDriver", "init")
 50createCallback("GBSIOPythonDriver", "deinit")
 51createCallback("GBSIOPythonDriver", "writeSB")
 52createCallback("GBSIOPythonDriver", "writeSC")
 53
 54class GBSIODriver(object):
 55    def __init__(self):
 56        self._handle = ffi.new_handle(self)
 57        self._native = ffi.gc(lib.GBSIOPythonDriverCreate(self._handle), lib.free)
 58
 59    def init(self):
 60        return True
 61
 62    def deinit(self):
 63        pass
 64
 65    def writeSB(self, value):
 66        pass
 67
 68    def writeSC(self, value):
 69        return value
 70
 71class GBSIOSimpleDriver(GBSIODriver):
 72    def __init__(self, period=0x100):
 73        super(GBSIOSimpleDriver, self).__init__()
 74        self.rx = 0x00
 75        self._period = period
 76
 77    def init(self):
 78        self._native.p.period = self._period
 79        return True
 80
 81    def writeSB(self, value):
 82        self.rx = value
 83
 84    def writeSC(self, value):
 85        self._native.p.period = self._period
 86        if value & 0x80:
 87            lib.mTimingDeschedule(ffi.addressof(self._native.p.p.timing), ffi.addressof(self._native.p.event))
 88            lib.mTimingSchedule(ffi.addressof(self._native.p.p.timing), ffi.addressof(self._native.p.event), self._native.p.period)
 89        return value
 90
 91    def isReady(self):
 92        return not self._native.p.remainingBits
 93
 94    @property
 95    def tx(self):
 96        self._native.p.pendingSB
 97
 98    @property
 99    def period(self):
100        return self._native.p.period
101
102    @tx.setter
103    def tx(self, newTx):
104        self._native.p.pendingSB = newTx
105        self._native.p.remainingBits = 8
106
107    @period.setter
108    def period(self, newPeriod):
109        self._period = newPeriod
110        if self._native.p:
111            self._native.p.period = newPeriod
112
113class GBMemory(Memory):
114    def __init__(self, core):
115        super(GBMemory, self).__init__(core, 0x10000)
116
117        self.cart = Memory(core, lib.GB_SIZE_CART_BANK0 * 2, lib.GB_BASE_CART_BANK0)
118        self.vram = Memory(core, lib.GB_SIZE_VRAM, lib.GB_BASE_VRAM)
119        self.sram = Memory(core, lib.GB_SIZE_EXTERNAL_RAM, lib.GB_REGION_EXTERNAL_RAM)
120        self.iwram = Memory(core, lib.GB_SIZE_WORKING_RAM_BANK0, lib.GB_BASE_WORKING_RAM_BANK0)
121        self.oam = Memory(core, lib.GB_SIZE_OAM, lib.GB_BASE_OAM)
122        self.io = Memory(core, lib.GB_SIZE_IO, lib.GB_BASE_IO)
123        self.hram = Memory(core, lib.GB_SIZE_HRAM, lib.GB_BASE_HRAM)
124
125class GBSprite(Sprite):
126    PALETTE_BASE = 8,
127
128    def __init__(self, obj, core):
129        self.x = obj.x
130        self.y = obj.y
131        self.tile = obj.tile
132        self._attr = obj.attr
133        self.width = 8
134        lcdc = core._native.memory.io[0x40]
135        self.height = 16 if lcdc & 4 else 8
136        if core._native.model >= lib.GB_MODEL_CGB:
137            if self._attr & 8:
138                self.tile += 512
139            self.paletteId = self._attr & 7
140        else:
141            self.paletteId = (self._attr >> 4) & 1
142        self.paletteId += 8
143
144
145class GBObjs:
146    def __init__(self, core):
147        self._core = core
148        self._obj = core._native.video.oam.obj
149
150    def __len__(self):
151        return 40
152
153    def __getitem__(self, index):
154        if index >= len(self):
155            raise IndexError()
156        sprite = GBSprite(self._obj[index], self._core)
157        sprite.constitute(self._core.tiles[0], 0)
158        return sprite