Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vectorize 2 #296

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
5 changes: 3 additions & 2 deletions pyboy/botsupport/screen.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#
cimport cython
cimport numpy as np
cimport numpy as cnp
from pyboy.core.mb cimport Motherboard

cnp.import_array()


cdef class Screen:
cdef Motherboard mb
cpdef np.ndarray[np.uint8_t, ndim=3] screen_ndarray(self)
cpdef cnp.ndarray[cnp.uint8_t, ndim=3] screen_ndarray(self)
11 changes: 7 additions & 4 deletions pyboy/core/cartridge/base_mbc.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

from libc.stdint cimport uint8_t, uint16_t, uint32_t
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t

from pyboy.core.cartridge.rtc cimport RTC
from pyboy.logging.logging cimport Logger
Expand All @@ -28,6 +28,9 @@ cdef class BaseMBC:
cdef bint rambank_initialized
cdef uint16_t rambank_selected
cdef uint16_t rombank_selected
cdef uint8_t[:] rombank_0
cdef uint8_t[:] rombank_view
cdef uint8_t[:] rambank_view
cdef bint cgb

cdef void save_state(self, IntIOInterface) noexcept
Expand All @@ -37,9 +40,9 @@ cdef class BaseMBC:
cdef void init_rambanks(self, uint8_t) noexcept
cdef str getgamename(self, uint8_t[:,:]) noexcept

cdef uint8_t getitem(self, uint16_t) noexcept nogil
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef uint8_t getitem(self, uint64_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil
cdef void overrideitem(self, int, uint16_t, uint8_t) noexcept nogil

cdef class ROMOnly(BaseMBC):
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil
15 changes: 11 additions & 4 deletions pyboy/core/cartridge/base_mbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ def __init__(self, filename, rombanks, external_ram_count, carttype, sram, batte
self.memorymodel = 0
self.rambank_enabled = False
self.rambank_selected = 0
self.rambank_view = self.rambanks[self.rambank_selected]
self.rombank_selected = 1
self.rombank_view = self.rombanks[self.rombank_selected]
self.rombank_0 = self.rombanks[0]

self.cgb = bool(self.getitem(0x0143) >> 7)

Expand Down Expand Up @@ -64,7 +67,9 @@ def save_state(self, f):

def load_state(self, f, state_version):
self.rombank_selected = f.read()
self.rombank_view = self.rombanks[self.rombank_selected]
self.rambank_selected = f.read()
self.rambank_view = self.rambanks[self.rambank_selected]
self.rambank_enabled = f.read()
self.memorymodel = f.read()
self.load_ram(f)
Expand Down Expand Up @@ -117,9 +122,10 @@ def overrideitem(self, rom_bank, address, value):

def getitem(self, address):
if 0x0000 <= address < 0x4000:
return self.rombanks[0, address]
return self.rombank_0[address]
elif 0x4000 <= address < 0x8000:
return self.rombanks[self.rombank_selected, address - 0x4000]
# return self.rombanks[self.rombank_selected, address - 0x4000]
return self.rombank_view[address - 0x4000]
elif 0xA000 <= address < 0xC000:
# if not self.rambank_initialized:
# logger.error("RAM banks not initialized: 0.4x", address)
Expand All @@ -130,7 +136,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.rambank_view[address - 0xA000]
# else:
# logger.error("Reading address invalid: %0.4x", address)

Expand All @@ -157,8 +163,9 @@ def setitem(self, address, value):
if value == 0:
value = 1
self.rombank_selected = (value & 0b1)
self.rombank_view = self.rombanks[self.rombank_selected]
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.rambank_view[address - 0xA000] = value
# else:
# logger.debug("Unexpected write to 0x%0.4x, value: 0x%0.2x", address, value)
6 changes: 2 additions & 4 deletions pyboy/core/cartridge/mbc1.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

from libc.stdint cimport uint8_t, uint16_t

from pyboy.logging.logging cimport Logger

from libc.stdint cimport uint8_t, uint16_t, uint64_t
from .base_mbc cimport BaseMBC


cdef Logger logger

cdef class MBC1(BaseMBC):
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil
cdef uint8_t bank_select_register1
cdef uint8_t bank_select_register2
13 changes: 9 additions & 4 deletions pyboy/core/cartridge/mbc1.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ 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.rambank_view = self.rambanks[self.rambank_selected % self.external_ram_count]
self.rambank_view[address - 0xA000] = value
# else:
# logger.error("Invalid writing address: %0.4x", address)

Expand All @@ -44,11 +45,13 @@ 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]
self.rombank_view = self.rombanks[self.rombank_selected]
return self.rombank_view[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]
self.rombank_view = self.rombanks[self.rombank_selected]
return self.rombank_view[address - 0x4000]
elif 0xA000 <= address < 0xC000:
if not self.rambank_initialized:
logger.error("RAM banks not initialized: %0.4x", address)
Expand All @@ -60,7 +63,8 @@ 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]
self.rambank_view = self.rambanks[self.rambank_selected]
return self.rambanks_view[address - 0xA000]
# else:
# logger.error("Reading address invalid: %0.4x", address)

