1 // 2 // Copyright (c) 2010-2023 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.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 15 namespace Antmicro.Renode.Peripherals.Miscellaneous 16 { 17 public sealed class NRF52840_PPI : BasicDoubleWordPeripheral, IKnownSize 18 { NRF52840_PPI(IMachine machine)19 public NRF52840_PPI(IMachine machine) : base(machine) 20 { 21 for(var i = 0; i < Channels; i++) 22 { 23 var j = i; 24 eventCallbacks[i] = offset => EventReceived(j, offset); 25 } 26 DefineRegisters(); 27 Reset(); 28 } 29 Reset()30 public override void Reset() 31 { 32 base.Reset(); 33 for(var i = 0; i < ChannelGroups; i++) 34 { 35 channelGroupEnabled[i] = false; 36 } 37 for(var i = 0; i < ConfigurableChannels; i++) 38 { 39 eventEndpoint[i] = 0; 40 taskEndpoint[i] = 0; 41 } 42 for(var i = 0; i < Channels; i++) 43 { 44 forkEndpoint[i] = 0; 45 } 46 foreach(var sender in registeredEventSenders) 47 { 48 sender.Provider.EventTriggered -= eventCallbacks[sender.Channel]; 49 } 50 registeredEventSenders.Clear(); 51 initialized = false; 52 } 53 WriteDoubleWord(long offset, uint value)54 public override void WriteDoubleWord(long offset, uint value) 55 { 56 if(!initialized) 57 { 58 DefinePreprogrammedChannels(); 59 initialized = true; 60 } 61 base.WriteDoubleWord(offset, value); 62 } 63 64 public long Size => 0x1000; 65 DefineRegisters()66 private void DefineRegisters() 67 { 68 for(var i = 0; i < ChannelGroups; i++) 69 { 70 var j = i; 71 ((Registers)((int)Registers.ChannelGroup0Enable + i * 8)).Define(this, name: "TASKS_CHG[n].EN") 72 .WithFlag(0, FieldMode.Write, name: "EN", writeCallback: (_, value) => 73 { 74 if(value) 75 { 76 channelGroupEnabled[j] = true; 77 } 78 }) 79 ; 80 81 ((Registers)((int)Registers.ChannelGroup0Disable + i * 8)).Define(this, name: "TASKS_CHG[n].DIS") 82 .WithFlag(0, FieldMode.Write, name: "DIS", writeCallback: (_, value) => 83 { 84 if(value) 85 { 86 channelGroupEnabled[j] = false; 87 } 88 }) 89 ; 90 } 91 92 Registers.ChannelEnable.Define(this, name: "CHEN") 93 .WithFlags(0, 32, out channelEnabled, name: "CH[i]") 94 ; 95 96 Registers.ChannelEnableSet.Define(this, name: "CHENSET") 97 .WithFlags(0, 32, name: "CH[i]", writeCallback: (i, _, value) => 98 { 99 if(value) 100 { 101 this.Log(LogLevel.Noisy, "PPI enable channel {0}", i); 102 channelEnabled[i].Value = true; 103 } 104 }, valueProviderCallback: (i, _) => channelEnabled[i].Value) 105 ; 106 107 Registers.ChannelEnableClear.Define(this, name: "CHENCLR") 108 .WithFlags(0, 32, name: "CH[i]", writeCallback: (i, _, value) => 109 { 110 if(value) 111 { 112 this.Log(LogLevel.Noisy, "PPI disable channel {0}", i); 113 channelEnabled[i].Value = false; 114 } 115 }, valueProviderCallback: (i, _) => channelEnabled[i].Value) 116 ; 117 118 for(var i = 0; i < ConfigurableChannels; i++) 119 { 120 var j = i; 121 122 ((Registers)((int)Registers.Channel0EventEndpoint + i * 8)).Define(this, name: "CH[n].EEP") 123 .WithValueField(0, 32, changeCallback: (oldValue, newValue) => UpdateEventEndpoint((uint)oldValue, (uint)newValue, j)) 124 ; 125 126 ((Registers)((int)Registers.Channel0TaskEndpoint + i * 8)).Define(this, name: "CH[n].TEP") 127 .WithValueField(0, 32, changeCallback: (_, value) => 128 { 129 taskEndpoint[j] = (uint)value; 130 this.Log(LogLevel.Noisy, "Connected channel {0} to trigger a task at 0x{1:X}", j, taskEndpoint[j]); 131 }) 132 ; 133 } 134 135 for(var i = 0; i < ChannelGroups; i++) 136 { 137 var j = i; 138 ((Registers)((int)Registers.ChannelGroup0 + i * 4)).Define(this, name: "CHG[n]") 139 .WithFlags(0, 32, out channelGroups[j]) 140 ; 141 } 142 143 for(var i = 0; i < Channels; i++) 144 { 145 var j = i; 146 147 ((Registers)((int)Registers.Fork0TaskEndpoint + i * 4)).Define(this, name: "FORK[n].TEP") 148 .WithValueField(0, 32, changeCallback: (_, value) => 149 { 150 forkEndpoint[j] = (uint)value; 151 this.Log(LogLevel.Noisy, "Connected channel {0} to trigger a fork task at 0x{1:X}", j, taskEndpoint[j]); 152 }) 153 ; 154 } 155 } 156 DefinePreprogrammedChannels()157 private void DefinePreprogrammedChannels() 158 { 159 // Predefined channels: 160 var entries = new List<Tuple<uint, uint>> 161 { 162 // Timer0 Compare0 -> Radio TxEn 163 Tuple.Create(0x40008140u, 0x40001000u), 164 // Timer0 Compare0 -> Radio RxEn 165 Tuple.Create(0x40008140u, 0x40001004u), 166 // Timer0 Compare1 -> Radio Disable 167 Tuple.Create(0x40008144u, 0x40001010u), 168 // Radio BCMatch -> AAR Start 169 Tuple.Create(0x40001128u, 0x4000F000u), 170 // Radio Ready -> CCM KSGen 171 Tuple.Create(0x40001100u, 0x4000F000u), //this address points both to AAR Start and CCM KSGen 172 // Radio Address -> CCM Crypt 173 Tuple.Create(0x40001104u, 0x4000F004u), 174 // Radio Address -> Timer0 Capture1 175 Tuple.Create(0x40001104u, 0x40008044u), 176 // Radio End -> Timer0 Capture2 177 Tuple.Create(0x4000110Cu, 0x40008048u), 178 // RTC0 Compare0 -> Radio TxEn 179 Tuple.Create(0x4000B140u, 0x40001000u), 180 // RTC0 Compare0 -> Radio RxEn 181 Tuple.Create(0x4000B140u, 0x40001004u), 182 // RTC0 Compare0 -> Timer0 Clear 183 Tuple.Create(0x4000B140u, 0x4000800Cu), 184 // RTC0 Compare0 -> Timer0 Start 185 Tuple.Create(0x4000B140u, 0x40008000u), 186 }; 187 for(var i = ConfigurableChannels; i < Channels; i++) 188 { 189 var entry = entries[i - ConfigurableChannels]; 190 UpdateEventEndpoint(0, entry.Item1, i); 191 taskEndpoint[i] = entry.Item2; 192 } 193 } 194 UpdateEventEndpoint(uint oldValue, uint newValue, int eventId)195 private void UpdateEventEndpoint(uint oldValue, uint newValue, int eventId) 196 { 197 if(oldValue != 0) 198 { 199 var target = sysbus.WhatPeripheralIsAt(oldValue); 200 if(target is INRFEventProvider nrfTarget) 201 { 202 //todo: how to do it on reset? 203 nrfTarget.EventTriggered -= eventCallbacks[eventId]; 204 registeredEventSenders.Remove(EventEntry.Create(nrfTarget, eventId)); 205 this.Log(LogLevel.Debug, "Disconnected channel {1} from event 0x{0:X}", oldValue, eventId); 206 } 207 else 208 { 209 this.Log(LogLevel.Error, "Failed to unregister PPI from 0x{0:X} for channel {1}", oldValue, eventId); 210 } 211 } 212 eventEndpoint[eventId] = newValue; 213 if(newValue != 0) 214 { 215 var target = sysbus.WhatPeripheralIsAt(newValue); 216 if(target is INRFEventProvider nrfTarget) 217 { 218 nrfTarget.EventTriggered += eventCallbacks[eventId]; 219 registeredEventSenders.Add(EventEntry.Create(nrfTarget, eventId)); 220 this.Log(LogLevel.Debug, "Connected channel {1} to event 0x{0:X}", newValue, eventId); 221 } 222 else 223 { 224 this.Log(LogLevel.Error, "Failed to register PPI from 0x{0:X} for channel {1}", newValue, eventId); 225 } 226 } 227 } 228 EventReceived(int id, uint offset)229 private void EventReceived(int id, uint offset) 230 { 231 if((eventEndpoint[id] & EventOffsetMask) != offset) 232 { 233 // this happens when we are registered for an event in the peripheral, but we receive a different one 234 return; 235 } 236 if(!channelEnabled[id].Value) 237 { 238 var foundGroup = false; 239 // if the channel is disabled, it may be enabled by a group 240 for(var i = 0; i < ChannelGroups; i++) 241 { 242 if(channelGroupEnabled[i] && channelGroups[i][id].Value) 243 { 244 foundGroup = true; 245 break; 246 } 247 } 248 if(!foundGroup) 249 { 250 this.Log(LogLevel.Noisy, "Received an event on channel {0} from 0x{1:X}, but it's disabled.", id, eventEndpoint[id]); 251 return; 252 } 253 } 254 if(taskEndpoint[id] != 0) 255 { 256 this.Log(LogLevel.Noisy, "Received an event on channel {0} from 0x{1:X}. Triggering task at 0x{2:X}", id, eventEndpoint[id], taskEndpoint[id]); 257 machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => sysbus.WriteDoubleWord(taskEndpoint[id], 1)); 258 } 259 else 260 { 261 this.Log(LogLevel.Warning, "Received an event on channel {0} from 0x{1:X}, but there is no task configured", id, eventEndpoint[id]); 262 } 263 if(forkEndpoint[id] != 0) 264 { 265 this.Log(LogLevel.Noisy, "Received an event on channel {0} from 0x{1:X}. Triggering fork task at 0x{2:X}", id, eventEndpoint[id], forkEndpoint[id]); 266 machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => sysbus.WriteDoubleWord(forkEndpoint[id], 1)); 267 } 268 } 269 270 private bool initialized; // should not be reset - used for delayed configuration after the machine is created 271 272 private readonly Action<uint>[] eventCallbacks = new Action<uint>[Channels]; //todo reset 273 private uint[] eventEndpoint = new uint[Channels]; 274 private uint[] taskEndpoint = new uint[Channels]; 275 private uint[] forkEndpoint = new uint[Channels]; 276 private bool[] channelGroupEnabled = new bool[ChannelGroups]; 277 278 private IFlagRegisterField[][] channelGroups = new IFlagRegisterField[ChannelGroups][]; 279 private IFlagRegisterField[] channelEnabled = new IFlagRegisterField[Channels]; 280 281 private HashSet<EventEntry> registeredEventSenders = new HashSet<EventEntry>(); 282 283 private const int EventOffsetMask = 0xFFF; 284 private const int ChannelGroups = 6; 285 private const int ConfigurableChannels = 20; 286 private const int Channels = 32; 287 288 private struct EventEntry 289 { CreateAntmicro.Renode.Peripherals.Miscellaneous.NRF52840_PPI.EventEntry290 public static EventEntry Create(INRFEventProvider provider, int channel) 291 { 292 return new EventEntry { Provider = provider, Channel = channel }; 293 } 294 public INRFEventProvider Provider; 295 public int Channel; 296 } 297 298 private enum Registers 299 { 300 ChannelGroup0Enable = 0x000, 301 ChannelGroup0Disable = 0x004, 302 ChannelGroup1Enable = 0x008, 303 ChannelGroup1Disable = 0x00C, 304 ChannelGroup2Enable = 0x010, 305 ChannelGroup2Disable = 0x014, 306 ChannelGroup3Enable = 0x018, 307 ChannelGroup3Disable = 0x01C, 308 ChannelGroup4Enable = 0x020, 309 ChannelGroup4Disable = 0x024, 310 ChannelGroup5Enable = 0x028, 311 ChannelGroup5Disable = 0x02C, 312 ChannelEnable = 0x500, 313 ChannelEnableSet = 0x504, 314 ChannelEnableClear = 0x508, 315 Channel0EventEndpoint = 0x510, 316 Channel0TaskEndpoint = 0x514, 317 Channel1EventEndpoint = 0x518, 318 Channel1TaskEndpoint = 0x51C, 319 Channel2EventEndpoint = 0x520, 320 Channel2TaskEndpoint = 0x524, 321 Channel3EventEndpoint = 0x528, 322 Channel3TaskEndpoint = 0x52C, 323 Channel4EventEndpoint = 0x530, 324 Channel4TaskEndpoint = 0x534, 325 Channel5EventEndpoint = 0x538, 326 Channel5TaskEndpoint = 0x53C, 327 Channel6EventEndpoint = 0x540, 328 Channel6TaskEndpoint = 0x544, 329 Channel7EventEndpoint = 0x548, 330 Channel7TaskEndpoint = 0x54C, 331 Channel8EventEndpoint = 0x550, 332 Channel8TaskEndpoint = 0x554, 333 Channel9EventEndpoint = 0x558, 334 Channel9TaskEndpoint = 0x55C, 335 Channel10EventEndpoint = 0x560, 336 Channel10TaskEndpoint = 0x564, 337 Channel11EventEndpoint = 0x568, 338 Channel11TaskEndpoint = 0x56C, 339 Channel12EventEndpoint = 0x570, 340 Channel12TaskEndpoint = 0x574, 341 Channel13EventEndpoint = 0x578, 342 Channel13TaskEndpoint = 0x57C, 343 Channel14EventEndpoint = 0x580, 344 Channel14TaskEndpoint = 0x584, 345 Channel15EventEndpoint = 0x588, 346 Channel15TaskEndpoint = 0x58C, 347 Channel16EventEndpoint = 0x590, 348 Channel16TaskEndpoint = 0x594, 349 Channel17EventEndpoint = 0x598, 350 Channel17TaskEndpoint = 0x59c, 351 Channel18EventEndpoint = 0x5A0, 352 Channel18TaskEndpoint = 0x5A4, 353 Channel19EventEndpoint = 0x5A8, 354 Channel19TaskEndpoint = 0x5AC, 355 ChannelGroup0 = 0x800, 356 ChannelGroup1 = 0x804, 357 ChannelGroup2 = 0x808, 358 ChannelGroup3 = 0x80C, 359 ChannelGroup4 = 0x810, 360 ChannelGroup5 = 0x814, 361 Fork0TaskEndpoint = 0x910, 362 Fork1TaskEndpoint = 0x914, 363 Fork2TaskEndpoint = 0x918, 364 Fork3TaskEndpoint = 0x91C, 365 Fork4TaskEndpoint = 0x920, 366 Fork5TaskEndpoint = 0x924, 367 Fork6TaskEndpoint = 0x928, 368 Fork7TaskEndpoint = 0x92C, 369 Fork8TaskEndpoint = 0x930, 370 Fork9TaskEndpoint = 0x934, 371 Fork10TaskEndpoint = 0x938, 372 Fork11TaskEndpoint = 0x93C, 373 Fork12TaskEndpoint = 0x940, 374 Fork13TaskEndpoint = 0x944, 375 Fork14TaskEndpoint = 0x948, 376 Fork15TaskEndpoint = 0x94C, 377 Fork16TaskEndpoint = 0x950, 378 Fork17TaskEndpoint = 0x954, 379 Fork18TaskEndpoint = 0x958, 380 Fork19TaskEndpoint = 0x95C, 381 Fork20TaskEndpoint = 0x960, 382 Fork21TaskEndpoint = 0x964, 383 Fork22TaskEndpoint = 0x968, 384 Fork23TaskEndpoint = 0x96C, 385 Fork24TaskEndpoint = 0x970, 386 Fork25TaskEndpoint = 0x974, 387 Fork26TaskEndpoint = 0x978, 388 Fork27TaskEndpoint = 0x97C, 389 Fork28TaskEndpoint = 0x980, 390 Fork29TaskEndpoint = 0x984, 391 Fork30TaskEndpoint = 0x988, 392 Fork31TaskEndpoint = 0x98C, 393 } 394 } 395 } 396