From 208f110fa89a6cbd124fe4f9670b5935a4f5740b Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Mon, 23 Sep 2024 17:17:38 +0200 Subject: [PATCH 01/22] Change TEST_CI to TEST_VERBOSE_IMAGES and invert semantic --- .github/workflows/pr-test.yml | 4 ++-- tests/test_acid_cgb.py | 2 +- tests/test_acid_dmg.py | 2 +- tests/test_basics.py | 2 +- tests/test_breakpoints.py | 2 +- tests/test_magen.py | 2 +- tests/test_mooneye.py | 2 +- tests/test_replay.py | 2 +- tests/test_rtc3test.py | 2 +- tests/test_samesuite.py | 2 +- tests/test_shonumi.py | 2 +- tests/test_which.py | 2 +- tests/test_whichboot.py | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index fa4875550..4d0ec332c 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -46,7 +46,7 @@ jobs: - name: Run PyTest env: PYTEST_SECRETS_KEY: ${{ secrets.PYTEST_SECRETS_KEY }} - TEST_CI: 1 + TEST_VERBOSE_IMAGES: 0 TEST_NO_UI: 1 run: | python -m pytest tests/ -n auto -v @@ -111,7 +111,7 @@ jobs: - name: Run PyTest env: PYTEST_SECRETS_KEY: ${{ secrets.PYTEST_SECRETS_KEY }} - TEST_CI: 1 + TEST_VERBOSE_IMAGES: 0 TEST_NO_UI: 1 run: | pypy3 -m pytest tests/ -n auto -v diff --git a/tests/test_acid_cgb.py b/tests/test_acid_cgb.py index 41f21c1c8..1a5e65db7 100644 --- a/tests/test_acid_cgb.py +++ b/tests/test_acid_cgb.py @@ -29,7 +29,7 @@ def test_cgb_acid(cgb_acid_file): # Converting to RGB as ImageChops.difference cannot handle Alpha: https://github.com/python-pillow/Pillow/issues/4849 old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_acid_dmg.py b/tests/test_acid_dmg.py index adf942af1..08694a0a9 100644 --- a/tests/test_acid_dmg.py +++ b/tests/test_acid_dmg.py @@ -30,7 +30,7 @@ def test_dmg_acid(cgb, dmg_acid_file): # Converting to RGB as ImageChops.difference cannot handle Alpha: https://github.com/python-pillow/Pillow/issues/4849 old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_basics.py b/tests/test_basics.py index 751f4ad85..612214cec 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -284,7 +284,7 @@ def test_all_modes(cgb, _bootrom, frames, rom, any_rom_cgb, boot_cgb_rom): old_image = PIL.Image.open(png_buf).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_breakpoints.py b/tests/test_breakpoints.py index 10e75b121..52f2512fc 100644 --- a/tests/test_breakpoints.py +++ b/tests/test_breakpoints.py @@ -254,7 +254,7 @@ def test_data_hooking_failure(default_rom): image1 = pyboy1.screen.image.convert("RGB") image2 = pyboy2.screen.image.convert("RGB") diff = PIL.ImageChops.difference(image1, image2) - if not diff.getbbox() and not os.environ.get("TEST_CI"): + if not diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image1.show() image2.show() diff.show() diff --git a/tests/test_magen.py b/tests/test_magen.py index e3999bd9f..cee03f386 100644 --- a/tests/test_magen.py +++ b/tests/test_magen.py @@ -29,7 +29,7 @@ def test_magen_test(magen_test_file): # Converting to RGB as ImageChops.difference cannot handle Alpha: https://github.com/python-pillow/Pillow/issues/4849 old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_mooneye.py b/tests/test_mooneye.py index c5bf9b705..a70655181 100644 --- a/tests/test_mooneye.py +++ b/tests/test_mooneye.py @@ -185,7 +185,7 @@ def test_mooneye(clean, rom, mooneye_dir, default_rom): else: diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_replay.py b/tests/test_replay.py index d855def23..5ccebe3e6 100644 --- a/tests/test_replay.py +++ b/tests/test_replay.py @@ -31,7 +31,7 @@ def verify_screen_image_np(pyboy, saved_array): match = np.all(np.frombuffer(saved_array, dtype=np.uint8).reshape(144, 160, 3) == pyboy.screen.ndarray) - if not match and not os.environ.get("TEST_CI"): + if not match and os.environ.get("TEST_VERBOSE_IMAGES"): from PIL import Image original = Image.frombytes("RGB", (160, 144), np.frombuffer(saved_array, dtype=np.uint8).reshape(144, 160, 3)) original.show() diff --git a/tests/test_rtc3test.py b/tests/test_rtc3test.py index 3118d6536..eb66feb0c 100644 --- a/tests/test_rtc3test.py +++ b/tests/test_rtc3test.py @@ -45,7 +45,7 @@ def test_rtc3test(subtest, rtc3test_file): # Converting to RGB as ImageChops.difference cannot handle Alpha: https://github.com/python-pillow/Pillow/issues/4849 old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_samesuite.py b/tests/test_samesuite.py index 16e0e5bba..edf36170c 100644 --- a/tests/test_samesuite.py +++ b/tests/test_samesuite.py @@ -155,7 +155,7 @@ def test_samesuite(clean, gb_type, rom, samesuite_dir, boot_cgb_rom, boot_rom, d old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_shonumi.py b/tests/test_shonumi.py index 01adfe01b..e9aaa6e48 100644 --- a/tests/test_shonumi.py +++ b/tests/test_shonumi.py @@ -37,7 +37,7 @@ def test_shonumi(rom, shonumi_dir): old_image = old_image.resize(image.size, resample=PIL.Image.Dither.NONE) diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_which.py b/tests/test_which.py index afa67f46e..2a358afe4 100644 --- a/tests/test_which.py +++ b/tests/test_which.py @@ -30,7 +30,7 @@ def test_which(cgb, which_file): # Converting to RGB as ImageChops.difference cannot handle Alpha: https://github.com/python-pillow/Pillow/issues/4849 old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() diff --git a/tests/test_whichboot.py b/tests/test_whichboot.py index 34d5bdb19..deee0e46b 100644 --- a/tests/test_whichboot.py +++ b/tests/test_whichboot.py @@ -30,7 +30,7 @@ def test_which(cgb, whichboot_file): # Converting to RGB as ImageChops.difference cannot handle Alpha: https://github.com/python-pillow/Pillow/issues/4849 old_image = PIL.Image.open(png_path).convert("RGB") diff = PIL.ImageChops.difference(image.convert("RGB"), old_image) - if diff.getbbox() and not os.environ.get("TEST_CI"): + if diff.getbbox() and os.environ.get("TEST_VERBOSE_IMAGES"): image.show() old_image.show() diff.show() From 9c8a7eea9badfc28cb06fde3789b150e85e0a97d Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Fri, 20 Sep 2024 21:30:39 +0200 Subject: [PATCH 02/22] Try to quit debug window better --- pyboy/plugins/debug.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pyboy/plugins/debug.py b/pyboy/plugins/debug.py index 012bbbca6..25520cad7 100644 --- a/pyboy/plugins/debug.py +++ b/pyboy/plugins/debug.py @@ -205,8 +205,14 @@ def handle_events(self, events): return events def stop(self): - if self.sdl2_event_pump: - sdl2.SDL_Quit() + self.tile1.stop() + self.tile2.stop() + self.tiledata0.stop() + if self.cgb: + self.tiledata1.stop() + self.sprite.stop() + self.spriteview.stop() + self.memory.stop() def enabled(self): if self.pyboy_argv.get("debug"): From 9407c384243cb51a55937d8a5fb5ce60c53ad169 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Mon, 16 Sep 2024 21:09:54 +0200 Subject: [PATCH 03/22] Remove redundant definitions in sound.pxd --- pyboy/core/sound.pxd | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyboy/core/sound.pxd b/pyboy/core/sound.pxd index 322ef25df..5a13b8e2f 100644 --- a/pyboy/core/sound.pxd +++ b/pyboy/core/sound.pxd @@ -91,11 +91,7 @@ cdef class SweepChannel(ToneChannel): cdef bint sweepenable # Internal sweep enable flag cdef int shadow # Shadow copy of period register for ignoring writes to sndper - cdef uint8_t getreg(self, uint8_t) noexcept nogil - cdef void setreg(self, uint8_t, uint8_t) noexcept nogil cdef bint sweep(self, bint) noexcept nogil - cdef void trigger(self) noexcept nogil - cdef void tickframe(self) noexcept nogil cdef class WaveChannel: From 6e6e0d8056dd9edc691cdbf9530603b924bb122e Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 17 Sep 2024 17:24:45 +0100 Subject: [PATCH 04/22] Restructure CPU interrupt handling --- pyboy/core/cpu.py | 56 +++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/pyboy/core/cpu.py b/pyboy/core/cpu.py index 288e16efd..a24d36e11 100644 --- a/pyboy/core/cpu.py +++ b/pyboy/core/cpu.py @@ -133,46 +133,40 @@ def check_interrupts(self): # Interrupt already queued. This happens only when using a debugger. return False - if (self.interrupts_flag_register & 0b11111) & (self.interrupts_enabled_register & 0b11111): - if self.handle_interrupt(INTR_VBLANK, 0x0040): - self.interrupt_queued = True - elif self.handle_interrupt(INTR_LCDC, 0x0048): - self.interrupt_queued = True - elif self.handle_interrupt(INTR_TIMER, 0x0050): - self.interrupt_queued = True - elif self.handle_interrupt(INTR_SERIAL, 0x0058): - self.interrupt_queued = True - elif self.handle_interrupt(INTR_HIGHTOLOW, 0x0060): - self.interrupt_queued = True - else: - logger.error("No interrupt triggered, but it should!") - self.interrupt_queued = False - return True - else: - self.interrupt_queued = False - return False - - def handle_interrupt(self, flag, addr): - if (self.interrupts_enabled_register & flag) and (self.interrupts_flag_register & flag): + raised_and_enabled = (self.interrupts_flag_register & 0b11111) & (self.interrupts_enabled_register & 0b11111) + if raised_and_enabled: # Clear interrupt flag if self.halted: self.PC += 1 # Escape HALT on return self.PC &= 0xFFFF - # Handle interrupt vectors if self.interrupt_master_enable: - self.interrupts_flag_register ^= flag # Remove flag - self.mb.setitem((self.SP - 1) & 0xFFFF, self.PC >> 8) # High - self.mb.setitem((self.SP - 2) & 0xFFFF, self.PC & 0xFF) # Low - self.SP -= 2 - self.SP &= 0xFFFF - - self.PC = addr - self.interrupt_master_enable = False - + if raised_and_enabled & INTR_VBLANK: + self.handle_interrupt(INTR_VBLANK, 0x0040) + elif raised_and_enabled & INTR_LCDC: + self.handle_interrupt(INTR_LCDC, 0x0048) + elif raised_and_enabled & INTR_TIMER: + self.handle_interrupt(INTR_TIMER, 0x0050) + elif raised_and_enabled & INTR_SERIAL: + self.handle_interrupt(INTR_SERIAL, 0x0058) + elif raised_and_enabled & INTR_HIGHTOLOW: + self.handle_interrupt(INTR_HIGHTOLOW, 0x0060) + self.interrupt_queued = True return True + else: + self.interrupt_queued = False return False + def handle_interrupt(self, flag, addr): + self.interrupts_flag_register ^= flag # Remove flag + self.mb.setitem((self.SP - 1) & 0xFFFF, self.PC >> 8) # High + self.mb.setitem((self.SP - 2) & 0xFFFF, self.PC & 0xFF) # Low + self.SP -= 2 + self.SP &= 0xFFFF + + self.PC = addr + self.interrupt_master_enable = False + def fetch_and_execute(self): opcode = self.mb.getitem(self.PC) if opcode == 0xCB: # Extension code From 2d0620836224563fc7f13f96052f926d55f79848 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Mon, 16 Sep 2024 21:09:29 +0200 Subject: [PATCH 05/22] Simplify CGB bank read in MB getitem --- pyboy/core/mb.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index 78264a527..b717b9065 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -350,8 +350,7 @@ def getitem(self, i): bank_offset = 0 if self.cgb and 0xD000 <= i: # Find which bank to read from at FF70 - bank = self.getitem(0xFF70) - bank &= 0b111 + bank = self.ram.non_io_internal_ram1[0xFF70 - 0xFF4C] & 0b111 if bank == 0x0: bank = 0x01 bank_offset = (bank-1) * 0x1000 From de5002720ac45f2d01ef93dd370385f886353653 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sun, 28 Jul 2024 21:34:52 -0700 Subject: [PATCH 06/22] Fix blargg tests for CPU without is_stuck --- tests/test_blargg.py | 124 +++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/tests/test_blargg.py b/tests/test_blargg.py index eac9731a7..420a93ce9 100644 --- a/tests/test_blargg.py +++ b/tests/test_blargg.py @@ -20,7 +20,7 @@ blargg_json = "tests/test_results/blargg.json" -def run_rom(rom): +def run_rom(rom, max_frames): pyboy = PyBoy(str(rom), window="null", cgb="cgb" in rom, sound_emulated=True) pyboy.set_emulation_speed(0) t = time.time() @@ -31,7 +31,7 @@ def run_rom(rom): result += b t = time.time() - if pyboy._is_cpu_stuck(): + if pyboy._is_cpu_stuck() or pyboy.frame_count > max_frames: break pyboy.tick(10, False) @@ -51,69 +51,69 @@ def run_rom(rom): @pytest.mark.parametrize( - "test_rom", [ - "cgb_sound/cgb_sound.gb", - "cgb_sound/rom_singles/01-registers.gb", - "cgb_sound/rom_singles/02-len ctr.gb", - "cgb_sound/rom_singles/03-trigger.gb", - "cgb_sound/rom_singles/04-sweep.gb", - "cgb_sound/rom_singles/05-sweep details.gb", - "cgb_sound/rom_singles/06-overflow on trigger.gb", - "cgb_sound/rom_singles/07-len sweep period sync.gb", - "cgb_sound/rom_singles/08-len ctr during power.gb", - "cgb_sound/rom_singles/09-wave read while on.gb", - "cgb_sound/rom_singles/10-wave trigger while on.gb", - "cgb_sound/rom_singles/11-regs after power.gb", - "cgb_sound/rom_singles/12-wave.gb", - "cpu_instrs/cpu_instrs.gb", - "cpu_instrs/individual/01-special.gb", - "cpu_instrs/individual/02-interrupts.gb", - "cpu_instrs/individual/03-op sp,hl.gb", - "cpu_instrs/individual/04-op r,imm.gb", - "cpu_instrs/individual/05-op rp.gb", - "cpu_instrs/individual/06-ld r,r.gb", - "cpu_instrs/individual/07-jr,jp,call,ret,rst.gb", - "cpu_instrs/individual/08-misc instrs.gb", - "cpu_instrs/individual/09-op r,r.gb", - "cpu_instrs/individual/10-bit ops.gb", - "cpu_instrs/individual/11-op a,(hl).gb", - "dmg_sound/dmg_sound.gb", - "dmg_sound/rom_singles/01-registers.gb", - "dmg_sound/rom_singles/02-len ctr.gb", - "dmg_sound/rom_singles/03-trigger.gb", - "dmg_sound/rom_singles/04-sweep.gb", - "dmg_sound/rom_singles/05-sweep details.gb", - "dmg_sound/rom_singles/06-overflow on trigger.gb", - "dmg_sound/rom_singles/07-len sweep period sync.gb", - "dmg_sound/rom_singles/08-len ctr during power.gb", - "dmg_sound/rom_singles/09-wave read while on.gb", - "dmg_sound/rom_singles/10-wave trigger while on.gb", - "dmg_sound/rom_singles/11-regs after power.gb", - "dmg_sound/rom_singles/12-wave write while on.gb", - "instr_timing/instr_timing.gb", - "interrupt_time/interrupt_time.gb", - "mem_timing/individual/01-read_timing.gb", - "mem_timing/individual/02-write_timing.gb", - "mem_timing/individual/03-modify_timing.gb", - "mem_timing/mem_timing.gb", - "mem_timing-2/mem_timing.gb", - "mem_timing-2/rom_singles/01-read_timing.gb", - "mem_timing-2/rom_singles/02-write_timing.gb", - "mem_timing-2/rom_singles/03-modify_timing.gb", - "oam_bug/oam_bug.gb", - "oam_bug/rom_singles/1-lcd_sync.gb", - "oam_bug/rom_singles/2-causes.gb", - "oam_bug/rom_singles/3-non_causes.gb", - "oam_bug/rom_singles/4-scanline_timing.gb", - "oam_bug/rom_singles/5-timing_bug.gb", - "oam_bug/rom_singles/6-timing_no_bug.gb", - "oam_bug/rom_singles/7-timing_effect.gb", - "oam_bug/rom_singles/8-instr_effect.gb", + "test_rom, max_frames", [ + ("cgb_sound/cgb_sound.gb", 4_000), + ("cgb_sound/rom_singles/01-registers.gb", 700), + ("cgb_sound/rom_singles/02-len ctr.gb", 700), + ("cgb_sound/rom_singles/03-trigger.gb", 700), + ("cgb_sound/rom_singles/04-sweep.gb", 700), + ("cgb_sound/rom_singles/05-sweep details.gb", 700), + ("cgb_sound/rom_singles/06-overflow on trigger.gb", 700), + ("cgb_sound/rom_singles/07-len sweep period sync.gb", 700), + ("cgb_sound/rom_singles/08-len ctr during power.gb", 700), + ("cgb_sound/rom_singles/09-wave read while on.gb", 700), + ("cgb_sound/rom_singles/10-wave trigger while on.gb", 700), + ("cgb_sound/rom_singles/11-regs after power.gb", 700), + ("cgb_sound/rom_singles/12-wave.gb", 700), + ("cpu_instrs/cpu_instrs.gb", 4_000), + ("cpu_instrs/individual/01-special.gb", 700), + ("cpu_instrs/individual/02-interrupts.gb", 700), + ("cpu_instrs/individual/03-op sp,hl.gb", 700), + ("cpu_instrs/individual/04-op r,imm.gb", 700), + ("cpu_instrs/individual/05-op rp.gb", 700), + ("cpu_instrs/individual/06-ld r,r.gb", 700), + ("cpu_instrs/individual/07-jr,jp,call,ret,rst.gb", 700), + ("cpu_instrs/individual/08-misc instrs.gb", 700), + ("cpu_instrs/individual/09-op r,r.gb", 700), + ("cpu_instrs/individual/10-bit ops.gb", 2_000), + ("cpu_instrs/individual/11-op a,(hl).gb", 2_000), + ("dmg_sound/dmg_sound.gb", 700), + ("dmg_sound/rom_singles/01-registers.gb", 700), + ("dmg_sound/rom_singles/02-len ctr.gb", 700), + ("dmg_sound/rom_singles/03-trigger.gb", 700), + ("dmg_sound/rom_singles/04-sweep.gb", 700), + ("dmg_sound/rom_singles/05-sweep details.gb", 700), + ("dmg_sound/rom_singles/06-overflow on trigger.gb", 700), + ("dmg_sound/rom_singles/07-len sweep period sync.gb", 700), + ("dmg_sound/rom_singles/08-len ctr during power.gb", 700), + ("dmg_sound/rom_singles/09-wave read while on.gb", 700), + ("dmg_sound/rom_singles/10-wave trigger while on.gb", 700), + ("dmg_sound/rom_singles/11-regs after power.gb", 700), + ("dmg_sound/rom_singles/12-wave write while on.gb", 700), + ("instr_timing/instr_timing.gb", 2_000), + ("interrupt_time/interrupt_time.gb", 700), + ("mem_timing/individual/01-read_timing.gb", 700), + ("mem_timing/individual/02-write_timing.gb", 700), + ("mem_timing/individual/03-modify_timing.gb", 700), + ("mem_timing/mem_timing.gb", 700), + ("mem_timing-2/mem_timing.gb", 700), + ("mem_timing-2/rom_singles/01-read_timing.gb", 700), + ("mem_timing-2/rom_singles/02-write_timing.gb", 700), + ("mem_timing-2/rom_singles/03-modify_timing.gb", 700), + ("oam_bug/oam_bug.gb", 2_000), + ("oam_bug/rom_singles/1-lcd_sync.gb", 700), + ("oam_bug/rom_singles/2-causes.gb", 700), + ("oam_bug/rom_singles/3-non_causes.gb", 700), + ("oam_bug/rom_singles/4-scanline_timing.gb", 700), + ("oam_bug/rom_singles/5-timing_bug.gb", 700), + ("oam_bug/rom_singles/6-timing_no_bug.gb", 700), + ("oam_bug/rom_singles/7-timing_effect.gb", 700), + ("oam_bug/rom_singles/8-instr_effect.gb", 700), ] ) -def test_blarggs(test_rom, blargg_dir): +def test_blarggs(test_rom, max_frames, blargg_dir): rom = str(blargg_dir / Path(test_rom)) - result = run_rom(rom) + result = run_rom(rom, max_frames) if os.path.isfile(blargg_json): with open(blargg_json, "r") as f: From f1faa97ed30748234da328a0b68470461a862118 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sun, 29 Sep 2024 17:23:02 +0200 Subject: [PATCH 07/22] Add places to bail in MB and opcodes but not CPU --- pyboy/core/cpu.pxd | 2 +- pyboy/core/mb.py | 7 +++++++ pyboy/core/opcodes.py | 3 +++ pyboy/core/opcodes_gen.py | 9 +++++++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pyboy/core/cpu.pxd b/pyboy/core/cpu.pxd index f1cf0d393..6b803d76a 100644 --- a/pyboy/core/cpu.pxd +++ b/pyboy/core/cpu.pxd @@ -26,7 +26,7 @@ cdef uint8_t INTR_VBLANK, INTR_LCDC, INTR_TIMER, INTR_SERIAL, INTR_HIGHTOLOW cdef class CPU: cdef bint is_stuck - cdef bint interrupt_master_enable, interrupt_queued, halted, stopped + cdef bint interrupt_master_enable, interrupt_queued, halted, stopped, bail cdef uint8_t interrupts_flag, interrupts_enabled, interrupts_flag_register, interrupts_enabled_register diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index b717b9065..78ead0825 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -441,9 +441,11 @@ def setitem(self, i, value): if 0x0000 <= i < 0x4000: # 16kB ROM bank #0 # Doesn't change the data. This is for MBC commands self.cartridge.setitem(i, value) + self.cpu.bail = True elif 0x4000 <= i < 0x8000: # 16kB switchable ROM bank # Doesn't change the data. This is for MBC commands self.cartridge.setitem(i, value) + self.cpu.bail = True elif 0x8000 <= i < 0xA000: # 8kB Video RAM if not self.cgb or self.lcd.vbk.active_bank == 0: self.lcd.VRAM0[i - 0x8000] = value @@ -525,13 +527,16 @@ def setitem(self, i, value): self.lcd.WX = value else: self.ram.io_ports[i - 0xFF00] = value + self.cpu.bail = True elif 0xFF4C <= i < 0xFF80: # Empty but unusable for I/O if self.bootrom_enabled and i == 0xFF50 and (value == 0x1 or value == 0x11): logger.debug("Bootrom disabled!") self.bootrom_enabled = False + self.cpu.bail = True # CGB registers elif self.cgb and i == 0xFF4D: self.key1 = value + self.cpu.bail = True elif self.cgb and i == 0xFF4F: self.lcd.vbk.set(value) elif self.cgb and i == 0xFF51: @@ -544,6 +549,7 @@ def setitem(self, i, value): self.hdma.hdma4 = value # & 0xF0 elif self.cgb and i == 0xFF55: self.hdma.set_hdma5(value, self) + self.cpu.bail = True elif self.cgb and i == 0xFF68: self.lcd.bcps.set(value) elif self.cgb and i == 0xFF69: @@ -562,6 +568,7 @@ def setitem(self, i, value): self.ram.internal_ram1[i - 0xFF80] = value elif i == 0xFFFF: # Interrupt Enable Register self.cpu.interrupts_enabled_register = value + self.cpu.bail = True # else: # logger.critical("Memory access violation. Tried to write: 0x%0.2x to 0x%0.4x", value, i) diff --git a/pyboy/core/opcodes.py b/pyboy/core/opcodes.py index 743036227..d90ede52e 100644 --- a/pyboy/core/opcodes.py +++ b/pyboy/core/opcodes.py @@ -12,6 +12,7 @@ FLAGC, FLAGH, FLAGN, FLAGZ = range(4, 8) def BRK(cpu): + cpu.bail = True cpu.mb.breakpoint_singlestep = 1 cpu.mb.breakpoint_singlestep_latch = 0 # NOTE: We do not increment PC @@ -2332,6 +2333,7 @@ def RET_D8(cpu): # D8 RET C def RETI_D9(cpu): # D9 RETI cpu.interrupt_master_enable = True + cpu.bail = (cpu.interrupts_flag_register & 0b11111) & (cpu.interrupts_enabled_register & 0b11111) cpu.PC = cpu.mb.getitem((cpu.SP + 1) & 0xFFFF) << 8 # High cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 @@ -2591,6 +2593,7 @@ def LD_FA(cpu, v): # FA LD A,(a16) def EI_FB(cpu): # FB EI cpu.interrupt_master_enable = True + cpu.bail = (cpu.interrupts_flag_register & 0b11111) & (cpu.interrupts_enabled_register & 0b11111) cpu.PC += 1 cpu.PC &= 0xFFFF return 4 diff --git a/pyboy/core/opcodes_gen.py b/pyboy/core/opcodes_gen.py index 279e94462..333ceb231 100644 --- a/pyboy/core/opcodes_gen.py +++ b/pyboy/core/opcodes_gen.py @@ -26,6 +26,7 @@ FLAGC, FLAGH, FLAGN, FLAGZ = range(4, 8) def BRK(cpu): + cpu.bail = True cpu.mb.breakpoint_singlestep = 1 cpu.mb.breakpoint_singlestep_latch = 0 # NOTE: We do not increment PC @@ -470,7 +471,10 @@ def CB(self): def EI(self): code = Code(self.name.split()[0], self.opcode, self.name, 0, self.length, self.cycles) - code.addline("cpu.interrupt_master_enable = True") + code.addlines([ + "cpu.interrupt_master_enable = True", + "cpu.bail = (cpu.interrupts_flag_register & 0b11111) & (cpu.interrupts_enabled_register & 0b11111)", + ]) return code.getcode() def DI(self): @@ -1001,8 +1005,9 @@ def RET(self): def RETI(self): code = Code(self.name.split()[0], self.opcode, self.name, False, self.length, self.cycles, branch_op=True) - code.addline("cpu.interrupt_master_enable = True") code.addlines([ + "cpu.interrupt_master_enable = True", + "cpu.bail = (cpu.interrupts_flag_register & 0b11111) & (cpu.interrupts_enabled_register & 0b11111)", "cpu.PC = cpu.mb.getitem((cpu.SP + 1) & 0xFFFF) << 8 # High", "cpu.PC |= cpu.mb.getitem(cpu.SP) # Low", "cpu.SP += 2", From b32e6274989f838658a597e8efb498fac926dd6b Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sun, 29 Sep 2024 17:26:47 +0200 Subject: [PATCH 08/22] Implement cycles target for CPU with support to bail --- pyboy/core/cpu.pxd | 7 ++++-- pyboy/core/cpu.py | 55 ++++++++++++++++++++++++++-------------------- pyboy/core/mb.pxd | 3 ++- pyboy/core/mb.py | 18 ++++++++------- pyboy/utils.py | 2 +- 5 files changed, 49 insertions(+), 36 deletions(-) diff --git a/pyboy/core/cpu.pxd b/pyboy/core/cpu.pxd index 6b803d76a..c7d58703e 100644 --- a/pyboy/core/cpu.pxd +++ b/pyboy/core/cpu.pxd @@ -4,7 +4,7 @@ # -from libc.stdint cimport int16_t, uint8_t, uint16_t, uint32_t, uint64_t +from libc.stdint cimport int16_t, uint8_t, uint16_t, int64_t cimport pyboy.core.mb from pyboy.utils cimport IntIOInterface @@ -30,13 +30,16 @@ cdef class CPU: cdef uint8_t interrupts_flag, interrupts_enabled, interrupts_flag_register, interrupts_enabled_register + cdef int64_t cycles + cdef inline int 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(_cycles0=int64_t) + cdef int tick(self, int64_t) noexcept nogil cdef void save_state(self, IntIOInterface) noexcept cdef void load_state(self, IntIOInterface, int) noexcept diff --git a/pyboy/core/cpu.py b/pyboy/core/cpu.py index a24d36e11..90c72ef97 100644 --- a/pyboy/core/cpu.py +++ b/pyboy/core/cpu.py @@ -39,6 +39,7 @@ def __init__(self, mb): self.halted = False self.stopped = False self.is_stuck = False + self.cycles = 0 def save_state(self, f): for n in [self.A, self.F, self.B, self.C, self.D, self.E]: @@ -53,6 +54,7 @@ def save_state(self, f): f.write(self.interrupts_enabled_register) f.write(self.interrupt_queued) f.write(self.interrupts_flag_register) + f.write_64bit(self.cycles) def load_state(self, f, state_version): self.A, self.F, self.B, self.C, self.D, self.E = [f.read() for _ in range(6)] @@ -69,6 +71,8 @@ def load_state(self, f, state_version): if state_version >= 8: self.interrupt_queued = f.read() self.interrupts_flag_register = f.read() + if state_version >= 12: + self.cycles = f.read_64bit() logger.debug("State loaded: %s", self.dump_state("")) def dump_state(self, sym_label): @@ -103,30 +107,33 @@ def dump_state(self, sym_label): def set_interruptflag(self, flag): self.interrupts_flag_register |= flag - def tick(self): - if self.check_interrupts(): - self.halted = False - # TODO: We return with the cycles it took to handle the interrupt - return 0 - - if self.halted and self.interrupt_queued: - # GBCPUman.pdf page 20 - # WARNING: The instruction immediately following the HALT instruction is "skipped" when interrupts are - # disabled (DI) on the GB,GBP, and SGB. - self.halted = False - self.PC += 1 - self.PC &= 0xFFFF - elif self.halted: - return 4 # TODO: Number of cycles for a HALT in effect? - - 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. - cycles = self.fetch_and_execute() - if not self.halted and old_pc == self.PC and old_sp == self.SP and not self.is_stuck and not self.mb.breakpoint_singlestep: - logger.debug("CPU is stuck: %s", self.dump_state("")) - self.is_stuck = True - self.interrupt_queued = False - return cycles + def tick(self, cycles_target): + _cycles0 = self.cycles + _target = _cycles0 + cycles_target + self.bail = False + while self.cycles < _target: + if self.check_interrupts(): + self.halted = False + # TODO: We return with the cycles it took to handle the interrupt + break + # return cycles + + if self.halted and self.interrupt_queued: + # GBCPUman.pdf page 20 + # WARNING: The instruction immediately following the HALT instruction is "skipped" when interrupts are + # disabled (DI) on the GB,GBP, and SGB. + self.halted = False + self.PC += 1 + self.PC &= 0xFFFF + elif self.halted: + self.cycles += cycles_target # TODO: Number of cycles for a HALT in effect? + break + + self.interrupt_queued = False + + self.cycles += self.fetch_and_execute() + if self.bail: # Possible cycles-target changes + break def check_interrupts(self): if self.interrupt_queued: diff --git a/pyboy/core/mb.pxd b/pyboy/core/mb.pxd index c43f7fb18..065c12b6d 100644 --- a/pyboy/core/mb.pxd +++ b/pyboy/core/mb.pxd @@ -21,6 +21,7 @@ from pyboy.utils cimport IntIOInterface, WindowEvent cdef Logger logger +cdef int64_t MAX_CYCLES cdef uint16_t STAT, LY, LYC cdef short VBLANK, LCDC, TIMER, SERIAL, HIGHTOLOW cdef int INTR_VBLANK, INTR_LCDC, INTR_TIMER, INTR_SERIAL, INTR_HIGHTOLOW @@ -59,7 +60,7 @@ cdef class Motherboard: cdef void buttonevent(self, WindowEvent) noexcept cdef void stop(self, bint) noexcept - @cython.locals(cycles=int64_t, mode0_cycles=int64_t, breakpoint_index=int64_t) + @cython.locals(cycles=int64_t, cycles_target=int64_t, mode0_cycles=int64_t, breakpoint_index=int64_t) cdef bint tick(self) noexcept nogil cdef void switch_speed(self) noexcept nogil diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index 78ead0825..bc78e3c09 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -15,6 +15,8 @@ logger = pyboy.logging.get_logger(__name__) +MAX_CYCLES = 1 << 16 + class Motherboard: def __init__( @@ -275,12 +277,10 @@ def processing_frame(self): def tick(self): while self.processing_frame(): + _cycles0 = self.cpu.cycles if self.cgb and self.hdma.transfer_active and self.lcd._STAT._mode & 0b11 == 0: - cycles = self.hdma.tick(self) + self.cpu.cycles = self.cpu.cycles + self.hdma.tick(self) else: - cycles = self.cpu.tick() - - if self.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. @@ -288,13 +288,12 @@ def tick(self): # it gets triggered mid-frame or by next frame # Serial is not implemented, so this isn't a concern - # Help Cython with types - mode0_cycles = 1 << 32 + mode0_cycles = MAX_CYCLES if self.cgb and self.hdma.transfer_active: mode0_cycles = self.lcd.cycles_to_mode0() - cycles = max( - 0, + cycles_target = max( + 4, min( self.lcd.cycles_to_interrupt(), self.timer.cycles_to_interrupt(), @@ -302,10 +301,13 @@ def tick(self): mode0_cycles ) ) + self.cpu.tick(cycles_target) #TODO: Support General Purpose DMA # https://gbdev.io/pandocs/CGB_Registers.html#bit-7--0---general-purpose-dma + cycles = self.cpu.cycles - _cycles0 + # TODO: Unify interface sclock = self.sound.clock if self.cgb and self.double_speed: diff --git a/pyboy/utils.py b/pyboy/utils.py index 8dee8a1bb..168844edc 100644 --- a/pyboy/utils.py +++ b/pyboy/utils.py @@ -5,7 +5,7 @@ __all__ = ["WindowEvent", "dec_to_bcd", "bcd_to_dec"] -STATE_VERSION = 11 +STATE_VERSION = 12 ############################################################## # Buffer classes From 4b6a0531510c12038ed354e24f717de4a9ce9036 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sun, 29 Sep 2024 17:12:40 +0200 Subject: [PATCH 09/22] Refactor LCD and Timer cycles_to_interrupts --- pyboy/core/cpu.pxd | 2 +- pyboy/core/cpu.py | 4 ++-- pyboy/core/lcd.pxd | 3 ++- pyboy/core/lcd.py | 16 ++++++++++++---- pyboy/core/mb.py | 10 ++++++---- pyboy/core/timer.pxd | 4 ++-- pyboy/core/timer.py | 37 +++++++++++++++++++------------------ 7 files changed, 44 insertions(+), 32 deletions(-) diff --git a/pyboy/core/cpu.pxd b/pyboy/core/cpu.pxd index c7d58703e..c53e51f16 100644 --- a/pyboy/core/cpu.pxd +++ b/pyboy/core/cpu.pxd @@ -4,7 +4,7 @@ # -from libc.stdint cimport int16_t, uint8_t, uint16_t, int64_t +from libc.stdint cimport int16_t, int64_t, uint8_t, uint16_t, int64_t cimport pyboy.core.mb from pyboy.utils cimport IntIOInterface diff --git a/pyboy/core/cpu.py b/pyboy/core/cpu.py index 90c72ef97..69525155d 100644 --- a/pyboy/core/cpu.py +++ b/pyboy/core/cpu.py @@ -97,8 +97,8 @@ def dump_state(self, sym_label): f"Interrupts - IME: {self.mb.cpu.interrupt_master_enable}, " f"IE: {self.mb.cpu.interrupts_enabled_register:08b}, " f"IF: {self.mb.cpu.interrupts_flag_register:08b}\n" - f"LCD Intr.: {self.mb.lcd.cycles_to_interrupt()}, LY:{self.mb.lcd.LY}, LYC:{self.mb.lcd.LYC}\n" - f"Timer Intr.: {self.mb.timer.cycles_to_interrupt()}\n" + f"LCD Intr.: {self.mb.lcd._cycles_to_interrupt}, LY:{self.mb.lcd.LY}, LYC:{self.mb.lcd.LYC}\n" + f"Timer Intr.: {self.mb.timer._cycles_to_interrupt}\n" f"halted:{self.halted}, " f"interrupt_queued:{self.interrupt_queued}, " f"stopped:{self.stopped}\n" diff --git a/pyboy/core/lcd.pxd b/pyboy/core/lcd.pxd index 4b4ed074a..c431aa981 100644 --- a/pyboy/core/lcd.pxd +++ b/pyboy/core/lcd.pxd @@ -48,10 +48,11 @@ cdef class LCD: cdef PaletteRegister OBP1 cdef Renderer renderer cdef uint8_t[144][5] _scanlineparameters + cdef uint64_t last_cycles + cdef int64_t _cycles_to_interrupt @cython.locals(interrupt_flag=uint8_t,bx=int,by=int,wx=int,wy=int) cdef uint8_t tick(self, int) noexcept nogil - cdef int64_t cycles_to_interrupt(self) noexcept nogil cdef void set_lcdc(self, uint8_t) noexcept nogil cdef uint8_t get_lcdc(self) noexcept nogil diff --git a/pyboy/core/lcd.py b/pyboy/core/lcd.py index 171d114c2..769d7eb99 100644 --- a/pyboy/core/lcd.py +++ b/pyboy/core/lcd.py @@ -58,6 +58,8 @@ def __init__(self, cgb, cartridge_cgb, color_palette, cgb_color_palette, randomi self.double_speed = False self.cgb = cgb self._scanlineparameters = [[0, 0, 0, 0, 0] for _ in range(ROWS)] + self.last_cycles = 0 + self._cycles_to_interrupt = 0 if self.cgb: # Setting for both modes, even though CGB is ignoring them. BGP[0] used in scanline_blank. @@ -103,9 +105,6 @@ def get_stat(self): def set_stat(self, value): self._STAT.set(value) - def cycles_to_interrupt(self): - return self.clock_target - self.clock - def cycles_to_mode0(self): multiplier = 2 if self.double_speed else 1 mode2 = 80 * multiplier @@ -130,7 +129,12 @@ def cycles_to_mode0(self): # logger.critical("Unsupported STAT mode: %d", mode) # return 0 - def tick(self, cycles): + def tick(self, _cycles): + cycles = _cycles - self.last_cycles + if cycles == 0: + return False + self.last_cycles = _cycles + interrupt_flag = 0 self.clock += cycles @@ -205,6 +209,7 @@ def tick(self, cycles): # Renderer self.renderer.blank_screen(self) + self._cycles_to_interrupt = self.clock_target - self.clock return interrupt_flag def save_state(self, f): @@ -239,6 +244,7 @@ def save_state(self, f): # CGB f.write(self.cgb) f.write(self.double_speed) + f.write_64bit(self.last_cycles) f.write_64bit(self.clock) f.write_64bit(self.clock_target) f.write(self.next_stat_mode) @@ -293,6 +299,8 @@ def load_state(self, f, state_version): self.cgb = _cgb self.double_speed = f.read() + if state_version >= 12: + self.last_cycles = f.read_64bit() self.clock = f.read_64bit() self.clock_target = f.read_64bit() self.next_stat_mode = f.read() diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index bc78e3c09..4fac92bc4 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -295,8 +295,8 @@ def tick(self): cycles_target = max( 4, min( - self.lcd.cycles_to_interrupt(), - self.timer.cycles_to_interrupt(), + self.timer._cycles_to_interrupt, + self.lcd._cycles_to_interrupt, # TODO: Be more agreesive. Only if actual interrupt enabled. # self.serial.cycles_to_interrupt(), mode0_cycles ) @@ -315,10 +315,10 @@ def tick(self): else: self.sound.clock = sclock + cycles - if self.timer.tick(cycles): + if self.timer.tick(self.cpu.cycles): self.cpu.set_interruptflag(INTR_TIMER) - lcd_interrupt = self.lcd.tick(cycles) + lcd_interrupt = self.lcd.tick(self.cpu.cycles) if lcd_interrupt: self.cpu.set_interruptflag(lcd_interrupt) @@ -365,6 +365,7 @@ def getitem(self, i): elif 0xFEA0 <= i < 0xFF00: # Empty but unusable for I/O return self.ram.non_io_internal_ram0[i - 0xFEA0] elif 0xFF00 <= i < 0xFF4C: # I/O ports + assert not self.timer.tick(self.cpu.cycles) if i == 0xFF04: return self.timer.DIV elif i == 0xFF05: @@ -478,6 +479,7 @@ def setitem(self, i, value): elif 0xFEA0 <= i < 0xFF00: # Empty but unusable for I/O self.ram.non_io_internal_ram0[i - 0xFEA0] = value elif 0xFF00 <= i < 0xFF4C: # I/O ports + assert not self.timer.tick(self.cpu.cycles) if i == 0xFF00: self.ram.io_ports[i - 0xFF00] = self.interaction.pull(value) elif i == 0xFF01: diff --git a/pyboy/core/timer.pxd b/pyboy/core/timer.pxd index 37d75b997..b444294e8 100644 --- a/pyboy/core/timer.pxd +++ b/pyboy/core/timer.pxd @@ -18,12 +18,12 @@ cdef class Timer: cdef uint64_t DIV, TIMA, TMA, TAC cdef uint16_t DIV_counter, TIMA_counter cdef uint64_t[4] dividers + cdef int64_t _cycles_to_interrupt + cdef uint64_t last_cycles cdef void reset(self) noexcept nogil @cython.locals(divider=cython.int) cdef bint tick(self, uint64_t) noexcept nogil - @cython.locals(divider=cython.int, cyclesleft=cython.uint) - cdef int64_t cycles_to_interrupt(self) noexcept nogil cdef void save_state(self, IntIOInterface) noexcept cdef void load_state(self, IntIOInterface, int) noexcept diff --git a/pyboy/core/timer.py b/pyboy/core/timer.py index 0f89226f8..16d5cf2b2 100644 --- a/pyboy/core/timer.py +++ b/pyboy/core/timer.py @@ -25,7 +25,9 @@ def __init__(self): self.TIMA_counter = 0 self.TMA = 0 self.TAC = 0 - self.dividers = [1024, 16, 64, 256] + self.dividers = [10, 4, 6, 8] + self._cycles_to_interrupt = 0 + self.last_cycles = 0 def reset(self): # TODO: Should probably one be DIV=0, but this makes a bunch of mooneye tests pass @@ -33,39 +35,35 @@ def reset(self): self.TIMA_counter = 0 self.DIV = 0 - def tick(self, cycles): + def tick(self, _cycles): + cycles = _cycles - self.last_cycles + if cycles == 0: + return False + self.last_cycles = _cycles + self.DIV_counter += cycles self.DIV += (self.DIV_counter >> 8) # Add overflown bits to DIV self.DIV_counter &= 0xFF # Remove the overflown bits self.DIV &= 0xFF if self.TAC & 0b100 == 0: # Check if timer is not enabled + self._cycles_to_interrupt = 1 << 16 return False self.TIMA_counter += cycles divider = self.dividers[self.TAC & 0b11] - if self.TIMA_counter >= divider: - self.TIMA_counter -= divider # Keeps possible remainder + ret = False + while self.TIMA_counter >= (1 << divider): + self.TIMA_counter -= (1 << divider) # Keeps possible remainder self.TIMA += 1 if self.TIMA > 0xFF: self.TIMA = self.TMA self.TIMA &= 0xFF - return True - - return False - - def cycles_to_interrupt(self): - if self.TAC & 0b100 == 0: # Check if timer is not enabled - # Large enough, that 'calculate_cycles' will choose 'x' - return 1 << 16 - - divider = self.dividers[self.TAC & 0b11] - - cyclesleft = ((0x100 - self.TIMA) * divider) - self.TIMA_counter - - return cyclesleft + ret = True + self._cycles_to_interrupt = ((0x100 - self.TIMA) << divider) - self.TIMA_counter + return ret def save_state(self, f): f.write(self.DIV) @@ -74,6 +72,7 @@ def save_state(self, f): f.write_16bit(self.TIMA_counter) f.write(self.TMA) f.write(self.TAC) + f.write_64bit(self.last_cycles) def load_state(self, f, state_version): self.DIV = f.read() @@ -82,3 +81,5 @@ def load_state(self, f, state_version): self.TIMA_counter = f.read_16bit() self.TMA = f.read() self.TAC = f.read() + if state_version >= 12: + self.last_cycles = f.read_64bit() From cecef342427fb99419c471ddb40480817896f2e3 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sun, 29 Sep 2024 17:18:48 +0200 Subject: [PATCH 10/22] Implement LCD cycles to frame --- pyboy/core/lcd.pxd | 2 +- pyboy/core/lcd.py | 3 +++ pyboy/core/mb.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pyboy/core/lcd.pxd b/pyboy/core/lcd.pxd index c431aa981..08c769fdc 100644 --- a/pyboy/core/lcd.pxd +++ b/pyboy/core/lcd.pxd @@ -49,7 +49,7 @@ cdef class LCD: cdef Renderer renderer cdef uint8_t[144][5] _scanlineparameters cdef uint64_t last_cycles - cdef int64_t _cycles_to_interrupt + cdef int64_t _cycles_to_interrupt, _cycles_to_frame @cython.locals(interrupt_flag=uint8_t,bx=int,by=int,wx=int,wy=int) cdef uint8_t tick(self, int) noexcept nogil diff --git a/pyboy/core/lcd.py b/pyboy/core/lcd.py index 769d7eb99..ffba52543 100644 --- a/pyboy/core/lcd.py +++ b/pyboy/core/lcd.py @@ -60,6 +60,7 @@ def __init__(self, cgb, cartridge_cgb, color_palette, cgb_color_palette, randomi self._scanlineparameters = [[0, 0, 0, 0, 0] for _ in range(ROWS)] self.last_cycles = 0 self._cycles_to_interrupt = 0 + self._cycles_to_frame = FRAME_CYCLES if self.cgb: # Setting for both modes, even though CGB is ignoring them. BGP[0] used in scanline_blank. @@ -210,6 +211,7 @@ def tick(self, _cycles): self.renderer.blank_screen(self) self._cycles_to_interrupt = self.clock_target - self.clock + self._cycles_to_frame = self.clock - FRAME_CYCLES return interrupt_flag def save_state(self, f): @@ -303,6 +305,7 @@ def load_state(self, f, state_version): self.last_cycles = f.read_64bit() self.clock = f.read_64bit() self.clock_target = f.read_64bit() + self._cycles_to_frame = self.clock - FRAME_CYCLES self.next_stat_mode = f.read() if self.cgb: diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index 4fac92bc4..71c54cd33 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -297,6 +297,7 @@ def tick(self): min( self.timer._cycles_to_interrupt, self.lcd._cycles_to_interrupt, # TODO: Be more agreesive. Only if actual interrupt enabled. + self.lcd._cycles_to_frame, # self.serial.cycles_to_interrupt(), mode0_cycles ) From 4310f988ab39d03a157bc95ff4116cce3bced9d3 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Tue, 17 Sep 2024 18:12:32 +0100 Subject: [PATCH 11/22] Only pre-check interrupts and halt in CPU tick --- pyboy/core/cpu.py | 36 +++++++++++++++++------------------- pyboy/core/opcodes.py | 1 + pyboy/core/opcodes_gen.py | 1 + 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pyboy/core/cpu.py b/pyboy/core/cpu.py index 69525155d..af86cf099 100644 --- a/pyboy/core/cpu.py +++ b/pyboy/core/cpu.py @@ -110,27 +110,25 @@ def set_interruptflag(self, flag): def tick(self, cycles_target): _cycles0 = self.cycles _target = _cycles0 + cycles_target - self.bail = False - while self.cycles < _target: - if self.check_interrupts(): - self.halted = False - # TODO: We return with the cycles it took to handle the interrupt - break - # return cycles - - if self.halted and self.interrupt_queued: - # GBCPUman.pdf page 20 - # WARNING: The instruction immediately following the HALT instruction is "skipped" when interrupts are - # disabled (DI) on the GB,GBP, and SGB. - self.halted = False - self.PC += 1 - self.PC &= 0xFFFF - elif self.halted: - self.cycles += cycles_target # TODO: Number of cycles for a HALT in effect? - break - self.interrupt_queued = False + if self.check_interrupts(): + self.halted = False + # TODO: Cycles it took to handle the interrupt + + if self.halted and self.interrupt_queued: + # GBCPUman.pdf page 20 + # WARNING: The instruction immediately following the HALT instruction is "skipped" when interrupts are + # disabled (DI) on the GB,GBP, and SGB. + self.halted = False + self.PC += 1 + self.PC &= 0xFFFF + elif self.halted: + self.cycles += cycles_target # TODO: Number of cycles for a HALT in effect? + self.interrupt_queued = False + self.bail = False + while self.cycles < _target: + # TODO: cpu-stuck check for blargg tests? self.cycles += self.fetch_and_execute() if self.bail: # Possible cycles-target changes break diff --git a/pyboy/core/opcodes.py b/pyboy/core/opcodes.py index d90ede52e..2c8f3e783 100644 --- a/pyboy/core/opcodes.py +++ b/pyboy/core/opcodes.py @@ -1088,6 +1088,7 @@ def LD_75(cpu): # 75 LD (HL),L def HALT_76(cpu): # 76 HALT cpu.halted = True + cpu.bail = True return 4 diff --git a/pyboy/core/opcodes_gen.py b/pyboy/core/opcodes_gen.py index 333ceb231..00c6a9906 100644 --- a/pyboy/core/opcodes_gen.py +++ b/pyboy/core/opcodes_gen.py @@ -460,6 +460,7 @@ def HALT(self): # TODO: Implement HALT bug. code.addlines([ "cpu.halted = True", + "cpu.bail = True", "return " + self.cycles[0], ]) return code.getcode() From 5f7fcaf1ee9f63af87c258ab5b796882ef0516b0 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Mon, 16 Sep 2024 21:08:45 +0200 Subject: [PATCH 12/22] Refactor sound ticking to have a tick method --- pyboy/core/mb.py | 13 ++++--------- pyboy/core/sound.pxd | 5 ++++- pyboy/core/sound.py | 11 +++++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index 71c54cd33..5fa028be3 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -277,7 +277,6 @@ def processing_frame(self): def tick(self): while self.processing_frame(): - _cycles0 = self.cpu.cycles if self.cgb and self.hdma.transfer_active and self.lcd._STAT._mode & 0b11 == 0: self.cpu.cycles = self.cpu.cycles + self.hdma.tick(self) else: @@ -298,6 +297,7 @@ def tick(self): self.timer._cycles_to_interrupt, self.lcd._cycles_to_interrupt, # TODO: Be more agreesive. Only if actual interrupt enabled. self.lcd._cycles_to_frame, + self.sound._cycles_to_interrupt, # TODO: Not implemented # self.serial.cycles_to_interrupt(), mode0_cycles ) @@ -307,14 +307,7 @@ def tick(self): #TODO: Support General Purpose DMA # https://gbdev.io/pandocs/CGB_Registers.html#bit-7--0---general-purpose-dma - cycles = self.cpu.cycles - _cycles0 - - # TODO: Unify interface - sclock = self.sound.clock - if self.cgb and self.double_speed: - self.sound.clock = sclock + cycles//2 - else: - self.sound.clock = sclock + cycles + self.sound.tick(self.cpu.cycles, self.double_speed) if self.timer.tick(self.cpu.cycles): self.cpu.set_interruptflag(INTR_TIMER) @@ -378,6 +371,7 @@ def getitem(self, i): elif i == 0xFF0F: return self.cpu.interrupts_flag_register elif 0xFF10 <= i < 0xFF40: + self.sound.tick(self.cpu.cycles, self.double_speed) return self.sound.get(i - 0xFF10) elif i == 0xFF40: return self.lcd.get_lcdc() @@ -499,6 +493,7 @@ def setitem(self, i, value): elif i == 0xFF0F: self.cpu.interrupts_flag_register = value elif 0xFF10 <= i < 0xFF40: + self.sound.tick(self.cpu.cycles, self.double_speed) self.sound.set(i - 0xFF10, value) elif i == 0xFF40: self.lcd.set_lcdc(value) diff --git a/pyboy/core/sound.pxd b/pyboy/core/sound.pxd index 5a13b8e2f..7b1afde74 100644 --- a/pyboy/core/sound.pxd +++ b/pyboy/core/sound.pxd @@ -4,7 +4,7 @@ # cimport cython -from libc.stdint cimport uint8_t, uint16_t, uint64_t +from libc.stdint cimport int64_t, uint8_t, uint16_t, uint64_t from pyboy.logging.logging cimport Logger from pyboy.utils cimport IntIOInterface @@ -28,6 +28,8 @@ cdef class Sound: cdef object audiobuffer cdef object audiobuffer_p + cdef uint64_t last_cycles + cdef int64_t _cycles_to_interrupt cdef int clock cdef bint poweron @@ -42,6 +44,7 @@ cdef class Sound: cdef uint8_t get(self, uint8_t) noexcept nogil cdef void set(self, uint8_t, uint8_t) noexcept nogil + cdef void tick(self, int64_t, bint) noexcept nogil @cython.locals(nsamples=int, sample=int, i=int) cdef void sync(self) noexcept with gil # TODO: nogil @cython.locals(queued_time=int, samples_per_frame=int) diff --git a/pyboy/core/sound.py b/pyboy/core/sound.py index b69de626c..cd40b2905 100644 --- a/pyboy/core/sound.py +++ b/pyboy/core/sound.py @@ -59,6 +59,8 @@ def __init__(self, enabled, emulate): self.audiobuffer = array("b", [0] * 4096) # Over 2 frames self.audiobuffer_p = c_void_p(self.audiobuffer.buffer_info()[0]) + self.last_cycles = 0 + self._cycles_to_interrupt = 1 << 16 self.clock = 0 self.poweron = True @@ -150,6 +152,15 @@ def set(self, offset, value): else: raise IndexError(f"Attempted to write register {offset} in sound memory") + def tick(self, _cycles, double_speed): + cycles = _cycles - self.last_cycles + self.last_cycles = _cycles + + if double_speed: + self.clock += cycles // 2 + else: + self.clock += cycles + def sync(self): """Run the audio for the number of clock cycles stored in self.clock""" if not self.emulate: From 0c15c6803f79ebd469d4c017fb6de63dfc89b49d Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Wed, 25 Sep 2024 20:33:01 +0200 Subject: [PATCH 13/22] Fix CPU clock cycles for CB 46, CB 4E, CB 56, CB 5E, CB 66, CB 6E, CB 76, CB 7E --- pyboy/core/opcodes.py | 16 ++++++++-------- pyboy/core/opcodes_gen.py | 6 ++++++ tests/test_results/blargg.json | 2 +- tests/test_results/cgb_whichboot.gb.png | Bin 2243 -> 2361 bytes tests/test_results/dmg_whichboot.gb.png | Bin 2225 -> 2337 bytes 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/pyboy/core/opcodes.py b/pyboy/core/opcodes.py index 2c8f3e783..75703064c 100644 --- a/pyboy/core/opcodes.py +++ b/pyboy/core/opcodes.py @@ -3587,7 +3587,7 @@ def BIT_146(cpu): # 146 BIT 0,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_147(cpu): # 147 BIT 0,A @@ -3675,7 +3675,7 @@ def BIT_14E(cpu): # 14E BIT 1,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_14F(cpu): # 14F BIT 1,A @@ -3763,7 +3763,7 @@ def BIT_156(cpu): # 156 BIT 2,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_157(cpu): # 157 BIT 2,A @@ -3851,7 +3851,7 @@ def BIT_15E(cpu): # 15E BIT 3,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_15F(cpu): # 15F BIT 3,A @@ -3939,7 +3939,7 @@ def BIT_166(cpu): # 166 BIT 4,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_167(cpu): # 167 BIT 4,A @@ -4027,7 +4027,7 @@ def BIT_16E(cpu): # 16E BIT 5,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_16F(cpu): # 16F BIT 5,A @@ -4115,7 +4115,7 @@ def BIT_176(cpu): # 176 BIT 6,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_177(cpu): # 177 BIT 6,A @@ -4203,7 +4203,7 @@ def BIT_17E(cpu): # 17E BIT 7,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + return 12 def BIT_17F(cpu): # 17F BIT 7,A diff --git a/pyboy/core/opcodes_gen.py b/pyboy/core/opcodes_gen.py index 00c6a9906..cd6c07b7a 100644 --- a/pyboy/core/opcodes_gen.py +++ b/pyboy/core/opcodes_gen.py @@ -1170,6 +1170,12 @@ def BIT(self): left = Literal(r0) right = Operand(r1) code = Code(self.name.split()[0], self.opcode, self.name, False, self.length, self.cycles) + + if self.opcode in [0x146, 0x14E, 0x156, 0x15E, 0x166, 0x16E, 0x176, 0x17E]: + # FIX: Corrent cycle count is 12, not 16! + code.cycles = ("12", ) + + code.addline("t = %s & (1 << %s)" % (right.get, left.get)) code.addlines(self.handleflags8bit(left.get, right.get, None, False)) diff --git a/tests/test_results/blargg.json b/tests/test_results/blargg.json index d82a5c967..5e153d5eb 100644 --- a/tests/test_results/blargg.json +++ b/tests/test_results/blargg.json @@ -24,7 +24,7 @@ "blargg/dmg_sound/rom_singles/10-wave trigger while on.gb": "10-wave trigger while on\n\n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99", "blargg/dmg_sound/rom_singles/11-regs after power.gb": "11-regs after power\n\n\nPowering off should clear NR13\n\nFailed #3\n", "blargg/dmg_sound/rom_singles/12-wave write while on.gb": "12-wave write while on\n\n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 F7 44 55 66 77 88 99 AA BB CC DD EE FF \n00 F7 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \nF7 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 A", - "blargg/instr_timing/instr_timing.gb": "instr_timing\n\n01:255-3 02:254-2 03:254-2 06:254-2 09:254-2 0A:254-2 0B:254-2 0E:254-2 11:255-3 12:254-2 13:254-2 16:254-2 18:255-3 19:254-2 1A:254-2 1B:254-2 1E:254-2 20:254-2 20:255-3 21:255-3 22:254-2 23:254-2 26:254-2 28:254-2 28:255-3 29:254-2 2A:254-2 2B:254-2 2E:254-2 30:254-2 30:255-3 31:255-3 32:254-2 33:254-2 34:255-3 35:255-3 36:255-3 38:254-2 38:255-3 39:254-2 3A:254-2 3B:254-2 3E:254-2 46:254-2 4E:254-2 56:254-2 5E:254-2 66:254-2 6E:254-2 70:254-2 71:254-2 72:254-2 73:254-2 74:254-2 75:254-2 77:254-2 7E:254-2 86:254-2 8E:254-2 96:254-2 9E:254-2 A6:254-2 AE:254-2 B6:254-2 BE:254-2 C0:254-2 C1:255-3 C2:255-3 C4:255-3 C4:2-6 C6:254-2 C8:254-2 CA:255-3 CC:255-3 CC:2-6 CD:2-6 CE:254-2 D0:254-2 D1:255-3 D2:255-3 D4:255-3 D4:2-6 D6:254-2 D8:254-2 DA:255-3 DC:255-3 DC:2-6 DE:254-2 E0:255-3 E1:255-3 E2:254-2 E6:254-2 EE:254-2 F0:255-3 F1:255-3 F2:254-2 F6:254-2 F8:255-3 F9:254-2 FE:254-2 CB 00:254-2 CB 01:254-2 CB 02:254-2 CB 03:254-2 CB 04:254-2 CB 05:254-2 CB 07:254-2 CB 08:254-2 CB 09:254-2 CB 0A:254-2 CB 0B:254-2 CB 0C:254-2 CB 0D:254-2 CB 0F:254-2 CB 10:254-2 CB 11:254-2 CB 12:254-2 CB 13:254-2 CB 14:254-2 CB 15:254-2 CB 17:254-2 CB 18:254-2 CB 19:254-2 CB 1A:254-2 CB 1B:254-2 CB 1C:254-2 CB 1D:254-2 CB 1F:254-2 CB 20:254-2 CB 21:254-2 CB 22:254-2 CB 23:254-2 CB 24:254-2 CB 25:254-2 CB 27:254-2 CB 28:254-2 CB 29:254-2 CB 2A:254-2 CB 2B:254-2 CB 2C:254-2 CB 2D:254-2 CB 2F:254-2 CB 30:254-2 CB 31:254-2 CB 32:254-2 CB 33:254-2 CB 34:254-2 CB 35:254-2 CB 37:254-2 CB 38:254-2 CB 39:254-2 CB 3A:254-2 CB 3B:254-2 CB 3C:254-2 CB 3D:254-2 CB 3F:254-2 CB 40:254-2 CB 41:254-2 CB 42:254-2 CB 43:254-2 CB 44:254-2 CB 45:254-2 CB 46:4-3 CB 47:254-2 CB 48:254-2 CB 49:254-2 CB 4A:254-2 CB 4B:254-2 CB 4C:254-2 CB 4D:254-2 CB 4E:4-3 CB 4F:254-2 CB 50:254-2 CB 51:254-2 CB 52:254-2 CB 53:254-2 CB 54:254-2 CB 55:254-2 CB 56:4-3 CB 57:254-2 CB 58:254-2 CB 59:254-2 CB 5A:254-2 CB 5B:254-2 CB 5C:254-2 CB 5D:254-2 CB 5E:4-3 CB 5F:254-2 CB 60:254-2 CB 61:254-2 CB 62:254-2 CB 63:254-2 CB 64:254-2 CB 65:254-2 CB 66:4-3 CB 67:254-2 CB 68:254-2 CB 69:254-2 CB 6A:254-2 CB 6B:254-2 CB 6C:254-2 CB 6D:254-2 CB 6E:4-3 CB 6F:254-2 CB 70:254-2 CB 71:254-2 CB 72:254-2 CB 73:254-2 CB 74:254-2 CB 75:254-2 CB 76:4-3 CB 77:254-2 CB 78:254-2 CB 79:254-2 CB 7A:254-2 CB 7B:254-2 CB 7C:254-2 CB 7D:254-2 CB 7E:4-3 CB 7F:254-2 CB 80:254-2 CB 81:254-2 CB 82:254-2 CB 83:254-2 CB 84:254-2 CB 85:254-2 CB 87:254-2 CB 88:254-2 CB 89:254-2 CB 8A:254-2 CB 8B:254-2 CB 8C:254-2 CB 8D:254-2 CB 8F:254-2 CB 90:254-2 CB 91:254-2 CB 92:254-2 CB 93:254-2 CB 94:254-2 CB 95:254-2 CB 97:254-2 CB 98:254-2 CB 99:254-2 CB 9A:254-2 CB 9B:254-2 CB 9C:254-2 CB 9D:254-2 CB 9F:254-2 CB A0:254-2 CB A1:254-2 CB A2:254-2 CB A3:254-2 CB A4:254-2 CB A5:254-2 CB A7:254-2 CB A8:254-2 CB A9:254-2 CB AA:254-2 CB AB:254-2 CB AC:254-2 CB AD:254-2 CB AF:254-2 CB B0:254-2 CB B1:254-2 CB B2:254-2 CB B3:254-2 CB B4:254-2 CB B5:254-2 CB B7:254-2 CB B8:254-2 CB B9:254-2 CB BA:254-2 CB BB:254-2 CB BC:254-2 CB BD:254-2 CB BF:254-2 CB C0:254-2 CB C1:254-2 CB C2:254-2 CB C3:254-2 CB C4:254-2 CB C5:254-2 CB C7:254-2 CB C8:254-2 CB C9:254-2 CB CA:254-2 CB CB:254-2 CB CC:254-2 CB CD:254-2 CB CF:254-2 CB D0:254-2 CB D1:254-2 CB D2:254-2 CB D3:254-2 CB D4:254-2 CB D5:254-2 CB D7:254-2 CB D8:254-2 CB D9:254-2 CB DA:254-2 CB DB:254-2 CB DC:254-2 CB DD:254-2 CB DF:254-2 CB E0:254-2 CB E1:254-2 CB E2:254-2 CB E3:254-2 CB E4:254-2 CB E5:254-2 CB E7:254-2 CB E8:254-2 CB E9:254-2 CB EA:254-2 CB EB:254-2 CB EC:254-2 CB ED:254-2 CB EF:254-2 CB F0:254-2 CB F1:254-2 CB F2:254-2 CB F3:254-2 CB F4:254-2 CB F5:254-2 CB F7:254-2 CB F8:254-2 CB F9:254-2 CB FA:254-2 CB FB:254-2 CB FC:254-2 CB FD:254-2 CB FF:254-2 \nFailed\n", + "blargg/instr_timing/instr_timing.gb": "instr_timing\n\n\nPassed\n", "blargg/interrupt_time/interrupt_time.gb": "interrupt time\n\n00 00 FC \n00 08 04 \n00 00 FC \n00 08 04 \n550B72D0 \nFailed\n", "blargg/mem_timing/individual/01-read_timing.gb": "01-read_timing\n\nF0:2-3 FA:2-4 CB 46:2-3 CB 4E:2-3 CB 56:2-3 CB 5E:2-3 CB 66:2-3 CB 6E:2-3 CB 76:2-3 CB 7E:2-3 \nFailed\n", "blargg/mem_timing/individual/02-write_timing.gb": "02-write_timing\n\n36:2-3 E0:2-3 EA:2-4 \nFailed\n", diff --git a/tests/test_results/cgb_whichboot.gb.png b/tests/test_results/cgb_whichboot.gb.png index 9edda33da10ab291af965807a5c1af627b3ca44e..b25f3c39dc979d00125d78e1b2635ac7f77efe42 100644 GIT binary patch literal 2361 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 Hu0mjf1rdqp delta 2224 zcmV;h2v7H+60s4G8Gix*0002j_tyXb2zW_EK~#90?VZt@<0=S%&H3j2U%BTZyBSvj z0fDIHznZZYi6jV;CfDclDapC~lv1wiDy2M@zOL*3n{KbE`(TYjIrXUq%Aw_BqChxu zm_qvF0zVxh?a$;#@g30oeM@t|w6wxLvHEsQ9}HSgss6+eet-S>{O2UMIGl`5c<3pW z={Hy7E7e z>$;pYsm~Ao+2E%S$nO>W1T4eh>kf6ma(`Fq;`;uW9G(0gT8>EmBMJ-kIia7lzlamO zP(twM3Kr#sihp#-HGc)QBJ`)_(1Xs%A^Kaj_fQ)h&G*$o2U9-%Em{t-tnl+`8mSz< z{#NZEKpwn>)0XZ!G3Cr4(qWi1PPRV?@?a;!WAcgNtO9N~-d9W^D^mbi-`hz<>7>@N| zSJZjoB3S7^jHTnQU<|`NxM}~`6%~qn>b>ciIr2D6f28nRd^>$1WOvDvD z+;YRd<*Agol)EXJ2OrMwZL>9;Jd(e&L!?Pxa(@}U$WKAcK(ycVB@s^lrllZ;Ppr@f zS+{lhCIJg%O$W6y3C2{ArKq@pHkQU;37_blEYO6X&nHdm#D4YQLlx|N)H?6)ex`+@6O#x^>b^ac~1 zYJaqzp#0{99-b&ze_|f|c=@i%VRF0z>iaKOK>4IQqCf-|_!hJxrY8~fO*)BJ=0SM{ z6FwH4g&Cjh1m8u2ou$HW;^#q=2TPTE%c%7VI*6p1c9h?S39X4_Ip-EIJy}MBw zMc1D)t*g)z^8`axgKm~uDk8XgE=z=+8A3?ZE1|XyIpVihci`8 zy8goHJj@W*$)FZTbg~*0{F#Qq)Dj6HdVbG&BUcJ)+65Bk%x-t9j2!F!_et(w0 zFmE%7qM1=~tMOT@=?t8ySTPSy3<-TsR-Q~cXcySG*F>zr3sxF7V#c~9EXYb5>zK4| ziM*>aZ7gNpx+T)Uxe`kmZuxO8m7Vh7FJ#`vK|cV$|48d9n6z=`!G|+`e{c<_T-bCb z9F}(N6M1N3zJoYc;0DtSjMRJoH)?X@z=IVamEY)WzLt-rS<1?$-VaoXk zf8T61ZZN-B@UYy*JOFI4t266F<1W@GrbPPn3@)0e=Yc;3f#- z=aI>aI6fyUt-As)&&gUm?)WNP(j;A)k$AAsR%POW#tUIYg+yy^=6>hFoZ7n^XsWn`Hh~FdG=5~Qy+{)>djP;RS&F?9$eoIW3PHM zP!DcS=R0m%XO^vkI7|*9Uw=CE3ialJi+;RBZ{xSBW9E)w=%SmCCJ#Kg-b}gZz9iQS zKyPSR9m$$?RyD!(X84vJ-Bn_h2TSGH=HK)6Z!1j3U1)JlJeaKq_kZ{O3*sIyIWzi{ ziTdg=+c{ZOb$kTeoV_5 zw$BVb&pFXV0?2M-y)XN{KbW7VV)`6uNR0j7A8ekd9&FvR>HC9SO>$Ul zAN}St(8eZts+D14Qh)O>j@qick$&+ELt=d6`-9&a_Z3bKAd|9JJvdRYUp+VxaZZqx zfE-m1PI|tg9{kN@J@|0O?+*q$aH==MD4J+btjK`&a3bCxjFI)-03zNWOq2CpR}Avt z$=S^Mt}9dJLaY7ytnc~}_x@lhS>H8b-L1;3@0vjUJ{YT;N`KqE`KtP^lngizN027< zAKirI$A)Q}C~w|64buc!w)wHN)GwXizW+?V&L4LX9D^*U>A>#2wd(IJCm5I8W<~Li z;yeK7ni%w(ZT$Z8qIETY(26&pG^tnTkGnYQ=D}~#?~QMb<$IHK`7!2E{qkClKF8R2 z%g8X{GkBC?Uw_4`Kk7Sx?Na$x?X;dEIr}nRgYV<)j~okXuy$!MC7oX^uBL;p`EeI# zY+&^rHYPmNF*ep4c=tm3 zVfijb+%Nny-+hJ5gAd2?wpmQhkjZg}F+aAb>+}Id)qfxLwNavT{Sk3onEW2rR;BAz zt}wreKGOPhzh+~nwe&%Z&Vn(v}9IfRD%`S~Ac$Rd0SYgr=z0000 Date: Wed, 25 Sep 2024 21:39:06 +0200 Subject: [PATCH 14/22] Fix memory timings, supporting sub-opcode timing --- pyboy/core/cpu.py | 2 +- pyboy/core/mb.py | 10 +- pyboy/core/opcodes.py | 1097 +++++++++++++++++--------------- pyboy/core/opcodes_gen.py | 138 +++- tests/test_results/blargg.json | 16 +- 5 files changed, 715 insertions(+), 548 deletions(-) diff --git a/pyboy/core/cpu.py b/pyboy/core/cpu.py index af86cf099..e6e0d0a90 100644 --- a/pyboy/core/cpu.py +++ b/pyboy/core/cpu.py @@ -129,7 +129,7 @@ def tick(self, cycles_target): self.bail = False while self.cycles < _target: # TODO: cpu-stuck check for blargg tests? - self.cycles += self.fetch_and_execute() + self.fetch_and_execute() if self.bail: # Possible cycles-target changes break diff --git a/pyboy/core/mb.py b/pyboy/core/mb.py index 5fa028be3..6090d7a8d 100644 --- a/pyboy/core/mb.py +++ b/pyboy/core/mb.py @@ -359,7 +359,10 @@ def getitem(self, i): elif 0xFEA0 <= i < 0xFF00: # Empty but unusable for I/O return self.ram.non_io_internal_ram0[i - 0xFEA0] elif 0xFF00 <= i < 0xFF4C: # I/O ports - assert not self.timer.tick(self.cpu.cycles) + # NOTE: A bit ad-hoc, but interrupts can occur right between writes + if self.timer.tick(self.cpu.cycles): + self.cpu.set_interruptflag(INTR_TIMER) + if i == 0xFF04: return self.timer.DIV elif i == 0xFF05: @@ -474,7 +477,10 @@ def setitem(self, i, value): elif 0xFEA0 <= i < 0xFF00: # Empty but unusable for I/O self.ram.non_io_internal_ram0[i - 0xFEA0] = value elif 0xFF00 <= i < 0xFF4C: # I/O ports - assert not self.timer.tick(self.cpu.cycles) + # NOTE: A bit ad-hoc, but interrupts can occur right between writes + if self.timer.tick(self.cpu.cycles): + self.cpu.set_interruptflag(INTR_TIMER) + if i == 0xFF00: self.ram.io_ports[i - 0xFF00] = self.interaction.pull(value) elif i == 0xFF01: diff --git a/pyboy/core/opcodes.py b/pyboy/core/opcodes.py index 75703064c..21fed5341 100644 --- a/pyboy/core/opcodes.py +++ b/pyboy/core/opcodes.py @@ -21,7 +21,7 @@ def BRK(cpu): def NOP_00(cpu): # 00 NOP cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_01(cpu, v): # 01 LD BC,d16 @@ -29,14 +29,14 @@ def LD_01(cpu, v): # 01 LD BC,d16 cpu.C = v & 0x00FF cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_02(cpu): # 02 LD (BC),A cpu.mb.setitem(((cpu.B << 8) + cpu.C), cpu.A) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_03(cpu): # 03 INC BC @@ -47,7 +47,7 @@ def INC_03(cpu): # 03 INC BC cpu.C = t & 0x00FF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_04(cpu): # 04 INC B @@ -61,7 +61,7 @@ def INC_04(cpu): # 04 INC B cpu.B = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_05(cpu): # 05 DEC B @@ -75,14 +75,14 @@ def DEC_05(cpu): # 05 DEC B cpu.B = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_06(cpu, v): # 06 LD B,d8 cpu.B = v cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLCA_07(cpu): # 07 RLCA @@ -95,7 +95,7 @@ def RLCA_07(cpu): # 07 RLCA cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_08(cpu, v): # 08 LD (a16),SP @@ -103,7 +103,7 @@ def LD_08(cpu, v): # 08 LD (a16),SP cpu.mb.setitem(v+1, cpu.SP >> 8) cpu.PC += 3 cpu.PC &= 0xFFFF - return 20 + cpu.cycles += 20 def ADD_09(cpu): # 09 ADD HL,BC @@ -117,14 +117,14 @@ def ADD_09(cpu): # 09 ADD HL,BC cpu.HL = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_0A(cpu): # 0A LD A,(BC) cpu.A = cpu.mb.getitem(((cpu.B << 8) + cpu.C)) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def DEC_0B(cpu): # 0B DEC BC @@ -135,7 +135,7 @@ def DEC_0B(cpu): # 0B DEC BC cpu.C = t & 0x00FF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_0C(cpu): # 0C INC C @@ -149,7 +149,7 @@ def INC_0C(cpu): # 0C INC C cpu.C = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_0D(cpu): # 0D DEC C @@ -163,14 +163,14 @@ def DEC_0D(cpu): # 0D DEC C cpu.C = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_0E(cpu, v): # 0E LD C,d8 cpu.C = v cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRCA_0F(cpu): # 0F RRCA @@ -183,7 +183,7 @@ def RRCA_0F(cpu): # 0F RRCA cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def STOP_10(cpu, v): # 10 STOP 0 @@ -192,7 +192,7 @@ def STOP_10(cpu, v): # 10 STOP 0 cpu.mb.setitem(0xFF04, 0) cpu.PC += 2 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_11(cpu, v): # 11 LD DE,d16 @@ -200,14 +200,14 @@ def LD_11(cpu, v): # 11 LD DE,d16 cpu.E = v & 0x00FF cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_12(cpu): # 12 LD (DE),A cpu.mb.setitem(((cpu.D << 8) + cpu.E), cpu.A) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_13(cpu): # 13 INC DE @@ -218,7 +218,7 @@ def INC_13(cpu): # 13 INC DE cpu.E = t & 0x00FF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_14(cpu): # 14 INC D @@ -232,7 +232,7 @@ def INC_14(cpu): # 14 INC D cpu.D = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_15(cpu): # 15 DEC D @@ -246,14 +246,14 @@ def DEC_15(cpu): # 15 DEC D cpu.D = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_16(cpu, v): # 16 LD D,d8 cpu.D = v cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLA_17(cpu): # 17 RLA @@ -266,13 +266,13 @@ def RLA_17(cpu): # 17 RLA cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def JR_18(cpu, v): # 18 JR r8 cpu.PC += 2 + ((v ^ 0x80) - 0x80) cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def ADD_19(cpu): # 19 ADD HL,DE @@ -286,14 +286,14 @@ def ADD_19(cpu): # 19 ADD HL,DE cpu.HL = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_1A(cpu): # 1A LD A,(DE) cpu.A = cpu.mb.getitem(((cpu.D << 8) + cpu.E)) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def DEC_1B(cpu): # 1B DEC DE @@ -304,7 +304,7 @@ def DEC_1B(cpu): # 1B DEC DE cpu.E = t & 0x00FF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_1C(cpu): # 1C INC E @@ -318,7 +318,7 @@ def INC_1C(cpu): # 1C INC E cpu.E = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_1D(cpu): # 1D DEC E @@ -332,14 +332,14 @@ def DEC_1D(cpu): # 1D DEC E cpu.E = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_1E(cpu, v): # 1E LD E,d8 cpu.E = v cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRA_1F(cpu): # 1F RRA @@ -352,7 +352,7 @@ def RRA_1F(cpu): # 1F RRA cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def JR_20(cpu, v): # 20 JR NZ,r8 @@ -360,17 +360,17 @@ def JR_20(cpu, v): # 20 JR NZ,r8 if ((cpu.F & (1 << FLAGZ)) == 0): cpu.PC += ((v ^ 0x80) - 0x80) cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 else: cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_21(cpu, v): # 21 LD HL,d16 cpu.HL = v cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_22(cpu): # 22 LD (HL+),A @@ -379,7 +379,7 @@ def LD_22(cpu): # 22 LD (HL+),A cpu.HL &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_23(cpu): # 23 INC HL @@ -389,7 +389,7 @@ def INC_23(cpu): # 23 INC HL cpu.HL = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_24(cpu): # 24 INC H @@ -403,7 +403,7 @@ def INC_24(cpu): # 24 INC H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_25(cpu): # 25 DEC H @@ -417,14 +417,14 @@ def DEC_25(cpu): # 25 DEC H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_26(cpu, v): # 26 LD H,d8 cpu.HL = (cpu.HL & 0x00FF) | (v << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def DAA_27(cpu): # 27 DAA @@ -447,7 +447,7 @@ def DAA_27(cpu): # 27 DAA cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def JR_28(cpu, v): # 28 JR Z,r8 @@ -455,10 +455,10 @@ def JR_28(cpu, v): # 28 JR Z,r8 if ((cpu.F & (1 << FLAGZ)) != 0): cpu.PC += ((v ^ 0x80) - 0x80) cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 else: cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def ADD_29(cpu): # 29 ADD HL,HL @@ -472,7 +472,7 @@ def ADD_29(cpu): # 29 ADD HL,HL cpu.HL = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_2A(cpu): # 2A LD A,(HL+) @@ -481,7 +481,7 @@ def LD_2A(cpu): # 2A LD A,(HL+) cpu.HL &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def DEC_2B(cpu): # 2B DEC HL @@ -491,7 +491,7 @@ def DEC_2B(cpu): # 2B DEC HL cpu.HL = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_2C(cpu): # 2C INC L @@ -505,7 +505,7 @@ def INC_2C(cpu): # 2C INC L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_2D(cpu): # 2D DEC L @@ -519,14 +519,14 @@ def DEC_2D(cpu): # 2D DEC L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_2E(cpu, v): # 2E LD L,d8 cpu.HL = (cpu.HL & 0xFF00) | (v & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def CPL_2F(cpu): # 2F CPL @@ -536,7 +536,7 @@ def CPL_2F(cpu): # 2F CPL cpu.F |= flag cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def JR_30(cpu, v): # 30 JR NC,r8 @@ -544,17 +544,17 @@ def JR_30(cpu, v): # 30 JR NC,r8 if ((cpu.F & (1 << FLAGC)) == 0): cpu.PC += ((v ^ 0x80) - 0x80) cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 else: cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_31(cpu, v): # 31 LD SP,d16 cpu.SP = v cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_32(cpu): # 32 LD (HL-),A @@ -563,7 +563,7 @@ def LD_32(cpu): # 32 LD (HL-),A cpu.HL &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_33(cpu): # 33 INC SP @@ -573,7 +573,7 @@ def INC_33(cpu): # 33 INC SP cpu.SP = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_34(cpu): # 34 INC (HL) @@ -584,10 +584,11 @@ def INC_34(cpu): # 34 INC (HL) cpu.F &= 0b00010000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 1 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def DEC_35(cpu): # 35 DEC (HL) @@ -598,17 +599,19 @@ def DEC_35(cpu): # 35 DEC (HL) cpu.F &= 0b00010000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 1 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def LD_36(cpu, v): # 36 LD (HL),d8 + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, v) cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def SCF_37(cpu): # 37 SCF @@ -617,7 +620,7 @@ def SCF_37(cpu): # 37 SCF cpu.F |= flag cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def JR_38(cpu, v): # 38 JR C,r8 @@ -625,10 +628,10 @@ def JR_38(cpu, v): # 38 JR C,r8 if ((cpu.F & (1 << FLAGC)) != 0): cpu.PC += ((v ^ 0x80) - 0x80) cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 else: cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def ADD_39(cpu): # 39 ADD HL,SP @@ -642,7 +645,7 @@ def ADD_39(cpu): # 39 ADD HL,SP cpu.HL = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_3A(cpu): # 3A LD A,(HL-) @@ -651,7 +654,7 @@ def LD_3A(cpu): # 3A LD A,(HL-) cpu.HL &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def DEC_3B(cpu): # 3B DEC SP @@ -661,7 +664,7 @@ def DEC_3B(cpu): # 3B DEC SP cpu.SP = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def INC_3C(cpu): # 3C INC A @@ -675,7 +678,7 @@ def INC_3C(cpu): # 3C INC A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def DEC_3D(cpu): # 3D DEC A @@ -689,14 +692,14 @@ def DEC_3D(cpu): # 3D DEC A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_3E(cpu, v): # 3E LD A,d8 cpu.A = v cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def CCF_3F(cpu): # 3F CCF @@ -705,454 +708,454 @@ def CCF_3F(cpu): # 3F CCF cpu.F |= flag cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_40(cpu): # 40 LD B,B cpu.B = cpu.B cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_41(cpu): # 41 LD B,C cpu.B = cpu.C cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_42(cpu): # 42 LD B,D cpu.B = cpu.D cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_43(cpu): # 43 LD B,E cpu.B = cpu.E cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_44(cpu): # 44 LD B,H cpu.B = (cpu.HL >> 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_45(cpu): # 45 LD B,L cpu.B = (cpu.HL & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_46(cpu): # 46 LD B,(HL) cpu.B = cpu.mb.getitem(cpu.HL) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_47(cpu): # 47 LD B,A cpu.B = cpu.A cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_48(cpu): # 48 LD C,B cpu.C = cpu.B cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_49(cpu): # 49 LD C,C cpu.C = cpu.C cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_4A(cpu): # 4A LD C,D cpu.C = cpu.D cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_4B(cpu): # 4B LD C,E cpu.C = cpu.E cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_4C(cpu): # 4C LD C,H cpu.C = (cpu.HL >> 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_4D(cpu): # 4D LD C,L cpu.C = (cpu.HL & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_4E(cpu): # 4E LD C,(HL) cpu.C = cpu.mb.getitem(cpu.HL) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_4F(cpu): # 4F LD C,A cpu.C = cpu.A cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_50(cpu): # 50 LD D,B cpu.D = cpu.B cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_51(cpu): # 51 LD D,C cpu.D = cpu.C cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_52(cpu): # 52 LD D,D cpu.D = cpu.D cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_53(cpu): # 53 LD D,E cpu.D = cpu.E cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_54(cpu): # 54 LD D,H cpu.D = (cpu.HL >> 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_55(cpu): # 55 LD D,L cpu.D = (cpu.HL & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_56(cpu): # 56 LD D,(HL) cpu.D = cpu.mb.getitem(cpu.HL) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_57(cpu): # 57 LD D,A cpu.D = cpu.A cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_58(cpu): # 58 LD E,B cpu.E = cpu.B cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_59(cpu): # 59 LD E,C cpu.E = cpu.C cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_5A(cpu): # 5A LD E,D cpu.E = cpu.D cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_5B(cpu): # 5B LD E,E cpu.E = cpu.E cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_5C(cpu): # 5C LD E,H cpu.E = (cpu.HL >> 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_5D(cpu): # 5D LD E,L cpu.E = (cpu.HL & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_5E(cpu): # 5E LD E,(HL) cpu.E = cpu.mb.getitem(cpu.HL) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_5F(cpu): # 5F LD E,A cpu.E = cpu.A cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_60(cpu): # 60 LD H,B cpu.HL = (cpu.HL & 0x00FF) | (cpu.B << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_61(cpu): # 61 LD H,C cpu.HL = (cpu.HL & 0x00FF) | (cpu.C << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_62(cpu): # 62 LD H,D cpu.HL = (cpu.HL & 0x00FF) | (cpu.D << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_63(cpu): # 63 LD H,E cpu.HL = (cpu.HL & 0x00FF) | (cpu.E << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_64(cpu): # 64 LD H,H cpu.HL = (cpu.HL & 0x00FF) | ((cpu.HL >> 8) << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_65(cpu): # 65 LD H,L cpu.HL = (cpu.HL & 0x00FF) | ((cpu.HL & 0xFF) << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_66(cpu): # 66 LD H,(HL) cpu.HL = (cpu.HL & 0x00FF) | (cpu.mb.getitem(cpu.HL) << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_67(cpu): # 67 LD H,A cpu.HL = (cpu.HL & 0x00FF) | (cpu.A << 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_68(cpu): # 68 LD L,B cpu.HL = (cpu.HL & 0xFF00) | (cpu.B & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_69(cpu): # 69 LD L,C cpu.HL = (cpu.HL & 0xFF00) | (cpu.C & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_6A(cpu): # 6A LD L,D cpu.HL = (cpu.HL & 0xFF00) | (cpu.D & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_6B(cpu): # 6B LD L,E cpu.HL = (cpu.HL & 0xFF00) | (cpu.E & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_6C(cpu): # 6C LD L,H cpu.HL = (cpu.HL & 0xFF00) | ((cpu.HL >> 8) & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_6D(cpu): # 6D LD L,L cpu.HL = (cpu.HL & 0xFF00) | ((cpu.HL & 0xFF) & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_6E(cpu): # 6E LD L,(HL) cpu.HL = (cpu.HL & 0xFF00) | (cpu.mb.getitem(cpu.HL) & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_6F(cpu): # 6F LD L,A cpu.HL = (cpu.HL & 0xFF00) | (cpu.A & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_70(cpu): # 70 LD (HL),B cpu.mb.setitem(cpu.HL, cpu.B) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_71(cpu): # 71 LD (HL),C cpu.mb.setitem(cpu.HL, cpu.C) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_72(cpu): # 72 LD (HL),D cpu.mb.setitem(cpu.HL, cpu.D) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_73(cpu): # 73 LD (HL),E cpu.mb.setitem(cpu.HL, cpu.E) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_74(cpu): # 74 LD (HL),H cpu.mb.setitem(cpu.HL, (cpu.HL >> 8)) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_75(cpu): # 75 LD (HL),L cpu.mb.setitem(cpu.HL, (cpu.HL & 0xFF)) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def HALT_76(cpu): # 76 HALT cpu.halted = True cpu.bail = True - return 4 + cpu.cycles += 4 def LD_77(cpu): # 77 LD (HL),A cpu.mb.setitem(cpu.HL, cpu.A) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_78(cpu): # 78 LD A,B cpu.A = cpu.B cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_79(cpu): # 79 LD A,C cpu.A = cpu.C cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_7A(cpu): # 7A LD A,D cpu.A = cpu.D cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_7B(cpu): # 7B LD A,E cpu.A = cpu.E cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_7C(cpu): # 7C LD A,H cpu.A = (cpu.HL >> 8) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_7D(cpu): # 7D LD A,L cpu.A = (cpu.HL & 0xFF) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def LD_7E(cpu): # 7E LD A,(HL) cpu.A = cpu.mb.getitem(cpu.HL) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_7F(cpu): # 7F LD A,A cpu.A = cpu.A cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_80(cpu): # 80 ADD A,B @@ -1167,7 +1170,7 @@ def ADD_80(cpu): # 80 ADD A,B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_81(cpu): # 81 ADD A,C @@ -1182,7 +1185,7 @@ def ADD_81(cpu): # 81 ADD A,C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_82(cpu): # 82 ADD A,D @@ -1197,7 +1200,7 @@ def ADD_82(cpu): # 82 ADD A,D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_83(cpu): # 83 ADD A,E @@ -1212,7 +1215,7 @@ def ADD_83(cpu): # 83 ADD A,E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_84(cpu): # 84 ADD A,H @@ -1227,7 +1230,7 @@ def ADD_84(cpu): # 84 ADD A,H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_85(cpu): # 85 ADD A,L @@ -1242,7 +1245,7 @@ def ADD_85(cpu): # 85 ADD A,L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADD_86(cpu): # 86 ADD A,(HL) @@ -1257,7 +1260,7 @@ def ADD_86(cpu): # 86 ADD A,(HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def ADD_87(cpu): # 87 ADD A,A @@ -1272,7 +1275,7 @@ def ADD_87(cpu): # 87 ADD A,A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_88(cpu): # 88 ADC A,B @@ -1287,7 +1290,7 @@ def ADC_88(cpu): # 88 ADC A,B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_89(cpu): # 89 ADC A,C @@ -1302,7 +1305,7 @@ def ADC_89(cpu): # 89 ADC A,C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_8A(cpu): # 8A ADC A,D @@ -1317,7 +1320,7 @@ def ADC_8A(cpu): # 8A ADC A,D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_8B(cpu): # 8B ADC A,E @@ -1332,7 +1335,7 @@ def ADC_8B(cpu): # 8B ADC A,E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_8C(cpu): # 8C ADC A,H @@ -1347,7 +1350,7 @@ def ADC_8C(cpu): # 8C ADC A,H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_8D(cpu): # 8D ADC A,L @@ -1362,7 +1365,7 @@ def ADC_8D(cpu): # 8D ADC A,L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def ADC_8E(cpu): # 8E ADC A,(HL) @@ -1377,7 +1380,7 @@ def ADC_8E(cpu): # 8E ADC A,(HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def ADC_8F(cpu): # 8F ADC A,A @@ -1392,7 +1395,7 @@ def ADC_8F(cpu): # 8F ADC A,A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_90(cpu): # 90 SUB B @@ -1407,7 +1410,7 @@ def SUB_90(cpu): # 90 SUB B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_91(cpu): # 91 SUB C @@ -1422,7 +1425,7 @@ def SUB_91(cpu): # 91 SUB C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_92(cpu): # 92 SUB D @@ -1437,7 +1440,7 @@ def SUB_92(cpu): # 92 SUB D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_93(cpu): # 93 SUB E @@ -1452,7 +1455,7 @@ def SUB_93(cpu): # 93 SUB E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_94(cpu): # 94 SUB H @@ -1467,7 +1470,7 @@ def SUB_94(cpu): # 94 SUB H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_95(cpu): # 95 SUB L @@ -1482,7 +1485,7 @@ def SUB_95(cpu): # 95 SUB L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SUB_96(cpu): # 96 SUB (HL) @@ -1497,7 +1500,7 @@ def SUB_96(cpu): # 96 SUB (HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SUB_97(cpu): # 97 SUB A @@ -1512,7 +1515,7 @@ def SUB_97(cpu): # 97 SUB A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_98(cpu): # 98 SBC A,B @@ -1527,7 +1530,7 @@ def SBC_98(cpu): # 98 SBC A,B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_99(cpu): # 99 SBC A,C @@ -1542,7 +1545,7 @@ def SBC_99(cpu): # 99 SBC A,C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_9A(cpu): # 9A SBC A,D @@ -1557,7 +1560,7 @@ def SBC_9A(cpu): # 9A SBC A,D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_9B(cpu): # 9B SBC A,E @@ -1572,7 +1575,7 @@ def SBC_9B(cpu): # 9B SBC A,E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_9C(cpu): # 9C SBC A,H @@ -1587,7 +1590,7 @@ def SBC_9C(cpu): # 9C SBC A,H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_9D(cpu): # 9D SBC A,L @@ -1602,7 +1605,7 @@ def SBC_9D(cpu): # 9D SBC A,L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def SBC_9E(cpu): # 9E SBC A,(HL) @@ -1617,7 +1620,7 @@ def SBC_9E(cpu): # 9E SBC A,(HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SBC_9F(cpu): # 9F SBC A,A @@ -1632,7 +1635,7 @@ def SBC_9F(cpu): # 9F SBC A,A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A0(cpu): # A0 AND B @@ -1645,7 +1648,7 @@ def AND_A0(cpu): # A0 AND B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A1(cpu): # A1 AND C @@ -1658,7 +1661,7 @@ def AND_A1(cpu): # A1 AND C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A2(cpu): # A2 AND D @@ -1671,7 +1674,7 @@ def AND_A2(cpu): # A2 AND D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A3(cpu): # A3 AND E @@ -1684,7 +1687,7 @@ def AND_A3(cpu): # A3 AND E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A4(cpu): # A4 AND H @@ -1697,7 +1700,7 @@ def AND_A4(cpu): # A4 AND H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A5(cpu): # A5 AND L @@ -1710,7 +1713,7 @@ def AND_A5(cpu): # A5 AND L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def AND_A6(cpu): # A6 AND (HL) @@ -1723,7 +1726,7 @@ def AND_A6(cpu): # A6 AND (HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def AND_A7(cpu): # A7 AND A @@ -1736,7 +1739,7 @@ def AND_A7(cpu): # A7 AND A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_A8(cpu): # A8 XOR B @@ -1749,7 +1752,7 @@ def XOR_A8(cpu): # A8 XOR B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_A9(cpu): # A9 XOR C @@ -1762,7 +1765,7 @@ def XOR_A9(cpu): # A9 XOR C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_AA(cpu): # AA XOR D @@ -1775,7 +1778,7 @@ def XOR_AA(cpu): # AA XOR D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_AB(cpu): # AB XOR E @@ -1788,7 +1791,7 @@ def XOR_AB(cpu): # AB XOR E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_AC(cpu): # AC XOR H @@ -1801,7 +1804,7 @@ def XOR_AC(cpu): # AC XOR H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_AD(cpu): # AD XOR L @@ -1814,7 +1817,7 @@ def XOR_AD(cpu): # AD XOR L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def XOR_AE(cpu): # AE XOR (HL) @@ -1827,7 +1830,7 @@ def XOR_AE(cpu): # AE XOR (HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def XOR_AF(cpu): # AF XOR A @@ -1840,7 +1843,7 @@ def XOR_AF(cpu): # AF XOR A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B0(cpu): # B0 OR B @@ -1853,7 +1856,7 @@ def OR_B0(cpu): # B0 OR B cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B1(cpu): # B1 OR C @@ -1866,7 +1869,7 @@ def OR_B1(cpu): # B1 OR C cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B2(cpu): # B2 OR D @@ -1879,7 +1882,7 @@ def OR_B2(cpu): # B2 OR D cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B3(cpu): # B3 OR E @@ -1892,7 +1895,7 @@ def OR_B3(cpu): # B3 OR E cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B4(cpu): # B4 OR H @@ -1905,7 +1908,7 @@ def OR_B4(cpu): # B4 OR H cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B5(cpu): # B5 OR L @@ -1918,7 +1921,7 @@ def OR_B5(cpu): # B5 OR L cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def OR_B6(cpu): # B6 OR (HL) @@ -1931,7 +1934,7 @@ def OR_B6(cpu): # B6 OR (HL) cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def OR_B7(cpu): # B7 OR A @@ -1944,7 +1947,7 @@ def OR_B7(cpu): # B7 OR A cpu.A = t cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_B8(cpu): # B8 CP B @@ -1958,7 +1961,7 @@ def CP_B8(cpu): # B8 CP B t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_B9(cpu): # B9 CP C @@ -1972,7 +1975,7 @@ def CP_B9(cpu): # B9 CP C t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_BA(cpu): # BA CP D @@ -1986,7 +1989,7 @@ def CP_BA(cpu): # BA CP D t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_BB(cpu): # BB CP E @@ -2000,7 +2003,7 @@ def CP_BB(cpu): # BB CP E t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_BC(cpu): # BC CP H @@ -2014,7 +2017,7 @@ def CP_BC(cpu): # BC CP H t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_BD(cpu): # BD CP L @@ -2028,7 +2031,7 @@ def CP_BD(cpu): # BD CP L t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_BE(cpu): # BE CP (HL) @@ -2042,7 +2045,7 @@ def CP_BE(cpu): # BE CP (HL) t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def CP_BF(cpu): # BF CP A @@ -2056,7 +2059,7 @@ def CP_BF(cpu): # BF CP A t &= 0xFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def RET_C0(cpu): # C0 RET NZ @@ -2065,11 +2068,11 @@ def RET_C0(cpu): # C0 RET NZ cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 cpu.SP &= 0xFFFF - return 20 + cpu.cycles += 20 else: cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def POP_C1(cpu): # C1 POP BC @@ -2079,22 +2082,22 @@ def POP_C1(cpu): # C1 POP BC cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def JP_C2(cpu, v): # C2 JP NZ,a16 if ((cpu.F & (1 << FLAGZ)) == 0): cpu.PC = v - return 16 + cpu.cycles += 16 else: cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def JP_C3(cpu, v): # C3 JP a16 cpu.PC = v - return 16 + cpu.cycles += 16 def CALL_C4(cpu, v): # C4 CALL NZ,a16 @@ -2106,9 +2109,9 @@ def CALL_C4(cpu, v): # C4 CALL NZ,a16 cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = v - return 24 + cpu.cycles += 24 else: - return 12 + cpu.cycles += 12 def PUSH_C5(cpu): # C5 PUSH BC @@ -2118,7 +2121,7 @@ def PUSH_C5(cpu): # C5 PUSH BC cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 16 def ADD_C6(cpu, v): # C6 ADD A,d8 @@ -2133,7 +2136,7 @@ def ADD_C6(cpu, v): # C6 ADD A,d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_C7(cpu): # C7 RST 00H @@ -2144,7 +2147,7 @@ def RST_C7(cpu): # C7 RST 00H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 0 - return 16 + cpu.cycles += 16 def RET_C8(cpu): # C8 RET Z @@ -2153,11 +2156,11 @@ def RET_C8(cpu): # C8 RET Z cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 cpu.SP &= 0xFFFF - return 20 + cpu.cycles += 20 else: cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RET_C9(cpu): # C9 RET @@ -2165,24 +2168,24 @@ def RET_C9(cpu): # C9 RET cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 cpu.SP &= 0xFFFF - return 16 + cpu.cycles += 16 def JP_CA(cpu, v): # CA JP Z,a16 if ((cpu.F & (1 << FLAGZ)) != 0): cpu.PC = v - return 16 + cpu.cycles += 16 else: cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def PREFIX_CB(cpu): # CB PREFIX CB logger.critical('CB cannot be called!') cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CALL_CC(cpu, v): # CC CALL Z,a16 @@ -2194,9 +2197,9 @@ def CALL_CC(cpu, v): # CC CALL Z,a16 cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = v - return 24 + cpu.cycles += 24 else: - return 12 + cpu.cycles += 12 def CALL_CD(cpu, v): # CD CALL a16 @@ -2207,7 +2210,7 @@ def CALL_CD(cpu, v): # CD CALL a16 cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = v - return 24 + cpu.cycles += 24 def ADC_CE(cpu, v): # CE ADC A,d8 @@ -2222,7 +2225,7 @@ def ADC_CE(cpu, v): # CE ADC A,d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_CF(cpu): # CF RST 08H @@ -2233,7 +2236,7 @@ def RST_CF(cpu): # CF RST 08H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 8 - return 16 + cpu.cycles += 16 def RET_D0(cpu): # D0 RET NC @@ -2242,11 +2245,11 @@ def RET_D0(cpu): # D0 RET NC cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 cpu.SP &= 0xFFFF - return 20 + cpu.cycles += 20 else: cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def POP_D1(cpu): # D1 POP DE @@ -2256,17 +2259,17 @@ def POP_D1(cpu): # D1 POP DE cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def JP_D2(cpu, v): # D2 JP NC,a16 if ((cpu.F & (1 << FLAGC)) == 0): cpu.PC = v - return 16 + cpu.cycles += 16 else: cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def CALL_D4(cpu, v): # D4 CALL NC,a16 @@ -2278,9 +2281,9 @@ def CALL_D4(cpu, v): # D4 CALL NC,a16 cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = v - return 24 + cpu.cycles += 24 else: - return 12 + cpu.cycles += 12 def PUSH_D5(cpu): # D5 PUSH DE @@ -2290,7 +2293,7 @@ def PUSH_D5(cpu): # D5 PUSH DE cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 16 def SUB_D6(cpu, v): # D6 SUB d8 @@ -2305,7 +2308,7 @@ def SUB_D6(cpu, v): # D6 SUB d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_D7(cpu): # D7 RST 10H @@ -2316,7 +2319,7 @@ def RST_D7(cpu): # D7 RST 10H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 16 - return 16 + cpu.cycles += 16 def RET_D8(cpu): # D8 RET C @@ -2325,11 +2328,11 @@ def RET_D8(cpu): # D8 RET C cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 cpu.SP &= 0xFFFF - return 20 + cpu.cycles += 20 else: cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RETI_D9(cpu): # D9 RETI @@ -2339,17 +2342,17 @@ def RETI_D9(cpu): # D9 RETI cpu.PC |= cpu.mb.getitem(cpu.SP) # Low cpu.SP += 2 cpu.SP &= 0xFFFF - return 16 + cpu.cycles += 16 def JP_DA(cpu, v): # DA JP C,a16 if ((cpu.F & (1 << FLAGC)) != 0): cpu.PC = v - return 16 + cpu.cycles += 16 else: cpu.PC += 3 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def CALL_DC(cpu, v): # DC CALL C,a16 @@ -2361,9 +2364,9 @@ def CALL_DC(cpu, v): # DC CALL C,a16 cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = v - return 24 + cpu.cycles += 24 else: - return 12 + cpu.cycles += 12 def SBC_DE(cpu, v): # DE SBC A,d8 @@ -2378,7 +2381,7 @@ def SBC_DE(cpu, v): # DE SBC A,d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_DF(cpu): # DF RST 18H @@ -2389,14 +2392,15 @@ def RST_DF(cpu): # DF RST 18H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 24 - return 16 + cpu.cycles += 16 def LDH_E0(cpu, v): # E0 LDH (a8),A + cpu.cycles += 4 cpu.mb.setitem(v + 0xFF00, cpu.A) cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def POP_E1(cpu): # E1 POP HL @@ -2405,14 +2409,14 @@ def POP_E1(cpu): # E1 POP HL cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_E2(cpu): # E2 LD (C),A cpu.mb.setitem(0xFF00 + cpu.C, cpu.A) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def PUSH_E5(cpu): # E5 PUSH HL @@ -2422,7 +2426,7 @@ def PUSH_E5(cpu): # E5 PUSH HL cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 16 def AND_E6(cpu, v): # E6 AND d8 @@ -2435,7 +2439,7 @@ def AND_E6(cpu, v): # E6 AND d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_E7(cpu): # E7 RST 20H @@ -2446,7 +2450,7 @@ def RST_E7(cpu): # E7 RST 20H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 32 - return 16 + cpu.cycles += 16 def ADD_E8(cpu, v): # E8 ADD SP,r8 @@ -2460,19 +2464,20 @@ def ADD_E8(cpu, v): # E8 ADD SP,r8 cpu.SP = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 16 def JP_E9(cpu): # E9 JP (HL) cpu.PC = cpu.HL - return 4 + cpu.cycles += 4 def LD_EA(cpu, v): # EA LD (a16),A + cpu.cycles += 8 cpu.mb.setitem(v, cpu.A) cpu.PC += 3 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def XOR_EE(cpu, v): # EE XOR d8 @@ -2485,7 +2490,7 @@ def XOR_EE(cpu, v): # EE XOR d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_EF(cpu): # EF RST 28H @@ -2496,14 +2501,15 @@ def RST_EF(cpu): # EF RST 28H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 40 - return 16 + cpu.cycles += 16 def LDH_F0(cpu, v): # F0 LDH A,(a8) + cpu.cycles += 4 cpu.A = cpu.mb.getitem(v + 0xFF00) cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def POP_F1(cpu): # F1 POP AF @@ -2513,21 +2519,21 @@ def POP_F1(cpu): # F1 POP AF cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_F2(cpu): # F2 LD A,(C) cpu.A = cpu.mb.getitem(0xFF00 + cpu.C) cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def DI_F3(cpu): # F3 DI cpu.interrupt_master_enable = False cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def PUSH_F5(cpu): # F5 PUSH AF @@ -2537,7 +2543,7 @@ def PUSH_F5(cpu): # F5 PUSH AF cpu.SP &= 0xFFFF cpu.PC += 1 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 16 def OR_F6(cpu, v): # F6 OR d8 @@ -2550,7 +2556,7 @@ def OR_F6(cpu, v): # F6 OR d8 cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_F7(cpu): # F7 RST 30H @@ -2561,7 +2567,7 @@ def RST_F7(cpu): # F7 RST 30H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 48 - return 16 + cpu.cycles += 16 def LD_F8(cpu, v): # F8 LD HL,SP+r8 @@ -2575,21 +2581,22 @@ def LD_F8(cpu, v): # F8 LD HL,SP+r8 cpu.HL &= 0xFFFF cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 12 def LD_F9(cpu): # F9 LD SP,HL cpu.SP = cpu.HL cpu.PC += 1 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def LD_FA(cpu, v): # FA LD A,(a16) + cpu.cycles += 8 cpu.A = cpu.mb.getitem(v) cpu.PC += 3 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def EI_FB(cpu): # FB EI @@ -2597,7 +2604,7 @@ def EI_FB(cpu): # FB EI cpu.bail = (cpu.interrupts_flag_register & 0b11111) & (cpu.interrupts_enabled_register & 0b11111) cpu.PC += 1 cpu.PC &= 0xFFFF - return 4 + cpu.cycles += 4 def CP_FE(cpu, v): # FE CP d8 @@ -2611,7 +2618,7 @@ def CP_FE(cpu, v): # FE CP d8 t &= 0xFF cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RST_FF(cpu): # FF RST 38H @@ -2622,7 +2629,7 @@ def RST_FF(cpu): # FF RST 38H cpu.SP -= 2 cpu.SP &= 0xFFFF cpu.PC = 56 - return 16 + cpu.cycles += 16 def RLC_100(cpu): # 100 RLC B @@ -2636,7 +2643,7 @@ def RLC_100(cpu): # 100 RLC B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLC_101(cpu): # 101 RLC C @@ -2650,7 +2657,7 @@ def RLC_101(cpu): # 101 RLC C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLC_102(cpu): # 102 RLC D @@ -2664,7 +2671,7 @@ def RLC_102(cpu): # 102 RLC D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLC_103(cpu): # 103 RLC E @@ -2678,7 +2685,7 @@ def RLC_103(cpu): # 103 RLC E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLC_104(cpu): # 104 RLC H @@ -2692,7 +2699,7 @@ def RLC_104(cpu): # 104 RLC H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLC_105(cpu): # 105 RLC L @@ -2706,10 +2713,11 @@ def RLC_105(cpu): # 105 RLC L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RLC_106(cpu): # 106 RLC (HL) + cpu.cycles += 4 t = (cpu.mb.getitem(cpu.HL) << 1) + (cpu.mb.getitem(cpu.HL) >> 7) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -2717,10 +2725,11 @@ def RLC_106(cpu): # 106 RLC (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RLC_107(cpu): # 107 RLC A @@ -2734,7 +2743,7 @@ def RLC_107(cpu): # 107 RLC A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_108(cpu): # 108 RRC B @@ -2748,7 +2757,7 @@ def RRC_108(cpu): # 108 RRC B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_109(cpu): # 109 RRC C @@ -2762,7 +2771,7 @@ def RRC_109(cpu): # 109 RRC C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_10A(cpu): # 10A RRC D @@ -2776,7 +2785,7 @@ def RRC_10A(cpu): # 10A RRC D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_10B(cpu): # 10B RRC E @@ -2790,7 +2799,7 @@ def RRC_10B(cpu): # 10B RRC E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_10C(cpu): # 10C RRC H @@ -2804,7 +2813,7 @@ def RRC_10C(cpu): # 10C RRC H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_10D(cpu): # 10D RRC L @@ -2818,10 +2827,11 @@ def RRC_10D(cpu): # 10D RRC L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RRC_10E(cpu): # 10E RRC (HL) + cpu.cycles += 4 t = (cpu.mb.getitem(cpu.HL) >> 1) + ((cpu.mb.getitem(cpu.HL) & 1) << 7) + ((cpu.mb.getitem(cpu.HL) & 1) << 8) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -2829,10 +2839,11 @@ def RRC_10E(cpu): # 10E RRC (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RRC_10F(cpu): # 10F RRC A @@ -2846,7 +2857,7 @@ def RRC_10F(cpu): # 10F RRC A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_110(cpu): # 110 RL B @@ -2860,7 +2871,7 @@ def RL_110(cpu): # 110 RL B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_111(cpu): # 111 RL C @@ -2874,7 +2885,7 @@ def RL_111(cpu): # 111 RL C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_112(cpu): # 112 RL D @@ -2888,7 +2899,7 @@ def RL_112(cpu): # 112 RL D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_113(cpu): # 113 RL E @@ -2902,7 +2913,7 @@ def RL_113(cpu): # 113 RL E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_114(cpu): # 114 RL H @@ -2916,7 +2927,7 @@ def RL_114(cpu): # 114 RL H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_115(cpu): # 115 RL L @@ -2930,10 +2941,11 @@ def RL_115(cpu): # 115 RL L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RL_116(cpu): # 116 RL (HL) + cpu.cycles += 4 t = (cpu.mb.getitem(cpu.HL) << 1) + ((cpu.F & (1 << FLAGC)) != 0) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -2941,10 +2953,11 @@ def RL_116(cpu): # 116 RL (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RL_117(cpu): # 117 RL A @@ -2958,7 +2971,7 @@ def RL_117(cpu): # 117 RL A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_118(cpu): # 118 RR B @@ -2972,7 +2985,7 @@ def RR_118(cpu): # 118 RR B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_119(cpu): # 119 RR C @@ -2986,7 +2999,7 @@ def RR_119(cpu): # 119 RR C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_11A(cpu): # 11A RR D @@ -3000,7 +3013,7 @@ def RR_11A(cpu): # 11A RR D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_11B(cpu): # 11B RR E @@ -3014,7 +3027,7 @@ def RR_11B(cpu): # 11B RR E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_11C(cpu): # 11C RR H @@ -3028,7 +3041,7 @@ def RR_11C(cpu): # 11C RR H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_11D(cpu): # 11D RR L @@ -3042,10 +3055,11 @@ def RR_11D(cpu): # 11D RR L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RR_11E(cpu): # 11E RR (HL) + cpu.cycles += 4 t = (cpu.mb.getitem(cpu.HL) >> 1) + (((cpu.F & (1 << FLAGC)) != 0) << 7) + ((cpu.mb.getitem(cpu.HL) & 1) << 8) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3053,10 +3067,11 @@ def RR_11E(cpu): # 11E RR (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RR_11F(cpu): # 11F RR A @@ -3070,7 +3085,7 @@ def RR_11F(cpu): # 11F RR A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_120(cpu): # 120 SLA B @@ -3084,7 +3099,7 @@ def SLA_120(cpu): # 120 SLA B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_121(cpu): # 121 SLA C @@ -3098,7 +3113,7 @@ def SLA_121(cpu): # 121 SLA C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_122(cpu): # 122 SLA D @@ -3112,7 +3127,7 @@ def SLA_122(cpu): # 122 SLA D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_123(cpu): # 123 SLA E @@ -3126,7 +3141,7 @@ def SLA_123(cpu): # 123 SLA E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_124(cpu): # 124 SLA H @@ -3140,7 +3155,7 @@ def SLA_124(cpu): # 124 SLA H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_125(cpu): # 125 SLA L @@ -3154,10 +3169,11 @@ def SLA_125(cpu): # 125 SLA L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SLA_126(cpu): # 126 SLA (HL) + cpu.cycles += 4 t = (cpu.mb.getitem(cpu.HL) << 1) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3165,10 +3181,11 @@ def SLA_126(cpu): # 126 SLA (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SLA_127(cpu): # 127 SLA A @@ -3182,7 +3199,7 @@ def SLA_127(cpu): # 127 SLA A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_128(cpu): # 128 SRA B @@ -3196,7 +3213,7 @@ def SRA_128(cpu): # 128 SRA B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_129(cpu): # 129 SRA C @@ -3210,7 +3227,7 @@ def SRA_129(cpu): # 129 SRA C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_12A(cpu): # 12A SRA D @@ -3224,7 +3241,7 @@ def SRA_12A(cpu): # 12A SRA D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_12B(cpu): # 12B SRA E @@ -3238,7 +3255,7 @@ def SRA_12B(cpu): # 12B SRA E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_12C(cpu): # 12C SRA H @@ -3252,7 +3269,7 @@ def SRA_12C(cpu): # 12C SRA H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_12D(cpu): # 12D SRA L @@ -3266,10 +3283,11 @@ def SRA_12D(cpu): # 12D SRA L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRA_12E(cpu): # 12E SRA (HL) + cpu.cycles += 4 t = ((cpu.mb.getitem(cpu.HL) >> 1) | (cpu.mb.getitem(cpu.HL) & 0x80)) + ((cpu.mb.getitem(cpu.HL) & 1) << 8) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3277,10 +3295,11 @@ def SRA_12E(cpu): # 12E SRA (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SRA_12F(cpu): # 12F SRA A @@ -3294,7 +3313,7 @@ def SRA_12F(cpu): # 12F SRA A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_130(cpu): # 130 SWAP B @@ -3307,7 +3326,7 @@ def SWAP_130(cpu): # 130 SWAP B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_131(cpu): # 131 SWAP C @@ -3320,7 +3339,7 @@ def SWAP_131(cpu): # 131 SWAP C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_132(cpu): # 132 SWAP D @@ -3333,7 +3352,7 @@ def SWAP_132(cpu): # 132 SWAP D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_133(cpu): # 133 SWAP E @@ -3346,7 +3365,7 @@ def SWAP_133(cpu): # 133 SWAP E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_134(cpu): # 134 SWAP H @@ -3359,7 +3378,7 @@ def SWAP_134(cpu): # 134 SWAP H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_135(cpu): # 135 SWAP L @@ -3372,20 +3391,22 @@ def SWAP_135(cpu): # 135 SWAP L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SWAP_136(cpu): # 136 SWAP (HL) + cpu.cycles += 4 t = ((cpu.mb.getitem(cpu.HL) & 0xF0) >> 4) | ((cpu.mb.getitem(cpu.HL) & 0x0F) << 4) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SWAP_137(cpu): # 137 SWAP A @@ -3398,7 +3419,7 @@ def SWAP_137(cpu): # 137 SWAP A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_138(cpu): # 138 SRL B @@ -3412,7 +3433,7 @@ def SRL_138(cpu): # 138 SRL B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_139(cpu): # 139 SRL C @@ -3426,7 +3447,7 @@ def SRL_139(cpu): # 139 SRL C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_13A(cpu): # 13A SRL D @@ -3440,7 +3461,7 @@ def SRL_13A(cpu): # 13A SRL D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_13B(cpu): # 13B SRL E @@ -3454,7 +3475,7 @@ def SRL_13B(cpu): # 13B SRL E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_13C(cpu): # 13C SRL H @@ -3468,7 +3489,7 @@ def SRL_13C(cpu): # 13C SRL H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_13D(cpu): # 13D SRL L @@ -3482,10 +3503,11 @@ def SRL_13D(cpu): # 13D SRL L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SRL_13E(cpu): # 13E SRL (HL) + cpu.cycles += 4 t = (cpu.mb.getitem(cpu.HL) >> 1) + ((cpu.mb.getitem(cpu.HL) & 1) << 8) flag = 0b00000000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3493,10 +3515,11 @@ def SRL_13E(cpu): # 13E SRL (HL) cpu.F &= 0b00000000 cpu.F |= flag t &= 0xFF + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SRL_13F(cpu): # 13F SRL A @@ -3510,7 +3533,7 @@ def SRL_13F(cpu): # 13F SRL A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_140(cpu): # 140 BIT 0,B @@ -3521,7 +3544,7 @@ def BIT_140(cpu): # 140 BIT 0,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_141(cpu): # 141 BIT 0,C @@ -3532,7 +3555,7 @@ def BIT_141(cpu): # 141 BIT 0,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_142(cpu): # 142 BIT 0,D @@ -3543,7 +3566,7 @@ def BIT_142(cpu): # 142 BIT 0,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_143(cpu): # 143 BIT 0,E @@ -3554,7 +3577,7 @@ def BIT_143(cpu): # 143 BIT 0,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_144(cpu): # 144 BIT 0,H @@ -3565,7 +3588,7 @@ def BIT_144(cpu): # 144 BIT 0,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_145(cpu): # 145 BIT 0,L @@ -3576,10 +3599,11 @@ def BIT_145(cpu): # 145 BIT 0,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_146(cpu): # 146 BIT 0,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 0) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3587,7 +3611,7 @@ def BIT_146(cpu): # 146 BIT 0,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_147(cpu): # 147 BIT 0,A @@ -3598,7 +3622,7 @@ def BIT_147(cpu): # 147 BIT 0,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_148(cpu): # 148 BIT 1,B @@ -3609,7 +3633,7 @@ def BIT_148(cpu): # 148 BIT 1,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_149(cpu): # 149 BIT 1,C @@ -3620,7 +3644,7 @@ def BIT_149(cpu): # 149 BIT 1,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_14A(cpu): # 14A BIT 1,D @@ -3631,7 +3655,7 @@ def BIT_14A(cpu): # 14A BIT 1,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_14B(cpu): # 14B BIT 1,E @@ -3642,7 +3666,7 @@ def BIT_14B(cpu): # 14B BIT 1,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_14C(cpu): # 14C BIT 1,H @@ -3653,7 +3677,7 @@ def BIT_14C(cpu): # 14C BIT 1,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_14D(cpu): # 14D BIT 1,L @@ -3664,10 +3688,11 @@ def BIT_14D(cpu): # 14D BIT 1,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_14E(cpu): # 14E BIT 1,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 1) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3675,7 +3700,7 @@ def BIT_14E(cpu): # 14E BIT 1,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_14F(cpu): # 14F BIT 1,A @@ -3686,7 +3711,7 @@ def BIT_14F(cpu): # 14F BIT 1,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_150(cpu): # 150 BIT 2,B @@ -3697,7 +3722,7 @@ def BIT_150(cpu): # 150 BIT 2,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_151(cpu): # 151 BIT 2,C @@ -3708,7 +3733,7 @@ def BIT_151(cpu): # 151 BIT 2,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_152(cpu): # 152 BIT 2,D @@ -3719,7 +3744,7 @@ def BIT_152(cpu): # 152 BIT 2,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_153(cpu): # 153 BIT 2,E @@ -3730,7 +3755,7 @@ def BIT_153(cpu): # 153 BIT 2,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_154(cpu): # 154 BIT 2,H @@ -3741,7 +3766,7 @@ def BIT_154(cpu): # 154 BIT 2,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_155(cpu): # 155 BIT 2,L @@ -3752,10 +3777,11 @@ def BIT_155(cpu): # 155 BIT 2,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_156(cpu): # 156 BIT 2,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 2) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3763,7 +3789,7 @@ def BIT_156(cpu): # 156 BIT 2,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_157(cpu): # 157 BIT 2,A @@ -3774,7 +3800,7 @@ def BIT_157(cpu): # 157 BIT 2,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_158(cpu): # 158 BIT 3,B @@ -3785,7 +3811,7 @@ def BIT_158(cpu): # 158 BIT 3,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_159(cpu): # 159 BIT 3,C @@ -3796,7 +3822,7 @@ def BIT_159(cpu): # 159 BIT 3,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_15A(cpu): # 15A BIT 3,D @@ -3807,7 +3833,7 @@ def BIT_15A(cpu): # 15A BIT 3,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_15B(cpu): # 15B BIT 3,E @@ -3818,7 +3844,7 @@ def BIT_15B(cpu): # 15B BIT 3,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_15C(cpu): # 15C BIT 3,H @@ -3829,7 +3855,7 @@ def BIT_15C(cpu): # 15C BIT 3,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_15D(cpu): # 15D BIT 3,L @@ -3840,10 +3866,11 @@ def BIT_15D(cpu): # 15D BIT 3,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_15E(cpu): # 15E BIT 3,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 3) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3851,7 +3878,7 @@ def BIT_15E(cpu): # 15E BIT 3,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_15F(cpu): # 15F BIT 3,A @@ -3862,7 +3889,7 @@ def BIT_15F(cpu): # 15F BIT 3,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_160(cpu): # 160 BIT 4,B @@ -3873,7 +3900,7 @@ def BIT_160(cpu): # 160 BIT 4,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_161(cpu): # 161 BIT 4,C @@ -3884,7 +3911,7 @@ def BIT_161(cpu): # 161 BIT 4,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_162(cpu): # 162 BIT 4,D @@ -3895,7 +3922,7 @@ def BIT_162(cpu): # 162 BIT 4,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_163(cpu): # 163 BIT 4,E @@ -3906,7 +3933,7 @@ def BIT_163(cpu): # 163 BIT 4,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_164(cpu): # 164 BIT 4,H @@ -3917,7 +3944,7 @@ def BIT_164(cpu): # 164 BIT 4,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_165(cpu): # 165 BIT 4,L @@ -3928,10 +3955,11 @@ def BIT_165(cpu): # 165 BIT 4,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_166(cpu): # 166 BIT 4,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 4) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -3939,7 +3967,7 @@ def BIT_166(cpu): # 166 BIT 4,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_167(cpu): # 167 BIT 4,A @@ -3950,7 +3978,7 @@ def BIT_167(cpu): # 167 BIT 4,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_168(cpu): # 168 BIT 5,B @@ -3961,7 +3989,7 @@ def BIT_168(cpu): # 168 BIT 5,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_169(cpu): # 169 BIT 5,C @@ -3972,7 +4000,7 @@ def BIT_169(cpu): # 169 BIT 5,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_16A(cpu): # 16A BIT 5,D @@ -3983,7 +4011,7 @@ def BIT_16A(cpu): # 16A BIT 5,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_16B(cpu): # 16B BIT 5,E @@ -3994,7 +4022,7 @@ def BIT_16B(cpu): # 16B BIT 5,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_16C(cpu): # 16C BIT 5,H @@ -4005,7 +4033,7 @@ def BIT_16C(cpu): # 16C BIT 5,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_16D(cpu): # 16D BIT 5,L @@ -4016,10 +4044,11 @@ def BIT_16D(cpu): # 16D BIT 5,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_16E(cpu): # 16E BIT 5,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 5) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -4027,7 +4056,7 @@ def BIT_16E(cpu): # 16E BIT 5,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_16F(cpu): # 16F BIT 5,A @@ -4038,7 +4067,7 @@ def BIT_16F(cpu): # 16F BIT 5,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_170(cpu): # 170 BIT 6,B @@ -4049,7 +4078,7 @@ def BIT_170(cpu): # 170 BIT 6,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_171(cpu): # 171 BIT 6,C @@ -4060,7 +4089,7 @@ def BIT_171(cpu): # 171 BIT 6,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_172(cpu): # 172 BIT 6,D @@ -4071,7 +4100,7 @@ def BIT_172(cpu): # 172 BIT 6,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_173(cpu): # 173 BIT 6,E @@ -4082,7 +4111,7 @@ def BIT_173(cpu): # 173 BIT 6,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_174(cpu): # 174 BIT 6,H @@ -4093,7 +4122,7 @@ def BIT_174(cpu): # 174 BIT 6,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_175(cpu): # 175 BIT 6,L @@ -4104,10 +4133,11 @@ def BIT_175(cpu): # 175 BIT 6,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_176(cpu): # 176 BIT 6,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 6) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -4115,7 +4145,7 @@ def BIT_176(cpu): # 176 BIT 6,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_177(cpu): # 177 BIT 6,A @@ -4126,7 +4156,7 @@ def BIT_177(cpu): # 177 BIT 6,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_178(cpu): # 178 BIT 7,B @@ -4137,7 +4167,7 @@ def BIT_178(cpu): # 178 BIT 7,B cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_179(cpu): # 179 BIT 7,C @@ -4148,7 +4178,7 @@ def BIT_179(cpu): # 179 BIT 7,C cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_17A(cpu): # 17A BIT 7,D @@ -4159,7 +4189,7 @@ def BIT_17A(cpu): # 17A BIT 7,D cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_17B(cpu): # 17B BIT 7,E @@ -4170,7 +4200,7 @@ def BIT_17B(cpu): # 17B BIT 7,E cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_17C(cpu): # 17C BIT 7,H @@ -4181,7 +4211,7 @@ def BIT_17C(cpu): # 17C BIT 7,H cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_17D(cpu): # 17D BIT 7,L @@ -4192,10 +4222,11 @@ def BIT_17D(cpu): # 17D BIT 7,L cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def BIT_17E(cpu): # 17E BIT 7,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & (1 << 7) flag = 0b00100000 flag += ((t & 0xFF) == 0) << FLAGZ @@ -4203,7 +4234,7 @@ def BIT_17E(cpu): # 17E BIT 7,(HL) cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 12 + cpu.cycles += 8 def BIT_17F(cpu): # 17F BIT 7,A @@ -4214,7 +4245,7 @@ def BIT_17F(cpu): # 17F BIT 7,A cpu.F |= flag cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_180(cpu): # 180 RES 0,B @@ -4222,7 +4253,7 @@ def RES_180(cpu): # 180 RES 0,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_181(cpu): # 181 RES 0,C @@ -4230,7 +4261,7 @@ def RES_181(cpu): # 181 RES 0,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_182(cpu): # 182 RES 0,D @@ -4238,7 +4269,7 @@ def RES_182(cpu): # 182 RES 0,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_183(cpu): # 183 RES 0,E @@ -4246,7 +4277,7 @@ def RES_183(cpu): # 183 RES 0,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_184(cpu): # 184 RES 0,H @@ -4254,7 +4285,7 @@ def RES_184(cpu): # 184 RES 0,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_185(cpu): # 185 RES 0,L @@ -4262,15 +4293,17 @@ def RES_185(cpu): # 185 RES 0,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_186(cpu): # 186 RES 0,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 0) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_187(cpu): # 187 RES 0,A @@ -4278,7 +4311,7 @@ def RES_187(cpu): # 187 RES 0,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_188(cpu): # 188 RES 1,B @@ -4286,7 +4319,7 @@ def RES_188(cpu): # 188 RES 1,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_189(cpu): # 189 RES 1,C @@ -4294,7 +4327,7 @@ def RES_189(cpu): # 189 RES 1,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_18A(cpu): # 18A RES 1,D @@ -4302,7 +4335,7 @@ def RES_18A(cpu): # 18A RES 1,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_18B(cpu): # 18B RES 1,E @@ -4310,7 +4343,7 @@ def RES_18B(cpu): # 18B RES 1,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_18C(cpu): # 18C RES 1,H @@ -4318,7 +4351,7 @@ def RES_18C(cpu): # 18C RES 1,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_18D(cpu): # 18D RES 1,L @@ -4326,15 +4359,17 @@ def RES_18D(cpu): # 18D RES 1,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_18E(cpu): # 18E RES 1,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 1) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_18F(cpu): # 18F RES 1,A @@ -4342,7 +4377,7 @@ def RES_18F(cpu): # 18F RES 1,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_190(cpu): # 190 RES 2,B @@ -4350,7 +4385,7 @@ def RES_190(cpu): # 190 RES 2,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_191(cpu): # 191 RES 2,C @@ -4358,7 +4393,7 @@ def RES_191(cpu): # 191 RES 2,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_192(cpu): # 192 RES 2,D @@ -4366,7 +4401,7 @@ def RES_192(cpu): # 192 RES 2,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_193(cpu): # 193 RES 2,E @@ -4374,7 +4409,7 @@ def RES_193(cpu): # 193 RES 2,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_194(cpu): # 194 RES 2,H @@ -4382,7 +4417,7 @@ def RES_194(cpu): # 194 RES 2,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_195(cpu): # 195 RES 2,L @@ -4390,15 +4425,17 @@ def RES_195(cpu): # 195 RES 2,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_196(cpu): # 196 RES 2,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 2) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_197(cpu): # 197 RES 2,A @@ -4406,7 +4443,7 @@ def RES_197(cpu): # 197 RES 2,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_198(cpu): # 198 RES 3,B @@ -4414,7 +4451,7 @@ def RES_198(cpu): # 198 RES 3,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_199(cpu): # 199 RES 3,C @@ -4422,7 +4459,7 @@ def RES_199(cpu): # 199 RES 3,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_19A(cpu): # 19A RES 3,D @@ -4430,7 +4467,7 @@ def RES_19A(cpu): # 19A RES 3,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_19B(cpu): # 19B RES 3,E @@ -4438,7 +4475,7 @@ def RES_19B(cpu): # 19B RES 3,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_19C(cpu): # 19C RES 3,H @@ -4446,7 +4483,7 @@ def RES_19C(cpu): # 19C RES 3,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_19D(cpu): # 19D RES 3,L @@ -4454,15 +4491,17 @@ def RES_19D(cpu): # 19D RES 3,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_19E(cpu): # 19E RES 3,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 3) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_19F(cpu): # 19F RES 3,A @@ -4470,7 +4509,7 @@ def RES_19F(cpu): # 19F RES 3,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A0(cpu): # 1A0 RES 4,B @@ -4478,7 +4517,7 @@ def RES_1A0(cpu): # 1A0 RES 4,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A1(cpu): # 1A1 RES 4,C @@ -4486,7 +4525,7 @@ def RES_1A1(cpu): # 1A1 RES 4,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A2(cpu): # 1A2 RES 4,D @@ -4494,7 +4533,7 @@ def RES_1A2(cpu): # 1A2 RES 4,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A3(cpu): # 1A3 RES 4,E @@ -4502,7 +4541,7 @@ def RES_1A3(cpu): # 1A3 RES 4,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A4(cpu): # 1A4 RES 4,H @@ -4510,7 +4549,7 @@ def RES_1A4(cpu): # 1A4 RES 4,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A5(cpu): # 1A5 RES 4,L @@ -4518,15 +4557,17 @@ def RES_1A5(cpu): # 1A5 RES 4,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A6(cpu): # 1A6 RES 4,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 4) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_1A7(cpu): # 1A7 RES 4,A @@ -4534,7 +4575,7 @@ def RES_1A7(cpu): # 1A7 RES 4,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A8(cpu): # 1A8 RES 5,B @@ -4542,7 +4583,7 @@ def RES_1A8(cpu): # 1A8 RES 5,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1A9(cpu): # 1A9 RES 5,C @@ -4550,7 +4591,7 @@ def RES_1A9(cpu): # 1A9 RES 5,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1AA(cpu): # 1AA RES 5,D @@ -4558,7 +4599,7 @@ def RES_1AA(cpu): # 1AA RES 5,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1AB(cpu): # 1AB RES 5,E @@ -4566,7 +4607,7 @@ def RES_1AB(cpu): # 1AB RES 5,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1AC(cpu): # 1AC RES 5,H @@ -4574,7 +4615,7 @@ def RES_1AC(cpu): # 1AC RES 5,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1AD(cpu): # 1AD RES 5,L @@ -4582,15 +4623,17 @@ def RES_1AD(cpu): # 1AD RES 5,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1AE(cpu): # 1AE RES 5,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 5) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_1AF(cpu): # 1AF RES 5,A @@ -4598,7 +4641,7 @@ def RES_1AF(cpu): # 1AF RES 5,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B0(cpu): # 1B0 RES 6,B @@ -4606,7 +4649,7 @@ def RES_1B0(cpu): # 1B0 RES 6,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B1(cpu): # 1B1 RES 6,C @@ -4614,7 +4657,7 @@ def RES_1B1(cpu): # 1B1 RES 6,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B2(cpu): # 1B2 RES 6,D @@ -4622,7 +4665,7 @@ def RES_1B2(cpu): # 1B2 RES 6,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B3(cpu): # 1B3 RES 6,E @@ -4630,7 +4673,7 @@ def RES_1B3(cpu): # 1B3 RES 6,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B4(cpu): # 1B4 RES 6,H @@ -4638,7 +4681,7 @@ def RES_1B4(cpu): # 1B4 RES 6,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B5(cpu): # 1B5 RES 6,L @@ -4646,15 +4689,17 @@ def RES_1B5(cpu): # 1B5 RES 6,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B6(cpu): # 1B6 RES 6,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 6) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_1B7(cpu): # 1B7 RES 6,A @@ -4662,7 +4707,7 @@ def RES_1B7(cpu): # 1B7 RES 6,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B8(cpu): # 1B8 RES 7,B @@ -4670,7 +4715,7 @@ def RES_1B8(cpu): # 1B8 RES 7,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1B9(cpu): # 1B9 RES 7,C @@ -4678,7 +4723,7 @@ def RES_1B9(cpu): # 1B9 RES 7,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1BA(cpu): # 1BA RES 7,D @@ -4686,7 +4731,7 @@ def RES_1BA(cpu): # 1BA RES 7,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1BB(cpu): # 1BB RES 7,E @@ -4694,7 +4739,7 @@ def RES_1BB(cpu): # 1BB RES 7,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1BC(cpu): # 1BC RES 7,H @@ -4702,7 +4747,7 @@ def RES_1BC(cpu): # 1BC RES 7,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1BD(cpu): # 1BD RES 7,L @@ -4710,15 +4755,17 @@ def RES_1BD(cpu): # 1BD RES 7,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def RES_1BE(cpu): # 1BE RES 7,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) & ~(1 << 7) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def RES_1BF(cpu): # 1BF RES 7,A @@ -4726,7 +4773,7 @@ def RES_1BF(cpu): # 1BF RES 7,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C0(cpu): # 1C0 SET 0,B @@ -4734,7 +4781,7 @@ def SET_1C0(cpu): # 1C0 SET 0,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C1(cpu): # 1C1 SET 0,C @@ -4742,7 +4789,7 @@ def SET_1C1(cpu): # 1C1 SET 0,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C2(cpu): # 1C2 SET 0,D @@ -4750,7 +4797,7 @@ def SET_1C2(cpu): # 1C2 SET 0,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C3(cpu): # 1C3 SET 0,E @@ -4758,7 +4805,7 @@ def SET_1C3(cpu): # 1C3 SET 0,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C4(cpu): # 1C4 SET 0,H @@ -4766,7 +4813,7 @@ def SET_1C4(cpu): # 1C4 SET 0,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C5(cpu): # 1C5 SET 0,L @@ -4774,15 +4821,17 @@ def SET_1C5(cpu): # 1C5 SET 0,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C6(cpu): # 1C6 SET 0,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 0) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1C7(cpu): # 1C7 SET 0,A @@ -4790,7 +4839,7 @@ def SET_1C7(cpu): # 1C7 SET 0,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C8(cpu): # 1C8 SET 1,B @@ -4798,7 +4847,7 @@ def SET_1C8(cpu): # 1C8 SET 1,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1C9(cpu): # 1C9 SET 1,C @@ -4806,7 +4855,7 @@ def SET_1C9(cpu): # 1C9 SET 1,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1CA(cpu): # 1CA SET 1,D @@ -4814,7 +4863,7 @@ def SET_1CA(cpu): # 1CA SET 1,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1CB(cpu): # 1CB SET 1,E @@ -4822,7 +4871,7 @@ def SET_1CB(cpu): # 1CB SET 1,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1CC(cpu): # 1CC SET 1,H @@ -4830,7 +4879,7 @@ def SET_1CC(cpu): # 1CC SET 1,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1CD(cpu): # 1CD SET 1,L @@ -4838,15 +4887,17 @@ def SET_1CD(cpu): # 1CD SET 1,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1CE(cpu): # 1CE SET 1,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 1) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1CF(cpu): # 1CF SET 1,A @@ -4854,7 +4905,7 @@ def SET_1CF(cpu): # 1CF SET 1,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D0(cpu): # 1D0 SET 2,B @@ -4862,7 +4913,7 @@ def SET_1D0(cpu): # 1D0 SET 2,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D1(cpu): # 1D1 SET 2,C @@ -4870,7 +4921,7 @@ def SET_1D1(cpu): # 1D1 SET 2,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D2(cpu): # 1D2 SET 2,D @@ -4878,7 +4929,7 @@ def SET_1D2(cpu): # 1D2 SET 2,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D3(cpu): # 1D3 SET 2,E @@ -4886,7 +4937,7 @@ def SET_1D3(cpu): # 1D3 SET 2,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D4(cpu): # 1D4 SET 2,H @@ -4894,7 +4945,7 @@ def SET_1D4(cpu): # 1D4 SET 2,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D5(cpu): # 1D5 SET 2,L @@ -4902,15 +4953,17 @@ def SET_1D5(cpu): # 1D5 SET 2,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D6(cpu): # 1D6 SET 2,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 2) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1D7(cpu): # 1D7 SET 2,A @@ -4918,7 +4971,7 @@ def SET_1D7(cpu): # 1D7 SET 2,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D8(cpu): # 1D8 SET 3,B @@ -4926,7 +4979,7 @@ def SET_1D8(cpu): # 1D8 SET 3,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1D9(cpu): # 1D9 SET 3,C @@ -4934,7 +4987,7 @@ def SET_1D9(cpu): # 1D9 SET 3,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1DA(cpu): # 1DA SET 3,D @@ -4942,7 +4995,7 @@ def SET_1DA(cpu): # 1DA SET 3,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1DB(cpu): # 1DB SET 3,E @@ -4950,7 +5003,7 @@ def SET_1DB(cpu): # 1DB SET 3,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1DC(cpu): # 1DC SET 3,H @@ -4958,7 +5011,7 @@ def SET_1DC(cpu): # 1DC SET 3,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1DD(cpu): # 1DD SET 3,L @@ -4966,15 +5019,17 @@ def SET_1DD(cpu): # 1DD SET 3,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1DE(cpu): # 1DE SET 3,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 3) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1DF(cpu): # 1DF SET 3,A @@ -4982,7 +5037,7 @@ def SET_1DF(cpu): # 1DF SET 3,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E0(cpu): # 1E0 SET 4,B @@ -4990,7 +5045,7 @@ def SET_1E0(cpu): # 1E0 SET 4,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E1(cpu): # 1E1 SET 4,C @@ -4998,7 +5053,7 @@ def SET_1E1(cpu): # 1E1 SET 4,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E2(cpu): # 1E2 SET 4,D @@ -5006,7 +5061,7 @@ def SET_1E2(cpu): # 1E2 SET 4,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E3(cpu): # 1E3 SET 4,E @@ -5014,7 +5069,7 @@ def SET_1E3(cpu): # 1E3 SET 4,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E4(cpu): # 1E4 SET 4,H @@ -5022,7 +5077,7 @@ def SET_1E4(cpu): # 1E4 SET 4,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E5(cpu): # 1E5 SET 4,L @@ -5030,15 +5085,17 @@ def SET_1E5(cpu): # 1E5 SET 4,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E6(cpu): # 1E6 SET 4,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 4) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1E7(cpu): # 1E7 SET 4,A @@ -5046,7 +5103,7 @@ def SET_1E7(cpu): # 1E7 SET 4,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E8(cpu): # 1E8 SET 5,B @@ -5054,7 +5111,7 @@ def SET_1E8(cpu): # 1E8 SET 5,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1E9(cpu): # 1E9 SET 5,C @@ -5062,7 +5119,7 @@ def SET_1E9(cpu): # 1E9 SET 5,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1EA(cpu): # 1EA SET 5,D @@ -5070,7 +5127,7 @@ def SET_1EA(cpu): # 1EA SET 5,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1EB(cpu): # 1EB SET 5,E @@ -5078,7 +5135,7 @@ def SET_1EB(cpu): # 1EB SET 5,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1EC(cpu): # 1EC SET 5,H @@ -5086,7 +5143,7 @@ def SET_1EC(cpu): # 1EC SET 5,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1ED(cpu): # 1ED SET 5,L @@ -5094,15 +5151,17 @@ def SET_1ED(cpu): # 1ED SET 5,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1EE(cpu): # 1EE SET 5,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 5) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1EF(cpu): # 1EF SET 5,A @@ -5110,7 +5169,7 @@ def SET_1EF(cpu): # 1EF SET 5,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F0(cpu): # 1F0 SET 6,B @@ -5118,7 +5177,7 @@ def SET_1F0(cpu): # 1F0 SET 6,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F1(cpu): # 1F1 SET 6,C @@ -5126,7 +5185,7 @@ def SET_1F1(cpu): # 1F1 SET 6,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F2(cpu): # 1F2 SET 6,D @@ -5134,7 +5193,7 @@ def SET_1F2(cpu): # 1F2 SET 6,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F3(cpu): # 1F3 SET 6,E @@ -5142,7 +5201,7 @@ def SET_1F3(cpu): # 1F3 SET 6,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F4(cpu): # 1F4 SET 6,H @@ -5150,7 +5209,7 @@ def SET_1F4(cpu): # 1F4 SET 6,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F5(cpu): # 1F5 SET 6,L @@ -5158,15 +5217,17 @@ def SET_1F5(cpu): # 1F5 SET 6,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F6(cpu): # 1F6 SET 6,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 6) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1F7(cpu): # 1F7 SET 6,A @@ -5174,7 +5235,7 @@ def SET_1F7(cpu): # 1F7 SET 6,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F8(cpu): # 1F8 SET 7,B @@ -5182,7 +5243,7 @@ def SET_1F8(cpu): # 1F8 SET 7,B cpu.B = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1F9(cpu): # 1F9 SET 7,C @@ -5190,7 +5251,7 @@ def SET_1F9(cpu): # 1F9 SET 7,C cpu.C = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1FA(cpu): # 1FA SET 7,D @@ -5198,7 +5259,7 @@ def SET_1FA(cpu): # 1FA SET 7,D cpu.D = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1FB(cpu): # 1FB SET 7,E @@ -5206,7 +5267,7 @@ def SET_1FB(cpu): # 1FB SET 7,E cpu.E = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1FC(cpu): # 1FC SET 7,H @@ -5214,7 +5275,7 @@ def SET_1FC(cpu): # 1FC SET 7,H cpu.HL = (cpu.HL & 0x00FF) | (t << 8) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1FD(cpu): # 1FD SET 7,L @@ -5222,15 +5283,17 @@ def SET_1FD(cpu): # 1FD SET 7,L cpu.HL = (cpu.HL & 0xFF00) | (t & 0xFF) cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def SET_1FE(cpu): # 1FE SET 7,(HL) + cpu.cycles += 4 t = cpu.mb.getitem(cpu.HL) | (1 << 7) + cpu.cycles += 4 cpu.mb.setitem(cpu.HL, t) cpu.PC += 2 cpu.PC &= 0xFFFF - return 16 + cpu.cycles += 8 def SET_1FF(cpu): # 1FF SET 7,A @@ -5238,7 +5301,7 @@ def SET_1FF(cpu): # 1FF SET 7,A cpu.A = t cpu.PC += 2 cpu.PC &= 0xFFFF - return 8 + cpu.cycles += 8 def no_opcode(cpu): diff --git a/pyboy/core/opcodes_gen.py b/pyboy/core/opcodes_gen.py index cd6c07b7a..e5c750ee5 100644 --- a/pyboy/core/opcodes_gen.py +++ b/pyboy/core/opcodes_gen.py @@ -265,7 +265,7 @@ def getcode(self): if not self.branch_op: self.lines.append("cpu.PC += %d" % self.length) self.lines.append("cpu.PC &= 0xFFFF") - self.lines.append("return " + self.cycles[0]) # Choose the 0th cycle count + self.lines.append("cpu.cycles += " + self.cycles[0]) # Choose the 0th cycle count code += "\n\t".join(self.lines) @@ -461,7 +461,7 @@ def HALT(self): code.addlines([ "cpu.halted = True", "cpu.bail = True", - "return " + self.cycles[0], + "cpu.cycles += " + self.cycles[0], ]) return code.getcode() @@ -557,6 +557,24 @@ def LD(self): code = Code( self.name.split()[0], self.opcode, self.name, left.immediate or right.immediate, self.length, self.cycles ) + + # These opcodes can be observed reading mid-cycle + if self.opcode == 0x36: + code.addline("cpu.cycles += 4") + code.cycles = (str(int(code.cycles[0]) - 4), ) + elif self.opcode == 0xE0: + code.addline("cpu.cycles += 4") + code.cycles = (str(int(code.cycles[0]) - 4), ) + elif self.opcode == 0xEA: + code.addline("cpu.cycles += 8") + code.cycles = (str(int(code.cycles[0]) - 8), ) + elif self.opcode == 0xF0: + code.addline("cpu.cycles += 4") + code.cycles = (str(int(code.cycles[0]) - 4), ) + elif self.opcode == 0xFA: + code.addline("cpu.cycles += 8") + code.cycles = (str(int(code.cycles[0]) - 8), ) + if self.is16bit and left.immediate and left.pointer: code.addline(left.set % ("%s & 0xFF" % right.get)) a, b = left.set.split(",") @@ -662,6 +680,13 @@ def INC(self): self.name.split()[0], self.opcode, self.name, left.immediate or right.immediate, self.length, self.cycles ) code.addlines(self.ALU(left, right, "+")) + + if self.opcode == 0x34: + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(-1, "cpu.cycles += 4") # Inject before read + code.cycles = ("8", ) # 12 - 4 + return code.getcode() def DEC(self): @@ -673,6 +698,13 @@ def DEC(self): self.name.split()[0], self.opcode, self.name, left.immediate or right.immediate, self.length, self.cycles ) code.addlines(self.ALU(left, right, "-")) + + if self.opcode == 0x35: + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(-1, "cpu.cycles += 4") # Inject before write + code.cycles = ("8", ) # 12 - 4 + return code.getcode() def ADC(self): @@ -858,16 +890,16 @@ def JP(self): self.name.split()[0], self.opcode, self.name, right.immediate, self.length, self.cycles, branch_op=True ) if left is None: - code.addlines(["cpu.PC = %s" % ("v" if right.immediate else r_code), "return " + self.cycles[0]]) + code.addlines(["cpu.PC = %s" % ("v" if right.immediate else r_code), "cpu.cycles += " + self.cycles[0]]) else: code.addlines([ "if %s:" % l_code, "\tcpu.PC = %s" % ("v" if right.immediate else r_code), - "\treturn " + self.cycles[0], + "\tcpu.cycles += " + self.cycles[0], "else:", "\tcpu.PC += %s" % self.length, "\tcpu.PC &= 0xFFFF", - "\treturn " + self.cycles[1], + "\tcpu.cycles += " + self.cycles[1], ]) return code.getcode() @@ -897,7 +929,7 @@ def JR(self): code.addlines([ "cpu.PC += %d + " % self.length + inline_signed_int8("v"), "cpu.PC &= 0xFFFF", - "return " + self.cycles[0], + "cpu.cycles += " + self.cycles[0], ]) else: code.addlines([ @@ -905,10 +937,10 @@ def JR(self): "if %s:" % l_code, "\tcpu.PC += " + inline_signed_int8("v"), "\tcpu.PC &= 0xFFFF", - "\treturn " + self.cycles[0], + "\tcpu.cycles += " + self.cycles[0], "else:", "\tcpu.PC &= 0xFFFF", - "\treturn " + self.cycles[1], + "\tcpu.cycles += " + self.cycles[1], ]) return code.getcode() @@ -948,7 +980,7 @@ def CALL(self): "cpu.SP -= 2", "cpu.SP &= 0xFFFF", "cpu.PC = %s" % ("v" if right.immediate else right.get), - "return " + self.cycles[0], + "cpu.cycles += " + self.cycles[0], ]) else: code.addlines([ @@ -958,9 +990,9 @@ def CALL(self): "\tcpu.SP -= 2", "\tcpu.SP &= 0xFFFF", "\tcpu.PC = %s" % ("v" if right.immediate else right.get), - "\treturn " + self.cycles[0], + "\tcpu.cycles += " + self.cycles[0], "else:", - "\treturn " + self.cycles[1], + "\tcpu.cycles += " + self.cycles[1], ]) return code.getcode() @@ -986,7 +1018,7 @@ def RET(self): "cpu.PC |= cpu.mb.getitem(cpu.SP) # Low", "cpu.SP += 2", "cpu.SP &= 0xFFFF", - "return " + self.cycles[0], + "cpu.cycles += " + self.cycles[0], ]) else: code.addlines([ @@ -995,11 +1027,11 @@ def RET(self): "\tcpu.PC |= cpu.mb.getitem(cpu.SP) # Low", "\tcpu.SP += 2", "\tcpu.SP &= 0xFFFF", - "\treturn " + self.cycles[0], + "\tcpu.cycles += " + self.cycles[0], "else:", "\tcpu.PC += %s" % self.length, "\tcpu.PC &= 0xFFFF", - "\treturn " + self.cycles[1], + "\tcpu.cycles += " + self.cycles[1], ]) return code.getcode() @@ -1013,7 +1045,7 @@ def RETI(self): "cpu.PC |= cpu.mb.getitem(cpu.SP) # Low", "cpu.SP += 2", "cpu.SP &= 0xFFFF", - "return " + self.cycles[0], + "cpu.cycles += " + self.cycles[0], ]) return code.getcode() @@ -1036,7 +1068,7 @@ def RST(self): code.addlines([ "cpu.PC = %s" % (right.code), - "return " + self.cycles[0], + "cpu.cycles += " + self.cycles[0], ]) return code.getcode() @@ -1055,6 +1087,14 @@ def rotateleft(self, name, left, throughcarry=False): code.addlines(self.handleflags8bit(left.get, None, None, throughcarry)) code.addline("t &= 0xFF") left.assign = True + + if left.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(left.set % "t") return code @@ -1092,6 +1132,14 @@ def rotateright(self, name, left, throughcarry=False): code.addline("t = (%s >> 1) + ((%s & 1) << 7)" % (left.get, left.get) + " + ((%s & 1) << 8)" % (left.get)) code.addlines(self.handleflags8bit(left.get, None, None, throughcarry)) code.addline("t &= 0xFF") + + if left.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(left.set % "t") return code @@ -1124,6 +1172,14 @@ def SLA(self): code.addline("t = (%s << 1)" % left.get) code.addlines(self.handleflags8bit(left.get, None, None, False)) code.addline("t &= 0xFF") + + if left.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(left.set % "t") return code.getcode() @@ -1137,6 +1193,14 @@ def SRA(self): code.addline("t = ((%s >> 1) | (%s & 0x80)) + ((%s & 1) << 8)" % (left.get, left.get, left.get)) code.addlines(self.handleflags8bit(left.get, None, None, False)) code.addline("t &= 0xFF") + + if left.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(left.set % "t") return code.getcode() @@ -1148,6 +1212,14 @@ def SRL(self): code.addline("t = (%s >> 1) + ((%s & 1) << 8)" % (left.get, left.get)) code.addlines(self.handleflags8bit(left.get, None, None, False)) code.addline("t &= 0xFF") + + if left.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(left.set % "t") return code.getcode() @@ -1158,6 +1230,14 @@ def SWAP(self): code.addline("t = ((%s & 0xF0) >> 4) | ((%s & 0x0F) << 4)" % (left.get, left.get)) code.addlines(self.handleflags8bit(left.get, None, None, False)) code.addline("t &= 0xFF") + + if left.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(left.set % "t") return code.getcode() @@ -1171,10 +1251,12 @@ def BIT(self): right = Operand(r1) code = Code(self.name.split()[0], self.opcode, self.name, False, self.length, self.cycles) - if self.opcode in [0x146, 0x14E, 0x156, 0x15E, 0x166, 0x16E, 0x176, 0x17E]: - # FIX: Corrent cycle count is 12, not 16! - code.cycles = ("12", ) - + # FIX: Correct cycle count is 12, not 16! + if right.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 12 - 4 code.addline("t = %s & (1 << %s)" % (right.get, left.get)) code.addlines(self.handleflags8bit(left.get, right.get, None, False)) @@ -1188,6 +1270,14 @@ def RES(self): code = Code(self.name.split()[0], self.opcode, self.name, False, self.length, self.cycles) code.addline("t = %s & ~(1 << %s)" % (right.get, left.get)) + + if right.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(right.set % "t") return code.getcode() @@ -1197,6 +1287,14 @@ def SET(self): right = Operand(r1) code = Code(self.name.split()[0], self.opcode, self.name, False, self.length, self.cycles) code.addline("t = %s | (1 << %s)" % (right.get, left.get)) + + if right.operand == "(HL)": + # HACK: Offset the timing by 4 cycles + # TODO: Probably should be generalized + code.lines.insert(0, "cpu.cycles += 4") # Inject before read + code.addline("cpu.cycles += 4") + code.cycles = ("8", ) # 16 - 4 - 4 + code.addline(right.set % "t") return code.getcode() diff --git a/tests/test_results/blargg.json b/tests/test_results/blargg.json index 5e153d5eb..67385b2d1 100644 --- a/tests/test_results/blargg.json +++ b/tests/test_results/blargg.json @@ -26,14 +26,14 @@ "blargg/dmg_sound/rom_singles/12-wave write while on.gb": "12-wave write while on\n\n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 F7 44 55 66 77 88 99 AA BB CC DD EE FF \n00 F7 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \nF7 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 A", "blargg/instr_timing/instr_timing.gb": "instr_timing\n\n\nPassed\n", "blargg/interrupt_time/interrupt_time.gb": "interrupt time\n\n00 00 FC \n00 08 04 \n00 00 FC \n00 08 04 \n550B72D0 \nFailed\n", - "blargg/mem_timing/individual/01-read_timing.gb": "01-read_timing\n\nF0:2-3 FA:2-4 CB 46:2-3 CB 4E:2-3 CB 56:2-3 CB 5E:2-3 CB 66:2-3 CB 6E:2-3 CB 76:2-3 CB 7E:2-3 \nFailed\n", - "blargg/mem_timing/individual/02-write_timing.gb": "02-write_timing\n\n36:2-3 E0:2-3 EA:2-4 \nFailed\n", - "blargg/mem_timing/individual/03-modify_timing.gb": "03-modify_timing\n\n35:0/0-2/3\n34:0/0-2/3\nCB 06:0/0-3/4\nCB 0E:0/0-3/4\nCB 16:0/0-3/4\nCB 1E:0/0-3/4\nCB 26:0/0-3/4\nCB 2E:0/0-3/4\nCB 36:0/0-3/4\nCB 3E:0/0-3/4\nCB 86:0/0-3/4\nCB 8E:0/0-3/4\nCB 96:0/0-3/4\nCB 9E:0/0-3/4\nCB A6:0/0-3/4\nCB AE:0/0-3/4\nCB B6:0/0-3/4\nCB BE:0/0-3/4\nCB C6:0/0-3/4\nCB CE:0/0-3/4\nCB D6:0/0-3/4\nCB DE:0/0-3/4\nCB E6:0/0-3/4\nCB EE:0/0-3/4\nCB F6:0/0-3/4\nCB FE:0/0-3/4\n\nFailed\n", - "blargg/mem_timing/mem_timing.gb": "mem_timing\n\n01:01 02:01 03:01 \n\nFailed 3 tests.\n", - "blargg/mem_timing-2/mem_timing.gb": "mem_timing\n\n01:01 02:01 03:01 \n\nRun failed tests\nindividually for\nmore details.\n\nFailed\n", - "blargg/mem_timing-2/rom_singles/01-read_timing.gb": "01-read_timing\n\nF0:2-3 FA:2-4 CB 46:2-3 CB 4E:2-3 CB 56:2-3 CB 5E:2-3 CB 66:2-3 CB 6E:2-3 CB 76:2-3 CB 7E:2-3 \nFailed\n", - "blargg/mem_timing-2/rom_singles/02-write_timing.gb": "02-write_timing\n\n36:2-3 E0:2-3 EA:2-4 \nFailed\n", - "blargg/mem_timing-2/rom_singles/03-modify_timing.gb": "03-modify_timing\n\n35:0/0-2/3\n34:0/0-2/3\nCB 06:0/0-3/4\nCB 0E:0/0-3/4\nCB 16:0/0-3/4\nCB 1E:0/0-3/4\nCB 26:0/0-3/4\nCB 2E:0/0-3/4\nCB 36:0/0-3/4\nCB 3E:0/0-3/4\nCB 86:0/0-3/4\nCB 8E:0/0-3/4\nCB 96:0/0-3/4\nCB 9E:0/0-3/4\nCB A6:0/0-3/4\nCB AE:0/0-3/4\nCB B6:0/0-3/4\nC", + "blargg/mem_timing/individual/01-read_timing.gb": "01-read_timing\n\n\nPassed\n", + "blargg/mem_timing/individual/02-write_timing.gb": "02-write_timing\n\n\nPassed\n", + "blargg/mem_timing/individual/03-modify_timing.gb": "03-modify_timing\n\n\nPassed\n", + "blargg/mem_timing/mem_timing.gb": "mem_timing\n\n01:ok 02:ok 03:ok \n\nPassed all tests\n", + "blargg/mem_timing-2/mem_timing.gb": "mem_timing\n\n01:ok 02:ok 03:ok \n\nPassed\n", + "blargg/mem_timing-2/rom_singles/01-read_timing.gb": "01-read_timing\n\n\nPassed\n", + "blargg/mem_timing-2/rom_singles/02-write_timing.gb": "02-write_timing\n\n\nPassed\n", + "blargg/mem_timing-2/rom_singles/03-modify_timing.gb": "03-modify_timing\n\n\nPassed\n", "blargg/oam_bug/oam_bug.gb": "oam_bug\n\n01:03 02:02 03:ok 04:03 05:02 06:ok 07:01 08:02 \n\nRun failed tests\nindividually for\nmore details.\n\nFailed\n", "blargg/oam_bug/rom_singles/1-lcd_sync.gb": "1-lcd_sync\n\n\nTurning LCD on starts too early in scanline\n\nFailed #3\n", "blargg/oam_bug/rom_singles/2-causes.gb": "2-causes\n\n\nLD DE,$FE00 : INC DE\n\nFailed #2\n", From b95c2cb9da350e25eea690ef673b747b5437d4fc Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Wed, 25 Sep 2024 21:44:11 +0200 Subject: [PATCH 15/22] Fix import order in opcodes_gen.py --- pyboy/core/opcodes_gen.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyboy/core/opcodes_gen.py b/pyboy/core/opcodes_gen.py index e5c750ee5..ecce26f78 100644 --- a/pyboy/core/opcodes_gen.py +++ b/pyboy/core/opcodes_gen.py @@ -35,11 +35,14 @@ def BRK(cpu): """ cimports = """ -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 From 3292f7a27f4f29af7a73db86f7d6c666bf4b6b2f Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sun, 29 Sep 2024 20:27:50 +0200 Subject: [PATCH 16/22] Defer post-tick and reduce time keeping on tick --- pyboy/__main__.py | 2 +- pyboy/pyboy.pxd | 6 +++--- pyboy/pyboy.py | 35 ++++++++++++++++------------------- tests/test_basics.py | 6 ++++++ 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/pyboy/__main__.py b/pyboy/__main__.py index 8c5209fd4..c3feff9de 100644 --- a/pyboy/__main__.py +++ b/pyboy/__main__.py @@ -169,7 +169,7 @@ def main(): pyboy.load_state(f) render = not argv.no_renderer - while pyboy._tick(render): + while pyboy.tick(): pass pyboy.stop() diff --git a/pyboy/pyboy.pxd b/pyboy/pyboy.pxd index 700647b68..f28edd4f3 100644 --- a/pyboy/pyboy.pxd +++ b/pyboy/pyboy.pxd @@ -43,9 +43,8 @@ cdef class PyBoy: cdef readonly str gamerom cdef readonly bint paused - cdef double avg_pre cdef double avg_tick - cdef double avg_post + cdef double avg_emu cdef readonly list events cdef list queued_input @@ -72,7 +71,7 @@ cdef class PyBoy: @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, bint) noexcept - @cython.locals(running=bint) + @cython.locals(running=bint, factor=double) cpdef bint tick(self, count=*, render=*) noexcept cpdef void stop(self, save=*) noexcept cpdef int save_state(self, object) except -1 @@ -84,6 +83,7 @@ cdef class PyBoy: cpdef void _unpause(self) noexcept cdef void _update_window_title(self) noexcept cdef void _post_tick(self) noexcept + cdef void _post_handle_events(self) noexcept cdef dict _hooks cdef object symbols_file diff --git a/pyboy/pyboy.py b/pyboy/pyboy.py index 5824fcdc3..4c806a61d 100644 --- a/pyboy/pyboy.py +++ b/pyboy/pyboy.py @@ -160,9 +160,8 @@ def __init__( raise KeyError(f"Unknown keyword argument: {k}") # Performance measures - self.avg_pre = 0 self.avg_tick = 0 - self.avg_post = 0 + self.avg_emu = 0 # Absolute frame count of the emulation self.frame_count = 0 @@ -378,9 +377,7 @@ def _tick(self, render): if self.stopped: return False - t_start = time.perf_counter_ns() self._handle_events(self.events) - t_pre = time.perf_counter_ns() if not self.paused: self.gameshark.tick() self.__rendering(render) @@ -407,18 +404,7 @@ def _tick(self, render): self.mb.breakpoint_singlestep = self.mb.breakpoint_singlestep_latch self.frame_count += 1 - t_tick = time.perf_counter_ns() - self._post_tick() - t_post = time.perf_counter_ns() - - nsecs = t_pre - t_start - self.avg_pre = 0.9 * self.avg_pre + (0.1*nsecs/1_000_000_000) - - nsecs = t_tick - t_pre - self.avg_tick = 0.9 * self.avg_tick + (0.1*nsecs/1_000_000_000) - - nsecs = t_post - t_tick - self.avg_post = 0.9 * self.avg_post + (0.1*nsecs/1_000_000_000) + self._post_handle_events() return not self.quitting @@ -467,11 +453,22 @@ def tick(self, count=1, render=True): False if emulation has ended otherwise True """ + _count = count running = False + t_start = time.perf_counter_ns() while count != 0: _render = render and count == 1 # Only render on last tick to improve performance running = self._tick(_render) count -= 1 + t_tick = time.perf_counter_ns() + self._post_tick() + t_post = time.perf_counter_ns() + + if _count > 0: + nsecs = t_tick - t_start + self.avg_tick = 0.9 * (self.avg_tick / _count) + (0.1*nsecs/1_000_000_000) + nsecs = t_post - t_start + self.avg_emu = 0.9 * (self.avg_emu / _count) + (0.1*nsecs/1_000_000_000) return running def _handle_events(self, events): @@ -538,6 +535,7 @@ def _post_tick(self): self._plugin_manager.post_tick() self._plugin_manager.frame_limiter(self.target_emulationspeed) + def _post_handle_events(self): # Prepare an empty list, as the API might be used to send in events between ticks self.events = [] while self.queued_input and self.frame_count == self.queued_input[0][0]: @@ -545,9 +543,8 @@ def _post_tick(self): self.events.append(WindowEvent(_event)) def _update_window_title(self): - avg_emu = self.avg_pre + self.avg_tick + self.avg_post - self.window_title = f"CPU/frame: {(self.avg_pre + self.avg_tick) / SPF * 100:0.2f}%" - self.window_title += f' Emulation: x{(round(SPF / avg_emu) if avg_emu > 0 else "INF")}' + self.window_title = f"CPU/frame: {(self.avg_tick) / SPF * 100:0.2f}%" + self.window_title += f' Emulation: x{(round(SPF / self.avg_emu) if self.avg_emu > 0 else "INF")}' if self.paused: self.window_title += "[PAUSED]" self.window_title += self._plugin_manager.window_title() diff --git a/tests/test_basics.py b/tests/test_basics.py index 612214cec..88b1c862a 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -47,6 +47,12 @@ def test_log_level_critical(default_rom, capsys): assert captured.out == "" +def test_tick_zero(default_rom): + pyboy = PyBoy(default_rom, window="null") + # Not permitted, but shouldn't crash the emulator either + pyboy.tick(0) + + def test_register_file(default_rom): pyboy = PyBoy(default_rom, window="null") pyboy.set_emulation_speed(0) From 0724cb01203b1046869dcd1e7eb240b9d27f3d87 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Sat, 14 Sep 2024 20:45:26 +0200 Subject: [PATCH 17/22] Update whichboot pytest --- tests/test_results/cgb_whichboot.gb.png | Bin 2361 -> 2472 bytes tests/test_results/dmg_whichboot.gb.png | Bin 2337 -> 2471 bytes tests/test_whichboot.py | 7 +++---- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_results/cgb_whichboot.gb.png b/tests/test_results/cgb_whichboot.gb.png index b25f3c39dc979d00125d78e1b2635ac7f77efe42..57c8411db1b9eea5915860959b4f53fff6d0921a 100644 GIT binary patch delta 2462 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 delta 2350 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 diff --git a/tests/test_whichboot.py b/tests/test_whichboot.py index deee0e46b..31fa35040 100644 --- a/tests/test_whichboot.py +++ b/tests/test_whichboot.py @@ -15,11 +15,10 @@ @pytest.mark.parametrize("cgb", [False, True]) -def test_which(cgb, whichboot_file): - pyboy = PyBoy(whichboot_file, window="null", cgb=cgb) +def test_which(cgb, whichboot_file, boot_rom, boot_cgb_rom): + pyboy = PyBoy(whichboot_file, window="null", cgb=cgb, bootrom=boot_cgb_rom if cgb else boot_rom) pyboy.set_emulation_speed(0) - pyboy.tick(59, True) - pyboy.tick(25, True) + pyboy.tick(1000, True) png_path = Path(f"tests/test_results/{'cgb' if cgb else 'dmg'}_{os.path.basename(whichboot_file)}.png") image = pyboy.screen.image From 5e8cf7ede858375fc36e67e7e074828743777c02 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Thu, 26 Sep 2024 16:25:12 +0200 Subject: [PATCH 18/22] Saving SameSuite and Blargg results for sound, although they are still wrong --- .../apu/channel_1/channel_1_align.gb.png | Bin 804 -> 894 bytes .../apu/channel_1/channel_1_align_cpu.gb.png | Bin 777 -> 874 bytes .../apu/channel_1/channel_1_delay.gb.png | Bin 784 -> 896 bytes .../apu/channel_1/channel_1_duty.gb.png | Bin 1438 -> 1571 bytes .../apu/channel_1/channel_1_duty_delay.gb.png | Bin 1382 -> 1430 bytes ...annel_1_extra_length_clocking-cgb0B.gb.png | Bin 751 -> 853 bytes .../channel_1/channel_1_freq_change.gb.png | Bin 1590 -> 1666 bytes .../channel_1_freq_change_timing-A.gb.png | Bin 601 -> 691 bytes ...channel_1_freq_change_timing-cgb0BC.gb.png | Bin 601 -> 691 bytes .../channel_1_freq_change_timing-cgbDE.gb.png | Bin 596 -> 681 bytes .../channel_1/channel_1_nrx2_glitch.gb.png | Bin 532 -> 620 bytes .../channel_1_nrx2_speed_change.gb.png | Bin 968 -> 1016 bytes .../apu/channel_1/channel_1_restart.gb.png | Bin 1550 -> 1564 bytes .../channel_1_restart_nrx2_glitch.gb.png | Bin 552 -> 660 bytes .../apu/channel_1/channel_1_stop_div.gb.png | Bin 1118 -> 1248 bytes .../channel_1/channel_1_stop_restart.gb.png | Bin 1485 -> 1514 bytes .../apu/channel_1/channel_1_sweep.gb.png | Bin 1472 -> 1585 bytes .../channel_1/channel_1_sweep_restart.gb.png | Bin 2078 -> 2288 bytes .../channel_1_sweep_restart_2.gb.png | Bin 1328 -> 1484 bytes .../apu/channel_1/channel_1_volume.gb.png | Bin 1376 -> 1545 bytes .../apu/channel_1/channel_1_volume_div.gb.png | Bin 968 -> 1043 bytes .../apu/channel_2/channel_2_align.gb.png | Bin 804 -> 894 bytes .../apu/channel_2/channel_2_align_cpu.gb.png | Bin 777 -> 874 bytes .../apu/channel_2/channel_2_delay.gb.png | Bin 784 -> 896 bytes .../apu/channel_2/channel_2_duty.gb.png | Bin 1438 -> 1571 bytes .../apu/channel_2/channel_2_duty_delay.gb.png | Bin 1382 -> 1430 bytes ...annel_2_extra_length_clocking-cgb0B.gb.png | Bin 792 -> 909 bytes .../channel_2/channel_2_freq_change.gb.png | Bin 1590 -> 1666 bytes .../channel_2/channel_2_nrx2_glitch.gb.png | Bin 532 -> 620 bytes .../channel_2_nrx2_speed_change.gb.png | Bin 968 -> 1016 bytes .../apu/channel_2/channel_2_restart.gb.png | Bin 1550 -> 1564 bytes .../channel_2_restart_nrx2_glitch.gb.png | Bin 552 -> 660 bytes .../apu/channel_2/channel_2_stop_div.gb.png | Bin 1128 -> 1252 bytes .../channel_2/channel_2_stop_restart.gb.png | Bin 1485 -> 1514 bytes .../apu/channel_2/channel_2_volume.gb.png | Bin 517 -> 614 bytes .../apu/channel_2/channel_2_volume_div.gb.png | Bin 817 -> 879 bytes .../apu/channel_3/channel_3_and_glitch.gb.png | Bin 827 -> 926 bytes .../apu/channel_3/channel_3_delay.gb.png | Bin 568 -> 671 bytes ...hannel_3_extra_length_clocking-cgb0.gb.png | Bin 897 -> 1015 bytes ...hannel_3_extra_length_clocking-cgbB.gb.png | Bin 872 -> 970 bytes .../channel_3/channel_3_first_sample.gb.png | Bin 510 -> 600 bytes .../channel_3_freq_change_delay.gb.png | Bin 576 -> 705 bytes .../channel_3/channel_3_restart_delay.gb.png | Bin 482 -> 565 bytes .../channel_3_restart_during_delay.gb.png | Bin 1092 -> 1261 bytes .../channel_3_restart_stop_delay.gb.png | Bin 513 -> 600 bytes .../channel_3/channel_3_shift_delay.gb.png | Bin 482 -> 565 bytes .../channel_3_shift_skip_delay.gb.png | Bin 510 -> 600 bytes .../apu/channel_3/channel_3_stop_delay.gb.png | Bin 479 -> 546 bytes .../apu/channel_3/channel_3_stop_div.gb.png | Bin 1254 -> 1338 bytes .../channel_3_wave_ram_dac_on_rw.gb.png | Bin 1480 -> 1731 bytes .../channel_3_wave_ram_locked_write.gb.png | Bin 2749 -> 3248 bytes .../channel_3/channel_3_wave_ram_sync.gb.png | Bin 810 -> 982 bytes .../apu/channel_4/channel_4_align.gb.png | Bin 886 -> 953 bytes .../apu/channel_4/channel_4_delay.gb.png | Bin 728 -> 856 bytes .../channel_4_equivalent_frequencies.gb.png | Bin 1443 -> 1558 bytes ...annel_4_extra_length_clocking-cgb0B.gb.png | Bin 777 -> 855 bytes .../channel_4/channel_4_freq_change.gb.png | Bin 950 -> 1014 bytes .../channel_4_frequency_alignment.gb.png | Bin 1573 -> 1577 bytes .../apu/channel_4/channel_4_lfsr.gb.png | Bin 1365 -> 1451 bytes .../apu/channel_4/channel_4_lfsr15.gb.png | Bin 1398 -> 1513 bytes .../apu/channel_4/channel_4_lfsr_15_7.gb.png | Bin 1721 -> 1833 bytes .../apu/channel_4/channel_4_lfsr_7_15.gb.png | Bin 1721 -> 1809 bytes .../channel_4/channel_4_lfsr_restart.gb.png | Bin 1365 -> 1453 bytes .../channel_4_lfsr_restart_fast.gb.png | Bin 1365 -> 1453 bytes .../apu/channel_4/channel_4_volume_div.gb.png | Bin 895 -> 974 bytes .../apu/div_trigger_volume_10.gb.png | Bin 653 -> 714 bytes .../SameSuite/apu/div_write_trigger.gb.png | Bin 1695 -> 1908 bytes .../SameSuite/apu/div_write_trigger_10.gb.png | Bin 1634 -> 1857 bytes .../apu/div_write_trigger_volume.gb.png | Bin 653 -> 714 bytes .../apu/div_write_trigger_volume_10.gb.png | Bin 653 -> 714 bytes tests/test_results/blargg.json | 6 +++--- 71 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_align.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_align.gb.png index e6601e48a50ced9b870491c13de4b93c204d530b..e1323bb000d3957bb2f8352948ce2706fa974e09 100644 GIT binary patch literal 894 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V`_hk3UQB-#RZ z-!gr6@6g#Q`&|njJSv-VAbNVS%95jJ!*gFm8m%c=y7k(%(%hv}y07nAm;3p}`u=mb z&q=PGJ->e6wrf#qw@wN2%3eDq=+x$Z^R3sqx4x~|a?jZQ{-62$_m|f2Fv~sF{VV-o zE9Zn2s~N9Fo&WFG>|Uk4bV_Ngx90SRx!LD`{Q9@&?VPCBKj&QB_4DWR?9ZLe3$_P& zS=s%HIve=kwpEYCf&WtG9`IulnpQ zv(VQmxikL%6*%;IXBGFqf=SUI`sdF7E0!ZaLF0GB{*1cFX_um`_iyu`zxeBXgM9gd zqRsbL^4(;AbN=N`_L@6?{++rMFL}N6Z^__1{EhK;nPsbVr5wl#7uikxH`s5>-)1+lpS7LeV@mCT z4}a=vPd)$nZq9aoiFxnuZ_hp+KiB;89+1Spy|>T3?RS5@SMvG%P5dt^9o+bKGWDJN zeeO?A_=f7|v5f0)#IJlX@eT981wSR{Ki^$`&o1G{>ie00VhSqi>QiTYtlU@q{BO*L zpD+F>+Ka!@J6A6I&*IvPS8Ug1q!#?xaW(OG!=uO6e7D)}{J&+l;OGCj2p1g#x@g{Z z{uy)c-|K$+cSjj8{LWhB%THLb{0(!J+yue%%x%x(VF72KQ3p~F)Gkr>dhWCBJAY}; zcwYH+|Nno*N{d)LrZ990DFia9cs00iPS9W!Qgs;qf-CmlDPOac;gEhRFkdlvy85}S Ib4q9e00~s3KmY&$ literal 804 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V1*PZ!6KiaBp*KP+0UAi}n= zI6m;cZ~V01hc%s5R~~&NQdU+!@v!*q6y=X1(m`Igx3xCq-VXATef{-~VQBc7^7F^1 z1oarUObFsqv@x{nFnrd2e8;*Lrq8jT{vQhWbDwzg=a1L%4)a_O7MyEJ?m2#axr0ZX z>*CMPvyB@+3Oe2RZY%cYciowP%ez5N6k4o0b z_ixy&(|-C<{?u*u!!K{D$;N*=erSUHsryB7i}s({>9YN~d-S5W%`a6z>SH3OsoIxE zPMbb;Qv0WG2j@!W{@s0kHn-Og)&&a2(<`yg}CbDnkS^)uuj_T-$s zeC|QbKhBmEd7G>M^0M#Q{b;&*-S~a?z7zf17HxU9S6^!0{^Iy8tADxt$=bca&NtQM z9rv|&B6r?2Z?)z&l0^Rsw^4FXc5uW4q jcFl_uEV$Z62Ju<`fB&Bci?6#jfKtDwtDnm{r-UW|#J7N6 diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_align_cpu.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_align_cpu.gb.png index 82a17ed6dc8cfa3b270df2f0ce3a450d2fc5593c..10551d8219cac0d8caaae3bd96a06831abd311ed 100644 GIT binary patch literal 874 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V`_M8De(BCQwG zub5WlpG#YAzd||vgoC4>9`kdLiLVawZ@s8KyT@ns)@$2xvqMWi-`ckJt=!+Q7b|~T zE-wB2`Mmzxt=n|GLqoS-Tea%d&EvaMBlE6(dwj9#{GXc7_4jI~S4p$kobvvqf8f2E z!=iU=J9JKeeQr{*WcsRAxwlunGTT%8Rx;jx-uC&Mff92r?)v%j`SfSP?2h`Oq0>)4 zU3MWg@>S8!82_p-*WI7Lecp5J?Dez1cC9nNpC5a@{QB?klzVm$?tK1T9T|GP_&3m2 zeZzeD2`iT89RBmZU7&9M?(GlE)pxSi-~M?s|KK;q&Q1J3nx9=SU3=};*RA!xWY*TV zSN?98Jo~R-=_$K}dcX5_4<0}351;n$)Q;TSyI=p+HjMwjuHo(1`=4HIKK_@veQ*D> z{@368++RO?KHvUp@P~E(?d(`*%b%UUiT}p8)0#Dto`bCLxT5*Hp?1UHjkOM+7X!_A zxye4K=HCvx$DbR%F{;mhfB$>+arwE^=WOS<`1$AK-uvg@_Pf8{d*n~>H%43j6DKso z4_vH_pE>_6*OYnxCx#z*Je5oCq}>DlS>J6G{LO#QJ@uZ|->!borZYcm7To7Hlb>t< z^n26Yqd!+&mOm~Pd-uV-U}h2d`K7n)7X0|pb@>}(fBie=ZTuN^Ccu!<0Q&a4{Ppx2 zxeIm=o`Ay5^!Z^9V8B$JvRm++QSze=P;~SCrnk&Osq!D#&sNJ#SpNIX+*iAI{??pP zd8Y2~hxx*Sst$`-Jf<*o3Mm9KsdzQGa8A%*6dL}5e_0RxpS?EA+ItBw4>5SU`njxg HN@xNAGYple literal 777 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V0qPZ!6KiaBp*2Npe65MWi@ z8b0NnT5Q?3=BO?X_0<^{*-Cfq|L{R)`5mz|E_K%<+j3VX-rm+B5%E6#bV$6Rz0G`O zrRQ^kx;my@l6~xSZl|5j<9(B)&hVf7@Acj?#&zDg+vWcmi}bnLibduW>&4G!QoQ53 z`1A3-GY?dFYrg$GPx@P}e(~a0e{*KO(r&0(yXJM&{N3wbpY}Q(`*Q=o+^qBUWd>h+ z*FN5NDenKWJ+%gNCgukHoTSg~T&r>abYW+m`E#MaU;pHIZ>cqy3sS#+YHH-G;_0cC zk(oO+^W|-3+`P75ySBjkYTRi%i=`%ayMo?7C~N&$b0=;^?aBU6TZ<&Vi+(=*`Fi=q z(1-D#OSjpbIe$~s-nM=z|GN2tGv&`WKfJ+yxpV#Zt@`?(JonA74T%5!1?UW!-wzJ{ zjGFnx=7wEG!M@sbzQ_G(`Dbsl^PhWu(tq-~f*&iwZ20F*&@L~quQswjEL&Dy_sx38 zy?Q3aH_f*E(>|Zs_V4HJ7YBdd44d*;?R8(F;`xo7zcPPn@9!=Ptrz%T5_9AJG9&5h ztl8fMW8O4x{Vj3GPGatM{CubcHot7C y-SGTi(LCeV_y4;bEco->*n+EVal!~8_A@RM`dVYMbGa@kiF>;GxvXEaktG3V{=i+PJ2B-$R% zOv@L1$D3dFZNb8Wni--`qPL%)TybE^{TZLcu6IU9W#`UX7Us3H%IETxwDtdfUaS0U z8U1?g*41AVCDzT$muQ>)`tRXCk3V~#kJ*1KDtqg-AiMc%rv#n4d3#MhF_H5l( zv+n25Ykk|VRX>xTe}9+W>BrI6-=E(e9=NZaas8)>b&P-Vm{hV%4@A9wwO{Z-hWyeg zM!vzCPp$S;zU`T>e}4A)m0RoPZr*xN`uN5z*Y?RhwzwB#UjOEg@%8oF%>N&G=r?z( z`TYJMubnY^;jP!APCqUBY4!4|{e7!^yY%e6<~)b5#=kP)F~5FR-unNUubcUIB;2!8 z*ndXzwt@X$fkW>%{}TK2Rwe)7v-mG!Ir0-Uem6YhpS_*`#LI8bici=j)cd`k`n%!u z{xkp1S@>Q)`}N=S>G#~LkN@ z`< zt@oAB`}zF&@7G((YToa${rs`k;djB!pHH`Xy*WH@6aS0f4LO!i_;!@u^M7`iar5W@ zPh<;TA7+txJO37Y&GFhb|1<42@=M=mFIj$;EB@ct|Dxr~zUVjT#JeeYHMnq2&|nl& sby&pWF@>R1NFk6(WmFImAiucJ8Lwv!J1Kbtn6nr>UHx3vIVCg!0H2VRHUIzs literal 784 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V1_PZ!6KiaBp@2Ieg`U|*+C>1F?UD=R3M(+LGzbk%jef{(OgYz5@Ucb{{u#Jaj zJD-dbhvJ=2p;uhKX#NWPoPFK+%eRoHe;-HWu3w)hF)fvIW@=>I^L0}C=lA(dRo>~h zZbsho{k!LV{LZ%eD8%T(^yL!kZ@b&o*1fIT#oxBOX!e(1{&u$Q>*wt(=|6jW<@OhO z&#$jr{ySmU3%eg68!p#=IDF-s)n@*4{!izZp0vB6{jZ`fYGdZCOV!IWZ^>{f&bi6{ zoLkno`t#)zuXe~-8ruI?Tm5+N=J}@e#>cETo-TiT*8D^7=ksrxPoH@;Z9n_ro&3wX zzy7{;mfvzl{5;zVt#xzfyIED9dYfBU{`*1Hz5IWVkBH8he{1)%OMkv>np}Tz@7en? zd$r#etUP%BwRzv_ZwG&#x%%Q*WY_p@jmD3pJ%@x+!Ncf{pVWd_?`UUzCVzg zyQAs8WMu7+XCIZz{8WCV8MJ?QsUf!0=70|gE@^4N1o7cwnEXZeZfNaWk4z2)78&qol`;+0H5k} A8~^|S diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_duty.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_duty.gb.png index 66d4896a20611fbdc6cf48724e78ba0128fd356c..254772b1a2ec0a27c1dcd43ad1475c483a1de313 100644 GIT binary patch literal 1571 zcma)6eKga17~fh9Wu}}$Yj-I{r??&0?atfQQWSAh*J~Jxyk%{LVYalq7gu??xvWk} zEJN-%g_*iuimb3!i6N}8mX~d2X7@*(?m73b`^WeDobU6T@AvsU&-e3rGJbV)($z86 z0f9ieN1Po!0DB8qxmudQp2Nn|Kp>6DBaR17#{VfUIi6Q(V{qu8m%D!Xa1r6*BTRc@ zw)UEgb8cZ(yO}m4dl+q5m!{Vl24|o5DKNyvC+zLou#qtoz;v-@Cnu?w4MMW}e!2q3 zrSD6H;}&9V_Z{my5f~v@Bz;jSS}Y|S0-&1Q@`dA6kl_|hl(RXE8-5ch3I{R9cG2Ml zXSBE3={5DsuZrs}_^y5P_ba3yl=AYlCr!3ru#)&>+UZB$w zoA+s(6G4(VG&Ng8n@(BeJSAt()FxC(N~Xz8M~BHBjG1}!@(Uz`J( zK89g6f0!=wgLMvH-hQDAEEXz2JE4D9D*(J#5b(gs>yS|w3K5$-n~%ty0^imYd^_V{ z>6X%G-~*X<(7z~|B1k1As{>KZFBH*aR2c%=s<)E!E1%jp zVtITZiRlhAlg&{)0glW~Ux#E;8igLwLoBH%e!e9SLbONqqo4-LZkoolD;qk6m}fB4!$vj?0_F^u)5r#yy>SRFu=t`Zht_5X@U1#pDpZ&K#?!D*U-~Ij0_kMoA-_1OYJ!zbIC%&^SR@0J#sdjSgWw1Qcana ztbu)H{mmk)^6;AiC&F0YkP_GKX}QytTus0)CEglYnphZZQY zaXc>Q4iw}F!TY`g`bMyN*();v_sPjQ%I&dRG_@Q*sfI}SJD@yVxW26%nA|KxnJsqe z9|`Cr$HVKUvQP{fsD)#>lio<6)#t7i^?_UAxvbT*bC+W zo{Q3t9;Kw^O***9((@+cj3w!Q^3~2h04%nQ212~-20{cru47W&!t=~WfgJKk(`Zc zsjQ$-DLg~%112R$d1Yu{9)56TSc)PkLhn*jD-QCZkCwBbvkx(YTYuZ+Y~ZFf=}K9j zc$6BU=uNIiXKv%LF=ma}>8bQuJKb%ZEab2fp}AM0V%jU5PsIKOoSf?7(l;0-*l3!_KG`(I$~S*cyh;> zm{;j{FnHa@-@(VTKto5cCuByJ`-P?av9C0=&X#}G`oPvul+&S2uFpl8j+cByFLw?e z|LeQ&GYf6|H0+s;U%y2>oBj-hfXnGEoSQ4a(sB%aTQW%q+uAV_%on~dL7jhV;{Hsn zz$mJyGEp)=x-V%9Co1hB)6wOkSLy`4mmbnDCf$JM3sL7?ca88!+7;w1w6#do-9*E~ z^R=SG!@72p*B};Us?^shzZfr3*}FAe!-vHtn=&>ekY&_42PM;9cz1CAPj4UFgaUtf z2-_*Rbj{V;kInl5F_^WPWD#>=DHp0vYwVR%H%3qAv3bq-L2hv|#X-=%={EdgN!4p9)|?`uyM+i-9G9zT-+c;dz*zamgA{(8n-eH zDQxWljy||;w{;Z71GO-nmKW|+f(z7*uxdb7;ud{ubLg$$VogZ%O_@%_vClI0iyF77 zZj#zqZCK0rc-;?<{8wtE`vmtYyPLZ@>pZRg&J6SrhrgZR=HmW$!+AP#B5pl<++|7g N?|Ngf9vn0-?H?kX+sXg{ diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_duty_delay.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_duty_delay.gb.png index b9f7a35f2489f3a61768f44225439c56ebce7bd5..46c209328d3ee040edad58b1c95c88cc5bdce8a4 100644 GIT binary patch literal 1430 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 O{Pe>5xwGByw7&oiZQD2i diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_extra_length_clocking-cgb0B.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_extra_length_clocking-cgb0B.gb.png index 4770cfb19f4469d292e5182f51a976d9431dd34e..9b6c97eddfd90881efced1aee59302e23ec9e3be 100644 GIT binary patch literal 853 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{AhklP7B-$<> ze53nn@6_3I|8A5t?hB5Idcj@fm&7x-PV}Vn#brycMNLm#xpazt{OL_sp51$Wc89;_ z)7yr6H;wFXmv8&`@87;(#%JEocyHe4>~8yR`}r@7@tacXY8cb?bE-dHyLL8zzWvpx z*Dp)7p57Ncb!JE1>*IgV&$MmdR-0RUzNT95?awd$$KPhZezyJm|47@Y6A~`}|91SW zyI;1(TYuNj+Ryyr4@@`SN&YuW{Pv%JKeumfep9RT!Tz3?W@_ZLpi|dB+}fsmt^U&a z+{)rNbJuUJ`)RTNn@)CJ?Z1%kb!oPi>A%)&5Aw2{e|~;?+qY7?`S#_zzE>H)yL|j& zU*XAVKfm?GRLgJMT6XN+clrHi;_c&qWgDNp*#G;j@%KG^8FtqHKV4@$oBn+Hf7biA zO#io>v9r_vd+FKy>VKN&8m`s9-}Sn|WhYRb6-eF5T_;Nq6wbe>9M3-It#$POA3q}g zN&eyXQA!{rf+@|GD#yJ^o{I|GjxNU+(W)zvlh?w{v@~+ut`! zH*ffP;cr8>VxA$}#d`asefPKjKYa5~?X$c57B_yY8NIJ_n0LZ=9dqBozW(`ttrFJu zSKHs+e189*QU{<<+kZ=c$k6}yuiN@bo2UJWjs6EqlwR7VBz c2gqO6?JqlHH`)bo0J95&r>mdKI;Vst05Yz5$N&HU literal 751 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 i2@VbEaktG3V{A*sR9}5)OeY z&xpO#VPxv5dcNGwc7Bzpr=o)!vVnf4$3Y?rr;HcWNL15Ge2Juar#gIsLS#wDr8@@ux+V zv0tvPw~s1cQ)%+Q=WqV=?cv{ct@D4r{iE*bqSB@Mr$3d{z3%z#U(feKX8qmwG83+B zmpT0B{d9qI&)@0(xU01NfqXUh@3+6_GEXYv`*AGa#vRB3sn)N3{cigMW6Pgkr++@r kv4q9Lt6`KND-8ZI{YpLd@4DbzP_kt3boFyt=akR{04oJE4*&oF literal 601 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|S$Sr;B4q#hkY{FJ`@R5OD|$ zey6YYf7+j%cg+GvA{M%?zPawJ$sEapCCMHyGGnh-&hr<4RvCBwYvbp??<%wHe>Q)< zog#Dm?dHc8_vXY{z54lfmj3$x8(-%ZZN2CJ@4=sM?6=nMzis>FXMMSy+kxw=_cNSV zEx1$qAW@<%vEpR-L(MS%i^r?9{yqHp@bbJ>c5nZEDYcqAEmcxa=XBA%>MJ$-tMA?N zuPdyZ?Q?lcZP~14vnQY4mH&ym`q$65;x+dwj#bT$S^Ir*{G9uG75o3?eP4X8n!m65 zN%p0m3)6NB$JrKtlrqm>o_BHP=X=esuQl&y&!1dgnN_>_b9+61+5VmHKQ!(EaktG3V{A*sR9}5)OeY z&xpO#VPxv5dcNGwc7Bzpr=o)!vVnf4$3Y?rr;HcWNL15Ge2Juar#gIsLS#wDr8@@ux+V zv0tvPw~s1cQ)%+Q=WqV=?cv{ct@D4r{iE*bqSB@Mr$3d{z3%z#U(feKX8qmwG83+B zmpT0B{d9qI&)@0(xU01NfqXUh@3+6_GEXYv`*AGa#vRB3sn)N3{cigMW6Pgkr++@r kv4q9Lt6`KND-8ZI{YpLd@4DbzP_kt3boFyt=akR{04oJE4*&oF literal 601 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|S$Sr;B4q#hkY{FJ`@R5OD|$ zey6YYf7+j%cg+GvA{M%?zPawJ$sEapCCMHyGGnh-&hr<4RvCBwYvbp??<%wHe>Q)< zog#Dm?dHc8_vXY{z54lfmj3$x8(-%ZZN2CJ@4=sM?6=nMzis>FXMMSy+kxw=_cNSV zEx1$qAW@<%vEpR-L(MS%i^r?9{yqHp@bbJ>c5nZEDYcqAEmcxa=XBA%>MJ$-tMA?N zuPdyZ?Q?lcZP~14vnQY4mH&ym`q$65;x+dwj#bT$S^Ir*{G9uG75o3?eP4X8n!m65 zN%p0m3)6NB$JrKtlrqm>o_BHP=X=esuQl&y&!1dgnN_>_b9+61+5VmHKQ!(EaktG3V{Ai++zBBpNPC zZeAa8Z|$C(?@8O;CP;1Wm@j?Kb4S9A`5iwuygafo_x84Rug#9_s95uQ*IT*2zb@{p zJ%90+|BU+G`*cnp{jGcY)5Bk1A4@)ezAg9moZ=qCWApDnm$?78#{Bu7h}-k!*T!o< z`+j~?{k-V&{nyspKK`@5{Jqh=cE-XQ?{(iIHFzZv)UJmL63U%?lC-kN>SWbLE1dG}a9SMJ;Y{o{F#B`h9Z g4Wk5EVNl0h@OgLHX=bHqz$D1v>FVdQ&MBb@0OQ#+EdT%j literal 596 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|S$^r;B4q#hkY{1G`omFgOIt z-V=+RlXvaAqQ^>OX4c&0+n?98siTn!JkFI~2Bj8HS3j3^P6EaktG3V_q@4j0OA`Tay zhi%LFmSz?$>G-SJgRN2fh~*?zjo(|V3Jw-^MrN;lY;o;Ojb-2C2=RWK|CPD-zkj{C z?|u38{qoP^^XsCs*XG_%OG{g8YHWPIroOWF{oniRjQ{WYyua?x)Stp!Hn-gW@_)F; z;_)i2;r6z>dyXIe|IN_2SmyYd8s7JtzV&<-Uw%3BTGaK&C02K1&Hw-Ue7kGDMa|`X z+xutE{QR@#Z`m%H=bwL8U0i%V{>|@yPbY7B|NCy~=k@ma@)v5X^5rL73Er0Y@2g_V z_u|iDe;zAsPx#C~YdgQkDZ2$fOYYezteowC@cfg`-+O-=GHEhS5>gl?$O(g$_nrLB VRC@()H33r*gQu&X%Q~loCIAr}*SP=y literal 532 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Vo2PZ!6KiaBp@9?WWX5OKH| z@vFOTPP}z&OP7kTSgK2rWxDCraHE2g3!a!AyRq$U*@oQP63N%T{ykqBdwhLq?EgJQ zDRt-m+C z_mAWDeyc}zwfCwE?tT!NJMX)kOnFtpx~Iq6EE*rP^a)$|Js4$R1j28|=+$x^S?l8d PfnwX!)z4*}Q$iB}(WdQ2 diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_nrx2_speed_change.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_nrx2_speed_change.gb.png index 955eced02c658132647fd047b512a08ed4abfd90..62cddba8d9aff7fbe6e0eae9410a2433348a9015 100644 GIT binary patch literal 1016 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-A8q*mRQa#?gF7M>f-f2N{-RA4|KK_3B^RePx>vqrIyv^?V_gcxehyN~r|NCrLjotmNc5NGjx4&IH zB`9zE?ZbSROJjH5&HFz2-}m>|&q<$;jMiUjvuE=&>&IWK?#9gD|6OnT>BFyM^`@Ww zYWef}=eq_x&ZmnHEUqj*l59$YroX*c(Z^SOs_Wu7G*7F}K9TuHo>|ABU zK1aN)?#~;U4M#1f{n=Pk!kF${6E+EGWay)PtImO<^DN;Ci5>Fh3r*t z8nU0;PTtNu&pMyaV~XX18WSKL@@MCRm)6PWi}!xYeeVB1Wxd6La=Iko3!p|~B|FM}3cJGf@ey8sX&1d#A{TZ|R&%!-W_gqP0 z{2sOIV}ow!^M>>D-V5o(m-6jM&*ND7XVZJm%)&m^dL4x8HRR9EW)=$lyYY;&x#FCD zs1b0lZGF$Fnfmkch4oLO=Omw$KU4p<;rsji8^ty}x9^K?nmRun7S>yLKlr(B`X)zQ<+R(3Ps`soR6nn}+_O7+USKMph0nW!W!dMSx$BWC;Tj5oTpm-HgqAkAXbwf@75jwsnSM`gckBS>Xa-ML KKbLh*2~7ZRrt1;_ literal 968 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Rrvr;B4q#hkZu11H^95MVtT zwr<5?&*`f2A!;HDkx7A-6|eqD9gbeRIX6PBXpTT~jDv)*OmfYNZ4(!*bN>_`9V>r! zlKsj5mOqUI9z4J8&oGbm;G-!`&K!y@>up3US|lEC%l&y`Tkgv}##wvj`38UWsAGz_ zesy12?Dc0Jd_U9dDy%~{*7rP3kDOL}-}%_S_nCQDDr{#jdo@utdrrj1Pu0gI zXG?3os#>C)U;kj2-K^Tsd3F(VCguj+a(XKhH)rPqYm@E4+cIX_)NZi47%5+4p06C| zxAxqpcfTI&-f+KWLB8v)D;H;N-eX(xsjDvbp3IU??NU9XG?UMjn^yFvo$Nm&o@B?R zy-&Dl?(^zj52B2BwEjN$=mPs{;rH_w%@(&jb=z5g`Kjqo<=;2ouVD_Pkm=RYeRn;{k%b;|!rr@+7WVk_6VPviOI{K@ux_r6Jt>VIC9 zCGPb(DE+r-qc!W?T7$CXigtI{tF1%#>DvGOz33sctoDyN#$G-aV#-^9e z>8CLCYO=;3uiJU){jOyfD74$zQ z@jT`Fk$e7USB4wZZa54w_z!bI;SYbyBaRy^IK diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_restart.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_restart.gb.png index 8999fc17c481cc818569b296fc7d2a26b067109e..0c220dc537142609fd106d63d58d20cd42a1a733 100644 GIT binary patch delta 1558 zcmYL~e>~H99LM*)m95gYN8K^qFxM$cp&zGjX?D^Hp_Dt7Wu?d|i$%%oyHio=80zN7 znttI#wseVpm|ulhqg;^W z&go@`Yb3t`r%hbMLWDLEfYABJP#+zPCpBS+(9g?V(Msne90_&!J|!|x?G>MR;G4dUd9R#N*B@JG9>r>`DZ{Kh z#;&q1UB5=20l$Sa$QnakTsEu+z=e7>40Qd_5NrEHXf0nUqF24xxQ<~u4BlcKpDwq2 z^UQu^1M2!cr{brS`{7ePShOH{4B_k<(GLjR+6kw_A)jiAw2POJGstp}f_AWQS{}}j z$mD>;Y47o@mM;*sUmzaSj#_JHXXaHZn>MsJkV?@2lqq9z6XIco)YlK9s$k&$u9;zw zxUqni9q+pfJ=5D74!b$`0W0f+L@b3W*tsnwa^{(9nYNG@&KW&Br3!xYxJwtS&Uugk zsfsz<$_5Lbs*f5bdWp+YnHdC!n?8+ds=c?+)+6O)NEIoB7%m*qT-=q^x$fj`xWg|O zyNkvNnP3fS_joKXIAwE? zm_F_|i(#I(E9FPfjYOS~E&``m=oXm9$aAaL|6F z09CTYXkSD$MWAAm)X1&P^OVAWDZ8 z;g%-j43uQ{CO=K-54FIF?4Um?o`{S;y$^LEX0}Z~rLtbIkpnq8xOt6egzi?7iJ)9{NdY9%GAJLyfJA1 z4ovPU@D?fGw||f&kvGYvTcdj%%NhYyPV)m&GEVaMWNzFdeSv?E%kMEqO}bs-8S-jU zrnkU2v=wg3mz@HLlMmi9NU$vLx^lx?vqLGX+Z;vW)M0$RqW0VRNO;z}s@lgJpf_<0{P#1y+Io>2%*;B&Fs7nRHj`gk7G8%14l;{2uOgNNn- z#VHgKBz7-b2@?N~47!smn5Fche8mK>=)Ggf8G(;T%0Ex x`Lm9jAZNe{c!?mm4Gk(4&*!5@KrND5mW%Ez!C;SAeu94hgvU-Fw-Q%s!awqnDeM3M delta 1544 zcmYLJdpy%?9A1fEmmO2eEzXL3I;E1Z%Gk7tpTm0y=5*H!M>I@0CT z(5H=rFny5Q)>78Uny@J?YZrIx{G2+U^ZxPv@&56ApZEDb&vOf&3C}jAErdZwI3a|= zbl>{8?>UZ~+XVgdq03hr{ecF`jjNorXsnHvAyUA_x%Dmk7p`ipyVbF@QZzJHHw5@65jy7M1 zo{oa?k8rdDd$L*w4XDn)$^yG=uMX9lC84PL$05+DRmW(K*w;XZMVng>Wjvy4`~s6F zTc$lAZ%)!5*vs%r=oX|ri$7nAkdhWXv1I{(@w8;5L|b1~eM7Ip%c9HmxvEdY?K{2( z9QKnJ>^Wke@8TJHJcy@q>==#hE1wBVkQRij)^r(z0{uX8e%|cs3mT<#;p2R!2srBU zuH>4Cc8~36AA>s`=ixc7oNnr_Aig{CYx1c$0Wo=NBCGR^@%(_=xA*B9$wkfJC5?pe zaMxtgV|#{;0gxFZ_c=P2CN6te+Y{Vz*~xcplo?`c$*3!s4Beg_Jn~C12{A3nuQ@ zJBZ9JLGJ<8y&U{7aaM_`u8jqyC)R*~*vpp~xUN){bA zNeK5V$+$T}$4vfF0WUBJHbNR#f=lQqT_;k^4Q{b>rr1T~kd>FFb~ z&k?B$@AikB+;VRg=$315c0gAUDe|k zc``=i6lysqAo}ws&^lLC>94R)u&5(94iN>Zu%eHoA4*I1 zb`~8W<`jJkL}Zo+Nkb;?GuO4);Aut)5SUO-Zq7v|Zky+?`sFn_=FN5j+!GxpqCXjW zHU85yg|>Qwdm4MwrQMYe*VQKpU%;tLoRHPJ*c<$Xs%>G@-g3;l_qt;(2->3R7S3Ky&N6WZ(?n7d^EGAr zpaAd+DC6*yKi2Nt1Kt^(+c$h)&or7YGr6Vnyy_5rzz`z2a@HNgjA&DE4$ll>BlbQw z6-ABeSO=I&id(6tPGvOMnkm=1BFziEkmey{q>Wg|mlA}cxwfAQENhi~C*R+EIAW5P z4dpr|R-rseBA;Ff8DB$;c+o;t0Fz>P%Q6ezq!>1DLRaLMYb1U%-eEe7^f^z+}3 z3LMqmt)h*kp~gn6`RhyNy}wPS&IUIWsWqA$#W|mroMVieYU6@V{E+72^+#|8FRKC= zjN*nw)*-Z7ZRjb?t7t(Y?E}ijCEsK9(EO)2tIV_?_h)mN10purB_E->E^|8pg`}R_ zfo6)D{ncE-U1Ua{2)}6YC>J@9Xisr&B<&b}Q}Z&ocDH!yf2y|P7#7g#A76K(V0#DT znQdWc1|v=W)AI_$DLTgFOeuZ12~9hXY@EaktG3V{Ai(ZcdL>w*# z&y4r^ulx6=wSQ^U+PRF&?|NKsYS?*F@L;a9-nppkx4-wLJ$rTId+l7?Prsht+LrtJ z(ze|4>-KWb>hJwYT)UO8{qUJHYqqAPJ)8Ob`TF;B|G%~SY+wHG`ttWi^-hiM)vN0n z;$|~=-sSmFU~#AB*x~=*%#1g`|9vK=y*#e^*w@XEKU!q3{r# z@ce!2URs*p^2@)MU;b$^*YCZ#?XO=qx8;V{Yu?^=H`e_A`S^A9HLKqKt}CxyYx<4x zY<>2>PmERjzCZpM{@VB(W2bGZ^t1SQrwUth`GfQGK5>}+U*Nu>)*%R}^#AsswfEPT zS)JSec>T5XH_V@W@1K4CEc%0S<>R{Cf0B(;7(6*Aj1uI8!Ik`-vBpzA&q#a>Ol=IF Lu6{1-oD!M literal 552 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|VoGPZ!6KiaBp@Ud(DXU~sr- z^{u;ZPW)`!DV{5DN3=iMGv{+k@~I`_&WG}ndr~9w_@|{xCciP=S2yQ*WzDSTKTl6| zfA-$EKDS{1#@}CmIoy8z{@twokNOQ;?xRd2)UC2nrLx-`>>l+1VJvX;%1 zsCk_%+=N4$xNFI^Cecz^w0zaOOGMj6b4z?hV-ZOtmj7cvJkRsP=a=W6AD*96Qxe>< zC$R_w!kwHLpYF(Rhq#!J9Nsum$VMPs`pNOJnH60yPf_|uC=PWgP>MOKsm`(vH&KBz z^d=W{a=F*Y>#gC!@~QLB)^SDkdw>l0Tow*7l6_*nBQrkxQYVv}(RgkFZc8NXRDfqSF8}4QsF-d}pI|zU$s$>(4$P5Y2?$V_(<5S)VBp0UP zXZ;^KOPmZa>$eeo3;c4te8lWODufa4hj(z#bw*2Q*@>Fn@5fcm4Zb0>NsP<3O|ICs z81}<?PAZ~Cz5=vX-VBSr>ozCR4B$*HIM#M zp-k6xS1>?hlKu3QSOmJ#W{Eb>WIV1nZ}3>opf~N|#f=!^m5iUxNyKHQYg#=oyNk#q zozn*0v%vav^uG*X2`S!^(GPP5rs;Xx`X;gL%)mwaLpA}r0n@DLV=+{gf=_L;Nd5H` zab6`&#oNo*b3U#jQd!Z^K9BC*H>X$)o;AYhQcZ(7m^pDEe(b!x^=n)h$yLkt6C~m1 z-E@j2q&^LusUC2yV_8~iqTbv!)J1i}rl36l`o&f?B+oz}*VuHeRM9L|J_PZjx+6tG z=V0FICz|TZc&-N76W``F940zjE%tiwIfQNRDZ7B2Kc!`R&kX4*0FMLGQuaxsqIv*A zS-;qyC0ldeHL%9cZzUELFAwk8vYH`0b*F1#up?U53MMi;=2Ou(X$rfKV6!qo62rGF zw$u7)KC*4lvHh3|Rl=jph&J+Drsb;|c&6oj#m(FQ1g19Y?Yi|9wX#!eU3(N_ps}JO zU@9cdFufnct_4!4tzf0Z*mt8ul8Ya%1$Tj`%Sd>&;LQr*#d;nbfi_#fu=4eNoi9tv z_UJd>S74bFwVK7c%xkp^YiZ0xEn6*cAhp1}LwNa0KB75$y4;)-RctWLQ7o(pB|X%h z|MwCy7Rw|V762xR8;9S0YgQ_ik&tu2;|8V))Ltzb<%R!__7UdFo>r=adBqK~>up(Y zI}iOEi|(c#J)sV S{wa>*xe(+_De=O%Le781jz+)$ literal 1118 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Seyr;B4q#hkZuZckdQAmX|) zyUy@m^ry{dnoZL)99Ws+wq@H&-qG4M<-T?u|1D#D|NVCL{f&1cn7&>7drbX~ zVZMC)`su3i>%+IH-ifaGI?a3fwk30Kp0$1*d}IH<(}C@WxTnM&+5O!4{>7rQ+_LGxy}J zTf3hh=G}bl`i-*4+4g<~(^eVpO#TB0hIw7bGQP0m@?Xs|FWjDVu`+w*T+#R^ zxk9BM_!b}EeDV7JrF?wht-mL&Y3_CO-ypkj!?|^5x9{QSYi}yJ5OF%%d&`_{F$VJU zGPms6_ATh=x5$#J8C&eZ5TK2pCUpZ*~Ge`B+@2e}pZa;4|&efSPpwS2^>4+W zE$00Gw^x6P|NHaBtgmnP}4Fu!(?x9p)v z)IYl$?;0}P!heS@RXzQFmHX4hC!?b0S^Y@KYJVEFqS^o4@~=TR{?*R)mDQQIoKNh0 z{nyPmPds|3qAj(4(_gjw=Jn@(KX{?Br9T@e*=`kK<1eejSNh@PPYr>spY48pt2BNx zdEu1r2e~S%#r|Hs$9_BRRQ-RMc|E7^>hYhCPI&d*?#CJR8D-mlvXp1$uWa@zTrH#}YaT-G@yGywpJwJF&E diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_stop_restart.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_stop_restart.gb.png index 005fdf1f3095699cd6fda0a3ed2754a1e265a582..c0bcf5904e91479e417f5fd489c74389b6a462d6 100644 GIT binary patch literal 1514 zcmX|>dsNbA7{_6xxJ*RnrWrb%Ewv`*W-5v|PGxpcr_Q``C@t*h4i3sRjfkna zOz~7=PJx;8mWHU!dyy7i%byGH%0Tgw0=gf$?T`0)&-=XRea`23zVGw=;_vINx6^bd z1On0XId(Vz+)KcftD_CtoEjn>0@14SIqVgbcwbr+n=L^jwHIS}GZ7Y~ukz1bi_36v z8#i{AB7Vp#rI#;spCx|Kp2!V2Zr^T%Pi#D!X+vFAhc&+C1n0;AcEIrq_c%zrj!h|O z*ccM$!j+1i$*^bI0DDV09o`CLL*u{j7}$cE>~TRC1T4^BJ3OQL!JKcik@yVzbmW*T zfv0?abr@5};>?P-V;UYn9GtL9MVjYygzFb^Y;fi|ryo|!21h0xYc|O8b82ZqvQjWA ztqtMZ<-21`xNP!zPmA`R>dm77E!sbsIcR(Ax!- zmmAo85XoV6g?ix5;7HPH7c}eY`T`|9k|&PEZG71U9oE-5^fZ%Rli-~~whXBd>4bP@ z2SG@9M4|;Cp$UT7s8Ke}Vl1xvS3xoWz9 zTZ#udP(GybP|8uSBs52rBY=ayb?tAxe5M%I&EA!x9F`C3XUK*$wf)shZe5xN7aB%V zg7*_8dE;^o@Xcy@PUSAg+(Qt*C$jbh<)xYqpl{EOr+(aOk)*^x$U zn7S{J4k}gb+qFuxiv*Z^lN~M5mg9dJ$YXd`X2Es8r-8SI2T-AP;(Y1E@!>XFZLy#O z#TSDx-lSz#D-O=QgjuUTv|*T!B~)yopf4z%Qf7CoRIc8b!j8{W2>aAI6Z8dmswtSe z<@o=VjLJ>}rV6L&nan8aNCR=WYDmA6Cj1SIP)HF*WZQELV+EDl_|qhd(Yd8CR}t+e zgS?#{Md9^;>`w#3lJxbelhQ7ihEzLo{$?b3bH+Ys%~%XsxK3>$c9*`?3YT?Muewbo zas^2UXP1W})W2f$#rgHUi(yw;UD4ThLAZ5AKoZwX5Y_y~%OTvgq$!&82=<;m0v#Ng zf7k!y=X)NIlt2KNVeXb;_D&-*<__#iZ`n(Zz6{-TqK6`M+ zfYBUlke5717&z(-IkgtWO76*|M=2M;w@-_8wTE=EXhFF~+g#ZD!i@>~2M+kZhL%)j z@*2O2R6%oHFU?aG=E{gk31p*?CoSO5omRjWWn!=;g0ixBil^!xU<+r$Y;Gb|+)Wvq z{OO7~UT@f4Bx_2C*1l4QoS!wfL~rs;rmUOlO;`I5!J7cti!BS2Oy=FKpxQ~=KHznn zI`Az{L>|M5Zmw*!u1#+@Xo}ehwtOg`lx8A1`%HiXi_tE)PycTMOwftl-V{#?{;?M#W+BI2 tYn#$|DJqlf<3&5FnRnpK*nPESP2cob@aStE$`_pB5T7Hyhk1A+;~#MD{h9y( literal 1485 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 TyMy}*00000NkvXXu0mjft5fSG diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_sweep_restart.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_sweep_restart.gb.png index f28a3f1971a231860136de59fa4a712a316558db..e51dc2d4f708f6b2ca07d2b506f998405cd71967 100644 GIT binary patch literal 2288 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 C15YFX diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_sweep_restart_2.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_sweep_restart_2.gb.png index 3b7ee8746ba3acf26fd70c5c7476cafa6f835eb9..1980e20aedd433d99994ba27ccb52d64cca33d13 100644 GIT binary patch literal 1484 zcmb7^ZB)`%7{Fni)RT!iTX~97b5>SPd$FQYkg55yiCHJjhTuGA9W@F;QxRC{vO0>U z(_9voBWI~(sidTMN<)XmswtGiza&M<6pjAzuKQ!1oz7|dun+g%b3Z)Kz0dFY-FqfF zYPZ9}WeZ_2m_vA2a16B8K%>OY2AbKeBo+*|pe#H%Xy1wI$xDfpi+)a_(yD|~ln2_S ztHD@Hkc5`{g`JDNr+IiHJ}v;aE0s%k4vC34LXdvB3X`DjSpD*^j`M8iQldz9wb!@E zXRtE4p5b6d0#gIr*z{qGR~mx+_=Sp08ZR2$#@jC<>&V_*sz4q*yCNt;Nzj;c(lG;`)09y}bRbV!_|7m!60&21x8b0G7M&8{aKQuMn=(#(vx+RTy> z7r5;H>B7E_rd4ll&rpH&6Ox+=;?uQKythSvoI$PV<(c?@m^Ph1$Kp~s9FFjTinj!~%84??R3v8``$gpG^sQwn{yf=`u(A#GrxX`pvXNm( z-3Vi5o$R9LQjdDSJhz8erd2a_7vS|oeiYK~$~UEm=iULFkr~yy`x)3n&vg&HYzIWj zGy|8}65n!d^R*Qm;j~Koa&D2n?|6Khc0nClLKg^os?_kAq&(>j(lEH2zO#vn-1_zP zOP;gUU1CZ@yk}d9Xwy5qS#4;r?QsPA;U0@CQGR3@J@*~R(yI&#wENv{3UrN^TN0Zq zl6}U+5w*)bYFy-9#^8aCn9ys*=??oXI>>nz6wg2!QKOX!Ji51!tdF8eFsMc(XgG9wJb>YscW_-j`jz@2of^a+9vH&5!Q0 zvVBO-M>%m&$GTAVLP-|EF;37&3UFu8%!}p&txzdgb2JC#ggc%aRTyS)t7&8~suQhc zLpa9=X4)=)aZ4n%c!fS{o;K0>H%9LYB3pfky2?jEI(|Zdf~^)PS;nyznnMkDOCCAz zsXoKhgpYXgm4rRG6A>dkDhJUXLq}#5mSg?!y%Fq6IbX{B5sVK+K^*^`jc-5vz&x0Z zi06}y&zfnUpsABDO%qh3oaVfA3wUbddeyTr=&8NGBBYbJqv;I@wu<@0Ix4b52(DYi z{Em5Nc#}`=^2N*q!1BXjXIkDVy;R%o>xxr!k=_G<++lD4SB`73vhNZW{0(~OAs_DW?s$mrxdI`+I=>X<8uCX7JbsyQx&Jr3$*&B zVH`Xp&YY!{cRHNK@FY19ZUF2ev1%b3PX7miCW(F28OU;xS#k39r@G!zva)?N6sU7g zGqB=4!c0`M(%N9(t)%hp++}OIBP#&Pi#F~Y-H%C`Pxp^Sox7HN1f>%m*=jyAk$vjb)MJ}ojx;MB zo8EG_JtqY_A#MC1?iHx?{1-WUKkwdi7;9HxlOO%RmY2Riy}hyBl1_j=X&5X#Br3QG HM>_d8Z(af1 literal 1328 zcma)6ZB&wH7^W|2iPLRoGFw4ZCpR+Dob)lpnV7Lsb8D5U;nAe6FvO3Pe8Cyn$1FcH zCt_5qbvkG=%TWzMFjGRQwmjG@6ohCQ@)hwSh z#QF8w!-jFuoUL&OS^GWw1?tv^u`JuV{5TJecEf>xaevAe6Vi-a-Db==qK}dH-%sgm zOx~+7$&*VPrTkNNN}OdM`W5Z0i3K;;{$hJ`!?5w5^UStvu>XBC*6;XuU>5|t{ylVRL36p|1$xiiW@g)JW2|I_ow_Rl& zzA7r~Cm(D`-uozVs}*E~0ZlZElw};GHT9h%-5J(LeIg!64!@VP{2p~X2%ttf@r=?h zZui#7ZRVxUbK^46KtsnWJWTW8`4uHwQ=nn@4r$rb%gmM`=*#YAgkdKN(NvCF-`x5J zA@-+53_l&Boc2eZ?1NX@))=JtqaWrT>Zr5tvoAL@o#%qMF?-~@s)*L5HZYS8Rbv2x zTYG>!Htl_trJ{H|*T>aGA01w6`aKr`^*k!B42{?jlhK1zpNT0<2d}-%QFEyHV=+o0 zvV>OTkeM^U&FH7wGhTlbIhE<_{;?ZQu7Qw!(XGl61ipAETCE=$b6FuQ&%;r8@OQc> z@Mx4ls`bK}rCP6iU}lk;BDl?;w1kfOj5d0CCsg~!^-{33ta$+*s;4pHXE)NihH&e6 zEV9<>i0^>|0+CtzQZ$%Zu2@W<`R*BGm#ehM)~$Z*JWeooZYMkWuK6^KaRN zD90h;!01#=X+^t%$)5x0Uc60j{!N%pNFAGCehQGqbfobFsV-gLlLKg;fq`gIYnQ#R zTMTE-Rukv=q=`1RP3#YI;&daDV1?jo)HHDoVOXMsuS>K@kvfQi49>T)uC$$AK`2=Q z!7ClFrQBIfyaZ)XbC4EAVERqJK*0PlL-Ob3PX>mvH zycPaC4dbq?w4h+crVXB(ml5ww;l4OGn51Om`XS4HeziTT30HX5&43JeXE|Xv2eJoW j&&$71PAu<@|KG=sc5+3%394p{cN3E0lZe+hWgh((<6ObG diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_volume.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_volume.gb.png index e662d1623910b43b69943a95d9408156e5206814..5628be2bbfd5a641dfe15b55a76bbff49ea7b768 100644 GIT binary patch literal 1545 zcmb7EX;hMF7==hNCj+K+%=olLGb_=P+LV5w$Ho+MqwF{gi8Wf5TVt9j2szrg9hcO! z%w<%dkua||vWe_3D;_hcdz;sKvacmS&}wX*LRayH0x zn_u@?ltv*ydCCPA%@8z=Cp&?rMSZPkPfgVbs=|7*Y^_fz)8p{|62kRQ?zPefv6eMz zwuUq1t?iM>9%dzNktJ@>t30sB5KMO@SvC0QmU0yqUV)uNJ8$D`ns&c^(^8F1ya!3Yf5qF^4`m8@;6ywSodn zYW9Tp%n&+E59nQ|2FtU!$Ht~&C7ImkjiDOy0i_BO&56U;-0&9;*6(6ua`)kW zYCa|^?8=CUEP1>eq&?a;I@Rpk&}bPdZ-3P%Pdq{lgvdK+{93MErdJS#N+xL9MD0E2?9JlaG$@<%uw_P0lJ&8vqa%yDDX*wxfb>N8Nv$ zokgzQGHD%vj7Ft7oi?f@ze2%Bv3?y4j*9x(n<-Zu2&dlGop1zZ8z7OiR(;kUAk-HI z=bBKU1-1Xu6p4%{A5C4a3`ZwC7@m1;xWcD}9$;>t9x3d)WW159$vA_^YHFYnKKRL# z_zZ#))rGG54dU1_Iv7Mou!2rxLLq=U0NF`zy1S&iZ`+BDrxOY645QVn{Vk@oiOld* zplLqAp@LkJHDzOKQ^$}mF-%%yb)ZeWBd1aIE+15#p%A$?&t@h` z;|B$TuE1kJly||h9+<^|e$kgzYkLZH`Gy9wyBcb~)87kg3yO#@oP$~Plk{B&7g)c` zV+KbTSqrRmoQhxhN+kVy0{4Q>kJ+@)A!SAr?h9eT?}=WcJbw8s$-$U8R`#=b~5urH+B+oRBrG+usOarH5VA>36KcZ(9)c`!fe-lSN%@QhSG=Kjmb?CdHjo^iKVH3rhG y7E&9ZXC*nk`wabn$9pa3=|J9WmPd;rZG@R-u@g#6Z8oq#7v>`^kQrRO?d0a3plbF%OP_(liK|!XT$=n?+7E3siM>PB z9dE3UUo0!YzqrenzuzmIU&M7$-blm=_D{~bhQWK(Ex8wSu<=gs!M1m>3&HdeB2Fu) zMrcE4H(aJ2BcjlvNm6qFSS2XNOAxow$?FZx2QGIPg@IDF3LLbB$Wj2{rIoc~Dp=Qg zr9Man^>{;ON$pdRAmBugm8BJ}RCpalczML83rNL~ zun}z$2|yaI)e;&#;Ti(^%6Mk~J-{r4AwWENmAl=>Aq1BO#`8h^hulAI*ZM|i@L=qK!aMtTVc07p8k$CT6q0)<@ zhSHU#b_}UUUq7lRM$Km{U&}J{?Znm{8TngO;J_Zf*;$vYodSw=yHY}TZNXW-%&Lk7 z`H^f&VR-K}pq+b1C#;waOY;9Au4H;eA|y_^Ef!$rL5t#8V)T`mD@wbSn`%pv0<+Aj zgsF_?yP|WupE2d#ZQ0!N4H{-m+R^3*mK6<^yEYlOE0ra-yu&#`z*G}EK20k8%BXam zld6vFZ$2=2@)v@fYVH1(Dxo6L0K6jurveMABQe0#F>`IcLS0uQQeZ1(n$2hcyELQi zW~myZg^KAN$QVT)X8Bw@y__^(^hAY7pV))Y5}4&OSs>8E zlW3TB`>Hkw29lZyTE6;ouft-e$dH{lvWcO&Y}1NQ?@ov=CYze*r7_+Eub7tp_u}x} zXA_<+q2R8o$wGv@7k`>D1rEA}6yGRY9D?h{)Y#CWutK31vJf@94n(w1a#WyKO@@w} ziSs^v*^ET8t}FXnTj7&|kCKl@3j{|#KKtR`pp)q{K}%j^(9xEeeF(D2*bP+*jj}p? z%5z~5xkZi|O$1AYttcG?c@L|zWtT!p^?8m;4rVAZu~NZYydKRBd-LtItRx(Y{gkn` z=exSHI2MfAo5=(u{kPt6zcZWA=!wm;W7N9G9^DLHppGZZV^_0i49I=qpb6lxTs_r{ xdRo*MNa{+&KlkZfy>>J=PsBFNsrsK|1Woh4JkVrdr(6Cxg9C{Hzx$DM{{=AAy|VxS diff --git a/tests/test_results/SameSuite/apu/channel_1/channel_1_volume_div.gb.png b/tests/test_results/SameSuite/apu/channel_1/channel_1_volume_div.gb.png index 290698e6687d268ab6ec84def3f7ea585e9ac8a1..1f34b7ecd485fadbabe4d1558e298457b35f3107 100644 GIT binary patch literal 1043 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-P9ICviKmoe++kslf>Qs+IdoV9G{l%lUQmSx8MdGh)7 z#zL9rTMK2%kH0>yer^5L=arVnqaSZ|`D<|gvki~4=Kud@OQ!_IRqpw-r~J>|J^t(B z&t+;pHQH`>PinpDtN(vKYhBf6wSTGom;b?LPK7{oW(%IfXU}U~xD~Fs)aP=D*G|5B zM&G)gi!Z;t^33O&$~k_^?-qW&zASUsoX3e0de1Ae|H!^-x7_o%V5#l0@4SzJy5^jJ zzPg3)aKO3epHnaS+wYe+{_)jZyS~TocKpizS{Zll3Y`1ft-TCc(`)5yIlfR2Q?#lXP@f`6zq4$^YTl|ledJy=IUByd& z!V0z816CWpZnRqfgb(zu{!Y)YJrEzV9%$|g{vQc@?Gm1UeO-8)Cp4*q2zo$-S?fUySFPpsW z+wc50s=xNYkMB*_-~BDvy|lEJU;a_``utCOAKaVHSd_>1p=0gp+l#+`&CcoFzV7+f zS!^FNetgS%Uwd}(*F9mI?Gm~_e5{=HmGQd0{cU!i*BkqlB%hOkj zviFqM_SbH?_xdYi`7>Q$T)*nS{+e0n>YwbH+t=mw=QwSfcJlqS^I<^K{?r|)ny30> z^DA(G#=Ha>w%1M}@K=Mj?YE0n>#wulnYmpizjw7gFfKf<^xx?VJ@t8Z&)4iL?`K6n zUi-Ro?Xubf)z71wuA0APwzHBK%l}&LbgAmi;;$g}Q|umiVROirx&vQ7eS4#pl0EZJ z-p`!S^Vu(%-<^4#$oYD2ocsih+5=PNerN0jx%p}SQ9;!P7htku@|eOPG`yHs>JKkt V%k#=j=LTkW22WQ%mvv4FO#oHN?lu4b literal 968 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Rrvr;B4q#hkZu0?TeIh_D9w zZOeG?dr#+Yz^Q{yK{`B!a_4Iv9?xBp#q;oJrgKl>yyp`P&lmS>47J_6Cr0n1{q)nR znt)ukqlki`y=@+hbd@Mpb-B%7wEW)kRsOg6-K>|^wF=~IzdfaJ_uXkb!@jmUhTWL| z^z-tKHeH)OiT|v)f523JxwO{t>dpCc{ZF0#crWMro?3%B({e9;^0k|LI6PgilK1Jo zN&25d*2_&7=knctH+)l&J_ z*q=u`?#s-1_W4QH9`oPVe*Vc^bF6xE?B}n`Uwrbx;}QJt`BKTlaBUpOA1PzU{}#)sMnpdbEn+n`P#m(?=D)?l5=#qwD;pplj4>B zXKC)S{2lmn*8Og|T=7ZF*P8qT^)9=AdRTXJt=6S!RR`1G=CysjHT#s^jzjDAw5;Fo zU-{VHsw(y+#7b9^_X4$8&+ruYryYl_uamnp396y=Xeo&T_Y?)>EBWEw) z?}XnE1pYkxEB)=@2Vk(+u4*dN(fjg9Rcy cLz{RmFI|+)=pK751e8NPUHx3vIVCg!08*sfKL7v# diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_align.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_align.gb.png index e6601e48a50ced9b870491c13de4b93c204d530b..e1323bb000d3957bb2f8352948ce2706fa974e09 100644 GIT binary patch literal 894 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V`_hk3UQB-#RZ z-!gr6@6g#Q`&|njJSv-VAbNVS%95jJ!*gFm8m%c=y7k(%(%hv}y07nAm;3p}`u=mb z&q=PGJ->e6wrf#qw@wN2%3eDq=+x$Z^R3sqx4x~|a?jZQ{-62$_m|f2Fv~sF{VV-o zE9Zn2s~N9Fo&WFG>|Uk4bV_Ngx90SRx!LD`{Q9@&?VPCBKj&QB_4DWR?9ZLe3$_P& zS=s%HIve=kwpEYCf&WtG9`IulnpQ zv(VQmxikL%6*%;IXBGFqf=SUI`sdF7E0!ZaLF0GB{*1cFX_um`_iyu`zxeBXgM9gd zqRsbL^4(;AbN=N`_L@6?{++rMFL}N6Z^__1{EhK;nPsbVr5wl#7uikxH`s5>-)1+lpS7LeV@mCT z4}a=vPd)$nZq9aoiFxnuZ_hp+KiB;89+1Spy|>T3?RS5@SMvG%P5dt^9o+bKGWDJN zeeO?A_=f7|v5f0)#IJlX@eT981wSR{Ki^$`&o1G{>ie00VhSqi>QiTYtlU@q{BO*L zpD+F>+Ka!@J6A6I&*IvPS8Ug1q!#?xaW(OG!=uO6e7D)}{J&+l;OGCj2p1g#x@g{Z z{uy)c-|K$+cSjj8{LWhB%THLb{0(!J+yue%%x%x(VF72KQ3p~F)Gkr>dhWCBJAY}; zcwYH+|Nno*N{d)LrZ990DFia9cs00iPS9W!Qgs;qf-CmlDPOac;gEhRFkdlvy85}S Ib4q9e00~s3KmY&$ literal 804 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V1*PZ!6KiaBp*KP+0UAi}n= zI6m;cZ~V01hc%s5R~~&NQdU+!@v!*q6y=X1(m`Igx3xCq-VXATef{-~VQBc7^7F^1 z1oarUObFsqv@x{nFnrd2e8;*Lrq8jT{vQhWbDwzg=a1L%4)a_O7MyEJ?m2#axr0ZX z>*CMPvyB@+3Oe2RZY%cYciowP%ez5N6k4o0b z_ixy&(|-C<{?u*u!!K{D$;N*=erSUHsryB7i}s({>9YN~d-S5W%`a6z>SH3OsoIxE zPMbb;Qv0WG2j@!W{@s0kHn-Og)&&a2(<`yg}CbDnkS^)uuj_T-$s zeC|QbKhBmEd7G>M^0M#Q{b;&*-S~a?z7zf17HxU9S6^!0{^Iy8tADxt$=bca&NtQM z9rv|&B6r?2Z?)z&l0^Rsw^4FXc5uW4q jcFl_uEV$Z62Ju<`fB&Bci?6#jfKtDwtDnm{r-UW|#J7N6 diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_align_cpu.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_align_cpu.gb.png index 82a17ed6dc8cfa3b270df2f0ce3a450d2fc5593c..10551d8219cac0d8caaae3bd96a06831abd311ed 100644 GIT binary patch literal 874 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V`_M8De(BCQwG zub5WlpG#YAzd||vgoC4>9`kdLiLVawZ@s8KyT@ns)@$2xvqMWi-`ckJt=!+Q7b|~T zE-wB2`Mmzxt=n|GLqoS-Tea%d&EvaMBlE6(dwj9#{GXc7_4jI~S4p$kobvvqf8f2E z!=iU=J9JKeeQr{*WcsRAxwlunGTT%8Rx;jx-uC&Mff92r?)v%j`SfSP?2h`Oq0>)4 zU3MWg@>S8!82_p-*WI7Lecp5J?Dez1cC9nNpC5a@{QB?klzVm$?tK1T9T|GP_&3m2 zeZzeD2`iT89RBmZU7&9M?(GlE)pxSi-~M?s|KK;q&Q1J3nx9=SU3=};*RA!xWY*TV zSN?98Jo~R-=_$K}dcX5_4<0}351;n$)Q;TSyI=p+HjMwjuHo(1`=4HIKK_@veQ*D> z{@368++RO?KHvUp@P~E(?d(`*%b%UUiT}p8)0#Dto`bCLxT5*Hp?1UHjkOM+7X!_A zxye4K=HCvx$DbR%F{;mhfB$>+arwE^=WOS<`1$AK-uvg@_Pf8{d*n~>H%43j6DKso z4_vH_pE>_6*OYnxCx#z*Je5oCq}>DlS>J6G{LO#QJ@uZ|->!borZYcm7To7Hlb>t< z^n26Yqd!+&mOm~Pd-uV-U}h2d`K7n)7X0|pb@>}(fBie=ZTuN^Ccu!<0Q&a4{Ppx2 zxeIm=o`Ay5^!Z^9V8B$JvRm++QSze=P;~SCrnk&Osq!D#&sNJ#SpNIX+*iAI{??pP zd8Y2~hxx*Sst$`-Jf<*o3Mm9KsdzQGa8A%*6dL}5e_0RxpS?EA+ItBw4>5SU`njxg HN@xNAGYple literal 777 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V0qPZ!6KiaBp*2Npe65MWi@ z8b0NnT5Q?3=BO?X_0<^{*-Cfq|L{R)`5mz|E_K%<+j3VX-rm+B5%E6#bV$6Rz0G`O zrRQ^kx;my@l6~xSZl|5j<9(B)&hVf7@Acj?#&zDg+vWcmi}bnLibduW>&4G!QoQ53 z`1A3-GY?dFYrg$GPx@P}e(~a0e{*KO(r&0(yXJM&{N3wbpY}Q(`*Q=o+^qBUWd>h+ z*FN5NDenKWJ+%gNCgukHoTSg~T&r>abYW+m`E#MaU;pHIZ>cqy3sS#+YHH-G;_0cC zk(oO+^W|-3+`P75ySBjkYTRi%i=`%ayMo?7C~N&$b0=;^?aBU6TZ<&Vi+(=*`Fi=q z(1-D#OSjpbIe$~s-nM=z|GN2tGv&`WKfJ+yxpV#Zt@`?(JonA74T%5!1?UW!-wzJ{ zjGFnx=7wEG!M@sbzQ_G(`Dbsl^PhWu(tq-~f*&iwZ20F*&@L~quQswjEL&Dy_sx38 zy?Q3aH_f*E(>|Zs_V4HJ7YBdd44d*;?R8(F;`xo7zcPPn@9!=Ptrz%T5_9AJG9&5h ztl8fMW8O4x{Vj3GPGatM{CubcHot7C y-SGTi(LCeV_y4;bEco->*n+EVal!~8_A@RM`dVYMbGa@kiF>;GxvXEaktG3V{=i+PJ2B-$R% zOv@L1$D3dFZNb8Wni--`qPL%)TybE^{TZLcu6IU9W#`UX7Us3H%IETxwDtdfUaS0U z8U1?g*41AVCDzT$muQ>)`tRXCk3V~#kJ*1KDtqg-AiMc%rv#n4d3#MhF_H5l( zv+n25Ykk|VRX>xTe}9+W>BrI6-=E(e9=NZaas8)>b&P-Vm{hV%4@A9wwO{Z-hWyeg zM!vzCPp$S;zU`T>e}4A)m0RoPZr*xN`uN5z*Y?RhwzwB#UjOEg@%8oF%>N&G=r?z( z`TYJMubnY^;jP!APCqUBY4!4|{e7!^yY%e6<~)b5#=kP)F~5FR-unNUubcUIB;2!8 z*ndXzwt@X$fkW>%{}TK2Rwe)7v-mG!Ir0-Uem6YhpS_*`#LI8bici=j)cd`k`n%!u z{xkp1S@>Q)`}N=S>G#~LkN@ z`< zt@oAB`}zF&@7G((YToa${rs`k;djB!pHH`Xy*WH@6aS0f4LO!i_;!@u^M7`iar5W@ zPh<;TA7+txJO37Y&GFhb|1<42@=M=mFIj$;EB@ct|Dxr~zUVjT#JeeYHMnq2&|nl& sby&pWF@>R1NFk6(WmFImAiucJ8Lwv!J1Kbtn6nr>UHx3vIVCg!0H2VRHUIzs literal 784 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V1_PZ!6KiaBp@2Ieg`U|*+C>1F?UD=R3M(+LGzbk%jef{(OgYz5@Ucb{{u#Jaj zJD-dbhvJ=2p;uhKX#NWPoPFK+%eRoHe;-HWu3w)hF)fvIW@=>I^L0}C=lA(dRo>~h zZbsho{k!LV{LZ%eD8%T(^yL!kZ@b&o*1fIT#oxBOX!e(1{&u$Q>*wt(=|6jW<@OhO z&#$jr{ySmU3%eg68!p#=IDF-s)n@*4{!izZp0vB6{jZ`fYGdZCOV!IWZ^>{f&bi6{ zoLkno`t#)zuXe~-8ruI?Tm5+N=J}@e#>cETo-TiT*8D^7=ksrxPoH@;Z9n_ro&3wX zzy7{;mfvzl{5;zVt#xzfyIED9dYfBU{`*1Hz5IWVkBH8he{1)%OMkv>np}Tz@7en? zd$r#etUP%BwRzv_ZwG&#x%%Q*WY_p@jmD3pJ%@x+!Ncf{pVWd_?`UUzCVzg zyQAs8WMu7+XCIZz{8WCV8MJ?QsUf!0=70|gE@^4N1o7cwnEXZeZfNaWk4z2)78&qol`;+0H5k} A8~^|S diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_duty.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_duty.gb.png index 66d4896a20611fbdc6cf48724e78ba0128fd356c..254772b1a2ec0a27c1dcd43ad1475c483a1de313 100644 GIT binary patch literal 1571 zcma)6eKga17~fh9Wu}}$Yj-I{r??&0?atfQQWSAh*J~Jxyk%{LVYalq7gu??xvWk} zEJN-%g_*iuimb3!i6N}8mX~d2X7@*(?m73b`^WeDobU6T@AvsU&-e3rGJbV)($z86 z0f9ieN1Po!0DB8qxmudQp2Nn|Kp>6DBaR17#{VfUIi6Q(V{qu8m%D!Xa1r6*BTRc@ zw)UEgb8cZ(yO}m4dl+q5m!{Vl24|o5DKNyvC+zLou#qtoz;v-@Cnu?w4MMW}e!2q3 zrSD6H;}&9V_Z{my5f~v@Bz;jSS}Y|S0-&1Q@`dA6kl_|hl(RXE8-5ch3I{R9cG2Ml zXSBE3={5DsuZrs}_^y5P_ba3yl=AYlCr!3ru#)&>+UZB$w zoA+s(6G4(VG&Ng8n@(BeJSAt()FxC(N~Xz8M~BHBjG1}!@(Uz`J( zK89g6f0!=wgLMvH-hQDAEEXz2JE4D9D*(J#5b(gs>yS|w3K5$-n~%ty0^imYd^_V{ z>6X%G-~*X<(7z~|B1k1As{>KZFBH*aR2c%=s<)E!E1%jp zVtITZiRlhAlg&{)0glW~Ux#E;8igLwLoBH%e!e9SLbONqqo4-LZkoolD;qk6m}fB4!$vj?0_F^u)5r#yy>SRFu=t`Zht_5X@U1#pDpZ&K#?!D*U-~Ij0_kMoA-_1OYJ!zbIC%&^SR@0J#sdjSgWw1Qcana ztbu)H{mmk)^6;AiC&F0YkP_GKX}QytTus0)CEglYnphZZQY zaXc>Q4iw}F!TY`g`bMyN*();v_sPjQ%I&dRG_@Q*sfI}SJD@yVxW26%nA|KxnJsqe z9|`Cr$HVKUvQP{fsD)#>lio<6)#t7i^?_UAxvbT*bC+W zo{Q3t9;Kw^O***9((@+cj3w!Q^3~2h04%nQ212~-20{cru47W&!t=~WfgJKk(`Zc zsjQ$-DLg~%112R$d1Yu{9)56TSc)PkLhn*jD-QCZkCwBbvkx(YTYuZ+Y~ZFf=}K9j zc$6BU=uNIiXKv%LF=ma}>8bQuJKb%ZEab2fp}AM0V%jU5PsIKOoSf?7(l;0-*l3!_KG`(I$~S*cyh;> zm{;j{FnHa@-@(VTKto5cCuByJ`-P?av9C0=&X#}G`oPvul+&S2uFpl8j+cByFLw?e z|LeQ&GYf6|H0+s;U%y2>oBj-hfXnGEoSQ4a(sB%aTQW%q+uAV_%on~dL7jhV;{Hsn zz$mJyGEp)=x-V%9Co1hB)6wOkSLy`4mmbnDCf$JM3sL7?ca88!+7;w1w6#do-9*E~ z^R=SG!@72p*B};Us?^shzZfr3*}FAe!-vHtn=&>ekY&_42PM;9cz1CAPj4UFgaUtf z2-_*Rbj{V;kInl5F_^WPWD#>=DHp0vYwVR%H%3qAv3bq-L2hv|#X-=%={EdgN!4p9)|?`uyM+i-9G9zT-+c;dz*zamgA{(8n-eH zDQxWljy||;w{;Z71GO-nmKW|+f(z7*uxdb7;ud{ubLg$$VogZ%O_@%_vClI0iyF77 zZj#zqZCK0rc-;?<{8wtE`vmtYyPLZ@>pZRg&J6SrhrgZR=HmW$!+AP#B5pl<++|7g N?|Ngf9vn0-?H?kX+sXg{ diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_duty_delay.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_duty_delay.gb.png index b9f7a35f2489f3a61768f44225439c56ebce7bd5..46c209328d3ee040edad58b1c95c88cc5bdce8a4 100644 GIT binary patch literal 1430 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 O{Pe>5xwGByw7&oiZQD2i diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_extra_length_clocking-cgb0B.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_extra_length_clocking-cgb0B.gb.png index d6e02f5e8ac561d23750a7921a2426bfb7a2bd31..276a0db09332c307624c5c60e2b605d17185811e 100644 GIT binary patch literal 909 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{Az)7Yz`!LN~o>MbNnlZJ;&t|!nJlFY%YqIJ>-fOq^J&y3!46i>{xMuQuJG;#DnoCQ* z?|r-Y_qRLulIQs?U;W!}`Q=CVQ}^fFUx|8cz_avEWlNBk=K6iMl5G#4?Ys9k`uy!p z^XHxZQuA#4^mq5G=KcNk@A}!BPtAI^q|ZOU`S-oTy~(!U4q*m|wL{!RZ){;zlK3isUDz4vncto1=&J7e_1 z-}4t!$4?JfrryWZDv+1;AQ zub3?_vMq*v%YVz?@76!Kmr?iU>i#C#|MmU5`7-41f{FS+r4F0;cJkerce(2M>xSrm z7i;Y1uYYGf|9p4-^uPORfBxo+IQ@pZwK{)${EwWqZ=ZkvzU6zqZT{(fwf8>X_69P~ z*VWd)SpLBCw?+2vpOxO{6Hiz6zj=Os@3q|j5BHVK`}^;&V*K$au8)Gb0(&2SSE??v zxBqscJ7<6X``-<7i{IIPyTw0q?|bID({-=ci~p|u?Yxe8+re$y>wlFV(7Y3M|NZY0 z``Z5>uQT3%JNMt^J$Lsr#=kvW|L;-Ur(B5$C5J^U9#a@Pg%kprRJb*0|V22PZ!6KiaBp@#!gyfAmZ@w z$Sd7L_YyYGWM5_c(naZk|H+3n{$)F?UTw@YYMXM&#CM^AZ?Mrn*!sEaXf6gD?z4!dR`t0{L zJr{pkeTaUV98qK3v-QK`x9&@m?A|YD_j~W>x1~2(pMU@BRI|{3UcR5^ z+#2~eHT8DO?r;89G{5{#+?IN~(^LNiKIcC_`TN0h?ccP1N%HG&y0)(0>UYBP`E%C$ zU%VPq@m%xPSN=7JfeJv1*bmr6)NU6zWOII_!THZcIk|gnLhQoQ?L_9UsX1P>PwJlC z{%?%^hJBA`)XN;-SbISGjQmf#9X8*$MZf=67Ux+%Rr~Maxj#S63|U|K8|eLyt6zL` zy#DO-#dGtUzr8s2^G{09_y13CFBYF^|EV-_cI9Ftx2<*CpWgfVU;g&zn)u)ED);lZ zod-JR@8=t$&-&jqpXPV0{C)e|L9kE#_w)aI^7C1bpL|5^`afo#@h1)xu(cT*%xQec n!;_w1!F*U!;@qfEdcuzSk7rf$; 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 i2@VbEaktG3V_q@4j0OA`Tay zhi%LFmSz?$>G-SJgRN2fh~*?zjo(|V3Jw-^MrN;lY;o;Ojb-2C2=RWK|CPD-zkj{C z?|u38{qoP^^XsCs*XG_%OG{g8YHWPIroOWF{oniRjQ{WYyua?x)Stp!Hn-gW@_)F; z;_)i2;r6z>dyXIe|IN_2SmyYd8s7JtzV&<-Uw%3BTGaK&C02K1&Hw-Ue7kGDMa|`X z+xutE{QR@#Z`m%H=bwL8U0i%V{>|@yPbY7B|NCy~=k@ma@)v5X^5rL73Er0Y@2g_V z_u|iDe;zAsPx#C~YdgQkDZ2$fOYYezteowC@cfg`-+O-=GHEhS5>gl?$O(g$_nrLB VRC@()H33r*gQu&X%Q~loCIAr}*SP=y literal 532 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Vo2PZ!6KiaBp@9?WWX5OKH| z@vFOTPP}z&OP7kTSgK2rWxDCraHE2g3!a!AyRq$U*@oQP63N%T{ykqBdwhLq?EgJQ zDRt-m+C z_mAWDeyc}zwfCwE?tT!NJMX)kOnFtpx~Iq6EE*rP^a)$|Js4$R1j28|=+$x^S?l8d PfnwX!)z4*}Q$iB}(WdQ2 diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_nrx2_speed_change.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_nrx2_speed_change.gb.png index 955eced02c658132647fd047b512a08ed4abfd90..62cddba8d9aff7fbe6e0eae9410a2433348a9015 100644 GIT binary patch literal 1016 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-A8q*mRQa#?gF7M>f-f2N{-RA4|KK_3B^RePx>vqrIyv^?V_gcxehyN~r|NCrLjotmNc5NGjx4&IH zB`9zE?ZbSROJjH5&HFz2-}m>|&q<$;jMiUjvuE=&>&IWK?#9gD|6OnT>BFyM^`@Ww zYWef}=eq_x&ZmnHEUqj*l59$YroX*c(Z^SOs_Wu7G*7F}K9TuHo>|ABU zK1aN)?#~;U4M#1f{n=Pk!kF${6E+EGWay)PtImO<^DN;Ci5>Fh3r*t z8nU0;PTtNu&pMyaV~XX18WSKL@@MCRm)6PWi}!xYeeVB1Wxd6La=Iko3!p|~B|FM}3cJGf@ey8sX&1d#A{TZ|R&%!-W_gqP0 z{2sOIV}ow!^M>>D-V5o(m-6jM&*ND7XVZJm%)&m^dL4x8HRR9EW)=$lyYY;&x#FCD zs1b0lZGF$Fnfmkch4oLO=Omw$KU4p<;rsji8^ty}x9^K?nmRun7S>yLKlr(B`X)zQ<+R(3Ps`soR6nn}+_O7+USKMph0nW!W!dMSx$BWC;Tj5oTpm-HgqAkAXbwf@75jwsnSM`gckBS>Xa-ML KKbLh*2~7ZRrt1;_ literal 968 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Rrvr;B4q#hkZu11H^95MVtT zwr<5?&*`f2A!;HDkx7A-6|eqD9gbeRIX6PBXpTT~jDv)*OmfYNZ4(!*bN>_`9V>r! zlKsj5mOqUI9z4J8&oGbm;G-!`&K!y@>up3US|lEC%l&y`Tkgv}##wvj`38UWsAGz_ zesy12?Dc0Jd_U9dDy%~{*7rP3kDOL}-}%_S_nCQDDr{#jdo@utdrrj1Pu0gI zXG?3os#>C)U;kj2-K^Tsd3F(VCguj+a(XKhH)rPqYm@E4+cIX_)NZi47%5+4p06C| zxAxqpcfTI&-f+KWLB8v)D;H;N-eX(xsjDvbp3IU??NU9XG?UMjn^yFvo$Nm&o@B?R zy-&Dl?(^zj52B2BwEjN$=mPs{;rH_w%@(&jb=z5g`Kjqo<=;2ouVD_Pkm=RYeRn;{k%b;|!rr@+7WVk_6VPviOI{K@ux_r6Jt>VIC9 zCGPb(DE+r-qc!W?T7$CXigtI{tF1%#>DvGOz33sctoDyN#$G-aV#-^9e z>8CLCYO=;3uiJU){jOyfD74$zQ z@jT`Fk$e7USB4wZZa54w_z!bI;SYbyBaRy^IK diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_restart.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_restart.gb.png index 8999fc17c481cc818569b296fc7d2a26b067109e..0c220dc537142609fd106d63d58d20cd42a1a733 100644 GIT binary patch delta 1558 zcmYL~e>~H99LM*)m95gYN8K^qFxM$cp&zGjX?D^Hp_Dt7Wu?d|i$%%oyHio=80zN7 znttI#wseVpm|ulhqg;^W z&go@`Yb3t`r%hbMLWDLEfYABJP#+zPCpBS+(9g?V(Msne90_&!J|!|x?G>MR;G4dUd9R#N*B@JG9>r>`DZ{Kh z#;&q1UB5=20l$Sa$QnakTsEu+z=e7>40Qd_5NrEHXf0nUqF24xxQ<~u4BlcKpDwq2 z^UQu^1M2!cr{brS`{7ePShOH{4B_k<(GLjR+6kw_A)jiAw2POJGstp}f_AWQS{}}j z$mD>;Y47o@mM;*sUmzaSj#_JHXXaHZn>MsJkV?@2lqq9z6XIco)YlK9s$k&$u9;zw zxUqni9q+pfJ=5D74!b$`0W0f+L@b3W*tsnwa^{(9nYNG@&KW&Br3!xYxJwtS&Uugk zsfsz<$_5Lbs*f5bdWp+YnHdC!n?8+ds=c?+)+6O)NEIoB7%m*qT-=q^x$fj`xWg|O zyNkvNnP3fS_joKXIAwE? zm_F_|i(#I(E9FPfjYOS~E&``m=oXm9$aAaL|6F z09CTYXkSD$MWAAm)X1&P^OVAWDZ8 z;g%-j43uQ{CO=K-54FIF?4Um?o`{S;y$^LEX0}Z~rLtbIkpnq8xOt6egzi?7iJ)9{NdY9%GAJLyfJA1 z4ovPU@D?fGw||f&kvGYvTcdj%%NhYyPV)m&GEVaMWNzFdeSv?E%kMEqO}bs-8S-jU zrnkU2v=wg3mz@HLlMmi9NU$vLx^lx?vqLGX+Z;vW)M0$RqW0VRNO;z}s@lgJpf_<0{P#1y+Io>2%*;B&Fs7nRHj`gk7G8%14l;{2uOgNNn- z#VHgKBz7-b2@?N~47!smn5Fche8mK>=)Ggf8G(;T%0Ex x`Lm9jAZNe{c!?mm4Gk(4&*!5@KrND5mW%Ez!C;SAeu94hgvU-Fw-Q%s!awqnDeM3M delta 1544 zcmYLJdpy%?9A1fEmmO2eEzXL3I;E1Z%Gk7tpTm0y=5*H!M>I@0CT z(5H=rFny5Q)>78Uny@J?YZrIx{G2+U^ZxPv@&56ApZEDb&vOf&3C}jAErdZwI3a|= zbl>{8?>UZ~+XVgdq03hr{ecF`jjNorXsnHvAyUA_x%Dmk7p`ipyVbF@QZzJHHw5@65jy7M1 zo{oa?k8rdDd$L*w4XDn)$^yG=uMX9lC84PL$05+DRmW(K*w;XZMVng>Wjvy4`~s6F zTc$lAZ%)!5*vs%r=oX|ri$7nAkdhWXv1I{(@w8;5L|b1~eM7Ip%c9HmxvEdY?K{2( z9QKnJ>^Wke@8TJHJcy@q>==#hE1wBVkQRij)^r(z0{uX8e%|cs3mT<#;p2R!2srBU zuH>4Cc8~36AA>s`=ixc7oNnr_Aig{CYx1c$0Wo=NBCGR^@%(_=xA*B9$wkfJC5?pe zaMxtgV|#{;0gxFZ_c=P2CN6te+Y{Vz*~xcplo?`c$*3!s4Beg_Jn~C12{A3nuQ@ zJBZ9JLGJ<8y&U{7aaM_`u8jqyC)R*~*vpp~xUN){bA zNeK5V$+$T}$4vfF0WUBJHbNR#f=lQqT_;k^4Q{b>rr1T~kd>FFb~ z&k?B$@AikB+;VRg=$315c0gAUDe|k zc``=i6lysqAo}ws&^lLC>94R)u&5(94iN>Zu%eHoA4*I1 zb`~8W<`jJkL}Zo+Nkb;?GuO4);Aut)5SUO-Zq7v|Zky+?`sFn_=FN5j+!GxpqCXjW zHU85yg|>Qwdm4MwrQMYe*VQKpU%;tLoRHPJ*c<$Xs%>G@-g3;l_qt;(2->3R7S3Ky&N6WZ(?n7d^EGAr zpaAd+DC6*yKi2Nt1Kt^(+c$h)&or7YGr6Vnyy_5rzz`z2a@HNgjA&DE4$ll>BlbQw z6-ABeSO=I&id(6tPGvOMnkm=1BFziEkmey{q>Wg|mlA}cxwfAQENhi~C*R+EIAW5P z4dpr|R-rseBA;Ff8DB$;c+o;t0Fz>P%Q6ezq!>1DLRaLMYb1U%-eEe7^f^z+}3 z3LMqmt)h*kp~gn6`RhyNy}wPS&IUIWsWqA$#W|mroMVieYU6@V{E+72^+#|8FRKC= zjN*nw)*-Z7ZRjb?t7t(Y?E}ijCEsK9(EO)2tIV_?_h)mN10purB_E->E^|8pg`}R_ zfo6)D{ncE-U1Ua{2)}6YC>J@9Xisr&B<&b}Q}Z&ocDH!yf2y|P7#7g#A76K(V0#DT znQdWc1|v=W)AI_$DLTgFOeuZ12~9hXY@EaktG3V{Ai(ZcdL>w*# z&y4r^ulx6=wSQ^U+PRF&?|NKsYS?*F@L;a9-nppkx4-wLJ$rTId+l7?Prsht+LrtJ z(ze|4>-KWb>hJwYT)UO8{qUJHYqqAPJ)8Ob`TF;B|G%~SY+wHG`ttWi^-hiM)vN0n z;$|~=-sSmFU~#AB*x~=*%#1g`|9vK=y*#e^*w@XEKU!q3{r# z@ce!2URs*p^2@)MU;b$^*YCZ#?XO=qx8;V{Yu?^=H`e_A`S^A9HLKqKt}CxyYx<4x zY<>2>PmERjzCZpM{@VB(W2bGZ^t1SQrwUth`GfQGK5>}+U*Nu>)*%R}^#AsswfEPT zS)JSec>T5XH_V@W@1K4CEc%0S<>R{Cf0B(;7(6*Aj1uI8!Ik`-vBpzA&q#a>Ol=IF Lu6{1-oD!M literal 552 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 diff --git a/tests/test_results/SameSuite/apu/channel_2/channel_2_stop_restart.gb.png b/tests/test_results/SameSuite/apu/channel_2/channel_2_stop_restart.gb.png index 005fdf1f3095699cd6fda0a3ed2754a1e265a582..c0bcf5904e91479e417f5fd489c74389b6a462d6 100644 GIT binary patch literal 1514 zcmX|>dsNbA7{_6xxJ*RnrWrb%Ewv`*W-5v|PGxpcr_Q``C@t*h4i3sRjfkna zOz~7=PJx;8mWHU!dyy7i%byGH%0Tgw0=gf$?T`0)&-=XRea`23zVGw=;_vINx6^bd z1On0XId(Vz+)KcftD_CtoEjn>0@14SIqVgbcwbr+n=L^jwHIS}GZ7Y~ukz1bi_36v z8#i{AB7Vp#rI#;spCx|Kp2!V2Zr^T%Pi#D!X+vFAhc&+C1n0;AcEIrq_c%zrj!h|O z*ccM$!j+1i$*^bI0DDV09o`CLL*u{j7}$cE>~TRC1T4^BJ3OQL!JKcik@yVzbmW*T zfv0?abr@5};>?P-V;UYn9GtL9MVjYygzFb^Y;fi|ryo|!21h0xYc|O8b82ZqvQjWA ztqtMZ<-21`xNP!zPmA`R>dm77E!sbsIcR(Ax!- zmmAo85XoV6g?ix5;7HPH7c}eY`T`|9k|&PEZG71U9oE-5^fZ%Rli-~~whXBd>4bP@ z2SG@9M4|;Cp$UT7s8Ke}Vl1xvS3xoWz9 zTZ#udP(GybP|8uSBs52rBY=ayb?tAxe5M%I&EA!x9F`C3XUK*$wf)shZe5xN7aB%V zg7*_8dE;^o@Xcy@PUSAg+(Qt*C$jbh<)xYqpl{EOr+(aOk)*^x$U zn7S{J4k}gb+qFuxiv*Z^lN~M5mg9dJ$YXd`X2Es8r-8SI2T-AP;(Y1E@!>XFZLy#O z#TSDx-lSz#D-O=QgjuUTv|*T!B~)yopf4z%Qf7CoRIc8b!j8{W2>aAI6Z8dmswtSe z<@o=VjLJ>}rV6L&nan8aNCR=WYDmA6Cj1SIP)HF*WZQELV+EDl_|qhd(Yd8CR}t+e zgS?#{Md9^;>`w#3lJxbelhQ7ihEzLo{$?b3bH+Ys%~%XsxK3>$c9*`?3YT?Muewbo zas^2UXP1W})W2f$#rgHUi(yw;UD4ThLAZ5AKoZwX5Y_y~%OTvgq$!&82=<;m0v#Ng zf7k!y=X)NIlt2KNVeXb;_D&-*<__#iZ`n(Zz6{-TqK6`M+ zfYBUlke5717&z(-IkgtWO76*|M=2M;w@-_8wTE=EXhFF~+g#ZD!i@>~2M+kZhL%)j z@*2O2R6%oHFU?aG=E{gk31p*?CoSO5omRjWWn!=;g0ixBil^!xU<+r$Y;Gb|+)Wvq z{OO7~UT@f4Bx_2C*1l4QoS!wfL~rs;rmUOlO;`I5!J7cti!BS2Oy=FKpxQ~=KHznn zI`Az{L>|M5Zmw*!u1#+@Xo}ehwtOg`lx8A1`%HiXi_tE)PycTMOwftl-V{#?{;?M#W+BI2 tYn#$|DJqlf<3&5FnRnpK*nPESP2cob@aStE$`_pB5T7Hyhk1A+;~#MD{h9y( literal 1485 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 PBQbco`njxgN@xNAF~x!T literal 817 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V0!PZ!6KiaBp@2NumXkYGrh za#HkRUP0v7#&7bhj!D6qZC~sBT{3zOOLfh8IiYyo^Gb~~pXU_knabJsJ)ZGj@_1qS zl9J0m4TI+Oehs;zywvY=d&Y{m-um+? zXU+0OazA^2{(Q}}?q}Jag;1kEL5yD4{4h#y^0oRWk1cCHpILf+#e3bSsdA5(Z-33q z>zm&hKKuUfX}{mpTt8THvvkAj2me3jeQ&<^{BvabwS!OBecD>~{J45v@q@b)g~R_` zT{q+I=EBXT1wXr|E`N|w*OTKHX*=n=Ty)zb&PDfj|ITvW-9Baad4J32U!BfeRSoUC ze!H}7@z0Ir#T`{kYCcvZZ;b7q(ykG&tM>j~?dqSm^{wOr)9V6eKF@H;oy%Dh6?<{r z-kp4Hza{$iC)r5p+p|0^yS-j(d1jY;Tjs1XcdySj$Bmy-^Z`s z`+v10p1u9c)ps5**VWhWz4d1YQ_|lrkGH*kAbqx6mS=wbv-bx-O5XhOQBgZj;eOAG zwZ`EEd%qw28Fz5~{-(Y25@Og7Ki|#QwmT+a>(hF>W@CdnjSqQv(i1G04@*j%J5a#Z dHu8kt@xNc`dGA!&g}b1v;OXk;vd$@?2>`2EaktG3V`_hk1(}Bv>!Z zOp6!1#~WYv?f5me#vUvs_PzExZAt%>cweyuwFO#J_8 zOQ-bj{rmA&mHx#4pI?TadY*K^zta0Z)128%LR%vaM7@4wD);SMn3v{dlc_;@-Q}^> zM?ZhAy>7epTEA`f>rdN{73!?r+JD@lul#zw^FFh3nf9_T+E=4Bm&WK#pIsiYb}NwX z_qG4|r)F(^dhg?k^1bzQ4DHQ%4xgQwCegP0^k#B$o7Z8bG~FMO)=cAsJVZM*mV6K~6BK#j@&{_@Rr=Q`CZ&~A=UO<4=t{do1jtbu&8V% z^S9Qw{bw1UUjOv0!R6@lhR@}0^PRQZA@jlurF8aUx zr@!}eU;bEK>wfO|^M=3se%`8S+p=ZfmuflP`frvmyq`7L@t>F#d#)k-_q>zxZ+W(v zzUSF-KxRVt&(PunU%qEu{;7QKFVdQ&MBb@0Kjgh1ONa4 literal 827 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|PUYr;B4q#hkaZ9~P}v5MkR` z9DlL>^7N(lI}QhQWNxu&Jo|3F@Q_L{VVg_PjSyMnXhLPTOGPx`RT{}Q~$Z` zSFZC)d;a>ay2AHG2^L!)q(-jV8uv`?mq>4Y7vH7+hu8M+e*fT4;e_}v$DeL)Ho3U> zocfh(?wg-kKYQE!@Jr6*OG0z!A6_jQeb0I8mT6NSPk;Tb`%sAYoi~-g6Ra*S&nWr# z&F;q62YYK;1-{kBbA7AzFLr3U+kc6D`>fQ68hM`Mb~F5J?!ULQIT2`AFY|Qer^BDV9W2Ou-~2g0 zYl5tJ`sd1&3D%!V?Bbm(ZO^|Bt}U>PzWVk=!_QA%tAAybt*F`iaqp9#%f5Zfo*;eS z{q~7Ev-_L*ztw(dh}qeE`=8V&rbexJfA{p%;vkhRchJIERX-9 z@3Vhi?2hKU7Y&2$tUZM9zOHe~tu@Ksm;CS4z8B#}MjZ83u@zV1Pg=x?ueqza;|6z=7{!Xyi_o4l<{rrQ01~RONM+Whe?UmP3hlmz|wV+Jl>FVdQ&MBb@ E0H_3WJpcdz diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_delay.gb.png index 3d42c450c02b2ed5c9547477c003d259c026bade..3f8ee77d5f11189c08bfffd0dd9c692ba520a3b1 100644 GIT binary patch literal 671 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{Ai&?h~7#spu zz7d~WUtD*sT7s`wYWl%zchYRx{|H2KFssaJ^H7MD)y&F+R5zS-}SZl_O{$}md7L>Uw?0WY;*kkXLH&&{{4FM$KLll>i$Rf z8RiwgkDuRrU;Ensitl=lYb8EJ-g_nA@ZPs!i5#27^O_yU5AXkGc1+^+u0F%Qhi{Y5 z@A&_FPwlxmpUs}<-1)Wm^i!j4xw~VhpMHAymHA*F^j;}ix@&IzLgIbm?ce>F$u Vwh70%Re=eQ!PC{xWt~$(69E3T6CeNp literal 568 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|VoKPZ!6KiaBp@I(FSQU~mY` zej!?G@q5#&L#h>T^rAdwJo$X@)Wj(>XZW|cPP2TzE%)@vZMntg)cfwI_pkizk?=P; zCHDI9>g%O{U!SgTe~DWM4fZPE!( diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_extra_length_clocking-cgb0.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_extra_length_clocking-cgb0.gb.png index a486d6c0dd5dd5989eb6b1ea0c6396e173b29ead..284dd155d280e3e6ebb31eee194cf74d0b5581a1 100644 GIT binary patch literal 1015 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-> z_v&u4*c5sG_@0n;tSthwxMvnG@nZhw8(6(jsM~Ml)@zxwvNWF_zi#6D_1*U4?|)e? zopSS|YV{}Y;_Jtr@9Y0_uBLj?{159MfBQ2jbJi=1K7Q^WIs5)I>i#V_UifEU=CwM; zPv@VuM`g>lEu6A{eZaFXkKN_B-%o!lm9=*EGn>i#<4^ysy7f40cCCqfUG=~HH*Y%D zDtc)?E!#b{Q0D%m`P$Dd`hc91|DFB`X(v?Io#)yy?fxdFZO^~2Vfb|V=lY%EQf-MJ zXD``uearJ(ac8eb?eE@Q!hFJh{(r5dQ!;0HY1-F&elLD6alh(gbv?uSXYa4?-F^V5 zapAj_pV=*Md;MSkQ|syb*!+q25Qoyo6Qn)b7tmP)(+tNQ8vhIwA4y!XGYH8t`da5@6^pL1v>lD?}li*)@{kr&rZav*Pr;@@b%!OHM z&(F{FH}l`P7n;3#?Vqimrr%(<`D{1sPxj9rb`NfbMcvc>H($8*xBrdke_DLgG!z24 nJf<)SEp2eo9Ay#;hb!`OojYB>&G!)lW@rXaS3j3^P6b*0|T>%r;B4q#hkaZE{ZKukYL-o zdHsvSFHdh0pZ9dbpOla=t8+1uHC+}ngm^WVR?cg0s+Wj$>@&;Q`5%N^3~*k(O- zexUX9)uh@a>*-4l*qpy?V!GPu^G0RW%O-0duc>U*o0xy<$E*i6Ommx(>vkW0s%IP_jr%*l!w*kuMgL}@z|U# z9o{~7f9S$Ona{PKS&NG2_S((XXFp>4d3&P7we9z7-hMj$A@1qz^vm}f(?379Z`;S% zc&2}@^WzOQpMO7_vV{M9^Xax#>{*fbYz#kJKl$9gDe3sz8v!RdpG{0ZAD;AR!H*RW zN`6#6x%v5P^cQQJnv<*A{Lb5)|Fiq2{Jn!`XZ)=FY(J0v`Na!wnt#fEdfA0F7n)W~B^e-`Wuj|-c6JnPwN^{QoB{*C8qcuYxg{RAG(b|5ve3bFq8bo!4=7&JlKveg_Tr-+fp#eIECb)B88c?RoeA&|%Z} zo8%6DeW3s3_>@agvhFUCa>ln+&)!LBCD)KB3P65v6y`S(hI^ zuY4Y))gmjd(Dp~iPw{sT=1qF_z&ZPfY4Wr0XMqNtU;h05qW7}bzdm4o7R%pO{7c>{ rWw!1AP)&B1g9Rcy?xO@!7(Cavm}IT1<0QTel(jrv{an^LB{Ts5KC_r} diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_extra_length_clocking-cgbB.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_extra_length_clocking-cgbB.gb.png index 6f909c62fed8dd413243fefcfe1779a2c993232f..1db7e34b7156ff1901b53c14ff46b5b67fc6af69 100644 GIT binary patch literal 970 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-mFv-C(=_Io}lf{C|tTH{Vj5?^x|yz0UXF zoS*$cUXsT@uJ^pWbG}6Vvbws+U%QH{$`}0k`f2;FugecM+Iju_Gr?l5-{seJ`|Evw zz595w=3LFn`fnE#{P&rEzxdLcK#iQ{#^fcjp_9F&-wfLE4EGj zcUNW;zr}px@@KUNmhzuHf9!Vgr}a-y*K0qxZg+0pGJLjiQuGg(U!F6NycJ=)wyl;Qn0>h&6 z^Ebw)i+?(QV|?B^S3bU0KH%QxhCe|-2i%zbJEP`h?UV0M@7Ku})ZKks_}l9B=aTUA zzz|8OetY@HB(vW+eSd!aQ9RFl?biR*GlFdRHU6JH&;0G#+mrgS&S-wM<^NH%Z|`dP zwckG7{`8G8e8&H%`%wv%=b6jq<}R%_U;g`iXWgyY_v;JoKdpbXz@4!($YGJl1PxXd guTdt!aQMd>EVH|d|67naFpn~Ly85}Sb4q9e04p%UN&o-= literal 872 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|T?Zr;B4q#hkaZq9-j;5MkYz zwC%;ClFet@FS0OaT)dX7a`w-rj}c9s{n8~JhI*%kjHab_8t&UztNh3NqMY`b{i^a^ z%lvbePun&9^rkbP_n0$$UjKZ##A6fR=wL(5Pv63~U0!eMzp*qSfBH}H&-I7IZ?0*V z|M+@W-sQ7@o`3rPna@vmuJM&WoqrbF>74D>pWt`BGU)UEv-VCLx3A~lnr_#2|LQ*X zk9$9C`TorRiS+k<3p$#wA1qyP^PbEP-A_kVe;+B!>J(jnz4EI=(X+~X&muoF-Br3j z<)i7rmCSRSUjO;n@Y%UaPe4Du&UOEx%l&I!w!b|;&+2{n&qKd#&cEJu&-VVF+n)}{ z-9MMVFYWZbo7JDbI?Qs;j+<-!emnc6yBHar11Ih^@I0o?)98dZrQNz z^^}QmSE}FsT=!=?-zUY{@kbl0^;^%?{58tkW`6%;`HA@}n?I-L*Phy&XIfqP_v@95 zpPz?Mo^)vW&n??4yDHv-1k$fHXP=$B#Cco1M3Qakmp?PDcig)@Q{T^UZ}Q&De+uQ| z*k{`Zvp=7#aDQKvY>pkntAt7?o2~n1mmTG~-n@Q>zFy?{Z%bc2s8Xi(3A z%De5d^y?LLN*4qd%(a&*sPj0_`snHTHSE`CnaA+&OQ`!{WugDAJ4#7DDmLwo3jg}% zZuZ~2pPyJ+)F1lp!;u1%|1tagY(dGm4Kkn4{a-bOdr^V~SKH!I0x1kWi%&Xex33^S RDhZT>JYD@<);T3K0RT!2o^1dC diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_first_sample.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_first_sample.gb.png index f2ca901cf18a6578bf2960124fa5b04e8564b2c8..4e03aa5746b589ed920b3b7f5a1413c42f9f03ff 100644 GIT binary patch literal 600 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V`d$GpW3A`S=N zWvt^Uf4s%En{sjn|@%7p^fp_SB*;dG5a7zc!aXpOs$x z`+DlW+}lsH>)@@&AwRaf$6) zzdt|!?0eVWdb>NRH9XAwPDlS`{Bf7X<5glq@wxW%6+g1_lY0tfj!Qh2x@Y;j^Y#CA z*4NKi=4a14`*#1W@3m{T<{jVne*U@t?SG3aA6I0q|F@*-huE3d6<`1J>nko{@$hOG eC8!n#|Cp}5X;^Bx=N>4b*0|VnxPZ!6KiaBquIp#GRh&VXL zeC?9yyS$5gRfp4bM_qqo?dOkGBK)0niqGZVp4Oau``MiQIq~b?Op=fS?83{1OVhy(C7dF diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_freq_change_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_freq_change_delay.gb.png index 6f0152dd6f41239ffdaf40da7e4e1b0d21341db1..f0b6a956039c387850d3791504cf33cd1d9d261e 100644 GIT binary patch literal 705 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{AKtCl%5r>P{ z)3)7sv-W1r`S#0fAtzki*9)KX{P7^rwIl9DK;pOB``dGGr$2kOE%$cak5|X@*IHk@ zGwb&K_xtCpe_i#p=Jl?7bI+gI_vZIL{nJLq#^=wQf4=*j|MaGqvwgp}KU;tE|KH#J z|DT@Ov!=H8|FxR5XV+(k8|EKwSpO+xKZD$C2G70H4>sw9U(flWcw#Ty6n3fpI!SC|7QQ3_b*0|OJgr;B4q#hkY{1O0A0h&Ws< zysBGO829$e;i*$^HBQsw_*r!B`Uj)H1LAJmB#O`F-agixd;8fO{Wc-+$NoJ#AMyX+l2prmcdlPQS&{Jn^55UBch|qotex9q zSl4Gi*KX?W-yg5uXPEE(U`O$T)X2W#IZZG1eue$+Kgs@X5&QR#4?ll>SAX#M6Z!hZ z`|tjHEM*(F{`$K9lRyLh9RK&2ec!tKRbQjuewUH?e(Ly=zZ|yj4*RQ{#Xo*o_^RXF zo9{9)=679}f4~3F@FVdQ&MBb@0EgZOhyVZp diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_restart_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_restart_delay.gb.png index 259d9f5ae1129bcd939ef163ab4e68056aa13ee1..c4ee58a79b7a58b437a5a612e57ce764aaabc526 100644 GIT binary patch literal 565 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-9&ED@(+2_wp-+Jwq`TffOpYK)9`@Q+I zjr_a+JJ0OD_h;kxd&djUoH=u^IxTHpW$o`jFMh?}H~zotv;DtcQ-8{G)okzo#sA?R zi^r?HhU0~IYL6fO|IN^N^R-zs*FU`bZC>I3XS>$jto|Q$z0~%O`Tt*^kN5e@%-iz* w?K{mMGw1BMKiio@lW~%e!YDzlFjzVNsqrq~OHr@8fysfv)78&qol`;+09$>z#{d8T literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|VnqPZ!6KiaBqud1oCl5MekN zI79nYfz{eg9La5e!pz#1WuRKI!l+P&W+Umt%xr+EJv%lg>L^nY`H zE0~ wg7v4Fi}k0kv1okE(kE=;_h6JkL?HZT`629bQfO!RHc;Goy85}Sb4q9e09Z!NU;qFB diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_restart_during_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_restart_during_delay.gb.png index 9a1241f816ea9ff8e709856cbc6e6c7035c67b4f..02ebf2603415a445b0160363f813ce72a8a398d7 100644 GIT binary patch literal 1261 zcmeH{-A`Hv0L3qzTCMFMT3x%;uPo`hty?>dsbK}y&Q+~dJE^Tm)T#?E>cq+n%JqUZ z*u+{(O*@^NfDcpS+=W_2@e6h9YK*i5rk4uTk0D-_sY41_E?4FsvBxFnoZrKFI}fM+ zYHGrfL+>5}0N_YcVto2O+xPvz-)}!fikme6;M1QJf8knX+omb6d?WH$-LmLK_K(a& z=bhwl-kHYfC*mU?kVJ^9^;Tz)3Ru@(D+NCml15#V>aFkvj3kCeku%P21>L*n_(Vu* zsB@^B|3W+xD{-jKPa4~59IM^!X^7r_9RiP^yLInyCu-)iM_w;=RI}cOU|V8-Z`EM87d}jLz&H%M}R}kWdnmn;YG=W;{jKD za?>Dk>+7&n!ZOTn)=+rx@wqZ4+VGb+O67Ll$@?1b;DgUh!4n2D(<*&J%(Uw1f>o;F zI+(IO%F{e_Zg)4*3UH6-aN{C~53G)4EXMFPdX}I%;<2;#7lkx7=X|J$-RQ+}N<~h` zP+QfOj@)BSV~4C4tjG;J1vV{RIuJJIt5MdWtb0bb{dDHam>^CxZ{{=3O9owPT3BDK7ujWQ#>f_z9bN2t z?V6o|)ijU3LfLkOv)a_;td^~lci!kFC~5$W&#|g)B2-Q#?=85O9W4i=u}1-pHx%}U8*-1HbXYE1pe|qVw^d|WS4!9v=}ZuyKH1_eSuI( zid7y$U28Q9Jk%wvr3dwHtq`6TnrZLX9wi9>*MG9Wtl(~?#(L`ac5wg3fTS-|<7F3b G*8U4Ocu6e) literal 1092 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|N`Ur;B4q#hkaZ6DKWJ5O7P( z>Yt`PWA{YmCzIaruhw9@#b+^VX3f6u-WzkJ=5Ly?mecb2l%N$JnosBO=e%FPZu&2= zNBsT$md_=UITWAEI9WWdP(2pmcm44`)ewPtk3aiA%vIyAv5Max%P@z#>1ZbFaf$2o zc8)D)w4$u`#m;V&3jf{YeR`A5(|f6rXQs{a@6}IUcf9^hVP&yW54 zqT<`ZM>0Eoqn01p#Fw9z^F#K`%PaGX()<1A7NtM_-PrED{K$T>^L7z)&uIPH9Cmc_ z$LY7(wkeZ;HPy#- z=N!9p{JU&xv6$@BLJP@1f3hb%+glU;ck{=zt!{sNXG}kI=KIr}gXa|3i~H_mtG)Ep zTzmhre~YE*jF0E6zb{%W+vFbgYg5|t1(649&vZQ4`n}XID*pd;*{Q2H2Y=bv^gHYA zuls5hWeo2HbFMvR(LWs&(|7%TfBBM62mhRN{4u5WgWb)|md;d)UZ4NG`o-FLb>*UW{q28;T|8L(>tDyVSC;vrxna@U=j`ME*Zle5(jQ!kHgf$D zA1iFGWkWqPhaz|yZn`5J@bqFmz#N?eLrp; zTmNp^`{~Dje>=FescPHH=wFBCOnYEg{&~l~!kV;o>z7SgCU$%C&*P8VU!A|U+(2pf z{?k3{o3G2Jd`>jg-OQXPGK=}9P>jay8Ou^vf8VuRw{FsX$@eAyZ1gKuAB|6$dH!f+ zP+fdl#61C-ef!zd;?ojqeT3gH`P!cOOdhE2Z`!VXvp*`$dVJ}rr+tZq-q~p{*;BTD z`50~a{ptOzkH3vR@6VU7*?srj_v)UHb^Gt^8wkeZ#*3}p<{`$Q9 zZFBjai~9CwcWvB%*C)cS{Qc(gHH*H#eawII|Ht1CZvI-oO@IHL`XBMU|9<$$uyi*k v6bk6@H63-_V8J2Ae(;e(#Hb)5K%U#%RmUDxwp#oiR62ON`njxgN@xNA@E{T} diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_restart_stop_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_restart_stop_delay.gb.png index 3eeb53263c5d92a60143a7b5715e3ba941f08213..87ed4935413b12719ac278bb478d8187cdf2b7bc 100644 GIT binary patch literal 600 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{|z^vO2A`TbL z7e;USzU-=>eV5OiBMTEAMZd6Iz;An&qfuXM*52=SeaYv~+%1$jZuj@gSNGTFO#7dG z`~Lg>dHw09@BY=BetP@onK!fF@4X&nZ2b9oo$-1*`?Xu&r9J<-_^11~{dNC;MxQ&A z`}X)}_s=tD#?POZWY^AU|8#8~!@qncm9MD{*=u)~oBf%xedf%^7HQAy_7s2Xdj0`s+7)^N)Y6`demaym^~G-@FfRW`8=pKH*37`G564ITTeLf|yiB e32KGGS80aA%&9ZJA7lll7zR&QKbLh*2~7Zkro)5) literal 513 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Vm;PZ!6KiaBquIc6O;5OHu^ z`K8Nlj{j=C7#}HiuLTRA7;X;Qmn!q;K*pM_-)iN}ztzTP|9$wU>g$e@xi|j5{#U#y z_jcv`ZMppF$vr!-%_{CQ?3*3G@n7AgInU20*Us&c{$_ute$S1^ckiuTKiTlu^B*tY zt=zM_|NlScJ<|>pes6p}=Xv>@rl%r*!+xJXDZKo}!QU0%erpxXaSoevppfY}r;K{R eD1(SVsAb$;6Z6ZpIcGB{YCT>3T-G@yGywo(7TMwe diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_shift_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_shift_delay.gb.png index 259d9f5ae1129bcd939ef163ab4e68056aa13ee1..c4ee58a79b7a58b437a5a612e57ce764aaabc526 100644 GIT binary patch literal 565 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-9&ED@(+2_wp-+Jwq`TffOpYK)9`@Q+I zjr_a+JJ0OD_h;kxd&djUoH=u^IxTHpW$o`jFMh?}H~zotv;DtcQ-8{G)okzo#sA?R zi^r?HhU0~IYL6fO|IN^N^R-zs*FU`bZC>I3XS>$jto|Q$z0~%O`Tt*^kN5e@%-iz* w?K{mMGw1BMKiio@lW~%e!YDzlFjzVNsqrq~OHr@8fysfv)78&qol`;+09$>z#{d8T literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|VnqPZ!6KiaBqud1oCl5MekN zI79nYfz{eg9La5e!pz#1WuRKI!l+P&W+Umt%xr+EJv%lg>L^nY`H zE0~ wg7v4Fi}k0kv1okE(kE=;_h6JkL?HZT`629bQfO!RHc;Goy85}Sb4q9e09Z!NU;qFB diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_shift_skip_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_shift_skip_delay.gb.png index f2ca901cf18a6578bf2960124fa5b04e8564b2c8..4e03aa5746b589ed920b3b7f5a1413c42f9f03ff 100644 GIT binary patch literal 600 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V`d$GpW3A`S=N zWvt^Uf4s%En{sjn|@%7p^fp_SB*;dG5a7zc!aXpOs$x z`+DlW+}lsH>)@@&AwRaf$6) zzdt|!?0eVWdb>NRH9XAwPDlS`{Bf7X<5glq@wxW%6+g1_lY0tfj!Qh2x@Y;j^Y#CA z*4NKi=4a14`*#1W@3m{T<{jVne*U@t?SG3aA6I0q|F@*-huE3d6<`1J>nko{@$hOG eC8!n#|Cp}5X;^Bx=N>4b*0|VnxPZ!6KiaBquIp#GRh&VXL zeC?9yyS$5gRfp4bM_qqo?dOkGBK)0niqGZVp4Oau``MiQIq~b?Op=fS?83{1OVhy(C7dF diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_stop_delay.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_stop_delay.gb.png index 2de2506731240d73107cf0cdbfae60205b01fb5a..d315c994644e4d95e462c8c7ee4e62e5f933574d 100644 GIT binary patch literal 546 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-+qKn?~h(~)ApR=rfZ){wC{oe1GxW9jH-ZB0B=FY$0@7EWf zi_AWI=8R=}TH3!~|2AFQWxe~|{JH;A{{Q`EFISf;ceo*Z=hga#|Go`N>Uay*e*HR+ zZGFk?nK!G?pQ)|5ely{{P?7nnHn3d>&p6OISt;YKDOwqkVKV VN6(Lb*0|VnSPZ!6KiaBquZOl4iAj06N z`Q(3f{af!u4)NVz3sYvUOnI5e6MZ5(t?zM!e&6F6GugktU;g}J?eRa4KUb%HyO+Io zW@Pr>bP0l+XkK_sQ(Z7{@j9a!8%0<2I!sYIW4sW?tqo2K;nt%WCT8Iyk}0bh;@u(%JEXTryUv zdFeFMZCusJzC(6ZRNOhTc&C9Wip)nmlTx5bR% zo`6DXcLasElo3iIRg8&a&xD9~Y{u}*rq|E(DHXXbKgRW)uuCmMee)v+|CNK|rH`C5 zIFXb%6{1eC>N9IefAqx8L zZpWPdg}O>C#tSW#D-EJ4hM%4GgN)XmrsNR;h@kmqH#@$#F_&P?zCnP}bdp*9mNv;N zXJcE7EgKe--T@{nM}u3RY=lvGjhdM|ve@ey<1XU4+`yX=t8IL?5XG3fuf^J!W`4Y6 zm2^H`orj@d7Sk%1Pv%hOOniL~%ix3qL^}!s#eivfVPTXx~@R~}+EU|_o z%0NU8Y!003i10g4pCV#mC=dbLB*@yYU#j2X7>!G6{+UsCnbrS;v2*1lqu~7>$}Qwvn*y(@F;!DpTT3HB z2pYhJj)HO@3IN572CqMlAY{A!)z*o~jN#5b*hjiq+Xf<*C&wJHl zX5x4?U6ihg5*y^1T+$GI1iDV!3^P?hTInTgSQLx|e&E}&Sp_E^iO{(r`F3fIg_scP z7y=kK+lvWDC9{CvU3FnFM_F30&vkY0DT}Dxt@BFCOH+xZ+JbIh3QYFD- zWZ!k4gyl~x>d1oH;~n&przRZ3fkqsr2C>#Ay7|7d97!SOcj+Dm$DvOHE&LmqIvcsi z#7dcN)6*Mu!m?wQf29US$_CW;^J~EEj^jT&fc%o;w@)E6FEQ( cUnEu^{Ii%WW!_be^C!BbrlckJoyxEK2Xpe04FCWD literal 1254 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|U!iPZ!6KiaBp*2Toh9AmCDZ z?)D1JA^yAl^%cklycUL^m6^}$#Cc~Ld9JjamHs#)S;xNDV`r6{mU#As~ zwWg{J*vKZT$DV--WN1r%cd2wNXv;b;YFJ+jP43Ox^T# zOLy+=KI!SN1Me&E-*;ud-tB*HUr+zl`P8z-;C%6=zm0452VFb!*?<2|zsC<28~xLq zJxOoU=~J(t|N8X0boJZ#T~|$S?O%R8X7$4V=C#w3Lkb%wG5bw9z3I*Gcl$r>d;f8h z?w830(&EmC>(#$lH-9}+damJ;WT$QO{w@2DT#F5fF{^C;SW@`q(VNvF@xCwr=zUFo zv47cpR`ou!b@t^~k6-&aeTine6=y>1^&OoN*G(_JmTkYAyfQB8(~s+Ux&L>S-|i2t z-*m#p`(^j^f4TdXW#0N;D|Te<+1Rh_yE6ZIKRQ#{*K^`t|LfPYw5#5har}R&w%XP5 z-hx-YUO%eiX5GsT`tr3j{`;%lU+2qBu8RK1_vOz9P1#m=dDGXss_r#cEB@l+ihQqm zTR!yFvLkLvm(Blf3H`VD+xwiaFG?rBjn_Z1?f>QeB3^sHzt7Jd44-BZyEwO6Y-7x7 z_xgf8+iUCVpPTH}y*S^RJ^taBIO!>T2iMo{jdKmJoA+Vma?f3vM)qsoKgsObRvz{4 zn*I5M=9lOG4=`0u4t{59x^iyF%bgo0OJ2BDUtBBGEYlx5&D`nUrr^CHYENUbC&qo7 zH>G&3>#uA7X21SAcN4RBRnh_RzuT`Z-<`p4m3B$jlyP#S#A6wsSDa6Gzqs7})OBO*N+>X_;@E`TH6-a^wkTeD_==2+a?8cdi3k; zed2E~PVn3D<@bX-KegOLtnT0N`ua)WlGFWL_1v|!2bR9PWtVqxx}NS*kn$JW=MRd$ zoaDaZXKg_Z>ydQ*ZFcQ{t8c#kwSE8hy({wH{ui?ax#M5)-UG!OR?6S4|9qcayjEs@ zw&@qgH!718f7`Dy|FZb^b4!Ui-tn`2Skbzf9G9##={K<6AwHvNGOmnu;7u9VdLRrW@~3`9-+eL Z>L*G5pKxP&GN>eD@O1TaS?83{1OVBIXgmM_ diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_wave_ram_dac_on_rw.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_wave_ram_dac_on_rw.gb.png index a84ad439131ee5fbcc1d076dbc599350ce86f327..1263c3b37b6c9f8a96b2d8c03020a930ab37e5b2 100644 GIT binary patch literal 1731 zcmeHIYf};k6xDUYrm1zU&E8_`I=-dym0N-}Dp{-KBVQ=kq|s=_x`Y}JVVt(jS86G= zY2ZetN#JHGX@ZY3HB8o2P#MrskyO+{5#+t>e%X)v2lm6gckaxYGjq?GGq>RBLw4UR3 zgP|KTq2}orlh~&bZ=|--z(v4CL_QV{69mb}4o-|@FgYJ-h%2rhPX((aG+_{%L|NFM zj3Y`Y?at5FWd4r>n^Myakv45U1c1%`DX8m-DM9e8rlbeY50!#_XTAB&e&TUm(}|ge z{9l9l_%$d(}2V%I{H$fR~l)e2bq?caFlYWxfBf&BvF_bG}wNgUoozSknO*>6wAW^SXeM zUEhp0I}^hVP08B?iG8U)RFzKmm@UfE84QP)G((UFYt9;A5$Nm4BUIrgoDcOmo16h# zOLfMvIwCy<0~2`B>gHq?2W!C6{-!w!I9$b&dO%%&QcwTlNVGX!V2x4(3(c4GWHcJ> zPLjky9JMqAhKm^OV7tp}gxE;Yaw~JXI#`dR@?E_7yM-C^2E5vuFA-+$D}+5nUWOxk zd^KlQ&b}LkYQ;*9D&F7_j8a>l8LA|9cSJ^lcpNCUJ*5L@Y_C+5ky>f&;i zYy^_1=o4kL)*B?WEh+OUFP!=02lMNGn8em=Otjdi;a$XUGTwMArH?MqSU4tg1A-@D z_I6gCPE3{JB4zU{lFCbR5@pLBP*aLqKQ^7MwBy({&`uBKUN_JyW0FPwb*j<4u;MY% zT^65_SDmgM*30$#6!+HVE{{}`@oDf}|h ziPNg5!ahv!E{xEip4()oY<|qh(6-IuG%y>2P_M=($j)Cu2`BtD5Wad7Iu6pMvv9?Bo(F zz<0f2b3lMK`D5AM+`uNzaMwJcyP{AK6@YAk24==-rYLHukdhk=YGROFf2G?cimG6K z(yZL~T5>!SSt{M96JoEY+x%?SXfNGq=0RPTOn>zTLS!=9tsDp8uEs)S%LAeW+w| VRv(l=wLB-Qh_I+o_Sv+8zW^sSXXyX{ literal 1480 zcmd^9YgZBm07YksW|5&`q_|>gx_s5CnFd(%QD=#%rMNOZIn#8eXp|3-He1cdG;`Bb z#790tQVca8BY~5fQw+pMG;~6lA{e3&qVjO=>}T}h-h0lyU+#x{Zr*ux;7)U>IRF6I zdG?H7=$6)Q;Q`Qiiva?S007uleAe&Og$$CsD(dR&=eu*UiUn95A}lR(^@o3)IUX;I zz_T5u;K^Om5c$K;E%Wz*%-RcYPnjv;v~!SY`P+%z!iM+^x_>vlzUNa)-5a4W?g31R%{D9=Y-ey8BT4DikH z8fP`o=aIdO^QMPGoAAU#h+KQ+<2<+Tjw{nFW5I#KC5Y^toCz2ezcam|p?7xNHnG6- z#*`y`epnAr-WOyzmn=7NkY5_=#cxsvu+Zj0`+y>zYTe=hoV6v-F_x>Kl-xTrSHk_GTR|ult0ADms4Rw+-RA(Eo^p|z1{#GI9bDU4fD>c zSy-HzXsm{>HyFT=-6oxL>S59iovzcCN|uYRGgGfAm1bq2HEA+I2DFRFd%V7;AeGg; z>QvFQ2L9H(=y|hu5GqP@R4&dq1_96-;`+03uCvmEJ&>>a?4tv`l;3j&v^X zE9$KrV_(n8FrA-%%;9iX>?B+bDeAhy$zy>2j390Jh1X19R4L=J*h{!H+&s0zr>32{ z80qGo#1$yITTS_sc=BOkxZ*sr=0!q8Hmxnbmw^mLwqI?^VTEIJ=oNxENP;U1GTHHM zKfZDTE;)niXRN&o@(ENGB!e*e1h zIWWdE3>8E5LJjHoI+GaAN-)3t0uO(bcu<^Z5Xvf2=ItJYXG52@5n8R%OT!+CP<1mw zP0;)uoAtB&XDCcS`x3O^O-a^wwu6+{rFc0;jX~qy?iocF?$~tvhFBh|ztz}x`Z|Y4 z|5yTTby}5!xK1wp)uTnI*sgp04GFDYKZ0e2UjwEZT$0SVAHWV5oyMvL)b62aG6d6- zbKfPacnQ?Dy>dN-RVD&?wT_#TM!*`=`<0zE5Py2*I;_4z&+h9!>Q1~Nk%P(#dLAL1 zOWBQujHIh&(^x3G=Skse`U{!m0ty)+2R)wwQz>h{@5eabyD>6$N8*%}DlRsPj=}`b zN^pu%MSfhqtU=kV`ruF;BnU$oB@R*~zefMG%NlHy13_ff5Y$-_RLQC~H&Dbs(*OTb zGwYZgrveT&QN4S6^|TgMcP)edrEtTS!>EqQQm&A-x!W)^&q)Sz;s_?Ugx5NSsOSdt z&l<#yMi57hY48MX=no;k&Dd>ZLtE=jA~!LC&E4_r`e-`JD;m8PE!@}Yk;p*J4# znBtbKz3Jn6HVwd-C!``Rmkr`~Hph3YeikBK)v#}u_uDCt4Hw*Dt7Wg^Ckp&o;)5}% smL5Goo69B^ZpPaoM!8$zCu$4qN#iEFbSB#*|2_0sf3#oQ>6jn?1zpkBg8%>k diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_wave_ram_locked_write.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_wave_ram_locked_write.gb.png index 7310a68b8dcd0e72c7f779250a07dd1468b55cbd..1c8338256444206264f8fd1afe26e1a04b3f1e8b 100644 GIT binary patch literal 3248 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 diff --git a/tests/test_results/SameSuite/apu/channel_3/channel_3_wave_ram_sync.gb.png b/tests/test_results/SameSuite/apu/channel_3/channel_3_wave_ram_sync.gb.png index cfbb95cf6bc6b70f53af95486c457ea311e59800..0e22fcadb3b3bc8b4960de55bc9dd94cccc83e90 100644 GIT binary patch literal 982 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-M{TmXv^$5cwlU;Q#=Pdm%Pfp6A&Amd&=_plpq(EKh-wM^Y+FqnIe{)y4O5Td7J+8 zpmWQ&-jiOx_wl#-x;LtIZHl(1*lXFp+~WyYk=CHO^jY?vFSqTKl$K?7b);6LzLDI1 z{`pi(&84sB-21UQ*S;_L$(;44E&5hJ&Xb?G>AeNt$ElBI^mlZ8{<&wzp@-~ax+6Z?F=@$c*z5j&f{{gYZ;e%0>vb%n3B8lPW%UUNPF?*Drg*}t#-y7lq< zyUq9Bz4-ZfKJ&gq#&4~ye?7PV_5CpOmFmyOIh-UH1h8pLVdP3}7-dp79InLQSh#HN U!4H8yfccfd)78&qol`;+0AXy&Jpcdz literal 810 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V1XPZ!6KiaBp@UMyT}z`$_v zh1$}KOnC=QFEZ%`{Y>yX?4cmQT)5}WZzUr!qwEc}-$j#U+8$=7Nwi5k?tJ`o@nz?y zC-mRUcl))^|NPtEb%iPKg1`H(ul)Dx{9Qlgn`M@txPLDf4#`_@`|ING`tW&b4fXHi z8rG#I?64`|P;B`yZRrc4i}@Gle_gwy@PEPf{Lt;Y?PF_Mm)l3*Uzpi`is$J$PqR&C zm6o?}S^qomOFaFw+q3L>ehJ^6r<|9~_}TID{m;+-cj9ac?tHY?-`jAC=O*{bbDyGC zoyxiFD4xA_U47xUq9tc6>w~A=Ui;7l! z9}#b^S-y^2AO0g>YUaCq#g?tRGkOfIEuVS>o!e$vui0{SzGd}w`TwuBzxdQ!^X~nL zpNh-eA7A^stSIs7{Y`~``!+p)`Pnx5di~G$4{rZ`mvg1+U-bFsZ~rZPocHHEn+5Y> vNr`g@3fS6=4dygHEaktG3V{whk3INBv=E2 z-%3`Rf7*1f|D5Q;9kD@&)=n;7;&J$CnDDNqk0&pBt=+13I>=iye12+V*5?=Vzn{x~ z{^i=!8C@TmuG5CKmGLa68Ham%Hyn;Z~w>h^Xo60^WppR=RMcIzJ0#p=VuK!Yj%sht$HK- z{n~c7Gqah6N>52VtB-f8u-)DNz+b(RrJBWFBcIP>isb|SQ|CX&WUZB-|Lxn2==!!j zmI*gj+h_94WX?N((}?}e^XuhpZ|4?9P6L@N`1$F5*$w;RyUVxB<(tdo)lQFJ{~l-u z(AV<6#O~zO_is=58TW63WkT-u;2jhHHn_|LT75#MAo|AJjg|{)^dVM00J^v1H{)4G z_VfAcf8YC9{#+I4#&S!; zspD(;W;1Kaf49it+wt%7wgb-^KJDFOsSxU&H=U-M;zH&N3d(tG#3+U3{RRt~Onw(Eh$Z z(Dk1#f=u1by65`6ZuXj|7c3wApZ8u+=YAjmOy+x4b|(Mk3;fKuCo@5#_yEw!r6Aw? zpWmJxd1}UN!844VR)4Z*uD$tvPs@j@Gr(Z!|Hom*u5wD|L+7V&%tgB{&bMjLb9+#; u_`dz0^i~&5g+MNkDNI638-^3}N_b*0|T?Ir;B4q#hkZuVv8Ot2(T$` z4d3!UEp}RMK)@AN#Iuv@R$Pu^y~tod%y#oZadADGXn zwf*g-se5{o^t9B-=ku=KUimFb|I^(!R;FQ0&la!Mm>s_07t40-ORo#77k-;xGj07; zpdn}c&%eL#8s3`!xpZ5dMd9@9f2DQ)@-h3}RP5%lAKu8nEO^`Zt^E3*ln zwx`xW=J$h>KcjZWt^ZoQ{`%{~UZ))^K_cI#zC3n5jsNUzcK>tF6PEiM|4umH%)IG2 zr(C-I8TX1qedpZkn_hob7wD=r`1R+8U4_xbYx`|$KlJUhY<(Hrf6hHR@R#p3U{J~= z3xB!(sk%<@R_I@sKQDF^)cB}M{btSnF7oD0^VVu9pnj`-d7t#-!h5#Lz0$7A-WS%i z$9St{{QHG_=kI(R_3~J}u-Z?XCH#|Sc_|fKvuN}Mf{kyZa1AXAO68j$?||}?r>mdKI;Vst0Dhmxk^lez diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_delay.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_delay.gb.png index e2236b163195a1d1e9883394c4b755891f4fef7d..62eb513118ef8660e6c55228be9c418ee43afb87 100644 GIT binary patch literal 856 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{=hk3UQB-#RZ z-_lk4E|z!g_eM5B^M%q&_M}+4J4MCRhlbm-BwoA}m3`S{YtX4jhQ7hG|9-i?{oC2< zZP(6jKl;mnr~AD*&*8gY|4p2+e(lz0CC2X|OJu4FZAy>|6_#f{tUnoE5yhj>M{nXljb z==JvB&uq6|dp&P$>1Xf97SpcX`fAws`0m&88SBql_c>et(!L5*AEP(@sPUR>QF_x) zmtOX-ug$){Cq4V_pG!c8S)VoFDZhR{@t);_gU{zO9}cN&$|t(d zzyDNbL+!n&hw(pc6avpNcHRQ=`M2%2J7xJm@chL-yZT?n4&}erT%ON-&(8R_^~7IYEO_NY!Bxi^mj(P9cR+K}3LD$v>m_e^1TnBl5r;!{F)a=d#Wzp$P!r C+j#;2 literal 728 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V21PZ!6KiaBp@2IjRWFfat( z_|hfkr|)f_!J)l6bg}62&--*P=f9&Z1>t$Z;PwA`m>%Tt!#UHC485QrAcKq#$#;;%VjjZEl{f&QZf9!_P z?!W7ner4NN_;+G$!R*MppK1-}{7%@l<-g{y$L(v@{YWL&S*RM0r^-WLP9aaA)H|Tfrg#5`>)z(|e|IYlKaG$;W z#R<_n=kj9i9~RwNZu^!iPk!!~oR<%OKUjTz`oy?-UFGZQ|JeP=^4~vSQsUfn-U7BZ rV}m)34|#af6D*hy1H}%EK%rXZX35y2E9CA8f>NxftDnm{r-UW|j}l7S diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_equivalent_frequencies.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_equivalent_frequencies.gb.png index 6d032ba3ff6d7cb45c7f0da664a4083674c685cc..ddd9971ee3f62829433e7b17158765a55af6b51f 100644 GIT binary patch literal 1558 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 diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_extra_length_clocking-cgb0B.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_extra_length_clocking-cgb0B.gb.png index afdd0f77c8cc1f858602c65d6bc607335d06904d..adf5da7d33c7b9c56588556a5ba35e2008e3a41c 100644 GIT binary patch literal 855 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-EaktG3V{==)PMHBCZ!- zhb`-P9_F*{(?koyR!;tzb^_NX{Wx%C>BLR9^Su1N-mA`D8-DfV;;q-j&)3x&u3Ne4 z?9a6~-Jc)d8vVY~LdLI8mao0r{`8;P&%y8a`d<$D`dW6?s#m+`>o3c+vfftu=UVCZ zGy3yWf7-l$KE3b$u5*9B{*+H&{o017V%k}T$;a+bS+(lgt&<{&_8w@^9bImGwW&`O<%_S-)!4^uH=zAM=Ik&h&vZ%>n- z8~;Bo@8#b4a}A@j)r+6W&;S3U*5UKb%HItxxpmz4ZrjE?9XtJe)3-cw>@_)}O_x;#>=DvCS{__p$<|6lg z*X(&%T#{Q?TXVVs91Q*QtN;GF^fCJS%>8!zUvGbK^oQN`XV+hEvpa0OzjdvB_51hb z<|lWbe_v$(V5xw-Vci9-@67+sf8ITZQGac9%00;so1X!lu=TXv1Bo|3{@ne}82__w z7cg*uP6v8-`fq>F`)?1||9`aaX`aLmmj)Nk2^x$-st$`-Jf<*o3Mm9Ksd$YF;t!Bt ZoPFoBWDkA4Sq98744$rjF6*2Ung9jle4YRR literal 777 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|V0qPZ!6KiaBp@UMzZ~AmNZ$ z@T=?OZdHA6{TW6&8cC~Si*4?Qn*Dqn)}OkhZOWx>xeGVtMti;Ne7^a^`m}wL^X9K- zpLKhBs^=ANaS*_WO=GFYA|`T;2Th7w32VgHJ*~{JDPjc1c$5gXvv{ z&zk?3-P*QxPUf`l$)BIzoq7CPsc!nU(!Upeu0H+p&nN5RKNlwbeo^y3XZ^gNn^iyF zeWrglpl9QsX&euP>Za|Uv~5k@d8>NwxT4Lw53@h}JZWld>?6BGyKnnnK7UkI>~8hb z?#9oLH9ne8kqLRXbm7zxTJ$@^b!F_4RzuUe8}rdG2%g$GG}>dZa)}( zZSUisN1qmHezvK%)0=+!-LJ*ZmuLREb39SP?t5YO-k;Z>w_Da6ooIJy*Mn2PfZASv zt(trxQR39ss=s$$?4BRr^SGjTiPZ7J^1p(gzuIkeKX&@*rrrB$Ri0(P{k><;@#xpl zoj)&sZ`gbO`@Q5>jGa~9yv6TbIi7E>;`*1ay!^rcvVGr!H^@!UuzkQk>pHXD!HM5Y z_r@E@U1HvLd&|Df>}#%X|8KNB^H%JAyQ(?&tLIn0U_5as|mhSHC^;{r2Lr`^?+! zU$2R`eHC5h@SSwm@+wC{JBU7!1J!gPcJZV$@g2WVHdHRR~W$` zQ9l>xnmzLG-h96My`gVM?dyH)Yf69ayfOLwYewy7UmNC}f!M$F_ix6zO~2<|XBJw@ zZX!PyL5H1r&1gCEDudl>JFk~NcN|}6`(W>FYu4HJTi9z#sw4ia*e`r3nZN8?rL96B z(2lR!^FIB*{<>!0Z@CTAW|RwlxwS`b!ivN8({{>8&fCfHux8hL#%#ZXf6u;V?EDpI zn^3jyxSXCXFsx=gV|ruSey`^PkNtt-&&Rnsg&Y>KOweFd@nRTG%oX=5|J*-XouC#0 P%+Cy-u6{1-oD!M<3d8E} literal 950 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Rrdr;B4q#hkZuV#{tTh_D6v zZO?dr_Lfdzq4xpo;`Q-e(G<( zox64Uv$HiXSH8EqTXi$Ic;cT4#d2+lRY96dpS@kV@zy=5yHoY&FVqa!KHc`~SN%!< zr_P%h>w50o_2vH=FNw1rp2-bV{cU%^Io~qz-gD=_r=5MdS8j*)AO7_D2QPlQnD$}6 zQ#;4hMfG~va`|bhchG9e7#+6wx18n`N?y7>(Y78mi{lOu3UVj z#ItAG`@K)z0To?7`EJq0-7hX*KX~!QUz_irrUpqJFI*vUyin@)tM%=#viF`?e)(L( z-k(>O8`^fIp1*cEd*=D`yPL~zeU)A|>7k|B)_I7RHXZ=r~ng7qa-u}}& zclFP!%75Q5{_}s@f92p)W2KKDZ6x|i4d(9Ie=m0LiLiZp_MFhOin5E5eUtzFn9PiW zUoTus*OHxkF#PoUxf82DKYaCI_0!kO&9n1+-Z=ifY9{Wkc_hI>Ef&pUYSph?jNs~=fEFBMM(QeW!+xu0w1pCiBAVE&7YpO-Gb zw6VBzpMCmwnI}8mzWJ$qzx&{IK$Mf`#tug!9eJMNjmlr!Ch1q<3*XI25lPe6gq0 zK<0Hq#XT#DdE5EgjK%-hrGAQh@Aj-h_K($LAz79BC46=2%7G_-zkU$=_vzBo4W$KM z?;b=6ujA9RuiJnB^!a=5zh9j<%lz|Fb&t8XtmT2?C8wTu=RR7~{IKSA_U6N%cdmba zkdZT-T|8#d>?doRUp`4FEqGt^k~3)ew{z{Qo2xJX{_D1QcfwDdf9XpKM0nf}4soK6 YS-8#o*vssTTR{2I)78&qol`;+0Ktafvj6}9 diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_frequency_alignment.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_frequency_alignment.gb.png index 751a11b294ef672ee6236e8bf3f9a10f1a4eef57..5d9ee0dec89633c72e68a0c1fecb1e9679243fbf 100644 GIT binary patch delta 1571 zcmY+FeKga19LG1qNE(VM{7jv5@8K>FjadC=aucOnouZm0ZfGaVLvpnTY`MC1tgP-) zB6%qEz$C6aYRN-2G1jPYDVCXaFl&BTyDRSIo^#K+|9t=Xe7+B#*ZcGSe5+PJSbcRp z%Nz!SahqbfU-t3rvHQ^?g_}S+F+L)sst(?Y`es2V5yj95)C&os%820PJ;%6`YWG~5 zj%78);z;4z0pDlus?vCYp_|H?01>H@5J9Bj`SFv5-cJns=mw{}!%xN3u{=pgc zfUmuh#vc88!KR}D>z1p{FPy3i@EobyYB*&0?Nn&bSTf%xE|ZYVA4w$WY^uBR?pmJA z+qx8N@lit)-2OP=dqF7IB+jekO&Je<;l=nJOIrS zFu;C)F48p8Q{v4;yUDoY>%K}ZxzmQ+MGOFC@lXagb08Ei2$-m@ut(u&)J^{D^?xC{ zaX8oYg$X2{SRBm(_7Rqy;c`ewt1gMDFKWDAxL_zWJ2!LbTwym^1uCD`<*d~~mj$bm zdmHnTd(LUtkG)wg@R{?|@E!Ib=6?T6#H7nsFS3SB+XgdWxe{Hyx#x+SUgp`M}>efwCYv2YBRX$b6;W zE6v z!~nLaPo~p`b?9c{0;M&k-p{KYv2C6$C6r_si5we;w*WSYsf5_LQupS~Ms}asE|9}Y zc&JNKWHQ>0$Pkg|Q-|rGAtxk^Y}~ePyNtBQ3dQz&!f1P@Dq`gbi%goJXiz3ugjvq6 z?e|HMbe>Xb*jK#g_~((QMLjsZsC85-Fh$WCzA}8w(Qd=^X%5DSD~o)xXQS!Y^GM%P zexRA$2vLSoXxOQEDWx=7YiU`L={J8(5P}*iE?fY#W*3zfj%CDGIECY&+P>lYvZ-)I z6ziMU1f;E90XvptUs86ZDvqj)C{vEhYTif%3z4U(tsLauL#vWe`TYy~b~jLPCRv<13{Ksy;_Soaq7% zoanzx5)(t)zC+#Y?rC^oN2ZfvJO-zj69d$1NzmNk?Q=@#Wk{GPP^?m9KTpZu0<+VO zY>{|B(arilga?@Db9UG-npt5PzSDFNvx)C9ODG3%x@;l~jD38pX8A%U!z+G7Ab8i8 zW)vx1;{BkrJD>S{EJkP)xfv}PrmHtPuNVQ@O`fOm=vv@_lNu)+1k2;&Q2_@>D}_`M zOA+XX#|9tGb&krdEM*iBD0p_I{!bAuLC37U63e6S3W9|^nYA(xSOuh(3qrVqtYRU; zL!MRLj_^<_x?~!Lq4OcZqKEOS^mpD3@-zZw25zeYi4*INMTNmK5g6!P9*dVU;HA?RCTssS!Zp_Z!c>#*oxK-b#5c~8m)Uxn4elV zH>O{=nH!6QVzTTYY%h>VFdr zYgD$R=v21lip%s2GDHhf2(*#jfK56*+Z^i&*y%J)i&b%<4n79|FQMn=2oJ9Fhl~1p zg0DPt@&4rx!C6%=c_xTQUszMlDiI=bJblLDeo({c9U-+>4!_=x_)R@y6__TF_7w{| z5o;Q}98t|gE)v^TyZVSkk%nFT)i%VI(IoMB~d delta 1567 zcmZ8idsLEV9By?SD>S;I>GGSAwlXhi>N5O1rD9%|nPy^|6prR?N*5=Id}~;ySV~qW z4DBSQnR&mIsTAdnK#@&lZYsB-|w9F_x#@Hd4A7%D@`Am7Hol5 zu7Hn3D_OC^WIn+6KzKU)ZE?))$z7&dee99b4VO=bHQ>h(qRJpl(yB|5zdqV=ZBb3E z3JqHokg`pEv7_Zstt80TQ~qHFEOU*OF)3K<^!Z6uFX=R8n%t-QpuNTnI9f>T=MAt29Wb(1*C`i|s{MWK! zEpvQ93l7`Y`fF{9<6(I4Ui!RdNl2P_W63)8iXxO{5`6Q5H_QdE%0~{X#4|^+naZg* z@rD2RnR%XSke9v-Z7FW>3wiZBLgYw(M`zYIB)E0AX?gP=iUbu;bp+B!KUpO7FCwia zU&nr;d@cPh=X@uou+vjx0@4%#)V*)+iqMno1im0z?SqUE+_ir};C3PAT*63Q1{vQE zz_yi*OGx*ovLu{QR5{A}!H}*n1Bezlc}$YcR3F$qHJPanKy3U5;9AiH{p$S2P;WoB zq@KpYSaUu-Pkwe<6QftX=-Y9yVg~!DD~HjpP@eMwOs!x!`6yXE~YxSe4Dt>yszfnAt2fO zO?)6eEaMVB#ysIY?{SUQ>P+Pzmjym;4Ae;A@)l%VrAoL$ZZITHI*!S#GxjOIPB(B2`nRVm1$NtznoHkD07C9Xx% z@K=K@C#CM?lNtxHrF4Rh>~Q(v;DkP-A;HM@EW+5AxDRNL%9gdx^iz9_It&W2(^z~;d z+|JbPe%Y)Z^turd%K*~!=K_Jeyj#b}wjlu3X2HPkK;cNYM9af!b=&W^J5Tcw zJt>%+e4J#WvFqvXNOj=uIy|=mC8yQ-xd~+)gtZD{^RAGbGnGjj6rjZx`>F_Hdj=r< zNUm9{C?zu%#!&7qM4`%v)}z?E|GF_u@iH>c6SRzBh|rv}7e~}{1tu+B9-E$KiK%+g zqF4P3AIe8~HM`D<8-v*Q7`X1&kA^Hl0Bq~%G9m3Myy)v(D_jz)aJJk^E0QMIe-Xx+c-;48J?kyOwj4S?W^_QxR?>2opWcU2y&M+M`^GDJRtb%TK;;0~-=T6!y$-!UXG;(N71mBpV&jQ%%WPi3> zH_H-d>1|!T+w1!+reKd?i*i#`yqlQjBy;YfmZ`t0D0NzN9=YNzw{^?OGCFenww8ti zqF-CFm_t~YHdELApY{q=Nwim{v!VWg7!j+y1m1CR_&m{Ke0crvLx| diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr.gb.png index 9a4ca6a49e32492a2c7e26722fe85115e61d6546..92e5341cd4868bca8bd294f8e41614fe89745295 100644 GIT binary patch literal 1451 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 diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr15.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr15.gb.png index 8ea5179f988465f679ca53748ce0978a86a8a019..101ebe4dd41095968bdab8aed94b837e5afd4f92 100644 GIT binary patch literal 1513 zcmb7^do{tVO!xo(xc8oW&$-{n=YGyj^ElTM)Ynh+U~N|r00Y$+K6`a+y?CLByM8r2NQ06(jzo~b9|uPF_vnRqK+0YJT^ZR zW4R>k$yoi$NvE$SRZ)pFFlcHn4mz7ZRx~oONJ}&&_)!zQY=`gPe5Q)G?G1CP^no7M zSm3j!B(IfHD-!`ydSs>yor8{a;Q0f<$4-m(xI(SQ!uu9eWmrq3uNVtk5R)Y`?3_2vo))` zqeQ+ySyp5Dh*F;}o~69jFSteNnxZ)gmR{@Yu(H8K^8m7AKvi?XpiS4nzf+G0~CX93j;1iv>fQ zC+UW!isWz{Q5F%<{sGZ7xH3T>zbY4lWf=wPGA8I!7IcG$h;~SS*dEPe#00a!X4NM_sU$N-*S_SIsodoQchpbx@-aJ1 zGS{=%5^>!AJ3J{0S;7@x16OxiYoS)EcF@-k`__&GxNg3!N$z; z@h0WIhV!ZSf`pyh?k*87S()y`-Hy2^x+ijn5PUV>@m@e&k5g7RFgMX75;$;xbD^<pmwb zVdvB?JvT#COj6gR93!_!W9@S{k zBYZ&AOd$x-Xx4aaK?dq=#G&0aD$b5i|j;B3n^pz zK7GI-t71--VuYe@cqcRRXqjoP6T$JOhrb~N!T)24YI^k(jwtL~hE_}YfpjZtg^fX@ i6Od?bi1{DO0^%>KTkxe{(rn-_T*J-flrzhTnD`F>7y=yt literal 1398 zcma)6dsLEV7-zLXCPJ-a5h>bQ7iWcL3W8+w64J2?WnPcQMAHh<3e(Ucqswt#=ydU@ z37KeRNR~L!Ep>FGa+VxZOwGPVCW(j&pQeu3$FkPhUpwc${PjHV@Akae+qY8f=3?i< zU@$vcP{0o8E`|2lIkTV>rk+s4VBb(^0Y8SMm*|D`!y0E~;NE8}_m_U^3#?G%>z$7F z^H$7K``wwY01|QsBGzJKSI$=%CxcH67-<0-y=h4U*j2%roK2DY;Lv>&qv;`0-%AE3 zOZq1T%H;D&zV%TW*q?o^ za9D`f7yB0mp6T2jgU}pH!C!W%Q0u^@ zz%FNLH2d7q_^F|wtv9uLQ;9-(S`^+_M%!L@cE@8CDfP`5x3zGmtfjGLz60;lOW_Ec z%U4j=bUP3GzHT*zqfw|qK-*T%4Qn@2@vsNBSu5^*I$CuV^T*p&osJWt|vpK z1^suK33`ERCqFt11b|XhKB`s1m*^cbigvNDQXL%}{o&1ErW=nl!_esqh6Mxs9;}bk zknI}dluRbYqc0RZIo<(|g8*}!Q#=gB`v5r`&NKKBenA>->D_0uaz9 z7Nr#nd;Ps8pZqztac?CuJSN$zUaEp0u-GJDl|NU!A2w}ndtk_UD~Q>1@zOgwf|?Ku z4$$&3+qOMtQiw!x%PE(Nq5M3Mu{%-TDeA$qRUg1lrioFg z{L!N-S{3$yZQmk2{n_G7mNuJqWLM}o-D?Hme7@dP?4HDzExVX!W5_vNM!;m2Cr^6a zyV3X3#&DH@snU0~5lN8f;}dbWk;XW6+ce1bjQ6DQOzR}Q!B(P?Z#}!wap;Jg-ut)D zyK>1Cb5r~H{gb5hrHy-ndw`)Jw=QYl7`8%VSuI;a6r01A*CYJl`^llxE;Hg=!5RmF zeFOhGi2bmMIz@|xjG}LAHq@F&-#JEo#(NF!(VbRv3peDK>{f62?zlp(8=Y1t6cc4) z|MU&ST3l)h=b?wEi%fUY@_4M&Y97UX5b%VkLZuz*RSE_k%3@NU4;U;82!H>{}4hb7W(DRnn(2@3k}dp)BW{ zGgJ(_IXcA^tMneC%FK?CFDwI<=k}35nf9!jpM@uR)c6)qmhqF-Ru8QTKwbWMKB6dc z(Bq?$8O~;6Uc<62=WWhiis)x^H3o!}Lah$FVXi_AGO3A0>dV5Uqen_>L*P|6<<$uJ z?lbTbMm4{=xfzc^7uw}DCWY29C|y^qiq!tGzc!4l>h^BZ&h205-Oaon-{O?36pD_$ zVv(7{LG5uTI4@SyajSA9QPnsB!Q5s*gy|T-$4Lq9JgDTnu>Tp!*6DSMNXOnoXc!M} zo!~p9`fhJ!VW1dQH!}P_P11rVV0vwF8*EWX)c;&hc@C))hR_CLto1*o1#S(v>Bl(n EH-I~~>;M1& diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr_15_7.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr_15_7.gb.png index 9401ace66f035a22502919ca8cbf2bce41740dce..dc1a67d258941bc275b5ab63986dd86e9ccd566a 100644 GIT binary patch delta 1829 zcmV+=2io|#4XF;08Gi-<0057*V1NJs2JlHlK~#90?VVwA>naR|ap!K)*+SOjY?k-q zm5ibS!Iqq3h4amHreG9gMaJb6?38oP+qUJD(#y}bZMksfaap&nYnH6*+O5|=5$z>9 zP9;XIdd(4g^!YD2=e#USO8-YArIgYq%jNf8`CYrn_9Z4IE`POht6p=&9v%OGe?CP8 zg^)A(K|4U^h6zZZR1jkrqASL&yIorIa3z$IBJ6EK7Pk9?wQ+A1|!y`f{bL z>)NgNu$T3EWPjMUty`~?$Lhb1Q;AWlKBe?huScfa?bfZ=$%lyl^g5tbhqL;R?%x_e zt37o<0_7tz%;+S9%t!SW{HGCb!Mp{ZWKSKCK%ovOKRtA-ova&~1xB|=&tiM$^$Gu7biiC0jtLoo>j4QA>VO1_iw>w0 zR+mS0K=gVzv^`qKL--HZ0cQt&r?GzhR{!BTpj8L+)X@;@@#M&W&_U5UBwPp7cD3@m zb{2c>XMe5SYlrS1?Z4F?t^>}lgIW8RApDmcvHyq;$n}7vh06%oYByq!z5+P{UT_3# zO(qEO=2AM~j5?TS|7ib1>VW8x)_VF@|H0vh$A9{L!IC37;FbDE`_FyBoP>m%gt+Vr zM&CwAT-=vq)vjzpTDT@4laK7hO$TK1kt4Y2fPeCL>VVV%sRIr|9dL3TP+l1k_XSHL zJ|ECCej#;02|@?6+M{*A=>1a%Bv3x019CkeX#rmksN3-tJXinJ0SS~#>40b*46UQh z*gsqcjLzOWg~l5G=>5ZWKv{>_*K4)+)X^e7pU~WYZ4&ayGWw5b$&B{s_)`ZYP^t-d zlz-a9gODDsI^bw~-h!`VkB+~K4!E~HA%(AcPY7BEjBbyJKU@d2j+~qT*+9o1t^-OA zttS(oiFm%C)m{=&$27+;x(+CbXditNW&QrB0}?3i+cHaLADM)Z`3SEAN+R0Neha1! zNT7U`4jA1YtpiTE9&q-NGx`M1`u(}RCx4_kQ@b5s`T2md9Wgv)F4tYvo=$`hS7^{&i!?R#a8Am8i1>w7|^&Fr&VGKPx|n8gf7){WX1qU&(V9S$L8AMA$_QASNQ@wD(6cKNgG=dv5!bWPe_Q`>9T1Im zq(+Ai?Z37E)Aj{R$3}I;=3oa(4+&F^0sZc#yfjiUn{rjJ?x7wvaK%n z+M)eN+gsyTorL7d)iJ{Tet&zF5F&wZ%hYzVZUz|xeg0N^Yy8|_R71!fxG$JMxzxVk z*>$w&_S69nU>&(951%=H)Byz%pHCP)e$)YtIu_bKdiVOA`K60bKK5P6=(*Y%C>VTd)TEyoI zTH|N6x1Rqg?+MYIISD~eBCL}DtN-Xph}GUz2OPP|2$8sN%REw+{cr^22uR4saNQS7 z$X>om2aK-6q5DVJht~noBY(9ud{+O1e|>lzP}W6!K40%VBdkaC^#72Ki`D^Wp9Naa zUlK8X)By<;R~beoF4qH+5#T~JZ^66;S3jtBf`oW;DIIV|9nACmBgPM|16oH~u={4v zcN%p3Ty#KvOy9!Kd|$Bq%!u#XmFE?4J)!md-E=_xN9L$~^gqI_{(sNj|G!jW@31V} zmu#oZLPl`kmf56PfLWaos?~4XgdVSE)yW@p&Ow+TM zb?dsm*sbf@t=B(C?0bF|A6xYv{?FcjcpcD+_4KX&&)z>=2h2tt%xW)*_?`}Q|B^#G zZq8U8P;z7zMtiJ1b$>t-8~KN13w^xTzIJTSB&Jqw)zcntFTc}Px!X<_T8t)ONi>~Y zqxKQMfZ6S>2}m7~V96P)1NPdD=uouB+ROToIv|OSRR^rjf(aSLI)3rtL<9;GkU(Jq z5-3bS0)+`kpfCXm6eb{n!UQBxn1BQd6Oce*0um@pKmvscNFJat0SOc)Ac689Uarch Te92Sk00000NkvXXu0mjfgZQPj delta 1716 zcmV;l221&=4!I4G8Gix*0002j_tyXb27pOKK~#90?Ok1(Dk}`^KHuGo6UXj zoJ{0Tf*noLRZkIWLIMpRCD^kO(d~BI1a7w*5gk>|A1{{+{ln#QX_iPh;d6=1?vYwu zA~DG~&zIYf?Hy=yK(*bgb;ai{tLf8==<(duAdlGmtlwl=$D`(R8?wEzte-1kJQ095B7-qQ6107X6=AqH?$r4gj&xSt$*uyw0!8`>>y(u%pb9f#=YnjXydm& z57xrEe}7iagBQ+^H~Sk7ljp%7^KTsw?nPshwQXznqGvdO6TEd?xOZ*}0DiDOz!=>S zSk%E7-7p~NVCdj?03AF=cpdz)8Q??*bIIgAYU>$aUYoVBIdlHF$GHaEY%!33=-}iy zQU~Ka*dbPa*-+O`^07pJ-amA3c95|SW(2+G9Dm*a>F!0(tWOf!{_*DDTnF<^jjFaCVtNoL)4%Ti8NV(}?1m#=z4|H&Hlmk2uez>4_J!4%5k2zSPoh;ESI(UWy zcme5ku&SItIyry!#<%Vtcjv*@@pyxI|9G3h-uTutSj$)E%YP&P{y>`ps_kB_D?WEw zZGZP_P5IjRp@Wm-t!uOU^SLk1gFT{Ni{!GfJ+BP&oWgn2?$x^DTQ9j}KuR z;#u597cF6c-Nv(`gCEyZAai42VFvg9aDTvQ+9_v@w|Lgylf|^?`{d-H)m?P`%wiYq zFrM%_SR4P@;#r@;(!&hj$u~RE_oxE$q5vfiJ@->}GBBc(nc(Z&k{L zr6_Fjx3ISoy~U&Tf20n^d9XvQ%;4hAGiLB7<9T-mLkDLA8SCI?ZJ=GNw|KPv!+-xi z*xS8p>v**O5BPmBH#vS^w72&y2mSrAI$wHTY3J?nid|$&VRffBzBb=R=F;h4fEmTZ zSlg}=wvNYJzUDt4mCWB(0_^tEB{|`6c*GQJnh2&y~1@wNFv2M2>T-_z+} z_AvQgDlOkzzNgc{)_iyQHU~rc>VMgcSUT96?=IiwU`SuJ-Q&Ex;^QJ=W4^b1PxnQK z>;emZGovr&3mu#tbTS=m&G(k?>2$C)tou`&?*TfPeI25MxkRfwo!p?%=Bwpv<1aT^ zT3cewG1^2hCi!)X$Ht@euk9Z#zuaUMkL>`1hY|3Dx30}j+UyN8`1>;$NPmX)d(l7) zkTV_3B~EmzwSQ~AI~{DjerWU6#^bF&&2=z;H2S|l%QMo+dGm5Sv)?O_u@2sY??Scl zGo0iL9h@CJoK!)U&)CgPR^1TW&05)dVfSiH`P%rs}KuR{J-^olOA8q6cZQlh5Au?IXjz#9=~pA8$NMbe)Jh;?SK6|7_S8nfps1H^Ydd6 z4{$W-y|>NE66~TK`gf;;wa~_It;@anUpWunD-8JBCv^FVcJdx8Yk&U?#SGr{2MHY6 z44;|uuPDe{ZM^Y!<>3c(aCY!$Q3YAvUEGF02Up@vnH}K=L#c>mLCT~rIXr1voTjp9ai+BywA#d$*ywm2an5mg?Dp6n@Q_Q@q zv+6jSkc671W)3h>iXKfGZ-jY4oorhM5z*8@ND+B(-uHW+_j|sw zsB>6Li$fMBCMK3=!$M*}%LG@oxf!@uaqu(~6En%#kihfTn>OxTsOfaFF3wdZi<6M) z-t{uQr26Lx=jbo8zSP8V{`Mzt?_leoKRqF-A3)TP@#o0mA|C!m1l`Zo_4@m|FMp1=2v>c^PyDxq}aQ+NpyeWWVxZhw#cXl?;H zW;FNm3b_Eyu6(@Tx4_yyxt=wESZK?*v?6c%kr?m;aZtLHiefUa(hu|zZJfKYBnv}q zSnR{rf8SaB;CF^^g=lO@fAyg#XlX4XAA;_h7$|fUHKUmQZB*}^51r}wp+aRmH3V** zB~Tv*Ui)6_#_25Uo9p^{ooq~P@OnRkL+m`fMCGCvDamm|rc?$xZfIbc6_ZKdHyPGV0cd*jdDuFrs+gn!95tgs6?b;ST0iDkOrGIHd@uf zzL#!0iu^6Ku#z?n;NltCwdHRyUxR&)&eKs&Yl53LMkI=Lgf1V2dut zZ_@lU?)0yk=7ygb&ZJ*;kh}jI_ zWkd2TCk7~J&JLxkH1KvS%uT3T)`COY;f6-^GzO~I`Y-3$kTWyAQ)!4^{VK|-k>jFY zz*7qdIx#6AA_P9Zk|Rcn_gFjzF<>jghi{Ib7iD7ytF+a6e7PNR z8hG|>mE!q%d@)^VlLDPNc$jQa2Xk#NsD(KcVvalk5&Z&R^^~BxYv{xH&ls~eKXsd$ zX_cZ$0lKskQ?@KaqVpQ&b8)c3p~=w3V-VXr(Q6$%!~JWbe*~8o|lK zC($e=-A2lzh&7NpwGZy`nel=B<#4Kdsf3KlR7A?Gb)CZ0dD_L@I9&->&Hw`U^kaNtup`x+-Q>IwV{P-N;GKxrnh9FC+yYGjUH1vkc8qJql z4l7-wKZL~-8;-({--A8xMsVsu!ifL85MIiGYbgRjcP57UQ*e+^JUvv3)u;0W#DKt1 z6cfn@gN-#hAo}^6;cb?oZ;5&e{$lzOFLJb1pJrA9qp#r!`|EpNZ8sw6=^48olrllS zKAAN5I68>#$489+Uc=o<%KGHjeEo-~N<`axjwFEd`-tQ@OC8D^a$OCpDCyaY%>PRA zNKOv&JOF>OY(FdRb^z;Nv8C@(ciyu>y-WViVJR1c+cPlemsWg-aT+kSRnXwd^d;== zR1|)FYgqU?6sn%zKS){8nzDBKHdw;fIH)?+dtQ?Ggivm>a8YA4{C=zpQJ1y*P9Nl5 z{%w%}4(wmF}gyU>2)km$!zni4;J zggmPr$Sq0nJdoutGcJ8^z*Zr+B0nyS@O7Y@@@3v`vzI21;HE?quFC9I-O_U-B`z1jU?0 z2)8#V($l^wy~yrk3QGg(nU@PGQZgy5L>w!C9_$rkzWnU`3nNYdzZ@T)U98+tCJI|yI&U;DV3ivR!s delta 1716 zcmV;l221&o4!I4G8Gix*0002j_tyXb27pOKK~#90?Ojop;~)$p`}T_M73NIsW!aDH z_)$zKCb$t)`f@-e0tbpFNhib@ACE^!@OV68jHAls@OHb!U)*lDVo3-=O48Q$rgTXP zC%#ob9AEm7_Ge%$f^=N06^S}Ns&(aC^`r6sRz5~7fIn9YAb)(p1TT&}!P~ZN+jfZ* z!Ud7L=%shjoA<8Dx*nkI@@8Mp{)7;o&*zrl`F!qmqsn(!uh6u$y(wMtNj}JoG_OE1 zWBwnHj^&g(F4js1bbM6n%D3wG=3DjC2QQA1HfdiXWFMaGxrl3^=YBfP!|O`b5$h9$ zp-YfA->To6Z-3QKAG|sueehI1*s7mC_zlq3Gwb;D_~5iEZEJ`RmXF`>clqr7elM1! z0vdg7cl#hS*xKJ7ADk`)F+q`^GPC%o*2GWGp2fvlZ#{7R)t{^SQI5MSu62d%$wKG+JY{(srmCu@JR8hM8xi z)yK!z{dY@DA3RWxyMC>#p0KRvZ~15gil)a~|41Lq`@x9NmtK8F7HcbfeWGybj6u`m zt)D)4bwv8$sdmv;J@mnYfi|AF&qYt_gS+*3>5s3wgW<6V((zHPi7#E!aj_OnkGKAw z=b~FU1b+xl-7eg}514Oc^e33vodTUcnAx2Mkv^C{_zci|Cz>8B;C!(66)mSjd(Qb= ze6S$2`8+FMI;`WPT30?=f9Zo4$4DQ{`@w+NVvI+gCoR{UdP%WX4)<7>WM^;T%h#%O zL}Fc%w(rC*_UOX?(g&}O=kJevzAAjtPmi6Y7@E%WVe?NCW7{nKTY=r>n zZ@$U$i2t7nW7APQe_m@6+apVbZhg>Z5yU6JG!F3LoXpsK)_}~@}fr4oF!PatJ zd!a8xYu{VX*ZE*;f4$qc!m0<(2TO_f{ax?ps6l)%-2GtbfR2x9O?+=X*7m*i&<8J$ zQ-6=mZm;)!c|RBsa6Wi5`aD4+U!QTT9&7vF<3k_3IwF`4mJ*QrwchP}>w)vZ-fM%k zzg9io<7w5?`8!!5F|1ND#0P(D22ARM&Ha@=r~R+TSzA(A;YT-L=*>^NnZ?CgH2s~s z=yc*{g++dF+f{n=^}bYMU6PFkg8m*Kyninjw7FBDX9i1LoYtJdQ2P6SCrfCJeBv6! zUSBI0iyU5ZKiHcuB_KZ7%7^p8Xt1tNXyfVbgXPfa{~&#g58{K(;~8I9+Lkz4d~iz3 z;$m&uS{5JGy7JNVTlKj6;BE3J7_k#i9?t{^0fR&G?|LhEw`S%t=Yk%Yu z*C0CkU^$%BN22Ms>T&nM*7@zN#|kw4Ry_lriDNRIzFm3@zb+s@lmabKfQi^rj(TRGwbt??CT+mryron^>_ZE<1J_FwMpp^wD3jJ zhG9$4^z;7*FAhEzy*i@vbJ21L@_(GOl|Q?FI3H{U^}j#C$(b5{FGJ4Y4n5xELm&Kx z@2$sseCUG*C&0UXGhZu9MPxeaoca>&)B)>&dMCiUeKWr?c~;Jmh~XWu4ybnmyxX_( z>4R5Cqz_(t7fm1h23Gx6J??Aa`I%b0W`mkElg^mg+s}6g);L9-6MQxuY=6Jre!j`d zTB)G&@B;ya;%rOPd_JCf2F%_*?*}iA{^z2JIS?oRoh-IrZy)acU^L%3d;0^PiLs9X>iytNZS*UAkSqGz`2F{T`Lp0tpx+1o z{QNlRAx0zi`dayTao?!vryJ1Q?WGHM1($(Otd;eXDLuZwMCEDg2r zi=Qf%qywbmqgoT+ss~NKl}{hMI*PNcWk%}4OYR3-`Bpt>`px{K z;KjiNFAgSnaWKJ)gDnYO98B=yV1gG16TCQ>;KjiNFAgSnar^^)v+FMCS`L~30000< KMNUMnLSTXgwvYb+ diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr_restart.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr_restart.gb.png index 640db3d070608a3d30476206e7b81277ea748fc0..73ad2b7b71c3891f8ee498c715d97c8821ea3268 100644 GIT binary patch literal 1453 zcmZuxZB&wH7=Fh!3`Rz@A8nM$9|R1(wRlmRhI*Gg$K zV`*Vcbf!^>A45HYTABG(jgtZ<8lokbC@CWHvX@rt&wf15^W#4EeP8!=-PiMT%&v$P zj%yqN09X+f8AgKMQs{6IUqN?49fb`54w+G5A^R95lQ+|-YOHg3;$8V2(FI|r+}m&@ zG&(^#;9xEqamT;Z)9&n?kr39cz8=Vs3Yp(7P^cu;3bUx~rx+dvDP(xvm4F@`OLSzQ7t9di;#GJosdd17jr^2c##% zNSVVp_!9i}QTA2E0ev1}C9`-p5*+8kp|N!8>{(M%aJ?fCC-R9x+YH0#l+zuQyeSmJmFm<=E2r_jmWNd zlK$F>>~$2_-QdoB^ArEM4}7O}av9IUp7-Fpqsr1*!P%9&k$JweO@o-2Z0Fqb?^@Ps zpPqm}uLDx{EDwjHGlIDpQAnO!*O#^zpllM9oj3taR~y8FFE$?Dk&E%|DX<(@`IlCk zD)*k~9~&vq(pB8XB&K2v71W^efGe8cs+A?WNZj;`xQnp$s==Age0AIF~3?%@S~x z?Q$R8?P#QHn{o9nMMHnV`|%^IUCSE%>b4wBzn z2+M9Mr)GE;83DaF$z?Lo8E(LJ!cI+1T52uDlGgb&+o0n0@XNAZPDJ-Zy)xUzrXs5~ z`OrfQO7fPtUs~?&SO0h5VZppf{4n5F3PhWeuHSLJf5M51`-7A64D}2KXpxQ2rOuNi zS_21`-byf`=rrSn)I|@LbxCa-4Cf9R#L}7o$%} z3kS&vwT3*O#x%lXPwx4K%v%LjX|uql1vaPzXgeTXn4Lro0e9;jt(P-C*A(O%K>7h^ z%x}-mlz1C{EOtq!@-1wvK%3PHM0`^5qji|onRytSQw*I@Jy1Zvvd3S#`+4|pd*kma z=}97DBW)(r**pj>uOJ#p?lKM7*0)K+eiwRXz2~SmgDQze@_Mgy7!_0O(HzPvJbds* zoZ$cr0`eX{XqK*FNA|nx4F-|PzV&F19xM$J^`C8$Jy}QV7HKNZL1t%s{&_x;UwtLQ znXpeW#iGaeXNgoSdPMh#4E#VSwGN6;S6cnE!50=CmG?)4CKHTBB8J6V;X6$}UI?$! zS5uIUitN$x2S%*9?x@&yg2>}U)gw63-m2tbwI6k)9BgT-0R6Me+(Gj=)R zk+CrB1-m79XKdtcAjHuDLD~?^4TW)>9Z_X5?EeiFN}eshP2DiBt%ts0AS!%Um@t&W F`3DHs;f??R literal 1365 zcma)6YgE!_7$-dgPvg?5vjF8%XQeGKd8uPwC@pU^XKJMuQrnqnUx>ZHZbra!`J#Z#(CG-{;%!d48AoIT9NaiCFBs z7y^MH$WdYOwtCTaPdGW)UWj&93xRxrBZr0V1t}IVjX+Js4!rxSGc*|d^=FX`ft|N+J)=6&gRnMg+qeNeQzz|@Av-gRRl8#hT?JfvpXmD z0!1U~3Gyn!0R|h6_3%G=@sr6K@pZ@)vINW8%aJF_hz0pvKSjEHvVZp+;}1aUE+yb_ z8c|>Kby=>6>gW$?dSd&}7f2_Hjw|7)E5~Kmd$wyRHhhu%cFO8?r8QLOT z?py7&>X8rf8xn<+?WP{U#;NKI_@q04!;Hvp$V6Qt5Bc14Tua~QZdo>+ghFWmA{*YQgNGf?gMRA15~pr+D6FnK7o_fKR1qdnU|-dsUwr z)!LcUN_@}u-D5zu9p*xGZOIYZgCT*k3 zs$Yj>H^P&W#kNeXmmr%t-8W9}9?q~cu6a&nU#ed9zzPzkEk*TX;_Z_Dn?CX?c5Z|A zc)*4;>Z0<}X&M?3fmXLg@H@%kc@z>^gvR6VT0dImccGD7mF&hZ9}ay)h$;tCHDHd( z7D7bERdJjUOtC;k1I|1+hJTwdPy7&^m3ks>kA0LOY-c8-PegiUb1hQf(bzV%@X-{* zJTLe7M| z+waVZJnOn_m4AzB(DGm&wMi(ENOsOq@EYY$J-(97K?Cm=RLrNM@-`z88^IKqKp>!c z6TDrV3!gUSf`D|ZJq}q_+AImDR>tD1u_{kyt1`CZ)Mku0h@_zA2GPf(deek#oktvD z&9Q3~2|?^{?U{!qnrVhFJ*VEav_$tYm24gMC_K+RW(N1*^(+KL0JXvPvat tWZUGxKNAV3sd?VF(0cxI90vD4&$;;+$u4TNXjE!nm*nu6u;wi^;eYOOo@oF8 diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr_restart_fast.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_lfsr_restart_fast.gb.png index 640db3d070608a3d30476206e7b81277ea748fc0..73ad2b7b71c3891f8ee498c715d97c8821ea3268 100644 GIT binary patch literal 1453 zcmZuxZB&wH7=Fh!3`Rz@A8nM$9|R1(wRlmRhI*Gg$K zV`*Vcbf!^>A45HYTABG(jgtZ<8lokbC@CWHvX@rt&wf15^W#4EeP8!=-PiMT%&v$P zj%yqN09X+f8AgKMQs{6IUqN?49fb`54w+G5A^R95lQ+|-YOHg3;$8V2(FI|r+}m&@ zG&(^#;9xEqamT;Z)9&n?kr39cz8=Vs3Yp(7P^cu;3bUx~rx+dvDP(xvm4F@`OLSzQ7t9di;#GJosdd17jr^2c##% zNSVVp_!9i}QTA2E0ev1}C9`-p5*+8kp|N!8>{(M%aJ?fCC-R9x+YH0#l+zuQyeSmJmFm<=E2r_jmWNd zlK$F>>~$2_-QdoB^ArEM4}7O}av9IUp7-Fpqsr1*!P%9&k$JweO@o-2Z0Fqb?^@Ps zpPqm}uLDx{EDwjHGlIDpQAnO!*O#^zpllM9oj3taR~y8FFE$?Dk&E%|DX<(@`IlCk zD)*k~9~&vq(pB8XB&K2v71W^efGe8cs+A?WNZj;`xQnp$s==Age0AIF~3?%@S~x z?Q$R8?P#QHn{o9nMMHnV`|%^IUCSE%>b4wBzn z2+M9Mr)GE;83DaF$z?Lo8E(LJ!cI+1T52uDlGgb&+o0n0@XNAZPDJ-Zy)xUzrXs5~ z`OrfQO7fPtUs~?&SO0h5VZppf{4n5F3PhWeuHSLJf5M51`-7A64D}2KXpxQ2rOuNi zS_21`-byf`=rrSn)I|@LbxCa-4Cf9R#L}7o$%} z3kS&vwT3*O#x%lXPwx4K%v%LjX|uql1vaPzXgeTXn4Lro0e9;jt(P-C*A(O%K>7h^ z%x}-mlz1C{EOtq!@-1wvK%3PHM0`^5qji|onRytSQw*I@Jy1Zvvd3S#`+4|pd*kma z=}97DBW)(r**pj>uOJ#p?lKM7*0)K+eiwRXz2~SmgDQze@_Mgy7!_0O(HzPvJbds* zoZ$cr0`eX{XqK*FNA|nx4F-|PzV&F19xM$J^`C8$Jy}QV7HKNZL1t%s{&_x;UwtLQ znXpeW#iGaeXNgoSdPMh#4E#VSwGN6;S6cnE!50=CmG?)4CKHTBB8J6V;X6$}UI?$! zS5uIUitN$x2S%*9?x@&yg2>}U)gw63-m2tbwI6k)9BgT-0R6Me+(Gj=)R zk+CrB1-m79XKdtcAjHuDLD~?^4TW)>9Z_X5?EeiFN}eshP2DiBt%ts0AS!%Um@t&W F`3DHs;f??R literal 1365 zcma)6YgE!_7$-dgPvg?5vjF8%XQeGKd8uPwC@pU^XKJMuQrnqnUx>ZHZbra!`J#Z#(CG-{;%!d48AoIT9NaiCFBs z7y^MH$WdYOwtCTaPdGW)UWj&93xRxrBZr0V1t}IVjX+Js4!rxSGc*|d^=FX`ft|N+J)=6&gRnMg+qeNeQzz|@Av-gRRl8#hT?JfvpXmD z0!1U~3Gyn!0R|h6_3%G=@sr6K@pZ@)vINW8%aJF_hz0pvKSjEHvVZp+;}1aUE+yb_ z8c|>Kby=>6>gW$?dSd&}7f2_Hjw|7)E5~Kmd$wyRHhhu%cFO8?r8QLOT z?py7&>X8rf8xn<+?WP{U#;NKI_@q04!;Hvp$V6Qt5Bc14Tua~QZdo>+ghFWmA{*YQgNGf?gMRA15~pr+D6FnK7o_fKR1qdnU|-dsUwr z)!LcUN_@}u-D5zu9p*xGZOIYZgCT*k3 zs$Yj>H^P&W#kNeXmmr%t-8W9}9?q~cu6a&nU#ed9zzPzkEk*TX;_Z_Dn?CX?c5Z|A zc)*4;>Z0<}X&M?3fmXLg@H@%kc@z>^gvR6VT0dImccGD7mF&hZ9}ay)h$;tCHDHd( z7D7bERdJjUOtC;k1I|1+hJTwdPy7&^m3ks>kA0LOY-c8-PegiUb1hQf(bzV%@X-{* zJTLe7M| z+waVZJnOn_m4AzB(DGm&wMi(ENOsOq@EYY$J-(97K?Cm=RLrNM@-`z88^IKqKp>!c z6TDrV3!gUSf`D|ZJq}q_+AImDR>tD1u_{kyt1`CZ)Mku0h@_zA2GPf(deek#oktvD z&9Q3~2|?^{?U{!qnrVhFJ*VEav_$tYm24gMC_K+RW(N1*^(+KL0JXvPvat tWZUGxKNAV3sd?VF(0cxI90vD4&$;;+$u4TNXjE!nm*nu6u;wi^;eYOOo@oF8 diff --git a/tests/test_results/SameSuite/apu/channel_4/channel_4_volume_div.gb.png b/tests/test_results/SameSuite/apu/channel_4/channel_4_volume_div.gb.png index bc1c2885e398bb63fd88684d79dc14358a016283..5961675095043a2ce527b79e78324ab5082cf506 100644 GIT binary patch literal 974 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-w# zm2B_$-e!LLyJ`vt^N)5jQ{DN>kz8~2PV=X7%+FbRCF-?B-_|LgUK{o$&)xI+`{%8R z60hzU@a%qly1l0Ur}x^eaeC8(yfn970}|@84FxpZ{tUAy(}*Z&JTTrP8N z%lx;irv&9~zkU8@X4Rd%?el%#|NEOF(H8%HN}@#B^{2nj&t^X5{`pyh%Uq+j$}egy z=Qmez{>z^1z2VR7Pe9R`P+8NN%zEE-fV})?`_DIg{eAq`sgIwSmwQ+LOwD`yM&gb)(V!5Ek?0+qr z3Hy}(CubR-F8&$(tig`|#5A?^18ZyhpUh>nw}vV+0n#CVstMFzJ zju)24{;RP2xA(!$m;Be3uKnu%eebOK{~7mg)2p|+|D^ih!_^kD(Yg-=zq?uWKbwAj zgnghD$j}jw|P)B-}^)QQ=q&N`<$1Beb=h*$xP5FJ}^`6dB$F#w(@Vj$D?0= zIt~i-y-y!UEZtK#*|5Iv>F%`Ly`}StP3JP(?YgfTvG1kKhns&5elGv#?-A8syyYH9 z{Y>U_Uo6~T+vfA_*qm>559C^Nc9m5xpEEw6zCAqOX`9~U?|SpsewuSyrXW3@fBFVA uT^>{Zi@Hx?5?b2eqNxzbb*0|T?0r;B4q#hkZu?iSrv5Mi6B zzCL6B>_3~nG-*0t=vQqzUa_^>l`p<`nY4!bDU%}-&nx*@KieFasJ{An`uE?q|DM>Xm;5jNc|T{v?d9?g_qv-NUTIpMIcwQV<$k4n#j0+% z=gZ6Qud?B{>#>%Ycb@N(%lE>%1y3uouhksiQ)@71UT%=pqR+N_tTsM14sp-+jLetQ z7w3vEJyKhJ&u)g_7qQ-Rx7iQxY!#Sy{&~oU8oSGP!uHP5vd>nRZ~NJ|FUIcu1Czp( z7`dYx6HMdPR)4&<=I6YhUT3@$uX=IG+1$Uxu5WsJ!w)-&zFLF175nbT{++P4=3mj2 z=%+_NeLGn2rupU1J8G~;iTg6KhsR0xhsf#NDi!&<{N1aRYBR-auD#2O zSpR<6M*h4F+VT&@w$&fm5qkbU-O~?e>^e2r~i2J)*z$v#dY(xeA!fV@Xzhv z4>rqK+IzWG|GSt`DSzj~KMRrDwi}}~Eq_m*Tl5vI2;e0iSd{`<|M-!7a!eN9cn zn~){?Uj_eWzq>kdckss!ITfJ%aXX25+xgp)<$2Bn!}>EYVE+BuWiV%_&(z=ftAWmY z-~8QJ?qc(k=wA<%B_&&?+5O1b%lkXw_XB}H$A61{JNN-=&+@;u1$N>6@tZy|ZVH~b z?*_!IH_Z<#etP&Rrtr#SYy<*^@MqOON!eBS!_{W|0Sdp_6i`!nsMzQ~U4 z+keR)$QD*uxtZ}@+3wBrKNe)?C--bz_gdm{amDiD{)+!8`|tN#KL4G)|9-q}{=c8k z%Z=+E6)dmK1u84Fkh%BXZ~66y1r_^W+X|F5#z;q%KqwhAlT z*Cf{c5;*kQ^0(lhr%Lh%pS?H9=l3`zccI1#NWW66KJeBw`dh;@{d4l~8$SPd{Ad2- zx8i==*PYFOeonT&eD2TZbN9at{&4c!_X;kv|ErfjxIgQ7wDzBA@0llUVpl1hZ2Q3M z#@mgy3x0Zk{?@SM4ddDEpO0HF0P<7rf$aD{!FIuW=Ax6n?;57B`+ahc^@Hs5w?SG> z=AQ%7R=>jw`$fL{pP4S`!8u_HgXbuL90q?`le7QL4%@G40!*U}p00i_>zopr0E$FD A2LJ#7 literal 653 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Qftr;B4q#hkY{FXk-@5OE01 zcqabS;%DTugFK2W)+QUgdKcv%ZV@^;mcyLy^rks}%M%}$Sm~ZFy7KYsQxo6Q_Log! zZ8xRc5TJY9aj72-dPKB)ssJZXZjD8%~$y_`@H=o{(Wc8-2PNuFsHWQ z?x+91@2<`-%C4*Zspmg+f6hHSi*t56?DoeUd@lTb&D&=C%sTOB#}jt@3;j6zy#EgS zZ`&WTwgs&Bi&MTo3%@R3$XfGj573w-`8o5p^Y>L(CB&WX=PhJ9&MBi_Fz3JsV|*9q XJ!9$dB+Viel*~L`{an^LB{Ts5dekrr diff --git a/tests/test_results/SameSuite/apu/div_write_trigger.gb.png b/tests/test_results/SameSuite/apu/div_write_trigger.gb.png index 6338b9a902cce4984b85577cb1f0920290a70308..5ee42b547ecd9227c7f492d05a2611a5b5d20d30 100644 GIT binary patch literal 1908 zcmbW2Yh2P<8plP}z?v3I%}W-x)->jrm3d1=EE~hpyc9ZWWn-u8KxXv^Zh5;e{zhbAeF=M!X>^6y881AT0NT8JN8B1(Adj51=KYG zdwlrw?_tz$oK9HVp&DPlVS?0qj+UlQI$aLud950#5kbA3#2MFjN>5ZV%JGwHV9`hb zBW0q151KAf)a=DaQnbl3(^!1Ag<#qmuWskk1WxhLf*7Opc1J|5ox{~Rrb~OQMZM)? zas|cYX^~L&1JN`2bAky$@0lR!kX}*#sQ6Tsq#=n|geg`qB>~Q>qTwwsJzBR@6RJC5 zljn{t*IUBiX@#`#;;TWgT_3@}+Vn8yb4Fvk5t5*dWhJOxKazXb?I6PbRtq3`DQdiv z4tXX|>xabD05_@Ml~8cpcw%bf$kga+Sha2Bw(W_RYxjmKC2@UP=05oa>@M^11Ty| zT&^dwB^Bu71-N!VmdS|T5Fw;@fKji-!tQV*{Q5H}of8I9_gr%1u%sIBS^a{~oF#*~@#-u0Ch&gY5*r{N`j)MYSsWr@u=MH{zt z%v#C@Ts=8?UK_?GB2)V3>ng=~WHR+3+N!5i3f?DqAC)YSk8_OSlaRud_-y!G(=g!s_8cAq|K$hUd>HhnV|lQ_iu4z(TrwAM(e31%?gI4a4;!4A8u36<>T`sBg{b0} zRXj_GQ#M&+1ab+atlIskwj_veiukLq?8ritqvqPJGI_04%mYE6K?b;3OhLpg>ZUEt zQhU{5@cRX@i~*0l+OnLD5U7GzH7_NK9I6bY(C>?=`u`A-(~jezj z?wkhy*Xv>2onn!qEcK}-y>)$-h}2gDJS*^BLcI!MpLN~Vp?_SWwNm*ng2;qE>O->> zl*<9@st&CG*m{Evp%0IorneU-MD|6q0NN%oc3VInAs~A&SU>i}8c?w98ROnKk?nJm z{vN~>Mm~Jdo*z?l+0RKj%&|!X^2hCfnswvxR`23B##-a(#2JBD9BIx6LM6Wn21U4I zGGiJCN~6s!2(g(TVQ6y82V?dOnL}g)SWjB{D8V_};d}tD-*>Kpqt_)-&MVA={HlDI z=ioNR?tD##+-J3oc*5Cq(1Ti7Z#sA*Hh3Rl7-Fw@`^gByUFS(4f=9@PuD0@W(-vZ- zuW8Z{ya=Nwq2*IHBMn~N1N!^4>QBN69QhR_?~(~zwVS}pTvWH=bfny0-}p5S6OeRo z11UYAqBtISPn=)m!dB@>=aog>s2!DvRK@!!L2SyJ05j|(DCeI`3Jz7J;>N%^9t%y= zR$usc=fI%TWm`<_M8w_gc~2eI?bVQuFpFKdv*Vl&c{A-hR`7l$2x4B++f{|0kJ*dl zjZl!0YY|y4o{G)Qi*kd(Al&5j!n)2}rhyXh$8D#%FJ0@BG43*LYhd1XVX3i?-;p@g!C#~iL-hYbpcE98f8AGQcfGEOpoemIopg_$Ui0B+V(L<9Q2 zZ;^4c>sdx3oXwdBsOITrm6Bb5%JR!>femhI!8y^V`ypj@5Bzy+;Ua{sZZTskbfn-M zxNIw0*6>K&_|&Uy4F+1VZD?XaLyA>_#Il&Zp}f>Y<0OXnCb3VbuUF@rzVRmit!?bf zu)3jn+iRdb+WnYsLCM=W29)fr=G$mUznwpm);N#VKEGKTWqYl+aoQ5%-+k8jY~%m4 bK7zmdb{4`zC;l7wO^s0JLjve$<8uBBb&K4S literal 1695 zcmah~X;f3!7LK*%^2A)!SU`wD#YzQUkf}0+po~(PEZT%Y5=8QF0wQDN0>#J!WDu)NUD#=krOG^v&>UvHM_TD-Qi!jb6L0T zx4M2Cy@B2u^x?yS+ZAaYi`_+D*H6^VY>k9?qRgp}>D`8aFgZ&!e)0xM-7uoM+?Eg| zK8D{FA9JD7^0aS)`();PX7TcK1Ajy4N`RBZ2nbS?g0hq6v{+{>fIGkM;+r1~ujy|{ z^{fNiS-d~tZ0uJ~cz0#?v+~9vA?goqyPM7$H9PEBD*O0ybx!@m+mG*JAQZ0|S9LdQ zDUvfj;ZTuWliY_KKRUf$mJ*!o!QJK^BF~Ck^t0x}&)qO*ndJ{AZJpkp$qlXDKd>>Q zj7LLurf2S=apFgI0z+Z)60Dk(ei@U$Bo0r@+Dc&apDeCI%RK3fI^bc$J}cH_&B%Wj z;Jfq(*_UaPHo=c8Zmf!5KP1p@6tuP!i%#dSdHnfR>#6d@Lyjzs z`P!&viG|Ph!J}CI)ok69&u5LLsV}mG{iWjuhiYPe&!d0wjeM+#>|}zkif!}$=X?%> zdD{$>9ok^U9{~8WE^0r(3nQeoVDAyS8WoOarduZ%#EGejc}E`B^Q$VO7ju=mAoRVKXc6t94NY z4z10;`qsaN&TB=cMfgzXVf%d9J^OXY;_fJ_jsDui_bI*YSx{-`wO8w$X)Yp#_y0qQD#QU;SUN3azscsOZtJxBOkm9#r9CctsC^!bxxEG^n zfcWI;;AZY(d$cktw_nKf0u3%lAFyv?Zd;{@K3|*SfaU?+?#U{*^7Do+IxaU!Tab_R z#?}_#T~(H}Pz=HUk)AlV8s?BG-k6!N6!IVO*j0-B9YjtDB+Gl=kDv7u7EH^@4GS)` zIQ7TMe^1)lnqaW-JnrtAyERi5x%M=-s z2aUr{j0oPN(N8SP4s-gX{?cPu?PxM==SfI8qAjJkHcKZH(%knanJXWbWv=)J%S}Vi zTJ+JVn0mmATbyyKKx?tVh+A2N|FM~&F<=tI4Uyo-mO2ZND!YA?ojWUUS4etqJs3=K z;k^AZqUnw)n1nk<<5avCpI1r8DfK|)%Mv~Pq)R?g8WM4=BHb{4?Zc|zrHbW{VwK0Y z-i#0aGIlTf98)3kEa@3)0KwlK4Amsf3wF`>!NZAn#oq6WG@sxA@%y%Dd540*TSmkfvnZsqa5AGe=MdUk@)y#rT$Rzp+t-kOc7Pv!q7(RrLAcf+X3r+rpn zR~(ow6x!}K@x6%Z)w-y}7|m^Bi!MsnB;v4gM=zrF`k>c$8D+ea|56$?YUIdzlPJ)# z?g5WxsdXLmK(;ll()zzoFFk@PfZ!l${2gx-7wHDtFp!ODUV@Bv+#oe4a9yI zMF`F#`V>C7~;gH0m>mQGgr@u#|8|BJh`iomh diff --git a/tests/test_results/SameSuite/apu/div_write_trigger_10.gb.png b/tests/test_results/SameSuite/apu/div_write_trigger_10.gb.png index cb6b4821bb89a2d9f3e03f7f2a285c60c6140f83..c62355ca7be4ec9725c3ffb119d021ef84f5623d 100644 GIT binary patch literal 1857 zcmbVNZ8RHL8b%Q9(TNt-&d{*gN$Cfx*%lQ^#v+1JomSe=(ymg%8pc+TG$}fYMmlIs zQR#GQN)cOaq9O6IZBbKFA5E4LyY@4e@|=e_ql&wZZf+@h1= z=pEZX-)>@JvI7$waLTwpFxG7=OXEso#!*a6fL54*uTB$c7Vcjx6T4d9zz8mQk_wbC zpUTT*MLoLNe$OpO%u4Q=G4ogGn&)96?9!t#oSc=)tXOJH{Sbvo?89V)yGhCTWpe~L z*4xz~2TP~nMcXEA^~Cj`_&6{P?Y0?M0^QrD)X0WQulGi$tFsN{sz#rpvS$@t+a_{{ zXTH_U?)ql#bsmpLzLHPt6Jw!&d3SErwXP!dLx@|KEv;9$bJ|u`TH`n)UZSl)27gX0WM14TSI_{Byjlf$JuY;&zEztAVO>>CMADQ;+zpKA0T92Qzf5^F3$~amc1RAo&p~A z=$i-~imYw%d=_=JmRHA2AiW6VB$+Xw(+6@bu4x}0`XX%(fcqmj6M4@-S%1m|^|OE4 zk51@pJs9$D?j+^Cyg`S9i#q&vJOx^DM|Y9 z>{w2xf^!U863YilMtYN}=XsU)AEy^DBAB6Tl(JF2WZx;dPmin#4X<--tYDYi;(xxJ zpcQ7SS#WwNesGlnBNjW^ENVnTL{kxn@XD*;!6~(`%M9@Jxcy;rN>9fc<#r1P$(|&k z5I+}Pij*5#H8Ib97lYcHK*2O7g4wT4nJHhRK(H78EG*9F{Zh>bu-uQF1X*>~{m+6Q z6>6Up_Q>X@NGL^(?(Vp%pkicYd28+*O`ix{UraAu#xHC}^;<=VtNtJuy&fwbWaJ&i zlD>PKzOd&-;n?vYwNJJ!_%i!8Bz^!V~mvu=c@y`^5<)L*_VFYXS3d*rHoCp znv*}qXzN7;gwe)0M(T$Ffk0rxqoaK-l`hQEoy2hA1}lsTp+a5t9F74L)$&AV))PzX zBlQ?no^*K2hP?R<;r?I1{YP7aBG80X#%>xeqVj$h7Zm)-vGVy54e=kkLMIGLNI1fP zI+N4=oMzEN6uVaeHX#RtROP2Y_p+eZhXnd``Z2EjM z73-0u^(LbF&!|m-r}2|H?TYmUqdb$H#|MFuVg+Di@Az?$+iqs9yKl<{isz{p8w^>r)DWklZc%6*1LSBRWFz_%vx2!#-R>x4hTj9PE-$hKRC5oM7|>Qa z`y~C>sRlklo0Hf#3-D*;fqtO09Q~W$^Z^j~-MOsIN1ltOI--l7Qjdmn_nqum-Mi4n zcL`is>~2|v9H_{{1n)vjGO f8TS82z3=MUmUq;ap!I^-9p!tY?k}r zsYaCmgTMilbDoI$VPnf+pDI5g#`t_b1Jm>Qj4=+3p9+7)yTp{h58(r$yxZ6|MZ^&4 zg2){J_1N5yj@vhu0|Z{X86aLA3mLI|(d>tK4lUgzIN#ZMi7 z#k(X&27U}rGnm}f@OG1L13#9B4|dMWr|2GCK4gjYBsp&IWBHjg81Xm6;e(wEKG-=A zAM9PxRNqZLk$+FA2Ma*NACE`w3jP$HUURP8=84q%&~1u{F%9u~`anqM(H2h7NASsH zloKYpU-G$x(cbm0>-oX~^DZ?f$R%$n7e;1;nj{=sZs=y70D9H{@2Vc$dd+A{J@{^3 zJglwBZ(k3-Tig5ic(V`YJK{Qn8~DiGd3w#cfo;7b(iT2)dtM|)Ulh7s!{|Zi0mY&@ z0Y8NA`h2i>mPS2zMczDv%Mr2h&~harJ}?d+?0;M{eK5^+KIy@aD8`#!6BJEL6-JKVS(HDho*D!hzdO)#g z9)G|O;qCQc!$X$1ENXln_+EbE3`YD7arj{8n(2dSuJcI`ek_lAuya{{H|Z3`DU#&H z-I{a;*RR*^&RcwN{QEx*vCAYM+0vmmk~;wK{k*Z7#3!x@Ci$>T{q@s$iw{26-uf~y z9|2$0lj8*4dBY6O zbu2KUrW!xn}xc+6dno_^~|d!QK_S-~SwbFByD3ctPIcgU`0eUxBBH;D5KM zr|!<%pQ1^W>DB}XX5DHI0K9>J>&Hi_E#i8!;79SUem@wz7Ty=_T=;yja~}0z?~0rI zU;&8u2KCyzd3w#cn)V_-SRV*!k9zIhd@>p3go*9W^}&S$=3Qz|kWb!_;2cxGM3)oU z#OIj8iTEgf`|ru3$HjQh_e|{`hkp-tF3&z#Ea{)gZ|{S#mXu}re6WbqwkkhQ%zK?( zk|V3+lMfmcU%y^^H*fdBxn1TM-DQh<>hApZJ{WwN@A~*?Wt(q}63^p$*WgF-s0Tae z?eB|*wvcBZ3_dvU!O(?bcRiRM*j&CZS|28ld#(rPPFar8UH0&i>O_%H4}bRHg9|5= zcd1Fh96nkTtlLxS!FTgHrf{N{;@|p@j^tPukJIC5T%*3*8ix;dF8E+OFP8K*dHCQ9 z?Y^E_>cNLnnNRlOU6LbPgik)mP<#U)Pblwp*%rGgw{NxiS&3pf_ERh zJKy!TSrIJreCZQ$y=(BJcz=66*zmRB$$^5umACugpP!$m(Li$)`@U_KM=p7N&k!R4 zKb(gTb}snf$-DqW{QLV`Z>ouh51!0ZhN4T#NmUzE5Zj)<@w9Y4T`_k@Kx}^lU2E1+P9Ac z`|98&b0NXbg#X!7ZU7TNU(Du!On#QI~Nk{ aT>k-+X3dBmVg>*J0000tP&Rrtr#SYy<*^@MqOON!eBS!_{W|0Sdp_6i`!nsMzQ~U4 z+keR)$QD*uxtZ}@+3wBrKNe)?C--bz_gdm{amDiD{)+!8`|tN#KL4G)|9-q}{=c8k z%Z=+E6)dmK1u84Fkh%BXZ~66y1r_^W+X|F5#z;q%KqwhAlT z*Cf{c5;*kQ^0(lhr%Lh%pS?H9=l3`zccI1#NWW66KJeBw`dh;@{d4l~8$SPd{Ad2- zx8i==*PYFOeonT&eD2TZbN9at{&4c!_X;kv|ErfjxIgQ7wDzBA@0llUVpl1hZ2Q3M z#@mgy3x0Zk{?@SM4ddDEpO0HF0P<7rf$aD{!FIuW=Ax6n?;57B`+ahc^@Hs5w?SG> z=AQ%7R=>jw`$fL{pP4S`!8u_HgXbuL90q?`le7QL4%@G40!*U}p00i_>zopr0E$FD A2LJ#7 literal 653 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Qftr;B4q#hkY{FXk-@5OE01 zcqabS;%DTugFK2W)+QUgdKcv%ZV@^;mcyLy^rks}%M%}$Sm~ZFy7KYsQxo6Q_Log! zZ8xRc5TJY9aj72-dPKB)ssJZXZjD8%~$y_`@H=o{(Wc8-2PNuFsHWQ z?x+91@2<`-%C4*Zspmg+f6hHSi*t56?DoeUd@lTb&D&=C%sTOB#}jt@3;j6zy#EgS zZ`&WTwgs&Bi&MTo3%@R3$XfGj573w-`8o5p^Y>L(CB&WX=PhJ9&MBi_Fz3JsV|*9q XJ!9$dB+Viel*~L`{an^LB{Ts5dekrr diff --git a/tests/test_results/SameSuite/apu/div_write_trigger_volume_10.gb.png b/tests/test_results/SameSuite/apu/div_write_trigger_volume_10.gb.png index ccfcd887aa58296553c3c2c4aa50808a6d4db717..6067c133f0db135c4f51ee10e1d4db2265182b7e 100644 GIT binary patch literal 714 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62OE&=-tP&Rrtr#SYy<*^@MqOON!eBS!_{W|0Sdp_6i`!nsMzQ~U4 z+keR)$QD*uxtZ}@+3wBrKNe)?C--bz_gdm{amDiD{)+!8`|tN#KL4G)|9-q}{=c8k z%Z=+E6)dmK1u84Fkh%BXZ~66y1r_^W+X|F5#z;q%KqwhAlT z*Cf{c5;*kQ^0(lhr%Lh%pS?H9=l3`zccI1#NWW66KJeBw`dh;@{d4l~8$SPd{Ad2- zx8i==*PYFOeonT&eD2TZbN9at{&4c!_X;kv|ErfjxIgQ7wDzBA@0llUVpl1hZ2Q3M z#@mgy3x0Zk{?@SM4ddDEpO0HF0P<7rf$aD{!FIuW=Ax6n?;57B`+ahc^@Hs5w?SG> z=AQ%7R=>jw`$fL{pP4S`!8u_HgXbuL90q?`le7QL4%@G40!*U}p00i_>zopr0E$FD A2LJ#7 literal 653 zcmeAS@N?(olHy`uVBq!ia0vp^3xIe62NRHFxc>b*0|Qftr;B4q#hkY{FXk-@5OE01 zcqabS;%DTugFK2W)+QUgdKcv%ZV@^;mcyLy^rks}%M%}$Sm~ZFy7KYsQxo6Q_Log! zZ8xRc5TJY9aj72-dPKB)ssJZXZjD8%~$y_`@H=o{(Wc8-2PNuFsHWQ z?x+91@2<`-%C4*Zspmg+f6hHSi*t56?DoeUd@lTb&D&=C%sTOB#}jt@3;j6zy#EgS zZ`&WTwgs&Bi&MTo3%@R3$XfGj573w-`8o5p^Y>L(CB&WX=PhJ9&MBi_Fz3JsV|*9q XJ!9$dB+Viel*~L`{an^LB{Ts5dekrr diff --git a/tests/test_results/blargg.json b/tests/test_results/blargg.json index 67385b2d1..8b2e1c0bd 100644 --- a/tests/test_results/blargg.json +++ b/tests/test_results/blargg.json @@ -20,10 +20,10 @@ "blargg/dmg_sound/rom_singles/06-overflow on trigger.gb": "06-overflow on trigger\n\n7FFF 7FFF 7FFF 7FFF 7FFF 7FFF 7FFF \n8D7112A4 \nFailed\n", "blargg/dmg_sound/rom_singles/07-len sweep period sync.gb": "07-len sweep period sync\n\n\nLength period is wrong\n\nFailed #2\n", "blargg/dmg_sound/rom_singles/08-len ctr during power.gb": "08-len ctr during power\n\n00 00 00 00 2144DF1C \nFailed\n", - "blargg/dmg_sound/rom_singles/09-wave read while on.gb": "09-wave read while on\n\n55 33 11 00 00 FF FF 00 11 11 33 88 BB CC 44 55 BB 11 DD DD 44 33 BB BB DD 77 11 CC CC 33 33 00 EE CC BB 88 77 77 77 88 99 BB DD 00 33 77 BB 00 55 DD 33 AA 99 11 99 22 BB 55 FF AA 55 11 DD 77 44 22 00 11 22 0652FAE5 \nFailed\n", + "blargg/dmg_sound/rom_singles/09-wave read while on.gb": "09-wave read while on\n\n88 33 11 00 FF FF FF 00 11 44 66 99 CC DD 55 AA AA FF 55 22 99 AA AA 33 CC 66 77 CC CC 33 FF CC 99 99 55 55 33 33 33 44 55 77 CC FF 22 66 CC 33 EE 44 11 88 FF 77 FF 88 11 BB 55 00 BB 33 CC 99 88 44 22 00 FF D075E68F \nFailed\n", "blargg/dmg_sound/rom_singles/10-wave trigger while on.gb": "10-wave trigger while on\n\n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99", "blargg/dmg_sound/rom_singles/11-regs after power.gb": "11-regs after power\n\n\nPowering off should clear NR13\n\nFailed #3\n", - "blargg/dmg_sound/rom_singles/12-wave write while on.gb": "12-wave write while on\n\n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 F7 44 55 66 77 88 99 AA BB CC DD EE FF \n00 F7 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \nF7 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 A", + "blargg/dmg_sound/rom_singles/12-wave write while on.gb": "12-wave write while on\n\n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 F7 55 66 77 88 99 AA BB CC DD EE FF \n00 F7 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \nF7 11 22 33 44 55 66 77 88 99 A", "blargg/instr_timing/instr_timing.gb": "instr_timing\n\n\nPassed\n", "blargg/interrupt_time/interrupt_time.gb": "interrupt time\n\n00 00 FC \n00 08 04 \n00 00 FC \n00 08 04 \n550B72D0 \nFailed\n", "blargg/mem_timing/individual/01-read_timing.gb": "01-read_timing\n\n\nPassed\n", @@ -52,7 +52,7 @@ "blargg/cgb_sound/rom_singles/06-overflow on trigger.gb": "06-overflow on trigger\n\n7FFF 7FFF 7FFF 7FFF 7FFF 7FFF 7FFF \n8D7112A4 \nFailed\n", "blargg/cgb_sound/rom_singles/07-len sweep period sync.gb": "07-len sweep period sync\n\n\nLength period is wrong\n\nFailed #2\n", "blargg/cgb_sound/rom_singles/08-len ctr during power.gb": "08-len ctr during power\n\n00 00 00 00 2144DF1C \nFailed\n", - "blargg/cgb_sound/rom_singles/09-wave read while on.gb": "09-wave read while on\n\n55 33 11 22 22 11 22 33 44 66 66 BB EE 22 22 77 11 77 88 55 CC CC CC 55 55 88 88 22 88 44 55 EE FF DD CC 99 99 88 88 AA BB DD 22 55 AA EE 22 77 CC 22 88 66 DD DD 55 EE 77 BB 00 66 11 DD 66 33 00 00 DD CC DD CCD5FE43 \nFailed\n", + "blargg/cgb_sound/rom_singles/09-wave read while on.gb": "09-wave read while on\n\n55 33 11 11 00 FF FF FF 00 33 55 88 99 DD 11 AA AA 55 BB 22 99 11 11 99 22 BB FF AA 55 11 11 AA 77 77 66 33 22 22 22 33 44 66 88 BB EE 22 66 BB 00 88 55 CC 33 BB 33 CC 77 11 BB 11 CC 88 44 11 EE CC AA 99 AA B7836723 \nFailed\n", "blargg/cgb_sound/rom_singles/10-wave trigger while on.gb": "10-wave trigger while on\n\n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 55 66 77 88 99", "blargg/cgb_sound/rom_singles/11-regs after power.gb": "11-regs after power\n\n\nPowering off should clear NR13\n\nFailed #3\n", "blargg/cgb_sound/rom_singles/12-wave.gb": "12-wave\n\n\nTimer period or phase resetting is wrong\n\nFailed #2\n" From 3451731fd72ee7f317d310751f6b64c63d34d9cc Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Thu, 26 Sep 2024 16:28:54 +0200 Subject: [PATCH 19/22] Saving Blargg interrupt time results as they depend on sound, and are still wrong --- tests/test_results/blargg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_results/blargg.json b/tests/test_results/blargg.json index 8b2e1c0bd..3a2ef5e18 100644 --- a/tests/test_results/blargg.json +++ b/tests/test_results/blargg.json @@ -25,7 +25,7 @@ "blargg/dmg_sound/rom_singles/11-regs after power.gb": "11-regs after power\n\n\nPowering off should clear NR13\n\nFailed #3\n", "blargg/dmg_sound/rom_singles/12-wave write while on.gb": "12-wave write while on\n\n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 44 F7 66 77 88 99 AA BB CC DD EE FF \n00 11 22 33 F7 55 66 77 88 99 AA BB CC DD EE FF \n00 F7 22 33 44 55 66 77 88 99 AA BB CC DD EE FF \nF7 11 22 33 44 55 66 77 88 99 A", "blargg/instr_timing/instr_timing.gb": "instr_timing\n\n\nPassed\n", - "blargg/interrupt_time/interrupt_time.gb": "interrupt time\n\n00 00 FC \n00 08 04 \n00 00 FC \n00 08 04 \n550B72D0 \nFailed\n", + "blargg/interrupt_time/interrupt_time.gb": "interrupt time\n\n00 00 00 \n00 08 08 \n00 00 00 \n00 08 08 \n5DDD9187 \nFailed\n", "blargg/mem_timing/individual/01-read_timing.gb": "01-read_timing\n\n\nPassed\n", "blargg/mem_timing/individual/02-write_timing.gb": "02-write_timing\n\n\nPassed\n", "blargg/mem_timing/individual/03-modify_timing.gb": "03-modify_timing\n\n\nPassed\n", From 64598396dce26c17e80422b061045d8611d4a236 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Thu, 26 Sep 2024 16:30:30 +0200 Subject: [PATCH 20/22] Saving Pokemon Pinball test even though it broke because of timing changes --- tests/test_game_wrapper_pokemon_pinball.py | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/test_game_wrapper_pokemon_pinball.py b/tests/test_game_wrapper_pokemon_pinball.py index bc693f647..c5f142111 100644 --- a/tests/test_game_wrapper_pokemon_pinball.py +++ b/tests/test_game_wrapper_pokemon_pinball.py @@ -67,37 +67,37 @@ def test_pokemon_catch_mode(pokemon_pinball_rom): pokemon_pinball.start_game(stage=Stage.RED_BOTTOM, timer_div=0x00) pyboy.button_press("a") pyboy.button_press("left") - pyboy.tick(50) + pyboy.tick(50, False) pokemon_pinball.start_catch_mode() - pyboy.tick(270) + pyboy.tick(270, False) pyboy.button_release("left") pyboy.button_release("a") pyboy.button("select") - pyboy.tick(20) + pyboy.tick(20, False) pyboy.button_press("left") pyboy.button_press("a") - pyboy.tick(500) + pyboy.tick(500, False) pyboy.button_release("left") - pyboy.tick(21) + pyboy.tick(21, False) pyboy.button_press("left") - pyboy.tick(100) + pyboy.tick(100, False) pyboy.button_release("a") - pyboy.tick(31) + pyboy.tick(31, False) pyboy.button_press("a") - pyboy.tick(200) + pyboy.tick(200, False) pyboy.button_release("left") - pyboy.tick(31) + pyboy.tick(31, False) pyboy.button_press("left") - pyboy.tick(200) + pyboy.tick(200, False) pyboy.button_release("left") - pyboy.tick(31) + pyboy.tick(31, False) pyboy.button_press("left") - pyboy.tick(400) + pyboy.tick(400, False) # NOTE: This sequence broke because of changed instruction timings - assert pokemon_pinball.score == 15635100 - assert pokemon_pinball.has_pokemon(Pokemon.BULBASAUR) - assert pokemon_pinball.has_pokemon(Pokemon.CHARMANDER) == False - assert pokemon_pinball.get_unique_pokemon_caught() == 1 + assert pokemon_pinball.score == 9030100 + assert not pokemon_pinball.has_pokemon(Pokemon.BULBASAUR) + assert not pokemon_pinball.has_pokemon(Pokemon.CHARMANDER) + assert pokemon_pinball.get_unique_pokemon_caught() == 0 pyboy.stop(False) From a6a895a21e498eabade1caac30be0cb53ec83284 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Thu, 26 Sep 2024 16:40:01 +0200 Subject: [PATCH 21/22] Saving Tetris example as timings (and randomness) have changed --- extras/examples/gamewrapper_tetris.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/examples/gamewrapper_tetris.py b/extras/examples/gamewrapper_tetris.py index f0cb1a4e3..a419cf26c 100644 --- a/extras/examples/gamewrapper_tetris.py +++ b/extras/examples/gamewrapper_tetris.py @@ -29,7 +29,7 @@ tetris.start_game(timer_div=0x00) # The timer_div works like a random seed in Tetris tetromino_at_0x00 = tetris.next_tetromino() -assert tetromino_at_0x00 == "Z", tetris.next_tetromino() +assert tetromino_at_0x00 == "O", tetris.next_tetromino() assert tetris.score == 0 assert tetris.level == 0 assert tetris.lines == 0 From 44630cb40b6a61bc8d90052de4f6fcde02a61329 Mon Sep 17 00:00:00 2001 From: Mads Ynddal Date: Mon, 30 Sep 2024 22:07:56 +0200 Subject: [PATCH 22/22] Update docs --- docs/index.html | 46 +++++++++++++++++++++++++++------------------- docs/utils.html | 2 +- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/docs/index.html b/docs/index.html index 84ecba16e..2ffd7ce4d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -230,9 +230,8 @@

Kwargs

raise KeyError(f"Unknown keyword argument: {k}") # Performance measures - self.avg_pre = 0 self.avg_tick = 0 - self.avg_post = 0 + self.avg_emu = 0 # Absolute frame count of the emulation self.frame_count = 0 @@ -448,9 +447,7 @@

Kwargs

if self.stopped: return False - t_start = time.perf_counter_ns() self._handle_events(self.events) - t_pre = time.perf_counter_ns() if not self.paused: self.gameshark.tick() self.__rendering(render) @@ -477,18 +474,7 @@

Kwargs

self.mb.breakpoint_singlestep = self.mb.breakpoint_singlestep_latch self.frame_count += 1 - t_tick = time.perf_counter_ns() - self._post_tick() - t_post = time.perf_counter_ns() - - nsecs = t_pre - t_start - self.avg_pre = 0.9 * self.avg_pre + (0.1*nsecs/1_000_000_000) - - nsecs = t_tick - t_pre - self.avg_tick = 0.9 * self.avg_tick + (0.1*nsecs/1_000_000_000) - - nsecs = t_post - t_tick - self.avg_post = 0.9 * self.avg_post + (0.1*nsecs/1_000_000_000) + self._post_handle_events() return not self.quitting @@ -537,11 +523,22 @@

Kwargs

False if emulation has ended otherwise True """ + _count = count running = False + t_start = time.perf_counter_ns() while count != 0: _render = render and count == 1 # Only render on last tick to improve performance running = self._tick(_render) count -= 1 + t_tick = time.perf_counter_ns() + self._post_tick() + t_post = time.perf_counter_ns() + + if _count > 0: + nsecs = t_tick - t_start + self.avg_tick = 0.9 * (self.avg_tick / _count) + (0.1*nsecs/1_000_000_000) + nsecs = t_post - t_start + self.avg_emu = 0.9 * (self.avg_emu / _count) + (0.1*nsecs/1_000_000_000) return running def _handle_events(self, events): @@ -608,6 +605,7 @@

Kwargs

self._plugin_manager.post_tick() self._plugin_manager.frame_limiter(self.target_emulationspeed) + def _post_handle_events(self): # Prepare an empty list, as the API might be used to send in events between ticks self.events = [] while self.queued_input and self.frame_count == self.queued_input[0][0]: @@ -615,9 +613,8 @@

Kwargs

self.events.append(WindowEvent(_event)) def _update_window_title(self): - avg_emu = self.avg_pre + self.avg_tick + self.avg_post - self.window_title = f"CPU/frame: {(self.avg_pre + self.avg_tick) / SPF * 100:0.2f}%" - self.window_title += f' Emulation: x{(round(SPF / avg_emu) if avg_emu > 0 else "INF")}' + self.window_title = f"CPU/frame: {(self.avg_tick) / SPF * 100:0.2f}%" + self.window_title += f' Emulation: x{(round(SPF / self.avg_emu) if self.avg_emu > 0 else "INF")}' if self.paused: self.window_title += "[PAUSED]" self.window_title += self._plugin_manager.window_title() @@ -1608,11 +1605,22 @@

Returns

False if emulation has ended otherwise True """ + _count = count running = False + t_start = time.perf_counter_ns() while count != 0: _render = render and count == 1 # Only render on last tick to improve performance running = self._tick(_render) count -= 1 + t_tick = time.perf_counter_ns() + self._post_tick() + t_post = time.perf_counter_ns() + + if _count > 0: + nsecs = t_tick - t_start + self.avg_tick = 0.9 * (self.avg_tick / _count) + (0.1*nsecs/1_000_000_000) + nsecs = t_post - t_start + self.avg_emu = 0.9 * (self.avg_emu / _count) + (0.1*nsecs/1_000_000_000) return running diff --git a/docs/utils.html b/docs/utils.html index d9aadd879..9aa5fa6ff 100644 --- a/docs/utils.html +++ b/docs/utils.html @@ -32,7 +32,7 @@

Module pyboy.utils

__all__ = ["WindowEvent", "dec_to_bcd", "bcd_to_dec"] -STATE_VERSION = 11 +STATE_VERSION = 12 ############################################################## # Buffer classes