lcd - Initial work on the LCD/PPU
This commit is contained in:
parent
dc81fcb4e5
commit
1716fe1e98
5 changed files with 232 additions and 1 deletions
4
Makeconf
4
Makeconf
|
@ -17,7 +17,9 @@ modules_libemu.a := memory/device.o \
|
|||
cpu/cpu.o \
|
||||
cpu/decoder.o \
|
||||
cartridge/mbc/mbc1.o \
|
||||
cartridge/cartridge.o
|
||||
cartridge/cartridge.o \
|
||||
lcd/lcd.o \
|
||||
lcd/palette.o \
|
||||
|
||||
modules_vgbc := main.o libemu.a
|
||||
verb_vgbc := link
|
||||
|
|
117
lcd/lcd.cpp
Normal file
117
lcd/lcd.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include <lcd/lcd.h>
|
||||
#include <cstring>
|
||||
|
||||
LCD::LCD(Cpu& cpu)
|
||||
: screenbuffer(), regLY(0), regLYC(0),
|
||||
intHBlank(false), intVBlank(false), intOAM(false), intLYC(false),
|
||||
cpu(cpu), bgp(false), obp{Palette(true),Palette(true)},
|
||||
vram_dirty(true)
|
||||
{
|
||||
screenbuffer.create(160,144);
|
||||
screenbuffer.clear();
|
||||
|
||||
std::memset(vram_raw, 0, 0x2000);
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
tilemap[i].create(8,8);
|
||||
}
|
||||
|
||||
|
||||
void LCD::write8(u16 addr, u8 data) {
|
||||
// VRAM access
|
||||
if (Range(0x8000,0x9FFF).contains(addr))
|
||||
{
|
||||
vram_raw[addr-0x8000] = data;
|
||||
vram_dirty = true;
|
||||
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;
|
||||
}
|
||||
}
|
55
lcd/lcd.h
Normal file
55
lcd/lcd.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <memory/device.h>
|
||||
#include <misc/types.h>
|
||||
#include <lcd/palette.h>
|
||||
#include <cpu/cpu.h>
|
||||
|
||||
class LCD;
|
||||
|
||||
enum LCDMode : u8 {
|
||||
ModeHBlank = 0b000000000,
|
||||
ModeVBlank = 0b000000001,
|
||||
ModeOAMSearch = 0b000000010,
|
||||
ModeTransferring = 0b000000011,
|
||||
};
|
||||
|
||||
enum RegStat : u8 {
|
||||
LycEqual = 0b000000100,
|
||||
IntSourceHBlank = 0b000001000,
|
||||
IntSourceVBlank = 0b000010000,
|
||||
IntSourceOAM = 0b000100000,
|
||||
IntSourceLYC = 0b001000000,
|
||||
};
|
||||
|
||||
class LCD : public Mem_device {
|
||||
private:
|
||||
// Graphics
|
||||
sf::RenderTexture screenbuffer;
|
||||
sf::Image tilemap[256];
|
||||
|
||||
// Emulated device
|
||||
u8 regLY;
|
||||
u8 regLYC;
|
||||
bool intHBlank;
|
||||
bool intVBlank;
|
||||
bool intOAM;
|
||||
bool intLYC;
|
||||
LCDMode currentMode;
|
||||
Palette bgp;
|
||||
Palette obp[2];
|
||||
|
||||
u8 vram_raw[0x2000];
|
||||
|
||||
// misc
|
||||
Cpu& cpu;
|
||||
bool enabled;
|
||||
bool vram_dirty;
|
||||
|
||||
public:
|
||||
LCD(Cpu& cpu);
|
||||
|
||||
virtual void write8(u16 addr, u8 data);
|
||||
virtual u8 read8(u16 addr);
|
||||
};
|
36
lcd/palette.cpp
Normal file
36
lcd/palette.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <lcd/palette.h>
|
||||
|
||||
const sf::Color Palette::colors[] = {
|
||||
sf::Color(255,255,255),
|
||||
sf::Color(170,170,170),
|
||||
sf::Color(85,85,85),
|
||||
sf::Color(0,0,0),
|
||||
};
|
||||
|
||||
const sf::Color Palette::transparent(0,0,0,255);
|
||||
|
||||
Palette::Palette(bool transparent0)
|
||||
: transparent0(transparent0)
|
||||
{
|
||||
setRegValue(0);
|
||||
}
|
||||
|
||||
void Palette::setRegValue(u8 regval)
|
||||
{
|
||||
for(int i = 0; i < 4; i++, regval >>= 2)
|
||||
idx_to_color[i] = regval & 0x3;
|
||||
}
|
||||
|
||||
u8 Palette::getRegValue()
|
||||
{
|
||||
u8 regval = 0;
|
||||
for(int i = 0; i < 4; i++, regval <<= 2)
|
||||
regval |= idx_to_color[i] & 0x3;
|
||||
return regval;
|
||||
}
|
||||
|
||||
const sf::Color& Palette::getColorByIdx(u8 idx)
|
||||
{
|
||||
if(idx == 0 && transparent0) return transparent;
|
||||
return colors[idx_to_color[idx]];
|
||||
}
|
21
lcd/palette.h
Normal file
21
lcd/palette.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <misc/types.h>
|
||||
|
||||
class Palette {
|
||||
private:
|
||||
static const sf::Color colors[4];
|
||||
static const sf::Color transparent;
|
||||
|
||||
u8 idx_to_color[4];
|
||||
bool transparent0;
|
||||
public:
|
||||
Palette(bool transparent0);
|
||||
|
||||
void setRegValue(u8 regval);
|
||||
u8 getRegValue();
|
||||
|
||||
const sf::Color& getColorByIdx(u8 idx);
|
||||
|
||||
};
|
Loading…
Reference in a new issue