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