1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
#include <stdlib.h>
#include "defs.h"
#include "hw.h"
#include "cpu.h"
#include "regs.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;
}
}
}
|