1 //
2 // Copyright (c) 2010-2019 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.Peripherals.Bus;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Time;
11 using System;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Miscellaneous
15 {
16     public class SAM_TRNG : BasicDoubleWordPeripheral, IKnownSize
17     {
SAM_TRNG(IMachine machine)18         public SAM_TRNG(IMachine machine) : base(machine)
19         {
20             DefineRegisters();
21         }
22 
23         public long Size => 0x4000;
24 
DefineRegisters()25         private void DefineRegisters()
26         {
27             Registers.Control.Define(this)
28                 .WithFlag(0, out var enableUnverified, FieldMode.Write, name: "CR_ENABLE")
29                 .WithReservedBits(1, 7)
30                 .WithValueField(8, 24, out var enableKey, FieldMode.Write, name: "CR_KEY")
31                 .WithWriteCallback((_, __) =>
32                 {
33                     /* The enable bit and enable key have to be written at
34                      * the same time -  verify it here.
35                      */
36                     if(enableUnverified.Value && enableKey.Value == RngKey)
37                     {
38                         enable.Value = true;
39                     }
40                 });
41 
42             Registers.InterruptStatus.Define(this)
43                 .WithFlag(0, out enable, FieldMode.Read, name: "ISR_DATRDY");
44 
45             Registers.OutputData.Define(this)
46                 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ =>
47                 {
48                     if(!enable.Value)
49                     {
50                         this.Log(LogLevel.Warning, "Reading TRNG data from an uninitialized device");
51 
52                         return 0;
53                     }
54 
55                     return (uint)rng.Next();
56                 }, name: "ODATA");
57 
58             /* Interrupts not generated properly yet */
59             Registers.InterruptEnable.Define(this)
60                 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) =>
61                 {
62                     if(value)
63                     {
64                         interruptEnabled.Value = true;
65                     }
66                 }, name: "IER_DATRDY");
67 
68             Registers.InterruptDisable.Define(this)
69                 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) =>
70                 {
71                     if(value)
72                     {
73                         interruptEnabled.Value = false;
74                     }
75                 }, name: "IER_DATRDY");
76 
77             Registers.InterruptMask.Define(this)
78                 .WithFlag(0, out interruptEnabled, FieldMode.Read, name: "IMR_DATRDY");
79         }
80 
81         private readonly PseudorandomNumberGenerator rng = EmulationManager.Instance.CurrentEmulation.RandomGenerator;
82 
83         private IFlagRegisterField enable;
84         private IFlagRegisterField interruptEnabled;
85 
86         /* Enable key - ASCII for "RNG" */
87         private const uint RngKey = 0x524E47;
88 
89         private enum Registers
90         {
91             Control = 0x0,
92             InterruptEnable = 0x10,
93             InterruptDisable = 0x14,
94             InterruptMask = 0x18,
95             InterruptStatus = 0x1C,
96             OutputData = 0x50,
97         }
98     }
99 }
100