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 8 using System.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Peripherals.CPU; 11 using Antmicro.Renode.Logging; 12 13 namespace Antmicro.Renode.Peripherals.IRQControllers.PLIC 14 { 15 public class IrqContext 16 { IrqContext(uint id, IPlatformLevelInterruptController irqController)17 public IrqContext(uint id, IPlatformLevelInterruptController irqController) 18 { 19 this.irqController = irqController; 20 this.id = id; 21 22 enabledSources = new HashSet<IrqSource>(); 23 pendingSources = new HashSet<IrqSource>(); 24 activeInterrupts = new Stack<IrqSource>(); 25 } 26 ToString()27 public override string ToString() 28 { 29 return $"[Context #{id}]"; 30 } 31 Reset()32 public void Reset() 33 { 34 activeInterrupts.Clear(); 35 enabledSources.Clear(); 36 37 RefreshInterrupt(); 38 } 39 RefreshInterrupt()40 public void RefreshInterrupt() 41 { 42 var forcedContext = irqController.ForcedContext; 43 if(forcedContext != -1 && this.id != forcedContext) 44 { 45 irqController.Connections[(int)this.id].Set(false); 46 return; 47 } 48 49 var currentPriority = activeInterrupts.Count > 0 ? activeInterrupts.Peek().Priority : 0; 50 var isPending = pendingSources.Any(x => x.Priority > currentPriority); 51 irqController.Connections[(int)this.id].Set(isPending); 52 } 53 CompleteHandlingInterrupt(IrqSource irq)54 public void CompleteHandlingInterrupt(IrqSource irq) 55 { 56 irqController.Log(LogLevel.Noisy, "Completing irq {0} at {1}", irq.Id, this); 57 58 if(activeInterrupts.Count == 0) 59 { 60 irqController.Log(LogLevel.Error, "Trying to complete irq {0} @ {1}, there are no active interrupts left", irq.Id, this); 61 return; 62 } 63 var topActiveInterrupt = activeInterrupts.Pop(); 64 if(topActiveInterrupt != irq) 65 { 66 irqController.Log(LogLevel.Error, "Trying to complete irq {0} @ {1}, but {2} is the active one", irq.Id, this, topActiveInterrupt.Id); 67 return; 68 } 69 70 if(irq.State) 71 { 72 MarkSourceAsPending(irq); 73 } 74 else 75 { 76 RemovePendingStatusFromSource(irq); 77 } 78 RefreshInterrupt(); 79 } 80 EnableSource(IrqSource s, bool enabled)81 public void EnableSource(IrqSource s, bool enabled) 82 { 83 if(enabled) 84 { 85 enabledSources.Add(s); 86 if(s.State) 87 { 88 MarkSourceAsPending(s); 89 } 90 } 91 else 92 { 93 enabledSources.Remove(s); 94 RemovePendingStatusFromSource(s); 95 } 96 irqController.Log(LogLevel.Noisy, "{0} source #{1} @ {2}", enabled ? "Enabling" : "Disabling", s.Id, this); 97 RefreshInterrupt(); 98 } 99 MarkSourceAsPending(IrqSource s)100 public void MarkSourceAsPending(IrqSource s) 101 { 102 if(enabledSources.Contains(s)) 103 { 104 if(pendingSources.Add(s)) 105 { 106 irqController.Log(LogLevel.Noisy, "Setting pending status to True for source #{0}", s.Id); 107 } 108 } 109 } 110 AcknowledgePendingInterrupt()111 public uint AcknowledgePendingInterrupt() 112 { 113 IrqSource pendingIrq; 114 115 var forcedContext = irqController.ForcedContext; 116 if(forcedContext != -1 && this.id != forcedContext) 117 { 118 pendingIrq = null; 119 } 120 else 121 { 122 pendingIrq = pendingSources 123 .OrderByDescending(x => x.Priority) 124 .ThenBy(x => x.Id).FirstOrDefault(); 125 } 126 127 if(pendingIrq == null) 128 { 129 irqController.Log(LogLevel.Noisy, "There is no pending interrupt to acknowledge at the moment for {0}. Currently enabled sources: {1}", this, string.Join(", ", enabledSources.Select(x => x.ToString()))); 130 return 0; 131 } 132 RemovePendingStatusFromSource(pendingIrq); 133 activeInterrupts.Push(pendingIrq); 134 135 irqController.Log(LogLevel.Noisy, "Acknowledging pending interrupt #{0} @ {1}", pendingIrq.Id, this); 136 137 RefreshInterrupt(); 138 return pendingIrq.Id; 139 } 140 RemovePendingStatusFromSource(IrqSource s)141 private void RemovePendingStatusFromSource(IrqSource s) 142 { 143 if(pendingSources.Remove(s)) 144 { 145 irqController.Log(LogLevel.Noisy, "Setting pending status to False for source #{0}", s.Id); 146 } 147 } 148 149 private readonly uint id; 150 private readonly IPlatformLevelInterruptController irqController; 151 private readonly HashSet<IrqSource> enabledSources; 152 private readonly HashSet<IrqSource> pendingSources; 153 private readonly Stack<IrqSource> activeInterrupts; 154 } 155 } 156