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 using System; 8 using System.Collections.Generic; 9 using System.Runtime.CompilerServices; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Time; 14 15 namespace Antmicro.Renode.Peripherals.Timers 16 { 17 public class RenesasDA14_GPT : BasicDoubleWordPeripheral, IKnownSize, IGPIOReceiver 18 { RenesasDA14_GPT(IMachine machine, long lowPowerFrequency = DefaultLowPowerFrequency, bool extendedTimer = false)19 public RenesasDA14_GPT(IMachine machine, long lowPowerFrequency = DefaultLowPowerFrequency, 20 bool extendedTimer = false) : base(machine) 21 { 22 this.lowPowerFrequency = lowPowerFrequency; 23 this.extendedTimer = extendedTimer; 24 25 timer = new LimitTimer(machine.ClockSource, lowPowerFrequency, this, "timer", FreeRunLimit, direction: Direction.Ascending, workMode: WorkMode.Periodic, eventEnabled: true); 26 timer.LimitReached += () => 27 { 28 var currentValue = timer.Limit; 29 var triggerInterrupt = true; 30 31 if(freeRunEnabled.Value && timer.Direction == Direction.Ascending && currentValue != FreeRunLimit) 32 { 33 timer.Limit = FreeRunLimit; 34 timer.Value = currentValue; 35 } 36 else 37 { 38 triggerInterrupt = currentValue != FreeRunLimit; 39 timer.Limit = timerLimit.Value; 40 timer.ResetValue(); 41 } 42 43 interruptTriggered = triggerInterrupt; 44 UpdateInterrupts(); 45 }; 46 47 IRQ = new GPIO(); 48 CaptureIRQ = new GPIO(); 49 50 connections = new GPIOConnection[extendedTimer ? ExtendedGPIOConnections : DefaultGPIOConnections]; 51 for(var i = 0; i < connections.Length; i++) 52 { 53 connections[i] = new GPIOConnection(this); 54 } 55 56 DefineRegisters(); 57 Reset(); 58 } 59 Reset()60 public override void Reset() 61 { 62 base.Reset(); 63 interruptTriggered = false; 64 foreach(var connection in connections) 65 { 66 connection.Reset(); 67 } 68 69 timer.Reset(); 70 IRQ.Unset(); 71 CaptureIRQ.Unset(); 72 } 73 OnGPIO(int number, bool value)74 public void OnGPIO(int number, bool value) 75 { 76 if(!IsValidConnection(number)) 77 { 78 return; 79 } 80 81 connections[number].SetValue(value); 82 } 83 84 [DefaultInterrupt] 85 public GPIO IRQ { get; } 86 public GPIO CaptureIRQ { get; } 87 88 public long Size => 0x100; 89 DefineRegisters()90 private void DefineRegisters() 91 { 92 Registers.Control.Define(this) 93 .WithFlag(0, out timerEnabled, name: "TIM_EN", 94 writeCallback: (_, __) => SetTimerEnabled()) 95 .WithTaggedFlag("TIM_ONESHOT_MODE_EN", 1) 96 .WithFlag(2, name: "TIM_COUNT_DOWN_EN", 97 valueProviderCallback: _ => timer.Direction == Direction.Descending, 98 changeCallback: (_, value) => timer.Direction = value ? Direction.Descending : Direction.Ascending) 99 .WithFlag(3, name: "TIM_IN1_EVENT_FALL_EN", 100 valueProviderCallback: _ => CallForConnection(0, con => con.UseFallingEdge), 101 writeCallback: (_, value) => CallForConnection(0, con => con.UseFallingEdge = value)) 102 .WithFlag(4, name: "TIM_IN2_EVENT_FALL_EN", 103 valueProviderCallback: _ => CallForConnection(1, con => con.UseFallingEdge), 104 writeCallback: (_, value) => CallForConnection(1, con => con.UseFallingEdge = value)) 105 .WithFlag(5, out interruptEnabled, name: "TIM_IRQ_EN", 106 writeCallback: (_, __) => UpdateInterrupts()) 107 .WithFlag(6, out freeRunEnabled, name: "TIM_FREE_RUN_MODE_EN") 108 .WithFlag(7, name: "TIM_SYS_CLK_EN", 109 valueProviderCallback: _ => timer.Frequency == DivNClockFrequency, 110 changeCallback: (_, value) => timer.Frequency = value ? DivNClockFrequency : lowPowerFrequency) 111 .WithFlag(8, out timerClockEnabled, name: "TIM_CLK_EN", 112 writeCallback: (_, __) => SetTimerEnabled()) 113 .If(extendedTimer) 114 .Then(r => r 115 .WithFlag(9, name: "TIM_IN3_EVENT_FALL_EN", 116 valueProviderCallback: _ => CallForConnection(2, con => con.UseFallingEdge), 117 writeCallback: (_, value) => CallForConnection(2, con => con.UseFallingEdge = value)) 118 .WithFlag(10, name: "TIM_IN4_EVENT_FALL_EN", 119 valueProviderCallback: _ => CallForConnection(3, con => con.UseFallingEdge), 120 writeCallback: (_, value) => CallForConnection(3, con => con.UseFallingEdge = value)) 121 .WithFlag(11, name: "TIM_CAP_GPIO1_IRQ_EN", 122 valueProviderCallback: _ => CallForConnection(0, con => con.InterruptEnabled), 123 writeCallback: (_, value) => CallForConnection(0, con => con.InterruptEnabled = value)) 124 .WithFlag(12, name: "TIM_CAP_GPIO2_IRQ_EN", 125 valueProviderCallback: _ => CallForConnection(1, con => con.InterruptEnabled), 126 writeCallback: (_, value) => CallForConnection(1, con => con.InterruptEnabled = value)) 127 .WithFlag(13, name: "TIM_CAP_GPIO3_IRQ_EN", 128 valueProviderCallback: _ => CallForConnection(2, con => con.InterruptEnabled), 129 writeCallback: (_, value) => CallForConnection(2, con => con.InterruptEnabled = value)) 130 .WithFlag(14, name: "TIM_CAP_GPIO4_IRQ_EN", 131 valueProviderCallback: _ => CallForConnection(3, con => con.InterruptEnabled), 132 writeCallback: (_, value) => CallForConnection(3, con => con.InterruptEnabled = value)) 133 .WithReservedBits(15, 17)) 134 .Else(r => r.WithReservedBits(9, 23)); 135 136 Registers.CounterValue.Define(this) 137 .WithValueField(0, 24, FieldMode.Read, name: "TIM_TIMER_VALUE", 138 valueProviderCallback: _ => GetTimerValue()) 139 .WithReservedBits(24, 8); 140 141 Registers.Status.Define(this) 142 .WithFlag(0, FieldMode.Read, name: "TIM_IN1_STATE", 143 valueProviderCallback: _ => CallForConnection(0, con => con.Value)) 144 .WithFlag(1, FieldMode.Read, name: "TIM_IN2_STATE", 145 valueProviderCallback: _ => CallForConnection(1, con => con.Value)) 146 .WithTag("TIM_ONESHOT_PHASE", 2, 2) 147 .If(extendedTimer) 148 .Then(r => r 149 .WithFlag(4, FieldMode.Read, name: "TIM_GPIO1_EVENT_PENDING", 150 valueProviderCallback: _ => CallForConnection(0, con => con.EventTriggered)) 151 .WithFlag(5, FieldMode.Read, name: "TIM_GPIO2_EVENT_PENDING", 152 valueProviderCallback: _ => CallForConnection(1, con => con.EventTriggered)) 153 .WithFlag(6, FieldMode.Read, name: "TIM_GPIO3_EVENT_PENDING", 154 valueProviderCallback: _ => CallForConnection(2, con => con.EventTriggered)) 155 .WithFlag(7, FieldMode.Read, name: "TIM_GPIO4_EVENT_PENDING", 156 valueProviderCallback: _ => CallForConnection(3, con => con.EventTriggered))) 157 .Else(r => r.WithReservedBits(4, 4)) 158 .WithFlag(8, FieldMode.Read, name: "TIM_IRQ_STATUS", 159 valueProviderCallback: _ => interruptTriggered) 160 .WithTaggedFlag("TIM_TIMER_BUSY", 9) 161 .WithTaggedFlag("TIM_PWM_BUSY", 10) 162 .WithFlag(11, FieldMode.Read, name: "TIM_SWITCHED_TO_DIVN_CLK", 163 valueProviderCallback: _ => timer.Frequency == DivNClockFrequency) 164 .If(extendedTimer) 165 .Then(r => r 166 .WithFlag(12, FieldMode.Read, name: "TIM_IN3_STATE", 167 valueProviderCallback: _ => CallForConnection(2, con => con.Value)) 168 .WithFlag(13, FieldMode.Read, name: "TIM_IN4_STATE", 169 valueProviderCallback: _ => CallForConnection(3, con => con.Value)) 170 .WithReservedBits(14, 18)) 171 .Else(r => r.WithReservedBits(12, 20)); 172 173 Registers.GPIO1Selection.Define(this) 174 .WithTag("TIM_GPIO1_CONF", 0, 6) 175 .WithReservedBits(6, 26); 176 177 Registers.GPIO2Selection.Define(this) 178 .WithTag("TIM_GPIO2_CONF", 0, 6) 179 .WithReservedBits(6, 26); 180 181 Registers.Settings.Define(this) 182 .WithValueField(0, 24, out timerLimit, name: "TIM_RELOAD", 183 writeCallback: (_, value) => 184 { 185 timer.Limit = value; 186 if(timer.Direction == Direction.Descending) 187 { 188 timer.ResetValue(); 189 } 190 }) 191 .WithValueField(24, 5, name: "TIM_PRESCALER", 192 valueProviderCallback: _ => (ulong)timer.Divider - 1, 193 writeCallback: (_, value) => timer.Divider = (int)value + 1) 194 .WithReservedBits(29, 3); 195 196 Registers.ShotDuration.Define(this) 197 .WithTag("TIM_SHOTWIDTH", 0, 24) 198 .WithReservedBits(24, 8); 199 200 Registers.EventValueGPIO1.Define(this) 201 .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO1", 202 valueProviderCallback: _ => CallForConnection(0, con => con.CaptureTimestamp)) 203 .WithReservedBits(24, 8); 204 205 Registers.EventValueGPIO2.Define(this) 206 .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO2", 207 valueProviderCallback: _ => CallForConnection(1, con => con.CaptureTimestamp)) 208 .WithReservedBits(24, 8); 209 210 Registers.Prescaler.Define(this) 211 .WithValueField(0, 5, FieldMode.Read, name: "TIM_PRESCALER_VAL", 212 valueProviderCallback: _ => (ulong)timer.Divider - 1) 213 .WithReservedBits(5, 27); 214 215 Registers.PWMControl.Define(this) 216 .WithTag("TIM_PWM_FREQ", 0, 16) 217 .WithTag("TIM_PWM_DC", 16, 16); 218 219 if(extendedTimer) 220 { 221 Registers.GPIO3Selection.Define(this) 222 .WithTag("TIM_GPIO3_CONF", 0, 6) 223 .WithReservedBits(6, 26); 224 225 Registers.GPIO4Selection.Define(this) 226 .WithTag("TIM_GPIO4_CONF", 0, 6) 227 .WithReservedBits(6, 26); 228 229 Registers.EventValueGPIO3.Define(this) 230 .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO3", 231 valueProviderCallback: _ => CallForConnection(2, con => con.CaptureTimestamp)) 232 .WithReservedBits(24, 8); 233 234 Registers.EventValueGPIO4.Define(this) 235 .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO4", 236 valueProviderCallback: _ => CallForConnection(3, con => con.CaptureTimestamp)) 237 .WithReservedBits(24, 8); 238 239 Registers.GPIOEventClear.Define(this) 240 .WithFlag(0, FieldMode.Write, name: "TIM_CLEAR_GPIO1_EVENT", 241 writeCallback: (_, value) => CallForConnection(0, con => ClearGPIOEvent(con, value))) 242 .WithFlag(1, FieldMode.Write, name: "TIM_CLEAR_GPIO2_EVENT", 243 writeCallback: (_, value) => CallForConnection(1, con => ClearGPIOEvent(con, value))) 244 .WithFlag(2, FieldMode.Write, name: "TIM_CLEAR_GPIO3_EVENT", 245 writeCallback: (_, value) => CallForConnection(2, con => ClearGPIOEvent(con, value))) 246 .WithFlag(3, FieldMode.Write, name: "TIM_CLEAR_GPIO4_EVENT", 247 writeCallback: (_, value) => CallForConnection(3, con => ClearGPIOEvent(con, value))) 248 .WithReservedBits(4, 28); 249 } 250 251 (extendedTimer ? Registers.InterruptClearExtended : Registers.InterruptClear).Define(this) 252 .WithFlag(0, FieldMode.Write, name: "TIM_CLEAR_IRQ", 253 writeCallback: (_, __) => 254 { 255 interruptTriggered = false; 256 UpdateInterrupts(); 257 }) 258 .WithReservedBits(1, 31); 259 } 260 GetTimerValue()261 private ulong GetTimerValue() 262 { 263 if(machine.GetSystemBus(this).TryGetCurrentCPU(out var cpu)) 264 { 265 cpu.SyncTime(); 266 } 267 268 return timer.Value; 269 } 270 UpdateInterrupts()271 private void UpdateInterrupts() 272 { 273 if(!timer.Enabled) 274 { 275 IRQ.Unset(); 276 CaptureIRQ.Unset(); 277 return; 278 } 279 280 var timerIrqValue = interruptEnabled.Value && interruptTriggered; 281 this.DebugLog("{0} interrupt", timerIrqValue ? "Setting" : "Unsetting"); 282 IRQ.Set(timerIrqValue); 283 284 if(extendedTimer) 285 { 286 var gpioIrqValue = false; 287 foreach(var connection in connections) 288 { 289 gpioIrqValue |= connection.InterruptEnabled && connection.EventTriggered; 290 } 291 292 this.DebugLog("{0} capture interrupt", gpioIrqValue ? "Setting" : "Unsetting"); 293 CaptureIRQ.Set(gpioIrqValue); 294 } 295 else 296 { 297 CaptureIRQ.Unset(); 298 } 299 } 300 SetTimerEnabled()301 private void SetTimerEnabled() 302 { 303 var enabled = timerEnabled.Value && timerClockEnabled.Value; 304 timer.Enabled = enabled; 305 } 306 CallForConnection(int index, Action<GPIOConnection> callback, bool logMessage = false)307 private void CallForConnection(int index, Action<GPIOConnection> callback, bool logMessage = false) 308 { 309 if(!IsValidConnection(index, logMessage)) 310 { 311 return; 312 } 313 314 callback(connections[index]); 315 } 316 CallForConnection(int index, Func<GPIOConnection, T> callback, bool logMessage = false)317 private T CallForConnection<T>(int index, Func<GPIOConnection, T> callback, bool logMessage = false) 318 { 319 if(!IsValidConnection(index, logMessage)) 320 { 321 return default(T); 322 } 323 324 return callback(connections[index]); 325 } 326 327 [MethodImpl(MethodImplOptions.AggressiveInlining)] IsValidConnection(int index, bool logMessage = true)328 private bool IsValidConnection(int index, bool logMessage = true) 329 { 330 if(index < 0 || index >= connections.Length) 331 { 332 if(logMessage) 333 { 334 this.WarningLog("GPIO connection {0} is out of range of [0;{1})", index, connections.Length); 335 } 336 337 return false; 338 } 339 return true; 340 } 341 ClearGPIOEvent(GPIOConnection connection, bool value)342 private void ClearGPIOEvent(GPIOConnection connection, bool value) 343 { 344 if(!value) 345 { 346 return; 347 } 348 349 connection.EventTriggered = false; 350 UpdateInterrupts(); 351 } 352 353 private readonly LimitTimer timer; 354 private readonly GPIOConnection[] connections; 355 356 private readonly long lowPowerFrequency; 357 private readonly bool extendedTimer; 358 359 private bool interruptTriggered; 360 361 private IFlagRegisterField interruptEnabled; 362 private IFlagRegisterField timerEnabled; 363 private IFlagRegisterField timerClockEnabled; 364 private IFlagRegisterField freeRunEnabled; 365 366 private IValueRegisterField timerLimit; 367 368 private const long DefaultLowPowerFrequency = 32000; 369 private const long DivNClockFrequency = 32000000; 370 private const long FreeRunLimit = (1 << 24) - 1; 371 372 private const int DefaultGPIOConnections = 2; 373 private const int ExtendedGPIOConnections = 4; 374 375 private enum Registers 376 { 377 Control = 0x00, // TIMER_CTRL_REG 378 CounterValue = 0x04, // TIMER_TIMER_VAL_REG 379 Status = 0x08, // TIMER_STATUS_REG 380 GPIO1Selection = 0x0C, // TIMER_GPIO1_CONF_REG 381 GPIO2Selection = 0x10, // TIMER_GPIO2_CONF_REG 382 Settings = 0x14, // TIMER_SETTINGS_REG 383 ShotDuration = 0x18, // TIMER_SHOTWIDTH_REG 384 // Gap 385 EventValueGPIO1 = 0x20, // TIMER_CAPTURE_GPIO1_REG 386 EventValueGPIO2 = 0x24, // TIMER_CAPTURE_GPIO2_REG 387 Prescaler = 0x28, // TIMER_PRESCALER_VAL_REG 388 PWMControl = 0x2C, // TIMER_PWM_CTRL_REG 389 // Gap 390 InterruptClear = 0x34, // TIMER_CLEAR_IRQ_REG 391 392 // Registers for extended timer version 393 GPIO3Selection = 0x34, // TIMER_GPIO3_CONF_REG 394 GPIO4Selection = 0x38, // TIMER_GPIO4_CONF_REG 395 EventValueGPIO3 = 0x3C, // TIMER_CAPTURE_GPIO3_REG 396 EventValueGPIO4 = 0x40, // TIMER_CAPTURE_GPIO4_REG 397 GPIOEventClear = 0x44, // TIMER_CLEAR_GPIO_EVENT_REG 398 InterruptClearExtended = 0x48, // TIMER_CLEAR_IRQ_REG 399 } 400 401 private class GPIOConnection 402 { GPIOConnection(RenesasDA14_GPT owner)403 public GPIOConnection(RenesasDA14_GPT owner) 404 { 405 this.owner = owner; 406 } 407 Reset()408 public void Reset() 409 { 410 Enabled = false; 411 InterruptEnabled = false; 412 EventTriggered = false; 413 Value = false; 414 UseFallingEdge = false; 415 CaptureTimestamp = 0; 416 } 417 SetValue(bool value)418 public void SetValue(bool value) 419 { 420 if(!Enabled) 421 { 422 return; 423 } 424 425 if(UseFallingEdge) 426 { 427 EventTriggered = Value && !value; 428 } 429 else 430 { 431 EventTriggered = !Value && value; 432 } 433 434 Value = value; 435 if(EventTriggered) 436 { 437 CaptureTimestamp = owner.GetTimerValue(); 438 } 439 owner.UpdateInterrupts(); 440 } 441 442 public bool Enabled { get; set; } 443 444 public bool EventTriggered { get; set; } 445 446 public bool Value { get; private set; } 447 public ulong CaptureTimestamp { get; private set; } 448 449 public bool InterruptEnabled { get; set; } 450 public bool UseFallingEdge { get; set; } 451 452 private readonly RenesasDA14_GPT owner; 453 } 454 } 455 } 456