1 /*************************************************************************** 2 * Copyright (C) 2007 by Sindre Aamås * 3 * aamas@stud.ntnu.no * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License version 2 as * 7 * published by the Free Software Foundation. * 8 * * 9 * This program is distributed in the hope that it will be useful, * 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 * GNU General Public License version 2 for more details. * 13 * * 14 * You should have received a copy of the GNU General Public License * 15 * version 2 along with this program; if not, write to the * 16 * Free Software Foundation, Inc., * 17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 18 ***************************************************************************/ 19 #ifndef VIDEO_H 20 #define VIDEO_H 21 22 #include "interruptrequester.h" 23 #include "video/lyc_irq.h" 24 #include "video/m0_irq.h" 25 #include "video/next_m0_time.h" 26 #include "video/ppu.h" 27 #include <memory> 28 29 namespace gambatte { 30 31 class VideoInterruptRequester 32 { 33 public: VideoInterruptRequester(InterruptRequester & intreq)34 explicit VideoInterruptRequester(InterruptRequester &intreq) : intreq_(intreq) {} flagHdmaReq()35 void flagHdmaReq() const { gambatte::flagHdmaReq(intreq_); } flagIrq(const unsigned bit)36 void flagIrq(const unsigned bit) const { intreq_.flagIrq(bit); } setNextEventTime(const unsigned long time)37 void setNextEventTime(const unsigned long time) const { intreq_.setEventTime<intevent_video>(time); } 38 39 private: 40 InterruptRequester &intreq_; 41 }; 42 43 class LCD 44 { 45 public: 46 LCD(const unsigned char *oamram, const unsigned char *vram_in, VideoInterruptRequester memEventRequester); 47 void reset(const unsigned char *oamram, unsigned char const *vram, bool cgb); 48 void setStatePtrs(SaveState &state); 49 void saveState(SaveState &state) const; 50 void loadState(const SaveState &state, const unsigned char *oamram); 51 void setDmgPaletteColor(unsigned palNum, unsigned colorNum, video_pixel_t rgb32); 52 void setVideoBuffer(video_pixel_t *videoBuf, int pitch); setDmgMode(bool mode)53 void setDmgMode(bool mode) { ppu_.setDmgMode(mode); } 54 swapToDMG()55 void swapToDMG() { 56 ppu_.setDmgMode(true); 57 refreshPalettes(); 58 } 59 dmgBgPaletteChange(const unsigned data,const unsigned long cycleCounter)60 void dmgBgPaletteChange(const unsigned data, const unsigned long cycleCounter) { 61 update(cycleCounter); 62 bgpData_[0] = data; 63 setDmgPalette(ppu_.bgPalette(), dmgColorsRgb32_, data); 64 } 65 dmgSpPalette1Change(const unsigned data,const unsigned long cycleCounter)66 void dmgSpPalette1Change(const unsigned data, const unsigned long cycleCounter) { 67 update(cycleCounter); 68 objpData_[0] = data; 69 setDmgPalette(ppu_.spPalette(), dmgColorsRgb32_ + 4, data); 70 } 71 dmgSpPalette2Change(const unsigned data,const unsigned long cycleCounter)72 void dmgSpPalette2Change(const unsigned data, const unsigned long cycleCounter) { 73 update(cycleCounter); 74 objpData_[1] = data; 75 setDmgPalette(ppu_.spPalette() + 4, dmgColorsRgb32_ + 8, data); 76 } 77 cgbBgColorChange(unsigned index,const unsigned data,const unsigned long cycleCounter)78 void cgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) { 79 if (bgpData_[index] != data) { 80 doCgbBgColorChange(index, data, cycleCounter); 81 if(index < 8) 82 doCgbColorChange(dmgColorsGBC_, dmgColorsRgb32_, index, data); 83 } 84 } 85 cgbSpColorChange(unsigned index,const unsigned data,const unsigned long cycleCounter)86 void cgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) { 87 if (objpData_[index] != data) { 88 doCgbSpColorChange(index, data, cycleCounter); 89 if(index < 8 * 2/*dmg has 2 sprite banks*/) 90 doCgbColorChange(dmgColorsGBC_ + 8, dmgColorsRgb32_ + 4, index, data); 91 } 92 } 93 cgbBgColorRead(const unsigned index,const unsigned long cycleCounter)94 unsigned cgbBgColorRead(const unsigned index, const unsigned long cycleCounter) { 95 return (ppu_.cgb() & cgbpAccessible(cycleCounter)) ? bgpData_[index] : 0xFF; 96 } 97 cgbSpColorRead(const unsigned index,const unsigned long cycleCounter)98 unsigned cgbSpColorRead(const unsigned index, const unsigned long cycleCounter) { 99 return (ppu_.cgb() & cgbpAccessible(cycleCounter)) ? objpData_[index] : 0xFF; 100 } 101 102 void updateScreen(bool blanklcd, unsigned long cc); 103 void resetCc(unsigned long oldCC, unsigned long newCc); 104 void speedChange(unsigned long cycleCounter); 105 bool vramAccessible(unsigned long cycleCounter); 106 bool oamReadable(unsigned long cycleCounter); 107 bool oamWritable(unsigned long cycleCounter); 108 void wxChange(unsigned newValue, unsigned long cycleCounter); 109 void wyChange(unsigned newValue, unsigned long cycleCounter); 110 void oamChange(unsigned long cycleCounter); 111 void oamChange(const unsigned char *oamram, unsigned long cycleCounter); 112 void scxChange(unsigned newScx, unsigned long cycleCounter); 113 void scyChange(unsigned newValue, unsigned long cycleCounter); 114 vramChange(const unsigned long cycleCounter)115 void vramChange(const unsigned long cycleCounter) { update(cycleCounter); } 116 117 unsigned getStat(unsigned lycReg, unsigned long cycleCounter); 118 getLyReg(const unsigned long cycleCounter)119 unsigned getLyReg(const unsigned long cycleCounter) { 120 unsigned lyReg = 0; 121 122 if (ppu_.lcdc() & 0x80) { 123 if (cycleCounter >= ppu_.lyCounter().time()) 124 update(cycleCounter); 125 126 lyReg = ppu_.lyCounter().ly(); 127 128 if (lyReg == 153) { 129 if (isDoubleSpeed()) { 130 if (ppu_.lyCounter().time() - cycleCounter <= 456 * 2 - 8) 131 lyReg = 0; 132 } else 133 lyReg = 0; 134 } else if (ppu_.lyCounter().time() - cycleCounter <= 4) 135 ++lyReg; 136 } 137 138 return lyReg; 139 } 140 nextMode1IrqTime()141 unsigned long nextMode1IrqTime() const { return eventTimes_(MODE1_IRQ); } 142 143 void lcdcChange(unsigned data, unsigned long cycleCounter); 144 void lcdstatChange(unsigned data, unsigned long cycleCounter); 145 void lycRegChange(unsigned data, unsigned long cycleCounter); 146 147 void enableHdma(unsigned long cycleCounter); 148 void disableHdma(unsigned long cycleCounter); hdmaIsEnabled()149 bool hdmaIsEnabled() const { return eventTimes_(HDMA_REQ) != disabled_time; } 150 151 void update(unsigned long cycleCounter); 152 isCgb()153 bool isCgb() const { return ppu_.cgb(); } isDoubleSpeed()154 bool isDoubleSpeed() const { return ppu_.lyCounter().isDoubleSpeed(); } 155 156 void setColorCorrection(bool colorCorrection); 157 void setColorCorrectionMode(unsigned colorCorrectionMode); 158 void setColorCorrectionBrightness(float colorCorrectionBrightness); 159 void setDarkFilterLevel(unsigned darkFilterLevel); 160 video_pixel_t gbcToRgb32(const unsigned bgr15); 161 private: 162 enum Event { MEM_EVENT, LY_COUNT }; enum { NUM_EVENTS = LY_COUNT + 1 }; 163 enum MemEvent { ONESHOT_LCDSTATIRQ, ONESHOT_UPDATEWY2, MODE1_IRQ, LYC_IRQ, SPRITE_MAP, 164 HDMA_REQ, MODE2_IRQ, MODE0_IRQ }; enum { NUM_MEM_EVENTS = MODE0_IRQ + 1 }; 165 166 class EventTimes 167 { 168 public: EventTimes(const VideoInterruptRequester memEventRequester)169 explicit EventTimes(const VideoInterruptRequester memEventRequester) : memEventRequester_(memEventRequester) {} 170 nextEvent()171 Event nextEvent() const { return static_cast<Event>(eventMin_.min()); } nextEventTime()172 unsigned long nextEventTime() const { return eventMin_.minValue(); } operator()173 unsigned long operator()(const Event e) const { return eventMin_.value(e); } set(const unsigned long time)174 template<Event e> void set(const unsigned long time) { eventMin_.setValue<e>(time); } set(const Event e,const unsigned long time)175 void set(const Event e, const unsigned long time) { eventMin_.setValue(e, time); } 176 nextMemEvent()177 MemEvent nextMemEvent() const { return static_cast<MemEvent>(memEventMin_.min()); } nextMemEventTime()178 unsigned long nextMemEventTime() const { return memEventMin_.minValue(); } operator()179 unsigned long operator()(const MemEvent e) const { return memEventMin_.value(e); } setm(const unsigned long time)180 template<MemEvent e> void setm(const unsigned long time) { memEventMin_.setValue<e>(time); setMemEvent(); } set(const MemEvent e,const unsigned long time)181 void set(const MemEvent e, const unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); } 182 flagIrq(const unsigned bit)183 void flagIrq(const unsigned bit) { memEventRequester_.flagIrq(bit); } flagHdmaReq()184 void flagHdmaReq() { memEventRequester_.flagHdmaReq(); } 185 186 private: 187 MinKeeper<NUM_EVENTS> eventMin_; 188 MinKeeper<NUM_MEM_EVENTS> memEventMin_; 189 VideoInterruptRequester memEventRequester_; 190 setMemEvent()191 void setMemEvent() { 192 const unsigned long nmet = nextMemEventTime(); 193 eventMin_.setValue<MEM_EVENT>(nmet); 194 memEventRequester_.setNextEventTime(nmet); 195 } 196 197 }; 198 199 PPU ppu_; 200 video_pixel_t dmgColorsRgb32_[3 * 4]; 201 unsigned char dmgColorsGBC_[3 * 8]; 202 unsigned char bgpData_[8 * 8]; 203 unsigned char objpData_[8 * 8]; 204 205 EventTimes eventTimes_; 206 M0Irq m0Irq_; 207 LycIrq lycIrq_; 208 NextM0Time nextM0Time_; 209 210 unsigned char statReg_; 211 unsigned char m2IrqStatReg_; 212 unsigned char m1IrqStatReg_; 213 214 static void setDmgPalette(video_pixel_t *palette, const video_pixel_t *dmgColors, unsigned data); 215 void setDmgPaletteColor(unsigned index, video_pixel_t rgb32); 216 217 void setDBuffer(); 218 void refreshPalettes(); 219 220 void doMode2IrqEvent(); 221 void event(); 222 223 unsigned long m0TimeOfCurrentLine(unsigned long cc); 224 bool cgbpAccessible(unsigned long cycleCounter); 225 226 void mode3CyclesChange(); 227 void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter); 228 void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter); 229 230 bool colorCorrection; 231 unsigned colorCorrectionMode; 232 float colorCorrectionBrightness; 233 unsigned darkFilterLevel; 234 void doCgbColorChange(unsigned char *const pdata, 235 video_pixel_t *const palette, unsigned index, const unsigned data); 236 237 void darkenRgb(float &r, float &g, float &b); 238 239 }; 240 241 } 242 243 #endif 244