Skip to content

Commit 41ecc70

Browse files
authored
Merge pull request #41 from eddmann/revert-40-claude/debug-gameboy-color-support-011CUzoWrkXWefs3zDCjKPsP
Revert "fix: enable Game Boy Color mode when loading CGB ROMs"
2 parents 194ddc2 + b205a11 commit 41ecc70

8 files changed

Lines changed: 30 additions & 173 deletions

File tree

src/Cpu/Cpu.php

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Gb\Cpu\Register\FlagRegister;
99
use Gb\Cpu\Register\Register16;
1010
use Gb\Interrupts\InterruptController;
11-
use Gb\System\CgbController;
1211

1312
/**
1413
* LR35902 CPU (Sharp SM83)
@@ -46,9 +45,6 @@ final class Cpu
4645
private int $pendingCycles = 0;
4746
private ?\Closure $cycleCallback = null;
4847

49-
// CGB controller for speed switching (optional, only needed for CGB)
50-
private ?CgbController $cgbController = null;
51-
5248
/**
5349
* @param BusInterface $bus Memory bus for reading/writing memory
5450
* @param InterruptController $interruptController Interrupt controller
@@ -458,36 +454,6 @@ public function setStopped(bool $stopped): void
458454
$this->stopped = $stopped;
459455
}
460456

461-
/**
462-
* Set the CGB controller for speed switching support.
463-
*
464-
* @param CgbController $cgbController CGB controller instance
465-
*/
466-
public function setCgbController(CgbController $cgbController): void
467-
{
468-
$this->cgbController = $cgbController;
469-
}
470-
471-
/**
472-
* Execute STOP instruction.
473-
* In CGB mode with speed switch prepared, triggers speed switch.
474-
* Otherwise, stops the CPU until button press.
475-
*/
476-
public function executeStop(): void
477-
{
478-
// Check if CGB speed switch is prepared
479-
if ($this->cgbController !== null && $this->cgbController->isSpeedSwitchPrepared()) {
480-
// Trigger speed switch (toggles between normal and double speed)
481-
$this->cgbController->triggerSpeedSwitch();
482-
// Don't stop the CPU - execution continues at new speed
483-
$this->stopped = false;
484-
} else {
485-
// Normal STOP behavior: halt and stop until button press
486-
$this->halted = true;
487-
$this->stopped = true;
488-
}
489-
}
490-
491457
/**
492458
* Get the Interrupt Master Enable flag.
493459
*

src/Cpu/InstructionSet.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ private static function buildInstruction(int $opcode): Instruction
371371
},
372372
),
373373

374-
// 0x10: STOP - Stop CPU and LCD until button press (or trigger speed switch in CGB)
374+
// 0x10: STOP - Stop CPU and LCD until button press
375375
0x10 => new Instruction(
376376
opcode: 0x10,
377377
mnemonic: 'STOP',
@@ -380,8 +380,8 @@ private static function buildInstruction(int $opcode): Instruction
380380
handler: static function (Cpu $cpu): int {
381381
// Read next byte (should be 0x00)
382382
self::readImm8($cpu);
383-
// Execute STOP - handles both speed switching and normal stop
384-
$cpu->executeStop();
383+
$cpu->setHalted(true);
384+
$cpu->setStopped(true);
385385
return 4;
386386
},
387387
),

src/Emulator.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,6 @@ private function initializeSystem(): void
131131
$this->interruptController
132132
);
133133

134-
// Enable CGB mode if cartridge supports it
135-
if ($this->cartridge->getHeader()->isCgbSupported()) {
136-
$this->ppu->enableCgbMode(true);
137-
}
138-
139134
// Create APU
140135
$this->apu = new Apu($this->audioSink);
141136

@@ -182,11 +177,8 @@ private function initializeSystem(): void
182177
// HDMA registers: HDMA1-HDMA5
183178
$this->bus->attachIoDevice($this->hdma, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55);
184179

185-
// Connect HDMA to PPU for H-Blank triggers
186-
$this->ppu->setHdmaController($this->hdma);
187-
188180
// Create CGB controller
189-
$this->cgb = new CgbController($vram, $wram);
181+
$this->cgb = new CgbController($vram);
190182
// CGB registers: KEY1, VBK, RP, SVBK
191183
$this->bus->attachIoDevice($this->cgb, 0xFF4D, 0xFF4F, 0xFF56, 0xFF70);
192184

@@ -205,9 +197,6 @@ private function initializeSystem(): void
205197
// Create CPU
206198
$this->cpu = new Cpu($this->bus, $this->interruptController);
207199

208-
// Set CGB controller on CPU for speed switching support
209-
$this->cpu->setCgbController($this->cgb);
210-
211200
// Optimization (Step 14): Pre-build all 512 instructions for faster dispatch
212201
// Expected: 1-2% performance gain by eliminating lazy initialization checks
213202
\Gb\Cpu\InstructionSet::warmCache();

src/Memory/Wram.php

Lines changed: 9 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,17 @@
1313
* In DMG mode: Single 8KB bank
1414
* In CGB mode: Bank 0 (0xC000-0xCFFF) + switchable banks 1-7 (0xD000-0xDFFF)
1515
*
16-
* CGB WRAM: 32KB (8 banks of 4KB each)
17-
* - Bank 0: Always at 0xC000-0xCFFF
18-
* - Banks 1-7: Switchable at 0xD000-0xDFFF via SVBK register
16+
* For now, implements DMG-style 8KB WRAM. CGB bank switching will be added later.
1917
*/
2018
final class Wram implements DeviceInterface
2119
{
22-
/** @var array<int, array<int, int>> Working RAM storage (8 banks × 4KB) */
23-
private array $banks;
24-
25-
/** @var int Currently selected bank for 0xD000-0xDFFF (1-7, defaults to 1) */
26-
private int $currentBank = 1;
20+
/** @var array<int, int> Working RAM storage (8KB = 8192 bytes) */
21+
private array $ram;
2722

2823
public function __construct()
2924
{
30-
// Initialize 8 banks of 4KB each with 0x00
31-
$this->banks = [];
32-
for ($bank = 0; $bank < 8; $bank++) {
33-
$this->banks[$bank] = array_fill(0, 4096, 0x00);
34-
}
25+
// Initialize 8KB of RAM with 0x00
26+
$this->ram = array_fill(0, 8192, 0x00);
3527
}
3628

3729
/**
@@ -42,16 +34,8 @@ public function __construct()
4234
*/
4335
public function readByte(int $address): int
4436
{
45-
$offset = $address & 0x1FFF;
46-
47-
if ($offset < 0x1000) {
48-
// 0xC000-0xCFFF: Always bank 0
49-
return $this->banks[0][$offset];
50-
} else {
51-
// 0xD000-0xDFFF: Switchable bank (1-7)
52-
$bankOffset = $offset - 0x1000;
53-
return $this->banks[$this->currentBank][$bankOffset];
54-
}
37+
$offset = $address & 0x1FFF; // Mask to 8KB
38+
return $this->ram[$offset];
5539
}
5640

5741
/**
@@ -62,37 +46,7 @@ public function readByte(int $address): int
6246
*/
6347
public function writeByte(int $address, int $value): void
6448
{
65-
$offset = $address & 0x1FFF;
66-
$value = $value & 0xFF;
67-
68-
if ($offset < 0x1000) {
69-
// 0xC000-0xCFFF: Always bank 0
70-
$this->banks[0][$offset] = $value;
71-
} else {
72-
// 0xD000-0xDFFF: Switchable bank (1-7)
73-
$bankOffset = $offset - 0x1000;
74-
$this->banks[$this->currentBank][$bankOffset] = $value;
75-
}
76-
}
77-
78-
/**
79-
* Set the current WRAM bank (CGB only, controlled by SVBK register).
80-
*
81-
* @param int $bank Bank number (0-7, where 0 is treated as 1)
82-
*/
83-
public function setBank(int $bank): void
84-
{
85-
// Bank 0 is treated as bank 1 (banks 1-7 are valid)
86-
$this->currentBank = ($bank & 0x07) === 0 ? 1 : ($bank & 0x07);
87-
}
88-
89-
/**
90-
* Get the current WRAM bank number.
91-
*
92-
* @return int Current bank (1-7)
93-
*/
94-
public function getBank(): int
95-
{
96-
return $this->currentBank;
49+
$offset = $address & 0x1FFF; // Mask to 8KB
50+
$this->ram[$offset] = $value & 0xFF;
9751
}
9852
}

