public Atmel91SystemTimer(Machine machine)
        {
            IRQ = new GPIO();

            PeriodIntervalTimer               = new LimitTimer(machine, 32768, int.MaxValue); // long.MaxValue couses crashes
            PeriodIntervalTimer.Value         = 0x00000000;
            PeriodIntervalTimer.AutoUpdate    = true;
            PeriodIntervalTimer.LimitReached += PeriodIntervalTimerAlarmHandler;

            WatchdogTimer               = new LimitTimer(machine, 32768, int.MaxValue);
            WatchdogTimer.Value         = 0x00020000;
            WatchdogTimer.AutoUpdate    = true;
            WatchdogTimer.Divider       = 128;
            WatchdogTimer.LimitReached += WatchdogTimerAlarmHandler;

            RealTimeTimer           = new AT91_InterruptibleTimer(machine, 32768, (ulong)BitHelper.Bits(20), Direction.Ascending);
            RealTimeTimer.Divider   = 0x00008000;
            RealTimeTimer.OnUpdate += () => {
                lock (localLock)
                {
                    if (RealtimeTimerIncrementInterruptMask)
                    {
                        RealTimeTimerIncrement = true;
                    }
                }
            };
        }
 //TODO: Stop timer on debug stop.
 //TODO: Use RCC to set restart cause.
 public STM32F4_IndependentWatchdog(Machine machine, long frequency) : base(machine)
 {
     watchdogTimer = new LimitTimer(machine.ClockSource, frequency, this, "STM32_IWDG", DefaultReloadValue, workMode: WorkMode.OneShot, enabled: false, eventEnabled: true);
     watchdogTimer.LimitReached += TimerLimitReachedCallback;
     DefineRegisters();
     Reset();
 }
Beispiel #3
0
        public PSE_Watchdog(Machine machine, long frequency) : base(machine)
        {
            internalTimer = new LimitTimer(machine.ClockSource, frequency, this, String.Empty, TimeDefault - MSVPDefault, workMode: WorkMode.OneShot, eventEnabled: true);
            internalTimer.LimitReached += TimerLimitReached;

            RefreshEnable = new GPIO();
            Trigger       = new GPIO();
        }
        public PSE_RTC(Machine machine) : base(machine)
        {
            WakeupIRQ = new GPIO();
            MatchIRQ = new GPIO();

            ticker = new LimitTimer(machine.ClockSource, 1, this, nameof(ticker), 1, Direction.Ascending, eventEnabled: true);
            ticker.LimitReached += HandleTick;
            ResetInnerTimer();
        }
Beispiel #5
0
        public MAX32650_RTC(Machine machine) : base(machine)
        {
            DefineRegisters();

            internalClock = new LimitTimer(machine.ClockSource, 0x1000, this, "rtc_tick", limit: 1, enabled: false, eventEnabled: true);
            internalClock.LimitReached += SubsecondTick;

            IRQ = new GPIO();
        }
 public AT91_InterruptibleTimer(Machine machine, long frequency, IPeripheral owner, string localName, ulong limit = ulong.MaxValue, Direction direction = Direction.Descending, bool enabled = false)
 {
     timer = new LimitTimer(machine.ClockSource, frequency, owner, localName, limit, direction, enabled);
     timer.LimitReached += () => { if (OnUpdate != null)
                                   {
                                       OnUpdate();
                                   }
     };
 }
 public AT91_InterruptibleTimer(Machine machine, long frequency, ulong limit = ulong.MaxValue, Direction direction = Direction.Descending, bool enabled = false)
 {
     timer = new LimitTimer(machine, frequency, limit, direction, enabled);
     timer.LimitReached += () => { if (OnUpdate != null)
                                   {
                                       OnUpdate();
                                   }
     };
 }
        public EFR32_Timer(Machine machine, long frequency, TimerWidth width) : base(machine)
        {
            IRQ              = new GPIO();
            this.width       = width;
            interruptManager = new InterruptManager <Interrupt>(this);

            innerTimer = new LimitTimer(machine.ClockSource, frequency, this, "timer", limit: (1UL << (int)width) - 1, direction: Direction.Ascending, eventEnabled: true, autoUpdate: true);
            innerTimer.LimitReached += LimitReached;
            DefineRegisters();
        }
Beispiel #9
0
 public void OnTimerLimitReached(LimitTimer timer)
 {
     if (timer == timer12 && interruptEnable12.Value)
     {
         interruptOccurred12.Value = true;
         Update();
     }
     else if (timer == timer34 && interruptEnable34.Value)
     {
         interruptOccurred34.Value = true;
         Update();
     }
 }
 public Murax_Timer(Machine machine, long frequency = 12000000) : base(machine)
 {
     for (var i = 0; i < NumberOfTimers; i++)
     {
         var j = i;
         innerTimers[j] = new LimitTimer(machine.ClockSource, frequency, this, ((Timer)j).ToString(), limit: ushort.MaxValue, eventEnabled: true, direction: Direction.Ascending, autoUpdate: true, workMode: WorkMode.OneShot);
         innerTimers[j].LimitReached += delegate
         {
             this.Log(LogLevel.Noisy, "{0}: limit reached", (Timer)j);
             interruptPending[j].Value = true;
             UpdateInterrupts();
         };
     }
 }
Beispiel #11
0
        public LiteX_Timer(Machine machine, long frequency) : base(machine)
        {
            innerTimer = new LimitTimer(machine.ClockSource, frequency, this, nameof(innerTimer), eventEnabled: true, autoUpdate: true);
            innerTimer.LimitReached += delegate
            {
                irqPending.Value = true;
                UpdateInterrupts();

                if (reloadValue == 0)
                {
                    innerTimer.Enabled = false;
                }
                innerTimer.Limit = reloadValue;
            };
        }
        public LiteX_Timer(Machine machine, long frequency) : base(machine)
        {
            innerTimer = new LimitTimer(machine.ClockSource, frequency, this, nameof(innerTimer), eventEnabled: true, autoUpdate: true);
            innerTimer.LimitReached += delegate
            {
                this.Log(LogLevel.Noisy, "Limit reached");
                irqPending.Value = true;
                UpdateInterrupts();

                if (reloadValue == 0)
                {
                    this.Log(LogLevel.Noisy, "No realod value - disabling the timer");
                    innerTimer.Enabled = false;
                }
                innerTimer.Limit = reloadValue;
            };
            DefineRegisters();
        }
