161 lines
3.6 KiB
C++
161 lines
3.6 KiB
C++
#include <lcd/lcd.h>
|
|
#include <cstring>
|
|
|
|
#include <iostream>
|
|
|
|
LCD::LCD(Cpu& cpu)
|
|
: screenbuffer(), regLY(90), regLYC(0),
|
|
intHBlank(false), intVBlank(false), intOAM(false), intLYC(false),
|
|
cpu(cpu), bgp(false), obp{Palette(true),Palette(true)},
|
|
vram_dirty(true), currentMode(ModeVBlank)
|
|
{
|
|
screenbuffer.create(160,144);
|
|
screenbuffer.clear();
|
|
|
|
std::memset(vram_raw, 0, 0x2000);
|
|
|
|
for(int i = 0; i < 384; i++)
|
|
{
|
|
tiles[i].create(8,8,sf::Color::Red);
|
|
}
|
|
}
|
|
|
|
void LCD::generate_tile(int idx)
|
|
{
|
|
std::cerr << "Updating tile " << idx << std::endl;
|
|
for(int y = 0, addr = idx << 4; y < 8; y++, addr+=2)
|
|
{
|
|
u8 a = vram_raw[addr];
|
|
u8 b = vram_raw[addr+1];
|
|
for(int x = 7; x >= 0; x--, a>>=1, b>>=1)
|
|
{
|
|
tiles[idx].setPixel(x,y,bgp.getColorByIdx( ((a&0x1) << 1) | (b&0x1)));
|
|
//tiles[idx].setPixel(x,y,sf::Color::Red);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LCD::vram_write(u16 addr, u8 data)
|
|
{
|
|
if (Range(0x8000, 0x97FF).contains(addr))
|
|
{
|
|
generate_tile((addr & 0x1FFF) >> 4);
|
|
}
|
|
}
|
|
|
|
void LCD::write8(u16 addr, u8 data) {
|
|
// VRAM access
|
|
if (Range(0x8000,0x9FFF).contains(addr))
|
|
{
|
|
vram_raw[addr-0x8000] = data;
|
|
vram_dirty = true;
|
|
vram_write(addr, data);
|
|
return;
|
|
}
|
|
|
|
switch(addr)
|
|
{
|
|
case 0xFF40: // LCDC
|
|
// TODO
|
|
break;
|
|
case 0xFF41: // STAT
|
|
intHBlank = data & IntSourceHBlank;
|
|
intVBlank = data & IntSourceVBlank;
|
|
intOAM = data & IntSourceOAM;
|
|
intLYC = data & IntSourceLYC;
|
|
break;
|
|
case 0xFF42: // SCY
|
|
// TODO
|
|
break;
|
|
case 0xFF43: // SCX
|
|
// TODO
|
|
break;
|
|
case 0xFF44: // LY
|
|
// Ignore
|
|
break;
|
|
case 0xFF45: // LYC
|
|
regLYC = data;
|
|
break;
|
|
case 0xFF46: // DMA (OAM DMA source address)
|
|
// TODO
|
|
break;
|
|
case 0xFF47: // BGP
|
|
bgp.setRegValue(data);
|
|
vram_dirty = true;
|
|
break;
|
|
case 0xFF48: // OBP0
|
|
obp[0].setRegValue(data);
|
|
vram_dirty = true;
|
|
break;
|
|
case 0xFF49: // OBP1
|
|
obp[1].setRegValue(data);
|
|
vram_dirty = true;
|
|
break;
|
|
case 0xFF4A: // WY
|
|
case 0xFF4B: // WX
|
|
// TODO
|
|
break;
|
|
}
|
|
}
|
|
|
|
u8 LCD::read8(u16 addr) {
|
|
// VRAM access
|
|
if (Range(0x8000,0x9FFF).contains(addr))
|
|
return vram_raw[addr-0x8000];
|
|
|
|
switch(addr)
|
|
{
|
|
case 0xFF40: // LCDC
|
|
// TODO
|
|
return 0x00;
|
|
case 0xFF41: // STAT
|
|
return (currentMode |
|
|
(regLY == regLYC ? LycEqual : 0) |
|
|
(intHBlank ? IntSourceHBlank : 0) |
|
|
(intVBlank ? IntSourceVBlank : 0) |
|
|
(intOAM ? IntSourceOAM : 0) |
|
|
(intLYC ? IntSourceLYC : 0));
|
|
case 0xFF42: // SCY
|
|
// TODO
|
|
return 0x00;
|
|
case 0xFF43: // SCX
|
|
// TODO
|
|
return 0x00;
|
|
case 0xFF44: // LY
|
|
return regLY;
|
|
case 0xFF45: // LYC
|
|
return regLYC;
|
|
case 0xFF46: // DMA (OAM DMA source address)
|
|
// TODO
|
|
return 0x00;
|
|
case 0xFF47: // BGP
|
|
return bgp.getRegValue();
|
|
case 0xFF48: // OBP0
|
|
return obp[0].getRegValue();
|
|
case 0xFF49: // OBP1
|
|
return obp[1].getRegValue();
|
|
case 0xFF4A: // WY
|
|
case 0xFF4B: // WY
|
|
// TODO
|
|
return 0x00;
|
|
default:
|
|
return 0xFF;
|
|
}
|
|
}
|
|
|
|
void LCD::render(sf::RenderTarget& target)
|
|
{
|
|
cpu.signalInterrupt(INT_VBlank);
|
|
for(int row = 0; row < 16; row++)
|
|
for(int col = 0; col < 12; col++)
|
|
{
|
|
unsigned int idx = row*12+col;
|
|
sf::Texture txt;
|
|
sf::Sprite spr;
|
|
|
|
txt.loadFromImage(tiles[idx]);
|
|
spr.setTexture(txt,true);
|
|
spr.setPosition(col*8,row*8);
|
|
target.draw(spr);
|
|
}
|
|
}
|