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 Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Logging;
11 
12 namespace Antmicro.Renode.Peripherals.Miscellaneous
13 {
14     public class LiteX_MMCM : BasicDoubleWordPeripheral, IKnownSize
15     {
LiteX_MMCM(IMachine machine)16         public LiteX_MMCM(IMachine machine) : base(machine)
17         {
18             mmcmRegisters = new uint[RegistersCount];
19 
20             DefineRegisters();
21         }
22 
Reset()23         public override void Reset()
24         {
25             base.Reset();
26 
27             for(var i = 0; i < mmcmRegisters.Length; i++)
28             {
29                 mmcmRegisters[i] = 0;
30             }
31         }
32 
33         public long Size => 0x100;
34 
DefineRegisters()35         private void DefineRegisters()
36         {
37             Registers.Reset.Define(this)
38                 .WithFlag(0, FieldMode.WriteOneToClear, name: "reset", writeCallback: (_, val) =>
39                 {
40                     if(val)
41                     {
42                         // this "reset" should not
43                         // clear the internal mmcm registers
44                         RegistersCollection.Reset();
45                     }
46                 })
47                 .WithReservedBits(1, 7)
48                 .WithIgnoredBits(8,24)
49             ;
50 
51             Registers.Locked.Define(this)
52                 .WithFlag(0, name: "locked", valueProviderCallback: _ => true) // we are always ready
53                 .WithReservedBits(1, 7)
54                 .WithIgnoredBits(8,24)
55             ;
56 
57             Registers.Read.Define(this)
58                 .WithFlag(0, FieldMode.WriteOneToClear, name: "read", writeCallback: (_, val) =>
59                 {
60                     if(val)
61                     {
62                         HandleRead();
63                     }
64                 })
65                 .WithReservedBits(1, 7)
66                 .WithIgnoredBits(8,24)
67             ;
68 
69             Registers.Write.Define(this)
70                 .WithFlag(0, FieldMode.WriteOneToClear, name: "write", writeCallback: (_, val) =>
71                 {
72                     if(val)
73                     {
74                         HandleWrite();
75                     }
76                 })
77                 .WithReservedBits(1, 7)
78                 .WithIgnoredBits(8,24)
79             ;
80 
81             Registers.DataReady.Define(this)
82                 .WithFlag(0, out dataReadyField, name: "drdy")
83                 .WithReservedBits(1, 7)
84                 .WithIgnoredBits(8,24)
85             ;
86             Registers.Address.Define(this)
87                 .WithValueField(0, 8, out addressField, name: "addr")
88                 .WithIgnoredBits(8,24)
89             ;
90             Registers.DataWriteLow.Define(this)
91                 .WithValueField(0, 8, out dataWriteLowField, FieldMode.Write, name: "dat_wL")
92                 .WithIgnoredBits(8,24)
93             ;
94             Registers.DataWriteHigh.Define(this)
95                 .WithValueField(0, 8, out dataWriteHighField, FieldMode.Write, name: "dat_wH")
96                 .WithIgnoredBits(8,24)
97             ;
98             Registers.DataReadLow.Define(this)
99                 .WithValueField(0, 8, out dataReadLowField, FieldMode.Read, name: "dat_rL")
100                 .WithIgnoredBits(8,24)
101             ;
102             Registers.DataReadHigh.Define(this)
103                 .WithValueField(0, 8, out dataReadHighField, FieldMode.Read, name: "dat_rH")
104                 .WithIgnoredBits(8,24)
105             ;
106         }
107 
HandleRead()108         private void HandleRead()
109         {
110             if((int)addressField.Value >= mmcmRegisters.Length)
111             {
112                 this.Log(LogLevel.Error, "Trying to read from a non-existing MMCM register #{0}. This model supports registers <0-{1}>", addressField.Value, mmcmRegisters.Length - 1);
113                 return;
114             }
115 
116             dataReadLowField.Value = (byte)mmcmRegisters[addressField.Value];
117             dataReadHighField.Value = mmcmRegisters[addressField.Value] >> 8;
118             dataReadyField.Value = true;
119         }
120 
HandleWrite()121         private void HandleWrite()
122         {
123             if((int)addressField.Value >= mmcmRegisters.Length)
124             {
125                 this.Log(LogLevel.Error, "Trying to write to a non-existing MMCM register #{0}. This model supports registers <0-{1}>", addressField.Value, mmcmRegisters.Length - 1);
126                 return;
127             }
128 
129             mmcmRegisters[addressField.Value] = (uint)((dataWriteHighField.Value << 8) | dataWriteLowField.Value);
130             dataReadyField.Value = true;
131         }
132 
133         private IFlagRegisterField dataReadyField;
134         private IValueRegisterField addressField;
135         private IValueRegisterField dataReadLowField;
136         private IValueRegisterField dataReadHighField;
137         private IValueRegisterField dataWriteLowField;
138         private IValueRegisterField dataWriteHighField;
139 
140         private uint[] mmcmRegisters;
141 
142         private const int RegistersCount = 0x50;    // 0x4F is the last register in MMCM
143 
144         private enum Registers
145         {
146             Reset = 0x0,
147             Locked = 0x4,
148             Read = 0x8,
149             Write = 0xc,
150             DataReady = 0x10,
151             Address = 0x14,
152             DataWriteLow = 0x18,
153             DataWriteHigh = 0x1c,
154             DataReadLow = 0x20,
155             DataReadHigh = 0x24
156         }
157     }
158 }
159