public void EnableSource(IrqSource s, bool enabled) { if (enabled) { enabledSources.Add(s); } else { enabledSources.Remove(s); } RefreshInterrupt(); }
public void EnableSource(IrqSource s, bool enabled) { if (enabled) { enabledSources.Add(s); } else { enabledSources.Remove(s); } irqController.Log(LogLevel.Noisy, "{0} source #{1} @ {2}", enabled ? "Enabling" : "Disabling", s.Id, this); RefreshInterrupt(); }
public void CompleteHandlingInterrupt(IrqSource irq) { lock (irqController.irqSources) { irqController.Log(LogLevel.Noisy, "Completing irq {0} at target {1}", irq.Id, irqId); var topActiveInterrupt = activeInterrupts.Pop(); if (topActiveInterrupt != irq) { irqController.Log(LogLevel.Error, "Trying to complete irq {0} at target {1}, but {2} is the active one", irq.Id, irqId, topActiveInterrupt.Id); return; } irq.IsPending = irq.State; RefreshInterrupt(); } }
public void CompleteHandlingInterrupt(IrqSource irq) { irqController.Log(LogLevel.Noisy, "Completing irq {0} at {1}", irq.Id, this); if (activeInterrupts.Count == 0) { irqController.Log(LogLevel.Error, "Trying to complete irq {0} @ {1}, there are no active interrupts left", irq.Id, this); return; } var topActiveInterrupt = activeInterrupts.Pop(); if (topActiveInterrupt != irq) { irqController.Log(LogLevel.Error, "Trying to complete irq {0} @ {1}, but {2} is the active one", irq.Id, this, topActiveInterrupt.Id); return; } irq.IsPending = irq.State; RefreshInterrupt(); }
public PlatformLevelInterruptController(Machine machine, int numberOfSources, int numberOfTargets = 1, bool prioritiesEnabled = true) { // numberOfSources has to fit between these two registers, one bit per source if (Math.Ceiling((numberOfSources + 1) / 32.0) * 4 > Registers.Target1Enables - Registers.Target0Enables) { throw new ConstructionException($"Current {this.GetType().Name} implementation does not support more than {Registers.Target1Enables - Registers.Target0Enables} sources"); } this.prioritiesEnabled = prioritiesEnabled; this.machine = machine; var connections = new Dictionary <int, IGPIO>(); for (var i = 0; i < 4 * numberOfTargets; i++) { connections[i] = new GPIO(); } Connections = connections; // irqSources are initialized from 1, as the source "0" is not used. irqSources = new IrqSource[numberOfSources + 1]; for (var i = 1u; i <= numberOfSources; i++) { irqSources[i] = new IrqSource(i); } irqTargets = new IrqTarget[numberOfTargets]; for (var i = 0u; i < numberOfTargets; i++) { irqTargets[i] = new IrqTarget(i, this); } var registersMap = new Dictionary <long, DoubleWordRegister>(); registersMap.Add((long)Registers.Source0Priority, new DoubleWordRegister(this) .WithValueField(0, 3, FieldMode.Read, writeCallback: (_, value) => { if (value != 0) { this.Log(LogLevel.Warning, $"Trying to set priority {value} to Source 0, which is illegal"); } })); for (var i = 1; i <= numberOfSources; i++) { var j = i; registersMap[(long)Registers.Source1Priority * i] = new DoubleWordRegister(this) .WithValueField(0, 3, valueProviderCallback: (_) => irqSources[j].Priority, writeCallback: (_, value) => { if (prioritiesEnabled) { this.Log(LogLevel.Noisy, "Setting priority {0} for source #{1}", value, j); irqSources[j].Priority = value; RefreshInterrupts(); } }); } AddTargetEnablesRegister(registersMap, 0x2000, 0, PrivilegeLevel.Machine, numberOfSources); for (var i = 0u; i <= 3; i++) { AddTargetEnablesRegister(registersMap, 0x2080 + i * 0x100, i + 1, PrivilegeLevel.Machine, numberOfSources); AddTargetEnablesRegister(registersMap, 0x2100 + i * 0x100, i + 1, PrivilegeLevel.Supervisor, numberOfSources); } AddTargetClaimCompleteRegister(registersMap, 0x200004, 0, PrivilegeLevel.Machine); for (var i = 0u; i <= 3; i++) { AddTargetClaimCompleteRegister(registersMap, 0x201004 + i * 0x2000, i + 1, PrivilegeLevel.Machine); AddTargetClaimCompleteRegister(registersMap, 0x202004 + i * 0x2000, i + 1, PrivilegeLevel.Supervisor); } registers = new DoubleWordRegisterCollection(this, registersMap); }
public PlatformLevelInterruptController(Machine machine, int numberOfSources, int numberOfTargets = 1, bool prioritiesEnabled = true) { if (numberOfTargets != 1) { throw new ConstructionException($"Current {this.GetType().Name} implementation does not support more than one target"); } // numberOfSources has to fit between these two registers, one bit per source if (Math.Ceiling((numberOfSources + 1) / 32.0) * 4 > Registers.Target1Enables - Registers.Target0Enables) { throw new ConstructionException($"Current {this.GetType().Name} implementation more than {Registers.Target1Enables - Registers.Target0Enables} sources"); } this.prioritiesEnabled = prioritiesEnabled; this.machine = machine; IRQ = new GPIO(); // irqSources are initialized from 1, as the source "0" is not used. irqSources = new IrqSource[numberOfSources + 1]; for (var i = 1; i <= numberOfSources; i++) { irqSources[i] = new IrqSource(); } activeInterrupts = new Stack <uint>(); var registersMap = new Dictionary <long, DoubleWordRegister> { { (long)Registers.Target0ClaimComplete, new DoubleWordRegister(this).WithValueField(0, 32, valueProviderCallback: _ => { return(AcknowledgePendingInterrupt()); }, writeCallback: (_, value) => { CompleteHandlingInterrupt(value); } ) } }; registersMap.Add((long)Registers.Source0Priority, new DoubleWordRegister(this) .WithValueField(0, 3, FieldMode.Read, writeCallback: (_, value) => { if (value != 0) { this.Log(LogLevel.Warning, $"Trying to set priority {value} to Source 0, which is illegal"); } })); for (var i = 1; i <= numberOfSources; i++) { var j = i; registersMap[(long)Registers.Source1Priority * i] = new DoubleWordRegister(this) .WithValueField(0, 3, valueProviderCallback: (_) => irqSources[j].Priority, writeCallback: (_, value) => { if (prioritiesEnabled) { irqSources[j].Priority = value; } }); } var vectorWidth = (uint)Registers.Target1Enables - (uint)Registers.Target0Enables; var maximumSourceDoubleWords = (int)Math.Ceiling((numberOfSources + 1) / 32.0) * 4; // When writing to TargetXEnables registers, the user will get an error in log when he tries to write to an // unused bit of a register that is at least partially used. A warning will be issued on a usual undefined register access otherwise. for (var target = 0u; target < numberOfTargets; target++) { for (var offset = 0u; offset < maximumSourceDoubleWords; offset += 4) { var lTarget = target; var lOffset = offset; registersMap.Add((long)Registers.Target0Enables + (vectorWidth * target) + offset, new DoubleWordRegister(this).WithValueField(0, 32, writeCallback: (_, value) => { lock (irqSources) { // Each source is represented by one bit. offset and lOffset indicate the offset in double words from TargetXEnables, // `bit` is the bit number in the given double word, // and `sourceIdBase + bit` indicate the source number. var sourceIdBase = lOffset * 8; var bits = BitHelper.GetBits(value); for (var bit = 0u; bit < bits.Length; bit++) { if (sourceIdBase + bit == 0) { //Source number 0 is not used. continue; } if (irqSources.Length <= (sourceIdBase + bit)) { if (bits[bit]) { this.Log(LogLevel.Error, "Trying to enable non-existing source: {0}", sourceIdBase + bit); } continue; } var targets = irqSources[sourceIdBase + bit].EnabledTargets; if (bits[bit]) { targets.Add(lTarget); } else { targets.Remove(lTarget); } } RefreshInterrupts(); } })); } } registers = new DoubleWordRegisterCollection(this, registersMap); }
public BeagleV_PlatformLevelInterruptController(int numberOfSources, int numberOfContexts = 1, bool prioritiesEnabled = true) { if (numberOfSources + 1 > MaxSources) { throw new ConstructionException($"Current {this.GetType().Name} implementation does not support more than {MaxSources} sources"); } var connections = new Dictionary <int, IGPIO>(); for (var i = 0; i < numberOfContexts; i++) { connections[i] = new GPIO(); } Connections = connections; irqSources = new IrqSource[numberOfSources]; for (var i = 0u; i < numberOfSources; i++) { irqSources[i] = new IrqSource(i, this); } irqContexts = new IrqContext[numberOfContexts]; for (var i = 0u; i < irqContexts.Length; i++) { irqContexts[i] = new IrqContext(i, this); } var registersMap = new Dictionary <long, DoubleWordRegister>(); registersMap.Add((long)Registers.Source0Priority, new DoubleWordRegister(this) .WithValueField(0, 3, FieldMode.Read, writeCallback: (_, value) => { if (value != 0) { this.Log(LogLevel.Warning, $"Trying to set priority {value} for Source 0, which is illegal"); } })); for (var i = 1; i < numberOfSources; i++) { var j = i; registersMap[(long)Registers.Source1Priority * i] = new DoubleWordRegister(this) .WithValueField(0, 3, valueProviderCallback: (_) => irqSources[j].Priority, writeCallback: (_, value) => { if (prioritiesEnabled) { irqSources[j].Priority = value; RefreshInterrupts(); } }); } for (var i = 0u; i < numberOfContexts; i++) { AddContextEnablesRegister(registersMap, (long)Registers.Context0Enables + i * ContextEnablesWidth, i, numberOfSources); AddContextClaimCompleteRegister(registersMap, (long)Registers.Context0ClaimComplete + i * ContextClaimWidth, i); } registers = new DoubleWordRegisterCollection(this, registersMap); }