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