O2Hawk: better fix for blockout

This commit is contained in:
alyosha-tas 2020-04-08 12:12:32 -04:00
parent 786fd9d5a1
commit cb2d365284
1 changed files with 36 additions and 81 deletions

View File

@ -4,15 +4,9 @@ using BizHawk.Common.NumberExtensions;
using BizHawk.Emulation.Common;
/*
Notes: The line position returned by A4 is offset from display by 6 lines.
The game blockout requires VBLank interrupt to be able to execute relative to a particular line value,
but this line value would fall outside vblank by a wide margin if the Y return matched screen position relative to end of VBL
This offset also makes the borders in Cosmic Conflict match to console, so presumably it is correct.
But this effect isn't enough by itself to get correct display. Also from the data sheet for the 8245, the 'program coordinates' of the
grid are 5 scanlines behind ahead of the actual display, so changes take effect 5 scanline later then for other objects like the BG.
Notes: Blockout expects STAT to return VBl 1 even outside VBl range. So this is an interrupt request bit, not a status bit (similar to sound)
Also, according to the 8245 data sheet, the hbl status flag starts at roughly halfway through the scanline. This is also
crucial for Blockout to display correctly.
crucial for Blockout to display correctly. However this bit is reset once HBL ends
Blockout also turns on HBL interrupts and expects them either not to fire (or only one to fire per write to A0)
*/
@ -31,14 +25,13 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
public const int HBL_CNT = 45;
public const int GRID_OFST = 24;
public const int OBJ_OFST = 0;
public const int SHT_SZ = 8;
public byte[] Sprites = new byte[16];
public byte[] Sprite_Shapes = new byte[32];
public byte[] Foreground = new byte[48];
public byte[] Quad_Chars = new byte[64];
public byte[] Grid_H = new byte[18 * SHT_SZ];
public byte[] Grid_V = new byte[10 * SHT_SZ];
public byte[] Grid_H = new byte[18];
public byte[] Grid_V = new byte[10];
public byte[] VDC_col_ret = new byte[8];
public byte VDC_ctrl, VDC_status, VDC_collision, VDC_color;
@ -58,10 +51,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
public bool HBL_req;
public int LY_ret;
public byte[] VDC_ctrl_latch = new byte[SHT_SZ];
public byte[] VDC_color_latch = new byte[SHT_SZ];
public int[] grid_brightness_latch = new int[SHT_SZ];
// local variables not stated
int current_pixel_offset;
int double_size;
@ -97,6 +86,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
{
ret = VDC_status;
// reading status clears IRQ request
VDC_status &= 0xF7;
Core.cpu.IRQPending = false;
}
else if (addr == 0xA2)
@ -118,7 +108,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
else if(addr == 0xA4)
{
if (latch_x_y) { ret = A4_latch; }
else { ret = (byte)LY_ret; }
else { ret = (byte)((LY_ret >= 0) ? LY_ret : 0); }
}
else if (addr == 0xA5)
{
@ -132,15 +122,15 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
else if ((addr >= 0xC0) && (addr <= 0xC8))
{
ret = Grid_H[(addr - 0xC0) * SHT_SZ];
ret = Grid_H[addr - 0xC0];
}
else if ((addr >= 0xD0) && (addr <= 0xD8))
{
ret = Grid_H[(addr - 0xD0 + 9) * SHT_SZ];
ret = Grid_H[addr - 0xD0 + 9];
}
else if ((addr >= 0xE0) && (addr <= 0xE9))
{
ret = Grid_V[(addr - 0xE0) * SHT_SZ];
ret = Grid_V[addr - 0xE0];
}
return ret;
@ -191,7 +181,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
{
VDC_status &= 0xFD;
latch_x_y = true;
A4_latch = (byte)LY_ret;
A4_latch = (byte)((LY_ret >= 0) ? LY_ret : 0);
A5_latch = (byte)(cycle);
}
@ -201,7 +191,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
VDC_ctrl = value;
VDC_ctrl_latch[SHT_SZ - 1] = value;
if (VDC_ctrl.Bit(2)) { Console.WriteLine("sound INT"); }
if (VDC_ctrl.Bit(0)) { Console.WriteLine("HBL INT"); }
@ -221,8 +210,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
//Console.WriteLine("VDC_color: " + value + " " + LY + " " + Core.cpu.TotalExecutedCycles);
grid_brightness = (!lum_en | VDC_color.Bit(6)) ? 8 : 0;
bg_brightness = !lum_en ? 8 : 0;
VDC_color_latch[SHT_SZ - 1] = value;
grid_brightness_latch[SHT_SZ - 1] = grid_brightness;
}
else if (addr == 0xA4)
{
@ -238,15 +225,15 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
else if ((addr >= 0xC0) && (addr <= 0xC8))
{
if (!VDC_ctrl.Bit(3)) { Grid_H[(addr - 0xC0) * SHT_SZ + SHT_SZ - 1] = value; } else { Console.WriteLine("blocked"); }
if (!VDC_ctrl.Bit(3)) { Grid_H[addr - 0xC0] = value; } else { Console.WriteLine("blocked"); }
}
else if ((addr >= 0xD0) && (addr <= 0xD8))
{
if (!VDC_ctrl.Bit(3)) { Grid_H[(addr - 0xD0 + 9) * SHT_SZ + SHT_SZ - 1] = value; } else { Console.WriteLine("blocked"); }
if (!VDC_ctrl.Bit(3)) { Grid_H[addr - 0xD0 + 9] = value; } else { Console.WriteLine("blocked"); }
}
else if ((addr >= 0xE0) && (addr <= 0xE9))
{
if (!VDC_ctrl.Bit(3)) { Grid_V[(addr - 0xE0) * SHT_SZ + SHT_SZ - 1] = value; } else { Console.WriteLine("blocked"); }
if (!VDC_ctrl.Bit(3)) { Grid_V[addr - 0xE0] = value; } else { Console.WriteLine("blocked"); }
}
//Console.WriteLine(addr + " " + value + " " + LY + " " + Core.cpu.TotalExecutedCycles);
}
@ -268,8 +255,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
if (grid_fill > 0)
{
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Pixel_Stat |= grid_fill_col;
grid_fill--;
}
@ -280,12 +267,12 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
int j = (int)Math.Floor((LY - GRID_OFST) / 24.0);
if ((k < 10) && (j < 8))
{
if (Grid_V[k * SHT_SZ].Bit(j))
if (Grid_V[k].Bit(j))
{
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Pixel_Stat |= 0x10;
if (VDC_ctrl_latch[0].Bit(7)) { grid_fill = 15; }
if (VDC_ctrl.Bit(7)) { grid_fill = 15; }
else { grid_fill = 1; }
grid_fill_col = 0x10;
}
@ -301,10 +288,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
{
if (j == 8)
{
if (Grid_H[(k + 9) * SHT_SZ].Bit(0))
if (Grid_H[k + 9].Bit(0))
{
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Pixel_Stat |= 0x20;
if (((cycle - 8) % 16) == 15) { grid_fill = 2; grid_fill_col = 0x20; }
@ -312,10 +299,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
else
{
if (Grid_H[k * SHT_SZ].Bit(j))
if (Grid_H[k].Bit(j))
{
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset+ 1] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Core._vidbuffer[LY * 372 + current_pixel_offset+ 1] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Pixel_Stat |= 0x20;
if (((cycle - 8) % 16) == 15) { grid_fill = 2; grid_fill_col = 0x20; }
}
@ -324,7 +311,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
// grid
if (VDC_ctrl_latch[0].Bit(6) && ((LY - GRID_OFST) >= 0) && (((LY - GRID_OFST) % GRID_OFST) < 3) && VDC_ctrl.Bit(3))
if (VDC_ctrl.Bit(6) && ((LY - GRID_OFST) >= 0) && (((LY - GRID_OFST) % GRID_OFST) < 3) && VDC_ctrl.Bit(3))
{
if (((cycle % 16) == 8) || ((cycle % 16) == 9))
@ -333,8 +320,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
int j = (int)Math.Floor((LY - GRID_OFST) / 24.0);
if ((k < 10) && (j < 9))
{
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color_latch[0] & 0x7) + grid_brightness_latch[0]];
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
Pixel_Stat |= 0x20;
}
}
@ -740,7 +727,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
else
{
if (cycle == 182 && (LY < LINE_VBL) && (LY >= 0))
if (cycle == 182 && (LY < LINE_VBL))
{
HBL = true;
// Send T1 pulses
@ -755,33 +742,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
}
}
if (cycle == 12)
{
// the grid uses values from 5 lines in the past, so cycle them here
for (int j = 0; j < (SHT_SZ - 1); j++)
{
VDC_ctrl_latch[j] = VDC_ctrl_latch[j + 1];
VDC_color_latch[j] = VDC_color_latch[j + 1];
grid_brightness_latch[j] = grid_brightness_latch[j + 1];
}
for (int i = 0; i < 18; i++)
{
for (int j = 0; j < (SHT_SZ - 1); j++)
{
Grid_H[i * SHT_SZ + j] = Grid_H[i * SHT_SZ + j + 1];
}
}
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < (SHT_SZ - 1); j++)
{
Grid_V[i * SHT_SZ + j] = Grid_V[i * SHT_SZ + j + 1];
}
}
}
if (cycle == 113 && (LY < LINE_VBL))
{
VDC_status |= 0x01;
@ -811,23 +771,18 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
LY_ret = 0;
}
if (LY == (LINE_MAX - 6))
{
LY = -6;
LY_ret = 0;
}
if (LY == 0)
if (LY == LINE_MAX)
{
LY = 0;
VBL = false;
Core.in_vblank = false;
Core.cpu.T1 = false;
if (Core.is_pal) { Core.cpu.IRQPending = false; }
VDC_status &= 0xF7;
for (int i = 0; i < 8; i++) { VDC_col_ret[i] = 0; }
LY_ret = 0;
}
if (LY < LINE_VBL && (LY >= 0))
if (LY < LINE_VBL)
{
HBL = false;
Core.cpu.T1 = false;
@ -843,14 +798,14 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
Sprite_Shapes = new byte[32];
Foreground = new byte[48];
Quad_Chars = new byte[64];
Grid_H = new byte[18 * SHT_SZ];
Grid_V = new byte[10 * SHT_SZ];
Grid_H = new byte[18];
Grid_V = new byte[10];
VDC_ctrl = VDC_status = VDC_collision = VDC_color = grid_fill_col = 0;
Pixel_Stat = A4_latch = A5_latch = 0;
bg_brightness = grid_brightness = grid_fill = LY_ret = cycle = 0;
VBL = HBL = lum_en = false;
LY = -6;
LY = 0;
AudioReset();
}