1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // Copyright (c) 2021 Google LLC 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.Collections.Generic; 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.Peripherals.IRQControllers.PLIC; 16 17 namespace Antmicro.Renode.Peripherals.IRQControllers 18 { 19 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)] 20 public class OpenTitan_PlatformLevelInterruptController : PlatformLevelInterruptControllerBase, IKnownSize 21 { OpenTitan_PlatformLevelInterruptController(int numberOfSources = 84, int numberOfContexts = 1)22 public OpenTitan_PlatformLevelInterruptController(int numberOfSources = 84, int numberOfContexts = 1) 23 // we set numberOfSources + 1, because ID 0 is reserved and represents no interrupt 24 : base(numberOfSources + 1, numberOfContexts, prioritiesEnabled: true, extraInterrupts: (uint)numberOfContexts) 25 { 26 // OpenTitan PLIC implementation contains an additional register per hart. 27 // Each of these memory mapped registers is intended to be connected to the MSIP bits 28 // within the MIP CSR registers of the individial harts. 29 // This allows interprocessor interrupts between harts. 30 31 FatalAlert = new GPIO(); 32 33 // OpenTitan PLIC implementation source is limited 34 if(numberOfSources + 1 > MaxNumberOfSources) 35 { 36 throw new ConstructionException($"Current {this.GetType().Name} implementation does not support more than {MaxNumberOfSources} sources"); 37 } 38 39 if(numberOfContexts > MaxNumberOfContexts) 40 { 41 throw new ConstructionException($"Current {this.GetType().Name} implementation does not support more than {MaxNumberOfContexts} contexts"); 42 } 43 44 this.numberOfContexts = numberOfContexts; 45 46 var registersMap = new Dictionary<long, DoubleWordRegister>(); 47 48 var interruptPendingRegisterCount = (int)Math.Ceiling((numberOfSources + 1) / 32.0); 49 for(var i = 0; i < interruptPendingRegisterCount; i++) 50 { 51 var interruptPendingOffset = (long)Registers.InterruptPending0 + i * 4; 52 this.Log(LogLevel.Noisy, "Creating InterruptPending{0}[0x{1:X}]", i, interruptPendingOffset); 53 registersMap.Add(interruptPendingOffset, new DoubleWordRegister(this) 54 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => 55 { 56 // TODO: Build register value from pending sources IRQs 57 return 0; 58 })); 59 } 60 61 for(uint i = 0; i <= numberOfSources; i++) 62 { 63 var j = i; 64 var sourcePriorityOffset = (uint)Registers.InterruptPriority0 + (4u * i); 65 this.Log(LogLevel.Noisy, "Creating SourcePriority{0}[0x{1:X}]", i, sourcePriorityOffset); 66 registersMap.Add(sourcePriorityOffset, new DoubleWordRegister(this) 67 .WithValueField(0, 3, 68 valueProviderCallback: _ => irqSources[j].Priority, 69 writeCallback: (_, value) => 70 { 71 irqSources[j].Priority = (uint)value; 72 RefreshInterrupts(); 73 }) 74 .WithReservedBits(3, 29)); 75 } 76 77 for(uint i = 0; i < numberOfContexts; i++) 78 { 79 var contextMachineEnablesOffset = (long)Registers.InterruptEnable0 + (i * ContextRegistersOffset); 80 this.Log(LogLevel.Noisy, $"ContextMachineEnablesOffset for Context{i} 0x{contextMachineEnablesOffset:X}"); 81 AddContextEnablesRegister(registersMap, contextMachineEnablesOffset, i, numberOfSources); 82 83 var contextPriorityThresholdOffset = (uint) Registers.Target0Threshold + (i * GeneralContextRegistersOffset); 84 AddContextPriorityThresholdRegister(registersMap, contextPriorityThresholdOffset, i); 85 86 var contextClaimCompleteOffset = contextPriorityThresholdOffset + 0x4; 87 AddContextClaimCompleteRegister(registersMap, contextClaimCompleteOffset, i); 88 89 var contextSoftwareOffset = (uint)Registers.Target0SoftwareInterrupt + (i * 0x4); 90 AddContextSoftwareInterruptRegister(registersMap, contextSoftwareOffset, i); 91 } 92 93 registers = new DoubleWordRegisterCollection(this, registersMap); 94 95 Registers.AlertTestRegister.Define(registers) 96 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") // FieldMode.Write 97 .WithIgnoredBits(1, 31); 98 } 99 100 public long Size => 0x8000000; 101 102 public GPIO FatalAlert { get; } 103 IsIrqSourceAvailable(int number)104 protected override bool IsIrqSourceAvailable(int number) 105 { 106 // source with ID 0 is reserved and represents no interrupt 107 return number != 0 && base.IsIrqSourceAvailable(number); 108 } 109 AddContextSoftwareInterruptRegister(Dictionary<long, DoubleWordRegister> registersMap, long offset, uint hartId)110 protected void AddContextSoftwareInterruptRegister(Dictionary<long, DoubleWordRegister> registersMap, long offset, uint hartId) 111 { 112 this.Log(LogLevel.Noisy, "Adding Context {0} software interrupt register address 0x{1:X}", hartId, offset); 113 registersMap.Add(offset, new DoubleWordRegister(this) 114 .WithFlag(0, 115 valueProviderCallback: _ => 116 { 117 return Connections[Connections.Count - numberOfContexts + (int)hartId].IsSet; 118 }, 119 writeCallback: (_, value) => 120 { 121 this.Log(LogLevel.Noisy, "Setting software interrupt for Context {0} to {1}", hartId, value); 122 Connections[Connections.Count - numberOfContexts + (int)hartId].Set(value); 123 }) 124 .WithReservedBits(1, 31)); 125 } 126 127 private readonly int numberOfContexts; 128 129 private const int MaxNumberOfSources = 255; 130 131 private const int MaxNumberOfContexts = ((int)Registers.InterruptEnable0 - (int)Registers.InterruptPending0) / ContextRegistersOffset; 132 133 private const int ContextRegistersOffset = 0x100; 134 135 private const int GeneralContextRegistersOffset = 0x1000; 136 137 #pragma warning disable format 138 private enum Registers : long 139 { 140 InterruptPriority0 = 0x0, 141 InterruptPending0 = 0x1000, 142 InterruptEnable0 = 0x2000, 143 Target0Threshold = 0x200000, 144 Target0InterruptClaim = 0x200004, 145 Target0SoftwareInterrupt = 0x4000000, 146 AlertTestRegister = 0x4004000, 147 } 148 #pragma warning restore format 149 } 150 } 151