From cb2d365284a42e009d9e7c9b626555c62e0dd354 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 8 Apr 2020 12:12:32 -0400 Subject: [PATCH] O2Hawk: better fix for blockout --- .../Consoles/Magnavox/Odyssey2/PPU.cs | 117 ++++++------------ 1 file changed, 36 insertions(+), 81 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs index e5470096ae..e73207a9ea 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs @@ -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(); }