1 // 2 // Copyright (c) 2010-2022 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.Time; 12 using Antmicro.Renode.Logging; 13 14 namespace Antmicro.Renode.Peripherals.Timers 15 { 16 public class IMX_GPTimer : BasicDoubleWordPeripheral, IKnownSize 17 { IMX_GPTimer(IMachine machine, int frequency = DefaultFrequency)18 public IMX_GPTimer(IMachine machine, int frequency = DefaultFrequency) : base(machine) 19 { 20 timers = new ComparingTimer[NumberOfCaptures]; 21 capturesPending = new IFlagRegisterField[NumberOfCaptures]; 22 capturesEnabled = new IFlagRegisterField[NumberOfCaptures]; 23 for(int i = 0; i < NumberOfCaptures; i++) 24 { 25 var j = i; 26 timers[j] = new ComparingTimer(machine.ClockSource, frequency, this, $"compare{j}", eventEnabled: true); 27 timers[j].CompareReached += () => 28 { 29 this.Log(LogLevel.Noisy, "Compare reached on Compare {0}. Compare Value {1}", j, timers[j].Compare); 30 capturesPending[j].Value = true; 31 UpdateInterrupts(); 32 }; 33 } 34 35 DefineRegisters(); 36 } 37 DefineRegisters()38 private void DefineRegisters() 39 { 40 Registers.Control.Define(this) 41 .WithFlag(0, name: "EN", writeCallback: (_, value) => 42 { 43 foreach(var timer in timers) 44 { 45 timer.Enabled = value; 46 } 47 } 48 ) 49 .WithTag("ENMOD", 1, 1) 50 .WithTag("DBGEN", 2, 1) 51 .WithTag("WAITEN", 3, 1) 52 .WithTag("DOZEEN", 4, 1) 53 .WithTag("STOPEN", 5, 1) 54 .WithTag("CLKSRC", 6, 3) 55 .WithFlag(9, out freeRunModeEnabled, name: "FRR") 56 .WithReservedBits(10, 5) 57 .WithFlag(15, writeCallback: (_, value) => 58 { 59 if(value) 60 { 61 Reset(); 62 } 63 }, name: "SWR") 64 .WithTag("IM1", 16, 2) 65 .WithTag("IM2", 18, 2) 66 .WithTag("OM1", 20, 3) 67 .WithTag("OM2", 23, 3) 68 .WithTag("OM3", 26, 3) 69 .WithTaggedFlag("FO1", 29) 70 .WithTaggedFlag("FO2", 30) 71 .WithTaggedFlag("FO3", 31) 72 ; 73 74 Registers.Prescaler.Define(this) 75 .WithTag("PRESCALER", 0, 12) 76 .WithReservedBits(12, 20) 77 ; 78 79 Registers.Status.Define(this) 80 .WithFlags(0, NumberOfCaptures, out capturesPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "OFn", 81 writeCallback: (_,__,___) => UpdateInterrupts()) 82 .WithFlag(3, FieldMode.Read | FieldMode.WriteOneToClear, name: "IF1") 83 .WithFlag(4, FieldMode.Read | FieldMode.WriteOneToClear, name: "IF2") 84 .WithFlag(5, FieldMode.Read | FieldMode.WriteOneToClear, name: "ROV") 85 .WithReservedBits(6, 26) 86 ; 87 88 Registers.Interrupt.Define(this) 89 .WithFlags(0, NumberOfCaptures, out capturesEnabled, name: "OFnIE", 90 writeCallback: (_,__,___) => UpdateInterrupts()) 91 .WithTaggedFlag("IF1IE", 3) 92 .WithTaggedFlag("IF2IE", 4) 93 .WithTaggedFlag("ROVIE", 5) 94 .WithReservedBits(6, 26) 95 ; 96 97 Registers.OutputCompare1.DefineMany(this, NumberOfCaptures, setup: (register, idx) => 98 { 99 register 100 .WithValueField(0, 32, name: $"COMP{idx+1}", writeCallback: (_, value) => 101 { 102 timers[idx].Compare = value; 103 // According to documentation, when timer is in Reset mode (FRR flag is set to 0), 104 // then counter value should be set to 0 after every write operation on output capture register 1 (i.e., idx == 0 in this model). 105 // We use separate timers for output channels, so it's necessary to reset all timers. 106 if(idx == 0 && freeRunModeEnabled.Value == false) 107 { 108 foreach(var timer in timers) 109 { 110 timer.Value = 0; 111 } 112 } 113 }, 114 valueProviderCallback: _ => (uint)timers[idx].Compare); 115 }); 116 117 Registers.InputCapture1.Define(this) 118 .WithTag("CAPT", 0, 32) 119 ; 120 121 Registers.InputCapture2.Define(this) 122 .WithTag("CAPT", 0, 32) 123 ; 124 125 Registers.Count.Define(this) 126 .WithValueField(0, 32, FieldMode.Read, name: "COUNT", valueProviderCallback: _ => (uint)timers[0].Value) 127 ; 128 } 129 Reset()130 public override void Reset() 131 { 132 base.Reset(); 133 UpdateInterrupts(); 134 } 135 136 public long Size => 0x1000; 137 UpdateInterrupts()138 public void UpdateInterrupts() 139 { 140 var status = false; 141 for(int i = 0; i < NumberOfCaptures; i++) 142 { 143 status |= capturesEnabled[i].Value && capturesPending[i].Value; 144 } 145 IRQ.Set(status); 146 } 147 148 public GPIO IRQ { get; } = new GPIO(); 149 150 private IFlagRegisterField freeRunModeEnabled; 151 private IFlagRegisterField[] capturesEnabled; 152 private IFlagRegisterField[] capturesPending; 153 private readonly ComparingTimer[] timers; 154 private const int NumberOfCaptures = 3; 155 private const int DefaultFrequency = 32000; 156 157 private enum Registers : long 158 { 159 Control = 0x00, 160 Prescaler = 0x04, 161 Status = 0x08, 162 Interrupt = 0x0c, 163 OutputCompare1 = 0x10, 164 OutputCompare2 = 0x14, 165 OutputCompare3 = 0x18, 166 InputCapture1 = 0x1c, 167 InputCapture2 = 0x20, 168 Count = 0x24, 169 } 170 } 171 } 172