diff --git a/pyboy/botsupport/screen.pxd b/pyboy/botsupport/screen.pxd index 07ef44cfb..33f037031 100644 --- a/pyboy/botsupport/screen.pxd +++ b/pyboy/botsupport/screen.pxd @@ -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) diff --git a/pyboy/core/cartridge/base_mbc.pxd b/pyboy/core/cartridge/base_mbc.pxd index c2967c622..9f0f978e4 100644 --- a/pyboy/core/cartridge/base_mbc.pxd +++ b/pyboy/core/cartridge/base_mbc.pxd @@ -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 @@ -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 @@ -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 diff --git a/pyboy/core/cartridge/base_mbc.py b/pyboy/core/cartridge/base_mbc.py index e022bd6fc..bae3ad7ba 100644 --- a/pyboy/core/cartridge/base_mbc.py +++ b/pyboy/core/cartridge/base_mbc.py @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) diff --git a/pyboy/core/cartridge/mbc1.pxd b/pyboy/core/cartridge/mbc1.pxd index f4b54e372..a039ac859 100644 --- a/pyboy/core/cartridge/mbc1.pxd +++ b/pyboy/core/cartridge/mbc1.pxd @@ -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 diff --git a/pyboy/core/cartridge/mbc1.py b/pyboy/core/cartridge/mbc1.py index cb705e76c..655084e17 100644 --- a/pyboy/core/cartridge/mbc1.py +++ b/pyboy/core/cartridge/mbc1.py @@ -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) @@ -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) @@ -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) @@ -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] diff --git a/pyboy/core/cartridge/mbc2.pxd b/pyboy/core/cartridge/mbc2.pxd index 2006f7454..2bfc2945b 100644 --- a/pyboy/core/cartridge/mbc2.pxd +++ b/pyboy/core/cartridge/mbc2.pxd @@ -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 diff --git a/pyboy/core/cartridge/mbc2.py b/pyboy/core/cartridge/mbc2.py index 45811369d..610bb0d8f 100644 --- a/pyboy/core/cartridge/mbc2.py +++ b/pyboy/core/cartridge/mbc2.py @@ -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) @@ -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) diff --git a/pyboy/core/cartridge/mbc3.pxd b/pyboy/core/cartridge/mbc3.pxd index a0469da3d..a68ca7699 100644 --- a/pyboy/core/cartridge/mbc3.pxd +++ b/pyboy/core/cartridge/mbc3.pxd @@ -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 diff --git a/pyboy/core/cartridge/mbc3.py b/pyboy/core/cartridge/mbc3.py index 813bf8721..056fd2a94 100644 --- a/pyboy/core/cartridge/mbc3.py +++ b/pyboy/core/cartridge/mbc3.py @@ -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) @@ -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: diff --git a/pyboy/core/cartridge/mbc5.pxd b/pyboy/core/cartridge/mbc5.pxd index 1adcdd904..03eb964fe 100644 --- a/pyboy/core/cartridge/mbc5.pxd +++ b/pyboy/core/cartridge/mbc5.pxd @@ -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 diff --git a/pyboy/core/cartridge/mbc5.py b/pyboy/core/cartridge/mbc5.py index fc17218e4..779d34393 100644 --- a/pyboy/core/cartridge/mbc5.py +++ b/pyboy/core/cartridge/mbc5.py @@ -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) diff --git a/pyboy/core/cartridge/rtc.pxd b/pyboy/core/cartridge/rtc.pxd index 02e5e356a..5597800ac 100644 --- a/pyboy/core/cartridge/rtc.pxd +++ b/pyboy/core/cartridge/rtc.pxd @@ -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 diff --git a/pyboy/core/cpu.pxd b/pyboy/core/cpu.pxd index 27e74e09f..d61572baa 100644 --- a/pyboy/core/cpu.pxd +++ b/pyboy/core/cpu.pxd @@ -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 @@ -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 diff --git a/pyboy/core/cpu.py b/pyboy/core/cpu.py index e66bc7dad..9f24bf74b 100644 --- a/pyboy/core/cpu.py +++ b/pyboy/core/cpu.py @@ -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 diff --git a/pyboy/core/mb.pxd b/pyboy/core/mb.pxd index b8535d84d..df96d080e 100644 --- a/pyboy/core/mb.pxd +++ b/pyboy/core/mb.pxd @@ -54,7 +54,16 @@ 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 @@ -62,8 +71,8 @@ cdef class Motherboard: @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 @@ -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 diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index 656049419..501ba2ac0 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -196,13 +196,20 @@ def processing_frame(self): return b def tick(self): + # This looks pointless, but when translated to C, + # I think this saves us a pointer dereference at every usage + lcd = self.lcd + timer = self.timer + sound = self.sound + cpu = self.cpu + hdma = self.hdma while self.processing_frame(): if self.cgb and self.hdma.transfer_active and self.lcd._STAT._mode & 0b11 == 0: - cycles = self.hdma.tick(self) + cycles = hdma.tick(self) else: - cycles = self.cpu.tick() + cycles = cpu.tick() - if self.cpu.halted: + if cpu.halted: # Fast-forward to next interrupt: # As we are halted, we are guaranteed, that our state # cannot be altered by other factors than time. @@ -212,12 +219,12 @@ def tick(self): # Help Cython with types mode0_cycles = 1 << 32 - if self.cgb and self.hdma.transfer_active: - mode0_cycles = self.lcd.cycles_to_mode0() + if self.cgb and hdma.transfer_active: + mode0_cycles = lcd.cycles_to_mode0() cycles = min( - self.lcd.cycles_to_interrupt(), - self.timer.cycles_to_interrupt(), + lcd.cycles_to_interrupt(), + timer.cycles_to_interrupt(), # self.serial.cycles_to_interrupt(), mode0_cycles ) @@ -226,28 +233,27 @@ def tick(self): # https://gbdev.io/pandocs/CGB_Registers.html#bit-7--0---general-purpose-dma # TODO: Unify interface - sclock = self.sound.clock if self.cgb and self.double_speed: - self.sound.clock = sclock + cycles//2 + sound.clock += cycles//2 else: - self.sound.clock = sclock + cycles + sound.clock += cycles - if self.timer.tick(cycles): - self.cpu.set_interruptflag(INTR_TIMER) + if timer.tick(cycles): + cpu.set_interruptflag(INTR_TIMER) - lcd_interrupt = self.lcd.tick(cycles) + lcd_interrupt = lcd.tick(cycles) if lcd_interrupt: - self.cpu.set_interruptflag(lcd_interrupt) + cpu.set_interruptflag(lcd_interrupt) # Escape halt. This happens when pressing 'return' in the debugger. It will make us skip breaking on halt # for every cycle, but do break on the next instruction -- even in an interrupt. - escape_halt = self.cpu.halted and self.breakpoint_latch == 1 # TODO: Replace with GDB Stub + escape_halt = cpu.halted and self.breakpoint_latch == 1 if self.breakpoints_enabled and (not escape_halt) and self.breakpoint_reached(): return True # TODO: Move SDL2 sync to plugin - self.sound.sync() + sound.sync() return False diff --git a/pyboy/core/opcodes.pxd b/pyboy/core/opcodes.pxd index 4370a933d..6ff060d1f 100644 --- a/pyboy/core/opcodes.pxd +++ b/pyboy/core/opcodes.pxd @@ -3,20 +3,17 @@ # DO NOT MODIFY THIS FILE. # CHANGES TO THE CODE SHOULD BE MADE IN 'opcodes_gen.py'. +from . cimport cpu cimport cython from libc.stdint cimport uint8_t, uint16_t, uint32_t from pyboy.logging.logging cimport Logger - -from . cimport cpu - - cdef Logger logger cdef uint16_t FLAGC, FLAGH, FLAGN, FLAGZ cdef uint8_t[512] OPCODE_LENGTHS @cython.locals(v=cython.int, a=cython.int, b=cython.int, pc=cython.ushort) -cdef int execute_opcode(cpu.CPU, uint16_t) noexcept nogil +cdef int execute_opcode(cpu.CPU, uint64_t) noexcept nogil cdef uint8_t no_opcode(cpu.CPU) noexcept nogil @cython.locals(v=int, flag=uint8_t, t=int) diff --git a/pyboy/core/opcodes.py b/pyboy/core/opcodes.py index 1762144ff..0d97c9b95 100644 --- a/pyboy/core/opcodes.py +++ b/pyboy/core/opcodes.py @@ -2166,7 +2166,7 @@ def JP_CA(cpu, v): # CA JP Z,a16 def PREFIX_CB(cpu): # CB PREFIX CB - logger.critical("CB cannot be called!") + logger.critical('CB cannot be called!') cpu.PC += 1 cpu.PC &= 0xFFFF return 4 diff --git a/pyboy/core/opcodes_gen.py b/pyboy/core/opcodes_gen.py index 90566067f..84beab668 100644 --- a/pyboy/core/opcodes_gen.py +++ b/pyboy/core/opcodes_gen.py @@ -39,7 +39,7 @@ cdef uint16_t FLAGC, FLAGH, FLAGN, FLAGZ cdef uint8_t[512] OPCODE_LENGTHS @cython.locals(v=cython.int, a=cython.int, b=cython.int, pc=cython.ushort) -cdef int execute_opcode(cpu.CPU, uint16_t) noexcept nogil +cdef int execute_opcode(cpu.CPU, uint64_t) noexcept nogil cdef uint8_t no_opcode(cpu.CPU) noexcept nogil """ diff --git a/pyboy/core/timer.pxd b/pyboy/core/timer.pxd index 43aaceb76..931d69079 100644 --- a/pyboy/core/timer.pxd +++ b/pyboy/core/timer.pxd @@ -15,13 +15,14 @@ from pyboy.logging.logging cimport Logger cdef Logger logger cdef class Timer: - cdef uint64_t DIV, TIMA, TMA, TAC - cdef uint16_t DIV_counter, TIMA_counter - cdef uint64_t[4] dividers + cdef cython.long TAC + cdef uint8_t TMA + cdef uint16_t DIV, DIV_counter, TIMA_counter, TIMA + cdef uint16_t[4] dividers cdef void reset(self) noexcept nogil - @cython.locals(divider=cython.int) - cdef bint tick(self, uint64_t) noexcept nogil + @cython.locals(divider=uint16_t) + cdef bint tick(self, int) noexcept nogil @cython.locals(divider=cython.int, cyclesleft=cython.uint) cdef uint64_t cycles_to_interrupt(self) noexcept nogil diff --git a/pyboy/core/timer.py b/pyboy/core/timer.py index 0f89226f8..45db0cf7c 100644 --- a/pyboy/core/timer.py +++ b/pyboy/core/timer.py @@ -35,9 +35,9 @@ def reset(self): def tick(self, cycles): self.DIV_counter += cycles - self.DIV += (self.DIV_counter >> 8) # Add overflown bits to DIV + self.DIV = (self.DIV + (self.DIV_counter >> 8)) & 0xFF # Add overflown bits to DIV self.DIV_counter &= 0xFF # Remove the overflown bits - self.DIV &= 0xFF + # self.DIV &= 0xFF if self.TAC & 0b100 == 0: # Check if timer is not enabled return False diff --git a/pyboy/pyboy.pxd b/pyboy/pyboy.pxd index 180948c36..87ef793ed 100644 --- a/pyboy/pyboy.pxd +++ b/pyboy/pyboy.pxd @@ -45,8 +45,9 @@ cdef class PyBoy: cdef list recorded_input cdef list external_input - @cython.locals(t_start=int64_t, t_pre=int64_t, t_tick=int64_t, t_post=int64_t, nsecs=int64_t) cpdef bint tick(self) noexcept + @cython.locals(t_start=int64_t, t_pre=int64_t, t_tick=int64_t, t_post=int64_t, nsecs=int64_t) + cdef bint tick_internal(self) noexcept cpdef void stop(self, save=*) noexcept @cython.locals(state_path=str) diff --git a/pyboy/pyboy.py b/pyboy/pyboy.py index 7735e459a..85aa33b6f 100644 --- a/pyboy/pyboy.py +++ b/pyboy/pyboy.py @@ -117,6 +117,9 @@ def __init__( self.initialized = True def tick(self): + return self.tick_internal() + + def tick_internal(self): """ Progresses the emulator ahead by one frame.