using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BizHawk.Emulation.Common { public class CoreComm { public ICoreFileProvider CoreFileProvider; /// /// if this is set, then the cpu should dump trace info to CpuTraceStream /// public TraceBuffer Tracer = new TraceBuffer(); /// /// for emu.on_snoop() /// public InputCallbackSystem InputCallback = new InputCallbackSystem(); public MemoryCallbackSystem MemoryCallbackSystem = new MemoryCallbackSystem(); public double VsyncRate { get { return VsyncNum / (double)VsyncDen; } } public int VsyncNum = 60; public int VsyncDen = 1; //a core should set these if you wish to provide rom status information yourself. otherwise it will be calculated by the frontend in a way you may not like, using RomGame-related concepts. public string RomStatusAnnotation; public string RomStatusDetails; public int ScreenLogicalOffsetX, ScreenLogicalOffsetY; public bool CpuTraceAvailable = false; public string TraceHeader = "Instructions"; // size hint to a/v out resizer. this probably belongs in VideoProvider? but it's somewhat different than VirtualWidth... public int NominalWidth = 640; public int NominalHeight = 480; public bool DriveLED = false; public bool UsesDriveLed = false; /// /// show a message. reasonably annoying (dialog box), shouldn't be used most of the time /// public Action ShowMessage { get; private set; } /// /// show a message. less annoying (OSD message). Should be used for ignorable helpful messages /// public Action Notify { get; private set; } public CoreComm(Action ShowMessage, Action NotifyMessage) { this.ShowMessage = ShowMessage; this.Notify = NotifyMessage; } public Func RequestGLContext; public Action ActivateGLContext; public Action DeactivateGLContext; //this shouldnt be necessary.. frontend should be changing context before it does anything.. but for now.. } public class TraceBuffer { public string TakeContents() { string s = buffer.ToString(); buffer.Clear(); return s; } public string Contents { get { return buffer.ToString(); } } public void Put(string content) { if (logging) { buffer.AppendLine(content); } } public TraceBuffer() { buffer = new StringBuilder(); } public bool Enabled { get { return logging; } set { logging = value; } } private readonly StringBuilder buffer; private bool logging; } public class InputCallbackSystem { private readonly List _list = new List(); public void Add(Action action) { _list.Add(action); } public void Call() { foreach (var action in _list) { action(); } } public void Remove(Action action) { _list.Remove(action); } public void RemoveAll(IEnumerable actions) { foreach (var action in actions) { _list.Remove(action); } } public void Clear() { _list.Clear(); } // why was this missing? public bool Has { get { return _list.Any(); } } } public class MemoryCallbackSystem { private readonly List _reads = new List(); private readonly List _readAddrs = new List(); private readonly List _writes = new List(); private readonly List _writeAddrs = new List(); private readonly List _executes = new List(); private readonly List _execAddrs = new List(); public void AddRead(Action function, uint? addr) { _reads.Add(function); _readAddrs.Add(addr); } public void AddWrite(Action function, uint? addr) { _writes.Add(function); _writeAddrs.Add(addr); } public void AddExecute(Action function, uint addr) { _executes.Add(function); _execAddrs.Add(addr); } public void CallRead(uint addr) { for (int i = 0; i < _reads.Count; i++) { if (!_readAddrs[i].HasValue || _readAddrs[i].Value == addr) { _reads[i](); } } } public void CallWrite(uint addr) { for (int i = 0; i < _writes.Count; i++) { if (!_writeAddrs[i].HasValue || _writeAddrs[i] == addr) { _writes[i](); } } } public void CallExecute(uint addr) { for (int i = 0; i < _executes.Count; i++) { if (_execAddrs[i] == addr) { _executes[i](); } } } public bool HasReads { get { return _reads.Any(); } } public bool HasWrites { get { return _writes.Any(); } } public bool HasExecutes { get { return _executes.Any(); } } public void Remove(Action action) { for (int i = 0; i < _reads.Count; i++) { if (_reads[i] == action) { _reads.Remove(_reads[i]); _readAddrs.Remove(_readAddrs[i]); } } for (int i = 0; i < _writes.Count; i++) { if (_writes[i] == action) { _writes.Remove(_writes[i]); _writeAddrs.Remove(_writeAddrs[i]); } } for (int i = 0; i < _executes.Count; i++) { if (_executes[i] == action) { _executes.Remove(_executes[i]); _execAddrs.Remove(_execAddrs[i]); } } } public void RemoveAll(IEnumerable actions) { foreach (var action in actions) { Remove(action); } } public void Clear() { _reads.Clear(); _readAddrs.Clear(); _writes.Clear(); _writes.Clear(); _executes.Clear(); _execAddrs.Clear(); } } }