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(); }
/* FIXME: function now will only lower vblank interrupt, description does not match anymore */ 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 stat_trigger() { static const int condbits[4] = { 0x08, 0x10, 0x20, 0x00 }; int flag = 0; if (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); }
/* lcdc_trans() Main LCDC emulation routine */ void lcdc_trans() { if (R_LCDC & 0x80) { /* LCDC operation enabled */ while (C <= 0) { /* Update current state */ switch ((byte)(R_STAT & 3)) { case 0: /* after hblank */ /* FIXME: first line of first frame will be skipped each time LCDC is started */ if (++R_LY <= 143) { stat_change(2); /* -> search */ } else { stat_change(1); /* -> vblank */ /* See "NOTE A" above */ /*if (cpu.halt) { hw_interrupt(IF_VBLANK, IF_VBLANK); C += 228; } else { C += 10; continue; }*/ break; } break; case 2: /* after search */ stat_change(3); /* -> transfer */ break; case 3: /* after transfer */ stat_change(0); /* -> hblank */ break; case 1: /* after (in) vblank */ if (R_LY == 0) { stat_change(2); /* -> search */ } break; } /* Handle current state */ switch ((byte)(R_STAT & 3)) { case 2: /* search */ if (R_LY == 0) { lcd_begin(); } C += 40; break; case 3: /* transfer */ lcd_refreshline(); C += 86; break; case 0: /* hblank */ if (hw.hdma & 0x80) { hw_hdma(); } C += 102; break; case 1: /* vblank */ if (!(hw.ilines & IF_VBLANK)) { C += 228; /*C += 218; See "NOTE A" above */ hw_interrupt(IF_VBLANK, IF_VBLANK); } else { R_LY++; if (R_LY < 153) { C += 228; } else if (R_LY == 153) { /* Handling special case on the last line part 1; see docs/HACKING */ C += 28; } else { /* Handling special case on the last line part 2; see docs/HACKING */ R_LY = 0; C += 200; } stat_trigger(); } break; } /* switch(state) */ } /* while (C <= 0) */ } /* if (R_LCDC & 0x80) */ else { /* LCDC operation disabled (short route) */ if (C <= 0) /* Original code does in fact return after each pass, there is no loop here */ { switch ((byte)(R_STAT & 3)) { case 2: /* after search */ stat_change(3); C += 86; break; case 3: /* after transfer */ stat_change(0); C += 102; break; case 0: /* after hblank */ stat_change(2); R_LY++; C += 40; break; case 1: /* after (in) vblank */ stat_change(2); C += 40; break; } } } }
void ioreg_write(byte r, byte b) { if (!hw.cgb) { switch (r) { case RI_VBK: case RI_BCPS: case RI_OCPS: case RI_BCPD: case RI_OCPD: case RI_SVBK: case RI_KEY1: case RI_HDMA1: case RI_HDMA2: case RI_HDMA3: case RI_HDMA4: case RI_HDMA5: return; } } switch(r) { case RI_TIMA: case RI_TMA: case RI_TAC: case RI_SCY: case RI_SCX: case RI_WY: case RI_WX: REG(r) = b; break; case RI_BGP: if (R_BGP == b) break; pal_write_dmg(0, 0, b); pal_write_dmg(8, 1, b); R_BGP = b; break; case RI_OBP0: if (R_OBP0 == b) break; pal_write_dmg(64, 2, b); R_OBP0 = b; break; case RI_OBP1: if (R_OBP1 == b) break; pal_write_dmg(72, 3, b); R_OBP1 = b; break; case RI_IF: case RI_IE: REG(r) = b & 0x1F; break; case RI_P1: REG(r) = b; pad_refresh(); break; case RI_SC: /* FIXME - this is a hack for stupid roms that probe serial */ if ((b & 0x81) == 0x81) { R_SB = 0xff; hw_interrupt(IF_SERIAL, IF_SERIAL); hw_interrupt(0, IF_SERIAL); } R_SC = b; /* & 0x7f; */ break; case RI_DIV: REG(r) = 0; break; case RI_LCDC: lcdc_change(b); break; case RI_STAT: stat_write(b); break; case RI_LYC: REG(r) = b; stat_trigger(); break; case RI_VBK: REG(r) = b | 0xFE; mem_updatemap(); break; case RI_BCPS: R_BCPS = b & 0xBF; R_BCPD = lcd.pal[b & 0x3F]; break; case RI_OCPS: R_OCPS = b & 0xBF; R_OCPD = lcd.pal[64 + (b & 0x3F)]; break; case RI_BCPD: R_BCPD = b; pal_write(R_BCPS & 0x3F, b); if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF; break; case RI_OCPD: R_OCPD = b; pal_write(64 + (R_OCPS & 0x3F), b); if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF; break; case RI_SVBK: REG(r) = b & 0x07; mem_updatemap(); break; case RI_DMA: hw_dma(b); break; case RI_KEY1: REG(r) = (REG(r) & 0x80) | (b & 0x01); break; case RI_HDMA1: REG(r) = b; break; case RI_HDMA2: REG(r) = b & 0xF0; break; case RI_HDMA3: REG(r) = b & 0x1F; break; case RI_HDMA4: REG(r) = b & 0xF0; break; case RI_HDMA5: hw_hdma_cmd(b); break; } switch (r) { case RI_BGP: case RI_OBP0: case RI_OBP1: /* printf("palette reg %02X write %02X at LY=%02X\n", r, b, R_LY); */ case RI_HDMA1: case RI_HDMA2: case RI_HDMA3: case RI_HDMA4: case RI_HDMA5: /* printf("HDMA %d: %02X\n", r - RI_HDMA1 + 1, b); */ break; } /* printf("reg %02X => %02X (%02X)\n", r, REG(r), b); */ }
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; } } }