A7800Hawk commit #4
-Start Maria DMA and frame execution -Refactor CPU execution -Expose more tools (Hex Editor, RAM Search, etc) -Add Ready and Halt behaviours trigggered by Maria
This commit is contained in:
parent
93254b4b6e
commit
7bb76f9f03
|
@ -54,7 +54,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem();
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
|
|
|
@ -12,7 +12,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
//Maria related variables
|
||||
public int cycle;
|
||||
public int cpu_cycle;
|
||||
public int scanline;
|
||||
public bool cpu_is_haltable;
|
||||
public bool cpu_is_halted;
|
||||
public bool cpu_halt_pending;
|
||||
public bool cpu_resume_pending;
|
||||
|
||||
// there are 4 maria cycles in a CPU cycle (fast access, both NTSC and PAL)
|
||||
// if the 6532 or TIA are accessed (PC goes to one of those addresses) the next access will be slower by 1/2 a CPU cycle
|
||||
|
@ -47,58 +50,67 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
// read the controller state here for now
|
||||
GetControllerState(controller);
|
||||
|
||||
scanline = 0;
|
||||
maria.RunFrame();
|
||||
}
|
||||
|
||||
// actually execute the frame
|
||||
while (scanline < 263)
|
||||
public void RunCPUCycle()
|
||||
{
|
||||
cpu_cycle++;
|
||||
tia._hsyncCnt++;
|
||||
|
||||
if (cpu_cycle <= (2 + (slow_access ? 1 : 0)))
|
||||
{
|
||||
maria.Execute(cycle, scanline);
|
||||
cycle++;
|
||||
cpu_cycle++;
|
||||
tia._hsyncCnt++;
|
||||
cpu_is_haltable = true;
|
||||
} else
|
||||
{
|
||||
cpu_is_haltable = false;
|
||||
}
|
||||
|
||||
// the time a cpu cycle takes depends on the status of the address bus
|
||||
// any address in range of the TIA or m6532 takes an extra cycle to complete
|
||||
if (cpu_cycle==(4 + (slow_access ? 2 : 0)))
|
||||
{
|
||||
// the time a cpu cycle takes depends on the status of the address bus
|
||||
// any address in range of the TIA or m6532 takes an extra cycle to complete
|
||||
if (cpu_cycle == (4 + (slow_access ? 2 : 0)))
|
||||
{
|
||||
if (!cpu_is_halted)
|
||||
cpu.ExecuteOne();
|
||||
cpu_cycle = 0;
|
||||
}
|
||||
|
||||
// determine if the next access will be fast or slow
|
||||
if (cpu.PC < 0x0400)
|
||||
|
||||
cpu_cycle = 0;
|
||||
|
||||
if (cpu_halt_pending)
|
||||
{
|
||||
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
|
||||
{
|
||||
slow_access = false;
|
||||
}
|
||||
cpu_halt_pending = false;
|
||||
cpu_is_halted = true;
|
||||
}
|
||||
|
||||
|
||||
if (cycle == 454)
|
||||
if (cpu_resume_pending)
|
||||
{
|
||||
scanline++;
|
||||
cycle = 0;
|
||||
tia._hsyncCnt = 0;
|
||||
cpu_resume_pending = false;
|
||||
cpu_is_halted = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// determine if the next access will be fast or slow
|
||||
if (cpu.PC < 0x0400)
|
||||
{
|
||||
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
|
||||
{
|
||||
slow_access = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetControllerState(IController controller)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
|
|
@ -127,18 +127,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
if (_isPAL)
|
||||
{
|
||||
maria._frameHz = 50;
|
||||
maria._screen_width = 454;
|
||||
maria._screen_width = 320;
|
||||
maria._screen_height = 313;
|
||||
maria._palette = PALPalette;
|
||||
}
|
||||
else
|
||||
{
|
||||
maria._frameHz = 60;
|
||||
maria._screen_width = 454;
|
||||
maria._screen_width = 320;
|
||||
maria._screen_height = 263;
|
||||
maria._palette = NTSCPalette;
|
||||
}
|
||||
|
||||
maria.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(maria);
|
||||
ser.Register<ISoundProvider>(tia);
|
||||
ServiceProvider = ser;
|
||||
|
@ -146,6 +148,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
_tracer = new TraceBuffer { Header = cpu.TraceHeader };
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
|
||||
SetupMemoryDomains();
|
||||
HardReset();
|
||||
}
|
||||
|
||||
|
@ -174,7 +177,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
private void ExecFetch(ushort addr)
|
||||
{
|
||||
//MemoryCallbacks.CallExecutes(addr);
|
||||
MemoryCallbacks.CallExecutes(addr);
|
||||
}
|
||||
|
||||
private void Reset_Mapper(string m)
|
||||
|
|
|
@ -7,8 +7,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
// Emulates the Atari 7800 Maria graphics chip
|
||||
public class Maria : IVideoProvider
|
||||
{
|
||||
public A7800Hawk Core { get; set; }
|
||||
|
||||
public int _frameHz = 60;
|
||||
public int _screen_width = 454;
|
||||
public int _screen_width = 320;
|
||||
public int _screen_height = 263;
|
||||
|
||||
public int[] _vidbuffer;
|
||||
|
@ -19,9 +21,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 454;
|
||||
public int VirtualWidth => 320;
|
||||
public int VirtualHeight => _screen_height;
|
||||
public int BufferWidth => 454;
|
||||
public int BufferWidth => 320;
|
||||
public int BufferHeight => _screen_height;
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
public int VsyncNumerator => _frameHz;
|
||||
|
@ -30,11 +32,145 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
// the Maria chip can directly access memory
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
|
||||
public int cycle;
|
||||
public int scanline;
|
||||
public bool sl_DMA_complete;
|
||||
|
||||
public int DMA_phase = 0;
|
||||
public int DMA_phase_counter;
|
||||
|
||||
public static int DMA_START_UP = 0;
|
||||
public static int DMA_HEADER = 1;
|
||||
public static int DMA_GRAPHICS = 2;
|
||||
public static int DMA_CHAR_MAP = 3;
|
||||
public static int DMA_SHUTDOWN_OTHER = 4;
|
||||
public static int DMA_SHUTDOWN_LAST = 5;
|
||||
|
||||
public byte list_low_byte;
|
||||
public byte list_high_byte;
|
||||
|
||||
|
||||
|
||||
// each frame contains 263 scanlines
|
||||
// each scanline consists of 113.5 CPU cycles (fast access) which equates to 454 Maria cycles
|
||||
// In total there are 29850.5 CPU cycles (fast access) in a frame
|
||||
public void Execute(int cycle, int scanline)
|
||||
public void RunFrame()
|
||||
{
|
||||
scanline = 0;
|
||||
|
||||
Core.Maria_regs[8] = 0x80; // indicates VBlank state
|
||||
|
||||
// we start off in VBlank for 20 scanlines
|
||||
// at the end of vblank is a DMA to set up the display for the start of drawing
|
||||
// this is free time for the CPU to set up display lists
|
||||
while (scanline < 19)
|
||||
{
|
||||
Core.RunCPUCycle();
|
||||
cycle++;
|
||||
|
||||
if (cycle == 454)
|
||||
{
|
||||
scanline++;
|
||||
cycle = 0;
|
||||
Core.tia._hsyncCnt = 0;
|
||||
Core.cpu.RDY = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// "The end of vblank is made up of a DMA startup plus a long shut down"
|
||||
sl_DMA_complete = false;
|
||||
DMA_phase = DMA_START_UP;
|
||||
DMA_phase_counter = 0;
|
||||
|
||||
for (int i=0; i<454;i++)
|
||||
{
|
||||
if (i<28)
|
||||
{
|
||||
// DMA doesn't start until 7 CPU cycles into a scanline
|
||||
}
|
||||
else if (i==28)
|
||||
{
|
||||
Core.cpu_halt_pending = true;
|
||||
DMA_phase_counter = 0;
|
||||
}
|
||||
else if (!sl_DMA_complete)
|
||||
{
|
||||
RunDMA(i - 28, true);
|
||||
}
|
||||
|
||||
Core.RunCPUCycle();
|
||||
}
|
||||
|
||||
scanline++;
|
||||
cycle = 0;
|
||||
|
||||
Core.Maria_regs[8] = 0; // we have now left VBLank
|
||||
|
||||
// Now proceed with the remaining scanlines
|
||||
// the first one is a pre-render line, since we didn't actually put any data into the buffer yet
|
||||
while (scanline < 263)
|
||||
{
|
||||
|
||||
|
||||
Core.RunCPUCycle();
|
||||
|
||||
cycle++;
|
||||
|
||||
if (cycle == 454)
|
||||
{
|
||||
scanline++;
|
||||
cycle = 0;
|
||||
Core.tia._hsyncCnt = 0;
|
||||
Core.cpu.RDY = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDMA(int c, bool short_dma)
|
||||
{
|
||||
// During DMA the CPU is HALTED, This appears to happen on the falling edge of Phi2
|
||||
// Current implementation is that a HALT request must be acknowledged in phi1
|
||||
// if the CPU is now in halted state, start DMA
|
||||
if (Core.cpu_is_halted)
|
||||
{
|
||||
DMA_phase_counter++;
|
||||
|
||||
if (DMA_phase_counter==2 && DMA_phase==DMA_START_UP)
|
||||
{
|
||||
DMA_phase_counter = 0;
|
||||
if (short_dma)
|
||||
DMA_phase = DMA_SHUTDOWN_LAST;
|
||||
else
|
||||
{
|
||||
DMA_phase = DMA_HEADER;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (DMA_phase == DMA_HEADER)
|
||||
{
|
||||
// get all the data from the display list header
|
||||
if (DMA_phase_counter==1)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (DMA_phase == DMA_SHUTDOWN_LAST)
|
||||
{
|
||||
if (DMA_phase_counter==4)
|
||||
{
|
||||
Core.cpu_resume_pending = true;
|
||||
sl_DMA_complete = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.M6502;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
|
@ -10,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
{
|
||||
public byte ReadMemory(ushort addr)
|
||||
{
|
||||
MemoryCallbacks.CallReads(addr);
|
||||
|
||||
if (addr < 0x0400) {
|
||||
if ((addr & 0xFF) < 0x20)
|
||||
{
|
||||
|
@ -85,6 +86,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
public void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
MemoryCallbacks.CallWrites(addr);
|
||||
|
||||
if (addr < 0x0400)
|
||||
{
|
||||
if ((addr & 0xFF) < 0x20)
|
||||
|
@ -92,18 +95,25 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
// return TIA registers or control register if it is still unlocked
|
||||
if ((A7800_control_register & 0x1) == 0 && (addr < 0x20))
|
||||
{
|
||||
A7800_control_register = value; // TODO: what to return here?
|
||||
A7800_control_register = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
TIA_regs[addr] = value; // TODO: what to return here?
|
||||
TIA_regs[addr] = value;
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xFF) < 0x40)
|
||||
{
|
||||
if ((A7800_control_register & 0x2) > 0)
|
||||
{
|
||||
Maria_regs[(addr & 0x3F) - 0x20] = value;
|
||||
var temp = (addr & 0x3F) - 0x20;
|
||||
|
||||
// register 8 is read only and controlled by Maria
|
||||
if (temp != 8)
|
||||
Maria_regs[temp] = value;
|
||||
|
||||
if (temp==4) // WSYNC
|
||||
cpu.RDY = false;
|
||||
}
|
||||
}
|
||||
else if (addr < 0x100)
|
||||
|
|
Loading…
Reference in New Issue