Expand All @@ -80,3 +84,4 @@ def load_state(self, f, state_version):
self.bank_select_register1 = self.rombank_selected & 0b00011111
self.bank_select_register2 = (self.rombank_selected & 0b01100000) >> 5
self.rambank_selected = self.bank_select_register2
self.rambank_view = self.rambanks[self.rambank_selected]
6 changes: 2 additions & 4 deletions pyboy/core/cartridge/mbc2.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

from libc.stdint cimport uint8_t, uint16_t

from pyboy.logging.logging cimport Logger

from libc.stdint cimport uint8_t, uint16_t, uint64_t
from .base_mbc cimport BaseMBC


cdef Logger logger

cdef class MBC2(BaseMBC):
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil
3 changes: 2 additions & 1 deletion pyboy/core/cartridge/mbc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def setitem(self, address, value):
if value == 0:
value = 1
self.rombank_selected = value % self.external_rom_count
self.rombank_view = self.rombanks[self.rombank_selected]
elif 0xA000 <= address < 0xC000:
if self.rambank_enabled:
# MBC2 includes built-in RAM of 512 x 4 bits (Only the 4 LSBs are used)
Expand All @@ -32,7 +33,7 @@ def getitem(self, address):
if 0x0000 <= address < 0x4000:
return self.rombanks[0, address]
elif 0x4000 <= address < 0x8000:
return self.rombanks[self.rombank_selected, address - 0x4000]
return self.rombank_view[address - 0x4000]
elif 0xA000 <= address < 0xC000:
if not self.rambank_initialized:
logger.error("RAM banks not initialized: %0.4x", address)
Expand Down
5 changes: 2 additions & 3 deletions pyboy/core/cartridge/mbc3.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

from libc.stdint cimport uint8_t, uint16_t

from pyboy.logging.logging cimport Logger

from libc.stdint cimport uint8_t, uint16_t, uint64_t
from .base_mbc cimport BaseMBC


cdef Logger logger

cdef class MBC3(BaseMBC):
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil
4 changes: 3 additions & 1 deletion pyboy/core/cartridge/mbc3.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ def setitem(self, address, value):
if value == 0:
value = 1
self.rombank_selected = value % self.external_rom_count
self.rombank_view = self.rombanks[self.rombank_selected]
elif 0x4000 <= address < 0x6000:
self.rambank_selected = value % self.external_ram_count
self.rambank_view = self.rambanks[self.rambank_selected]
elif 0x6000 <= address < 0x8000:
if self.rtc_enabled:
self.rtc.writecommand(value)
Expand All @@ -41,7 +43,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.rambank_view[address - 0xA000] = value
elif 0x08 <= self.rambank_selected <= 0x0C:
self.rtc.setregister(self.rambank_selected, value)
# else:
Expand Down
4 changes: 2 additions & 2 deletions pyboy/core/cartridge/mbc5.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

from libc.stdint cimport uint8_t, uint16_t

from pyboy.logging.logging cimport Logger

from libc.stdint cimport uint8_t, uint16_t, uint64_t
from .base_mbc cimport BaseMBC


cdef Logger logger

cdef class MBC5(BaseMBC):
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil
5 changes: 4 additions & 1 deletion pyboy/core/cartridge/mbc5.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ def setitem(self, address, value):
elif 0x2000 <= address < 0x3000:
# 8-bit register used for the lower 8 bits of the ROM bank number.
self.rombank_selected = ((self.rombank_selected & 0b100000000) | value) % self.external_rom_count
self.rombank_view = self.rombanks[self.rombank_selected]
elif 0x3000 <= address < 0x4000:
# 1-bit register used for the most significant bit of the ROM bank number.
self.rombank_selected = (((value & 0x1) << 8) | (self.rombank_selected & 0xFF)) % self.external_rom_count
self.rombank_view = self.rombanks[self.rombank_selected]
elif 0x4000 <= address < 0x6000:
self.rambank_selected = (value & 0xF) % self.external_ram_count
self.rambank_view = self.rambanks[self.rambank_selected]
elif 0xA000 <= address < 0xC000:
if self.rambank_enabled:
self.rambanks[self.rambank_selected, address - 0xA000] = value
self.rambank_view[address - 0xA000] = value
else:
logger.debug("Unexpected write to 0x%0.4x, value: 0x%0.2x", address, value)
2 changes: 1 addition & 1 deletion pyboy/core/cartridge/rtc.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ cdef class RTC:
@cython.locals(days=uint64_t)
cdef void latch_rtc(self) noexcept nogil
cdef void writecommand(self, uint8_t) noexcept nogil
cdef uint8_t getregister(self, uint8_t) noexcept nogil
cdef uint8_t getregister(self, uint64_t) noexcept nogil
@cython.locals(t=cython.double, days=uint64_t)
cdef void setregister(self, uint8_t, uint8_t) noexcept nogil
8 changes: 5 additions & 3 deletions pyboy/core/cpu.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ cdef class CPU:

