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; - } -}