src/Ppu/ColorPalette.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,8 @@ final class ColorPalette
4242
public function __construct()
4343
{
4444
// Initialize palettes with white (0x7FFF = all 1s in 15-bit RGB)
45-
// Each color is 2 bytes: low byte (0xFF), high byte (0x7F)
46-
$this->bgPalette = [];
47-
$this->objPalette = [];
48-
for ($i = 0; $i < 64; $i += 2) {
49-
$this->bgPalette[$i] = 0xFF; // Low byte
50-
$this->bgPalette[$i + 1] = 0x7F; // High byte
51-
$this->objPalette[$i] = 0xFF; // Low byte
52-
$this->objPalette[$i + 1] = 0x7F; // High byte
53-
}
45+
$this->bgPalette = array_fill(0, 64, 0xFF);
46+
$this->objPalette = array_fill(0, 64, 0xFF);
5447
}
5548

5649
/**

src/Ppu/Ppu.php

Lines changed: 13 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Gb\Ppu;
66

77
use Gb\Bus\DeviceInterface;
8-
use Gb\Dma\HdmaController;
98
use Gb\Interrupts\InterruptController;
109
use Gb\Interrupts\InterruptType;
1110
use Gb\Memory\Vram;
@@ -98,19 +97,12 @@ final class Ppu implements DeviceInterface
9897
/** @var array<int, int> */
9998
private array $bgColorBuffer = [];
10099

