using System; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; namespace BizHawk.Emulation.Common { public class MemoryDomain { public enum Endian { Big, Little, Unknown } public readonly string Name; /// /// Special note: if this is 0, the memorydomain is 0x100000000 (full 32bits) in size. /// This was judged to be less of a mess than using a bunch of longs everywhere. /// public readonly int Size; public readonly Endian EndianType; public readonly Func PeekByte; public readonly Action PokeByte; public MemoryDomain(string name, int size, Endian endian, Func peekByte, Action pokeByte) { Name = name; Size = size; EndianType = endian; PeekByte = peekByte; PokeByte = pokeByte; } /// /// create a memorydomain that references an unmanaged memory block /// /// /// /// /// must remain valid as long as the MemoryDomain exists! /// if false, writes will be ignored /// public unsafe static MemoryDomain FromIntPtr(string name, int size, Endian endian, IntPtr data, bool writable = true) { if (data == IntPtr.Zero) throw new ArgumentNullException("data"); if (size <= 0) throw new ArgumentOutOfRangeException("size"); byte* p = (byte*)data; return new MemoryDomain ( name, size, endian, delegate(int addr) { if (addr < 0 || addr >= size) throw new ArgumentOutOfRangeException(); return p[addr]; }, delegate(int addr, byte val) { if (writable) { if (addr < 0 || addr >= size) throw new ArgumentOutOfRangeException(); p[addr] = val; } } ); } /// /// create a memorydomain that references an unmanaged memory block with 16 bit swaps /// /// /// /// /// must remain valid as long as the MemoryDomain exists! /// if false, writes will be ignored /// public unsafe static MemoryDomain FromIntPtrSwap16(string name, int size, Endian endian, IntPtr data, bool writable = true) { if (data == IntPtr.Zero) throw new ArgumentNullException("data"); if (size <= 0) throw new ArgumentOutOfRangeException("size"); byte* p = (byte*)data; return new MemoryDomain ( name, size, endian, delegate(int addr) { if (addr < 0 || addr >= size) throw new ArgumentOutOfRangeException(); return p[addr ^ 1]; }, delegate(int addr, byte val) { if (writable) { if (addr < 0 || addr >= size) throw new ArgumentOutOfRangeException(); p[addr ^ 1] = val; } } ); } public override string ToString() { return Name; } public ushort PeekWord(int addr, bool bigEndian) { Endian endian = bigEndian ? Endian.Big : Endian.Little; switch (endian) { default: case Endian.Big: return (ushort)((PeekByte(addr) << 8) | (PeekByte(addr + 1))); case Endian.Little: return (ushort)((PeekByte(addr)) | (PeekByte(addr + 1) << 8)); } } public uint PeekDWord(int addr, bool bigEndian) { Endian endian = bigEndian ? Endian.Big : Endian.Little; switch (endian) { default: case Endian.Big: return (uint)((PeekByte(addr) << 24) | (PeekByte(addr + 1) << 16) | (PeekByte(addr + 2) << 8) | (PeekByte(addr + 3) << 0)); case Endian.Little: return (uint)((PeekByte(addr) << 0) | (PeekByte(addr + 1) << 8) | (PeekByte(addr + 2) << 16) | (PeekByte(addr + 3) << 24)); } } public void PokeWord(int addr, ushort val, bool bigEndian) { Endian endian = bigEndian ? Endian.Big : Endian.Little; switch (endian) { default: case Endian.Big: PokeByte(addr + 0, (byte)(val >> 8)); PokeByte(addr + 1, (byte)(val)); break; case Endian.Little: PokeByte(addr + 0, (byte)(val)); PokeByte(addr + 1, (byte)(val >> 8)); break; } } public void PokeDWord(int addr, uint val, bool bigEndian) { Endian endian = bigEndian ? Endian.Big : Endian.Little; switch (endian) { default: case Endian.Big: PokeByte(addr + 0, (byte)(val >> 24)); PokeByte(addr + 1, (byte)(val >> 16)); PokeByte(addr + 2, (byte)(val >> 8)); PokeByte(addr + 3, (byte)(val)); break; case Endian.Little: PokeByte(addr + 0, (byte)(val)); PokeByte(addr + 1, (byte)(val >> 8)); PokeByte(addr + 2, (byte)(val >> 16)); PokeByte(addr + 3, (byte)(val >> 24)); break; } } } public class MemoryDomainList : ReadOnlyCollection { private readonly int _mainMemoryIndex; public MemoryDomainList(IList domains) : base(domains) { } public MemoryDomainList(IList domains, int mainMemoryIndex) : this(domains) { _mainMemoryIndex = mainMemoryIndex; } public MemoryDomain this[string name] { get { return this.FirstOrDefault(x => x.Name == name); } } public MemoryDomain MainMemory { get { return this[_mainMemoryIndex]; } } public bool HasSystemBus { get { return this.Any(x => x.Name == "System Bus" || x.Name == "BUS"); // Have to account for "BUS" because some developers don't like consistency! } } public MemoryDomain SystemBus { get { return this.FirstOrDefault(x => x.Name == "System Bus" || x.Name == "BUS"); } } } }