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