Update to v078r06 release.

byuu says:

This adds ikari_01's emulation of the ICD2 (Super Game Boy) $6001 register.

It basically removes a really ugly hack where I was intercepting the DMA
transfer destination address to determine while Game Boy tile row to
transfer.  This should make implementing SGB emulation in other
emulators easier, as said hooks were very emulator-specific.
This commit is contained in:
Tim Allen 2011-05-08 23:46:37 +10:00
parent 52443936e6
commit bc0b86891a
9 changed files with 67 additions and 60 deletions

View File

@ -1,5 +1,6 @@
class Interface { class Interface {
public: public:
virtual void lcd_scanline() {}
virtual void joyp_write(bool p15, bool p14) {} virtual void joyp_write(bool p15, bool p14) {}
virtual void video_refresh(const uint8_t *data) {} virtual void video_refresh(const uint8_t *data) {}

View File

@ -75,6 +75,7 @@ void LCD::render() {
uint8_t *output = screen + status.ly * 160; uint8_t *output = screen + status.ly * 160;
for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55; for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55;
system.interface->lcd_scanline();
} }
uint16 LCD::read_tile(bool select, unsigned x, unsigned y) { uint16 LCD::read_tile(bool select, unsigned x, unsigned y) {

View File

@ -33,10 +33,6 @@ void ICD2::init() {
} }
void ICD2::load() { void ICD2::load() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
} }
void ICD2::unload() { void ICD2::unload() {
@ -52,10 +48,8 @@ void ICD2::power() {
void ICD2::reset() { void ICD2::reset() {
create(ICD2::Enter, cpu.frequency / 5); create(ICD2::Enter, cpu.frequency / 5);
r2181 = 0x00; r6000_ly = 0x00;
r2182 = 0x00; r6000_row = 0x00;
r6000 = 0x00;
r6003 = 0x00; r6003 = 0x00;
r6004 = 0xff; r6004 = 0xff;
r6005 = 0xff; r6005 = 0xff;
@ -65,7 +59,9 @@ void ICD2::reset() {
r7800 = 0x0000; r7800 = 0x0000;
mlt_req = 0; mlt_req = 0;
for(unsigned n = 0; n < 320; n++) vram[n] = 0xff; foreach(byte, lcd.buffer) byte = 0xff;
foreach(byte, lcd.output) byte = 0xff;
lcd.row = 0;
packetsize = 0; packetsize = 0;
joyp_id = 3; joyp_id = 3;

View File

@ -1,5 +1,15 @@
#ifdef ICD2_CPP #ifdef ICD2_CPP
//called on rendered lines 0-143 (not on Vblank lines 144-153)
void ICD2::lcd_scanline() {
if((GameBoy::lcd.status.ly & 7) == 0) {
lcd.row = (lcd.row + 1) & 3;
}
unsigned offset = (lcd.row * 160 * 8) + ((GameBoy::lcd.status.ly & 7) * 160);
memcpy(lcd.buffer + offset, GameBoy::lcd.screen + GameBoy::lcd.status.ly * 160, 160);
}
void ICD2::joyp_write(bool p15, bool p14) { void ICD2::joyp_write(bool p15, bool p14) {
//joypad handling //joypad handling
if(p15 == 1 && p14 == 1) { if(p15 == 1 && p14 == 1) {

View File

@ -1,3 +1,4 @@
void lcd_scanline();
void joyp_write(bool p15, bool p14); void joyp_write(bool p15, bool p14);
void video_refresh(const uint8_t *data); void video_refresh(const uint8_t *data);
void audio_sample(int16_t center, int16_t left, int16_t right); void audio_sample(int16_t center, int16_t left, int16_t right);

View File

@ -1,38 +1,19 @@
#ifdef ICD2_CPP #ifdef ICD2_CPP
uint8 ICD2::mmio_read(unsigned addr) { //convert linear pixel data { 0x00, 0x55, 0xaa, 0xff } to 2bpp planar tiledata
if((uint16)addr == 0x2181) return cpu.mmio_read(addr); void ICD2::render(const uint8 *source) {
if((uint16)addr == 0x2182) return cpu.mmio_read(addr); memset(lcd.output, 0x00, 320);
if((uint16)addr == 0x420b) return cpu.mmio_read(addr);
return 0x00;
}
void ICD2::mmio_write(unsigned addr, uint8 data) { for(unsigned y = 0; y < 8; y++) {
if((uint16)addr == 0x420b && data == 0x10) { for(unsigned x = 0; x < 160; x++) {
unsigned offset = (r2182 << 8) | (r2181 << 0); unsigned pixel = *source++ / 0x55;
r7800 = 0; pixel ^= 3;
unsigned row = 0;
if(offset >= 0x5000 && offset <= 0x6540) row = (offset - 0x5000) / 320;
if(offset >= 0x6800 && offset <= 0x7d40) row = (offset - 0x6800) / 320;
uint8 *source = GameBoy::lcd.screen + row * 160 * 8; unsigned addr = y * 2 + (x / 8 * 16);
memset(vram, 0x00, 320); lcd.output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
lcd.output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
for(unsigned y = row * 8; y < row * 8 + 8; y++) {
for(unsigned x = 0; x < 160; x++) {
unsigned pixel = *source++ / 0x55;
pixel ^= 3;
unsigned addr = (x / 8 * 16) + ((y & 7) * 2);
vram[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
vram[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
}
} }
} }
if((uint16)addr == 0x2181) return cpu.mmio_write(addr, r2181 = data);
if((uint16)addr == 0x2182) return cpu.mmio_write(addr, r2182 = data);
if((uint16)addr == 0x420b) return cpu.mmio_write(addr, data);
} }
uint8 ICD2::read(unsigned addr) { uint8 ICD2::read(unsigned addr) {
@ -40,7 +21,9 @@ uint8 ICD2::read(unsigned addr) {
//LY counter //LY counter
if(addr == 0x6000) { if(addr == 0x6000) {
return GameBoy::lcd.status.ly; r6000_ly = GameBoy::lcd.status.ly;
r6000_row = lcd.row;
return r6000_ly;
} }
//command ready port //command ready port
@ -66,7 +49,7 @@ uint8 ICD2::read(unsigned addr) {
//VRAM port //VRAM port
if(addr == 0x7800) { if(addr == 0x7800) {
uint8 data = vram[r7800]; uint8 data = lcd.output[r7800];
r7800 = (r7800 + 1) % 320; r7800 = (r7800 + 1) % 320;
return data; return data;
} }
@ -77,6 +60,17 @@ uint8 ICD2::read(unsigned addr) {
void ICD2::write(unsigned addr, uint8 data) { void ICD2::write(unsigned addr, uint8 data) {
addr &= 0xffff; addr &= 0xffff;
//VRAM port
if(addr == 0x6001) {
r6001 = data;
r7800 = 0;
unsigned offset = (r6000_row - (4 - (r6001 - (r6000_ly & 3)))) & 3;
render(lcd.buffer + offset * 160 * 8);
return;
}
//control port //control port
//d7: 0 = halt, 1 = reset //d7: 0 = halt, 1 = reset
//d5,d4: 0 = 1-player, 1 = 2-player, 2 = 4-player, 3 = ??? //d5,d4: 0 = 1-player, 1 = 2-player, 2 = 4-player, 3 = ???

View File

@ -1,16 +1,19 @@
uint8 r2181; void render(const uint8 *source);
uint8 r2182;
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 r6000; uint8 r6000_ly; //SGB BIOS' cache of LY
uint8 r6003; uint8 r6000_row; //SGB BIOS' cache of ROW
uint8 r6004; uint8 r6001; //VRAM conversion
uint8 r6005; uint8 r6003; //control port
uint8 r6006; uint8 r6004; //joypad 1
uint8 r6007; uint8 r6005; //joypad 2
uint8 r7000[16]; uint8 r6006; //joypad 3
unsigned r7800; uint8 r6007; //joypad 4
uint8 mlt_req; uint8 r7000[16]; //JOYP packet data
unsigned r7800; //VRAM offset
uint8 mlt_req; //number of active joypads
uint8 vram[320]; struct LCD {
uint8 buffer[4 * 160 * 8]; //four tile rows of linear video data
uint8 output[320]; //one tile row of 2bpp video data
unsigned row; //active ICD2 rendering tile row
} lcd;

View File

@ -18,10 +18,9 @@ void ICD2::serialize(serializer &s) {
s.integer(bitdata); s.integer(bitdata);
s.integer(bitoffset); s.integer(bitoffset);
s.integer(r2181); s.integer(r6000_ly);
s.integer(r2182); s.integer(r6000_row);
s.integer(r6001);
s.integer(r6000);
s.integer(r6003); s.integer(r6003);
s.integer(r6004); s.integer(r6004);
s.integer(r6005); s.integer(r6005);
@ -31,7 +30,9 @@ void ICD2::serialize(serializer &s) {
s.integer(r7800); s.integer(r7800);
s.integer(mlt_req); s.integer(mlt_req);
s.array(vram); s.array(lcd.buffer);
s.array(lcd.output);
s.integer(lcd.row);
} }
#endif #endif

View File

@ -1,7 +1,7 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "078.05"; static const char Version[] = "078.06";
static const unsigned SerializerVersion = 20; static const unsigned SerializerVersion = 20;
} }
} }