summaryrefslogtreecommitdiffstats
path: root/src/LcdController.php
diff options
context:
space:
mode:
authorGabriel Rodrigues Couto <gabrielrcouto@gmail.com>2016-07-02 23:18:46 -0300
committerGabriel Rodrigues Couto <gabrielrcouto@gmail.com>2016-07-02 23:18:46 -0300
commit89e12a4415c38e04631747b4bc6103e0a64b1e8b (patch)
tree55f847a5cd1af60a86850968affb95607611bb7d /src/LcdController.php
parentadffbf649de03cbb83b2cdc09559f45c567e42c2 (diff)
downloadphp-terminal-gameboy-emulator-origin/master.zip
php-terminal-gameboy-emulator-origin/master.tar.gz
php-terminal-gameboy-emulator-origin/master.tar.bz2
Some functions moved to LcdControllerHEADorigin/masterorigin/HEADmaster
TerminalCanvas refactored, removed Drawille dependency, implemented a faster braille render. Thank you @whatthejeff for the inspiration :-) Little FPS gain #46
Diffstat (limited to 'src/LcdController.php')
-rw-r--r--src/LcdController.php164
1 files changed, 132 insertions, 32 deletions
diff --git a/src/LcdController.php b/src/LcdController.php
index 5501465..9e2015d 100644
--- a/src/LcdController.php
+++ b/src/LcdController.php
@@ -4,13 +4,74 @@ namespace GameBoy;
class LcdController
{
+ //Actual scan line...
+ public $actualScanLine = 0;
+
protected $core;
+ //Is the emulated LCD controller on?
+ public $LCDisOn = false;
+
+ //Should we trigger an interrupt if LY==LYC?
+ public $LYCMatchTriggerSTAT = false;
+
+ //The scan line mode (for lines 1-144 it's 2-3-0, for 145-154 it's 1)
+ public $modeSTAT = 0;
+
+ //Should we trigger an interrupt if in mode 0?
+ public $mode0TriggerSTAT = false;
+
+ //Should we trigger an interrupt if in mode 1?
+ public $mode1TriggerSTAT = false;
+
+ //Should we trigger an interrupt if in mode 2?
+ public $mode2TriggerSTAT = false;
+
+ //Tracker for STAT triggering.
+ public $STATTracker = 0;
+
public function __construct($core)
{
$this->core = $core;
}
+ public function matchLYC()
+ {
+ // LY - LYC Compare
+ // If LY==LCY
+ if ($this->core->memory[0xFF44] == $this->core->memory[0xFF45]) {
+ $this->core->memory[0xFF41] |= 0x04; // set STAT bit 2: LY-LYC coincidence flag
+ if ($this->LYCMatchTriggerSTAT) {
+ $this->core->memory[0xFF0F] |= 0x2; // set IF bit 1
+ }
+ } else {
+ $this->core->memory[0xFF41] &= 0xFB; // reset STAT bit 2 (LY!=LYC)
+ }
+ }
+
+ public function notifyScanline()
+ {
+ if ($this->actualScanLine == 0) {
+ $this->core->windowSourceLine = 0;
+ }
+ // determine the left edge of the window (160 if window is inactive)
+ $windowLeft = ($this->core->gfxWindowDisplay && $this->core->memory[0xFF4A] <= $this->actualScanLine) ? min(160, $this->core->memory[0xFF4B] - 7) : 160;
+ // step 1: background+window
+ $skippedAnything = $this->core->drawBackgroundForLine($this->actualScanLine, $windowLeft, 0);
+ // At this point, the high (alpha) byte in the frameBuffer is 0xff for colors 1,2,3 and
+ // 0x00 for color 0. Foreground sprites draw on all colors, background sprites draw on
+ // top of color 0 only.
+ // step 2: sprites
+ $this->core->drawSpritesForLine($this->actualScanLine);
+ // step 3: prio tiles+window
+ if ($skippedAnything) {
+ $this->core->drawBackgroundForLine($this->actualScanLine, $windowLeft, 0x80);
+ }
+ if ($windowLeft < 160) {
+ ++$this->core->windowSourceLine;
+ }
+ }
+
/**
* Scan Line and STAT Mode Control
* @param int $line Memory Scanline
@@ -18,64 +79,63 @@ class LcdController
public function scanLine($line)
{
//When turned off = Do nothing!
- //@TODO - Move LCDisOn to this class
- if ($this->core->LCDisOn) {
+ if ($this->LCDisOn) {
if ($line < 143) {
//We're on a normal scan line:
if ($this->core->LCDTicks < 20) {
- $this->core->scanLineMode2(); // mode2: 80 cycles
+ $this->scanLineMode2(); // mode2: 80 cycles
} elseif ($this->core->LCDTicks < 63) {
- $this->core->scanLineMode3(); // mode3: 172 cycles
+ $this->scanLineMode3(); // mode3: 172 cycles
} elseif ($this->core->LCDTicks < 114) {
- $this->core->scanLineMode0(); // mode0: 204 cycles
+ $this->scanLineMode0(); // mode0: 204 cycles
} else {
//We're on a new scan line:
$this->core->LCDTicks -= 114;
- $this->core->actualScanLine = ++$this->core->memory[0xFF44];
- $this->core->matchLYC();
- if ($this->core->STATTracker != 2) {
- if ($this->core->hdmaRunning && !$this->core->halt && $this->core->LCDisOn) {
+ $this->actualScanLine = ++$this->core->memory[0xFF44];
+ $this->matchLYC();
+ if ($this->STATTracker != 2) {
+ if ($this->core->hdmaRunning && !$this->core->halt && $this->LCDisOn) {
$this->core->performHdma(); //H-Blank DMA
}
- if ($this->core->mode0TriggerSTAT) {
+ if ($this->mode0TriggerSTAT) {
$this->core->memory[0xFF0F] |= 0x2; // set IF bit 1
}
}
- $this->core->STATTracker = 0;
- $this->core->scanLineMode2(); // mode2: 80 cycles
+ $this->STATTracker = 0;
+ $this->scanLineMode2(); // mode2: 80 cycles
if ($this->core->LCDTicks >= 114) {
//We need to skip 1 or more scan lines:
$this->core->notifyScanline();
- $this->scanLine($this->core->actualScanLine); //Scan Line and STAT Mode Control
+ $this->scanLine($this->actualScanLine); //Scan Line and STAT Mode Control
}
}
} elseif ($line == 143) {
//We're on the last visible scan line of the LCD screen:
if ($this->core->LCDTicks < 20) {
- $this->core->scanLineMode2(); // mode2: 80 cycles
+ $this->scanLineMode2(); // mode2: 80 cycles
} elseif ($this->core->LCDTicks < 63) {
- $this->core->scanLineMode3(); // mode3: 172 cycles
+ $this->scanLineMode3(); // mode3: 172 cycles
} elseif ($this->core->LCDTicks < 114) {
- $this->core->scanLineMode0(); // mode0: 204 cycles
+ $this->scanLineMode0(); // mode0: 204 cycles
} else {
//Starting V-Blank:
//Just finished the last visible scan line:
$this->core->LCDTicks -= 114;
- $this->core->actualScanLine = ++$this->core->memory[0xFF44];
- $this->core->matchLYC();
- if ($this->core->mode1TriggerSTAT) {
+ $this->actualScanLine = ++$this->core->memory[0xFF44];
+ $this->matchLYC();
+ if ($this->mode1TriggerSTAT) {
$this->core->memory[0xFF0F] |= 0x2; // set IF bit 1
}
- if ($this->core->STATTracker != 2) {
- if ($this->core->hdmaRunning && !$this->core->halt && $this->core->LCDisOn) {
+ if ($this->STATTracker != 2) {
+ if ($this->core->hdmaRunning && !$this->core->halt && $this->LCDisOn) {
$this->core->performHdma(); //H-Blank DMA
}
- if ($this->core->mode0TriggerSTAT) {
+ if ($this->mode0TriggerSTAT) {
$this->core->memory[0xFF0F] |= 0x2; // set IF bit 1
}
}
- $this->core->STATTracker = 0;
- $this->core->modeSTAT = 1;
+ $this->STATTracker = 0;
+ $this->modeSTAT = 1;
$this->core->memory[0xFF0F] |= 0x1; // set IF flag 0
//LCD off takes at least 2 frames.
if ($this->core->drewBlank > 0) {
@@ -83,7 +143,7 @@ class LcdController
}
if ($this->core->LCDTicks >= 114) {
//We need to skip 1 or more scan lines:
- $this->scanLine($this->core->actualScanLine); //Scan Line and STAT Mode Control
+ $this->scanLine($this->actualScanLine); //Scan Line and STAT Mode Control
}
}
} elseif ($line < 153) {
@@ -91,30 +151,70 @@ class LcdController
if ($this->core->LCDTicks >= 114) {
//We're on a new scan line:
$this->core->LCDTicks -= 114;
- $this->core->actualScanLine = ++$this->core->memory[0xFF44];
- $this->core->matchLYC();
+ $this->actualScanLine = ++$this->core->memory[0xFF44];
+ $this->matchLYC();
if ($this->core->LCDTicks >= 114) {
//We need to skip 1 or more scan lines:
- $this->scanLine($this->core->actualScanLine); //Scan Line and STAT Mode Control
+ $this->scanLine($this->actualScanLine); //Scan Line and STAT Mode Control
}
}
} else {
//VBlank Ending (We're on the last actual scan line)
if ($this->core->memory[0xFF44] == 153) {
$this->core->memory[0xFF44] = 0; //LY register resets to 0 early.
- $this->core->matchLYC(); //LY==LYC Test is early here (Fixes specific one-line glitches (example: Kirby2 intro)).
+ $this->matchLYC(); //LY==LYC Test is early here (Fixes specific one-line glitches (example: Kirby2 intro)).
}
if ($this->core->LCDTicks >= 114) {
//We reset back to the beginning:
$this->core->LCDTicks -= 114;
- $this->core->actualScanLine = 0;
- $this->core->scanLineMode2(); // mode2: 80 cycles
+ $this->actualScanLine = 0;
+ $this->scanLineMode2(); // mode2: 80 cycles
if ($this->core->LCDTicks >= 114) {
//We need to skip 1 or more scan lines:
- $this->scanLine($this->core->actualScanLine); //Scan Line and STAT Mode Control
+ $this->scanLine($this->actualScanLine); //Scan Line and STAT Mode Control
}
}
}
}
}
+
+ public function scanLineMode0()
+ {
+ // H-Blank
+ if ($this->modeSTAT != 0) {
+ if ($this->core->hdmaRunning && !$this->core->halt && $this->LCDisOn) {
+ $this->performHdma(); //H-Blank DMA
+ }
+ if ($this->mode0TriggerSTAT || ($this->mode2TriggerSTAT && $this->STATTracker == 0)) {
+ $this->core->memory[0xFF0F] |= 0x2; // if STAT bit 3 -> set IF bit1
+ }
+ $this->notifyScanline();
+ $this->STATTracker = 2;
+ $this->modeSTAT = 0;
+ }
+ }
+
+ public function scanLineMode2()
+ {
+ // OAM in use
+ if ($this->modeSTAT != 2) {
+ if ($this->mode2TriggerSTAT) {
+ $this->core->memory[0xFF0F] |= 0x2; // set IF bit 1
+ }
+ $this->STATTracker = 1;
+ $this->modeSTAT = 2;
+ }
+ }
+
+ public function scanLineMode3()
+ {
+ // OAM in use
+ if ($this->modeSTAT != 3) {
+ if ($this->mode2TriggerSTAT && $this->STATTracker == 0) {
+ $this->core->memory[0xFF0F] |= 0x2; // set IF bit 1
+ }
+ $this->STATTracker = 1;
+ $this->modeSTAT = 3;
+ }
+ }
}