gnuboy-for-dfi/lcdc.c
rofl0r 26a601131d Revert "import inofficial 1.0.4pre by joshua"
This reverts commit 9859b44888.

This change causes 2 bugs with the GBC game Cannon Fodder

( Cannon Fodder (U) (M5) [C][!].gbc
  md5sum 762d6c94874d8ac894ad100c0a4b50ab )

1) the 3D scenes flicker and there are some artifacts in the title
   screen,
2) as soon as mission 2 starts, the CPU goes into an endless loop
   and doesn't process input anymore - this is really nasty, as it
   is even impossible to get out of gnuboy itself, at least in fb
   mode.

i was skeptical about this inofficial patch since the beginning,
since it was not done by laguna himself but by some gamers, and
now it's confirmed that it's broken. afaict this patch includes
3-4 logical changes, if further issues are experienced it may make
sense to try one after the other to see if it fixes them.
2017-11-22 23:42:33 +00:00

179 lines
2.9 KiB
C

#include <stdlib.h>
#include "defs.h"
#include "hw.h"
#include "cpu.h"
#include "regs.h"
#include "lcd.h"
#define C (cpu.lcdc)
/*
* stat_trigger updates the STAT interrupt line to reflect whether any
* of the conditions set to be tested (by bits 3-6 of R_STAT) are met.
* This function should be called whenever any of the following occur:
* 1) LY or LYC changes.
* 2) A state transition affects the low 2 bits of R_STAT (see below).
* 3) The program writes to the upper bits of R_STAT.
* stat_trigger also updates bit 2 of R_STAT to reflect whether LY=LYC.
*/
void stat_trigger()
{
static const int condbits[4] = { 0x08, 0x30, 0x20, 0x00 };
int flag = 0;
if ((R_LY < 0x91) && (R_LY == R_LYC))
{
R_STAT |= 0x04;
if (R_STAT & 0x40) flag = IF_STAT;
}
else R_STAT &= ~0x04;
if (R_STAT & condbits[R_STAT&3]) flag = IF_STAT;
if (!(R_LCDC & 0x80)) flag = 0;
hw_interrupt(flag, IF_STAT);
}
void stat_write(byte b)
{
R_STAT = (R_STAT & 0x07) | (b & 0x78);
if (!hw.cgb && !(R_STAT & 2)) /* DMG STAT write bug => interrupt */
hw_interrupt(IF_STAT, IF_STAT);
stat_trigger();
}
/*
* stat_change is called when a transition results in a change to the
* LCD STAT condition (the low 2 bits of R_STAT). It raises or lowers
* the VBLANK interrupt line appropriately and calls stat_trigger to
* update the STAT interrupt line.
*/
static void stat_change(int stat)
{
stat &= 3;
R_STAT = (R_STAT & 0x7C) | stat;
if (stat != 1) hw_interrupt(0, IF_VBLANK);
/* hw_interrupt((stat == 1) ? IF_VBLANK : 0, IF_VBLANK); */
stat_trigger();
}
void lcdc_change(byte b)
{
byte old = R_LCDC;
R_LCDC = b;
if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */
{
R_LY = 0;
stat_change(2);
C = 40;
lcd_begin();
}
}
void lcdc_trans()
{
if (!(R_LCDC & 0x80))
{
while (C <= 0)
{
switch ((byte)(R_STAT & 3))
{
case 0:
case 1:
stat_change(2);
C += 40;
break;
case 2:
stat_change(3);
C += 86;
break;
case 3:
stat_change(0);
if (hw.hdma & 0x80)
hw_hdma();
else
C += 102;
break;
}
return;
}
}
while (C <= 0)
{
switch ((byte)(R_STAT & 3))
{
case 1:
if (!(hw.ilines & IF_VBLANK))
{
C += 218;
hw_interrupt(IF_VBLANK, IF_VBLANK);
break;
}
if (R_LY == 0)
{
lcd_begin();
stat_change(2);
C += 40;
break;
}
else if (R_LY < 152)
C += 228;
else if (R_LY == 152)
C += 28;
else
{
R_LY = -1;
C += 200;
}
R_LY++;
stat_trigger();
break;
case 2:
lcd_refreshline();
stat_change(3);
C += 86;
break;
case 3:
stat_change(0);
if (hw.hdma & 0x80)
hw_hdma();
/* FIXME -- how much of the hblank does hdma use?? */
/* else */
C += 102;
break;
case 0:
if (++R_LY >= 144)
{
if (cpu.halt)
{
hw_interrupt(IF_VBLANK, IF_VBLANK);
C += 228;
}
else C += 10;
stat_change(1);
break;
}
stat_change(2);
C += 40;
break;
}
}
}