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);
        }