2012-04-26 10:51:13 +00:00
|
|
|
#ifdef PPU_CPP
|
2010-12-29 11:03:42 +00:00
|
|
|
|
2012-04-26 10:51:13 +00:00
|
|
|
unsigned PPU::vram_addr(uint16 addr) const {
|
2011-10-27 00:00:17 +00:00
|
|
|
return (status.vram_bank * 0x2000) + (addr & 0x1fff);
|
|
|
|
}
|
|
|
|
|
2012-04-26 10:51:13 +00:00
|
|
|
uint8 PPU::mmio_read(uint16 addr) {
|
2011-10-27 00:00:17 +00:00
|
|
|
if(addr >= 0x8000 && addr <= 0x9fff) return vram[vram_addr(addr)];
|
2010-12-29 11:03:42 +00:00
|
|
|
if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff];
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
if(addr == 0xff40) { //LCDC
|
|
|
|
return (status.display_enable << 7)
|
|
|
|
| (status.window_tilemap_select << 6)
|
|
|
|
| (status.window_display_enable << 5)
|
|
|
|
| (status.bg_tiledata_select << 4)
|
|
|
|
| (status.bg_tilemap_select << 3)
|
2011-10-28 09:51:43 +00:00
|
|
|
| (status.ob_size << 2)
|
|
|
|
| (status.ob_enable << 1)
|
2011-01-02 04:46:54 +00:00
|
|
|
| (status.bg_enable << 0);
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff41) { //STAT
|
2011-01-02 04:46:54 +00:00
|
|
|
unsigned mode;
|
2011-08-19 11:36:26 +00:00
|
|
|
if(status.ly >= 144) mode = 1; //Vblank
|
2011-08-18 13:58:27 +00:00
|
|
|
else if(status.lx < 80) mode = 2; //OAM
|
Update to v074r11 release.
byuu says:
Changelog:
- debugger compiles on all three profiles
- libsnes compiles on all three platforms (no API changes to libsnes)
- memory.cpp : namespace memory removed (wram -> cpu, apuram -> smp,
vram, oam, cgram -> ppu)
- sa1.cpp : namespace memory removed (SA-1 specific functions merged
inline to SA1::bus_read,write)
- GameBoy: added serial link support with interrupts and proper 8192hz
timing, but obviously it acts as if no other GB is connected to it
- GameBoy: added STAT OAM interrupt, and better STAT d1,d0 mode values
- UI: since Qt is dead, I've renamed the config files back to bsnes.cfg
and bsnes-geometry.cfg
- SA1: IRAM was not syncing to CPU on SA-1 side
- PPU/Accuracy and PPU/Performance needed Sprite oam renamed to Sprite
sprite; so that I could add uint8 oam[544]
- makes more sense anyway, OAM = object attribute memory, obj or
sprite are better names for Sprite rendering class
- more cleanup
2011-01-24 09:03:17 +00:00
|
|
|
else if(status.lx < 252) mode = 3; //LCD
|
2011-08-18 13:58:27 +00:00
|
|
|
else mode = 0; //Hblank
|
2011-01-02 04:46:54 +00:00
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
return (status.interrupt_lyc << 6)
|
|
|
|
| (status.interrupt_oam << 5)
|
|
|
|
| (status.interrupt_vblank << 4)
|
|
|
|
| (status.interrupt_hblank << 3)
|
2011-01-02 04:46:54 +00:00
|
|
|
| ((status.ly == status.lyc) << 2)
|
|
|
|
| (mode << 0);
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff42) { //SCY
|
|
|
|
return status.scy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff43) { //SCX
|
|
|
|
return status.scx;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff44) { //LY
|
2010-12-29 11:03:42 +00:00
|
|
|
return status.ly;
|
|
|
|
}
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
if(addr == 0xff45) { //LYC
|
|
|
|
return status.lyc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff47) { //BGP
|
2011-10-27 00:00:17 +00:00
|
|
|
return (bgp[3] << 6)
|
|
|
|
| (bgp[2] << 4)
|
|
|
|
| (bgp[1] << 2)
|
|
|
|
| (bgp[0] << 0);
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff48) { //OBP0
|
2011-10-27 00:00:17 +00:00
|
|
|
return (obp[0][3] << 6)
|
|
|
|
| (obp[0][2] << 4)
|
|
|
|
| (obp[0][1] << 2)
|
|
|
|
| (obp[0][0] << 0);
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff49) { //OBP1
|
2011-10-27 00:00:17 +00:00
|
|
|
return (obp[1][3] << 6)
|
|
|
|
| (obp[1][2] << 4)
|
|
|
|
| (obp[1][1] << 2)
|
|
|
|
| (obp[1][0] << 0);
|
2010-12-30 07:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff4a) { //WY
|
|
|
|
return status.wy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff4b) { //WX
|
|
|
|
return status.wx;
|
|
|
|
}
|
|
|
|
|
2011-10-27 00:00:17 +00:00
|
|
|
if(addr == 0xff69) { //BGPD
|
|
|
|
return bgpd[status.bgpi];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff6b) { //OBPD
|
|
|
|
return obpd[status.obpi];
|
|
|
|
}
|
|
|
|
|
2010-12-29 11:03:42 +00:00
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
2012-04-26 10:51:13 +00:00
|
|
|
void PPU::mmio_write(uint16 addr, uint8 data) {
|
2011-10-27 00:00:17 +00:00
|
|
|
if(addr >= 0x8000 && addr <= 0x9fff) { vram[vram_addr(addr)] = data; return; }
|
2010-12-29 11:03:42 +00:00
|
|
|
if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; }
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
if(addr == 0xff40) { //LCDC
|
2011-08-19 11:36:26 +00:00
|
|
|
if(status.display_enable == false && (data & 0x80)) {
|
|
|
|
status.lx = 0; //unverified behavior; fixes Super Mario Land 2 - Tree Zone
|
|
|
|
}
|
|
|
|
|
2010-12-30 07:18:47 +00:00
|
|
|
status.display_enable = data & 0x80;
|
|
|
|
status.window_tilemap_select = data & 0x40;
|
|
|
|
status.window_display_enable = data & 0x20;
|
|
|
|
status.bg_tiledata_select = data & 0x10;
|
|
|
|
status.bg_tilemap_select = data & 0x08;
|
2011-10-28 09:51:43 +00:00
|
|
|
status.ob_size = data & 0x04;
|
|
|
|
status.ob_enable = data & 0x02;
|
2011-01-02 04:46:54 +00:00
|
|
|
status.bg_enable = data & 0x01;
|
2010-12-30 07:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff41) { //STAT
|
|
|
|
status.interrupt_lyc = data & 0x40;
|
|
|
|
status.interrupt_oam = data & 0x20;
|
|
|
|
status.interrupt_vblank = data & 0x10;
|
|
|
|
status.interrupt_hblank = data & 0x08;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff42) { //SCY
|
|
|
|
status.scy = data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff43) { //SCX
|
|
|
|
status.scx = data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff44) { //LY
|
2010-12-29 11:03:42 +00:00
|
|
|
status.ly = 0;
|
|
|
|
return;
|
|
|
|
}
|
2010-12-30 07:18:47 +00:00
|
|
|
|
|
|
|
if(addr == 0xff45) { //LYC
|
|
|
|
status.lyc = data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff47) { //BGP
|
2011-10-27 00:00:17 +00:00
|
|
|
bgp[3] = (data >> 6) & 3;
|
|
|
|
bgp[2] = (data >> 4) & 3;
|
|
|
|
bgp[1] = (data >> 2) & 3;
|
|
|
|
bgp[0] = (data >> 0) & 3;
|
2010-12-30 07:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff48) { //OBP0
|
2011-10-27 00:00:17 +00:00
|
|
|
obp[0][3] = (data >> 6) & 3;
|
|
|
|
obp[0][2] = (data >> 4) & 3;
|
|
|
|
obp[0][1] = (data >> 2) & 3;
|
|
|
|
obp[0][0] = (data >> 0) & 3;
|
2010-12-30 07:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff49) { //OBP1
|
2011-10-27 00:00:17 +00:00
|
|
|
obp[1][3] = (data >> 6) & 3;
|
|
|
|
obp[1][2] = (data >> 4) & 3;
|
|
|
|
obp[1][1] = (data >> 2) & 3;
|
|
|
|
obp[1][0] = (data >> 0) & 3;
|
2010-12-30 07:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff4a) { //WY
|
|
|
|
status.wy = data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff4b) { //WX
|
|
|
|
status.wx = data;
|
|
|
|
return;
|
|
|
|
}
|
2011-10-27 00:00:17 +00:00
|
|
|
|
|
|
|
if(addr == 0xff4f) { //VBK
|
|
|
|
status.vram_bank = data & 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff68) { //BGPI
|
|
|
|
status.bgpi_increment = data & 0x80;
|
|
|
|
status.bgpi = data & 0x3f;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff69) { //BGPD
|
|
|
|
bgpd[status.bgpi] = data;
|
|
|
|
if(status.bgpi_increment) status.bgpi++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff6a) { //OBPI
|
|
|
|
status.obpi_increment = data & 0x80;
|
|
|
|
status.obpi = data & 0x3f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0xff6b) { //OBPD
|
|
|
|
obpd[status.obpi] = data;
|
|
|
|
if(status.obpi_increment) status.obpi++;
|
|
|
|
}
|
2010-12-29 11:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|