1 //
2 // Copyright (c) 2010-2020 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.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Peripherals.Timers;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
18     public sealed class STM32F4_RCC : IDoubleWordPeripheral, IKnownSize, IProvidesRegisterCollection<DoubleWordRegisterCollection>
19     {
STM32F4_RCC(IMachine machine, STM32F4_RTC rtcPeripheral)20         public STM32F4_RCC(IMachine machine, STM32F4_RTC rtcPeripheral)
21         {
22             // Renode, in general, does not include clock control peripherals.
23             // While this is doable, it seldom benefits real software development
24             // and is very cumbersome to maintain.
25             //
26             // To properly support the RTC peripheral, we need to add this stub class.
27             // It is common in Renode that whenever a register is implemented, it
28             // either contains actual logic or tags, indicating not implemented fields.
29             //
30             // Here, however, we want to fake most of the registers as r/w values.
31             // Usually we implemented this logic with Python peripherals.
32             //
33             // Keep in mind that most of these registers do not affect other
34             // peripherals or their clocks.
35             var registersMap = new Dictionary<long, DoubleWordRegister>
36             {
37                 {(long)Registers.ClockControl, new DoubleWordRegister(this, 0x483)
38                     .WithFlag(0, out var hsion, name: "HSION")
39                     .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => hsion.Value, name: "HSIRDY")
40                     .WithReservedBits(2, 1)
41                     .WithValueField(3, 5, name: "HSITRIM")
42                     .WithTag("HSICAL", 8, 8)
43                     .WithFlag(16, out var hseon, name: "HSEON")
44                     .WithFlag(17, FieldMode.Read, valueProviderCallback: _ => hseon.Value, name: "HSERDY")
45                     .WithTag("HSEBYP", 18, 1)
46                     .WithTag("CSSON", 19, 1)
47                     .WithReservedBits(20, 4)
48                     .WithFlag(24, out var pllon, name: "PLLON")
49                     .WithFlag(25, FieldMode.Read, valueProviderCallback: _ => pllon.Value, name: "PLLRDY")
50                     .WithFlag(26, out var plli2son, name: "PLLI2SON")
51                     .WithFlag(27, FieldMode.Read, valueProviderCallback: _ => plli2son.Value, name: "PLLI2SRDY")
52                     .WithFlag(28, out var pllsaion, name: "PLLSAION")
53                     .WithFlag(29, FieldMode.Read, valueProviderCallback: _ => pllsaion.Value, name: "PLLSAIRDY")
54                     .WithReservedBits(30, 2)
55                 },
56                 {(long)Registers.PLLConfiguration, new DoubleWordRegister(this, 0x24003010)
57                     .WithValueField(0, 6, name: "PLLM")
58                     .WithValueField(6, 9, name: "PLLN")
59                     .WithReservedBits(15, 1)
60                     .WithValueField(16, 2, name: "PLLP")
61                     .WithReservedBits(18, 4)
62                     .WithValueField(22, 1, name: "PLLSRC")
63                     .WithReservedBits(23, 1)
64                     .WithValueField(24, 4, name: "PLLQ")
65                     .WithReservedBits(28, 4)
66                 },
67                 {(long)Registers.ClockConfiguration, new DoubleWordRegister(this)
68                     .WithValueField(0, 2, out var systemClockSwitch, name: "SW")
69                     .WithValueField(2, 2, FieldMode.Read, name: "SWS", valueProviderCallback: _ => systemClockSwitch.Value)
70                     .WithValueField(4, 4, name: "HPRE")
71                     .WithReservedBits(8, 2)
72                     .WithValueField(10, 3, name: "PPRE1")
73                     .WithValueField(13, 3, name: "PPRE2")
74                     .WithValueField(16, 5, name: "RTCPRE")
75                     .WithValueField(21, 2, name: "MCO1")
76                     .WithValueField(23, 1, name: "I2SSCR")
77                     .WithValueField(24, 3, name: "MCO1PRE")
78                     .WithValueField(27, 3, name: "MCO2PRE")
79                     .WithValueField(30, 2, name: "MCO2")
80                 },
81                 //ClockInterrupt not implemented
82                 {(long)Registers.AHB1PeripheralReset, new DoubleWordRegister(this)
83                     .WithValueField(0, 11, name: "GPIOxRST")
84                     .WithReservedBits(11, 1)
85                     .WithFlag(12, name: "CRCRST")
86                     .WithReservedBits(13, 8)
87                     .WithValueField(21, 3, name: "DMAxRST")
88                     .WithReservedBits(24, 1)
89                     .WithFlag(25, name: "ETHMACRST")
90                     .WithReservedBits(26, 3)
91                     .WithFlag(29, name: "OTGHSRST")
92                     .WithReservedBits(30, 2)
93                 },
94                 {(long)Registers.AHB2PeripheralReset, new DoubleWordRegister(this)
95                     .WithFlag(0, name: "DCMIRST")
96                     .WithReservedBits(1, 3)
97                     .WithFlag(4, name: "CRYPRST")
98                     .WithFlag(5, name: "HASHRST")
99                     .WithFlag(6, name: "RNGRST")
100                     .WithFlag(7, name: "OTGFSRST")
101                     .WithReservedBits(8, 24)
102                 },
103                 {(long)Registers.AHB3PeripheralReset, new DoubleWordRegister(this)
104                     .WithFlag(0, name: "FMCRST")
105                     .WithReservedBits(1, 30)
106                 },
107                 {(long)Registers.APB1PeripheralReset, new DoubleWordRegister(this)
108                     .WithValueField(0, 9, name: "TIMxRST")
109                     .WithReservedBits(9, 2)
110                     .WithFlag(11, name: "WWDGRST")
111                     .WithReservedBits(12, 2)
112                     .WithValueField(14, 2, name: "SPIxRST")
113                     .WithReservedBits(16, 1)
114                     .WithValueField(17, 4, name: "UARTxRST")
115                     .WithValueField(21, 3, name: "I2CxRST")
116                     .WithReservedBits(24, 1)
117                     .WithValueField(25, 2, name: "CANxRST")
118                     .WithReservedBits(27, 1)
119                     .WithFlag(28, name: "PWRRST")
120                     .WithFlag(29, name: "DACRST")
121                     .WithValueField(30, 2, name: "UARTxRST")
122                 },
123                 {(long)Registers.APB2PeripheralReset, new DoubleWordRegister(this)
124                     .WithValueField(0, 2, name: "TIMxRST")
125                     .WithReservedBits(2, 2)
126                     .WithValueField(4, 2, name: "USARTxRST")
127                     .WithReservedBits(6, 2)
128                     .WithFlag(8, name: "ADCRST")
129                     .WithReservedBits(9, 2)
130                     .WithFlag(11, name: "SDIORST")
131                     .WithValueField(12, 2, name: "SPIxRST")
132                     .WithFlag(14, name: "SYSCFGRST")
133                     .WithReservedBits(15, 1)
134                     .WithValueField(16, 3, name: "TIMxRST")
135                     .WithReservedBits(19, 1)
136                     .WithValueField(20, 2, name: "SPIxRST")
137                     .WithFlag(22, name: "SAI1RST")
138                     .WithReservedBits(23, 3)
139                     .WithFlag(26, name: "LTDCRST")
140                     .WithReservedBits(27, 5)
141                 },
142                 {(long)Registers.AHB1PeripheralClockEnable, new DoubleWordRegister(this)
143                     .WithValueField(0, 11, name: "GPIOxEN")
144                     .WithReservedBits(11, 1)
145                     .WithFlag(12, name: "CRCEN")
146                     .WithReservedBits(13, 5)
147                     .WithFlag(18, name: "BKPSRAMEN")
148                     .WithReservedBits(19, 1)
149                     .WithFlag(20, name: "CCMDATARAMEN")
150                     .WithValueField(21, 3, name: "DMAxEN")
151                     .WithReservedBits(24, 1)
152                     .WithValueField(25, 4, name: "ETHMACxEN")
153                     .WithValueField(29, 2, name: "OTGHSxEN")
154                     .WithReservedBits(31, 1)
155                 },
156                 {(long)Registers.AHB2PeripheralClockEnable, new DoubleWordRegister(this)
157                     .WithFlag(0, name: "DCMIEN")
158                     .WithReservedBits(1, 3)
159                     .WithFlag(4, name: "CRYPEN")
160                     .WithFlag(5, name: "HASHEN")
161                     .WithFlag(6, name: "RNGEN")
162                     .WithFlag(7, name: "OTGFSEN")
163                     .WithReservedBits(8, 24)
164                 },
165                 {(long)Registers.AHB3PeripheralClockEnable, new DoubleWordRegister(this)
166                     .WithFlag(0, name: "FMCEN")
167                     .WithReservedBits(1, 30)
168                 },
169                 {(long)Registers.APB1PeripheralClockEnable, new DoubleWordRegister(this)
170                     .WithValueField(0, 9, name: "TIMxEN")
171                     .WithReservedBits(9, 2)
172                     .WithFlag(11, name: "WWDGEN")
173                     .WithReservedBits(12, 2)
174                     .WithValueField(14, 2, name: "SPIxEN")
175                     .WithReservedBits(16, 1)
176                     .WithValueField(17, 4, name: "UARTxEN")
177                     .WithValueField(21, 3, name: "I2CxEN")
178                     .WithReservedBits(24, 1)
179                     .WithValueField(25, 2, name: "CANxEN")
180                     .WithReservedBits(27, 1)
181                     .WithFlag(28, name: "PWREN")
182                     .WithFlag(29, name: "DACEN")
183                     .WithValueField(30, 2, name: "UARTxEN")
184                 },
185                 {(long)Registers.APB2PeripheralClockEnable, new DoubleWordRegister(this)
186                     .WithValueField(0, 2, name: "TIMxEN")
187                     .WithReservedBits(2, 2)
188                     .WithValueField(4, 2, name: "USARTxEN")
189                     .WithReservedBits(6, 2)
190                     .WithValueField(8, 3, name: "ADCxEN")
191                     .WithFlag(11, name: "SDIOEN")
192                     .WithValueField(12, 2, name: "SPIxEN")
193                     .WithFlag(14, name: "SYSCFGEN")
194                     .WithReservedBits(15, 1)
195                     .WithValueField(16, 3, name: "TIMxEN")
196                     .WithReservedBits(19, 1)
197                     .WithValueField(20, 2, name: "SPIxEN")
198                     .WithFlag(22, name: "SAI1EN")
199                     .WithReservedBits(23, 3)
200                     .WithFlag(26, name: "LTDCEN")
201                     .WithReservedBits(27, 5)
202                 },
203                 {(long)Registers.AHB1PeripheralClockEnableInLowPowerMode, new DoubleWordRegister(this)
204                     .WithValueField(0, 11, name: "GPIOxLPEN")
205                     .WithReservedBits(11, 1)
206                     .WithFlag(12, name: "CRCLPEN")
207                     .WithReservedBits(13, 2)
208                     .WithFlag(15, name: "FLITFLPEN")
209                     .WithValueField(16, 2, name: "SRAMxLPEN")
210                     .WithFlag(18, name: "BKPSRAMLPEN")
211                     .WithFlag(19, name: "SRAM3LPEN")
212                     .WithReservedBits(20, 1)
213                     .WithValueField(21, 3, name: "DMAxLPEN")
214                     .WithReservedBits(24, 1)
215                     .WithValueField(25, 4, name: "ETHMACxLPEN")
216                     .WithValueField(29, 2, name: "OTGHSxLPEN")
217                     .WithReservedBits(31, 1)
218                 },
219                 {(long)Registers.AHB2PeripheralClockEnableInLowPowerMode, new DoubleWordRegister(this)
220                     .WithFlag(0, name: "DCMILPEN")
221                     .WithReservedBits(1, 3)
222                     .WithFlag(4, name: "CRYPLPEN")
223                     .WithFlag(5, name: "HASHLPEN")
224                     .WithFlag(6, name: "RNGLPEN")
225                     .WithFlag(7, name: "OTGFSLPEN")
226                     .WithReservedBits(8, 24)
227                 },
228                 {(long)Registers.AHB3PeripheralClockEnableInLowPowerMode, new DoubleWordRegister(this)
229                     .WithFlag(0, name: "FMCLPEN")
230                     .WithReservedBits(1, 30)
231                 },
232                 {(long)Registers.APB1PeripheralClockEnableInLowPowerMode, new DoubleWordRegister(this)
233                     .WithValueField(0, 9, name: "TIMxLPEN")
234                     .WithReservedBits(9, 2)
235                     .WithFlag(11, name: "WWDGLPEN")
236                     .WithReservedBits(12, 2)
237                     .WithValueField(14, 2, name: "SPIxLPEN")
238                     .WithReservedBits(16, 1)
239                     .WithValueField(17, 4, name: "UARTxLPEN")
240                     .WithValueField(21, 3, name: "I2CxLPEN")
241                     .WithReservedBits(24, 1)
242                     .WithValueField(25, 2, name: "CANxLPEN")
243                     .WithReservedBits(27, 1)
244                     .WithFlag(28, name: "PWRLPEN")
245                     .WithFlag(29, name: "DACLPEN")
246                     .WithValueField(30, 2, name: "UARTxLPEN")
247                 },
248                 {(long)Registers.APB2PeripheralClockEnableInLowPowerMode, new DoubleWordRegister(this)
249                     .WithValueField(0, 2, name: "TIMxLPEN")
250                     .WithReservedBits(2, 2)
251                     .WithValueField(4, 2, name: "USARTxLPEN")
252                     .WithReservedBits(6, 2)
253                     .WithValueField(8, 3, name: "ADCxLPEN")
254                     .WithFlag(11, name: "SDIOLPEN")
255                     .WithValueField(12, 2, name: "SPIxLPEN")
256                     .WithFlag(14, name: "SYSCFGLPEN")
257                     .WithReservedBits(15, 1)
258                     .WithValueField(16, 3, name: "TIMxLPEN")
259                     .WithReservedBits(19, 1)
260                     .WithValueField(20, 2, name: "SPIxLPEN")
261                     .WithFlag(22, name: "SAI1LPEN")
262                     .WithReservedBits(23, 3)
263                     .WithFlag(26, name: "LTDCLPEN")
264                     .WithReservedBits(27, 5)
265                 },
266                 {(long)Registers.BackupDomainControl, new DoubleWordRegister(this)
267                     .WithFlag(0, out var lseon, name: "LSEON")
268                     .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => lseon.Value, name: "LSERDY")
269                     .WithValueField(2, 1, name: "LSEBYP")
270                     .WithReservedBits(3, 5)
271                     .WithValueField(8, 2, name: "RTCSEL")
272                     .WithReservedBits(10, 5)
273                     .WithFlag(15, name: "RTCEN",
274                         writeCallback: (_, value) =>
275                         {
276                             if(value)
277                             {
278                                 machine.SystemBus.EnablePeripheral(rtcPeripheral);
279                             }
280                             else
281                             {
282                                 machine.SystemBus.DisablePeripheral(rtcPeripheral);
283                             }
284                         })
285                     .WithValueField(16, 1, name: "BDRST")
286                     .WithReservedBits(17, 15)
287                 },
288                 {(long)Registers.ClockControlAndStatus, new DoubleWordRegister(this, 0x0E000000)
289                     .WithFlag(0, out var lsion, name: "LSION")
290                     .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => lsion.Value, name: "LSIRDY")
291                     .WithReservedBits(2, 21)
292                     .WithTag("RMVF", 24, 1)
293                     .WithTag("BORRSTF", 25, 1)
294                     .WithTag("PINRSTF", 26, 1)
295                     .WithTag("PORRSTF", 27, 1)
296                     .WithTag("SFTRSTF", 28, 1)
297                     .WithTag("IWDGRSTF", 29, 1)
298                     .WithTag("WWDGRSTF", 30, 1)
299                     .WithTag("LPWRRSTF", 31, 1)
300                 },
301                 {(long)Registers.SpreadSpectrumClockGeneration, new DoubleWordRegister(this)
302                     .WithValueField(0, 13, name: "MODPER")
303                     .WithValueField(13, 15, name: "INCSTEP")
304                     .WithReservedBits(28, 2)
305                     .WithFlag(30, name: "SPREADSEL")
306                     .WithFlag(31, name: "SSCGEN")
307                 },
308                 {(long)Registers.PLLI2SConfiguration, new DoubleWordRegister(this, 0x24003000)
309                     .WithReservedBits(0, 6)
310                     .WithValueField(6, 9, name: "PLLI2SNx")
311                     .WithReservedBits(15, 9)
312                     .WithValueField(24, 4, name: "PLLI2SQ")
313                     .WithValueField(28, 3, name: "PLLI2SRx")
314                     .WithReservedBits(31, 1)
315                 },
316                 {(long)Registers.PLLSAIConfiguration, new DoubleWordRegister(this, 0x24003000)
317                     .WithReservedBits(0, 6)
318                     .WithValueField(6, 9, name: "PLLSAIN")
319                     .WithReservedBits(15, 9)
320                     .WithValueField(24, 4, name: "PLLSAIQ")
321                     .WithValueField(28, 3, name: "PLLSAIR")
322                     .WithReservedBits(31, 1)
323                 },
324                 {(long)Registers.DedicatedClockConfiguration, new DoubleWordRegister(this)
325                     .WithValueField(0, 5, name: "PLLI2SDIVQ")
326                     .WithReservedBits(5, 3)
327                     .WithValueField(8, 5, name: "PLLSAIDIVQ")
328                     .WithReservedBits(13, 3)
329                     .WithValueField(16, 2, name: "PLLSAIDIVR")
330                     .WithReservedBits(18, 2)
331                     .WithValueField(20, 2, name: "SAI1ASRC")
332                     .WithValueField(22, 2, name: "SAI1BSRC")
333                     .WithFlag(24, name: "TIMPRE")
334                     .WithReservedBits(25, 7)
335                 },
336             };
337 
338             RegistersCollection = new DoubleWordRegisterCollection(this, registersMap);
339         }
340 
ReadDoubleWord(long offset)341         public uint ReadDoubleWord(long offset)
342         {
343             return RegistersCollection.Read(offset);
344         }
345 
WriteDoubleWord(long offset, uint value)346         public void WriteDoubleWord(long offset, uint value)
347         {
348             RegistersCollection.Write(offset, value);
349         }
350 
Reset()351         public void Reset()
352         {
353             RegistersCollection.Reset();
354         }
355 
356         public long Size => 0x400;
357 
358         public DoubleWordRegisterCollection RegistersCollection { get; }
359 
360         private enum Registers
361         {
362             ClockControl = 0x0,
363             PLLConfiguration = 0x4,
364             ClockConfiguration = 0x8,
365             ClockInterrupt = 0xC,
366             AHB1PeripheralReset = 0x10,
367             AHB2PeripheralReset = 0x14,
368             AHB3PeripheralReset = 0x18,
369             //gap
370             APB1PeripheralReset = 0x20,
371             APB2PeripheralReset = 0x24,
372             //gap
373             AHB1PeripheralClockEnable = 0x30,
374             AHB2PeripheralClockEnable = 0x34,
375             AHB3PeripheralClockEnable = 0x38,
376             APB1PeripheralClockEnable = 0x40,
377             APB2PeripheralClockEnable = 0x44,
378             AHB1PeripheralClockEnableInLowPowerMode = 0x50,
379             AHB2PeripheralClockEnableInLowPowerMode = 0x54,
380             AHB3PeripheralClockEnableInLowPowerMode = 0x58,
381             APB1PeripheralClockEnableInLowPowerMode = 0x60,
382             APB2PeripheralClockEnableInLowPowerMode = 0x64,
383             BackupDomainControl = 0x70,
384             ClockControlAndStatus = 0x74,
385             SpreadSpectrumClockGeneration = 0x80,
386             PLLI2SConfiguration = 0x84,
387             PLLSAIConfiguration = 0x88,
388             DedicatedClockConfiguration = 0x8C,
389         }
390     }
391 }
392