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