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