Atari7800Hawk: More Core Work
- Adds Fire button (centipede and Asteroid now playable) - Improve Maria, add holey DMA, fix numerous bugs - Fix slow cycle memory mapping.
This commit is contained in:
parent
8a5e613fff
commit
d9cc1558aa
|
@ -21,6 +21,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
// input state of controllers and console
|
||||
public byte p1_state;
|
||||
public byte p2_state;
|
||||
public byte p1_fire;
|
||||
public byte p2_fire;
|
||||
public byte con_state;
|
||||
|
||||
// there are 4 maria cycles in a CPU cycle (fast access, both NTSC and PAL)
|
||||
|
@ -50,9 +52,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
_islag = true;
|
||||
|
||||
p1_state = GetControllerState(controller, 1);
|
||||
p2_state = GetControllerState(controller, 2);
|
||||
con_state = GetConsoleState(controller);
|
||||
GetControllerState(controller);
|
||||
GetConsoleState(controller);
|
||||
|
||||
maria.RunFrame();
|
||||
|
||||
|
@ -114,41 +115,43 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
}
|
||||
|
||||
// determine if the next access will be fast or slow
|
||||
if (cpu.PC < 0x0400)
|
||||
if ((cpu.PC & 0xFCE0) == 0)
|
||||
{
|
||||
if ((cpu.PC & 0xFF) < 0x20)
|
||||
{
|
||||
if ((A7800_control_register & 0x1) == 0 && (cpu.PC < 0x20))
|
||||
{
|
||||
slow_access = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
slow_access = true;
|
||||
}
|
||||
}
|
||||
else if (cpu.PC < 0x300)
|
||||
{
|
||||
slow_access = true;
|
||||
}
|
||||
else
|
||||
// return TIA registers or control register if it is still unlocked
|
||||
if ((A7800_control_register & 0x1) == 0)
|
||||
{
|
||||
slow_access = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
slow_access = true;
|
||||
}
|
||||
}
|
||||
else if ((cpu.PC & 0xFF80) == 0x280)
|
||||
{
|
||||
slow_access = true;
|
||||
}
|
||||
else if ((cpu.PC & 0xFE80) == 0x480)
|
||||
{
|
||||
slow_access = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
slow_access = false;
|
||||
}
|
||||
}
|
||||
|
||||
public byte GetControllerState(IController controller, int index)
|
||||
public void GetControllerState(IController controller)
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
|
||||
if (index == 1)
|
||||
return _controllerDeck.ReadPort1(controller);
|
||||
else
|
||||
return _controllerDeck.ReadPort2(controller);
|
||||
p1_state = _controllerDeck.ReadPort1(controller);
|
||||
p2_state = _controllerDeck.ReadPort2(controller);
|
||||
p1_fire = _controllerDeck.ReadFire1(controller);
|
||||
p2_fire = _controllerDeck.ReadFire2(controller);
|
||||
}
|
||||
|
||||
public byte GetConsoleState(IController controller)
|
||||
public void GetConsoleState(IController controller)
|
||||
{
|
||||
byte result = 0;
|
||||
|
||||
|
@ -173,7 +176,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
result |= 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
con_state = result;
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
|
|
@ -143,6 +143,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
maria.Core = this;
|
||||
m6532.Core = this;
|
||||
tia.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(maria);
|
||||
ser.Register<ISoundProvider>(tia);
|
||||
|
|
|
@ -60,6 +60,16 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
return Port2.Read(c);
|
||||
}
|
||||
|
||||
public byte ReadFire1(IController c)
|
||||
{
|
||||
return Port1.ReadFire(c);
|
||||
}
|
||||
|
||||
public byte ReadFire2(IController c)
|
||||
{
|
||||
return Port2.ReadFire(c);
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
|
|
|
@ -1,120 +1,125 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a controller plugged into a controller port on the intellivision
|
||||
/// </summary>
|
||||
public interface IPort
|
||||
{
|
||||
byte Read(IController c);
|
||||
|
||||
byte ReadFire(IController c);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
|
||||
int PortNum { get; }
|
||||
}
|
||||
|
||||
[DisplayName("Unplugged Controller")]
|
||||
public class UnpluggedController : IPort
|
||||
{
|
||||
public UnpluggedController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = new List<string>()
|
||||
};
|
||||
}
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a controller plugged into a controller port on the intellivision
|
||||
/// </summary>
|
||||
public interface IPort
|
||||
{
|
||||
byte Read(IController c);
|
||||
|
||||
byte ReadFire(IController c);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
|
||||
int PortNum { get; }
|
||||
}
|
||||
|
||||
[DisplayName("Unplugged Controller")]
|
||||
public class UnpluggedController : IPort
|
||||
{
|
||||
public UnpluggedController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = new List<string>()
|
||||
};
|
||||
}
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public byte ReadFire(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
}
|
||||
|
||||
[DisplayName("Joystick Controller")]
|
||||
public class StandardController : IPort
|
||||
{
|
||||
public StandardController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xF;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (c.IsPressed(Definition.BoolButtons[i]))
|
||||
{
|
||||
result -= (byte)(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
}
|
||||
|
||||
[DisplayName("Joystick Controller")]
|
||||
public class StandardController : IPort
|
||||
{
|
||||
public StandardController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public byte Read(IController c)
|
||||
{
|
||||
byte result = 0xF;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (c.IsPressed(Definition.BoolButtons[i]))
|
||||
{
|
||||
result -= (byte)(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (PortNum==1)
|
||||
{
|
||||
result = (byte)(result << 4);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte ReadFire(IController c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// Nothing todo, I think
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"U", "D", "L", "R", "Fire"
|
||||
};
|
||||
|
||||
private static byte[] HandControllerButtons =
|
||||
{
|
||||
0x0, // UP
|
||||
0x0, // Down
|
||||
0x0, // Left
|
||||
0x0, // Right
|
||||
};
|
||||
}
|
||||
}
|
||||
byte result = 0x80;
|
||||
if (c.IsPressed(Definition.BoolButtons[4]))
|
||||
{
|
||||
result = 0x00; // zero means fire is pressed
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// Nothing todo, I think
|
||||
}
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"U", "D", "L", "R", "Fire"
|
||||
};
|
||||
|
||||
private static byte[] HandControllerButtons =
|
||||
{
|
||||
0x0, // UP
|
||||
0x0, // Down
|
||||
0x0, // Left
|
||||
0x0, // Right
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
// additional entries used only in 5-byte header mode
|
||||
public bool write_mode;
|
||||
public bool ind_mode;
|
||||
public bool exp_mode;
|
||||
public byte[] obj; // up to 32 bytes can compose one object
|
||||
}
|
||||
|
||||
|
@ -292,7 +291,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
GFX_Objects[header_counter].ind_mode = temp.Bit(5);
|
||||
header_pointer++;
|
||||
temp = (byte)(ReadMemory((ushort)(current_DLL_addr + header_pointer)));
|
||||
GFX_Objects[header_counter].addr |= (ushort)((temp/* + current_DLL_offset*/)<< 8);
|
||||
GFX_Objects[header_counter].addr |= (ushort)(temp << 8);
|
||||
header_pointer++;
|
||||
temp = ReadMemory((ushort)(current_DLL_addr + header_pointer));
|
||||
int temp_w = (temp & 0x1F); // this is the 2's complement of width (for reasons that escape me)
|
||||
|
@ -314,7 +313,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
GFX_Objects[header_counter].h_pos = ReadMemory((ushort)(current_DLL_addr + header_pointer));
|
||||
header_pointer++;
|
||||
|
||||
GFX_Objects[header_counter].exp_mode = true;
|
||||
DMA_phase_next = DMA_GRAPHICS;
|
||||
|
||||
header_read_time = 10;
|
||||
|
@ -330,16 +328,17 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
GFX_Objects[header_counter].palette = (byte)((temp & 0xE0) >> 5);
|
||||
header_pointer++;
|
||||
temp = (byte)(ReadMemory((ushort)(current_DLL_addr + header_pointer)));
|
||||
GFX_Objects[header_counter].addr |= (ushort)((temp + current_DLL_offset)<< 8);
|
||||
GFX_Objects[header_counter].addr |= (ushort)(temp << 8);
|
||||
header_pointer++;
|
||||
GFX_Objects[header_counter].h_pos = ReadMemory((ushort)(current_DLL_addr + header_pointer));
|
||||
header_pointer++;
|
||||
|
||||
GFX_Objects[header_counter].exp_mode = false;
|
||||
DMA_phase_next = DMA_GRAPHICS;
|
||||
|
||||
GFX_Objects[header_counter].write_mode = global_write_mode;
|
||||
|
||||
GFX_Objects[header_counter].ind_mode = false;
|
||||
|
||||
header_read_time = 8;
|
||||
}
|
||||
|
||||
|
@ -356,55 +355,61 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
{
|
||||
if (DMA_phase_counter == 1)
|
||||
{
|
||||
// get all the graphics data
|
||||
// the time this takes depend on the source and number of bytes
|
||||
if (GFX_Objects[header_counter].exp_mode)
|
||||
ushort addr_t = 0;
|
||||
|
||||
// in 5 byte mode, we first have to check if we are in direct or indirect mode
|
||||
if (GFX_Objects[header_counter].ind_mode)
|
||||
{
|
||||
// in 5 byte mode, we first have to check if we are in direct or indirect mode
|
||||
if (GFX_Objects[header_counter].ind_mode)
|
||||
int ch_size = 0;
|
||||
|
||||
if (Core.Maria_regs[0x1C].Bit(4))
|
||||
{
|
||||
//Console.Write(" Indirect graphics");
|
||||
|
||||
int ch_size = 0;
|
||||
|
||||
if (Core.Maria_regs[0x1C].Bit(4))
|
||||
{
|
||||
graphics_read_time = 6 * GFX_Objects[header_counter].width + 3;
|
||||
ch_size = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
graphics_read_time = 9 * GFX_Objects[header_counter].width + 3;
|
||||
ch_size = 2;
|
||||
}
|
||||
|
||||
// the address here is specified by CHAR_BASE maria registers
|
||||
//ushort addr = (ushort)(GFX_Objects[header_counter].addr & 0xFF);
|
||||
ushort addr = (ushort)(ReadMemory(GFX_Objects[header_counter].addr));
|
||||
addr |= (ushort)((Core.Maria_regs[0x14] + current_DLL_offset) << 8);
|
||||
|
||||
for (int i = 0; i < GFX_Objects[header_counter].width; i ++)
|
||||
{
|
||||
// if game is programmed correctly, should always be less then 32
|
||||
// but in order to not go out of bounds, lets clamp it here anyway
|
||||
if (i * ch_size < 32)
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i * ch_size] = ReadMemory((ushort)(addr + i));
|
||||
}
|
||||
if ((i * ch_size + 1 < 32) && (ch_size == 2))
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i * ch_size + 1] = ReadMemory((ushort)(addr + i));
|
||||
}
|
||||
}
|
||||
graphics_read_time = 9 * GFX_Objects[header_counter].width + 3;
|
||||
ch_size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
graphics_read_time = 3 * GFX_Objects[header_counter].width;
|
||||
graphics_read_time = 6 * GFX_Objects[header_counter].width + 3;
|
||||
ch_size = 1;
|
||||
}
|
||||
|
||||
// do direct reads same as in 4 byte mode
|
||||
for (int i = 0; i < GFX_Objects[header_counter].width; i++)
|
||||
// the address here is specified by CHAR_BASE maria registers
|
||||
//ushort addr = (ushort)(GFX_Objects[header_counter].addr & 0xFF);
|
||||
for (int i = 0; i < GFX_Objects[header_counter].width; i++)
|
||||
{
|
||||
addr_t = ReadMemory((ushort)(GFX_Objects[header_counter].addr + i));
|
||||
addr_t |= (ushort)((Core.Maria_regs[0x14] + current_DLL_offset) << 8);
|
||||
|
||||
if ((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11)))
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i] = ReadMemory((ushort)((GFX_Objects[header_counter].addr + (current_DLL_offset << 8) + i)));
|
||||
if (i * ch_size < 32)
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i * ch_size] = 0;
|
||||
}
|
||||
if ((i * ch_size + 1 < 32) && (ch_size == 2))
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i * ch_size + 1] = 0;
|
||||
}
|
||||
if (ch_size == 1)
|
||||
{
|
||||
graphics_read_time -= 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
graphics_read_time -= 9;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i * ch_size < 32)
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i * ch_size] = ReadMemory(addr_t);
|
||||
}
|
||||
if ((i * ch_size + 1 < 32) && (ch_size == 2))
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i * ch_size + 1] = ReadMemory(addr_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -414,12 +419,21 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
for (int i = 0; i < GFX_Objects[header_counter].width; i++)
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i] = ReadMemory((ushort)(GFX_Objects[header_counter].addr + i));
|
||||
addr_t = (ushort)(GFX_Objects[header_counter].addr + (current_DLL_offset << 8) + i);
|
||||
if ((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11)))
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i] = 0;
|
||||
graphics_read_time -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
GFX_Objects[header_counter].obj[i] = ReadMemory(addr_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DMA_phase_counter == graphics_read_time)
|
||||
if (DMA_phase_counter == graphics_read_time || graphics_read_time == 0)
|
||||
{
|
||||
// We have read the graphics data, for this header, now return to the header list
|
||||
// This loop will continue until a header indicates its time to stop
|
||||
|
|
|
@ -34,7 +34,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
}
|
||||
else
|
||||
{
|
||||
return TIA_regs[addr & 0x1F]; // TODO: what to return here?
|
||||
return tia.ReadMemory((ushort)(addr & 0x1F), false);
|
||||
//return TIA_regs[addr & 0x1F]; // TODO: what to return here?
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xFCE0) == 0x20)
|
||||
|
|
Loading…
Reference in New Issue