1 //
2 // Copyright (c) 2010-2024 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 System.Collections.ObjectModel;
11 using System.IO;
12 using System.Linq;
13 using Antmicro.Renode.Core;
14 using Antmicro.Renode.Core.Structure.Registers;
15 using Antmicro.Renode.Exceptions;
16 using Antmicro.Renode.Logging;
17 using Antmicro.Renode.Utilities;
18 using Antmicro.Renode.Time;
19 using Antmicro.Renode.Debugging;
20 
21 namespace Antmicro.Renode.Peripherals.Timers
22 {
23     public class IMXRT_PWM : BasicWordPeripheral, IKnownSize, INumberedGPIOOutput
24     {
IMXRT_PWM(IMachine machine, long frequency = 10000000)25         public IMXRT_PWM(IMachine machine, long frequency = 10000000) : base(machine)
26         {
27             halfCycleTimer = new ComparingTimer(machine.ClockSource, frequency, this, "halfCycleTimer", compare: ushort.MaxValue, limit: ushort.MaxValue, workMode: WorkMode.Periodic, enabled: false, eventEnabled: true);
28             fullCycleTimer = new ComparingTimer(machine.ClockSource, frequency, this, "fullCycleTimer", compare: ushort.MaxValue, limit: ushort.MaxValue, workMode: WorkMode.Periodic, enabled: false, eventEnabled: true);
29 
30             halfCycleTimer.CompareReached += () => OnCompare(false);
31             fullCycleTimer.CompareReached += () => OnCompare(true);
32 
33             Connections = new ReadOnlyDictionary<int, IGPIO>(Enumerable.Range(0, NumberOfSubmodules * 3 + 2).ToDictionary<int, int, IGPIO>(x => x, x => new GPIO()));
34             DefineRegisters();
35         }
36 
Reset()37         public override void Reset()
38         {
39             base.Reset();
40             UpdateInterrupts();
41         }
42 
43         // The Connections is composed of Compare, Capture and Reload IRQ triplets
44         // in that order for every submodule in ascending index order. The second
45         // to last and last connection are Reload Error and Fault in that order.
46         public IReadOnlyDictionary<int, IGPIO> Connections { get; }
47 
48         public long Size => 0x200;
49 
UpdateInterrupts()50         private void UpdateInterrupts()
51         {
52             // At the moment only Reload IRQ for submodule 0 is implemented
53             GetReloadIRQ(0).Set(reloadFlag.Value && reloadInterruptEnable.Value);
54             for(var i = 0; i < NumberOfSubmodules; ++i)
55             {
56                 this.Log(LogLevel.Debug, "Setting submodule#{0} events: compare {1}, capture {2}, reload {3}.", i, GetCompareIRQ(i).IsSet, GetCaptureIRQ(i).IsSet, GetReloadIRQ(i).IsSet);
57             }
58             this.Log(LogLevel.Debug, "Setting reload error {0} and fault {1}", ReloadError.IsSet, Fault.IsSet);
59         }
60 
DefineRegisters()61         private void DefineRegisters()
62         {
63             Registers.MasterControl.Define(this)
64                 .WithTag("LDOK - Load Okay", 0, 4)
65                 .WithTag("CLDOK - Clear Load Okay", 4, 4)
66                 .WithFlags(8, 4, name: "RUN - Run", writeCallback: (idx, _, val) =>
67                 {
68                     ConfigureSubmodule(idx, val);
69                 })
70                 .WithTag("IPOL - Current Polarity", 12, 4)
71             ;
72 
73             Registers.Submodule0InitialCount.Define(this)
74                 .WithValueField(0, 16, out initValue, name: "INIT - Initial Count Register Bits");
75 
76             Registers.Submodule0Value0.Define(this)
77                 .WithValueField(0, 16, out value0, name: "VAL0 - Value Register 0");
78 
79             Registers.Submodule0Value1.Define(this)
80                 .WithValueField(0, 16, out value1, name: "VAL1 - Value Register 1");
81 
82             Registers.Submodule0Control.Define(this)
83                 .WithTaggedFlag("DBLEN - Double Switching Enable", 0)
84                 .WithTaggedFlag("DBLX - PWMX Double Switching Enable", 1)
85                 .WithTaggedFlag("LDMOD - Load Mode Select", 2)
86                 .WithTaggedFlag("SPLIT - Split the DBLPWM signal to PWMA and PWMB", 3)
87                 .WithTag("PRSC - Prescaler", 4, 3)
88                 .WithTaggedFlag("COMPMODE - Compare Mode", 7)
89                 .WithTag("DT - Deadtime", 8, 2)
90                 .WithFlag(10, out fullCycleReload, name: "FULL - Full Cycle Reload")
91                 .WithFlag(11, out halfCycleReload, name: "HALF - Half Cycle Reload")
92                 .WithTag("LDFQ - Load Frequency", 12, 4);
93 
94             Registers.Submodule0Status.Define(this)
95                 .WithTag("CMPF - Compare Flags", 0, 6)
96                 .WithTaggedFlag("CFX0 - Capture Flag X0", 6)
97                 .WithTaggedFlag("CFX1 - Capture Flag X1", 7)
98                 .WithTaggedFlag("CFB0 - Capture Flag B0", 8)
99                 .WithTaggedFlag("CFB1 - Capture Flag B1", 9)
100                 .WithTaggedFlag("CFA0 - Capture Flag A0", 10)
101                 .WithTaggedFlag("CFA1 - Capture Flag A1", 11)
102                 .WithFlag(12, out reloadFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "RF - Reload Flag")
103                 .WithTaggedFlag("REF - Reload Error Flag", 13)
104                 .WithTaggedFlag("RUF - Registers Updated Flag", 14)
105                 .WithReservedBits(15, 1)
106                 .WithWriteCallback((_, __) => UpdateInterrupts());
107 
108             Registers.Submodule0InterruptEnable.Define(this)
109                 .WithTag("CMPIE - Compare Interrupt Enables", 0, 6)
110                 .WithTaggedFlag("CX0IE - Capture X 0 Interrupt Enable", 6)
111                 .WithTaggedFlag("CX1IE - Capture X 1 Interrupt Enable", 7)
112                 .WithTaggedFlag("CB0IE - Capture B 0 Interrupt Enable", 8)
113                 .WithTaggedFlag("CB1IE - Capture B 1 Interrupt Enable", 9)
114                 .WithTaggedFlag("CA0IE - Capture A 0 Interrupt Enable", 10)
115                 .WithTaggedFlag("CA1IE - Capture A 1 Interrupt Enable", 11)
116                 .WithFlag(12, out reloadInterruptEnable, name: "RIE - Reload Interrupt Enable")
117                 .WithTaggedFlag("REIE - Reload Error Interrupt Enable", 13)
118                 .WithReservedBits(14, 2)
119                 .WithWriteCallback((_, __) => UpdateInterrupts());
120         }
121 
ConfigureSubmodule(int idx, bool enabled)122         private void ConfigureSubmodule(int idx, bool enabled)
123         {
124             DebugHelper.Assert(idx >= 0 && idx < NumberOfSubmodules);
125 
126             if(idx != 0)
127             {
128                 this.Log(LogLevel.Warning, "Currently only submodule 0 is supported");
129                 return;
130             }
131 
132             if(enabled)
133             {
134                 ReloadTimer(false);
135                 ReloadTimer(true);
136             }
137 
138             halfCycleTimer.Enabled = enabled;
139             fullCycleTimer.Enabled = enabled;
140         }
141 
OnCompare(bool fullCycle)142         private void OnCompare(bool fullCycle)
143         {
144             if(fullCycle && fullCycleReload.Value
145                 || !fullCycle && halfCycleReload.Value)
146             {
147                 ReloadTimer(fullCycle);
148             }
149 
150             reloadFlag.Value = true;
151             UpdateInterrupts();
152         }
153 
ReloadTimer(bool fullCycle)154         private void ReloadTimer(bool fullCycle)
155         {
156             var timer = fullCycle
157                 ? fullCycleTimer
158                 : halfCycleTimer;
159 
160             var valueRegister = fullCycle
161                 ? value1
162                 : value0;
163 
164             // this model supports signed values
165             // in registers in order to make symmetric patterns easier
166             // to configure (less calculations needed);
167             // our timer infrastructure operates on unsiged values
168             // that's why we need to calculate and add offset
169             var initSignedValue = (short)initValue.Value;
170             if(initSignedValue < 0)
171             {
172                 timer.Value = 0;
173                 timer.Compare = valueRegister.Value + (ushort)(-initSignedValue);
174             }
175             else
176             {
177                 timer.Value = initValue.Value;
178                 timer.Compare = valueRegister.Value;
179             }
180         }
181 
GetCompareIRQ(int index)182         private IGPIO GetCompareIRQ(int index)
183         {
184             return Connections[index * 3];
185         }
186 
GetCaptureIRQ(int index)187         private IGPIO GetCaptureIRQ(int index)
188         {
189             return Connections[index * 3 + 1];
190         }
191 
GetReloadIRQ(int index)192         private IGPIO GetReloadIRQ(int index)
193         {
194             return Connections[index * 3 + 2];
195         }
196 
197         private IGPIO ReloadError => Connections[NumberOfSubmodules * 3];
198         private IGPIO Fault => Connections[NumberOfSubmodules * 3 + 1];
199 
200         private IFlagRegisterField reloadInterruptEnable;
201         private IFlagRegisterField reloadFlag;
202         private IFlagRegisterField halfCycleReload;
203         private IFlagRegisterField fullCycleReload;
204         private IValueRegisterField value0;
205         private IValueRegisterField value1;
206         private IValueRegisterField initValue;
207 
208         private ComparingTimer halfCycleTimer;
209         private ComparingTimer fullCycleTimer;
210 
211         private const int NumberOfSubmodules = 4;
212 
213         private enum Registers
214         {
215             Submodule0Counter = 0x000,
216             Submodule0InitialCount = 0x002,
217             Submodule0Control2 = 0x004,
218             Submodule0Control = 0x006,
219             Submodule0Value0 = 0x00A,
220             Submodule0FractionalValue1 = 0x00C,
221             Submodule0Value1 = 0x00E,
222             Submodule0FractionalValue2 = 0x010,
223             Submodule0Value2 = 0x012,
224             Submodule0FractionalValue3 = 0x014,
225             Submodule0Value3 = 0x016,
226             Submodule0FractionalValue4 = 0x018,
227             Submodule0Value4 = 0x01A,
228             Submodule0FractionalValue5 = 0x01C,
229             Submodule0Value5 = 0x01E,
230             Submodule0FractionalControl = 0x020,
231             Submodule0OutputControl = 0x022,
232             Submodule0Status = 0x024,
233             Submodule0InterruptEnable = 0x026,
234             Submodule0DMAEnable = 0x028,
235             Submodule0OutputTriggerControl = 0x02A,
236             Submodule0FaultDisableMapping0 = 0x02C,
237             Submodule0FaultDisableMapping1 = 0x02E,
238             Submodule0DeadtimeCount0 = 0x030,
239             Submodule0DeadtimeCount1 = 0x032,
240             Submodule0CaptureControlA = 0x034,
241             Submodule0CaptureCompareA = 0x036,
242             Submodule0CaptureControlB = 0x038,
243             Submodule0CaptureCompareB = 0x03A,
244             Submodule0CaptureControlX = 0x03C,
245             Submodule0CaptureCompareX = 0x03E,
246             Submodule0CaptureValue0 = 0x040,
247             Submodule0CaptureValue0Cycle = 0x042,
248             Submodule0CaptureValue1 = 0x044,
249             Submodule0CaptureValue1Cycle = 0x046,
250             Submodule0CaptureValue2 = 0x048,
251             Submodule0CaptureValue2Cycle = 0x04A,
252             Submodule0CaptureValue3 = 0x04C,
253             Submodule0CaptureValue3Cycle = 0x04E,
254             Submodule0CaptureValue4 = 0x050,
255             Submodule0CaptureValue4Cycle = 0x052,
256             Submodule0CaptureValue5 = 0x054,
257             Submodule0CaptureValue5Cycle = 0x056,
258 
259             Submodule1Counter = 0x060,
260             Submodule1InitialCount = 0x062,
261             Submodule1Control2 = 0x064,
262             Submodule1Control = 0x066,
263             Submodule1Value0 = 0x06A,
264             Submodule1FractionalValue1 = 0x06C,
265             Submodule1Value1 = 0x06E,
266             Submodule1FractionalValue2 = 0x070,
267             Submodule1Value2 = 0x072,
268             Submodule1FractionalValue3 = 0x074,
269             Submodule1Value3 = 0x076,
270             Submodule1FractionalValue4 = 0x078,
271             Submodule1Value4 = 0x07A,
272             Submodule1FractionalValue5 = 0x07C,
273             Submodule1Value5 = 0x07E,
274             Submodule1FractionalControl = 0x080,
275             Submodule1OutputControl = 0x082,
276             Submodule1Status = 0x084,
277             Submodule1InterruptEnable = 0x086,
278             Submodule1DMAEnable = 0x088,
279             Submodule1OutputTriggerControl = 0x08A,
280             Submodule1FaultDisableMapping0 = 0x08C,
281             Submodule1FaultDisableMapping1 = 0x08E,
282             Submodule1DeadtimeCount0 = 0x090,
283             Submodule1DeadtimeCount1 = 0x092,
284             Submodule1CaptureControlA = 0x094,
285             Submodule1CaptureCompareA = 0x096,
286             Submodule1CaptureControlB = 0x098,
287             Submodule1CaptureCompareB = 0x09A,
288             Submodule1CaptureControlX = 0x09C,
289             Submodule1CaptureCompareX = 0x09E,
290             Submodule1CaptureValue0 = 0x0A0,
291             Submodule1CaptureValue0Cycle = 0x0A2,
292             Submodule1CaptureValue1 = 0x0A4,
293             Submodule1CaptureValue1Cycle = 0x0A6,
294             Submodule1CaptureValue2 = 0x0A8,
295             Submodule1CaptureValue2Cycle = 0x0AA,
296             Submodule1CaptureValue3 = 0x0AC,
297             Submodule1CaptureValue3Cycle = 0x0AE,
298             Submodule1CaptureValue4 = 0x0B0,
299             Submodule1CaptureValue4Cycle = 0x0B2,
300             Submodule1CaptureValue5 = 0x0B4,
301             Submodule1CaptureValue5Cycle = 0x0B6,
302 
303             Submodule2Counter = 0x0C0,
304             Submodule2InitialCount = 0x0C2,
305             Submodule2Control2 = 0x0C4,
306             Submodule2Control = 0x0C6,
307             Submodule2Value0 = 0x0CA,
308             Submodule2FractionalValue1 = 0x0CC,
309             Submodule2Value1 = 0x0CE,
310             Submodule2FractionalValue2 = 0x0D0,
311             Submodule2Value2 = 0x0D2,
312             Submodule2FractionalValue3 = 0x0D4,
313             Submodule2Value3 = 0x0D6,
314             Submodule2FractionalValue4 = 0x0D8,
315             Submodule2Value4 = 0x0DA,
316             Submodule2FractionalValue5 = 0x0DC,
317             Submodule2Value5 = 0x0DE,
318             Submodule2FractionalControl = 0x0E0,
319             Submodule2OutputControl = 0x0E2,
320             Submodule2Status = 0x0E4,
321             Submodule2InterruptEnable = 0x0E6,
322             Submodule2DMAEnable = 0x0E8,
323             Submodule2OutputTriggerControl = 0x0EA,
324             Submodule2FaultDisableMapping0 = 0x0EC,
325             Submodule2FaultDisableMapping1 = 0x0EE,
326             Submodule2DeadtimeCount0 = 0x0F0,
327             Submodule2DeadtimeCount1 = 0x0F2,
328             Submodule2CaptureControlA = 0x0F4,
329             Submodule2CaptureCompareA = 0x0F6,
330             Submodule2CaptureControlB = 0x0F8,
331             Submodule2CaptureCompareB = 0x0FA,
332             Submodule2CaptureControlX = 0x0FC,
333             Submodule2CaptureCompareX = 0x0FE,
334             Submodule2CaptureValue0 = 0x100,
335             Submodule2CaptureValue0Cycle = 0x102,
336             Submodule2CaptureValue1 = 0x104,
337             Submodule2CaptureValue1Cycle = 0x106,
338             Submodule2CaptureValue2 = 0x108,
339             Submodule2CaptureValue2Cycle = 0x10A,
340             Submodule2CaptureValue3 = 0x10C,
341             Submodule2CaptureValue3Cycle = 0x10E,
342             Submodule2CaptureValue4 = 0x110,
343             Submodule2CaptureValue4Cycle = 0x112,
344             Submodule2CaptureValue5 = 0x114,
345             Submodule2CaptureValue5Cycle = 0x116,
346 
347             Submodule3Counter = 0x120,
348             Submodule3InitialCount = 0x122,
349             Submodule3Control2 = 0x124,
350             Submodule3Control = 0x126,
351             Submodule3Value0 = 0x12A,
352             Submodule3FractionalValue1 = 0x12C,
353             Submodule3Value1 = 0x12E,
354             Submodule3FractionalValue2 = 0x130,
355             Submodule3Value2 = 0x132,
356             Submodule3FractionalValue3 = 0x134,
357             Submodule3Value3 = 0x136,
358             Submodule3FractionalValue4 = 0x138,
359             Submodule3Value4 = 0x13A,
360             Submodule3FractionalValue5 = 0x13C,
361             Submodule3Value5 = 0x13E,
362             Submodule3FractionalControl = 0x140,
363             Submodule3OutputControl = 0x142,
364             Submodule3Status = 0x144,
365             Submodule3InterruptEnable = 0x146,
366             Submodule3DMAEnable = 0x148,
367             Submodule3OutputTriggerControl = 0x14A,
368             Submodule3FaultDisableMapping0 = 0x14C,
369             Submodule3FaultDisableMapping1 = 0x14E,
370             Submodule3DeadtimeCount0 = 0x150,
371             Submodule3DeadtimeCount1 = 0x152,
372             Submodule3CaptureControlA = 0x154,
373             Submodule3CaptureCompareA = 0x156,
374             Submodule3CaptureControlB = 0x158,
375             Submodule3CaptureCompareB = 0x15A,
376             Submodule3CaptureControlX = 0x15C,
377             Submodule3CaptureCompareX = 0x15E,
378             Submodule3CaptureValue0 = 0x160,
379             Submodule3CaptureValue0Cycle = 0x162,
380             Submodule3CaptureValue1 = 0x164,
381             Submodule3CaptureValue1Cycle = 0x166,
382             Submodule3CaptureValue2 = 0x168,
383             Submodule3CaptureValue2Cycle = 0x16A,
384             Submodule3CaptureValue3 = 0x16C,
385             Submodule3CaptureValue3Cycle = 0x16E,
386             Submodule3CaptureValue4 = 0x170,
387             Submodule3CaptureValue4Cycle = 0x172,
388             Submodule3CaptureValue5 = 0x174,
389             Submodule3CaptureValue5Cycle = 0x176,
390 
391             OutputEnable = 0x180,
392             Mask = 0x182,
393             SoftwareControlledOutput = 0x184,
394             PWMSourceSelect = 0x186,
395             MasterControl = 0x188,
396             MasterControl2 = 0x18A,
397             FaultControl = 0x18C,
398             FaultStatus = 0x18E,
399             FaultFilter = 0x190,
400             FaultTest = 0x192,
401             FaultControl2 = 0x194,
402         }
403     }
404 }
405