1 //
2 // Copyright (c) 2010-2025 Antmicro
3 // Copyright (c) 2022-2025 Silicon Labs
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 
9 using System;
10 using System.Collections.Generic;
11 using System.IO;
12 using Antmicro.Renode.Core;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Exceptions;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Peripherals.Timers;
18 using Antmicro.Renode.Time;
19 
20 namespace Antmicro.Renode.Peripherals.Miscellaneous.SiLabs
21 {
22     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
23     public class EFR32xG2_SMU_1 : IBusPeripheral, IKnownSize
24     {
EFR32xG2_SMU_1(Machine machine)25         public EFR32xG2_SMU_1(Machine machine)
26         {
27             this.machine = machine;
28 
29             SecureIRQ = new GPIO();
30             SecurePriviledgedIRQ = new GPIO();
31             NonSecurePriviledgedIRQ = new GPIO();
32 
33             privilegedPeripheralAccess = new IFlagRegisterField[NumberOfPeripherals];
34             nonSecurePrivilegedPeripheralAccess = new IFlagRegisterField[NumberOfPeripherals];
35             securePeripheralAccess = new IFlagRegisterField[NumberOfPeripherals];
36             disablePeripheralAccess = new IFlagRegisterField[NumberOfPeripherals];
37             privilegedBusMusterAccess = new IFlagRegisterField[NumberOfBusMasters];
38             secureBusMusterAccess = new IFlagRegisterField[NumberOfBusMasters];
39 
40             secureRegistersCollection = BuildSecureRegistersCollection();
41             nonSecureRegistersCollection = BuildNonSecureRegistersCollection();
42         }
43 
Reset()44         public void Reset()
45         {
46         }
47 
48         [ConnectionRegionAttribute("smu_s")]
WriteDoubleWordSecure(long offset, uint value)49         public void WriteDoubleWordSecure(long offset, uint value)
50         {
51             Write<Registers>(secureRegistersCollection, "SmuSecure", offset, value);
52         }
53 
54         [ConnectionRegionAttribute("smu_s")]
ReadDoubleWordSecure(long offset)55         public uint ReadDoubleWordSecure(long offset)
56         {
57             return Read<Registers>(secureRegistersCollection, "SmuSecure", offset);
58         }
59 
60         [ConnectionRegionAttribute("smu_ns")]
WriteDoubleWordNonSecure(long offset, uint value)61         public void WriteDoubleWordNonSecure(long offset, uint value)
62         {
63             Write<Registers>(nonSecureRegistersCollection, "SmuNonSecure", offset, value);
64         }
65 
66         [ConnectionRegionAttribute("smu_ns")]
ReadDoubleWordNonSecure(long offset)67         public uint ReadDoubleWordNonSecure(long offset)
68         {
69             return Read<Registers>(nonSecureRegistersCollection, "SmuNonSecure", offset);
70         }
71 
72         private uint Read<T>(DoubleWordRegisterCollection registersCollection, string regionName, long offset, bool internal_read = false)
73         where T : struct, IComparable, IFormattable
74         {
75             var result = 0U;
76             long internal_offset = offset;
77 
78             // Set, Clear, Toggle registers should only be used for write operations. But just in case we convert here as well.
79             if (offset >= SetRegisterOffset && offset < ClearRegisterOffset)
80             {
81                 // Set register
82                 internal_offset = offset - SetRegisterOffset;
83                 if(!internal_read)
84                 {
85                     this.Log(LogLevel.Noisy, "SET Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset);
86                 }
87             } else if (offset >= ClearRegisterOffset && offset < ToggleRegisterOffset)
88             {
89                 // Clear register
90                 internal_offset = offset - ClearRegisterOffset;
91                 if(!internal_read)
92                 {
93                     this.Log(LogLevel.Noisy, "CLEAR Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset);
94                 }
95             } else if (offset >= ToggleRegisterOffset)
96             {
97                 // Toggle register
98                 internal_offset = offset - ToggleRegisterOffset;
99                 if(!internal_read)
100                 {
101                     this.Log(LogLevel.Noisy, "TOGGLE Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset);
102                 }
103             }
104 
105             if(!registersCollection.TryRead(internal_offset, out result))
106             {
107                 if(!internal_read)
108                 {
109                     this.Log(LogLevel.Noisy, "Unhandled read from {0} at offset 0x{1:X} ({2}).", regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"));
110                 }
111             }
112             else
113             {
114                 if(!internal_read)
115                 {
116                     this.Log(LogLevel.Noisy, "{0}: Read from {1} at offset 0x{2:X} ({3}), returned 0x{4:X}",
117                              this.GetTime(), regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"), result);
118                 }
119             }
120 
121             return result;
122         }
123 
124         private void Write<T>(DoubleWordRegisterCollection registersCollection, string regionName, long offset, uint value)
125         where T : struct, IComparable, IFormattable
126         {
machine.ClockSource.ExecuteInLockAntmicro.Renode.Peripherals.Miscellaneous.SiLabs.EFR32xG2_SMU_1.IFormattable127             machine.ClockSource.ExecuteInLock(delegate {
128                 long internal_offset = offset;
129                 uint internal_value = value;
130 
131                 if (offset >= SetRegisterOffset && offset < ClearRegisterOffset)
132                 {
133                     // Set register
134                     internal_offset = offset - SetRegisterOffset;
135                     uint old_value = Read<T>(registersCollection, regionName, internal_offset, true);
136                     internal_value = old_value | value;
137                     this.Log(LogLevel.Noisy, "SET Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, SET_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset, value, old_value, internal_value);
138                 } else if (offset >= ClearRegisterOffset && offset < ToggleRegisterOffset)
139                 {
140                     // Clear register
141                     internal_offset = offset - ClearRegisterOffset;
142                     uint old_value = Read<T>(registersCollection, regionName, internal_offset, true);
143                     internal_value = old_value & ~value;
144                     this.Log(LogLevel.Noisy, "CLEAR Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, CLEAR_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset, value, old_value, internal_value);
145                 } else if (offset >= ToggleRegisterOffset)
146                 {
147                     // Toggle register
148                     internal_offset = offset - ToggleRegisterOffset;
149                     uint old_value = Read<T>(registersCollection, regionName, internal_offset, true);
150                     internal_value = old_value ^ value;
151                     this.Log(LogLevel.Noisy, "TOGGLE Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, TOGGLE_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", Enum.Format(typeof(T), internal_offset, "G"), offset, internal_offset, value, old_value, internal_value);
152                 }
153 
154                 this.Log(LogLevel.Noisy, "{0}: Write to {1} at offset 0x{2:X} ({3}), value 0x{4:X}",
155                         this.GetTime(), regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"), internal_value);
156 
157                 if(!registersCollection.TryWrite(internal_offset, internal_value))
158                 {
159                     this.Log(LogLevel.Debug, "Unhandled write to {0} at offset 0x{1:X} ({2}), value 0x{3:X}.", regionName, internal_offset, Enum.Format(typeof(T), internal_offset, "G"), internal_value);
160                     return;
161                 }
162             });
163         }
164 
BuildSecureRegistersCollection()165         private DoubleWordRegisterCollection BuildSecureRegistersCollection()
166         {
167             var registerDictionary = new Dictionary<long, DoubleWordRegister>
168             {
169                 {(long)Registers.IpVersion, new DoubleWordRegister(this, 0x1)
170                     .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => Version, name: "IPVERSION")
171                 },
172                 {(long)Registers.Status, new DoubleWordRegister(this)
173                     .WithFlag(0, out secureLock, FieldMode.Read, name: "SMULOCK")
174                     .WithFlag(1, out secureProgrammingError, FieldMode.Read, name: "SMUPRGERR")
175                     .WithReservedBits(2, 30)
176                 },
177                 {(long)Registers.Lock, new DoubleWordRegister(this)
178                     .WithValueField(0, 24, FieldMode.Write, writeCallback: (_, value) =>
179                     {
180                         secureLock.Value = (value != UnlockKey);
181                     }, name: "SMULOCKKEY")
182                     .WithReservedBits(24, 8)
183                 },
184                 {(long)Registers.InterruptFlags, new DoubleWordRegister(this)
185                     .WithFlag(0, out PPU_PrivilegeInterrupt, name: "PPUPRIVIF")
186                     .WithReservedBits(1, 1)
187                     .WithFlag(2, out PPU_InstructionInterrupt, name: "PPUINSTIF")
188                     .WithReservedBits(3, 13)
189                     .WithFlag(16, out PPU_SecurityInterrupt, name: "PPUSECIF")
190                     .WithFlag(17, out BMPU_SecurityInterrupt, name: "BMPUSECIF")
191                     .WithReservedBits(18, 14)
192                     .WithChangeCallback((_, __) => UpdateInterrupts())
193                 },
194                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
195                     .WithFlag(0, out PPU_PrivilegeInterruptEnable, name: "PPUPRIVIEN")
196                     .WithReservedBits(1, 1)
197                     .WithFlag(2, out PPU_InstructionInterruptEnable, name: "PPUINSTIEN")
198                     .WithReservedBits(3, 13)
199                     .WithFlag(16, out PPU_SecurityInterruptEnable, name: "PPUSECIEN")
200                     .WithFlag(17, out BMPU_SecurityInterruptEnable, name: "BMPUSECIEN")
201                     .WithReservedBits(18, 14)
202                     .WithChangeCallback((_, __) => UpdateInterrupts())
203                 },
204                 {(long)Registers.M33Control, new DoubleWordRegister(this)
205                     .WithFlag(0, out lockSAU, name: "LOCKSAU")
206                     .WithFlag(1, out lockNonSecureMPU, name: "LOCKNSMPU")
207                     .WithFlag(2, out lockSecureMPU, name: "LOCKSMPU")
208                     .WithFlag(3, out lockNonSecureVTOR, name: "LOCKNSVTOR")
209                     .WithFlag(4, out lockSecureVTAIRCR, name: "LOCKSVTAIRCR")
210                     .WithReservedBits(5, 27)
211                 },
212                 {(long)Registers.M33InitNsVector, new DoubleWordRegister(this)
213                     .WithReservedBits(0, 7)
214                     .WithTag("TBLOFF", 7, 25)
215                 },
216                 {(long)Registers.M33InitSVector, new DoubleWordRegister(this)
217                     .WithReservedBits(0, 7)
218                     .WithTag("TBLOFF", 7, 25)
219                 },
220                 {(long)Registers.PPU_PriviledgedAttribute0, new DoubleWordRegister(this, 0xFFFFFFFF)
221                     .For((r, i) => r.WithFlag(i, out privilegedPeripheralAccess[i], name: $"PPUPATD{i}"), 0 , 32)
222                 },
223                 {(long)Registers.PPU_PriviledgedAttribute1, new DoubleWordRegister(this, 0xFFFFFFFF)
224                     .For((r, i) => r.WithFlag(i, out privilegedPeripheralAccess[i + 32], name: $"PPUPATD{i}"), 0 , 32)
225                 },
226                 {(long)Registers.PPU_SecureAttribute0, new DoubleWordRegister(this, 0xFFFFFFFF)
227                     .For((r, i) => r.WithFlag(i, out securePeripheralAccess[i], name: $"PPUSATD{i}"), 0 , 32)
228                 },
229                 {(long)Registers.PPU_SecureAttribute1, new DoubleWordRegister(this, 0xFFFFFFFF)
230                     .For((r, i) => r.WithFlag(i, out securePeripheralAccess[i + 32], name: $"PPUSATD{i}"), 0 , 32)
231                 },
232                 {(long)Registers.PPU_Disable0, new DoubleWordRegister(this)
233                     .For((r, i) => r.WithFlag(i, out disablePeripheralAccess[i], name: $"PPUDIS{i}"), 0 , 32)
234                 },
235                 {(long)Registers.PPU_Disable1, new DoubleWordRegister(this)
236                     .For((r, i) => r.WithFlag(i, out disablePeripheralAccess[i + 32], name: $"PPUDIS{i}"), 0 , 32)
237                 },
238                 {(long)Registers.PPU_FaultStatus, new DoubleWordRegister(this)
239                     .WithValueField(0, 8, out PPU_FaultStatus, FieldMode.Read, name: "PPUFSPERIPHID")
240                     .WithReservedBits(8, 24)
241                 },
242                 {(long)Registers.BMPU_PriviledgedAttribute0, new DoubleWordRegister(this, 0x1F)
243                     .WithFlag(0, out privilegedBusMusterAccess[0], name: "BMPUPATD0")
244                     .WithFlag(1, out privilegedBusMusterAccess[1], name: "BMPUPATD1")
245                     .WithFlag(2, out privilegedBusMusterAccess[2], name: "BMPUPATD2")
246                     .WithFlag(3, out privilegedBusMusterAccess[3], name: "BMPUPATD3")
247                     .WithFlag(4, out privilegedBusMusterAccess[4], name: "BMPUPATD4")
248                     .WithReservedBits(5, 27)
249                 },
250                 {(long)Registers.BMPU_SecureAttribute0, new DoubleWordRegister(this, 0x1F)
251                     .WithFlag(0, out secureBusMusterAccess[0], name: "BMPUSATD0")
252                     .WithFlag(1, out secureBusMusterAccess[1], name: "BMPUSATD1")
253                     .WithFlag(2, out secureBusMusterAccess[2], name: "BMPUSATD2")
254                     .WithFlag(3, out secureBusMusterAccess[3], name: "BMPUSATD3")
255                     .WithFlag(4, out secureBusMusterAccess[4], name: "BMPUSATD4")
256                     .WithReservedBits(5, 27)
257                 },
258                 {(long)Registers.BMPU_FaultStatus, new DoubleWordRegister(this)
259                     .WithValueField(0, 8, out BMPU_FaultStatus, FieldMode.Read, name: "BMPUFSMASTERID")
260                     .WithReservedBits(8, 24)
261                 },
262                 {(long)Registers.BMPU_FaultStatusAddress, new DoubleWordRegister(this)
263                     .WithValueField(0, 32, out BMPU_FaultStatusAddress, FieldMode.Read, name: "BMPUFSMASTERID")
264                 },
265                 {(long)Registers.ESAU_RegionTypes0, new DoubleWordRegister(this)
266                     .WithReservedBits(0, 12)
267                     .WithFlag(12, out ESAU_Region3NonSecureType, name: "ESAUR3NS")
268                     .WithReservedBits(13, 19)
269                 },
270                 {(long)Registers.ESAU_RegionTypes1, new DoubleWordRegister(this)
271                     .WithReservedBits(0, 12)
272                     .WithFlag(12, out ESAU_Region11NonSecureType, name: "ESAUR11NS")
273                     .WithReservedBits(13, 19)
274                 },
275                 {(long)Registers.ESAU_MovableRegionBoundary0_1, new DoubleWordRegister(this, 0x02000000)
276                     .WithReservedBits(0, 12)
277                     .WithValueField(12, 16, out ESAU_MovableRegionBoundary0_1, name: "ESAUMRB01")
278                     .WithReservedBits(28, 4)
279                     .WithChangeCallback((_, __) => CheckMovableRegions())
280                 },
281                 {(long)Registers.ESAU_MovableRegionBoundary1_2, new DoubleWordRegister(this, 0x04000000)
282                     .WithReservedBits(0, 12)
283                     .WithValueField(12, 16, out ESAU_MovableRegionBoundary1_2, name: "ESAUMRB12")
284                     .WithReservedBits(28, 4)
285                     .WithChangeCallback((_, __) => CheckMovableRegions())
286                 },
287                 {(long)Registers.ESAU_MovableRegionBoundary4_5, new DoubleWordRegister(this, 0x02000000)
288                     .WithReservedBits(0, 12)
289                     .WithValueField(12, 16, out ESAU_MovableRegionBoundary4_5, name: "ESAUMRB45")
290                     .WithReservedBits(28, 4)
291                     .WithChangeCallback((_, __) => CheckMovableRegions())
292                 },
293                 {(long)Registers.ESAU_MovableRegionBoundary5_6, new DoubleWordRegister(this, 0x04000000)
294                     .WithReservedBits(0, 12)
295                     .WithValueField(12, 16, out ESAU_MovableRegionBoundary5_6, name: "ESAUMRB56")
296                     .WithReservedBits(28, 4)
297                     .WithChangeCallback((_, __) => CheckMovableRegions())
298                 },
299             };
300             return new DoubleWordRegisterCollection(this, registerDictionary);
301         }
302 
BuildNonSecureRegistersCollection()303         private DoubleWordRegisterCollection BuildNonSecureRegistersCollection()
304         {
305             var registerDictionary = new Dictionary<long, DoubleWordRegister>
306             {
307                 {(long)Registers.Status, new DoubleWordRegister(this)
308                     .WithFlag(0, out nonSecureLock, FieldMode.Read, name: "SMULOCK")
309                     .WithFlag(1, out nonSecureProgrammingError, FieldMode.Read, name: "SMUPRGERR")
310                     .WithReservedBits(2, 30)
311                 },
312                 {(long)Registers.Lock, new DoubleWordRegister(this)
313                     .WithValueField(0, 24, FieldMode.Write, writeCallback: (_, value) =>
314                     {
315                         nonSecureLock.Value = (value != UnlockKey);
316                     }, name: "SMULOCKKEY")
317                     .WithReservedBits(24, 8)
318                 },
319                 {(long)Registers.InterruptFlags, new DoubleWordRegister(this)
320                     .WithFlag(0, out PPUNS_PrivilegeInterrupt, name: "PPUNSPRIVIF")
321                     .WithReservedBits(1, 1)
322                     .WithFlag(2, out PPUNS_InstructionInterrupt, name: "PPUNSINSTIF")
323                     .WithReservedBits(3, 29)
324                     .WithChangeCallback((_, __) => UpdateInterrupts())
325                 },
326                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
327                     .WithFlag(0, out PPUNS_PrivilegeInterruptEnable, name: "PPUNSPRIVIEN")
328                     .WithReservedBits(1, 1)
329                     .WithFlag(2, out PPUNS_InstructionInterruptEnable, name: "PPUNSINSTIEN")
330                     .WithReservedBits(3, 29)
331                     .WithChangeCallback((_, __) => UpdateInterrupts())
332                 },
333                 {(long)Registers.PPU_PriviledgedAttribute0, new DoubleWordRegister(this, 0xFFFFFFFF)
334                     .For((r, i) => r.WithFlag(i, out nonSecurePrivilegedPeripheralAccess[i], name: $"PPUPATD{i}"), 0 , 32)
335                 },
336                 {(long)Registers.PPU_PriviledgedAttribute1, new DoubleWordRegister(this, 0xFFFFFFFF)
337                     .For((r, i) => r.WithFlag(i, out nonSecurePrivilegedPeripheralAccess[i + 32], name: $"PPUPATD{i}"), 0 , 32)
338                 },
339                 {(long)Registers.PPU_FaultStatus, new DoubleWordRegister(this)
340                     .WithValueField(0, 8, out PPU_NonSecureFaultStatus, FieldMode.Read, name: "PPUFSPERIPHID")
341                     .WithReservedBits(8, 24)
342                 },
343             };
344             return new DoubleWordRegisterCollection(this, registerDictionary);
345         }
346 
347         public long Size => 0x4000;
348         public GPIO SecureIRQ { get; }
349         public GPIO SecurePriviledgedIRQ { get; }
350         public GPIO NonSecurePriviledgedIRQ { get; }
351         private readonly Machine machine;
352         private readonly DoubleWordRegisterCollection secureRegistersCollection;
353         private readonly DoubleWordRegisterCollection nonSecureRegistersCollection;
354         private const uint SetRegisterOffset = 0x1000;
355         private const uint ClearRegisterOffset = 0x2000;
356         private const uint ToggleRegisterOffset = 0x3000;
357         private const uint Version = 1;
358         private const uint UnlockKey = 0xACCE55;
359         private const uint NumberOfPeripherals = 64;
360         private const uint NumberOfBusMasters = 5;
361 #region register fields
362         private readonly IFlagRegisterField[] privilegedPeripheralAccess;
363         private readonly IFlagRegisterField[] nonSecurePrivilegedPeripheralAccess;
364         private readonly IFlagRegisterField[] securePeripheralAccess;
365         private readonly IFlagRegisterField[] disablePeripheralAccess;
366         private readonly IFlagRegisterField[] privilegedBusMusterAccess;
367         private readonly IFlagRegisterField[] secureBusMusterAccess;
368         private IValueRegisterField ESAU_MovableRegionBoundary0_1;
369         private IValueRegisterField ESAU_MovableRegionBoundary1_2;
370         private IValueRegisterField ESAU_MovableRegionBoundary4_5;
371         private IValueRegisterField ESAU_MovableRegionBoundary5_6;
372         private IFlagRegisterField ESAU_Region3NonSecureType;
373         private IFlagRegisterField ESAU_Region11NonSecureType;
374         private IFlagRegisterField secureLock;
375         private IFlagRegisterField nonSecureLock;
376         private IFlagRegisterField secureProgrammingError;
377         private IFlagRegisterField nonSecureProgrammingError;
378         private IValueRegisterField PPU_FaultStatus;
379         private IValueRegisterField PPU_NonSecureFaultStatus;
380         private IValueRegisterField BMPU_FaultStatus;
381         private IValueRegisterField BMPU_FaultStatusAddress;
382         // TODO: SAU, MPUs, VTOR, VTAIRCR access must be filtered by SMU.
383         private IFlagRegisterField lockSAU;
384         private IFlagRegisterField lockNonSecureMPU;
385         private IFlagRegisterField lockSecureMPU;
386         private IFlagRegisterField lockNonSecureVTOR;
387         private IFlagRegisterField lockSecureVTAIRCR;
388         // Secure Interrupts
389         private IFlagRegisterField PPU_PrivilegeInterrupt;
390         private IFlagRegisterField PPU_InstructionInterrupt;
391         private IFlagRegisterField PPU_SecurityInterrupt;
392         private IFlagRegisterField BMPU_SecurityInterrupt;
393         private IFlagRegisterField PPU_PrivilegeInterruptEnable;
394         private IFlagRegisterField PPU_InstructionInterruptEnable;
395         private IFlagRegisterField PPU_SecurityInterruptEnable;
396         private IFlagRegisterField BMPU_SecurityInterruptEnable;
397         // Non-Secure Interrupts
398         private IFlagRegisterField PPUNS_PrivilegeInterrupt;
399         private IFlagRegisterField PPUNS_InstructionInterrupt;
400         private IFlagRegisterField PPUNS_PrivilegeInterruptEnable;
401         private IFlagRegisterField PPUNS_InstructionInterruptEnable;
402 #endregion
403 
404 #region methods
GetTime()405         private TimeInterval GetTime() => machine.LocalTimeSource.ElapsedVirtualTime;
406 
UpdateInterrupts()407         private void UpdateInterrupts()
408         {
409 
410             /*
411             The SMU contains three external interrupt lines, privileged, secure, and ns_privileged.
412             The privileged interrupt is asserted when the PPUINSTIF or the PPUPRIVIF is high and
413             the corresponding IEN bit is high.
414             The secure interrupt is asserted when the BMPUSECIF or the PPUSECIF is high and
415             the corresponding IEN bit is high.
416             The ns_privileged interrupt is asserted when the PPUNSPRIVIF or the PPUNSINSTIF is high and
417             the corresponding NSIEN bit is high.
418             */
419             machine.ClockSource.ExecuteInLock(delegate {
420                 var irq = ((BMPU_SecurityInterruptEnable.Value && BMPU_SecurityInterrupt.Value)
421                            || PPU_SecurityInterruptEnable.Value && PPU_SecurityInterrupt.Value);
422                 SecureIRQ.Set(irq);
423 
424                 irq = ((PPU_PrivilegeInterruptEnable.Value && PPU_PrivilegeInterrupt.Value)
425                        || (PPU_InstructionInterruptEnable.Value && PPU_InstructionInterrupt.Value));
426                 SecurePriviledgedIRQ.Set(irq);
427 
428                 irq = ((PPUNS_PrivilegeInterruptEnable.Value && PPUNS_PrivilegeInterrupt.Value)
429                        || (PPUNS_InstructionInterruptEnable.Value && PPUNS_InstructionInterrupt.Value));
430                 NonSecurePriviledgedIRQ.Set(irq);
431             });
432         }
433 
434         /*
435          ESAU Memory Regions
436           Region Num. |  Base Address       |   Limit Address      |  Security Attribute
437           ------------+---------------------+----------------------+----------------------
438              0        |  0x00000000         |   0x00000000|mrb01   |  Secure
439              1        |  0x00000000|mrb01   |   0x00000000|mrb12   |  Non-Secure-Callable
440              2        |  0x00000000|mrb12   |   0x0FE00000         |  Non-Secure
441              3        |  0x0FE00000         |   0x10000000         |  Secure or Non-Secure
442              4        |  0x20000000         |   0x20000000|mrb45   |  Secure
443              5        |  0x20000000|mrb45   |   0x20000000|mrb56   |  Non-Secure-Callable
444              6        |  0x20000000|mrb56   |   0x30000000         |  Non-Secure
445              7        |  0x40000000         |   0x50000000         |  Secure
446              8        |  0x50000000         |   0x60000000         |  Non-Secure
447              9        |  0xA0000000         |   0xB0000000         |  Secure
448              10       |  0xB0000000         |   0xC0000000         |  Non-Secure
449              11       |  0xE0044000         |   0xE00FE000         |  Secure or Non-Secure
450              12       |  0xE00FE000         |   0xE00FF000         |  Exempt
451         */
GetMemoryAddressSecurityType(uint address)452         private SecurityType GetMemoryAddressSecurityType(uint address)
453         {
454             // Region 0
455             if (address < (((uint)ESAU_MovableRegionBoundary0_1.Value) << 12))
456             {
457                 return SecurityType.Secure;
458             }
459             // Region 1
460             else if ((((uint)ESAU_MovableRegionBoundary0_1.Value) << 12) <= address
461                      && address < (((uint)ESAU_MovableRegionBoundary1_2.Value) << 12))
462             {
463                 return SecurityType.NonSecureCallable;
464             }
465             // Region 2
466             else if ((((uint)ESAU_MovableRegionBoundary1_2.Value) << 12) <= address
467                      && address < 0x0FE00000)
468             {
469                 return SecurityType.NonSecure;
470             }
471             // Region 3
472             else if (0x0FE00000 <= address && address < 0x10000000)
473             {
474                 return (ESAU_Region3NonSecureType.Value) ? SecurityType.NonSecure : SecurityType.Secure;
475             }
476             // Region 4
477             else if (0x20000000 <= address
478                      && address < (0x20000000 | (((uint)ESAU_MovableRegionBoundary4_5.Value) << 12)))
479             {
480                 return SecurityType.Secure;
481             }
482             // Region 5
483             else if ((0x20000000 | (((uint)ESAU_MovableRegionBoundary4_5.Value) << 12)) <= address
484                      && address < (0x20000000 | (((uint)ESAU_MovableRegionBoundary5_6.Value) << 12)))
485             {
486                 return SecurityType.NonSecureCallable;
487             }
488             // Region 6
489             else if ((0x20000000 | (((uint)ESAU_MovableRegionBoundary5_6.Value) << 12)) <= address
490                      && address < 0x30000000)
491             {
492                 return SecurityType.NonSecure;
493             }
494             // Region 7
495             else if (0x40000000 <= address && address < 0x50000000)
496             {
497                 return SecurityType.Secure;
498             }
499             // Region 8
500             else if (0x50000000 <= address && address < 0x60000000)
501             {
502                 return SecurityType.NonSecure;
503             }
504             // Region 9
505             else if (0xA0000000 <= address && address < 0xB0000000)
506             {
507                 return SecurityType.Secure;
508             }
509             // Region 10
510             else if (0xB0000000 <= address && address < 0xC0000000)
511             {
512                 return SecurityType.NonSecure;
513             }
514             // Region 11
515             else if (0xE0044000 <= address && address < 0xE00FE000)
516             {
517                 return (ESAU_Region11NonSecureType.Value) ? SecurityType.NonSecure : SecurityType.Secure;
518             }
519             // Region 12
520             else if (0xE00FE000 <= address && address < 0xE00FF000)
521             {
522                 return SecurityType.Exempt;
523             }
524 
525             this.Log(LogLevel.Error, "GetMemoryAddressSecurityType() invalid address");
526             return SecurityType.None;
527         }
528 
CheckMovableRegions()529         private void CheckMovableRegions()
530         {
531             if (ESAU_MovableRegionBoundary0_1.Value > ESAU_MovableRegionBoundary1_2.Value
532                 || ESAU_MovableRegionBoundary1_2.Value > 0x0FE00000
533                 || ESAU_MovableRegionBoundary4_5.Value > ESAU_MovableRegionBoundary5_6.Value
534                 || ((0x20000000 | (((uint)ESAU_MovableRegionBoundary5_6.Value) << 12))) >= 0x30000000)
535             {
536                 // TODO: do we need to fire an interrupt or trigger a fault?
537                 secureProgrammingError.Value = true;
538             }
539         }
540 #endregion
541 
542 #region enums
543         private enum SecurityType
544         {
545             None              = 0,
546             Secure            = 1,
547             NonSecure         = 2,
548             NonSecureCallable = 3,
549             Exempt            = 4,
550         }
551 
552         private enum PeripheralIndex
553         {
554             Scratchpad   = 0,
555             Emu          = 1,
556             Cmu          = 2,
557             Hfxo0        = 3,
558             Hfrco0       = 4,
559             Fsrco        = 5,
560             Dpll0        = 6,
561             Lfxo         = 7,
562             Lfrco        = 8,
563             Ulfrco       = 9,
564             Msc          = 10,
565             Icache0      = 11,
566             Prs          = 12,
567             Gpio         = 13,
568             Ldma         = 14,
569             LdmaXbar     = 15,
570             Timer0       = 16,
571             Timer1       = 17,
572             Timer2       = 18,
573             Timer3       = 19,
574             Timer4       = 20,
575             Usart0       = 21,
576             Usart1       = 22,
577             Burtc        = 23,
578             I2c1         = 24,
579             ChipTestCtrl = 25,
580             SyscfgCfgNs  = 26,
581             Syscfg       = 27,
582             Buram        = 28,
583             IfadcDebug   = 29,
584             Gpcrc        = 30,
585             Dci          = 31,
586             RootCfg      = 32,
587             Dcdc         = 33,
588             Pdm          = 34,
589             RfSense      = 35,
590             RadioAes     = 36,
591             Smu          = 37,
592             SmuCfgNs     = 38,
593             Rtcc         = 39,
594             LeTimer0     = 40,
595             Iadc0        = 41,
596             I2c0         = 42,
597             Wdog0        = 43,
598             Amuxcp0      = 44,
599             Euart0       = 45,
600             CryptoAcc    = 46,
601             AhbRadio     = 47,
602         }
603 
604         private enum BusMasterIndex
605         {
606             RadioAes        = 0,
607             CryptoAcc       = 1,
608             RadioSubSystem  = 2,
609             RadioFadcdDebug = 3,
610             Ldma            = 4,
611         }
612 
613         private enum Registers
614         {
615             IpVersion                                 = 0x0000,
616             Status                                    = 0x0004,
617             Lock                                      = 0x0008,
618             InterruptFlags                            = 0x000C,
619             InterruptEnable                           = 0x0010,
620             M33Control                                = 0x0020,
621             M33InitNsVector                           = 0x0024,
622             M33InitSVector                            = 0x0028,
623             PPU_PriviledgedAttribute0                 = 0x0040,
624             PPU_PriviledgedAttribute1                 = 0x0044,
625             PPU_SecureAttribute0                      = 0x0060,
626             PPU_SecureAttribute1                      = 0x0064,
627             PPU_Disable0                              = 0x0120,
628             PPU_Disable1                              = 0x0124,
629             PPU_FaultStatus                           = 0x0140,
630             BMPU_PriviledgedAttribute0                = 0x0150,
631             BMPU_SecureAttribute0                     = 0x0170,
632             BMPU_FaultStatus                          = 0x0250,
633             BMPU_FaultStatusAddress                   = 0x0254,
634             ESAU_RegionTypes0                         = 0x0260,
635             ESAU_RegionTypes1                         = 0x0264,
636             ESAU_MovableRegionBoundary0_1             = 0x0270,
637             ESAU_MovableRegionBoundary1_2             = 0x0274,
638             ESAU_MovableRegionBoundary4_5             = 0x0280,
639             ESAU_MovableRegionBoundary5_6             = 0x0284,
640             // Set registers
641             IpVersion_Set                             = 0x1000,
642             Status_Set                                = 0x1004,
643             Lock_Set                                  = 0x1008,
644             InterruptFlags_Set                        = 0x100C,
645             InterruptEnable_Set                       = 0x1010,
646             M33Control_Set                            = 0x1020,
647             M33InitNsVector_Set                       = 0x1024,
648             M33InitSVector_Set                        = 0x1028,
649             PPU_PriviledgedAttribute0_Set             = 0x1040,
650             PPU_PriviledgedAttribute1_Set             = 0x1044,
651             PPU_SecureAttribute0_Set                  = 0x1060,
652             PPU_SecureAttribute1_Set                  = 0x1064,
653             PPU_Disable0_Set                          = 0x1120,
654             PPU_Disable1_Set                          = 0x1124,
655             PPU_FaultStatus_Set                       = 0x1140,
656             BMPU_PriviledgedAttribute0_Set            = 0x1150,
657             BMPU_SecureAttribute0_Set                 = 0x1170,
658             BMPU_FaultStatus_Set                      = 0x1250,
659             BMPU_FaultStatusAddress_Set               = 0x1254,
660             ESAU_RegionTypes0_Set                     = 0x1260,
661             ESAU_RegionTypes1_Set                     = 0x1264,
662             ESAU_MovableRegionBoundary0_1_Set         = 0x1270,
663             ESAU_MovableRegionBoundary1_2_Set         = 0x1274,
664             ESAU_MovableRegionBoundary4_5_Set         = 0x1280,
665             ESAU_MovableRegionBoundary5_6_Set         = 0x1284,
666             // Clear registers
667             IpVersion_Clr                             = 0x2000,
668             Status_Clr                                = 0x2004,
669             Lock_Clr                                  = 0x2008,
670             InterruptFlags_Clr                        = 0x200C,
671             InterruptEnable_Clr                       = 0x2010,
672             M33Control_Clr                            = 0x2020,
673             M33InitNsVector_Clr                       = 0x2024,
674             M33InitSVector_Clr                        = 0x2028,
675             PPU_PriviledgedAttribute0_Clr             = 0x2040,
676             PPU_PriviledgedAttribute1_Clr             = 0x2044,
677             PPU_SecureAttribute0_Clr                  = 0x2060,
678             PPU_SecureAttribute1_Clr                  = 0x2064,
679             PPU_Disable0_Clr                          = 0x2120,
680             PPU_Disable1_Clr                          = 0x2124,
681             PPU_FaultStatus_Clr                       = 0x2140,
682             BMPU_PriviledgedAttribute0_Clr            = 0x2150,
683             BMPU_SecureAttribute0_Clr                 = 0x2170,
684             BMPU_FaultStatus_Clr                      = 0x2250,
685             BMPU_FaultStatusAddress_Clr               = 0x2254,
686             ESAU_RegionTypes0_Clr                     = 0x2260,
687             ESAU_RegionTypes1_Clr                     = 0x2264,
688             ESAU_MovableRegionBoundary0_1_Clr         = 0x2270,
689             ESAU_MovableRegionBoundary1_2_Clr         = 0x2274,
690             ESAU_MovableRegionBoundary4_5_Clr         = 0x2280,
691             ESAU_MovableRegionBoundary5_6_Clr         = 0x2284,
692             // Toggle registers
693             IpVersion_Tgl                             = 0x3000,
694             Status_Tgl                                = 0x3004,
695             Lock_Tgl                                  = 0x3008,
696             InterruptFlags_Tgl                        = 0x300C,
697             InterruptEnable_Tgl                       = 0x3010,
698             M33Control_Tgl                            = 0x3020,
699             M33InitNsVector_Tgl                       = 0x3024,
700             M33InitSVector_Tgl                        = 0x3028,
701             PPU_PriviledgedAttribute0_Tgl             = 0x3040,
702             PPU_PriviledgedAttribute1_Tgl             = 0x3044,
703             PPU_SecureAttribute0_Tgl                  = 0x3060,
704             PPU_SecureAttribute1_Tgl                  = 0x3064,
705             PPU_Disable0_Tgl                          = 0x3120,
706             PPU_Disable1_Tgl                          = 0x3124,
707             PPU_FaultStatus_Tgl                       = 0x3140,
708             BMPU_PriviledgedAttribute0_Tgl            = 0x3150,
709             BMPU_SecureAttribute0_Tgl                 = 0x3170,
710             BMPU_FaultStatus_Tgl                      = 0x3250,
711             BMPU_FaultStatusAddress_Tgl               = 0x3254,
712             ESAU_RegionTypes0_Tgl                     = 0x3260,
713             ESAU_RegionTypes1_Tgl                     = 0x3264,
714             ESAU_MovableRegionBoundary0_1_Tgl         = 0x3270,
715             ESAU_MovableRegionBoundary1_2_Tgl         = 0x3274,
716             ESAU_MovableRegionBoundary4_5_Tgl         = 0x3280,
717             ESAU_MovableRegionBoundary5_6_Tgl         = 0x3284,
718       }
719 #endregion
720     }
721 }