Beispiel #13
0
        public TexasInstrumentsTimer(Machine machine)
        {
            IRQ12 = new GPIO();
            IRQ34 = new GPIO();

            timer12 = new LimitTimer(machine.ClockSource, 24000000, direction: Direction.Ascending, eventEnabled: true); // clocked from AUXCLK (default 24 MHz)
            timer34 = new LimitTimer(machine.ClockSource, 24000000, direction: Direction.Ascending, eventEnabled: true);
            timer12.LimitReached += () => OnTimerLimitReached(timer12);
            timer34.LimitReached += () => OnTimerLimitReached(timer34);

            timerControlRegister                   = new DoubleWordRegister(this);
            timerGlobalControlRegister             = new DoubleWordRegister(this, 3);
            timerInterruptControlAndStatusRegister = new DoubleWordRegister(this, 0x10001); // the driver expects interrupts to be enabled; inconsistent with timer user's guixde

            timerControlRegister.DefineEnumField <OperationMode>(6, 2, changeCallback: (oldValue, newValue) => OnEnableModeChanged(oldValue, newValue, timer12));
            timerControlRegister.DefineEnumField <OperationMode>(22, 2, changeCallback: (oldValue, newValue) => OnEnableModeChanged(oldValue, newValue, timer34));
            resetOnRead12 = timerControlRegister.DefineFlagField(10);
            resetOnRead34 = timerControlRegister.DefineFlagField(26);

            timerGlobalControlRegister.DefineFlagField(0, changeCallback: (oldValue, newValue) =>
            {
                if (!newValue)
                {
                    timer12.Reset();
                }
            });
            timerGlobalControlRegister.DefineFlagField(1, changeCallback: (oldValue, newValue) =>
            {
                if (!newValue)
                {
                    timer34.Reset();
                }
            });

            timerGlobalControlRegister.DefineEnumField <TimerMode>(2, 2, changeCallback: OnTimerModeChanged);

            timerGlobalControlRegister.DefineValueField(8, 4, changeCallback: (oldValue, newValue) => timer34.Divider = (int)newValue);
            interruptEnable12   = timerInterruptControlAndStatusRegister.DefineFlagField(0);
            interruptEnable34   = timerInterruptControlAndStatusRegister.DefineFlagField(16);
            interruptOccurred12 = timerInterruptControlAndStatusRegister.DefineFlagField(3);
            interruptOccurred34 = timerInterruptControlAndStatusRegister.DefineFlagField(19);

            Reset();
        }
        public MPFS_Timer(Machine machine, long frequency = 100000000)
        {
            Timer1IRQ = new GPIO();
            Timer2IRQ = new GPIO();

            timerInterruptEnable       = new IFlagRegisterField[NumberOfInternalTimers];
            rawInterruptStatus         = new IFlagRegisterField[NumberOfInternalTimers];
            backgroundLoadValue        = new ulong[NumberOfInternalTimers];
            backgroundLoadValueIsValid = new bool[NumberOfInternalTimers];

            timer = new LimitTimer[NumberOfInternalTimers]
            {
                new LimitTimer(machine.ClockSource, frequency, this, "0", uint.MaxValue, autoUpdate: true, eventEnabled: true),
                new LimitTimer(machine.ClockSource, frequency, this, "1", uint.MaxValue, autoUpdate: true, eventEnabled: true),
                new LimitTimer(machine.ClockSource, frequency, this, "2", autoUpdate: true, eventEnabled: true)
            };

            for (var i = 0; i < NumberOfInternalTimers; i++)
            {
                var j = i;
                timer[i].LimitReached += delegate
                {
                    rawInterruptStatus[j].Value = true;
                    lock (timer[j])
                    {
                        if (backgroundLoadValueIsValid[j])
                        {
                            backgroundLoadValueIsValid[j] = false;
                            timer[j].Limit = backgroundLoadValue[j];
                            // TODO: doesn't it reduce the tick count by one (I mean shouldn't we put the new value AFTER this tick is finished?)
                        }
                    }
                    UpdateInterrupt();
                };
            }

            var registersMap = new Dictionary <long, DoubleWordRegister>
            {
                // the rest of registers is generated using `GenerateRegistersForTimer` method calls located below

                { (long)Registers.Timer64ValueHigh, new DoubleWordRegister(this)
                  .WithValueField(0, 32, FieldMode.Read, name: "TIM64VALUEU", valueProviderCallback: _ => (uint)(timer[Timer.Timer64].Value >> 32)) },
        public EOSS3_SimplePeriodicTimer(Machine machine) : base(machine)
        {
            interruptTimestamps = new ushort[NumberOfInterrupts];
            FFEKickOff          = new GPIO();

            timerSoftware30Bit       = new LimitTimer(machine.ClockSource, 1000 /*count every 1ms*/, this, "Software Use Timer", limit: 0x3FFFFFFF, enabled: false, eventEnabled: false, direction: Time.Direction.Ascending);
            timerFFEKickOffUpCounter = new LimitTimer(machine.ClockSource, 1000 /*count every 1ms*/, this, "FFE Kick-Off", limit: 0x4 /* the minimal legal limit, as LimitTimer does not accept 0 */,
                                                      enabled: false, eventEnabled: true, direction: Time.Direction.Ascending);

            timerFFEKickOffUpCounter.LimitReached += delegate
            {
                if (sleepMode.Value)
                {
                    this.Log(LogLevel.Noisy, "FFE Kick-Off is masked");
                }
                else
                {
                    FFEKickOff.Blink();
                    this.Log(LogLevel.Noisy, "FFE Kick-Off!");
                }
            };
            DefineRegisters();
        }
 public InnerTimer(Machine machine, int frequency)
 {
     CoreTimer = new LimitTimer(machine.ClockSource, frequency, limit: InitialLimit, direction: Direction.Descending, eventEnabled: true);
 }
Beispiel #17
0
        private void OnEnableModeChanged(OperationMode oldValue, OperationMode newValue, LimitTimer timer)
        {
            switch (newValue)
            {
            case OperationMode.Disabled:
                timer.Enabled = false;
                break;

            case OperationMode.Continuous:
            case OperationMode.ContinuousReload:
                timer.Mode         = WorkMode.Periodic;
                timer.Enabled      = true;
                timer.EventEnabled = true;
                break;

            case OperationMode.Once:
                timer.Mode         = WorkMode.OneShot;
                timer.Enabled      = true;
                timer.EventEnabled = true;
                break;
            }
        }
Beispiel #18
0
        public STM32F4_RTC(Machine machine)
        {
            mainTimer = new TimerConfig(this);
            alarmA    = new AlarmConfig(this, mainTimer);
            alarmB    = new AlarmConfig(this, mainTimer);

            AlarmIRQ             = new GPIO();
            ticker               = new LimitTimer(machine.ClockSource, 1, this, nameof(ticker), 1, direction: Direction.Ascending, eventEnabled: true);
            ticker.LimitReached += UpdateState;
            ResetInnerTimers();

            IFlagRegisterField syncFlag = null;

            var registerMap = new Dictionary <long, DoubleWordRegister>
            {
                { (long)Registers.TimeRegister, new DoubleWordRegister(this)
                  .WithValueField(0, 4, name: "SU",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Second, Rank.Units, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Second, Rank.Units))
                  .WithValueField(4, 3, name: "ST",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Second, Rank.Tens, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Second, Rank.Tens))
                  .WithReservedBits(7, 1)
                  .WithValueField(8, 4, name: "MU",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Minute, Rank.Units, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Minute, Rank.Units))
                  .WithValueField(12, 3, name: "MT",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Minute, Rank.Tens, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Minute, Rank.Tens))
                  .WithReservedBits(15, 1)
                  .WithValueField(16, 4, name: "HU",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Hour, Rank.Units, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Hour, Rank.Units))
                  .WithValueField(20, 2, name: "HT",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Hour, Rank.Tens, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Hour, Rank.Tens))
                  .WithFlag(22, name: "PM",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfInInitMode(Registers.TimeRegister) && CheckIfUnlocked(Registers.TimeRegister))
                        {
                            mainTimer.PM = value;
                        }
                    },
                            valueProviderCallback: _ => mainTimer.PM)
                  .WithReservedBits(23, 9) },
                { (long)Registers.DateRegister, new DoubleWordRegister(this, 0x2101)
                  .WithValueField(0, 4, name: "DU",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Day, Rank.Units, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Day, Rank.Units))
                  .WithValueField(4, 2, name: "DT",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Day, Rank.Tens, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Day, Rank.Tens))
                  .WithReservedBits(6, 2)
                  .WithValueField(8, 4, name: "MU",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Month, Rank.Units, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Month, Rank.Units))
                  .WithValueField(12, 1, name: "MT",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Month, Rank.Tens, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Month, Rank.Tens))
                  .WithValueField(13, 3, name: "WDU",
                                  writeCallback: (_, value) =>
                    {
                        if (CheckIfInInitMode(Registers.DateRegister) && CheckIfUnlocked(Registers.DateRegister))
                        {
                            if (value == 0)
                            {
                                this.Log(LogLevel.Warning, "Writting value 0 to WeekDay register is forbidden");
                                return;
                            }
                            mainTimer.WeekDay = (DayOfTheWeek)value;
                        }
                    },
                                  valueProviderCallback: _ => (uint)mainTimer.WeekDay)
                  .WithValueField(16, 4, name: "YU",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Year, Rank.Units, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Year, Rank.Units))
                  .WithValueField(20, 4, name: "YT",
                                  writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Year, Rank.Tens, value),
                                  valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Year, Rank.Tens))
                  .WithReservedBits(24, 8) },
                { (long)Registers.ControlRegister, new DoubleWordRegister(this)
                  .WithTag("WUCKSEL", 0, 3)
                  .WithTag("TSEDGE", 3, 1)
                  .WithTag("REFCKON", 4, 1)
                  .WithTag("BYPSHAD", 5, 1)
                  .WithFlag(6, name: "FMT",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfUnlocked(Registers.ControlRegister))
                        {
                            AMPMFormat = value;

                            mainTimer.ConfigureAMPM();
                            alarmA.ConfigureAMPM();
                            alarmB.ConfigureAMPM();
                        }
                    },
                            valueProviderCallback: _ => AMPMFormat)
                  .WithTag("DCE", 7, 1)
                  .WithFlag(8, name: "ALRAE",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfUnlocked(Registers.ControlRegister))
                        {
                            alarmA.Enable = value;
                        }
                    },
                            valueProviderCallback: _ => alarmA.Enable)
                  .WithFlag(9, name: "ALRBE",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfUnlocked(Registers.ControlRegister))
                        {
                            alarmB.Enable = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.Enable)
                  .WithTag("WUTE", 10, 1)  // Wakeup Timer not supported
                  .WithTag("TSE", 11, 1)   // Timestamp not supported
                  .WithFlag(12, name: "ALRAIE",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfUnlocked(Registers.ControlRegister))
                        {
                            alarmA.InterruptEnable = value;
                        }
                    },
                            valueProviderCallback: _ => alarmA.InterruptEnable)
                  .WithFlag(13, name: "ALRBIE",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfUnlocked(Registers.ControlRegister) && value)
                        {
                            alarmB.InterruptEnable = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.InterruptEnable)
                  .WithTag("WUTIE", 14, 1)  // Wakeup Timer not supported
                  .WithTag("TSIE", 15, 1)   // Timestamp not supported
                  .WithTag("ADD1H", 16, 1)
                  .WithTag("SUB1H", 17, 1)
                  .WithTag("BKP", 18, 1)
                  .WithTag("COSEL", 19, 1)
                  .WithTag("POL", 20, 1)
                  .WithTag("OSEL", 21, 2)
                  .WithTag("COE", 23, 1)
                  .WithReservedBits(24, 8) },
                { (long)Registers.ISR, new DoubleWordRegister(this, 0x7)
                  .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => !alarmA.Enable, name: "ALRAWF")
                  .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => !alarmB.Enable, name: "ALRBWF")
                  .WithTag("WUTWF", 2, 1)
                  .WithTag("SHPF", 3, 1)
                  .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => mainTimer.TimeState.Year != 2000, name: "INITS")
                  .WithFlag(5, out syncFlag, FieldMode.Read | FieldMode.WriteZeroToClear, name: "RSF",
                            readCallback: (_, curr) =>
                    {
                        // this strange logic is required by the Zephyr driver;
                        // it wants to read 0 before reading 1, otherwise it times-out
                        if (!curr)
                        {
                            syncFlag.Value = true;
                        }
                    })
                  .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => initMode, name: "INITF")
                  .WithFlag(7, FieldMode.Write, name: "INIT",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfUnlocked(Registers.ISR))
                        {
                            ticker.Enabled = !value;
                            initMode       = value;
                        }
                    })
                  .WithFlag(8, FieldMode.WriteZeroToClear | FieldMode.Read, name: "ALRAF",
                            changeCallback: (_, __) =>
                    {
                        alarmA.Flag = false;
                    },
                            valueProviderCallback: _ => alarmA.Flag)
                  .WithFlag(9, FieldMode.WriteZeroToClear | FieldMode.Read, name: "ALRBF",
                            changeCallback: (_, __) =>
                    {
                        alarmB.Flag = false;
                    },
                            valueProviderCallback: _ => alarmB.Flag)
                  .WithTag("WUTF", 10, 1)
                  .WithTag("TSF", 11, 1)
                  .WithTag("TSOVF", 12, 1)
                  .WithTag("TAMP1F", 13, 1)
                  .WithTag("TAMP2F", 14, 1)
                  .WithReservedBits(15, 1)
                  .WithTag("RECALPF", 16, 1)
                  .WithReservedBits(17, 15) },
                { (long)Registers.PrescalerRegister, new DoubleWordRegister(this)
                  .WithTag("PREDIV_S", 0, 15)
                  .WithReservedBits(15, 1)
                  .WithTag("PREDIV_A", 16, 7)
                  .WithReservedBits(23, 9) },
                { (long)Registers.WakeupTimerRegister, new DoubleWordRegister(this, 0x7F00FF)
                  .WithTag("WUT", 0, 16)
                  .WithReservedBits(16, 16) },
                { (long)Registers.CalibrationRegister, new DoubleWordRegister(this)
                  .WithTag("DC", 0, 5)
                  .WithReservedBits(5, 2)
                  .WithTag("DCS", 7, 1)
                  .WithReservedBits(8, 24) },
                { (long)Registers.AlarmARegister, new DoubleWordRegister(this)
                  .WithValueField(0, 4, name: "SU",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Second, Rank.Units, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Second, Rank.Units))
                  .WithValueField(4, 3, name: "ST",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Second, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Second, Rank.Tens))
                  .WithFlag(7, name: "MSK1",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister))
                        {
                            alarmA.SecondsMask = value;
                        }
                    },
                            valueProviderCallback: _ => alarmA.SecondsMask)
                  .WithValueField(8, 4, name: "MU",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Minute, Rank.Units, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Minute, Rank.Units))
                  .WithValueField(12, 3, name: "MT",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Minute, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Minute, Rank.Tens))
                  .WithFlag(15, name: "MSK2",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister))
                        {
                            alarmA.MinutesMask = value;
                        }
                    }, valueProviderCallback: _ => alarmA.MinutesMask)
                  .WithValueField(16, 4, name: "HU",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Hour, Rank.Units, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Hour, Rank.Units))
                  .WithValueField(20, 2, name: "HT",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Hour, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Hour, Rank.Tens))
                  .WithFlag(22, name: "PM",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister))
                        {
                            alarmA.PM = value;
                        }
                    },
                            valueProviderCallback: _ => alarmA.PM)
                  .WithFlag(23, name: "MSK3",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister))
                        {
                            alarmA.HoursMask = value;
                        }
                    }, valueProviderCallback: _ => alarmA.HoursMask)
                  .WithValueField(24, 4, name: "DU",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Day, Rank.Units, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Day, Rank.Units))
                  .WithValueField(28, 2, name: "DT",
                                  writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Day, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Day, Rank.Tens))
                  .WithTag("WDSEL", 30, 1)   // Weekday instead of date units usupported
                  .WithFlag(31, name: "MSK4",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister))
                        {
                            alarmA.DaysMask = value;
                        }
                    },
                            valueProviderCallback: _ => alarmA.DaysMask) },
                { (long)Registers.AlarmBRegister, new DoubleWordRegister(this)
                  .WithValueField(0, 4, name: "SU",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Second, Rank.Units, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Second, Rank.Units))
                  .WithValueField(4, 3, name: "ST",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Second, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Second, Rank.Tens))
                  .WithFlag(7, name: "MSK1",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister))
                        {
                            alarmB.SecondsMask = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.SecondsMask)
                  .WithValueField(8, 4, name: "MU",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Minute, Rank.Units, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Minute, Rank.Units))
                  .WithValueField(12, 3, name: "MT",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Minute, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Minute, Rank.Tens))
                  .WithFlag(15, name: "MSK2",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister))
                        {
                            alarmB.MinutesMask = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.MinutesMask)
                  .WithValueField(16, 4, name: "HU",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Hour, Rank.Units, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Hour, Rank.Units))
                  .WithValueField(20, 2, name: "HT",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Hour, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Hour, Rank.Tens))
                  .WithFlag(22, name: "PM",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister))
                        {
                            alarmB.PM = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.PM)
                  .WithFlag(23, name: "MSK3",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister))
                        {
                            alarmB.HoursMask = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.HoursMask)
                  .WithValueField(24, 4, name: "DU",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Day, Rank.Units, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Day, Rank.Units))
                  .WithValueField(28, 2, name: "DT",
                                  writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Day, Rank.Tens, value),
                                  valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Day, Rank.Tens))
                  .WithTag("WDSEL", 30, 1)   // Weekday instead of date units usupported
                  .WithFlag(31, name: "MSK4",
                            writeCallback: (_, value) =>
                    {
                        if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister))
                        {
                            alarmB.DaysMask = value;
                        }
                    },
                            valueProviderCallback: _ => alarmB.DaysMask) },
                { (long)Registers.WriteProtectionRegister, new DoubleWordRegister(this)
                  .WithValueField(0, 8, name: "KEY",
                                  writeCallback: (_, value) =>
                    {
                        if (value == UnlockKey1 && !firstStageUnlocked)
                        {
                            firstStageUnlocked = true;
                        }
                        else if (value == UnlockKey2 && firstStageUnlocked)
                        {
                            registersUnlocked = true;
                        }
                        else
                        {
                            firstStageUnlocked = false;
                            registersUnlocked  = false;
                        }
                    },
                                  valueProviderCallback: _ => 0)
                  .WithReservedBits(8, 24) },
                { (long)Registers.SubSecondRegister, new DoubleWordRegister(this)
                  .WithTag("SS", 0, 16)
                  .WithReservedBits(16, 16) },
                { (long)Registers.ShiftControlRegister, new DoubleWordRegister(this)
                  .WithTag("SUBFS", 0, 15)
                  .WithReservedBits(15, 16)
                  .WithTag("ADD1S", 31, 1) },
                { (long)Registers.TimestampTimeRegister, new DoubleWordRegister(this)
                  .WithTag("Second", 0, 7)
                  .WithReservedBits(7, 1)
                  .WithTag("Minute", 8, 7)
                  .WithReservedBits(15, 1)
                  .WithTag("Hour", 16, 6)
                  .WithTag("PM", 22, 1)
                  .WithReservedBits(23, 9) },
                { (long)Registers.TimestampDateRegister, new DoubleWordRegister(this)
                  .WithTag("Day", 0, 6)
                  .WithReservedBits(6, 2)
                  .WithTag("Month", 8, 5)
                  .WithTag("WDU", 13, 3)
                  .WithReservedBits(16, 16) },
                { (long)Registers.TimestampSubSecondRegister, new DoubleWordRegister(this)
                  .WithTag("SS", 0, 16)
                  .WithReservedBits(16, 16) },
                { (long)Registers.ClockCalibrationRegister, new DoubleWordRegister(this)
                  .WithTag("CALM", 0, 9)
                  .WithReservedBits(9, 4)
                  .WithTag("CALW16", 13, 1)
                  .WithTag("CALW8", 14, 1)
                  .WithTag("CALP", 15, 1)
                  .WithReservedBits(16, 16) },
                { (long)Registers.TamperAndAlternateFunctionConfigurationRegister, new DoubleWordRegister(this)
                  .WithTag("TAMP1E", 0, 1)
                  .WithTag("TAMP1TRG", 1, 1)
                  .WithTag("TAMPIE", 2, 1)
                  .WithTag("TAMP2E", 3, 1)
                  .WithTag("TAMP2TRG", 4, 1)
                  .WithReservedBits(5, 2)
                  .WithTag("TAMPTS", 7, 1)
                  .WithTag("TAMPFREQ", 8, 3)
                  .WithTag("TAMPFLT", 11, 2)
                  .WithTag("TAMPPRCH", 13, 2)
                  .WithTag("TAMPPUDIS", 15, 1)
                  .WithTag("TAMP1INSEL", 16, 1)
                  .WithTag("TSINSEL", 17, 1)
                  .WithTag("ALARMOUTTYPE", 18, 1)
                  .WithReservedBits(19, 13) },
                { (long)Registers.AlarmASubSecondRegister, new DoubleWordRegister(this)
                  .WithTag("SS", 0, 15)
                  .WithReservedBits(15, 9)
                  .WithTag("MASKSS", 24, 4)
                  .WithReservedBits(28, 4) },
                { (long)Registers.AlarmBSubSecondRegister, new DoubleWordRegister(this)
                  .WithTag("SS", 0, 15)
                  .WithReservedBits(15, 9)
                  .WithTag("MASKSS", 24, 4)
                  .WithReservedBits(28, 4) },
            };

            registers = new DoubleWordRegisterCollection(this, registerMap);
        }
 public DA1468x_Watchdog(Machine machine, long frequency) : base(machine)
 {
     internalTimer = new LimitTimer(machine.ClockSource, frequency, this, "DA1468x_Watchdog", TimerLimit, direction: Direction.Descending, enabled: false, workMode: WorkMode.OneShot, eventEnabled: true);
     internalTimer.LimitReached += TimerLimitReached;
 }
        public STM32_Timer(Machine machine, long frequency, uint initialLimit) : base(machine.ClockSource, frequency, limit: initialLimit, direction: Direction.Ascending, enabled: false, autoUpdate: false)
        {
            IRQ = new GPIO();
            this.initialLimit = initialLimit;

            LimitReached += delegate
            {
                if (updateDisable.Value)
                {
                    return;
                }
                Limit = autoReloadValue;

                for (var i = 0; i < NumberOfCCChannels; ++i)
                {
                    ccTimers[i].Enabled = Enabled && ccTimers[i].EventEnabled;
                }

                if (updateInterruptEnable.Value && repetitionsLeft == 0)
                {
                    // 2 of central-aligned modes should raise IRQ only on overflow/underflow, hence it happens 2 times less often
                    var centerAlignedUnbalancedMode = (centerAlignedMode.Value == CenterAlignedMode.CenterAligned1) || (centerAlignedMode.Value == CenterAlignedMode.CenterAligned2);
                    this.Log(LogLevel.Noisy, "IRQ pending");
                    updateInterruptFlag = true;
                    repetitionsLeft     = (uint)(1 + repetitionCounter.Value * (centerAlignedUnbalancedMode ? 2 : 1));
                    UpdateInterrupts();
                }

                if (repetitionsLeft > 0)
                {
                    repetitionsLeft--;
                }
            };

            for (var i = 0; i < NumberOfCCChannels; ++i)
            {
                var j = i;
                ccTimers[j] = new LimitTimer(machine.ClockSource, frequency, this, String.Format("cctimer{0}", j + 1), limit: initialLimit, eventEnabled: true, direction: Direction.Ascending, enabled: false, autoUpdate: false);
                ccTimers[j].LimitReached += delegate
                {
                    ccTimers[j].Enabled = false;
                    ccInterruptFlag[j]  = true;
                    this.Log(LogLevel.Noisy, "cctimer{0}: Compare IRQ pending", j + 1);
                    UpdateInterrupts();
                };
            }

            var registersMap = new Dictionary <long, DoubleWordRegister>
            {
                { (long)Registers.Control1, new DoubleWordRegister(this)
                  .WithFlag(0, writeCallback: (_, val) => Enabled = val, valueProviderCallback: _ => Enabled, name: "Counter enable (CEN)")
                  .WithFlag(1, out updateDisable, name: "Update disable (UDIS)")
                  .WithFlag(2, out updateRequestSource, name: "Update request source (URS)")
                  .WithFlag(3, writeCallback: (_, val) => Mode      = val ? WorkMode.OneShot : WorkMode.Periodic, valueProviderCallback: _ => Mode == WorkMode.OneShot, name: "One-pulse mode (OPM)")
                  .WithFlag(4, writeCallback: (_, val) => Direction = val ? Direction.Descending : Direction.Ascending, valueProviderCallback: _ => Direction == Direction.Descending, name: "Direction (DIR)")
                  .WithEnumField(5, 2, out centerAlignedMode, name: "Center-aligned mode selection (CMS)")
                  .WithFlag(7, out autoReloadPreloadEnable, name: "Auto-reload preload enable (APRE)")
                  .WithTag("Clock Division (CKD)", 8, 2)
                  .WithReservedBits(10, 22)
                  .WithWriteCallback((_, __) => { UpdateCaptureCompareTimers(); UpdateInterrupts(); }) },

                { (long)Registers.Control2, new DoubleWordRegister(this)
                  .WithTaggedFlag("CCPC", 0)
                  .WithReservedBits(1, 1)
                  .WithTaggedFlag("CCUS", 2)
                  .WithTaggedFlag("CCDS", 3)
                  .WithTag("MMS", 4, 2)
                  .WithTaggedFlag("TI1S", 7)
                  .WithTaggedFlag("OIS1", 8)
                  .WithTaggedFlag("OIS1N", 9)
                  .WithTaggedFlag("OIS2", 10)
                  .WithTaggedFlag("OIS2N", 11)
                  .WithTaggedFlag("OIS3", 12)
                  .WithTaggedFlag("OIS3N", 13)
                  .WithTaggedFlag("OIS4", 14)
                  .WithReservedBits(15, 17) },

                { (long)Registers.SlaveModeControl, new DoubleWordRegister(this)
                  .WithTag("SMS", 0, 3)
                  .WithTaggedFlag("OCCS", 3)
                  .WithTag("TS", 4, 2)
                  .WithTaggedFlag("MSM", 7)
                  .WithTag("ETF", 8, 3)
                  .WithTag("ETPS", 12, 2)
                  .WithTaggedFlag("ECE", 14)
                  .WithTaggedFlag("ETP", 15)
                  .WithReservedBits(16, 16) },

                { (long)Registers.DmaOrInterruptEnable, new DoubleWordRegister(this)
                  .WithFlag(0, out updateInterruptEnable, name: "Update interrupt enable (UIE)")
                  .WithFlag(1, valueProviderCallback: _ => ccTimers[0].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(0, val), name: "Capture/Compare 1 interrupt enable (CC1IE)")
                  .WithFlag(2, valueProviderCallback: _ => ccTimers[1].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(1, val), name: "Capture/Compare 2 interrupt enable (CC2IE)")
                  .WithFlag(3, valueProviderCallback: _ => ccTimers[2].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(2, val), name: "Capture/Compare 3 interrupt enable (CC3IE)")
                  .WithFlag(4, valueProviderCallback: _ => ccTimers[3].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(3, val), name: "Capture/Compare 4 interrupt enable (CC4IE)")
                  .WithReservedBits(5, 1)
                  .WithTag("Trigger interrupt enable (TIE)", 6, 1)
                  .WithReservedBits(7, 1)
                  .WithTag("Update DMA request enable (UDE)", 8, 1)
                  .WithTag("Capture/Compare 1 DMA request enable (CC1DE)", 9, 1)
                  .WithTag("Capture/Compare 2 DMA request enable (CC2DE)", 10, 1)
                  .WithTag("Capture/Compare 3 DMA request enable (CC3DE)", 11, 1)
                  .WithTag("Capture/Compare 4 DMA request enable (CC4DE)", 12, 1)
                  .WithReservedBits(13, 1)
                  .WithTag("Trigger DMA request enable (TDE)", 14, 1)
                  .WithReservedBits(15, 17)
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },

                { (long)Registers.Status, new DoubleWordRegister(this)
                  .WithFlag(0, FieldMode.Read | FieldMode.WriteZeroToClear,
                            writeCallback: (_, val) =>
                    {
                        if (!val)
                        {
                            updateInterruptFlag = false;
                            this.Log(LogLevel.Noisy, "IRQ claimed");
                        }
                    },
                            valueProviderCallback: (_) =>
                    {
                        return(updateInterruptFlag);
                    },
                            name: "Update interrupt flag (UIF)")
                  .WithFlag(1, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(0, val), valueProviderCallback: _ => ccInterruptFlag[0], name: "Capture/Compare 1 interrupt flag (CC1IF)")
                  .WithFlag(2, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(1, val), valueProviderCallback: _ => ccInterruptFlag[1], name: "Capture/Compare 2 interrupt flag (CC2IF)")
                  .WithFlag(3, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(2, val), valueProviderCallback: _ => ccInterruptFlag[2], name: "Capture/Compare 3 interrupt flag (CC3IF)")
                  .WithFlag(4, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(3, val), valueProviderCallback: _ => ccInterruptFlag[3], name: "Capture/Compare 4 interrupt flag (CC4IF)")
                  // Reserved fields were changed to flags to prevent from very frequent logging
                  .WithFlag(5, name: "Reserved1")
                  // These write callbacks are here only to prevent from very frequent logging.
                  .WithValueField(6, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Trigger interrupt flag (TIE)")
                  .WithFlag(7, name: "Reserved2")
                  .WithFlag(8, name: "Reserved3")
                  .WithValueField(9, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 1 overcapture flag (CC1OF)")
                  .WithValueField(10, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 2 overcapture flag (CC2OF)")
                  .WithValueField(11, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 3 overcapture flag (CC3OF)")
                  .WithValueField(12, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 4 overcapture flag (CC4OF)")
                  .WithValueField(13, 19, name: "Reserved4")
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },

                { (long)Registers.EventGeneration, new DoubleWordRegister(this)
                  .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
                    {
                        if (updateDisable.Value)
                        {
                            return;
                        }
                        if (Direction == Direction.Ascending)
                        {
                            Value = 0;
                        }
                        else if (Direction == Direction.Descending)
                        {
                            Value = autoReloadValue;
                        }

                        repetitionsLeft = repetitionCounter.Value;

                        if (!updateRequestSource.Value && updateInterruptEnable.Value)
                        {
                            this.Log(LogLevel.Noisy, "IRQ pending");
                            updateInterruptFlag = true;
                        }
                        for (var i = 0; i < NumberOfCCChannels; ++i)
                        {
                            if (ccTimers[i].Enabled)
                            {
                                ccTimers[i].Value = Value;
                            }
                        }
                    }, name: "Update generation (UG)")
                  .WithTag("Capture/compare 1 generation (CC1G)", 1, 1)
                  .WithTag("Capture/compare 2 generation (CC2G)", 2, 1)
                  .WithTag("Capture/compare 3 generation (CC3G)", 3, 1)
                  .WithTag("Capture/compare 4 generation (CC4G)", 4, 1)
                  .WithTaggedFlag("Capture/compare update generation (COMG)", 5)
                  .WithTag("Trigger generation (TG)", 6, 1)
                  .WithReservedBits(7, 25)
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },

                { (long)Registers.CaptureOrCompareMode1, new DoubleWordRegister(this)
                  .WithTag("CC1S", 0, 2)
                  .WithTaggedFlag("OC1FE", 2)
                  .WithTaggedFlag("OC1PE", 3)
                  .WithTag("OC1M", 4, 3)
                  .WithTaggedFlag("OC1CE", 7)
                  .WithTag("CC2S", 8, 2)
                  .WithTag("OC2M", 12, 3)
                  .WithReservedBits(15, 17) },

                { (long)Registers.CaptureOrCompareMode2, new DoubleWordRegister(this)
                  // Fields of this register vary between 'Output compare'/'Input compare' mode
                  // Only common fields were defined
                  .WithTag("CC3S", 0, 2)
                  //Output mode:
                  // "OC3FE", 2
                  // "OC3PE", 3
                  // "OC3M", 4, 3
                  // "OC3CE", 7
                  // Input mode:
                  // "IC3PSC", 2, 2
                  // "IC3F", 4, 4
                  .WithReservedBits(2, 6)
                  .WithTag("CC4S", 8, 2)
                  .WithReservedBits(10, 6)
                  //Output mode:
                  // "OC4FE", 2
                  // "OC4PE", 3
                  // "OC4M", 4, 3
                  // "OC4CE", 7
                  // Input mode:
                  // "IC4PSC", 2, 2
                  // "IC4F", 4, 4
                },

                { (long)Registers.CaptureOrCompareEnable, new DoubleWordRegister(this)
                  .WithTaggedFlag("CC1E", 0)
                  .WithTaggedFlag("CC1P", 1)
                  .WithTaggedFlag("CC1NE", 2)
                  .WithTaggedFlag("CC1NP", 3)
                  .WithTaggedFlag("CC2E", 4)
                  .WithTaggedFlag("CC2P", 5)
                  .WithTaggedFlag("CC2NE", 6)
                  .WithTaggedFlag("CC2NP", 7)
                  .WithTaggedFlag("CC3E", 8)
                  .WithTaggedFlag("CC3P", 9)
                  .WithTaggedFlag("CC3NE", 10)
                  .WithTaggedFlag("CC3NP", 11)
                  .WithTaggedFlag("CC4E", 12)
                  .WithTaggedFlag("CC4P", 13)
                  .WithReservedBits(14, 18) },

                { (long)Registers.Counter, new DoubleWordRegister(this)
                  .WithValueField(0, 32, writeCallback: (_, val) => Value = val, valueProviderCallback: _ => (uint)Value, name: "Counter value (CNT)")
                  .WithWriteCallback((_, val) =>
                    {
                        for (var i = 0; i < NumberOfCCChannels; ++i)
                        {
                            if (val < ccTimers[i].Limit)
                            {
                                ccTimers[i].Value = val;
                            }
                        }
                        UpdateInterrupts();
                    }) },

                { (long)Registers.Prescaler, new DoubleWordRegister(this)
                  .WithValueField(0, 32, writeCallback: (_, val) => Divider = (int)val + 1, valueProviderCallback: _ => (uint)Divider - 1, name: "Prescaler value (PSC)")
                  .WithWriteCallback((_, __) =>
                    {
                        for (var i = 0; i < NumberOfCCChannels; ++i)
                        {
                            ccTimers[i].Divider = Divider;
                        }
                        UpdateInterrupts();
                    }) },

                { (long)Registers.AutoReload, new DoubleWordRegister(this)
                  .WithValueField(0, 32, writeCallback: (_, val) =>
                    {
                        autoReloadValue = val;
                        if (!autoReloadPreloadEnable.Value)
                        {
                            Limit = autoReloadValue;
                        }
                    }, valueProviderCallback: _ => autoReloadValue, name: "Counter value (CNT)")
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },
                { (long)Registers.RepetitionCounter, new DoubleWordRegister(this)
                  .WithValueField(0, 8, out repetitionCounter, name: "Repetition counter (TIM1_RCR)")
                  .WithReservedBits(8, 24) },
                { (long)Registers.BreakAndDeadTime, new DoubleWordRegister(this)
                  .WithTag("Dead Time Generator (DTG)", 0, 8)
                  .WithTag("LOCK", 8, 2)
                  .WithTaggedFlag("Off-state selection idle mode (OSSI)", 10)
                  .WithTaggedFlag("Off-state selection run mode (OSSR)", 11)
                  .WithTaggedFlag("Break enable (BKE)", 12)
                  .WithTaggedFlag("Break polarity (BKP)", 13)
                  .WithTaggedFlag("Automatic output enable (AOE)", 14)
                  .WithTaggedFlag("Main Output Enable (MOE)", 15)
                  .WithReservedBits(16, 16) },
            };

            for (var i = 0; i < NumberOfCCChannels; ++i)
            {
                var j = i;
                registersMap.Add((long)Registers.CaptureOrCompare1 + (j * 0x4), new DoubleWordRegister(this)
                                 .WithValueField(0, 32, valueProviderCallback: _ => (uint)ccTimers[j].Limit, writeCallback: (_, val) => { ccTimers[j].Limit = val; }, name: String.Format("Capture/compare value {0} (CCR{0})", j + 1))
                                 .WithWriteCallback((_, __) => { UpdateCaptureCompareTimer(j); UpdateInterrupts(); })
                                 );
            }

            registers = new DoubleWordRegisterCollection(this, registersMap);
            Reset();

            EventEnabled = true;
        }
        public STM32_Timer(Machine machine, long frequency, uint initialLimit) : base(machine.ClockSource, frequency, limit: initialLimit, direction: Direction.Ascending, enabled: false, autoUpdate: false)
        {
            IRQ = new GPIO();
            this.initialLimit = initialLimit;

            LimitReached += delegate
            {
                if (updateDisable.Value)
                {
                    return;
                }
                if (updateInterruptEnable.Value)
                {
                    this.Log(LogLevel.Noisy, "IRQ pending");
                    updateInterruptFlag = true;
                }
                Limit = autoReloadValue;

                for (var i = 0; i < NumberOfCCChannels; ++i)
                {
                    ccTimers[i].Enabled = Enabled && ccTimers[i].EventEnabled;
                }
                UpdateInterrupts();
            };

            for (var i = 0; i < NumberOfCCChannels; ++i)
            {
                var j = i;
                ccTimers[j] = new LimitTimer(machine.ClockSource, frequency, this, String.Format("cctimer{0}", j + 1), limit: initialLimit, eventEnabled: true, direction: Direction.Ascending, enabled: false, autoUpdate: false);
                ccTimers[j].LimitReached += delegate
                {
                    ccTimers[j].Enabled = false;
                    ccInterruptFlag[j]  = true;
                    this.Log(LogLevel.Noisy, "cctimer{0}: Compare IRQ pending", j + 1);
                    UpdateInterrupts();
                };
            }

            var registersMap = new Dictionary <long, DoubleWordRegister>
            {
                { (long)Registers.Control1, new DoubleWordRegister(this)
                  .WithFlag(0, writeCallback: (_, val) => Enabled = val, valueProviderCallback: _ => Enabled, name: "Counter enable (CEN)")
                  .WithFlag(1, out updateDisable, name: "Update disable (UDIS)")
                  .WithFlag(2, out updateRequestSource, name: "Update request source (URS)")
                  .WithFlag(3, writeCallback: (_, val) => Mode      = val ? WorkMode.OneShot : WorkMode.Periodic, valueProviderCallback: _ => Mode == WorkMode.OneShot, name: "One-pulse mode (OPM)")
                  .WithFlag(4, writeCallback: (_, val) => Direction = val ? Direction.Descending : Direction.Ascending, valueProviderCallback: _ => Direction == Direction.Descending, name: "Direction (DIR)")
                  .WithTag("Center-aligned mode selection (CMS)", 5, 2)
                  .WithFlag(7, out autoReloadPreloadEnable, name: "Auto-reload preload enable (APRE)")
                  .WithTag("Clock Division (CKD)", 8, 2)
                  .WithReservedBits(10, 22)
                  .WithWriteCallback((_, __) => { UpdateCaptureCompareTimers(); UpdateInterrupts(); }) },

                { (long)Registers.DmaOrInterruptEnable, new DoubleWordRegister(this)
                  .WithFlag(0, out updateInterruptEnable, name: "Update interrupt enable (UIE)")
                  .WithFlag(1, valueProviderCallback: _ => ccTimers[0].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(0, val), name: "Capture/Compare 1 interrupt enable (CC1IE)")
                  .WithFlag(2, valueProviderCallback: _ => ccTimers[1].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(1, val), name: "Capture/Compare 2 interrupt enable (CC2IE)")
                  .WithFlag(3, valueProviderCallback: _ => ccTimers[2].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(2, val), name: "Capture/Compare 3 interrupt enable (CC3IE)")
                  .WithFlag(4, valueProviderCallback: _ => ccTimers[3].EventEnabled, writeCallback: (_, val) => WriteCaptureCompareInterruptEnable(3, val), name: "Capture/Compare 4 interrupt enable (CC4IE)")
                  .WithReservedBits(5, 1)
                  .WithTag("Trigger interrupt enable (TIE)", 6, 1)
                  .WithReservedBits(7, 1)
                  .WithTag("Update DMA request enable (UDE)", 8, 1)
                  .WithTag("Capture/Compare 1 DMA request enable (CC1DE)", 9, 1)
                  .WithTag("Capture/Compare 2 DMA request enable (CC2DE)", 10, 1)
                  .WithTag("Capture/Compare 3 DMA request enable (CC3DE)", 11, 1)
                  .WithTag("Capture/Compare 4 DMA request enable (CC4DE)", 12, 1)
                  .WithReservedBits(13, 1)
                  .WithTag("Trigger DMA request enable (TDE)", 14, 1)
                  .WithReservedBits(15, 17)
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },

                { (long)Registers.Status, new DoubleWordRegister(this)
                  .WithFlag(0, FieldMode.Read | FieldMode.WriteZeroToClear,
                            writeCallback: (_, val) =>
                    {
                        if (!val)
                        {
                            updateInterruptFlag = false;
                            this.Log(LogLevel.Noisy, "IRQ claimed");
                        }
                    },
                            valueProviderCallback: (_) =>
                    {
                        return(updateInterruptFlag);
                    },
                            name: "Update interrupt flag (UIF)")
                  .WithFlag(1, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(0, val), valueProviderCallback: _ => ccInterruptFlag[0], name: "Capture/Compare 1 interrupt flag (CC1IF)")
                  .WithFlag(2, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(1, val), valueProviderCallback: _ => ccInterruptFlag[1], name: "Capture/Compare 2 interrupt flag (CC2IF)")
                  .WithFlag(3, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(2, val), valueProviderCallback: _ => ccInterruptFlag[2], name: "Capture/Compare 3 interrupt flag (CC3IF)")
                  .WithFlag(4, FieldMode.Read | FieldMode.WriteZeroToClear, writeCallback: (_, val) => ClaimCaptureCompareInterrupt(3, val), valueProviderCallback: _ => ccInterruptFlag[3], name: "Capture/Compare 4 interrupt flag (CC4IF)")
                  .WithReservedBits(5, 1)
                  // These write callbacks are here only to prevent from very frequent logging.
                  .WithValueField(6, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Trigger interrupt flag (TIE)")
                  .WithReservedBits(7, 2)
                  .WithValueField(9, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 1 overcapture flag (CC1OF)")
                  .WithValueField(10, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 2 overcapture flag (CC2OF)")
                  .WithValueField(11, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 3 overcapture flag (CC3OF)")
                  .WithValueField(12, 1, FieldMode.WriteZeroToClear, writeCallback: (_, __) => {}, name: "Capture/Compare 4 overcapture flag (CC4OF)")
                  .WithReservedBits(13, 18)
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },

                { (long)Registers.EventGeneration, new DoubleWordRegister(this)
                  .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
                    {
                        if (updateDisable.Value)
                        {
                            return;
                        }
                        if (Direction == Direction.Ascending)
                        {
                            Value = 0;
                        }
                        else if (Direction == Direction.Descending)
                        {
                            Value = autoReloadValue;
                        }
                        if (!updateRequestSource.Value && updateInterruptEnable.Value)
                        {
                            this.Log(LogLevel.Noisy, "IRQ pending");
                            updateInterruptFlag = true;
                        }
                        for (var i = 0; i < NumberOfCCChannels; ++i)
                        {
                            if (ccTimers[i].Enabled)
                            {
                                ccTimers[i].Value = Value;
                            }
                        }
                    }, name: "Update generation (UG)")
                  .WithTag("Capture/compare 1 generation (CC1G)", 1, 1)
                  .WithTag("Capture/compare 2 generation (CC2G)", 2, 1)
                  .WithTag("Capture/compare 3 generation (CC3G)", 3, 1)
                  .WithTag("Capture/compare 4 generation (CC4G)", 4, 1)
                  .WithReservedBits(5, 1)
                  .WithTag("Trigger generation (TG)", 6, 1)
                  .WithReservedBits(7, 25)
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },

                { (long)Registers.Counter, new DoubleWordRegister(this)
                  .WithValueField(0, 32, writeCallback: (_, val) => Value = val, valueProviderCallback: _ => (uint)Value, name: "Counter value (CNT)")
                  .WithWriteCallback((_, val) =>
                    {
                        for (var i = 0; i < NumberOfCCChannels; ++i)
                        {
                            if (val < ccTimers[i].Limit)
                            {
                                ccTimers[i].Value = val;
                            }
                        }
                        UpdateInterrupts();
                    }) },

                { (long)Registers.Prescaler, new DoubleWordRegister(this)
                  .WithValueField(0, 32, writeCallback: (_, val) => Divider = (int)val + 1, valueProviderCallback: _ => (uint)Divider - 1, name: "Prescaler value (PSC)")
                  .WithWriteCallback((_, __) =>
                    {
                        for (var i = 0; i < NumberOfCCChannels; ++i)
                        {
                            ccTimers[i].Divider = Divider;
                        }
                        UpdateInterrupts();
                    }) },

                { (long)Registers.AutoReload, new DoubleWordRegister(this)
                  .WithValueField(0, 32, writeCallback: (_, val) =>
                    {
                        autoReloadValue = val;
                        if (!autoReloadPreloadEnable.Value)
                        {
                            Limit = autoReloadValue;
                        }
                    }, valueProviderCallback: _ => autoReloadValue, name: "Counter value (CNT)")
                  .WithWriteCallback((_, __) => UpdateInterrupts()) },
            };

            for (var i = 0; i < NumberOfCCChannels; ++i)
            {
                var j = i;
                registersMap.Add((long)Registers.CaptureOrCompare1 + (j * 0x4), new DoubleWordRegister(this)
                                 .WithValueField(0, 32, valueProviderCallback: _ => (uint)ccTimers[j].Limit, writeCallback: (_, val) => { ccTimers[j].Limit = val; }, name: String.Format("Capture/compare value {0} (CCR{0})", j + 1))
                                 .WithWriteCallback((_, __) => { UpdateCaptureCompareTimer(j); UpdateInterrupts(); })
                                 );
            }

            registers = new DoubleWordRegisterCollection(this, registersMap);
            Reset();

            EventEnabled = true;
        }
 public InnerTimer(Machine machine, int frequency, GaislerGPTimer parent)
 {
     CoreTimer = new LimitTimer(machine.ClockSource, frequency, parent, nameof(CoreTimer), InitialLimit, Direction.Descending, eventEnabled: true);
 }