//#define ARM_DEBUG namespace GarboDev { using System; using System.IO; using System.Threading; using System.Timers; using System.Windows.Forms; using System.Collections.Generic; using BizHawk.Emulation; using BizHawk; public class GbaManager : IEmulator, ISyncSoundProvider, IVideoProvider { public const int cpuFreq = 16 * 1024 * 1024; private int framesRendered; private Arm7Processor arm7 = null; private Memory memory = null; private VideoManager videoManager = null; private SoundManager soundManager = null; private bool skipBios = false; public delegate void CpuUpdateDelegate(Arm7Processor processor, Memory memory); private event CpuUpdateDelegate onCpuUpdate = null; public Arm7Processor Arm7 { get { return this.arm7; } } public VideoManager VideoManager { get { return this.videoManager; } } public SoundManager SoundManager { get { return this.soundManager; } } public Memory Memory { get { return this.memory; } } public Dictionary Breakpoints { get { return this.arm7.Breakpoints; } } public ushort KeyState { get { if (this.memory != null) { return this.memory.KeyState; } return 0x3FF; } set { this.arm7.KeyState = value; } } public int FramesRendered { get { return this.framesRendered; } set { this.framesRendered = value; } } public event CpuUpdateDelegate OnCpuUpdate { add { this.onCpuUpdate += value; this.onCpuUpdate(this.arm7, this.memory); } remove { this.onCpuUpdate -= value; } } public bool SkipBios { get { return this.skipBios; } set { this.skipBios = value; } } public GbaManager(CoreComm comm) { _corecomm = comm; this.memory = new Memory(); this.arm7 = new Arm7Processor(this.memory); this.videoManager = new VideoManager(this); this.videoManager.Memory = this.memory; this.soundManager = new SoundManager(this.memory, 44100); this.framesRendered = 0; Renderer renderer = new Renderer(); renderer.Initialize(null); VideoManager.Renderer = renderer; videoManager.Presenter = delegate(uint[] data) { Buffer.BlockCopy(data, 0, this.vbuf, 0, 240 * 160 * 4); }; } public void Load(byte[] rom, byte[] bios) { LoadBios(bios); LoadRom(rom); } public void Reset() { //this.Halt(); this.arm7.Reset(this.skipBios); this.memory.Reset(); this.videoManager.Reset(); } public void LoadState(BinaryReader state) { } public void SaveState(BinaryWriter state) { state.Write("GARB"); } public void LoadBios(byte[] biosRom) { this.memory.LoadBios(biosRom); if (this.onCpuUpdate != null) { this.onCpuUpdate(this.arm7, this.memory); } } public void LoadRom(byte[] cartRom) { //this.Halt(); /* byte[] logo = new byte[] { 0x24,0xff,0xae,0x51,0x69,0x9a,0xa2,0x21, 0x3d,0x84,0x82,0x0a,0x84,0xe4,0x09,0xad, 0x11,0x24,0x8b,0x98,0xc0,0x81,0x7f,0x21, 0xa3,0x52,0xbe,0x19,0x93,0x09,0xce,0x20, 0x10,0x46,0x4a,0x4a,0xf8,0x27,0x31,0xec, 0x58,0xc7,0xe8,0x33,0x82,0xe3,0xce,0xbf, 0x85,0xf4,0xdf,0x94,0xce,0x4b,0x09,0xc1, 0x94,0x56,0x8a,0xc0,0x13,0x72,0xa7,0xfc, 0x9f,0x84,0x4d,0x73,0xa3,0xca,0x9a,0x61, 0x58,0x97,0xa3,0x27,0xfc,0x03,0x98,0x76, 0x23,0x1d,0xc7,0x61,0x03,0x04,0xae,0x56, 0xbf,0x38,0x84,0x00,0x40,0xa7,0x0e,0xfd, 0xff,0x52,0xfe,0x03,0x6f,0x95,0x30,0xf1, 0x97,0xfb,0xc0,0x85,0x60,0xd6,0x80,0x25, 0xa9,0x63,0xbe,0x03,0x01,0x4e,0x38,0xe2, 0xf9,0xa2,0x34,0xff,0xbb,0x3e,0x03,0x44, 0x78,0x00,0x90,0xcb,0x88,0x11,0x3a,0x94, 0x65,0xc0,0x7c,0x63,0x87,0xf0,0x3c,0xaf, 0xd6,0x25,0xe4,0x8b,0x38,0x0a,0xac,0x72, 0x21,0xd4,0xf8,0x07 }; Array.Copy(logo, 0, cartRom, 4, logo.Length); cartRom[0xB2] = 0x96; cartRom[0xBD] = 0; for (int i = 0xA0; i <= 0xBC; i++) cartRom[0xBD] = (byte)(cartRom[0xBD] - cartRom[i]); cartRom[0xBD] = (byte)((cartRom[0xBD] - 0x19) & 0xFF); */ this.memory.LoadCartridge(cartRom); this.Reset(); if (this.onCpuUpdate != null) { this.onCpuUpdate(this.arm7, this.memory); } } public void Step() { //this.Halt(); this.arm7.Step(); if (this.onCpuUpdate != null) { this.onCpuUpdate(this.arm7, this.memory); } } public void StepScanline() { //this.Halt(); this.arm7.Execute(960); this.videoManager.RenderLine(); this.videoManager.EnterHBlank(this.arm7); this.arm7.Execute(272); this.videoManager.LeaveHBlank(this.arm7); if (this.onCpuUpdate != null) { this.onCpuUpdate(this.arm7, this.memory); } } void UpdateInputState() { ushort ret = 0; if (_controller["Up"]) ret |= 64; if (_controller["Down"]) ret |= 128; if (_controller["Left"]) ret |= 32; if (_controller["Right"]) ret |= 16; if (_controller["Select"]) ret |= 4; if (_controller["Start"]) ret |= 8; if (_controller["B"]) ret |= 2; if (_controller["A"]) ret |= 1; if (_controller["L"]) ret |= 512; if (_controller["R"]) ret |= 256; ret ^= 0x3ff; KeyState = ret; } private void StepFrame() { UpdateInputState(); if (_controller["Power"]) Reset(); int vramCycles = 0; bool inHblank = false; //HighPerformanceTimer profileTimer = new HighPerformanceTimer(); while (true) { const int cycleStep = 123; if (vramCycles <= 0) { if (inHblank) { vramCycles += 960; bool HitVBlank = this.videoManager.LeaveHBlank(this.arm7); inHblank = false; if (HitVBlank) break; } else { vramCycles += 272; this.videoManager.RenderLine(); this.videoManager.EnterHBlank(this.arm7); inHblank = true; } } this.arm7.Execute(cycleStep); #if ARM_DEBUG if (this.arm7.BreakpointHit) { this.waitingToHalt = true; Monitor.Wait(this); } #endif vramCycles -= cycleStep; this.arm7.FireIrq(); } } IVideoProvider IEmulator.VideoProvider { get { return this; } } ISoundProvider IEmulator.SoundProvider { get { return null; } } ISyncSoundProvider IEmulator.SyncSoundProvider { get { return this; } } bool IEmulator.StartAsyncSound() { return false; } void IEmulator.EndAsyncSound() { } ControllerDefinition IEmulator.ControllerDefinition { get { return BizHawk.Emulation.Consoles.Nintendo.GBA.GBA.GBAController; } } IController _controller; IController IEmulator.Controller { get { return _controller; } set { _controller = value; } } void IEmulator.FrameAdvance(bool render, bool rendersound) { StepFrame(); } int IEmulator.Frame { get { return 0; } } int IEmulator.LagCount { get { return 0; } set { } } bool IEmulator.IsLagFrame { get { return false; } } string IEmulator.SystemId { get { return "GBA"; } } bool IEmulator.DeterministicEmulation { get { return true; } } byte[] IEmulator.ReadSaveRam() { return new byte[0]; } void IEmulator.StoreSaveRam(byte[] data) { } void IEmulator.ClearSaveRam() { } bool IEmulator.SaveRamModified { get { return false; } set { } } void IEmulator.ResetFrameCounter() { } void IEmulator.SaveStateText(TextWriter writer) { } void IEmulator.LoadStateText(TextReader reader) { } void IEmulator.SaveStateBinary(BinaryWriter writer) { } void IEmulator.LoadStateBinary(BinaryReader reader) { } byte[] IEmulator.SaveStateBinary() { return new byte[16]; } CoreComm _corecomm; CoreComm IEmulator.CoreComm { get { return _corecomm; } } IList IEmulator.MemoryDomains { get { return new List(); } } MemoryDomain IEmulator.MainMemory { get { return null; } } void IDisposable.Dispose() { } int[] vbuf = new int[240 * 160]; int[] IVideoProvider.GetVideoBuffer() { return vbuf; } int IVideoProvider.VirtualWidth { get { return 240; } } int IVideoProvider.BufferWidth { get { return 240; } } int IVideoProvider.BufferHeight { get { return 160; } } int IVideoProvider.BackgroundColor { get { return unchecked((int)0xff000000); } } void ISyncSoundProvider.GetSamples(out short[] samples, out int nsamp) { nsamp = soundManager.SamplesMixed / 2; samples = new short[nsamp * 2]; soundManager.GetSamples(samples, nsamp * 2); } void ISyncSoundProvider.DiscardSamples() { // should implement } } }