#include #include #include 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); } for(int l = 0; l < 2; l++) std::memset(&tilemap[l], 0, 32*32); } void LCD::generate_tile(int idx) { 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))); } } } 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 < 32; row++) for(int col = 0; col < 32; col++) { unsigned int map_idx = row*32+col; sf::Texture txt; sf::Sprite spr; unsigned int tile_idx = tilemap[0][map_idx]; txt.loadFromImage(tiles[tile_idx]); spr.setTexture(txt,true); spr.setPosition(col*8,row*8); target.draw(spr); } }