all repos — mgba @ 74803ac15b4d22bac87b231200eeb42e7ce93d6e

mGBA Game Boy Advance Emulator

src/platform/python/mgba/memory.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
 7
 8class MemoryView(object):
 9    def __init__(self, core, width, size, base=0, sign="u"):
10        self._core = core
11        self._width = width
12        self._size = size
13        self._base = base
14        self._busRead = getattr(self._core, "busRead" + str(width * 8))
15        self._busWrite = getattr(self._core, "busWrite" + str(width * 8))
16        self._rawRead = getattr(self._core, "rawRead" + str(width * 8))
17        self._rawWrite = getattr(self._core, "rawWrite" + str(width * 8))
18        self._mask = (1 << (width * 8)) - 1 # Used to force values to fit within range so that negative values work
19        if sign == "u" or sign == "unsigned":
20            self._type = "uint{}_t".format(width * 8)
21        elif sign == "i" or sign == "s" or sign == "signed":
22            self._type = "int{}_t".format(width * 8)
23        else:
24            raise ValueError("Invalid sign type: '{}'".format(sign))
25
26    def _addrCheck(self, address):
27        if isinstance(address, slice):
28            start = address.start or 0
29            stop = self._size - self._width if address.stop is None else address.stop
30        else:
31            start = address
32            stop = address + self._width
33        if start >= self._size or stop > self._size:
34            raise IndexError()
35        if start < 0 or stop < 0:
36            raise IndexError()
37
38    def __len__(self):
39        return self._size
40
41    def __getitem__(self, address):
42        self._addrCheck(address)
43        if isinstance(address, slice):
44            start = address.start or 0
45            stop = self._size - self._width if address.stop is None else address.stop
46            step = address.step or self._width
47            return [int(ffi.cast(self._type, self._busRead(self._core, self._base + a))) for a in range(start, stop, step)]
48        else:
49            return int(ffi.cast(self._type, self._busRead(self._core, self._base + address)))
50
51    def __setitem__(self, address, value):
52        self._addrCheck(address)
53        if isinstance(address, slice):
54            start = address.start or 0
55            stop = self._size - self._width if address.stop is None else address.stop
56            step = address.step or self._width
57            for a in range(start, stop, step):
58                self._busWrite(self._core, self._base + a, value[a] & self._mask)
59        else:
60            self._busWrite(self._core, self._base + address, value & self._mask)
61
62    def rawRead(self, address, segment=-1):
63        self._addrCheck(address)
64        return int(ffi.cast(self._type, self._rawRead(self._core, self._base + address, segment)))
65
66    def rawWrite(self, address, value, segment=-1):
67        self._addrCheck(address)
68        self._rawWrite(self._core, self._base + address, segment, value & self._mask)
69
70class Memory(object):
71    def __init__(self, core, size, base=0):
72        self.size = size
73        self.base = base
74
75        self.u8 = MemoryView(core, 1, size, base, "u")
76        self.u16 = MemoryView(core, 2, size, base, "u")
77        self.u32 = MemoryView(core, 4, size, base, "u")
78        self.s8 = MemoryView(core, 1, size, base, "s")
79        self.s16 = MemoryView(core, 2, size, base, "s")
80        self.s32 = MemoryView(core, 4, size, base, "s")
81
82    def __len__(self):
83        return self._size