1 // 2 // Copyright (c) 2010-2021 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 Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 13 namespace Antmicro.Renode.Peripherals.Miscellaneous 14 { 15 public sealed class NRF52840_RNG : BasicDoubleWordPeripheral, IKnownSize, INRFEventProvider 16 { NRF52840_RNG(IMachine machine)17 public NRF52840_RNG(IMachine machine) : base(machine) 18 { 19 rng = EmulationManager.Instance.CurrentEmulation.RandomGenerator; 20 IRQ = new GPIO(); 21 DefineRegisters(); 22 } 23 Reset()24 public override void Reset() 25 { 26 base.Reset(); 27 IRQ.Unset(); 28 } 29 30 public long Size => 0x1000; 31 32 public GPIO IRQ { get; } 33 34 public event Action<uint> EventTriggered; 35 DefineRegisters()36 private void DefineRegisters() 37 { 38 Registers.Start.Define(this) 39 .WithFlag(0, out started, FieldMode.Write, name: "TASKS_START") 40 .WithReservedBits(1, 31) 41 .WithWriteCallback((_, __) => Update()) 42 ; 43 44 Registers.Stop.Define(this) 45 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => started.Value &= !value, name: "TASKS_STOP") 46 .WithReservedBits(1, 31) 47 .WithWriteCallback((_, __) => Update()) 48 ; 49 50 Registers.ValueReady.Define(this) 51 .WithFlag(0, writeCallback: (_, value) => 52 { 53 if(!value) 54 { 55 IRQ.Unset(); 56 } 57 Update(); 58 }, valueProviderCallback: _ => started.Value, name: "EVENTS_VALRDY") 59 .WithReservedBits(1, 31) 60 ; 61 62 Registers.Shorts.Define(this, name: "SHORTS") 63 .WithFlag(0, out readyToStopShortEnabled, name: "VALRDY_STOP") 64 .WithReservedBits(1, 31) 65 .WithWriteCallback((_, __) => Update()) 66 ; 67 68 Registers.InterruptEnableSet.Define(this, name: "INTENSET") 69 .WithFlag(0, out interruptEnabled, FieldMode.Set | FieldMode.Read, name: "VALRDY") 70 .WithReservedBits(1, 31) 71 .WithWriteCallback((_, __) => Update()) 72 ; 73 74 Registers.InterruptEnableClear.Define(this, name: "INTENCLR") 75 .WithFlag(0, writeCallback: (_, value) => interruptEnabled.Value &= !value, valueProviderCallback: _ => interruptEnabled.Value, name: "VALRDY") 76 .WithReservedBits(1, 31) 77 .WithWriteCallback((_, __) => Update()) 78 ; 79 80 Registers.Config.Define(this, name: "CONFIG") 81 .WithTaggedFlag("DERCEN", 0) 82 .WithReservedBits(1, 31) 83 ; 84 85 Registers.Value.Define(this, name: "VALUE") 86 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => started.Value ? (uint)rng.Next(0, byte.MaxValue) : 0u, name: "VALUE") 87 .WithReservedBits(8, 24) 88 ; 89 } 90 Update()91 private void Update() 92 { 93 var value = started.Value && interruptEnabled.Value; 94 if(value) 95 { 96 this.Log(LogLevel.Noisy, "Generated new interrupt for RNG"); 97 EventTriggered?.Invoke(0); 98 } 99 IRQ.Set(value); 100 if(started.Value && readyToStopShortEnabled.Value) 101 { 102 started.Value = false; 103 IRQ.Set(false); 104 } 105 } 106 107 private readonly PseudorandomNumberGenerator rng; 108 private IFlagRegisterField started; 109 private IFlagRegisterField readyToStopShortEnabled; 110 private IFlagRegisterField interruptEnabled; 111 112 private enum Registers 113 { 114 Start = 0x0, 115 Stop = 0x4, 116 ValueReady = 0x100, 117 Shorts = 0x200, 118 InterruptEnableSet = 0x304, 119 InterruptEnableClear = 0x308, 120 Config = 0x504, 121 Value = 0x508 122 } 123 } 124 } 125