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