Replace the SpringbokRiscV32_WindowMMU with the Renode internal one

This introduces all the changes needed in the repl, resc and the SpringbokRiscV32_ControlBlock.
To use it in tests this CL must be applied: https://spacebeaker-review.googlesource.com/c/shodan/kata/projects/processmanager/+/19681
BusPointRegistration from the https://spacebeaker-review.googlesource.com/c/shodan/sim-config/+/19480 is not needed as the MMU can operate on the globally accessible memory.

Change-Id: I3309609a018b94f6b73da98088a2b1904707265d
diff --git a/platforms/springbok.repl b/platforms/springbok.repl
index ce6d50a..97e6c8f 100644
--- a/platforms/springbok.repl
+++ b/platforms/springbok.repl
@@ -34,28 +34,13 @@
 ram_vec_csr: Memory.MappedMemory @ sysbus 0x38000000
     size: 0x00001000
 
-// TODO(jonathantate): The addresses for these WindowMMUs are not final while we
-// figure out how to have different memory maps for vector core / SMC with
-// Renode. From the vector core's point of view, the WindowMMUs should be at
-// 0x30000000/0x34000000 for IMMU/DMMU respectively, but from the SMC's point of
-// view that should be where the instruction/data TCMs are.
-vec_immu : CPU.SpringbokRiscV32_WindowMMU @ sysbus 0x33000000
-    tcm: ram_vec_imem
-    windowSize: 0x10000
-    tcmSize: 0x10000
-    pageSize: 0x400
-    numWindows: 2
-
-vec_dmmu : CPU.SpringbokRiscV32_WindowMMU @ sysbus 0x35000000
-    tcm: ram_vec_dmem
-    windowSize: 0x400000
-    tcmSize: 0x400000
-    pageSize: 0x400
-    numWindows: 4
-
 vec_controlblock : CPU.SpringbokRiscV32_ControlBlock @ sysbus 0x47000000
     core: cpu2
-    imem: ram_vec_imem
-    dmem: ram_vec_dmem
-    immu: vec_immu
-    dmmu: vec_dmmu
+    iMmuNumWindows: 2
+    iMmuVirtualWindowSize: 0x10000
+    iMmuMemorySize: 0x20000
+    iMmuRangeStart: 0x32000000
+    dMmuNumWindows: 4
+    dMmuVirtualWindowSize: 0x400000
+    dMmuMemorySize: 0x1000000
+    dMmuRangeStart: 0x34000000
diff --git a/shodan.resc b/shodan.resc
index 70f7f41..78ea9c7 100644
--- a/shodan.resc
+++ b/shodan.resc
@@ -6,9 +6,9 @@
 using sysbus
 mach create $name
 EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.RiscV32"
-include @sim/config/shodan_infrastructure/SpringbokRiscV32_WindowMMU.cs
-EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.SpringbokRiscV32_WindowMMU"
 include @sim/config/shodan_infrastructure/SpringbokRiscV32.cs
+EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.SpringbokRiscV32"
+EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.SpringbokRiscV32_ControlBlock"
 include @sim/config/shodan_infrastructure/SmcRiscV32.cs
 include @sim/config/shodan_infrastructure/OpenTitan2_UART.cs
 include @sim/config/shodan_infrastructure/Mailbox.cs
diff --git a/shodan_infrastructure/SpringbokRiscV32.cs b/shodan_infrastructure/SpringbokRiscV32.cs
index cd69f8a..db08c92 100644
--- a/shodan_infrastructure/SpringbokRiscV32.cs
+++ b/shodan_infrastructure/SpringbokRiscV32.cs
@@ -10,12 +10,12 @@
 
 using Antmicro.Renode.Core;
 using Antmicro.Renode.Core.Structure.Registers;
+using Antmicro.Renode.Exceptions;
 using Antmicro.Renode.Logging;
+using Antmicro.Renode.Peripherals.Miscellaneous;
 using Antmicro.Renode.Peripherals.Bus;
-using Antmicro.Renode.Peripherals.Memory;
-using Antmicro.Renode.Peripherals.Timers;
 using Antmicro.Renode.Utilities;
