Skip to content

Commit

Permalink
Change PyPy array to memoryview to merge code with Cython
Browse files Browse the repository at this point in the history
  • Loading branch information
Baekalfen committed Nov 15, 2023
1 parent 9d93bc4 commit 4ffcb73
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 172 deletions.
9 changes: 5 additions & 4 deletions pyboy/core/cartridge/base_mbc.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

from pyboy.utils cimport IntIOInterface
from pyboy.core.cartridge.rtc cimport RTC
from libc.stdint cimport uint8_t, uint16_t, uint32_t

from pyboy.core.cartridge.rtc cimport RTC
from pyboy.utils cimport IntIOInterface


cdef class BaseMBC:
cdef str filename
cdef str gamename
cdef uint8_t[:, :] rombanks
# 16 is absoulte max. 8KB in each bank
cdef uint8_t[16][8 * 1024] rambanks
cdef uint8_t[:,:] rambanks
cdef uint8_t carttype
cdef bint battery
cdef bint rtc_enabled
Expand Down
24 changes: 12 additions & 12 deletions pyboy/core/cartridge/base_mbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def save_ram(self, f):

for bank in range(self.external_ram_count):
for byte in range(8 * 1024):
f.write(self.rambanks[bank][byte])
f.write(self.rambanks[bank, byte])

logger.debug("RAM saved.")

Expand All @@ -89,18 +89,18 @@ def load_ram(self, f):

for bank in range(self.external_ram_count):
for byte in range(8 * 1024):
self.rambanks[bank][byte] = f.read()
self.rambanks[bank, byte] = f.read()

logger.debug("RAM loaded.")

def init_rambanks(self, n):
self.rambank_initialized = True
# In real life the values in RAM are scrambled on initialization.
# Allocating the maximum, as it is easier in Cython. And it's just 128KB...
self.rambanks = [array.array("B", [0] * (8*1024)) for _ in range(16)]
self.rambanks = memoryview(array.array("B", [0] * (8*1024*16))).cast("B", shape=(16, 8 * 1024))

def getgamename(self, rombanks):
return "".join([chr(x) for x in rombanks[0][0x0134:0x0142]]).split("\0")[0]
return "".join([chr(rombanks[0, x]) for x in range(0x0134, 0x0142)]).split("\0")[0]

def setitem(self, address, value):
raise Exception("Cannot set item in MBC")
Expand All @@ -109,17 +109,17 @@ def overrideitem(self, rom_bank, address, value):
if 0x0000 <= address < 0x4000:
logger.debug(
"Performing overwrite on address: %s:%s. New value: %s Old value: %s" %
(hex(rom_bank), hex(address), hex(value), self.rombanks[rom_bank][address])
(hex(rom_bank), hex(address), hex(value), self.rombanks[rom_bank, address])
)
self.rombanks[rom_bank][address] = value
self.rombanks[rom_bank, address] = value
else:
logger.error("Invalid override address: %s" % hex(address))

def getitem(self, address):
if 0x0000 <= address < 0x4000:
return self.rombanks[0][address]
return self.rombanks[0, address]
elif 0x4000 <= address < 0x8000:
return self.rombanks[self.rombank_selected][address - 0x4000]
return self.rombanks[self.rombank_selected, address - 0x4000]
elif 0xA000 <= address < 0xC000:
# if not self.rambank_initialized:
# logger.error("RAM banks not initialized: %s" % hex(address))
Expand All @@ -130,7 +130,7 @@ def getitem(self, address):
if self.rtc_enabled and 0x08 <= self.rambank_selected <= 0x0C:
return self.rtc.getregister(self.rambank_selected)
else:
return self.rambanks[self.rambank_selected][address - 0xA000]
return self.rambanks[self.rambank_selected, address - 0xA000]
# else:
# logger.error("Reading address invalid: %s" % address)

Expand All @@ -139,7 +139,7 @@ def __repr__(self):
"Cartridge:",
"Filename: %s" % self.filename,
"Game name: %s" % self.gamename,
"GB Color: %s" % str(self.ROMBanks[0][0x143] == 0x80),
"GB Color: %s" % str(self.ROMBanks[0, 0x143] == 0x80),
"Cartridge type: %s" % hex(self.cartType),
"Number of ROM banks: %s" % self.external_rom_count,
"Active ROM bank: %s" % self.rombank_selected,
Expand All @@ -159,6 +159,6 @@ def setitem(self, address, value):
self.rombank_selected = (value & 0b1)
logger.debug("Switching bank 0x%0.4x, 0x%0.2x" % (address, value))
elif 0xA000 <= address < 0xC000:
self.rambanks[self.rambank_selected][address - 0xA000] = value
self.rambanks[self.rambank_selected, address - 0xA000] = value
# else:
# logger.debug("Unexpected write to 0x%0.4x, value: 0x%0.2x" % (address, value))
# logger.debug("Unexpected write to 0x%0.4x, value: 0x%0.2x" % (address, value))
20 changes: 5 additions & 15 deletions pyboy/core/cartridge/cartridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,16 @@

logger = logging.getLogger(__name__)

try:
from cython import compiled
cythonmode = compiled
except ImportError:
cythonmode = False


def load_cartridge(filename):
rombanks = load_romfile(filename)
if not validate_checksum(rombanks):
raise Exception("Cartridge header checksum mismatch!")

