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