BizHawk/EMU7800/Core/AddressSpace.cs

154 lines
4.3 KiB
C#

/*
* AddressSpace.cs
*
* The class representing the memory map or address space of a machine.
*
* Copyright © 2003, 2011 Mike Murphy
*
*/
using System;
namespace EMU7800.Core
{
public sealed class AddressSpace
{
public MachineBase M { get; private set; }
readonly int AddrSpaceShift;
readonly int AddrSpaceSize;
readonly int AddrSpaceMask;
readonly int PageShift;
readonly int PageSize;
readonly IDevice[] MemoryMap;
IDevice Snooper;
public byte DataBusState { get; private set; }
public override string ToString()
{
return "AddressSpace";
}
public byte this[ushort addr]
{
get
{
if (Snooper != null)
{
// here DataBusState is just facilitating a dummy read to the snooper device
// the read operation may have important side effects within the device
DataBusState = Snooper[addr];
}
var pageno = (addr & AddrSpaceMask) >> PageShift;
var dev = MemoryMap[pageno];
DataBusState = dev[addr];
return DataBusState;
}
set
{
DataBusState = value;
if (Snooper != null)
{
Snooper[addr] = DataBusState;
}
var pageno = (addr & AddrSpaceMask) >> PageShift;
var dev = MemoryMap[pageno];
dev[addr] = DataBusState;
}
}
public void Map(ushort basea, ushort size, IDevice device)
{
if (device == null)
throw new ArgumentNullException("device");
for (int addr = basea; addr < basea + size; addr += PageSize)
{
var pageno = (addr & AddrSpaceMask) >> PageShift;
MemoryMap[pageno] = device;
}
LogDebug("{0}: Mapped {1} to ${2:x4}:${3:x4}", this, device, basea, basea + size - 1);
}
public void Map(ushort basea, ushort size, Cart cart)
{
if (cart == null)
throw new ArgumentNullException("cart");
cart.Attach(M);
var device = (IDevice)cart;
if (cart.RequestSnooping)
{
Snooper = device;
}
Map(basea, size, device);
}
#region Constructors
private AddressSpace()
{
}
public AddressSpace(MachineBase m, int addrSpaceShift, int pageShift)
{
if (m == null)
throw new ArgumentNullException("m");
M = m;
AddrSpaceShift = addrSpaceShift;
AddrSpaceSize = 1 << AddrSpaceShift;
AddrSpaceMask = AddrSpaceSize - 1;
PageShift = pageShift;
PageSize = 1 << PageShift;
MemoryMap = new IDevice[1 << addrSpaceShift >> PageShift];
IDevice nullDev = new NullDevice(M);
for (var pageno=0; pageno < MemoryMap.Length; pageno++)
{
MemoryMap[pageno] = nullDev;
}
}
#endregion
#region Serialization Members
public AddressSpace(DeserializationContext input, MachineBase m, int addrSpaceShift, int pageShift) : this(m, addrSpaceShift, pageShift)
{
if (input == null)
throw new ArgumentNullException("input");
input.CheckVersion(1);
DataBusState = input.ReadByte();
}
public void GetObjectData(SerializationContext output)
{
if (output == null)
throw new ArgumentNullException("output");
output.WriteVersion(1);
output.Write(DataBusState);
}
#endregion
#region Helpers
[System.Diagnostics.Conditional("DEBUG")]
void LogDebug(string format, params object[] args)
{
if (M == null || M.Logger == null)
return;
M.Logger.WriteLine(format, args);
}
#endregion
}
}