-using Antmicro.Renode.Utilities.Binding;
+using Antmicro.Renode.Debugging;
 
 using Endianess = ELFSharp.ELF.Endianess;
 
@@ -198,17 +198,31 @@
 
         public SpringbokRiscV32_ControlBlock(Machine machine,
                                              SpringbokRiscV32 core,
-                                             MappedMemory imem,
-                                             MappedMemory dmem,
-                                             SpringbokRiscV32_WindowMMU immu=null,
-                                             SpringbokRiscV32_WindowMMU dmmu=null)
+                                             uint iMmuNumWindows,
+                                             ulong iMmuMemorySize,
+                                             ulong iMmuVirtualWindowSize,
+                                             ulong iMmuRangeStart,
+                                             uint dMmuNumWindows,
+                                             ulong dMmuRangeStart,
+                                             ulong dMmuMemorySize,
+                                             ulong dMmuVirtualWindowSize)
         {
             Machine = machine;
             Core = core;
-            IMem = imem;
-            DMem = dmem;
-            IMmu = immu;
-            DMmu = dmmu;
+
+            this.iMmuNumWindows = iMmuNumWindows;
+            this.iMmuRangeStart = iMmuRangeStart;
+            this.iMmuMemorySize = iMmuMemorySize;
+            this.dMmuNumWindows = dMmuNumWindows;
+            this.dMmuRangeStart = dMmuRangeStart;
+            this.dMmuMemorySize = dMmuMemorySize;
+            this.iMmuVirtualWindowSize = iMmuVirtualWindowSize;
+            this.dMmuVirtualWindowSize = dMmuVirtualWindowSize;
+
+            Core.EnableExternalWindowMmu(true);
+
+            IMmu = InitMmu(iMmuRangeStart, iMmuMemorySize, iMmuNumWindows, iMmuVirtualWindowSize);
+            DMmu = InitMmu(dMmuRangeStart, dMmuMemorySize, dMmuNumWindows, dMmuVirtualWindowSize);
 
             HostReqIRQ = new GPIO();
             FinishIRQ = new GPIO();
@@ -220,15 +234,7 @@
             RegistersCollection = new DoubleWordRegisterCollection(this);
             DefineRegisters();
 
-            if (IMmu != null)
-            {
-              IMmu.RegisterFaultCallback(() => { ExecFault(FaultType.InstructionFetch); });
-            }
-
-            if (DMmu != null)
-            {
-              DMmu.RegisterFaultCallback(() => { ExecFault(FaultType.DataAccess); });
-            }
+            Core.AddHookOnMmuFault(HandleFault);
 
             Reset();
         }
@@ -239,6 +245,20 @@
             RegistersCollection.Reset();
         }
 
+        private ExternalMmuBase InitMmu(ulong rangeStart, ulong memorySize, uint windowsCount, ulong windowSize)
+        {
+            var mmu = new ExternalMmuBase(this.Core, windowsCount);
+
+            for(uint windowIndex = 0; windowIndex<windowsCount; windowIndex++)
+            {
+                var windowStart = rangeStart + windowIndex * windowSize;
+                var windowEnd = windowStart + windowSize;
+                mmu.SetWindowStart(windowIndex, windowStart);
+                mmu.SetWindowEnd(windowIndex, windowEnd);
+            }
+            return mmu;
+        }
+
         private void DefineRegisters()
         {
             Registers.IntrState.Define32(this)
@@ -291,7 +311,7 @@
                         {
                             this.Log(LogLevel.Noisy, "Resetting core.");
                             Core.Reset();
-                            ulong startAddress = (val & ~(ulong)Mode.Mask) + Machine.SystemBus.GetRegistrationPoints(IMem, Core).First().Range.StartAddress;
+                            ulong startAddress = (val & ~(ulong)Mode.Mask) + iMmuRangeStart;
                             this.Log(LogLevel.Noisy, "Setting PC to 0x{0:X}.", startAddress);
                             Core.PC = startAddress;
                         }
@@ -344,7 +364,7 @@
                                 writeAddress < ((InitEndAddress.Value + InstructionPageSize - 1) & ~(InstructionPageSize - 1));
                                 writeAddress += InstructionPageSize)
                                     {
-                                        IMem.WriteBytes(writeAddress, InstructionErasePattern, 0, InstructionPageSize);
+                                        Machine.SystemBus.WriteBytes(InstructionErasePattern, iMmuRangeStart + (ulong)writeAddress, (uint)InstructionPageSize, true);
                                     }
                                 }
                                 else
