cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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 */