1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Exceptions; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.CPU; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.Peripherals.Miscellaneous 16 { 17 public class ExternalMmuBase: IPeripheral 18 { ExternalMmuBase(ICPUWithExternalMmu cpu, uint windowsCount)19 public ExternalMmuBase(ICPUWithExternalMmu cpu, uint windowsCount) 20 { 21 this.cpu = cpu; 22 this.windowsCount = windowsCount; 23 windowMapping = new Dictionary<uint, uint>(); 24 25 cpu.EnableExternalWindowMmu(true); 26 for(uint index = 0; index < windowsCount; index++) 27 { 28 AddWindow(index); 29 } 30 } 31 Reset()32 public virtual void Reset() 33 { 34 foreach(var realIndex in windowMapping.Values) 35 { 36 cpu.ResetMmuWindow(realIndex); 37 } 38 windowMapping.Clear(); 39 } 40 SetWindowStart(uint index, ulong startAddress)41 public void SetWindowStart(uint index, ulong startAddress) 42 { 43 if(TryGetRealWindowIndex(index, out var realIndex)) 44 { 45 cpu.SetMmuWindowStart(realIndex, startAddress); 46 } 47 } 48 SetWindowEnd(uint index, ulong endAddress)49 public void SetWindowEnd(uint index, ulong endAddress) 50 { 51 if(TryGetRealWindowIndex(index, out var realIndex)) 52 { 53 cpu.SetMmuWindowEnd(realIndex, endAddress); 54 } 55 } 56 GetWindowStart(uint index)57 public ulong GetWindowStart(uint index) 58 { 59 if(TryGetRealWindowIndex(index, out var realIndex)) 60 { 61 return cpu.GetMmuWindowStart(realIndex); 62 } 63 return 0; 64 } 65 GetWindowEnd(uint index)66 public ulong GetWindowEnd(uint index) 67 { 68 if(TryGetRealWindowIndex(index, out var realIndex)) 69 { 70 return cpu.GetMmuWindowEnd(realIndex); 71 } 72 return 0; 73 } 74 SetWindowAddend(uint index, ulong addend)75 public void SetWindowAddend(uint index, ulong addend) 76 { 77 if(TryGetRealWindowIndex(index, out var realIndex)) 78 { 79 cpu.SetMmuWindowAddend(realIndex, addend); 80 } 81 } 82 SetWindowPrivileges(uint index, uint privileges)83 public void SetWindowPrivileges(uint index, uint privileges) 84 { 85 if(TryGetRealWindowIndex(index, out var realIndex)) 86 { 87 cpu.SetMmuWindowPrivileges(realIndex, (uint)privileges); 88 } 89 } 90 GetWindowAddend(uint index)91 public ulong GetWindowAddend(uint index) 92 { 93 if(TryGetRealWindowIndex(index, out var realIndex)) 94 { 95 return cpu.GetMmuWindowAddend(realIndex); 96 } 97 return 0; 98 } 99 GetWindowPrivileges(uint index)100 public uint GetWindowPrivileges(uint index) 101 { 102 if(TryGetRealWindowIndex(index, out var realIndex)) 103 { 104 return cpu.GetMmuWindowPrivileges(realIndex); 105 } 106 return 0; 107 } 108 ContainsWindowWithIndex(uint index)109 public bool ContainsWindowWithIndex(uint index) 110 { 111 return windowMapping.ContainsValue(index); 112 } 113 AddWindow(uint index, ulong? rangeStart = null, ulong? rangeEnd = null, ulong? addend = null, Privilege? privilege = null, Privilege? type = Privilege.All)114 protected void AddWindow(uint index, ulong? rangeStart = null, ulong? rangeEnd = null, ulong? addend = null, Privilege? privilege = null, Privilege? type = Privilege.All) 115 { 116 var realIndex = cpu.AcquireExternalMmuWindow((uint)type.Value); 117 if(realIndex == -1) 118 { 119 throw new ConstructionException("Failed to acquire the MMU window. Possibly ran out of windows"); 120 } 121 windowMapping.Add(index, (uint)realIndex); 122 123 if(rangeStart.HasValue) 124 { 125 cpu.SetMmuWindowStart((uint)realIndex, rangeStart.Value); 126 } 127 if(rangeEnd.HasValue) 128 { 129 cpu.SetMmuWindowEnd((uint)realIndex, rangeEnd.Value); 130 } 131 if(addend.HasValue) 132 { 133 cpu.SetMmuWindowAddend((uint)realIndex, addend.Value); 134 } 135 if(privilege.HasValue) 136 { 137 cpu.SetMmuWindowPrivileges((uint)realIndex, (uint)privilege.Value); 138 } 139 } 140 TryGetRealWindowIndex(uint index, out uint realIndex)141 private bool TryGetRealWindowIndex(uint index, out uint realIndex) 142 { 143 realIndex = 0; 144 if(index >= windowsCount) 145 { 146 this.Log(LogLevel.Error, "Window index {0} is higher than the peripheral windows count: {1}", index, windowsCount); 147 return false; 148 } 149 realIndex = windowMapping[index]; 150 return true; 151 } 152 153 // There might be more than one ExternalMmu for a single CPU, hence the MMU window index is not the CPU MMU window index 154 private readonly Dictionary<uint, uint> windowMapping; 155 private readonly ICPUWithExternalMmu cpu; 156 private readonly uint windowsCount; 157 158 public enum Privilege : uint 159 { 160 Read = 0b001, 161 Write = 0b010, 162 ReadAndWrite = 0b011, 163 Execute = 0b100, 164 All = 0b111, 165 } 166 } 167 } 168