1 // 2 // Copyright (c) 2010-2018 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Renode.Peripherals.Bus; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Time; 14 15 namespace Antmicro.Renode.Peripherals.Timers 16 { 17 public class TexasInstrumentsTimer : IDoubleWordPeripheral, IKnownSize 18 { TexasInstrumentsTimer(IMachine machine)19 public TexasInstrumentsTimer(IMachine machine) 20 { 21 IRQ12 = new GPIO(); 22 IRQ34 = new GPIO(); 23 24 timer12 = new LimitTimer(machine.ClockSource, 24000000, this, nameof(timer12), direction: Direction.Ascending, eventEnabled: true); // clocked from AUXCLK (default 24 MHz) 25 timer34 = new LimitTimer(machine.ClockSource, 24000000, this, nameof(timer34), direction: Direction.Ascending, eventEnabled: true); 26 timer12.LimitReached += () => OnTimerLimitReached(timer12); 27 timer34.LimitReached += () => OnTimerLimitReached(timer34); 28 29 timerControlRegister = new DoubleWordRegister(this); 30 timerGlobalControlRegister = new DoubleWordRegister(this, 3); 31 timerInterruptControlAndStatusRegister = new DoubleWordRegister(this, 0x10001); // the driver expects interrupts to be enabled; inconsistent with timer user's guixde 32 33 timerControlRegister.DefineEnumField<OperationMode>(6, 2, changeCallback: (oldValue, newValue) => OnEnableModeChanged(oldValue, newValue, timer12)); 34 timerControlRegister.DefineEnumField<OperationMode>(22, 2, changeCallback: (oldValue, newValue) => OnEnableModeChanged(oldValue, newValue, timer34)); 35 resetOnRead12 = timerControlRegister.DefineFlagField(10); 36 resetOnRead34 = timerControlRegister.DefineFlagField(26); 37 38 timerGlobalControlRegister.DefineFlagField(0, changeCallback: (oldValue, newValue) => 39 { 40 if(!newValue) 41 { 42 timer12.Reset(); 43 } 44 }); 45 timerGlobalControlRegister.DefineFlagField(1, changeCallback: (oldValue, newValue) => 46 { 47 if(!newValue) 48 { 49 timer34.Reset(); 50 } 51 }); 52 53 timerGlobalControlRegister.DefineEnumField<TimerMode>(2, 2, changeCallback: OnTimerModeChanged); 54 55 timerGlobalControlRegister.DefineValueField(8, 4, changeCallback: (oldValue, newValue) => timer34.Divider = (int)newValue); 56 interruptEnable12 = timerInterruptControlAndStatusRegister.DefineFlagField(0); 57 interruptEnable34 = timerInterruptControlAndStatusRegister.DefineFlagField(16); 58 interruptOccurred12 = timerInterruptControlAndStatusRegister.DefineFlagField(3); 59 interruptOccurred34 = timerInterruptControlAndStatusRegister.DefineFlagField(19); 60 61 Reset(); 62 } 63 WriteDoubleWord(long offset, uint value)64 public void WriteDoubleWord(long offset, uint value) 65 { 66 switch((Registers)offset) 67 { 68 case Registers.TimerCounter12: 69 CounterRegister12 = value; 70 Update(); 71 break; 72 case Registers.TimerCounter34: 73 CounterRegister34 = value; 74 Update(); 75 break; 76 case Registers.TimerControl: 77 timerControlRegister.Write(offset, value); 78 Update(); 79 break; 80 case Registers.TimerGlobalControl: 81 timerGlobalControlRegister.Write(offset, value); 82 break; 83 case Registers.TimerPeriod12: 84 timerPeriod12 = value; 85 UpdateTimerLimits(); 86 Update(); 87 break; 88 case Registers.TimerPeriod34: 89 timerPeriod34 = value; 90 UpdateTimerLimits(); 91 Update(); 92 break; 93 case Registers.TimerInterruptControlAndStatus: 94 timerInterruptControlAndStatusRegister.Write(offset, value); 95 break; 96 default: 97 this.LogUnhandledWrite(offset, value); 98 break; 99 } 100 } 101 ReadDoubleWord(long offset)102 public uint ReadDoubleWord(long offset) 103 { 104 switch((Registers)offset) 105 { 106 case Registers.PeripheralIdentification12: 107 return peripheralIdentification; 108 case Registers.TimerCounter12: 109 if(resetOnRead12.Value && timerMode == TimerMode.Unchained32) // only available in 32 bit unchained mode 110 { 111 var value = CounterRegister12; 112 CounterRegister12 = 0; 113 return value; 114 } 115 return CounterRegister12; 116 case Registers.TimerCounter34: 117 if(resetOnRead34.Value && timerMode == TimerMode.Unchained32) // only available in 32 bit unchained mode 118 { 119 var value = CounterRegister34; 120 CounterRegister34 = 0; 121 return value; 122 } 123 return CounterRegister34; 124 case Registers.TimerControl: 125 return timerControlRegister.Read(); 126 case Registers.TimerGlobalControl: 127 return timerGlobalControlRegister.Read(); 128 case Registers.TimerPeriod12: 129 return timerPeriod12; 130 case Registers.TimerPeriod34: 131 return timerPeriod34; 132 case Registers.TimerInterruptControlAndStatus: 133 return timerInterruptControlAndStatusRegister.Read(); 134 default: 135 this.LogUnhandledRead(offset); 136 return 0; 137 } 138 } 139 OnTimerLimitReached(LimitTimer timer)140 public void OnTimerLimitReached(LimitTimer timer) 141 { 142 if(timer == timer12 && interruptEnable12.Value) 143 { 144 interruptOccurred12.Value = true; 145 Update(); 146 } 147 else if(timer == timer34 && interruptEnable34.Value) 148 { 149 interruptOccurred34.Value = true; 150 Update(); 151 } 152 } 153 Reset()154 public void Reset() 155 { 156 timer12.Reset(); 157 timer34.Reset(); 158 timerControlRegister.Reset(); 159 timerGlobalControlRegister.Reset(); 160 timerInterruptControlAndStatusRegister.Reset(); 161 } 162 163 public long Size 164 { 165 get 166 { 167 return 0x200; 168 } 169 } 170 171 public GPIO IRQ12 172 { 173 get; 174 private set; 175 } 176 177 public GPIO IRQ34 178 { 179 get; 180 private set; 181 } 182 UpdateTimerLimits()183 private void UpdateTimerLimits() 184 { 185 if(timerMode == TimerMode.GeneralPurpose64) 186 { 187 timer12.Limit = (((ulong)timerPeriod12) << 32) | timerPeriod34; 188 } 189 else 190 { 191 timer12.Limit = timerPeriod12; 192 timer34.Limit = timerPeriod34; 193 } 194 } 195 Update()196 private void Update() 197 { 198 if(interruptOccurred12.Value) 199 { 200 IRQ12.Blink(); 201 interruptOccurred12.Value = false; 202 } 203 else if(interruptOccurred34.Value) 204 { 205 IRQ34.Blink(); 206 interruptOccurred34.Value = false; 207 } 208 } 209 OnEnableModeChanged(OperationMode oldValue, OperationMode newValue, LimitTimer timer)210 private void OnEnableModeChanged(OperationMode oldValue, OperationMode newValue, LimitTimer timer) 211 { 212 switch(newValue) 213 { 214 case OperationMode.Disabled: 215 timer.Enabled = false; 216 break; 217 case OperationMode.Continuous: 218 case OperationMode.ContinuousReload: 219 timer.Mode = WorkMode.Periodic; 220 timer.Enabled = true; 221 timer.EventEnabled = true; 222 break; 223 case OperationMode.Once: 224 timer.Mode = WorkMode.OneShot; 225 timer.Enabled = true; 226 timer.EventEnabled = true; 227 break; 228 } 229 } 230 OnTimerModeChanged(TimerMode oldValue, TimerMode newValue)231 private void OnTimerModeChanged(TimerMode oldValue, TimerMode newValue) 232 { 233 timerMode = newValue; 234 switch(newValue) 235 { 236 case TimerMode.GeneralPurpose64: 237 timer34.Enabled = false; 238 break; 239 case TimerMode.Watchdog64: 240 case TimerMode.Chained32: 241 this.Log(LogLevel.Warning, "Unsupported TMS320 timer mode set: {0}", newValue); 242 break; 243 } 244 UpdateTimerLimits(); 245 } 246 247 private uint CounterRegister12 248 { 249 get 250 { 251 if(timerMode == TimerMode.GeneralPurpose64) 252 { 253 temporaryCounterRegister34 = (uint)(timer12.Value >> 32); 254 return (uint)(timer12.Value); 255 } 256 else 257 { 258 return (uint)timer12.Value; 259 260 } 261 } 262 set 263 { 264 if(timerMode == TimerMode.GeneralPurpose64) 265 { 266 timer12.Value &= ~0xffffffffUL; 267 timer12.Value |= value; 268 } 269 else 270 { 271 timer12.Value = value; 272 } 273 } 274 } 275 276 private uint CounterRegister34 277 { 278 get 279 { 280 if(timerMode == TimerMode.GeneralPurpose64) 281 { 282 return temporaryCounterRegister34; 283 } 284 else 285 { 286 return (uint)timer34.Value; 287 } 288 } 289 set 290 { 291 if(timerMode == TimerMode.GeneralPurpose64) 292 { 293 timer12.Value &= 0xffffffffL; 294 timer12.Value |= ((ulong)value << 32); 295 } 296 else 297 { 298 timer34.Value = value; 299 } 300 } 301 } 302 303 private uint temporaryCounterRegister34, timerPeriod12, timerPeriod34; 304 private readonly DoubleWordRegister timerControlRegister, timerGlobalControlRegister, timerInterruptControlAndStatusRegister; 305 private readonly IFlagRegisterField resetOnRead12, resetOnRead34, interruptEnable12, interruptEnable34, interruptOccurred12, interruptOccurred34; 306 private TimerMode timerMode; 307 private readonly LimitTimer timer12, timer34; 308 private const uint peripheralIdentification = 0x010701; 309 310 private enum Registers 311 { 312 PeripheralIdentification12 = 0x00, 313 EmulationManagement = 0x04, 314 TimerCounter12 = 0x10, 315 TimerCounter34 = 0x14, 316 TimerPeriod12 = 0x18, 317 TimerPeriod34 = 0x1c, 318 TimerControl = 0x20, 319 TimerGlobalControl = 0x24, 320 WatchdogTimerControl = 0x28, 321 TimerReload12 = 0x34, 322 TimerReload34 = 0x38, 323 TimerCapture12 = 0x3c, 324 TimerCapture34 = 0x40, 325 TimerInterruptControlAndStatus = 0x44, 326 } 327 328 private enum TimerMode 329 { 330 GeneralPurpose64 = 0x0, 331 Unchained32 = 0x1, 332 Watchdog64 = 0x2, 333 Chained32 = 0x3 334 } 335 336 private enum OperationMode 337 { 338 Disabled = 0x0, 339 Once = 0x1, 340 Continuous = 0x2, 341 ContinuousReload = 0x3 342 } 343 } 344 } 345 346