1 //
2 // Copyright (c) 2010-2024 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.Collections.Generic;
8 using Antmicro.Renode.Core.Structure.Registers;
9 using Antmicro.Renode.Exceptions;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Peripherals.IRQControllers;
13 
14 namespace Antmicro.Renode.Peripherals.IRQControllers.ARM_GenericInterruptControllerModel
15 {
16     internal class Utils
17     {
18         internal static void AddRegistersAtOffset<T>(Dictionary<long, T> registersMap, long offset, IEnumerable<T> registers)
19         where T : PeripheralRegister
20         {
21             foreach(var register in registers)
22             {
23                 if(registersMap.ContainsKey(offset))
24                 {
25                     throw new ConstructionException($"The register map already contains register at 0x{offset:x} offset.");
26                 }
27                 registersMap[offset] = register;
28                 offset += BitHelper.CalculateBytesCount(register.RegisterWidth);
29             }
30         }
31 
TryWriteByteToDoubleWordCollection(DoubleWordRegisterCollection registers, long offset, uint value, ARM_GenericInterruptController gic)32         internal static bool TryWriteByteToDoubleWordCollection(DoubleWordRegisterCollection registers, long offset, uint value, ARM_GenericInterruptController gic)
33         {
34             AlignRegisterOffset(offset, DoubleWordRegister.DoubleWordWidth, out var alignedOffset, out var byteOffset);
35             var registerExists = registers.TryRead(alignedOffset, out var currentValue);
36             if(registerExists)
37             {
38                 BitHelper.UpdateWithShifted(ref currentValue, value, byteOffset * BitHelper.BitsPerByte, BitHelper.BitsPerByte);
39                 registerExists &= registers.TryWrite(alignedOffset, currentValue);
40             }
41             return registerExists;
42         }
43 
TryReadByteFromDoubleWordCollection(DoubleWordRegisterCollection registers, long offset, out byte value, ARM_GenericInterruptController gic)44         internal static bool TryReadByteFromDoubleWordCollection(DoubleWordRegisterCollection registers, long offset, out byte value, ARM_GenericInterruptController gic)
45         {
46             AlignRegisterOffset(offset, DoubleWordRegister.DoubleWordWidth, out var alignedOffset, out var byteOffset);
47             var registerExists = registers.TryRead(alignedOffset, out var registerValue);
48             value = (byte)(registerValue >> (byteOffset * BitHelper.BitsPerByte));
49             return registerExists;
50         }
51 
TryWriteDoubleWordToQuadWordCollection(QuadWordRegisterCollection registers, long offset, uint value, ARM_GenericInterruptController gic)52         internal static bool TryWriteDoubleWordToQuadWordCollection(QuadWordRegisterCollection registers, long offset, uint value, ARM_GenericInterruptController gic)
53         {
54             AlignRegisterOffset(offset, QuadWordRegister.QuadWordWidth, out var alignedOffset, out var byteOffset);
55             if(byteOffset % BitHelper.CalculateBytesCount(DoubleWordRegister.DoubleWordWidth) != 0)
56             {
57                 // Unaligned access is forbidden.
58                 gic.Log(LogLevel.Warning, "Unaligned register write");
59                 return false;
60             }
61             var registerExists = registers.TryRead(alignedOffset, out var currentValue);
62             if(registerExists)
63             {
64                 BitHelper.UpdateWithShifted(ref currentValue, value, byteOffset * BitHelper.BitsPerByte, BitHelper.BitsPerByte);
65                 registerExists &= registers.TryWrite(alignedOffset, currentValue);
66             }
67             return registerExists;
68         }
69 
TryReadDoubleWordFromQuadWordCollection(QuadWordRegisterCollection registers, long offset, out uint value, ARM_GenericInterruptController gic)70         internal static bool TryReadDoubleWordFromQuadWordCollection(QuadWordRegisterCollection registers, long offset, out uint value, ARM_GenericInterruptController gic)
71         {
72             AlignRegisterOffset(offset, QuadWordRegister.QuadWordWidth, out var alignedOffset, out var byteOffset);
73             if(byteOffset % BitHelper.CalculateBytesCount(DoubleWordRegister.DoubleWordWidth) != 0)
74             {
75                 // Unaligned access is forbidden.
76                 gic.Log(LogLevel.Warning, "Unaligned register read");
77                 value = 0;
78                 return false;
79             }
80             var registerExists = registers.TryRead(alignedOffset, out var registerValue);
81             value = (uint)(registerValue >> (byteOffset * BitHelper.BitsPerByte));
82             return registerExists;
83         }
84 
AlignRegisterOffset(long offset, int bitsPerRegister, out long alignedOffset, out int byteOffset)85         private static void AlignRegisterOffset(long offset, int bitsPerRegister, out long alignedOffset, out int byteOffset)
86         {
87             var bytesPerRegister = BitHelper.CalculateBytesCount(bitsPerRegister);
88             byteOffset = (int)(offset % bytesPerRegister);
89             alignedOffset = offset - byteOffset;
90         }
91     }
92 }
93