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; 8 using System.Collections.Generic; 9 using System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Utilities; 16 using Antmicro.Renode.Peripherals.CPU; 17 using Antmicro.Renode.Peripherals.IRQControllers.PLIC; 18 19 namespace Antmicro.Renode.Peripherals.IRQControllers 20 { 21 [AllowedTranslations(AllowedTranslation.QuadWordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] 22 public class PlatformLevelInterruptController : PlatformLevelInterruptControllerBase, IKnownSize 23 { PlatformLevelInterruptController(int numberOfSources, int numberOfContexts, bool prioritiesEnabled = true)24 public PlatformLevelInterruptController(int numberOfSources, int numberOfContexts, bool prioritiesEnabled = true) 25 // we set numberOfSources + 1, because the standard PLIC controller counts sources from 1 26 : base(numberOfSources + 1, numberOfContexts, prioritiesEnabled) 27 { 28 if(numberOfSources + 1 > MaxSources) 29 { 30 throw new ConstructionException($"Current {this.GetType().Name} implementation does not support more than {MaxSources} sources"); 31 } 32 33 var registersMap = new Dictionary<long, DoubleWordRegister>(); 34 35 registersMap.Add((long)Registers.Source0Priority, new DoubleWordRegister(this) 36 .WithValueField(0, 3, FieldMode.Read, writeCallback: (_, value) => 37 { 38 if(value != 0) 39 { 40 this.Log(LogLevel.Warning, $"Trying to set priority {value} for Source 0, which is illegal"); 41 } 42 })); 43 for(var i = 1; i <= numberOfSources; i++) 44 { 45 var j = i; 46 registersMap[(long)Registers.Source1Priority * i] = new DoubleWordRegister(this) 47 .WithValueField(0, 3, 48 valueProviderCallback: (_) => irqSources[j].Priority, 49 writeCallback: (_, value) => 50 { 51 if(prioritiesEnabled) 52 { 53 irqSources[j].Priority = (uint)value; 54 RefreshInterrupts(); 55 } 56 }); 57 } 58 59 for(var i = 0u; i < numberOfContexts; i++) 60 { 61 AddContextEnablesRegister(registersMap, (long)Registers.Context0Enables + i * ContextEnablesWidth, i, numberOfSources); 62 AddContextClaimCompleteRegister(registersMap, (long)Registers.Context0ClaimComplete + i * ContextClaimWidth, i); 63 AddContextPriorityThresholdRegister(registersMap, (long)Registers.Context0PriorityThreshold + i * ContextClaimWidth, i); 64 } 65 66 registers = new DoubleWordRegisterCollection(this, registersMap); 67 } 68 69 public long Size => 0x4000000; 70 IsIrqSourceAvailable(int number)71 protected override bool IsIrqSourceAvailable(int number) 72 { 73 // the standard PLIC controller does not support source 0 74 return number != 0 && base.IsIrqSourceAvailable(number); 75 } 76 77 private enum Registers : long 78 { 79 Source0Priority = 0x0, //this is a fake register, as there is no source 0, but the software writes to it anyway. 80 Source1Priority = 0x4, 81 Source2Priority = 0x8, 82 // ... 83 StartOfPendingArray = 0x1000, 84 Context0Enables = 0x2000, 85 Context1Enables = 0x2080, 86 Context2Enables = 0x2100, 87 // ... 88 Context0PriorityThreshold = 0x200000, 89 Context0ClaimComplete = 0x200004, 90 // ... 91 Context1PriorityThreshold = 0x201000, 92 Context1ClaimComplete = 0x201004, 93 // ... 94 Context2PriorityThreshold = 0x202000, 95 Context2ClaimComplete = 0x202004, 96 // 97 Context3PriorityThreshold = 0x203000, 98 Context3ClaimComplete = 0x203004, 99 // 100 Context4PriorityThreshold = 0x204000, 101 Context4ClaimComplete = 0x204004, 102 // ... 103 } 104 105 private const long ContextEnablesWidth = Registers.Context1Enables - Registers.Context0Enables; 106 private const long ContextClaimWidth = Registers.Context1ClaimComplete - Registers.Context0ClaimComplete; 107 private const uint MaxSources = (uint)(ContextEnablesWidth / 4) * 32; 108 } 109 } 110