diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs index 056eb62a0a..0a83661f8a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IDebuggable.cs @@ -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) { diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs index 09ad452125..d66887478e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs @@ -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) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IMemoryDomains.cs index 3d7d86a4f4..5090e1f139 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IMemoryDomains.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using BizHawk.Emulation.Common; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs index 32c4872461..a34a2151fd 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs @@ -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(maria); ser.Register(tia); ServiceProvider = ser; @@ -146,6 +148,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk _tracer = new TraceBuffer { Header = cpu.TraceHeader }; ser.Register(_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) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Maria.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Maria.cs index 95f136866b..25d717cb47 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Maria.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Maria.cs @@ -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 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; + } + + + } + } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs index a7541855c6..d6ec152ba9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/MemoryMap.cs @@ -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)