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 8 using System; 9 using System.Linq; 10 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Utilities; 15 using Antmicro.Renode.Time; 16 17 namespace Antmicro.Renode.Peripherals.Timers 18 { 19 public class EFR32xG2_BURTC : BasicDoubleWordPeripheral, IKnownSize 20 { EFR32xG2_BURTC(Machine machine, long frequency = 32768)21 public EFR32xG2_BURTC(Machine machine, long frequency = 32768) : base(machine) 22 { 23 IRQ = new GPIO(); 24 interruptManager = new InterruptManager<Interrupt>(this); 25 26 innerTimer = new ComparingTimer(machine.ClockSource, frequency, this, "burtc", limit: uint.MaxValue, compare: uint.MaxValue, workMode: WorkMode.Periodic, eventEnabled: true); 27 28 // TODO: add support for the overflow exception 29 innerTimer.CompareReached += delegate 30 { 31 interruptManager.SetInterrupt(Interrupt.CompareMatch); 32 }; 33 34 DefineRegisters(); 35 } 36 Reset()37 public override void Reset() 38 { 39 base.Reset(); 40 innerTimer.Reset(); 41 interruptManager.Reset(); 42 } 43 44 public long Size => 0x3034; 45 46 [IrqProvider] 47 public GPIO IRQ { get; } 48 DefineRegisters()49 private void DefineRegisters() 50 { 51 Register.IpVersion.Define(this) 52 .WithTag("IPVERSION", 0, 32); 53 54 Register.ModuleEnable.Define(this) 55 .WithTaggedFlag("EN", 0) 56 .WithReservedBits(1, 31); 57 58 Register.Configuration.Define(this) 59 .WithTaggedFlag("DEBUGRUN", 0) 60 .WithTaggedFlag("COMPTOP", 1) 61 .WithReservedBits(2, 2) 62 .WithValueField(4, 4, 63 writeCallback: (_, value) => innerTimer.Divider = (uint)Math.Pow(2, value), 64 valueProviderCallback: _ => (uint)Math.Log(innerTimer.Divider, 2), 65 name: "CNTPRESC") 66 .WithReservedBits(8, 24); 67 68 Register.Command.Define(this) 69 .WithEnumField<DoubleWordRegister, Command>(0, 2, FieldMode.Write, writeCallback: (_, value) => 70 { 71 switch(value) 72 { 73 case Command.None: 74 break; 75 case Command.Start: 76 innerTimer.Enabled = true; 77 break; 78 case Command.Stop: 79 innerTimer.Enabled = false; 80 break; 81 default: 82 this.Log(LogLevel.Warning, "Unsupported command combination: {0}", value); 83 break; 84 } 85 }, name: "START/STOP") 86 .WithReservedBits(2, 30); 87 88 Register.Status.Define(this) 89 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => innerTimer.Enabled, name: "RUNNING") 90 .WithTaggedFlag("LOCK", 1) 91 .WithReservedBits(2, 30); 92 93 RegistersCollection.AddRegister((long)Register.InterruptFlags, interruptManager.GetRegister<DoubleWordRegister>( 94 valueProviderCallback: (irq, _) => interruptManager.IsSet(irq), 95 writeCallback: (irq, _, newValue) => interruptManager.SetInterrupt(irq, newValue))); 96 97 RegistersCollection.AddRegister((long)Register.InterruptEnable, interruptManager.GetInterruptEnableRegister<DoubleWordRegister>()); 98 99 Register.CounterValue.Define(this) 100 .WithValueField(0, 32, 101 writeCallback: (_, value) => innerTimer.Value = value, 102 valueProviderCallback: _ => innerTimer.Value, 103 name: "CNT"); 104 105 Register.SynchronizationBusy.Define(this) 106 .WithTaggedFlag("START", 0) 107 .WithTaggedFlag("STOP", 1) 108 .WithTaggedFlag("PRECNT", 2) 109 .WithTaggedFlag("CNT", 3) 110 .WithTaggedFlag("COMP", 4) 111 .WithTaggedFlag("EN", 5) 112 .WithReservedBits(6, 26); 113 114 Register.ConfigurationLock.Define(this) 115 .WithTag("LOCK", 0, 15) 116 .WithReservedBits(15, 17); 117 118 Register.CompareValue.Define(this) 119 .WithValueField(0, 32, 120 writeCallback: (_, value) => innerTimer.Compare = value, 121 valueProviderCallback: _ => (uint)innerTimer.Compare, 122 name: "COMP"); 123 124 RegistersCollection.AddRegister((long)Register.InterruptEnableSet, interruptManager.GetInterruptEnableSetRegister<DoubleWordRegister>()); 125 126 RegistersCollection.AddRegister((long)Register.InterruptFlagsClear, interruptManager.GetInterruptClearRegister<DoubleWordRegister>()); 127 } 128 129 private readonly InterruptManager<Interrupt> interruptManager; 130 private readonly ComparingTimer innerTimer; 131 132 private enum Interrupt 133 { 134 Overflow, 135 CompareMatch, 136 } 137 138 private enum Command 139 { 140 None = 0b00, 141 Start = 0b01, 142 Stop = 0b10, 143 } 144 145 private enum Register 146 { 147 IpVersion = 0x0, 148 ModuleEnable = 0x4, 149 Configuration = 0x8, 150 Command = 0xC, 151 Status = 0x10, 152 InterruptFlags = 0x14, 153 InterruptEnable = 0x18, 154 PreCounterValue = 0x1C, 155 CounterValue = 0x20, 156 EM4WakeupRequest = 0x24, 157 SynchronizationBusy = 0x28, 158 ConfigurationLock = 0x2C, 159 CompareValue = 0x30, 160 161 IpVersionSet = 0x1000, 162 ModuleEnableSet = 0x1004, 163 ConfigurationSet = 0x1008, 164 CommandSet = 0x100C, 165 StatusSet = 0x1010, 166 InterruptFlagsSet = 0x1014, 167 InterruptEnableSet = 0x1018, 168 PreCounterValueSet = 0x101C, 169 CounterValueSet = 0x1020, 170 EM4WakeupRequestSet = 0x1024, 171 SynchronizationBusySet = 0x1028, 172 ConfigurationLockSet = 0x102C, 173 CompareValueSet = 0x1030, 174 175 IpVersionClear = 0x2000, 176 ModuleEnableClear = 0x2004, 177 ConfigurationClear = 0x2008, 178 CommandClear = 0x200C, 179 StatusClear = 0x2010, 180 InterruptFlagsClear = 0x2014, 181 InterruptEnableClear = 0x2018, 182 PreCounterValueClear = 0x201C, 183 CounterValueClear = 0x2020, 184 EM4WakeupRequestClear = 0x2024, 185 SynchronizationBusyClear = 0x2028, 186 ConfigurationLockClear = 0x202C, 187 CompareValueClear = 0x2030, 188 189 IpVersionToggle = 0x3000, 190 ModuleEnableToggle = 0x3004, 191 ConfigurationToggle = 0x3008, 192 CommandToggle = 0x300C, 193 StatusToggle = 0x3010, 194 InterruptFlagsToggle = 0x3014, 195 InterruptEnableToggle = 0x3018, 196 PreCounterValueToggle = 0x301C, 197 CounterValueToggle = 0x3020, 198 EM4WakeupRequestToggle = 0x3024, 199 SynchronizationBusyToggle = 0x3028, 200 ConfigurationLockToggle = 0x302C, 201 CompareValueToggle = 0x3030 202 } 203 } 204 } 205