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