152 lines
4.2 KiB
C++
152 lines
4.2 KiB
C++
// Meteor - A Nintendo Gameboy Advance emulator
|
|
// Copyright (C) 2009-2011 Philippe Daouadi
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "ameteor/lcd.hpp"
|
|
#include "ameteor/io.hpp"
|
|
#include "globals.hpp"
|
|
#include "ameteor.hpp"
|
|
|
|
#include "debug.hpp"
|
|
|
|
namespace AMeteor
|
|
{
|
|
Lcd::Lcd () :
|
|
m_screen(MEM, IO)
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void Lcd::Reset ()
|
|
{
|
|
CLOCK.AddLcd(960); // call me at first H-Blank
|
|
}
|
|
|
|
void Lcd::TimeEvent ()
|
|
{
|
|
uint16_t& dispstat = IO.GetRef16(Io::DISPSTAT);
|
|
uint16_t& vcount = IO.GetRef16(Io::VCOUNT);
|
|
|
|
if (dispstat & 0x2) // if we were H-Blanking
|
|
{
|
|
//debug("hblank end");
|
|
// we are not anymore, we're on next line
|
|
dispstat ^= 0x2;
|
|
// call me when we are H-Blanking again
|
|
CLOCK.AddLcd(960);
|
|
|
|
// we have finished drawing a line, do our stuff...
|
|
if (vcount == 227) // this was the last line
|
|
{
|
|
vcount = 0; // we're now at first
|
|
// we reload the reference points
|
|
m_screen.UpdateBg2RefX(IO.DRead32(Io::BG2X_L));
|
|
m_screen.UpdateBg2RefY(IO.DRead32(Io::BG2Y_L));
|
|
m_screen.UpdateBg3RefX(IO.DRead32(Io::BG3X_L));
|
|
m_screen.UpdateBg3RefY(IO.DRead32(Io::BG3Y_L));
|
|
// and we draw the line 0
|
|
m_screen.DrawLine(0);
|
|
// FIXME see below, vblank finished
|
|
dispstat ^= 0x1;
|
|
}
|
|
else
|
|
{
|
|
++vcount; // we're on next line
|
|
if (vcount < 160) // we draw normally
|
|
m_screen.DrawLine(vcount);
|
|
else if (vcount == 160) // We enter V-Blank
|
|
{
|
|
dispstat |= 0x1;
|
|
if (dispstat & (0x1 << 3)) // if V-Blank irq is enabled
|
|
CPU.SendInterrupt(0x1);
|
|
DMA.CheckAll(Dma::VBlank);
|
|
|
|
KEYPAD.VBlank();
|
|
|
|
// we send the vblank signal
|
|
//sig_vblank.emit();
|
|
}
|
|
// NOTE : v-blank finishes on line 227, not 0
|
|
// FIXME on vba, it finishes on 0
|
|
//if (vcount == 227) // V-Blank finished
|
|
//dispstat ^= 0x1;
|
|
}
|
|
|
|
// check for vcount match
|
|
if (vcount == ((dispstat >> 8) & 0xFF)) // vcount match
|
|
{
|
|
dispstat |= 0x4; // enable vcount match bit
|
|
if (dispstat & (0x1 << 5)) // if V-Counter irq is enabled
|
|
CPU.SendInterrupt(0x4);
|
|
}
|
|
else // no vcount match
|
|
dispstat &= ~(uint16_t)0x4;
|
|
// scanline callback for frontend
|
|
if (slcallbackline == vcount)
|
|
scanlinecallback_bizhawk();
|
|
}
|
|
else // if we were not H-Blanking
|
|
{
|
|
//debug("hblank vcount : " << std::dec << vcount);
|
|
// now, we are
|
|
dispstat |= 0x2;
|
|
// call me when we are not H-Blanking anymore
|
|
CLOCK.AddLcd(272);
|
|
|
|
// NOTE : H-Blank interrupts are not generated during V-Blank
|
|
// FIXME vba generates hblank interrupts even during vblank
|
|
// if H-Blank irq is enabled //and we're not in V-Blank
|
|
if ((dispstat & 0x10) == 0x10)
|
|
CPU.SendInterrupt(0x2);
|
|
// NOTE : hblank DMAs are not triggered during vblank
|
|
// (seen on vba)
|
|
if (!(dispstat & 0x1))
|
|
// if we're not vblanking
|
|
DMA.CheckAll(Dma::HBlank);
|
|
}
|
|
}
|
|
|
|
bool Lcd::SaveState (std::ostream& stream)
|
|
{
|
|
if (!m_screen.SaveState(stream))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Lcd::LoadState (std::istream& stream)
|
|
{
|
|
if (!m_screen.LoadState(stream))
|
|
return false;
|
|
|
|
UpdateDispCnt (IO.DRead16(Io::DISPCNT));
|
|
UpdateBg0Cnt (IO.DRead16(Io::BG0CNT));
|
|
UpdateBg1Cnt (IO.DRead16(Io::BG1CNT));
|
|
UpdateBg2Cnt (IO.DRead16(Io::BG2CNT));
|
|
UpdateBg3Cnt (IO.DRead16(Io::BG3CNT));
|
|
UpdateBg0XOff (IO.DRead16(Io::BG0HOFS));
|
|
UpdateBg0YOff (IO.DRead16(Io::BG0VOFS));
|
|
UpdateBg1XOff (IO.DRead16(Io::BG1HOFS));
|
|
UpdateBg1YOff (IO.DRead16(Io::BG1VOFS));
|
|
UpdateBg2XOff (IO.DRead16(Io::BG2HOFS));
|
|
UpdateBg2YOff (IO.DRead16(Io::BG2VOFS));
|
|
UpdateBg3XOff (IO.DRead16(Io::BG3HOFS));
|
|
UpdateBg3YOff (IO.DRead16(Io::BG3VOFS));
|
|
OamWrite (0x07000000, 0x07000400);
|
|
|
|
return true;
|
|
}
|
|
}
|