154 lines
4.3 KiB
C#
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
|
|
}
|
|
} |