1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System.Collections.Generic;
8 using Antmicro.Renode.Peripherals.Bus;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public class NPCX_MTC : IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
17     {
NPCX_MTC(IMachine machine)18         public NPCX_MTC(IMachine machine)
19         {
20             IRQ = new GPIO();
21 
22             timer = new LimitTimer(machine.ClockSource, 1, this, "timer", 1, eventEnabled: true);
23             timer.LimitReached += () =>
24             {
25                 timerValue.Value++;
26                 if(BitHelper.GetValue(timerValue.Value, 0, PredefinedTimeBits) == predefinedTime.Value)
27                 {
28                     predefinedTimeOccurred.Value = true;
29                     UpdateInterrupt();
30                 }
31             };
32 
33             var registerMap = new Dictionary<long, DoubleWordRegister>
34             {
35                 {(long)Registers.TimingTicksCount, new DoubleWordRegister(this)
36                     .WithValueField(0, 32, out timerValue, name: "TTC (Timing Ticks Count)", softResettable: false)
37                 },
38                 {(long)Registers.WakeUpTicksCount, new DoubleWordRegister(this)
39                     .WithFlag(31, out interruptEnabled, name: "WIE (Wake-Up/Interrupt Enabled)")
40                     .WithFlag(30, out predefinedTimeOccurred, FieldMode.Read | FieldMode.WriteOneToClear)
41                     .WithReservedBits(25, 5)
42                     .WithValueField(0, 25, out predefinedTime, name: "PT (Predefined Time)")
43                     .WithWriteCallback((_, __) => UpdateInterrupt())
44                 },
45             };
46             RegistersCollection = new DoubleWordRegisterCollection(this, registerMap);
47 
48             Reset();
49         }
50 
Reset()51         public void Reset()
52         {
53             RegistersCollection.Reset();
54             timer.Enabled = true;
55             IRQ.Unset();
56         }
57 
ReadDoubleWord(long offset)58         public uint ReadDoubleWord(long offset)
59         {
60             return RegistersCollection.Read(offset);
61         }
62 
WriteDoubleWord(long offset, uint value)63         public void WriteDoubleWord(long offset, uint value)
64         {
65             RegistersCollection.Write(offset, value);
66         }
67 
68         public GPIO IRQ { get; }
69         public long Size => 0x08;
70         public DoubleWordRegisterCollection RegistersCollection { get; }
71 
UpdateInterrupt()72         private void UpdateInterrupt()
73         {
74             var irqState = interruptEnabled.Value && predefinedTimeOccurred.Value;
75             this.DebugLog("{0} interrupt", irqState ? "Setting" : "Unsetting");
76             IRQ.Set(irqState);
77         }
78 
79         private readonly LimitTimer timer;
80 
81         private readonly IValueRegisterField timerValue;
82         private readonly IValueRegisterField predefinedTime;
83         private readonly IFlagRegisterField predefinedTimeOccurred;
84         private readonly IFlagRegisterField interruptEnabled;
85 
86         private const int PredefinedTimeBits = 25;
87 
88         private enum Registers : long
89         {
90             TimingTicksCount = 0x00, // TTC
91             WakeUpTicksCount = 0x04, // WTC
92         }
93     }
94 }
95