O2Hawk: fix Blockout and other issues
This commit is contained in:
parent
dbfa5ce5a2
commit
8827550a17
BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2
|
@ -3,6 +3,17 @@ using BizHawk.Common;
|
|||
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
|
||||
|
||||
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.
|
||||
|
||||
Blockout also turns on HBL interrupts and expects them either not to fire (or only one to fire per write to A0)
|
||||
*/
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
||||
{
|
||||
|
@ -16,6 +27,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
public int LINE_MAX;
|
||||
|
||||
public const int HBL_CNT = 45;
|
||||
public const int GRID_OFST = 18;
|
||||
public const int OBJ_OFST = -6;
|
||||
|
||||
public byte[] Sprites = new byte[16];
|
||||
public byte[] Sprite_Shapes = new byte[32];
|
||||
|
@ -38,6 +51,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
public bool HBL;
|
||||
public bool lum_en;
|
||||
|
||||
public bool latch_x_y;
|
||||
public bool HBL_req;
|
||||
public int LY_ret;
|
||||
|
||||
// local variables not stated
|
||||
int current_pixel_offset;
|
||||
int double_size;
|
||||
|
@ -68,11 +85,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
else if (addr == 0xA0)
|
||||
{
|
||||
ret = VDC_ctrl;
|
||||
//Core.cpu.IRQPending = false;
|
||||
}
|
||||
else if (addr == 0xA1)
|
||||
{
|
||||
ret = VDC_status;
|
||||
// reading status clears IRQ request
|
||||
Core.cpu.IRQPending = false;
|
||||
}
|
||||
else if (addr == 0xA2)
|
||||
|
@ -93,13 +110,14 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
else if(addr == 0xA4)
|
||||
{
|
||||
if (VDC_ctrl.Bit(1)) { ret = A4_latch; }
|
||||
else { ret = (byte)LY; }
|
||||
if (latch_x_y) { ret = A4_latch; }
|
||||
else { ret = (byte)LY_ret; }
|
||||
}
|
||||
else if (addr == 0xA5)
|
||||
{
|
||||
if (VDC_ctrl.Bit(1)) { ret = A5_latch; }
|
||||
else { ret = (byte)(cycle - HBL_CNT); }
|
||||
// reading the x reg clears the latch
|
||||
if (latch_x_y) { ret = A5_latch; latch_x_y = false; VDC_status |= 0x2; }
|
||||
else { ret = (byte)(cycle); }
|
||||
}
|
||||
else if (addr <= 0xAA)
|
||||
{
|
||||
|
@ -149,17 +167,24 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
else if (addr == 0xA0)
|
||||
{
|
||||
VDC_ctrl = value;
|
||||
//Console.WriteLine("VDC_ctrl: " + value + " " + Core.cpu.TotalExecutedCycles);
|
||||
if (VDC_ctrl.Bit(1))
|
||||
{
|
||||
if (value.Bit(1) && !VDC_ctrl.Bit(1))
|
||||
{
|
||||
VDC_status &= 0xFD;
|
||||
A4_latch = (byte)LY;
|
||||
A5_latch = (byte)(cycle - HBL_CNT);
|
||||
latch_x_y = true;
|
||||
A4_latch = (byte)LY_ret;
|
||||
A5_latch = (byte)(cycle);
|
||||
}
|
||||
else { VDC_status |= 0x2; }
|
||||
|
||||
if (value.Bit(0) && !VDC_ctrl.Bit(0))
|
||||
{
|
||||
HBL_req = true;
|
||||
}
|
||||
|
||||
VDC_ctrl = value;
|
||||
|
||||
if (VDC_ctrl.Bit(2)) { Console.WriteLine("sound INT"); }
|
||||
//if (VDC_ctrl.Bit(0)) { Console.WriteLine("HBL INT"); }
|
||||
}
|
||||
else if (addr == 0xA1)
|
||||
{
|
||||
|
@ -209,20 +234,12 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
Pixel_Stat = 0;
|
||||
// drawing cycles
|
||||
if (cycle >= HBL_CNT)
|
||||
if (cycle < 182)
|
||||
{
|
||||
// draw a pixel
|
||||
if (LY < LINE_VBL)
|
||||
if ((LY < LINE_VBL) && (LY >= 0))
|
||||
{
|
||||
if (cycle == HBL_CNT)
|
||||
{
|
||||
HBL = false;
|
||||
VDC_status |= 0x01;
|
||||
// Send T1 pulses
|
||||
Core.cpu.T1 = false;
|
||||
}
|
||||
|
||||
current_pixel_offset = (cycle - HBL_CNT) * 2;
|
||||
current_pixel_offset = cycle * 2;
|
||||
|
||||
// background
|
||||
Core._vidbuffer[LY * 372 + current_pixel_offset] = (int)Color_Palette_BG[((VDC_color >> 3) & 0x7) + bg_brightness];
|
||||
|
@ -236,10 +253,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
grid_fill--;
|
||||
}
|
||||
|
||||
if ((((cycle - HBL_CNT) % 16) == 8) && ((LY - 24) >= 0))
|
||||
if (((cycle % 16) == 8) && ((LY - GRID_OFST) >= 0))
|
||||
{
|
||||
int k = (int)Math.Floor((cycle - HBL_CNT) / 16.0);
|
||||
int j = (int)Math.Floor((LY - 24) / 24.0);
|
||||
int k = (int)Math.Floor(cycle / 16.0);
|
||||
int j = (int)Math.Floor((LY - GRID_OFST) / 24.0);
|
||||
if ((k < 10) && (j < 8))
|
||||
{
|
||||
if (Grid_V[k].Bit(j))
|
||||
|
@ -254,10 +271,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
}
|
||||
|
||||
if (((LY % 24) < 3) && ((cycle - HBL_CNT - 8) >= 0) && ((LY - 24) >= 0))
|
||||
if ((((LY - GRID_OFST) % 24) < 3) && ((cycle - 8) >= 0) && ((LY - GRID_OFST) >= 0))
|
||||
{
|
||||
int k = (int)Math.Floor((cycle - HBL_CNT - 8) / 16.0);
|
||||
int j = (int)Math.Floor((LY - 24) / 24.0);
|
||||
int k = (int)Math.Floor((cycle - 8) / 16.0);
|
||||
int j = (int)Math.Floor((LY - GRID_OFST) / 24.0);
|
||||
//Console.WriteLine(k + " " + j);
|
||||
if ((k < 9) && (j < 9))
|
||||
{
|
||||
|
@ -269,7 +286,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
Core._vidbuffer[LY * 372 + current_pixel_offset + 1] = (int)Color_Palette_BG[(VDC_color & 0x7) + grid_brightness];
|
||||
Pixel_Stat |= 0x20;
|
||||
|
||||
if (((cycle - HBL_CNT - 8) % 16) == 15) { grid_fill = 2; grid_fill_col = 0x20; }
|
||||
if (((cycle - 8) % 16) == 15) { grid_fill = 2; grid_fill_col = 0x20; }
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -279,20 +296,20 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
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 - HBL_CNT - 8) % 16) == 15) { grid_fill = 2; grid_fill_col = 0x20; }
|
||||
if (((cycle - 8) % 16) == 15) { grid_fill = 2; grid_fill_col = 0x20; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// grid
|
||||
if (VDC_ctrl.Bit(6) && ((LY - 24) >= 0) && ((LY % 24) < 3))
|
||||
if (VDC_ctrl.Bit(6) && ((LY - GRID_OFST) >= 0) && (((LY - GRID_OFST) % GRID_OFST) < 3))
|
||||
{
|
||||
|
||||
if ((((cycle - HBL_CNT) % 16) == 8) || (((cycle - HBL_CNT) % 16) == 9))
|
||||
if (((cycle % 16) == 8) || ((cycle % 16) == 9))
|
||||
{
|
||||
int k = (int)Math.Floor((cycle - HBL_CNT) / 16.0);
|
||||
int j = (int)Math.Floor((LY - 24) / 24.0);
|
||||
int k = (int)Math.Floor(cycle / 16.0);
|
||||
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 & 0x7) + grid_brightness];
|
||||
|
@ -305,13 +322,13 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
// single characters
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
if ((LY >= Foreground[i * 4]) && (LY < (Foreground[i * 4] + 8 * 2)))
|
||||
if (((LY - OBJ_OFST) >= Foreground[i * 4]) && ((LY - OBJ_OFST) < (Foreground[i * 4] + 8 * 2)))
|
||||
{
|
||||
if (((cycle - HBL_CNT) >= Foreground[i * 4 + 1]) && ((cycle - HBL_CNT) < (Foreground[i * 4 + 1] + 8)))
|
||||
if ((cycle >= Foreground[i * 4 + 1]) && (cycle < (Foreground[i * 4 + 1] + 8)))
|
||||
{
|
||||
// sprite is in drawing region, pick a pixel
|
||||
int offset_y = (LY - Foreground[i * 4]) >> 1;
|
||||
int offset_x = 7 - ((cycle - HBL_CNT) - Foreground[i * 4 + 1]);
|
||||
int offset_y = ((LY - OBJ_OFST) - Foreground[i * 4]) >> 1;
|
||||
int offset_x = 7 - (cycle - Foreground[i * 4 + 1]);
|
||||
int char_sel = Foreground[i * 4 + 2];
|
||||
|
||||
int char_pick = (char_sel - (((~(Foreground[i * 4] >> 1)) + 1) & 0xFF));
|
||||
|
@ -353,13 +370,13 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
// quads
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
if ((LY >= Quad_Chars[i * 16]) && (LY < (Quad_Chars[i * 16] + 8 * 2)))
|
||||
if (((LY - OBJ_OFST) >= Quad_Chars[i * 16]) && ((LY - OBJ_OFST) < (Quad_Chars[i * 16] + 8 * 2)))
|
||||
{
|
||||
if (((cycle - HBL_CNT) >= Quad_Chars[i * 16 + 1]) && ((cycle - HBL_CNT) < (Quad_Chars[i * 16 + 1] + 64)))
|
||||
if ((cycle >= Quad_Chars[i * 16 + 1]) && (cycle < (Quad_Chars[i * 16 + 1] + 64)))
|
||||
{
|
||||
// sprite is in drawing region, pick a pixel
|
||||
int offset_y = (LY - Quad_Chars[i * 16]) >> 1;
|
||||
int offset_x = 63 - ((cycle - HBL_CNT) - Quad_Chars[i * 16 + 1]);
|
||||
int offset_y = ((LY - OBJ_OFST) - Quad_Chars[i * 16]) >> 1;
|
||||
int offset_x = 63 - (cycle - Quad_Chars[i * 16 + 1]);
|
||||
int quad_num = 3;
|
||||
while (offset_x > 15)
|
||||
{
|
||||
|
@ -416,18 +433,18 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
double_size = Sprites[i * 4 + 2].Bit(2) ? 4 : 2;
|
||||
right_shift = Sprites[i * 4 + 2].Bit(0) ? 1 : 0;
|
||||
|
||||
if ((LY >= Sprites[i * 4]) && (LY < (Sprites[i * 4] + 8 * double_size)))
|
||||
if (((LY - OBJ_OFST) >= Sprites[i * 4]) && ((LY - OBJ_OFST) < (Sprites[i * 4] + 8 * double_size)))
|
||||
{
|
||||
right_shift_even = (Sprites[i * 4 + 2].Bit(1) && (((Sprites[i * 4] + 8 * double_size - LY) % 2) == 0)) ? 1 : 0;
|
||||
right_shift_even = (Sprites[i * 4 + 2].Bit(1) && (((Sprites[i * 4] + 8 * double_size - (LY - OBJ_OFST)) % 2) == 0)) ? 1 : 0;
|
||||
x_base = Sprites[i * 4 + 1];
|
||||
|
||||
if ((right_shift + right_shift_even) == 0)
|
||||
{
|
||||
if (((cycle - HBL_CNT) >= x_base) && ((cycle - HBL_CNT) < (x_base + 8 * (double_size / 2))))
|
||||
if ((cycle >= x_base) && (cycle < (x_base + 8 * (double_size / 2))))
|
||||
{
|
||||
// character is in drawing region, pick a pixel
|
||||
int offset_y = (LY - Sprites[i * 4]) >> (double_size / 2);
|
||||
int offset_x = ((cycle - HBL_CNT) - x_base) >> (double_size / 2 - 1);
|
||||
int offset_y = ((LY - OBJ_OFST) - Sprites[i * 4]) >> (double_size / 2);
|
||||
int offset_x = (cycle - x_base) >> (double_size / 2 - 1);
|
||||
|
||||
int pixel_pick = (Sprite_Shapes[i * 8 + offset_y] >> offset_x) & 1;
|
||||
|
||||
|
@ -448,15 +465,15 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
// special shifted cases
|
||||
// since we are drawing two pixels at a time, we need to be careful that the next background / grid / char pixel
|
||||
// doesn't overwrite the shifted pixel on the next pass
|
||||
if (((cycle - HBL_CNT) >= x_base) && ((cycle - HBL_CNT) < (x_base + 1 + 8 * (double_size / 2))))
|
||||
if ((cycle >= x_base) && (cycle < (x_base + 1 + 8 * (double_size / 2))))
|
||||
{
|
||||
// character is in drawing region, pick a pixel
|
||||
int offset_y = (LY - Sprites[i * 4]) >> (double_size / 2);
|
||||
int offset_x = ((cycle - HBL_CNT) - x_base) >> (double_size / 2 - 1);
|
||||
int offset_y = ((LY - OBJ_OFST) - Sprites[i * 4]) >> (double_size / 2);
|
||||
int offset_x = (cycle - x_base) >> (double_size / 2 - 1);
|
||||
|
||||
if (double_size == 2)
|
||||
{
|
||||
if (((cycle - HBL_CNT) - x_base) == 8)
|
||||
if ((cycle - x_base) == 8)
|
||||
{
|
||||
offset_x = 7;
|
||||
|
||||
|
@ -477,7 +494,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
Pixel_Stat |= (byte)(1 << i);
|
||||
}
|
||||
}
|
||||
else if (((cycle - HBL_CNT) - x_base) == 0)
|
||||
else if ((cycle - x_base) == 0)
|
||||
{
|
||||
if ((right_shift + right_shift_even) < 2)
|
||||
{
|
||||
|
@ -498,7 +515,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
else
|
||||
{
|
||||
offset_x = cycle - HBL_CNT - x_base;
|
||||
offset_x = cycle - x_base;
|
||||
|
||||
if ((right_shift + right_shift_even) < 2)
|
||||
{
|
||||
|
@ -547,9 +564,9 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((((cycle - HBL_CNT) - x_base) >> 1) == 8)
|
||||
if (((cycle - x_base) >> 1) == 8)
|
||||
{
|
||||
if ((((cycle - HBL_CNT) - x_base) % 2) == 0)
|
||||
if (((cycle - x_base) % 2) == 0)
|
||||
{
|
||||
offset_x = 7;
|
||||
|
||||
|
@ -570,9 +587,9 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((((cycle - HBL_CNT) - x_base) >> 1) == 0)
|
||||
else if (((cycle - x_base) >> 1) == 0)
|
||||
{
|
||||
if ((((cycle - HBL_CNT) - x_base) % 2) == 1)
|
||||
if (((cycle - x_base) % 2) == 1)
|
||||
{
|
||||
offset_x = 0;
|
||||
|
||||
|
@ -611,9 +628,9 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((((cycle - HBL_CNT) - x_base) % 2) == 1)
|
||||
if (((cycle - x_base) % 2) == 1)
|
||||
{
|
||||
offset_x = (cycle - HBL_CNT - x_base) >> 1;
|
||||
offset_x = (cycle - x_base) >> 1;
|
||||
|
||||
int pixel_pick = (Sprite_Shapes[i * 8 + offset_y] >> offset_x) & 1;
|
||||
|
||||
|
@ -630,7 +647,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
else
|
||||
{
|
||||
offset_x = (cycle - HBL_CNT - x_base) >> 1;
|
||||
offset_x = (cycle - x_base) >> 1;
|
||||
|
||||
if ((right_shift + right_shift_even) < 2)
|
||||
{
|
||||
|
@ -699,6 +716,28 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cycle == 182 && (LY < LINE_VBL))
|
||||
{
|
||||
HBL = true;
|
||||
// Send T1 pulses
|
||||
Core.cpu.T1 = true;
|
||||
}
|
||||
|
||||
if (cycle == 212 && (LY < LINE_VBL))
|
||||
{
|
||||
VDC_status &= 0xFE;
|
||||
if (VDC_ctrl.Bit(0) && Core.is_pal) { Core.cpu.IRQPending = false; }
|
||||
LY_ret = LY_ret + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cycle == 113 && (LY < LINE_VBL))
|
||||
{
|
||||
VDC_status |= 0x01;
|
||||
if (VDC_ctrl.Bit(0) && HBL_req) { Core.cpu.IRQPending = true; HBL_req = false; }
|
||||
}
|
||||
|
||||
cycle++;
|
||||
|
||||
|
@ -717,20 +756,34 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
Core.cpu.IRQPending = true;
|
||||
Core.cpu.T1 = true;
|
||||
}
|
||||
if (LY == LINE_MAX)
|
||||
|
||||
if (LY >= 255)
|
||||
{
|
||||
LY_ret = 0xFF;
|
||||
}
|
||||
|
||||
if (LY == (LINE_MAX - 6))
|
||||
{
|
||||
LY = -6;
|
||||
LY_ret = 0;
|
||||
}
|
||||
|
||||
if (LY == 0)
|
||||
{
|
||||
LY = 0;
|
||||
VBL = false;
|
||||
Core.in_vblank = false;
|
||||
Core.cpu.T1 = false;
|
||||
//Core.cpu.IRQPending = false;
|
||||
VDC_status &= 0xF7;
|
||||
for (int i = 0; i < 8; i++) { VDC_col_ret[i] = 0; }
|
||||
}
|
||||
|
||||
if (LY < LINE_VBL)
|
||||
{
|
||||
HBL = true;
|
||||
VDC_status &= 0xFE;
|
||||
HBL = false;
|
||||
//VDC_status |= 0x01;
|
||||
// send T1 pulses
|
||||
Core.cpu.T1 = true;
|
||||
Core.cpu.T1 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -746,11 +799,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
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 = cycle = 0;
|
||||
bg_brightness = grid_brightness = grid_fill = LY_ret = cycle = 0;
|
||||
VBL = HBL = lum_en = false;
|
||||
LY = -6;
|
||||
|
||||
|
||||
AudioReset();
|
||||
AudioReset();
|
||||
}
|
||||
|
||||
public void set_region(bool pal_flag)
|
||||
|
@ -896,6 +949,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
ser.Sync(nameof(VBL), ref VBL);
|
||||
ser.Sync(nameof(HBL), ref HBL);
|
||||
|
||||
ser.Sync(nameof(latch_x_y), ref latch_x_y);
|
||||
ser.Sync(nameof(HBL_req), ref HBL_req);
|
||||
ser.Sync(nameof(LY_ret), ref LY_ret);
|
||||
|
||||
AudioSyncState(ser);
|
||||
}
|
||||
|
||||
|
@ -1018,6 +1075,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
ser.Sync(nameof(tick_cnt), ref tick_cnt);
|
||||
ser.Sync(nameof(shift_cnt), ref shift_cnt);
|
||||
ser.Sync(nameof(output_bit), ref output_bit);
|
||||
|
||||
ser.Sync(nameof(latch_x_y), ref latch_x_y);
|
||||
}
|
||||
|
||||
#region audio
|
||||
|
|
Loading…
Reference in New Issue