










#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 36 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;




}




}




}




