cdef uint8_t interrupts_flag, interrupts_enabled, interrupts_flag_register, interrupts_enabled_register

cdef inline int check_interrupts(self) noexcept nogil
cdef inline bint check_interrupts(self) noexcept nogil
cdef void set_interruptflag(self, int) noexcept nogil
cdef bint handle_interrupt(self, uint8_t, uint16_t) noexcept nogil

@cython.locals(opcode=uint16_t)
cdef inline uint8_t fetch_and_execute(self) noexcept nogil
cdef int tick(self) noexcept nogil
@cython.locals(old_pc=uint16_t, old_sp=int)
cdef uint8_t tick(self) noexcept nogil
cdef void save_state(self, IntIOInterface) noexcept
cdef void load_state(self, IntIOInterface, int) noexcept

Expand All @@ -46,7 +47,8 @@ cdef class CPU:

# Only short (16-bit) needed, but I'm not sure all intermittent
# results do not overflow
cdef int HL, SP, PC
cdef int HL, SP
cdef uint16_t PC

cdef pyboy.core.mb.Motherboard mb

Expand Down
11 changes: 8 additions & 3 deletions pyboy/core/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,15 @@ def tick(self):

old_pc = self.PC # If the PC doesn't change, we're likely stuck
old_sp = self.SP # Sometimes a RET can go to the same PC, so we check the SP too.
# Fetch and execute will mutate the PC
# TODO: Find a way to have opcodes not mutate cpu as much
# Then we can check if the PC changed, and if not, we're stuck.
# This way there are fewer cross-shared object dereferences
cycles = self.fetch_and_execute()
if not self.halted and old_pc == self.PC and old_sp == self.SP and not self.is_stuck:
logger.debug("CPU is stuck: %s", self.dump_state(""))
self.is_stuck = True
# if not self.halted and old_pc == self.PC and old_sp == self.SP and not self.is_stuck:
# logger.error("CPU is stuck: %s", self.dump_state(""))
# self.is_stuck = True
self.is_stuck = not self.halted and old_pc == self.PC and old_sp == self.SP and not self.is_stuck
self.interrupt_queued = False
return cycles

Expand Down
17 changes: 13 additions & 4 deletions pyboy/core/mb.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,25 @@ cdef class Motherboard:

cdef void buttonevent(self, WindowEvent) noexcept
cdef void stop(self, bint) noexcept
@cython.locals(cycles=int64_t, escape_halt=cython.int, mode0_cycles=int64_t)

@cython.locals(
lcd=pyboy.core.lcd.LCD,
timer=pyboy.core.timer.Timer,
sound=pyboy.core.sound.Sound,
cpu=pyboy.core.cpu.CPU,
hdma=HDMA,
cycles=uint16_t,
escape_halt=cython.int,
mode0_cycles=int64_t)
cdef bint tick(self) noexcept nogil

cdef void switch_speed(self) noexcept nogil

@cython.locals(pc=cython.int, bank=cython.int)
cdef bint breakpoint_reached(self) noexcept with gil

cdef uint8_t getitem(self, uint16_t) noexcept nogil
cdef void setitem(self, uint16_t, uint8_t) noexcept nogil
cdef uint8_t getitem(self, uint64_t) noexcept nogil
cdef void setitem(self, uint64_t, uint8_t) noexcept nogil

@cython.locals(offset=cython.int, dst=cython.int, n=cython.int)
cdef void transfer_DMA(self, uint8_t) noexcept nogil
Expand All @@ -83,7 +92,7 @@ cdef class HDMA:
cdef uint16_t curr_dst

cdef void set_hdma5(self, uint8_t, Motherboard) noexcept nogil
cdef int tick(self, Motherboard) noexcept nogil
cdef uint16_t tick(self, Motherboard) noexcept nogil

cdef void save_state(self, IntIOInterface) noexcept
cdef void load_state(self, IntIOInterface, int) noexcept
Loading
Loading