@@ -353,7 +373,7 @@
                                 writeAddress < ((InitEndAddress.Value + DataPageSize - 1) & ~(DataPageSize - 1));
                                 writeAddress += DataPageSize)
                                     {
-                                        DMem.WriteBytes(writeAddress, DataErasePattern, 0, DataPageSize);
+                                        Machine.SystemBus.WriteBytes(DataErasePattern, dMmuRangeStart + (ulong)writeAddress, (uint)DataPageSize, true);
                                     }
                                 }
                                 InitStatusPending.Value = false;
@@ -379,14 +399,19 @@
                 {
                     offset -= 1024;
                     uint window = (uint)(offset >> 4);
+                    if(window >= iMmuNumWindows)
+                    {
+                        this.Log(LogLevel.Warning, "Invalid window number {}", window);
+                        return 0;
+                    }
                     switch (offset & 15)
                     {
                     case 0:
-                        return IMmu.GetWindowOffset(window);
+                        return checked((uint)IMmu.GetWindowStart(window));
                     case 4:
-                        return IMmu.GetWindowLength(window);
+                        return checked((uint)(IMmu.GetWindowEnd(window) - IMmu.GetWindowStart(window))); // windowLength
                     case 8:
-                        return IMmu.GetWindowPermission(window);
+                        return checked((uint)IMmu.GetWindowPrivileges(window));
                     default:
                         this.Log(LogLevel.Warning, "No Springbok IMmu register at address 0x{0:X}.", offset);
                         return 0;
@@ -399,14 +424,19 @@
                 {
                     offset -= 2048;
                     uint window = (uint)(offset >> 4);
+                    if(window >= dMmuNumWindows)
+                    {
+                        this.Log(LogLevel.Warning, "Invalid window number {}", window);
+                        return 0;
+                    }
                     switch (offset & 15)
                     {
                     case 0:
-                        return DMmu.GetWindowOffset(window);
+                        return checked((uint)DMmu.GetWindowStart(window));
                     case 4:
-                        return DMmu.GetWindowLength(window);
+                        return checked((uint)(DMmu.GetWindowEnd(window) - DMmu.GetWindowStart(window))); // windowLength
                     case 8:
-                        return DMmu.GetWindowPermission(window);
+                        return checked((uint)DMmu.GetWindowPrivileges(window));
                     default:
                         this.Log(LogLevel.Warning, "No Springbok DMmu register at address 0x{0:X}.", offset);
                         return 0;
@@ -431,16 +461,28 @@
                 {
                     offset -= 1024;
                     uint window = (uint)(offset >> 4);
+                    if(window >= iMmuNumWindows)
+                    {
+                        this.Log(LogLevel.Warning, "Invalid window number {}", window);
+                        return;
+                    }
                     switch (offset & 15)
                     {
                     case 0:
-                        IMmu.SetWindowOffset(window, value);
+                        var virtualWindowOffset = this.iMmuRangeStart + window * this.iMmuVirtualWindowSize;
+                        IMmu.SetWindowAddend(window, value - virtualWindowOffset);
                         return;
                     case 4:
-                        IMmu.SetWindowLength(window, value);
+                        // This assumes that the window start has already been set
+                        var windowEnd = IMmu.GetWindowStart(window) + value + 1;
+                        IMmu.SetWindowEnd(window, windowEnd); // windowLength
                         return;
                     case 8:
-                        IMmu.SetWindowPermission(window, value);
+                        if (value > 3)
+                        {
+                            this.Log(LogLevel.Noisy, "Window permission value {0} out of range", value);
+                        }
+                        IMmu.SetWindowPrivileges(window, value << 2); // For the insn, the DataRead is InsnFetch
                         return;
                     }
                 }
@@ -450,16 +492,32 @@
                 {
                     offset -= 2048;
                     uint window = (uint)(offset >> 4);
+                    if(window >= dMmuNumWindows)
+                    {
+                        this.Log(LogLevel.Warning, "Invalid window number {}", window);
+                        return;
+                    }
                     switch (offset & 15)
                     {
                     case 0:
-                        DMmu.SetWindowOffset(window, value);
+                        uint virtualWindowOffset = (uint)(this.dMmuRangeStart + window * this.dMmuVirtualWindowSize);
+                        DMmu.SetWindowAddend(window, value - (uint)virtualWindowOffset);
                         return;
                     case 4:
-                        DMmu.SetWindowLength(window, value);
+                        if ((value + 1) > this.dMmuMemorySize)
+                        {
+                            this.Log(LogLevel.Error, "Window length 0x{1:X} exceeds the memory size 0x{1:X}", value, dMmuMemorySize);
+                        }
+                        // This assumes that the window start has already been set
+                        var windowEnd = DMmu.GetWindowStart(window) + value + 1;
+                        DMmu.SetWindowEnd(window, windowEnd); //windowLength
                         return;
                     case 8:
-                        DMmu.SetWindowPermission(window, value);
+                        if (value > 3)
+                        {
+                            this.Log(LogLevel.Noisy, "Window permission value {0} out of range", value);
+                        }
+                        DMmu.SetWindowPrivileges(window, value);
                         return;
                     }
                 }
@@ -534,6 +592,54 @@
 
         public DoubleWordRegisterCollection RegistersCollection { get; private set; }
 
+        private void HandleFault(ulong faultAddress, AccessType accessType, int windowIndex)
+        {
+            var faultType = (accessType == AccessType.Execute)? FaultType.InstructionFetch : FaultType.DataAccess;
+
+            if(faultType == FaultType.InstructionFetch)
+            {
+                LogFaultType(IMmu, faultAddress, accessType, iMmuRangeStart, iMmuVirtualWindowSize, iMmuNumWindows);
+            }
+            else
+            {
+                LogFaultType(DMmu, faultAddress, accessType, dMmuRangeStart, dMmuVirtualWindowSize, dMmuNumWindows);
+            }
+
+            ExecFault(faultType);
+        }
+
+        private void LogFaultType(ExternalMmuBase mmu, ulong faultAddress, AccessType accessType, ulong rangeStart, ulong virtualWindowSize, uint numberOfWindows)
+        {
+            var mmuName = mmu.GetType().Name;
+            var virtualWindowIndex = (uint)((faultAddress - rangeStart) / virtualWindowSize);
+
+            if(virtualWindowIndex >= numberOfWindows)
+            {
+                this.Log(LogLevel.Error, "{0}: Translation request for {1} at 0x{2:X}: failure, no window at address", mmuName, accessType, faultAddress);
+            }
+            else
+            {
+                var windowEnd = mmu.GetWindowEnd(virtualWindowIndex);
+                var windowPrivilege = mmu.GetWindowPrivileges(virtualWindowIndex);
+
+                if(faultAddress > windowEnd)
+                {
+                    this.Log(LogLevel.Error, "{0}: Translation request for {1} at 0x{2:X}: failure on window {3}, out of range, window ends at 0x{4:X}",
+                             mmuName, accessType, faultAddress, virtualWindowIndex, windowEnd);
+                }
+                else if((windowPrivilege & (uint)accessType) == 0)
+                {
+                    this.Log(LogLevel.Error, "{0}: Translation request for {1} at 0x{2:X}: failure on window {3}, no permission, window permissions are 0x{4:X}",
+                             mmuName, accessType, faultAddress, virtualWindowIndex, windowPrivilege);
+                }
+                else
+                {
+                    this.Log(LogLevel.Error, "{0}: Translation request for {1} at 0x{2:X}: failed for unknown reason. This should not occur",
+                             mmuName, accessType, faultAddress);
+                }
+            }
+        }
+
         public GPIO HostReqIRQ { get; }
         public GPIO FinishIRQ { get; }
         public GPIO InstructionFaultIRQ { get; }
@@ -575,10 +681,16 @@
         private Mode mode;
         private readonly Machine Machine;
         private readonly SpringbokRiscV32 Core;
-        private readonly SpringbokRiscV32_WindowMMU IMmu;
-        private readonly SpringbokRiscV32_WindowMMU DMmu;
-        private readonly MappedMemory IMem;
-        private readonly MappedMemory DMem;
+        private readonly ExternalMmuBase IMmu;
+        private readonly ExternalMmuBase DMmu;
+        private readonly uint dMmuNumWindows;
+        private readonly ulong dMmuRangeStart;
+        private readonly ulong dMmuMemorySize;
+        private readonly ulong dMmuVirtualWindowSize;
+        private readonly uint iMmuNumWindows;
+        private readonly ulong iMmuRangeStart;
+        private readonly ulong iMmuMemorySize;
+        private readonly ulong iMmuVirtualWindowSize;
 
         // Length of register space.
         public long Size => 0x1000;
diff --git a/shodan_infrastructure/SpringbokRiscV32_WindowMMU.cs b/shodan_infrastructure/SpringbokRiscV32_WindowMMU.cs
deleted file mode 100644
index 235754d..0000000
--- a/shodan_infrastructure/SpringbokRiscV32_WindowMMU.cs
+++ /dev/null
@@ -1,500 +0,0 @@
-//
-// Copyright (c) 2021 Google LLC
-//
-// This file is licensed under the MIT License.
-// Full license text is available in 'licenses/MIT.txt'.
-//
-using System;
-using Antmicro.Renode.Core;
-using System.Linq;
-using Antmicro.Renode.Exceptions;
-using Antmicro.Renode.Peripherals.Bus;
-using Antmicro.Renode.Peripherals.Memory;
-using Antmicro.Renode.Logging;
-
-namespace Antmicro.Renode.Peripherals.CPU
-{
-  /*
-   * The WindowMMU performs minimal memory address translation and protection
-   * by providing one or more windows of software configurable length and offset
-   * into another address space. The configuration of the WindowMMU is intended
-   * to be handled by a secure operating context, and in the case of Matcha via
-   * the System Management Core through Springbok's configuration register file.
-   *
-   * The WindowMMU has four implementation defined configuration parameters:
-   *   o Number of windows
-   *     This defines how many address translation windows the WindowMMU has.
-   *     It can be any number, but to keep things small in Matcha we have 2 for
-   *     the Vector Core's instruction fetch WindowMMU and 4 for the data
-   *     WindowMMU.
-   *   o Window size
-   *     This defines the input virtual address aperture for each window.
-   *     The total virtual address aperture for the WindowMMU is the first power
-   *     of two greater or equal to Window Size times Number of Windows (in
-   *     other words, log2ceil(WINDOW_SIZE * NUMBER_OF_WINDOWS)). This must be a
-   *     power-of-two multiple of page size. In Matcha this is 4 MiB.
-   *   o TCM size
-   *     This defines the output physical address aperture for the whole
-   *     WindowMMU. This does not need to be the same as window size, though in
-   *     Matcha it is.
-   *   o Page size
-   *     This defines the granularity of window offsets and lengths. It must be
-   *     a power-of-two multiple of the largest single access size. In Matcha
-   *     to simplify hardware design and match this up with the SMC's MMU's page
-   *     size it is set to 4 KiB.
-   *
-   * Pseudo-code describing a translation:
-   *
-   *   uint window_length[number_of_windows];
-   *   uint window_offset[number_of_windows];
-   *   bool window_writable[number_of_windows];
-   *   bool window_readable[number_of_windows];
-   *
-   *   uint getTranslation(uint addr, bool write) {
-   *     uint window = addr / window_size;
-   *     uint local_addr = addr % window_size;
-   *     bool permitted = write? window_writable[window] :
-   *                             window_readable[window];
-   *
-   *     if (permitted && local_addr < (window_length[window] + page_size))
-   *       return local_addr + window_offset[window];
-   *     else
-   *       throw access_fault;
-   *   }
-   */
-
-  public class SpringbokRiscV32_WindowMMU : IBytePeripheral, IWordPeripheral, IDoubleWordPeripheral, IMultibyteWritePeripheral, IKnownSize
-  {
-    private uint GetNextPowerOfTwo(uint input)
-    {
-      uint retval = input - 1;
-      for (int i = 1; i <= 16; i <<= 1)
-      {
-        retval |= retval >> i;
-      }
-      return retval + 1;
-    }
-
-    private uint GetLog2Ceil(uint input)
-    {
-      uint retval = 0;
-      uint v = GetNextPowerOfTwo(input);
-      while (v > 1)
-      {
-        retval++;
-        v >>= 1;
-      }
-      return retval;
-    }
-
-    public SpringbokRiscV32_WindowMMU(Machine machine,
-                                      MappedMemory tcm,
-                                      long windowSize,
-                                      long tcmSize,
-                                      long pageSize,
-                                      long numWindows)
-    {
-      this.tcm = tcm;
-      this.windowSize = (uint)windowSize;
-      this.tcmSize = (uint)tcmSize;
-      this.pageSize = (uint)pageSize;
-      this.numWindows = (uint)numWindows;
-      this.faultCallback = null;
-
-      windowSizeBits = GetLog2Ceil(this.windowSize);
-      tcmSizeBits = GetLog2Ceil(this.tcmSize);
-      pageSizeBits = GetLog2Ceil(this.pageSize);
-      numWindowsBits = GetLog2Ceil(this.numWindows);
-
-      windowSizeMask = (uint)((1 << (int)windowSizeBits) - 1);
-      tcmSizeMask = (uint)((1 << (int)tcmSizeBits) - 1);
-      pageSizeMask = (uint)((1 << (int)pageSizeBits) - 1);
-      offsetLengthMask = GetNextPowerOfTwo(this.tcmSize) / this.pageSize - 1;
-
-      Reset();
-    }
-
-    private enum AccessType {
-      Read,
-      Write,
-      ReadOrWrite,
-      ReadAndWrite
-    };
-
-    private string AccessTypeToString(AccessType type) {
-      switch (type) {
-        case AccessType.Read:
-          return "Read";
-        case AccessType.Write:
-          return "Write";
-        case AccessType.ReadOrWrite:
-          return "ReadOrWrite";
-        case AccessType.ReadAndWrite:
-          return "ReadAndWrite";
-        default:
-          return "<unknown>";
-      }
-    }
-
-    private bool GetTranslatedAddress(uint offset,
-                                      AccessType accessType,
-                                      out uint translatedAddress)
-    {
-      if (enabled)
-      {
-        uint window = offset >> (int)windowSizeBits;
-        if (window >= numWindows) {
-          translatedAddress = 0;
-          this.Log(LogLevel.Error,
-                   "Translation request for {0} at 0x{1:X}: failure, no window at address",
-                   AccessTypeToString(accessType), offset);
-          return false;
-        }
-
-        uint windowAddr = offset & windowSizeMask;
-        uint windowOffset = windowOffsets[window];
-        uint windowLength = windowLengths[window] + pageSize;
-        uint windowPermission = windowPermissions[window];
-        bool hasPermission = false;
-        switch (accessType) {
-          case AccessType.Read:
-            hasPermission = (windowPermission & 1) != 0;
-            break;
-          case AccessType.Write:
-            hasPermission = (windowPermission & 2) != 0;
-            break;
-          case AccessType.ReadOrWrite:
-            hasPermission = (windowPermission & 3) != 0;
-            break;
-          case AccessType.ReadAndWrite:
-            hasPermission = (windowPermission & 3) == 3;
-            break;
-        }
-
-        if (!hasPermission || (windowAddr >= windowLength))
-        {
-          translatedAddress = 0;
-          if (!hasPermission) {
-            this.Log(LogLevel.Error,
-                     "Translation request for {0} at 0x{1:X}: failure on window {2}, no permission, window permissions are 0x{3:X}",
-                     AccessTypeToString(accessType), offset, window, windowPermission);
-          }
-          else
-          {
-            this.Log(LogLevel.Error,
-                     "Translation request for {0} at 0x{1:X}: failure on window {2}, out of range, window size is 0x{3:X}",
-                     AccessTypeToString(accessType), offset, window, windowLength);
-          }
-          return false;
-        }
-
-        translatedAddress = windowOffset + windowAddr;
-        this.Log(LogLevel.Noisy,
-                 "Translation request for {0} at 0x{1:X}: success on window {2}, to tcm+0x{3:X}",
-                 AccessTypeToString(accessType), offset, window, translatedAddress);
-        return true;
-      }
-      else
-      {
-        translatedAddress = offset;
-        this.Log(LogLevel.Noisy,
-                 "Translation request for {0} at 0x{1:X}: pass-through, to tcm+0x{2:X}",
-                 AccessTypeToString(accessType), offset, translatedAddress);
-        return true;
-      }
-    }
-
-    public byte ReadByte(long offset)
-    {
-      uint translatedAddress;
-      if (GetTranslatedAddress(checked((uint)offset), AccessType.Read, out translatedAddress))
-      {
-        return tcm.ReadByte(translatedAddress);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-        return 0;
-      }
-    }
-
-    public void WriteByte(long offset, byte value)
-    {
-      uint translatedAddress;
-      if (GetTranslatedAddress(checked((uint)offset), AccessType.Write, out translatedAddress))
-      {
-        tcm.WriteByte(translatedAddress, value);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-      }
-    }
-
-    public ushort ReadWord(long offset)
-    {
-      uint translatedAddress;
-      if (GetTranslatedAddress(checked((uint)offset), AccessType.Read, out translatedAddress))
-      {
-        return tcm.ReadWord(translatedAddress);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-        return 0;
-      }
-    }
-
-    public void WriteWord(long offset, ushort value)
-    {
-      uint translatedAddress;
-      if (GetTranslatedAddress(checked((uint)offset), AccessType.Write, out translatedAddress))
-      {
-        tcm.WriteWord(translatedAddress, value);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-      }
-    }
-
-    public uint ReadDoubleWord(long offset)
-    {
-      uint translatedAddress;
-      if (GetTranslatedAddress(checked((uint)offset), AccessType.Read, out translatedAddress))
-      {
-        return tcm.ReadDoubleWord(translatedAddress);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-        return 0;
-      }
-    }
-
-    public void WriteDoubleWord(long offset, uint value)
-    {
-      uint translatedAddress;
-      if (GetTranslatedAddress(checked((uint)offset), AccessType.Write, out translatedAddress))
-      {
-        tcm.WriteDoubleWord(translatedAddress, value);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-      }
-    }
-
-    public ulong TranslateAbsolute(ulong address)
-    {
-      foreach (var range in systemBus.GetRegistrationPoints(this).Select(x => x.Range))
-      {
-        if (range.Contains(address))
-        {
-          ulong offset = address - range.StartAddress;
-          uint translatedAddress;
-          if (GetTranslatedAddress(checked((uint)offset), AccessType.ReadOrWrite, out translatedAddress)) {
-            return translatedAddress;
-          }
-        }
-      }
-      throw new RecoverableException("Cannot translate address that does not lay in redirector.");
-    }
-
-    public byte[] ReadBytes(long offset, int count)
-    {
-      uint startTranslatedAddress, lastTranslatedAddress;
-      bool startValid = GetTranslatedAddress(checked((uint)offset), AccessType.Read, out startTranslatedAddress);
-      bool endValid = GetTranslatedAddress(checked((uint)(offset + count - 1)), AccessType.Read, out lastTranslatedAddress);
-
-      if (startValid && endValid)
-      {
-        return tcm.ReadBytes(startTranslatedAddress, count);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-        return new byte[count];
-      }
-    }
-
-    public void WriteBytes(long offset, byte[] array, int startingIndex, int count)
-    {
-      uint startTranslatedAddress, lastTranslatedAddress;
-      bool startValid = GetTranslatedAddress(checked((uint)offset), AccessType.Write, out startTranslatedAddress);
-      bool endValid = GetTranslatedAddress(checked((uint)(offset + count - 1)), AccessType.Write, out lastTranslatedAddress);
-
-      if (startValid && endValid)
-      {
-        tcm.WriteBytes(startTranslatedAddress, array, startingIndex, count);
-      }
-      else
-      {
-        // Trigger interrupt
-        if (faultCallback != null)
-        {
-          faultCallback();
-        }
-      }
-    }
-
-    public void Reset()
-    {
-      enabled = true;
-      windowOffsets = new uint[numWindows];
-      windowLengths = new uint[numWindows];
-      windowPermissions = new uint[numWindows];
-    }
-
-    public uint GetWindowOffset(uint window)
-    {
-      if (window < windowSize)
-      {
-        return windowOffsets[window];
-      }
-      else
-      {
-        this.Log(LogLevel.Error, "Invalid window number {0}", window);
-        return 0;
-      }
-    }
-
-    public uint GetWindowLength(uint window)
-    {
-      if (window < windowSize)
-      {
-        return windowLengths[window];
-      }
-      else
-      {
-        this.Log(LogLevel.Error, "Invalid window number {0}", window);
-        return 0;
-      }
-    }
-
-    public uint GetWindowPermission(uint window)
-    {
-      if (window < windowSize)
-      {
-        return windowPermissions[window];
-      }
-      else
-      {
-        this.Log(LogLevel.Error, "Invalid window number {0}", window);
-        return 0;
-      }
-    }
-
-    public void SetWindowOffset(uint window, uint value)
-    {
-      if (value > tcmSizeMask)
-      {
-        this.Log(LogLevel.Noisy, "Window length value {0} out of range", value);
-      }
-
-      if (window < windowSize)
-      {
-        windowOffsets[window] = value & tcmSizeMask & ~pageSizeMask;
-      }
-      else
-      {
-        this.Log(LogLevel.Error, "Invalid window number {0}", window);
-      }
-    }
-
-    public void SetWindowLength(uint window, uint value)
-    {
-      if (value > tcmSizeMask)
-      {
-        this.Log(LogLevel.Noisy, "Window length value {0} out of range", value);
-      }
-
-      if (window < windowSize)
-      {
-        windowLengths[window] = value & tcmSizeMask & ~pageSizeMask;
-      }
-      else
-      {
-        this.Log(LogLevel.Error, "Invalid window number {0}", window);
-      }
-    }
-
-    public void SetWindowPermission(uint window, uint value)
-    {
-      if (value > 3)
-      {
-        this.Log(LogLevel.Noisy, "Window permission value {0} out of range", value);
-      }
-
-      if (window < windowSize)
-      {
-        windowPermissions[window] = value & 3;
-      }
-      else
-      {
-        this.Log(LogLevel.Error, "Invalid window number {0}", window);
-      }
-    }
-
-    public void RegisterFaultCallback(Action faultCallback)
-    {
-      this.faultCallback = faultCallback;
-    }
-
-    public long Size => (long)GetNextPowerOfTwo(windowSize * numWindows);
-
-    private readonly SystemBus systemBus;
-    private readonly MappedMemory tcm;
-
-    public readonly uint windowSize;
-    public readonly uint tcmSize;
-    public readonly uint pageSize;
-    public readonly uint numWindows;
-
-    public readonly uint windowSizeBits;
-    public readonly uint tcmSizeBits;
-    public readonly uint pageSizeBits;
-    public readonly uint numWindowsBits;
-
-    public readonly uint windowSizeMask;
-    public readonly uint tcmSizeMask;
-    public readonly uint pageSizeMask;
-    public readonly uint offsetLengthMask;
-
-    // TO-DO(jonathantate): Need to plumb the enable bit to the control block register file
-    public bool enabled;
-    private uint[] windowOffsets;
-    private uint[] windowLengths;
-    private uint[] windowPermissions;
-
-    private Action faultCallback;
-  }
-}