# WARN: The following table doesn't work for MBC2! See Pan Docs
external_ram_count = int(EXTERNAL_RAM_TABLE[rombanks[0][0x0149]])
external_ram_count = int(EXTERNAL_RAM_TABLE[rombanks[0, 0x0149]])

carttype = rombanks[0][0x0147]
carttype = rombanks[0, 0x0147]
cartinfo = CARTRIDGE_TABLE.get(carttype, None)
if cartinfo is None:
raise Exception("Catridge type invalid: %s" % carttype)
Expand All @@ -47,9 +41,9 @@ def load_cartridge(filename):
def validate_checksum(rombanks):
x = 0
for m in range(0x134, 0x14D):
x = x - rombanks[0][m] - 1
x = x - rombanks[0, m] - 1
x &= 0xff
return rombanks[0][0x14D] == x
return rombanks[0, 0x14D] == x


def load_romfile(filename):
Expand All @@ -66,11 +60,7 @@ def load_romfile(filename):
logger.error("Unexpected ROM file length")
raise Exception("Bad ROM file size")

if cythonmode:
return memoryview(romdata).cast("B", shape=(len(romdata) // banksize, banksize))
else:
v = memoryview(romdata)
return [v[i:i + banksize] for i in range(0, len(romdata), banksize)]
return memoryview(romdata).cast("B", shape=(len(romdata) // banksize, banksize))


# yapf: disable
Expand Down
8 changes: 4 additions & 4 deletions pyboy/core/cartridge/mbc1.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def setitem(self, address, value):
elif 0xA000 <= address < 0xC000:
if self.rambank_enabled:
self.rambank_selected = self.bank_select_register2 if self.memorymodel == 1 else 0
self.rambanks[self.rambank_selected % self.external_ram_count][address - 0xA000] = value
self.rambanks[self.rambank_selected % self.external_ram_count, address - 0xA000] = value
# else:
# logger.error("Invalid writing address: %0.4x", address)

Expand All @@ -43,11 +43,11 @@ def getitem(self, address):
self.rombank_selected = (self.bank_select_register2 << 5) % self.external_rom_count
else:
self.rombank_selected = 0
return self.rombanks[self.rombank_selected][address]
return self.rombanks[self.rombank_selected, address]
elif 0x4000 <= address < 0x8000:
self.rombank_selected = \
((self.bank_select_register2 << 5) | self.bank_select_register1) % self.external_rom_count
return self.rombanks[self.rombank_selected][address - 0x4000]
return self.rombanks[self.rombank_selected, address - 0x4000]
elif 0xA000 <= address < 0xC000:
if not self.rambank_initialized:
logger.error("RAM banks not initialized: %s" % hex(address))
Expand All @@ -59,7 +59,7 @@ def getitem(self, address):
self.rambank_selected = self.bank_select_register2 % self.external_ram_count
else:
self.rambank_selected = 0
return self.rambanks[self.rambank_selected][address - 0xA000]
return self.rambanks[self.rambank_selected, address - 0xA000]
# else:
# logger.error("Reading address invalid: %0.4x", address)

Expand Down
8 changes: 4 additions & 4 deletions pyboy/core/cartridge/mbc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ def setitem(self, address, value):
elif 0xA000 <= address < 0xC000:
if self.rambank_enabled:
# MBC2 includes built-in RAM of 512 x 4 bits (Only the 4 LSBs are used)
self.rambanks[0][address % 512] = value | 0b11110000
self.rambanks[0, address % 512] = value | 0b11110000
# else:
# logger.debug("Unexpected write to 0x%0.4x, value: 0x%0.2x", address, value)

def getitem(self, address):
if 0x0000 <= address < 0x4000:
return self.rombanks[0][address]
return self.rombanks[0, address]
elif 0x4000 <= address < 0x8000:
return self.rombanks[self.rombank_selected][address - 0x4000]
return self.rombanks[self.rombank_selected, address - 0x4000]
elif 0xA000 <= address < 0xC000:
if not self.rambank_initialized:
logger.error("RAM banks not initialized: %s" % hex(address))
Expand All @@ -40,6 +40,6 @@ def getitem(self, address):
return 0xFF

else:
return self.rambanks[0][address % 512] | 0b11110000
return self.rambanks[0, address % 512] | 0b11110000
# else:
# logger.error("Reading address invalid: %0.4x", address)
2 changes: 1 addition & 1 deletion pyboy/core/cartridge/mbc3.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def setitem(self, address, value):
elif 0xA000 <= address < 0xC000:
if self.rambank_enabled:
if self.rambank_selected <= 0x03:
self.rambanks[self.rambank_selected][address - 0xA000] = value
self.rambanks[self.rambank_selected, address - 0xA000] = value
elif 0x08 <= self.rambank_selected <= 0x0C:
self.rtc.setregister(self.rambank_selected, value)
# else:
Expand Down
2 changes: 1 addition & 1 deletion pyboy/core/cartridge/mbc5.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ def setitem(self, address, value):
self.rambank_selected = (value & 0xF) % self.external_ram_count
elif 0xA000 <= address < 0xC000:
if self.rambank_enabled:
self.rambanks[self.rambank_selected][address - 0xA000] = value
self.rambanks[self.rambank_selected, address - 0xA000] = value
else:
logger.debug("Unexpected write to 0x%0.4x, value: 0x%0.2x" % (address, value))
Loading

0 comments on commit 4ffcb73

Please sign in to comment.