IORegistersMemoryRule.h (13624B)
1/* 2 * Gearboy - Nintendo Game Boy Emulator 3 * Copyright (C) 2012 Ignacio Sanchez 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 as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * any later version. 9 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see http://www.gnu.org/licenses/ 17 * 18 */ 19 20#ifndef IOREGISTERSMEMORYRULE_H 21#define IOREGISTERSMEMORYRULE_H 22 23#include "definitions.h" 24 25class Video; 26class Processor; 27class Input; 28class Audio; 29class Memory; 30 31class IORegistersMemoryRule 32{ 33public: 34 IORegistersMemoryRule(Processor* pProcessor, Memory* pMemory, Video* pVideo, Input* pInput, Audio* pAudio); 35 ~IORegistersMemoryRule(); 36 u8 PerformRead(u16 address); 37 void PerformWrite(u16 address, u8 value); 38 void Reset(bool bCGB); 39 40private: 41 Processor* m_pProcessor; 42 Memory* m_pMemory; 43 Video* m_pVideo; 44 Input* m_pInput; 45 Audio* m_pAudio; 46 bool m_bCGB; 47}; 48 49#include "Video.h" 50#include "Processor.h" 51#include "Input.h" 52#include "Audio.h" 53#include "Memory.h" 54 55inline u8 IORegistersMemoryRule::PerformRead(u16 address) 56{ 57 switch (address) 58 { 59 case 0xFF00: 60 { 61 // P1 62 return m_pInput->Read(); 63 } 64 case 0xFF03: 65 { 66 // UNDOCUMENTED 67 return 0xFF; 68 } 69 case 0xFF07: 70 { 71 // TAC 72 return m_pMemory->Retrieve(0xFF07) | 0xF8; 73 } 74 case 0xFF08: 75 case 0xFF09: 76 case 0xFF0A: 77 case 0xFF0B: 78 case 0xFF0C: 79 case 0xFF0D: 80 case 0xFF0E: 81 { 82 // UNDOCUMENTED 83 return 0xFF; 84 } 85 case 0xFF0F: 86 { 87 // IF 88 return m_pMemory->Retrieve(0xFF0F) | 0xE0; 89 } 90 case 0xFF10: 91 case 0xFF11: 92 case 0xFF12: 93 case 0xFF13: 94 case 0xFF14: 95 case 0xFF15: 96 case 0xFF16: 97 case 0xFF17: 98 case 0xFF18: 99 case 0xFF19: 100 case 0xFF1A: 101 case 0xFF1B: 102 case 0xFF1C: 103 case 0xFF1D: 104 case 0xFF1E: 105 case 0xFF1F: 106 case 0xFF20: 107 case 0xFF21: 108 case 0xFF22: 109 case 0xFF23: 110 case 0xFF24: 111 case 0xFF25: 112 case 0xFF26: 113 case 0xFF27: 114 case 0xFF28: 115 case 0xFF29: 116 case 0xFF2A: 117 case 0xFF2B: 118 case 0xFF2C: 119 case 0xFF2D: 120 case 0xFF2E: 121 case 0xFF2F: 122 case 0xFF30: 123 case 0xFF31: 124 case 0xFF32: 125 case 0xFF33: 126 case 0xFF34: 127 case 0xFF35: 128 case 0xFF36: 129 case 0xFF37: 130 case 0xFF38: 131 case 0xFF39: 132 case 0xFF3A: 133 case 0xFF3B: 134 case 0xFF3C: 135 case 0xFF3D: 136 case 0xFF3E: 137 case 0xFF3F: 138 { 139 // SOUND REGISTERS 140 return m_pAudio->ReadAudioRegister(address); 141 } 142 case 0xFF41: 143 { 144 // STAT 145 return m_pMemory->Retrieve(0xFF41) | 0x80; 146 } 147 case 0xFF44: 148 { 149 // LY 150 return (m_pVideo->IsScreenEnabled() ? m_pMemory->Retrieve(0xFF44) : 0x00); 151 } 152 case 0xFF4C: 153 { 154 // UNDOCUMENTED 155 return 0xFF; 156 } 157 case 0xFF4F: 158 { 159 // VBK 160 return m_pMemory->Retrieve(0xFF4F) | 0xFE; 161 } 162 case 0xFF51: 163 { 164 // HDMA1 165 return (m_bCGB ? m_pMemory->GetHDMARegister(1) : m_pMemory->Retrieve(address)); 166 } 167 case 0xFF52: 168 { 169 // HDMA2 170 return (m_bCGB ? m_pMemory->GetHDMARegister(2) : m_pMemory->Retrieve(address)); 171 } 172 case 0xFF53: 173 { 174 // HDMA3 175 return (m_bCGB ? m_pMemory->GetHDMARegister(3) : m_pMemory->Retrieve(address)); 176 } 177 case 0xFF54: 178 { 179 // HDMA4 180 return (m_bCGB ? m_pMemory->GetHDMARegister(4) : m_pMemory->Retrieve(address)); 181 } 182 case 0xFF55: 183 { 184 // DMA CGB 185 return (m_bCGB ? m_pMemory->GetHDMARegister(5) : m_pMemory->Retrieve(address)); 186 } 187 case 0xFF68: 188 case 0xFF6A: 189 { 190 // BCPS, OCPS 191 return (m_bCGB ? (m_pMemory->Retrieve(address) | 0x40) : 0xC0); 192 } 193 case 0xFF69: 194 case 0xFF6B: 195 { 196 // BCPD, OCPD 197 return (m_bCGB ? m_pMemory->Retrieve(address) : 0xFF); 198 } 199 case 0xFF70: 200 { 201 // SVBK 202 return (m_bCGB ? (m_pMemory->Retrieve(0xFF70) | 0xF8) : 0xFF); 203 } 204 case 0xFF76: 205 { 206 // UNDOCUMENTED 207 return (m_bCGB ? 0x00 : 0xFF); 208 } 209 case 0xFF77: 210 { 211 // UNDOCUMENTED 212 return (m_bCGB ? 0x0 : 0xFF); 213 } 214 } 215 216 return m_pMemory->Retrieve(address); 217} 218 219inline void IORegistersMemoryRule::PerformWrite(u16 address, u8 value) 220{ 221 switch (address) 222 { 223 case 0xFF00: 224 { 225 // P1 226 m_pInput->Write(value); 227 break; 228 } 229 case 0xFF04: 230 { 231 // DIV 232 m_pProcessor->ResetDIVCycles(); 233 break; 234 } 235 case 0xFF07: 236 { 237 // TAC 238 value &= 0x07; 239 u8 current_tac = m_pMemory->Retrieve(0xFF07); 240 if ((current_tac & 0x03) != (value & 0x03)) 241 { 242 m_pProcessor->ResetTIMACycles(); 243 } 244 m_pMemory->Load(address, value); 245 break; 246 } 247 case 0xFF0F: 248 { 249 // IF 250 m_pMemory->Load(address, value & 0x1F); 251 break; 252 } 253 case 0xFF10: 254 case 0xFF11: 255 case 0xFF12: 256 case 0xFF13: 257 case 0xFF14: 258 case 0xFF15: 259 case 0xFF16: 260 case 0xFF17: 261 case 0xFF18: 262 case 0xFF19: 263 case 0xFF1A: 264 case 0xFF1B: 265 case 0xFF1C: 266 case 0xFF1D: 267 case 0xFF1E: 268 case 0xFF1F: 269 case 0xFF20: 270 case 0xFF21: 271 case 0xFF22: 272 case 0xFF23: 273 case 0xFF24: 274 case 0xFF25: 275 case 0xFF26: 276 case 0xFF27: 277 case 0xFF28: 278 case 0xFF29: 279 case 0xFF2A: 280 case 0xFF2B: 281 case 0xFF2C: 282 case 0xFF2D: 283 case 0xFF2E: 284 case 0xFF2F: 285 case 0xFF30: 286 case 0xFF31: 287 case 0xFF32: 288 case 0xFF33: 289 case 0xFF34: 290 case 0xFF35: 291 case 0xFF36: 292 case 0xFF37: 293 case 0xFF38: 294 case 0xFF39: 295 case 0xFF3A: 296 case 0xFF3B: 297 case 0xFF3C: 298 case 0xFF3D: 299 case 0xFF3E: 300 case 0xFF3F: 301 { 302 // SOUND REGISTERS 303 m_pAudio->WriteAudioRegister(address, value); 304 break; 305 } 306 case 0xFF40: 307 { 308 // LCDC 309 u8 current_lcdc = m_pMemory->Retrieve(0xFF40); 310 u8 new_lcdc = value; 311 m_pMemory->Load(address, new_lcdc); 312 if (!IsSetBit(current_lcdc, 5) && IsSetBit(new_lcdc, 5)) 313 m_pVideo->ResetWindowLine(); 314 if (IsSetBit(new_lcdc, 7)) 315 m_pVideo->EnableScreen(); 316 else 317 m_pVideo->DisableScreen(); 318 break; 319 } 320 case 0xFF41: 321 { 322 // STAT 323 u8 current_stat = m_pMemory->Retrieve(0xFF41) & 0x07; 324 u8 new_stat = (value & 0x78) | (current_stat & 0x07); 325 m_pMemory->Load(address, new_stat); 326 u8 lcdc = m_pMemory->Retrieve(0xFF40); 327 u8 signal = m_pVideo->GetIRQ48Signal(); 328 int mode = m_pVideo->GetCurrentStatusMode(); 329 signal &= ((new_stat >> 3) & 0x0F); 330 m_pVideo->SetIRQ48Signal(signal); 331 332 if (IsSetBit(lcdc, 7)) 333 { 334 if (IsSetBit(new_stat, 3) && (mode == 0)) 335 { 336 if (signal == 0) 337 { 338 m_pProcessor->RequestInterrupt(Processor::LCDSTAT_Interrupt); 339 } 340 signal = SetBit(signal, 0); 341 } 342 if (IsSetBit(new_stat, 4) && (mode == 1)) 343 { 344 if (signal == 0) 345 { 346 m_pProcessor->RequestInterrupt(Processor::LCDSTAT_Interrupt); 347 } 348 signal = SetBit(signal, 1); 349 } 350 if (IsSetBit(new_stat, 5) && (mode == 2)) 351 { 352 if (signal == 0) 353 { 354 m_pProcessor->RequestInterrupt(Processor::LCDSTAT_Interrupt); 355 } 356 //signal = SetBit(signal, 2); 357 } 358 m_pVideo->CompareLYToLYC(); 359 } 360 break; 361 } 362 case 0xFF44: 363 { 364 // LY 365 u8 current_ly = m_pMemory->Retrieve(0xFF44); 366 if (IsSetBit(current_ly, 7) && !IsSetBit(value, 7)) 367 { 368 m_pVideo->DisableScreen(); 369 } 370 break; 371 } 372 case 0xFF45: 373 { 374 // LYC 375 u8 current_lyc = m_pMemory->Retrieve(0xFF45); 376 if (current_lyc != value) 377 { 378 m_pMemory->Load(0xFF45, value); 379 u8 lcdc = m_pMemory->Retrieve(0xFF40); 380 if (IsSetBit(lcdc, 7)) 381 { 382 m_pVideo->CompareLYToLYC(); 383 } 384 } 385 break; 386 } 387 case 0xFF46: 388 { 389 // DMA 390 m_pMemory->Load(address, value); 391 m_pMemory->PerformDMA(value); 392 break; 393 } 394 case 0xFF4D: 395 { 396 // KEY1 397 if (m_bCGB) 398 { 399 u8 current_key1 = m_pMemory->Retrieve(0xFF4D); 400 m_pMemory->Load(address, (current_key1 & 0x80) | (value & 0x01) | 0x7E); 401 } 402 else 403 m_pMemory->Load(address, value); 404 break; 405 } 406 case 0xFF4F: 407 { 408 // VBK 409 if (m_bCGB) 410 { 411 value &= 0x01; 412 m_pMemory->SwitchCGBLCDRAM(value); 413 } 414 m_pMemory->Load(address, value); 415 break; 416 } 417 case 0xFF50: 418 { 419 // BOOT 420 if ((value & 0x01) > 0) 421 { 422 m_pMemory->DisableBootromRegistry(); 423 } 424 break; 425 } 426 case 0xFF51: 427 { 428 // HDMA1 429 if (m_bCGB) 430 m_pMemory->SetHDMARegister(1, value); 431 else 432 m_pMemory->Load(address, value); 433 break; 434 } 435 case 0xFF52: 436 { 437 // HDMA2 438 if (m_bCGB) 439 m_pMemory->SetHDMARegister(2, value); 440 else 441 m_pMemory->Load(address, value); 442 break; 443 } 444 case 0xFF53: 445 { 446 // HDMA3 447 if (m_bCGB) 448 m_pMemory->SetHDMARegister(3, value); 449 else 450 m_pMemory->Load(address, value); 451 break; 452 } 453 case 0xFF54: 454 { 455 // HDMA4 456 if (m_bCGB) 457 m_pMemory->SetHDMARegister(4, value); 458 else 459 m_pMemory->Load(address, value); 460 break; 461 } 462 case 0xFF55: 463 { 464 // DMA CGB 465 if (m_bCGB) 466 m_pMemory->SwitchCGBDMA(value); 467 else 468 m_pMemory->Load(address, value); 469 break; 470 } 471 case 0xFF68: 472 { 473 // BCPS 474 m_pMemory->Load(address, value); 475 if (m_bCGB) 476 m_pVideo->UpdatePaletteToSpecification(true, value); 477 break; 478 } 479 case 0xFF69: 480 { 481 // BCPD 482 m_pMemory->Load(address, value); 483 if (m_bCGB) 484 m_pVideo->SetColorPalette(true, value); 485 break; 486 } 487 case 0xFF6A: 488 { 489 // OCPS 490 m_pMemory->Load(address, value); 491 if (m_bCGB) 492 m_pVideo->UpdatePaletteToSpecification(false, value); 493 break; 494 } 495 case 0xFF6B: 496 { 497 // OCPD 498 m_pMemory->Load(address, value); 499 if (m_bCGB) 500 m_pVideo->SetColorPalette(false, value); 501 break; 502 } 503 case 0xFF6C: 504 { 505 // UNDOCUMENTED 506 m_pMemory->Load(0xFF6C, value | 0xFE); 507 break; 508 } 509 case 0xFF70: 510 { 511 // SVBK 512 if (m_bCGB) 513 { 514 value &= 0x07; 515 m_pMemory->SwitchCGBWRAM(value); 516 } 517 m_pMemory->Load(address, value); 518 break; 519 } 520 case 0xFF75: 521 { 522 // UNDOCUMENTED 523 m_pMemory->Load(0xFF75, value | 0x8F); 524 break; 525 } 526 case 0xFFFF: 527 { 528 // IE 529 m_pMemory->Load(address, value & 0x1F); 530 break; 531 } 532 default: 533 { 534 m_pMemory->Load(address, value); 535 } 536 } 537} 538 539#endif /* IOREGISTERSMEMORYRULE_H */