SNES: added PPU1/PPU2 Open Bus support, STAT77/STAT78 registers should be more accurate (even if still not perfect)

This commit is contained in:
Fabio Priuli 2009-08-09 23:08:07 +00:00
parent 6f1d76124a
commit 060c4654ac
2 changed files with 73 additions and 37 deletions

View File

@ -489,6 +489,8 @@ struct SNES_PPU_STRUCT /* once all the regs are saved in this structure, it woul
UINT8 main_bg_enabled[5]; // these would probably better fit the layer struct, but it would make worse the code in snes_update_mode_X() UINT8 main_bg_enabled[5]; // these would probably better fit the layer struct, but it would make worse the code in snes_update_mode_X()
UINT8 sub_bg_enabled[5]; UINT8 sub_bg_enabled[5];
UINT8 ppu1_open_bus;
UINT8 ppu2_open_bus;
UINT16 mosaic_table[16][4096]; UINT16 mosaic_table[16][4096];
UINT8 clipmasks[6][SNES_SCR_WIDTH + 8]; UINT8 clipmasks[6][SNES_SCR_WIDTH + 8];

View File

@ -73,7 +73,7 @@ static void snes_latch_counters(running_machine *machine)
snes_ppu.beam.latch_vert = video_screen_get_vpos(machine->primary_screen); snes_ppu.beam.latch_vert = video_screen_get_vpos(machine->primary_screen);
snes_ppu.beam.latch_horz = snes_ppu.beam.current_horz; snes_ppu.beam.latch_horz = snes_ppu.beam.current_horz;
snes_ram[STAT78] |= 0x40; // indicate we latched snes_ram[STAT78] |= 0x40; // indicate we latched
read_ophct = read_opvct = 0; // clear read flags // read_ophct = read_opvct = 0; // clear read flags - 2009-08: I think we must clear these when STAT78 is read...
// printf("latched @ H %d V %d\n", snes_ppu.beam.latch_horz, snes_ppu.beam.latch_vert); // printf("latched @ H %d V %d\n", snes_ppu.beam.latch_horz, snes_ppu.beam.latch_vert);
} }
@ -351,39 +351,56 @@ READ8_HANDLER( snes_r_io )
return 0; return 0;
case 0x2016: case 0x2016:
return 2; return 2;
case OAMDATA: /* 21xy for x=0,1,2 and y=4,5,6,8,9,a returns PPU1 open bus*/
case BGMODE:
case MOSAIC:
case BG2SC:
case BG3SC:
case BG4SC:
case BG4VOFS:
case VMAIN:
case VMADDL:
case VMDATAL:
case VMDATAH:
case M7SEL:
case W34SEL:
case WOBJSEL:
case WH0:
case WH2:
case WH3:
case WBGLOG:
return snes_ppu.ppu1_open_bus;
/* Shien The Blade Chaser / Shien's Revenge reads here instead */ /* Shien The Blade Chaser / Shien's Revenge reads here instead */
case NMITIMEN: case NMITIMEN:
return snes_open_bus_r(space,0); return snes_open_bus_r(space,0);
case OAMADDL: // According to BSNES, these should return snes_open_bus_r!
case OAMADDH: // case OAMADDL:
case VMADDL: // case OAMADDH:
case VMADDH: // case VMADDH:
case VMDATAL: // case CGADD:
case VMDATAH: // case CGDATA:
case CGADD: // return snes_ram[offset];
case CGDATA:
return snes_ram[offset];
case MPYL: /* Multiplication result (low) */ case MPYL: /* Multiplication result (low) */
{ {
/* Perform 16bit * 8bit multiply */ /* Perform 16bit * 8bit multiply */
UINT32 c = snes_ppu.mode7.matrix_a * (INT8)(snes_ppu.mode7.matrix_b >> 8); UINT32 c = snes_ppu.mode7.matrix_a * (INT8)(snes_ppu.mode7.matrix_b >> 8);
snes_ram[MPYL] = c & 0xff; snes_ppu.ppu1_open_bus = c & 0xff;
return snes_ram[MPYL]; return snes_ppu.ppu1_open_bus;
} }
case MPYM: /* Multiplication result (mid) */ case MPYM: /* Multiplication result (mid) */
{ {
/* Perform 16bit * 8bit multiply */ /* Perform 16bit * 8bit multiply */
UINT32 c = snes_ppu.mode7.matrix_a * (INT8)(snes_ppu.mode7.matrix_b >> 8); UINT32 c = snes_ppu.mode7.matrix_a * (INT8)(snes_ppu.mode7.matrix_b >> 8);
snes_ram[MPYM] = (c >> 8) & 0xff; snes_ppu.ppu1_open_bus = (c >> 8) & 0xff;
return snes_ram[MPYM]; return snes_ppu.ppu1_open_bus;
} }
case MPYH: /* Multiplication result (high) */ case MPYH: /* Multiplication result (high) */
{ {
/* Perform 16bit * 8bit multiply */ /* Perform 16bit * 8bit multiply */
UINT32 c = snes_ppu.mode7.matrix_a * (INT8)(snes_ppu.mode7.matrix_b >> 8); UINT32 c = snes_ppu.mode7.matrix_a * (INT8)(snes_ppu.mode7.matrix_b >> 8);
snes_ram[MPYH] = (c >> 16) & 0xff; snes_ppu.ppu1_open_bus = (c >> 16) & 0xff;
return snes_ram[MPYH]; return snes_ppu.ppu1_open_bus;
} }
case SLHV: /* Software latch for H/V counter */ case SLHV: /* Software latch for H/V counter */
snes_latch_counters(space->machine); snes_latch_counters(space->machine);
@ -401,7 +418,7 @@ READ8_HANDLER( snes_r_io )
oam_addr &= 0x1ff; oam_addr &= 0x1ff;
} }
value = (snes_oam[oam_addr] >> (snes_ram[OAMDATA] << 3)) & 0xff; snes_ppu.ppu1_open_bus = (snes_oam[oam_addr] >> (snes_ram[OAMDATA] << 3)) & 0xff;
snes_ram[OAMDATA] = (snes_ram[OAMDATA] + 1) % 2; snes_ram[OAMDATA] = (snes_ram[OAMDATA] + 1) % 2;
if( snes_ram[OAMDATA] == 0 ) if( snes_ram[OAMDATA] == 0 )
{ {
@ -409,13 +426,13 @@ READ8_HANDLER( snes_r_io )
snes_ppu.oam.address_low = snes_ram[OAMADDL] = snes_ppu.oam.address & 0xff; snes_ppu.oam.address_low = snes_ram[OAMADDL] = snes_ppu.oam.address & 0xff;
snes_ppu.oam.address_high = snes_ram[OAMADDH] = (snes_ppu.oam.address >> 8) & 0x1; snes_ppu.oam.address_high = snes_ram[OAMADDH] = (snes_ppu.oam.address >> 8) & 0x1;
} }
return value; return snes_ppu.ppu1_open_bus;
} }
case RVMDATAL: /* Read data from VRAM (low) */ case RVMDATAL: /* Read data from VRAM (low) */
{ {
UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL];
value = vram_read_buffer & 0xff; snes_ppu.ppu1_open_bus = vram_read_buffer & 0xff;
if (!vram_fgr_high) if (!vram_fgr_high)
{ {
@ -437,12 +454,12 @@ READ8_HANDLER( snes_r_io )
snes_ram[VMADDH] = (addr>>8)&0xff; snes_ram[VMADDH] = (addr>>8)&0xff;
} }
} }
return value; return snes_ppu.ppu1_open_bus;
case RVMDATAH: /* Read data from VRAM (high) */ case RVMDATAH: /* Read data from VRAM (high) */
{ {
UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL];
value = (vram_read_buffer>>8) & 0xff; snes_ppu.ppu1_open_bus = (vram_read_buffer>>8) & 0xff;
if (vram_fgr_high) if (vram_fgr_high)
{ {
@ -464,48 +481,65 @@ READ8_HANDLER( snes_r_io )
snes_ram[VMADDH] = (addr>>8)&0xff; snes_ram[VMADDH] = (addr>>8)&0xff;
} }
} }
return value; return snes_ppu.ppu1_open_bus;
case RCGDATA: /* Read data from CGRAM */ case RCGDATA: /* Read data from CGRAM */
value = ((UINT8 *)snes_cgram)[cgram_address]; if (cgram_address & 0x01)
{
snes_ppu.ppu2_open_bus = ((UINT8 *)snes_cgram)[cgram_address] & 0xff;
}
else
{
snes_ppu.ppu2_open_bus &= 0x80;
snes_ppu.ppu2_open_bus |= ((UINT8 *)snes_cgram)[cgram_address] & 0x7f;
}
cgram_address = (cgram_address + 1) % (SNES_CGRAM_SIZE - 2); cgram_address = (cgram_address + 1) % (SNES_CGRAM_SIZE - 2);
return value; return snes_ppu.ppu2_open_bus;
case OPHCT: /* Horizontal counter data by ext/soft latch */ case OPHCT: /* Horizontal counter data by ext/soft latch */
{ {
/* FIXME: need to handle STAT78 reset */ /* FIXME: need to handle STAT78 reset */
if( read_ophct ) if( read_ophct )
{ {
value = (snes_ppu.beam.latch_horz >> 8) & 0x1; snes_ppu.ppu2_open_bus &= 0xfe;
read_ophct = 0; snes_ppu.ppu2_open_bus |= (snes_ppu.beam.latch_horz >> 8) & 0x01;
} }
else else
{ {
value = snes_ppu.beam.latch_horz & 0xff; snes_ppu.ppu2_open_bus = snes_ppu.beam.latch_horz & 0xff;
read_ophct = 1;
} }
return value; read_ophct ^= 1;
return snes_ppu.ppu2_open_bus;
} }
case OPVCT: /* Vertical counter data by ext/soft latch */ case OPVCT: /* Vertical counter data by ext/soft latch */
{ {
/* FIXME: need to handle STAT78 reset */ /* FIXME: need to handle STAT78 reset */
if( read_opvct ) if( read_opvct )
{ {
value = (snes_ppu.beam.latch_vert >> 8) & 0x1; snes_ppu.ppu2_open_bus &= 0xfe;
read_opvct = 0; snes_ppu.ppu2_open_bus |= (snes_ppu.beam.latch_vert >> 8) & 0x01;
} }
else else
{ {
value = snes_ppu.beam.latch_vert & 0xff; snes_ppu.ppu2_open_bus = snes_ppu.beam.latch_vert & 0xff;
read_opvct = 1;
} }
return value; read_opvct ^= 1;
return snes_ppu.ppu2_open_bus;
} }
case STAT77: /* PPU status flag and version number */ case STAT77: /* PPU status flag and version number */
return snes_ram[offset]; value = snes_ram[offset] & 0xc0; // 0x80 & 0x40 are Time Over / Range Over Sprite flags, set by the video code
// 0x20 - Master/slave mode select. Little is known about this bit. We always seem to read back 0 here.
value |= (snes_ppu.ppu1_open_bus & 0x10);
snes_ram[offset] = value; // not sure if this is needed...
snes_ppu.ppu1_open_bus = value;
return snes_ppu.ppu1_open_bus;
case STAT78: /* PPU status flag and version number */ case STAT78: /* PPU status flag and version number */
/* FIXME: need to reset OPHCT and OPVCT */ /* FIXME: need to reset OPHCT and OPVCT */
value = snes_ram[offset]; value = snes_ram[offset];
snes_ram[offset] &= ~0x40; // clear 'latched counters' flag value &= ~0x40; // clear 'latched counters' flag
return value; value |= (snes_ppu.ppu1_open_bus & 0x20);
snes_ram[offset] = value; // not sure if this is needed...
snes_ppu.ppu2_open_bus = value;
return snes_ppu.ppu2_open_bus;
case WMDATA: /* Data to read from WRAM */ case WMDATA: /* Data to read from WRAM */
{ {
UINT32 addr = ((snes_ram[WMADDH] & 0x1) << 16) | (snes_ram[WMADDM] << 8) | snes_ram[WMADDL]; UINT32 addr = ((snes_ram[WMADDH] & 0x1) << 16) | (snes_ram[WMADDM] << 8) | snes_ram[WMADDL];