1 // 2 // Copyright (c) 2010-2023 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.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Peripherals.CPU; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.Miscellaneous 17 { 18 public class ExternalWindowMMU: ExternalMmuBase, IDoubleWordPeripheral, IKnownSize 19 { ExternalWindowMMU(ICPUWithExternalMmu cpu, ulong startAddress, ulong windowSize, uint numberOfWindows)20 public ExternalWindowMMU(ICPUWithExternalMmu cpu, ulong startAddress, ulong windowSize, uint numberOfWindows) : base(cpu, numberOfWindows) 21 { 22 this.numberOfWindows = numberOfWindows; 23 IRQ = new GPIO(); 24 registers = DefineRegisters(); 25 26 cpu.AddHookOnMmuFault((faultAddress, accessType, faultyWindowAddress) => 27 { 28 if(faultyWindowAddress != -1 && this.ContainsWindowWithIndex((uint)faultyWindowAddress)) 29 { 30 this.TriggerInterrupt(); 31 throw new CpuAbortException("Mmu fault occured. This must be handled properly"); 32 } 33 }); 34 } 35 Reset()36 public override void Reset() 37 { 38 registers.Reset(); 39 base.Reset(); 40 } 41 ReadDoubleWord(long offset)42 public uint ReadDoubleWord(long offset) 43 { 44 return registers.Read(offset); 45 } 46 WriteDoubleWord(long offset, uint value)47 public void WriteDoubleWord(long offset, uint value) 48 { 49 registers.Write(offset, value); 50 } 51 52 public GPIO IRQ { get; } 53 54 public long Size => 0x1000; 55 TriggerInterrupt()56 private void TriggerInterrupt() 57 { 58 this.Log(LogLevel.Debug, "MMU fault occured. Setting the IRQ"); 59 IRQ.Set(); 60 } 61 DefineRegisters()62 private DoubleWordRegisterCollection DefineRegisters() 63 { 64 var registersMap = new Dictionary<long, DoubleWordRegister>(); 65 66 for(uint i = 0; i < numberOfWindows; i++) 67 { 68 var index = i; 69 registersMap.Add((long)Register.RangeStartBase + index * 4, new DoubleWordRegister(this) 70 .WithValueField(0, 32, name: $"RANGE_START[{index}]", writeCallback: (_, value) => 71 { 72 SetWindowStart(index, (ulong)value); 73 }, valueProviderCallback: _ => 74 { 75 return (uint)GetWindowStart(index); 76 })); 77 registersMap.Add((long)Register.RangeEndBase + index * 4, new DoubleWordRegister(this) 78 .WithValueField(0, 32, name: $"RANGE_END[{index}]", writeCallback: (_, value) => 79 { 80 SetWindowEnd(index, (ulong)value); 81 }, valueProviderCallback: _ => 82 { 83 return (uint)GetWindowEnd(index); 84 })); 85 registersMap.Add((long)Register.AddendBase + index * 4, new DoubleWordRegister(this) 86 .WithValueField(0, 32, name: $"ADDEND[{index}]", writeCallback: (_, value) => 87 { 88 SetWindowAddend(index, (ulong)value); 89 }, valueProviderCallback: _ => 90 { 91 return (uint)GetWindowAddend(index); 92 })); 93 registersMap.Add((long)Register.PrivilegesBase + index * 4, new DoubleWordRegister(this) 94 .WithValueField(0, 32, name: $"PRIVILEGES[{index}]", writeCallback: (_, value) => 95 { 96 SetWindowPrivileges(index, (uint)value); 97 }, valueProviderCallback: _ => 98 { 99 return GetWindowPrivileges(index); 100 })); 101 } 102 return new DoubleWordRegisterCollection(this, registersMap); 103 } 104 105 private readonly uint numberOfWindows; 106 private readonly DoubleWordRegisterCollection registers; 107 108 private enum Register 109 { 110 RangeStartBase = 0x0, 111 RangeEndBase = 0x400, 112 AddendBase = 0x800, 113 PrivilegesBase = 0xC00, 114 } 115 } 116 } 117