101-
// Background priority buffer for CGB priority rules (stores BG-to-OAM priority bit)
102-
/** @var array<int, bool> */
103-
private array $bgPriorityBuffer = [];
104-
105100
/** @var ColorPalette Color palette system (CGB) */
106101
private readonly ColorPalette $colorPalette;
107102

108103
/** @var bool CGB mode enabled */
109104
private bool $cgbMode = false;
110105

111-
/** @var HdmaController|null HDMA controller for H-Blank DMA transfers (CGB) */
112-
private ?HdmaController $hdmaController = null;
113-
114106
public function __construct(
115107
private readonly Vram $vram,
116108
private readonly Oam $oam,
@@ -217,11 +209,6 @@ private function setMode(PpuMode $mode): void
217209
// Update STAT register mode bits
218210
$this->stat = ($this->stat & ~self::STAT_MODE_MASK) | $mode->getStatBits();
219211

220-
// Trigger HDMA H-Blank transfer if entering H-Blank mode
221-
if ($mode === PpuMode::HBlank && $this->hdmaController !== null) {
222-
$this->hdmaController->onHBlank();
223-
}
224-
225212
// Trigger STAT interrupt if enabled for this mode
226213
$statInterrupt = match ($mode) {
227214
PpuMode::HBlank => ($this->stat & self::STAT_MODE0_INT) !== 0,
@@ -254,7 +241,6 @@ private function renderScanline(): void
254241
// Initialize scanline buffer and BG color buffer
255242
$this->scanlineBuffer = array_fill(0, ArrayFramebuffer::WIDTH, Color::fromDmgShade(0));
256243
$this->bgColorBuffer = array_fill(0, ArrayFramebuffer::WIDTH, 0);
257-
$this->bgPriorityBuffer = array_fill(0, ArrayFramebuffer::WIDTH, false);
258244

259245
// Render layers
260246
if (($this->lcdc & self::LCDC_BG_WINDOW_ENABLE) !== 0) {
@@ -301,7 +287,6 @@ private function renderBackground(): void
301287
$vramBank = ($attributes & 0x08) !== 0 ? 1 : 0; // Bit 3: VRAM bank
302288
$xFlip = ($attributes & 0x20) !== 0; // Bit 5: horizontal flip
303289
$yFlip = ($attributes & 0x40) !== 0; // Bit 6: vertical flip
304-
$bgPriority = ($attributes & 0x80) !== 0; // Bit 7: BG-to-OAM priority
305290

306291
// Apply flips
307292
$finalTileY = $yFlip ? (7 - $tileY) : $tileY;
@@ -314,9 +299,8 @@ private function renderBackground(): void
314299
// Get pixel color
315300
$color = $this->getTilePixel($vramData, $tileDataAddr, $finalTileX, $finalTileY);
316301

317-
// Store raw color and priority for sprite priority checking
302+
// Store raw color for sprite priority checking
318303
$this->bgColorBuffer[$x] = $color;
319-
$this->bgPriorityBuffer[$x] = $bgPriority;
320304

321305
// Apply palette
322306
if ($this->cgbMode) {
@@ -362,7 +346,6 @@ private function renderWindow(): void
362346
$vramBank = ($attributes & 0x08) !== 0 ? 1 : 0; // Bit 3: VRAM bank
363347
$xFlip = ($attributes & 0x20) !== 0; // Bit 5: horizontal flip
364348
$yFlip = ($attributes & 0x40) !== 0; // Bit 6: vertical flip
365-
$bgPriority = ($attributes & 0x80) !== 0; // Bit 7: BG-to-OAM priority
366349

367350
// Apply flips
368351
$finalTileY = $yFlip ? (7 - $tileY) : $tileY;
@@ -374,9 +357,8 @@ private function renderWindow(): void
374357

375358
$color = $this->getTilePixel($vramData, $tileDataAddr, $finalTileX, $finalTileY);
376359

377-
// Store raw color and priority for sprite priority checking
360+
// Store raw color for sprite priority checking
378361
$this->bgColorBuffer[$x] = $color;
379-
$this->bgPriorityBuffer[$x] = $bgPriority;
380362

381363
// Apply palette
382364
if ($this->cgbMode) {
@@ -484,17 +466,9 @@ private function renderSprite(array $sprite, int $spriteHeight, array $vramData)
484466
}
485467

486468
// Check priority (behind BG)
487-
$bgColor = $this->bgColorBuffer[$pixelX];
488-
if ($bgColor !== 0) {
489-
// In CGB mode, check BG priority bit first
490-
if ($this->cgbMode && $this->bgPriorityBuffer[$pixelX]) {
491-
// BG priority bit is set - BG always wins
492-
continue;
493-
}
494-
// Otherwise, use normal sprite priority (behindBg flag)
495-
if ($behindBg) {
496-
continue;
497-
}
469+
if ($behindBg && $this->bgColorBuffer[$pixelX] !== 0) {
470+
// If BG pixel is not color 0, sprite is hidden behind BG
471+
continue;
498472
}
499473

500474
if ($this->cgbMode) {
@@ -562,14 +536,6 @@ public function isCgbMode(): bool
562536
return $this->cgbMode;
563537
}
564538

565-
/**
566-
* Set the HDMA controller for H-Blank DMA transfers.
567-
*/
568-
public function setHdmaController(HdmaController $hdmaController): void
569-
{
570-
$this->hdmaController = $hdmaController;
571-
}
572-
573539
// DeviceInterface implementation for I/O registers
574540
public function readByte(int $address): int
575541
{
@@ -585,11 +551,10 @@ public function readByte(int $address): int
585551
self::OBP1 => $this->obp1,
586552
self::WY => $this->wy,
587553
self::WX => $this->wx,
588-
// CGB color palette registers - only accessible in CGB mode
589-
self::BCPS => $this->cgbMode ? $this->colorPalette->readBgIndex() : 0xFF,
590-
self::BCPD => $this->cgbMode ? $this->colorPalette->readBgData() : 0xFF,
591-
self::OCPS => $this->cgbMode ? $this->colorPalette->readObjIndex() : 0xFF,
592-
self::OCPD => $this->cgbMode ? $this->colorPalette->readObjData() : 0xFF,
554+
self::BCPS => $this->colorPalette->readBgIndex(),
555+
self::BCPD => $this->colorPalette->readBgData(),
556+
self::OCPS => $this->colorPalette->readObjIndex(),
557+
self::OCPD => $this->colorPalette->readObjData(),
593558
default => 0xFF,
594559
};
595560
}
@@ -608,11 +573,10 @@ public function writeByte(int $address, int $value): void
608573
self::OBP1 => $this->obp1 = $value,
609574
self::WY => $this->wy = $value,
610575
self::WX => $this->wx = $value,
611-
// CGB color palette registers - only writable in CGB mode
612-
self::BCPS => $this->cgbMode ? $this->colorPalette->writeBgIndex($value) : null,
613-
self::BCPD => $this->cgbMode ? $this->colorPalette->writeBgData($value) : null,
614-
self::OCPS => $this->cgbMode ? $this->colorPalette->writeObjIndex($value) : null,
615-
self::OCPD => $this->cgbMode ? $this->colorPalette->writeObjData($value) : null,
576+
self::BCPS => $this->colorPalette->writeBgIndex($value),
577+
self::BCPD => $this->colorPalette->writeBgData($value),
578+
self::OCPS => $this->colorPalette->writeObjIndex($value),
579+
self::OCPD => $this->colorPalette->writeObjData($value),
616580
default => null,
617581
};
618582

0 commit comments

Comments
 (0)