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