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 Antmicro.Renode.Core; 8 using Antmicro.Renode.Core.Structure.Registers; 9 using Antmicro.Renode.Exceptions; 10 using Antmicro.Renode.Time; 11 using Antmicro.Renode.Peripherals.Bus; 12 using System.Collections.Generic; 13 using System.Threading.Tasks; 14 15 namespace Antmicro.Renode.Peripherals.Timers 16 { 17 public class ARM_PrivateTimer : BasicDoubleWordPeripheral, IKnownSize 18 { ARM_PrivateTimer(IMachine machine, ulong frequency)19 public ARM_PrivateTimer(IMachine machine, ulong frequency) : base(machine) 20 { 21 if(frequency > long.MaxValue) 22 { 23 throw new ConstructionException($"Timer doesn't support frequency greater than {long.MaxValue}, given {frequency}."); 24 } 25 Frequency = (long)frequency; 26 27 BuildRegisters(); 28 timer = new LimitTimer(machine.ClockSource, Frequency, this, "Timer", 29 limit: uint.MaxValue, direction: Direction.Descending, workMode: WorkMode.OneShot, autoUpdate: true); 30 timer.LimitReached += UpdateInterrupt; 31 } 32 Reset()33 public override void Reset() 34 { 35 base.Reset(); 36 timer.Reset(); 37 UpdateInterrupt(); 38 } 39 40 public long Size => 0x200; 41 42 public GPIO IRQ { get; } = new GPIO(); 43 public long Frequency { get; } 44 BuildRegisters()45 private void BuildRegisters() 46 { 47 Registers.Load.Define(this) 48 .WithValueField(0, 32, name: "Load", 49 writeCallback: (_, val) => timer.Limit = val, 50 valueProviderCallback: (_) => (uint)timer.Limit 51 ); 52 Registers.Counter.Define(this) 53 .WithValueField(0, 32, name: "Counter", 54 writeCallback: (_, val) => 55 { 56 if(machine.SystemBus.TryGetCurrentCPU(out var cpu)) 57 { 58 cpu.SyncTime(); 59 } 60 timer.Value = val; 61 }, 62 valueProviderCallback: (_) => (uint)timer.Value 63 ); 64 Registers.Control.Define(this) 65 .WithReservedBits(16, 16) 66 .WithValueField(8, 8, name: "Prescaler", 67 writeCallback: (_, val) => timer.Divider = (int)val + 1, 68 valueProviderCallback: (_) => (ulong)timer.Divider - 1 69 ) 70 .WithReservedBits(3, 5) 71 .WithFlag(2, name: "InterruptEnabled", 72 writeCallback: (_, val) => timer.EventEnabled = val, 73 valueProviderCallback: (_) => timer.EventEnabled 74 ) 75 .WithFlag(1, name: "AutoLoad", 76 writeCallback: (_, val) => timer.Mode = val ? WorkMode.Periodic : WorkMode.OneShot, 77 valueProviderCallback: (_) => timer.Mode == WorkMode.Periodic 78 ) 79 .WithFlag(0, name: "Enabled", 80 writeCallback: (_, val) => timer.Enabled = val, 81 valueProviderCallback: (_) => timer.Enabled 82 ) 83 .WithWriteCallback( 84 (_, __) => UpdateInterrupt() 85 ); 86 Registers.InterruptStatus.Define(this) 87 .WithReservedBits(1, 31) 88 .WithFlag(0, name: "InterruptStatus", 89 writeCallback: (_, val) => { if(val) timer.ClearInterrupt(); }, 90 valueProviderCallback: (_) => timer.RawInterrupt 91 ) 92 .WithWriteCallback( 93 (_, __) => UpdateInterrupt() 94 ); 95 } 96 UpdateInterrupt()97 private void UpdateInterrupt() 98 { 99 IRQ.Set(timer.Interrupt); 100 } 101 102 private readonly LimitTimer timer; 103 104 private enum Registers : long 105 { 106 Load = 0x00, 107 Counter = 0x04, 108 Control = 0x08, 109 InterruptStatus = 0x0C 110 } 111 } 112 } 113