1 // 2 // Copyright (c) 2010-2024 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.Linq; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Peripherals.Bus; 11 using Antmicro.Renode.Time; 12 using Antmicro.Renode.Logging; 13 14 namespace Antmicro.Renode.Peripherals.Timers 15 { 16 public class S32K3XX_SystemTimerModule : LimitTimer, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 17 { S32K3XX_SystemTimerModule(IMachine machine, uint clockFrequency)18 public S32K3XX_SystemTimerModule(IMachine machine, uint clockFrequency) : base(machine.ClockSource, clockFrequency, uint.MaxValue) 19 { 20 IRQ = new GPIO(); 21 22 RegistersCollection = new DoubleWordRegisterCollection(this); 23 DefineRegisters(); 24 25 channelTimer = new LimitTimer[ChannelCount]; 26 for(var i = 0; i < ChannelCount; ++i) 27 { 28 var j = i; 29 channelTimer[i] = new LimitTimer(machine.ClockSource, clockFrequency, this, $"channel#{j}", workMode: WorkMode.OneShot); 30 channelTimer[i].LimitReached += UpdateInterrupts; 31 } 32 33 LimitReached += () => 34 { 35 for(var i = 0; i < ChannelCount; ++i) 36 { 37 channelTimer[i].Value = channelTimer[i].Limit; 38 channelTimer[i].Enabled = channelTimer[i].EventEnabled; 39 } 40 }; 41 } 42 ReadDoubleWord(long offset)43 public uint ReadDoubleWord(long offset) 44 { 45 return RegistersCollection.Read(offset); 46 } 47 WriteDoubleWord(long offset, uint value)48 public void WriteDoubleWord(long offset, uint value) 49 { 50 RegistersCollection.Write(offset, value); 51 } 52 Reset()53 public override void Reset() 54 { 55 base.Reset(); 56 RegistersCollection.Reset(); 57 58 for(var i = 0; i < ChannelCount; ++i) 59 { 60 channelTimer[i].Reset(); 61 } 62 } 63 64 public long Size => 0x4000; 65 public GPIO IRQ { get; } 66 public DoubleWordRegisterCollection RegistersCollection { get; } 67 UpdateInterrupts()68 private void UpdateInterrupts() 69 { 70 var interrupt = channelTimer.Any(timer => timer.RawInterrupt); 71 IRQ.Set(interrupt); 72 } 73 DefineRegisters()74 private void DefineRegisters() 75 { 76 Registers.Control.Define(this) 77 .WithFlag(0, name: "TimerEnable", 78 valueProviderCallback: _ => Enabled, 79 writeCallback: (_, value) => Enabled = value) 80 .WithTaggedFlag("Freeze", 1) 81 .WithReservedBits(2, 6) 82 .WithValueField(8, 8, name: "CounterPrescaler", 83 valueProviderCallback: _ => (uint)(Divider - 1), 84 writeCallback: (_, value) => 85 { 86 Divider = (int)value + 1; 87 for(var i = 0; i < ChannelCount; ++i) 88 { 89 channelTimer[i].Divider = Divider; 90 } 91 }) 92 .WithReservedBits(16, 16); 93 ; 94 95 Registers.Count.Define(this) 96 .WithValueField(0, 32, FieldMode.Read, name: "TimerCount", 97 valueProviderCallback: _ => Value) 98 ; 99 100 var channelSize = (uint)(Registers.ChannelControl1 - Registers.ChannelControl0); 101 Registers.ChannelControl0.DefineMany(this, ChannelCount, (register, index) => 102 { 103 register 104 .WithFlag(0, name: "ChannelEnable", 105 valueProviderCallback: _ => channelTimer[index].EventEnabled, 106 changeCallback: (_, value) => 107 { 108 channelTimer[index].EventEnabled = value; 109 if(!value) 110 { 111 return; 112 } 113 114 if(channelTimer[index].Limit > Value) 115 { 116 channelTimer[index].Value = Value; 117 channelTimer[index].Enabled = true; 118 } 119 else 120 { 121 this.Log(LogLevel.Debug, "Channel#{0} has been enabled, but it will be started after counter underflows."); 122 } 123 }) 124 .WithReservedBits(1, 31) 125 ; 126 }, stepInBytes: channelSize); 127 128 Registers.ChannelInterrupt0.DefineMany(this, ChannelCount, (register, index) => 129 { 130 register 131 .WithFlag(0, name: "ChannelInterruptFlag", 132 valueProviderCallback: _ => channelTimer[index].RawInterrupt, 133 writeCallback: (_, value) => 134 { 135 if(value) 136 { 137 channelTimer[index].ClearInterrupt(); 138 UpdateInterrupts(); 139 } 140 }) 141 .WithReservedBits(1, 31) 142 ; 143 }, stepInBytes: channelSize); 144 145 Registers.ChannelCompare0.DefineMany(this, ChannelCount, (register, index) => 146 { 147 register 148 .WithValueField(0, 32, name: "ChannelCompare", 149 valueProviderCallback: _ => channelTimer[index].Limit, 150 writeCallback: (_, value) => channelTimer[index].Limit = value) 151 ; 152 }, stepInBytes: channelSize); 153 } 154 155 private const uint ChannelCount = 4; 156 157 private readonly LimitTimer[] channelTimer; 158 159 private enum Registers 160 { 161 Control = 0x0, // CR 162 Count = 0x4, // CNT 163 ChannelControl0 = 0x10, // CCR0 164 ChannelInterrupt0 = 0x14, // CIR0 165 ChannelCompare0 = 0x18, // CMP0 166 ChannelControl1 = 0x20, // CCR1 167 ChannelInterrupt1 = 0x24, // CIR1 168 ChannelCompare1 = 0x28, // CMP1 169 ChannelControl2 = 0x30, // CCR2 170 ChannelInterrupt2 = 0x34, // CIR2 171 ChannelCompare2 = 0x38, // CMP2 172 ChannelControl3 = 0x40, // CCR3 173 ChannelInterrupt3 = 0x44, // CIR3 174 ChannelCompare3 = 0x48 // CMP3 175 } 176 } 177 } 178