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 Antmicro.Renode.Core.Structure.Registers; 8 using Antmicro.Renode.Logging; 9 using Antmicro.Renode.Utilities; 10 11 namespace Antmicro.Renode.Peripherals.IRQControllers 12 { 13 public class STM32_EXTICore 14 { STM32_EXTICore(IPeripheral parent, ulong lineConfigurableMask, bool treatOutOfRangeLinesAsDirect = false, bool separateConfigs = false, bool allowMaskingDirectLines = true)15 public STM32_EXTICore(IPeripheral parent, ulong lineConfigurableMask, bool treatOutOfRangeLinesAsDirect = false, 16 bool separateConfigs = false, bool allowMaskingDirectLines = true) 17 { 18 this.parent = parent; 19 this.treatOutOfRangeLinesAsDirect = treatOutOfRangeLinesAsDirect; 20 this.allowMaskingDirectLines = allowMaskingDirectLines; 21 this.separateConfigs = separateConfigs; 22 LineConfigurableMask = lineConfigurableMask; 23 } 24 CanSetInterruptValue(byte lineNumber, bool value, out bool isLineConfigurable)25 public bool CanSetInterruptValue(byte lineNumber, bool value, out bool isLineConfigurable) 26 { 27 // Line out of range will never be reported as configurable 28 isLineConfigurable = IsLineConfigurable(lineNumber, out var isOutOfRange); 29 if(isOutOfRange) 30 { 31 return treatOutOfRangeLinesAsDirect; 32 } 33 34 // When using separeteConfigs the 'InterruptMask' is not used 35 if(!separateConfigs && !BitHelper.IsBitSet(InterruptMask.Value, lineNumber)) 36 { 37 if(isLineConfigurable || allowMaskingDirectLines) 38 { 39 return false; 40 } 41 } 42 43 if(isLineConfigurable) 44 { 45 var raisingEvent = (BitHelper.IsBitSet(RisingEdgeMask.Value, lineNumber) && value); 46 var fallingEvent = (BitHelper.IsBitSet(FallingEdgeMask.Value, lineNumber) && !value); 47 48 return raisingEvent || fallingEvent; 49 } 50 51 return true; 52 } 53 IsLineConfigurable(byte lineNumber, out bool isOutOfRange)54 public bool IsLineConfigurable(byte lineNumber, out bool isOutOfRange) 55 { 56 if(lineNumber >= MaxLineNumber) 57 { 58 if(!treatOutOfRangeLinesAsDirect) 59 { 60 parent.Log(LogLevel.Error, "Invalid line number: {0}. Accepted range is [0;{1})", lineNumber, MaxLineNumber); 61 } 62 isOutOfRange = true; 63 return false; 64 } 65 isOutOfRange = false; 66 return BitHelper.IsBitSet(LineConfigurableMask, lineNumber); 67 } 68 UpdatePendingValue(byte bit, bool value)69 public void UpdatePendingValue(byte bit, bool value) 70 { 71 IValueRegisterField registerField; 72 if(separateConfigs) 73 { 74 var isRaising = (value != true); 75 registerField = isRaising ? PendingRaisingInterrupts : PendingFallingInterrupts; 76 } 77 else 78 { 79 registerField = PendingInterrupts; 80 } 81 var reg = registerField.Value; 82 BitHelper.SetBit(ref reg, (byte)bit, value); 83 registerField.Value = reg; 84 } 85 86 // Those fields have to be public, as they should be used as out parameters 87 // You could use ref properties instead, but mono may generate bad IL for them 88 89 public IValueRegisterField InterruptMask; 90 public IValueRegisterField PendingInterrupts; 91 public IValueRegisterField RisingEdgeMask; 92 public IValueRegisterField FallingEdgeMask; 93 // Below fields are used only when the 'separateConfigs' is set 94 public IValueRegisterField PendingRaisingInterrupts; 95 public IValueRegisterField PendingFallingInterrupts; 96 97 public ulong LineConfigurableMask { get; } 98 99 private readonly IPeripheral parent; 100 101 private readonly bool treatOutOfRangeLinesAsDirect; 102 private readonly bool allowMaskingDirectLines; 103 private readonly bool separateConfigs; 104 105 // Max number is 64 due to using ulongs as backing values 106 private const byte MaxLineNumber = 64; 107 } 108 } 109