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 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 15 namespace Antmicro.Renode.Peripherals.GPIOPort 16 { 17 public class NRF52840_GPIOTasksEvents : BasicDoubleWordPeripheral, IKnownSize 18 { NRF52840_GPIOTasksEvents(IMachine machine, NRF52840_GPIO port0 = null, NRF52840_GPIO port1 = null)19 public NRF52840_GPIOTasksEvents(IMachine machine, NRF52840_GPIO port0 = null, NRF52840_GPIO port1 = null) : base(machine) 20 { 21 IRQ = new GPIO(); 22 DefineRegisters(); 23 24 ports = new [] { port0, port1 }; 25 if(port0 != null) 26 { 27 port0.PinChanged += OnPinChanged; 28 port0.Detect += OnDetect; 29 } 30 if(port1 != null) 31 { 32 port1.PinChanged += OnPinChanged; 33 port1.Detect += OnDetect; 34 } 35 36 pinToChannelMapping = new Dictionary<NRF52840_GPIO.Pin, Channel>(); 37 channels = new Channel[NumberOfChannels]; 38 for(var i = 0; i < channels.Length; i++) 39 { 40 channels[i] = new Channel(i, this); 41 } 42 } 43 Reset()44 public override void Reset() 45 { 46 base.Reset(); 47 foreach(var ch in channels) 48 { 49 ch.Reset(); 50 } 51 pinToChannelMapping.Clear(); 52 53 UpdateInterrupt(); 54 } 55 56 public GPIO IRQ { get; } 57 58 public long Size => 0x1000; 59 DefineRegisters()60 private void DefineRegisters() 61 { 62 Registers.TasksOut.DefineMany(this, NumberOfChannels, (register, idx) => { 63 register 64 .WithFlag(0, FieldMode.Write, name: "TASKS_OUT", 65 writeCallback: (_, val) => channels[idx].WritePin(val)) 66 .WithReservedBits(1, 31); 67 }); 68 69 Registers.TasksSet.DefineMany(this, NumberOfChannels, (register, idx) => { 70 register 71 .WithFlag(0, FieldMode.Write, name: "TASKS_SET", 72 writeCallback: (_, val) => { if(val) channels[idx].SetPin(); }) 73 .WithReservedBits(1, 31); 74 }); 75 76 Registers.TasksClear.DefineMany(this, NumberOfChannels, (register, idx) => { 77 register 78 .WithFlag(0, FieldMode.Write, name: "TASKS_CLR", 79 writeCallback: (_, val) => { if(val) channels[idx].ClearPin(); }) 80 .WithReservedBits(1, 31); 81 }); 82 83 Registers.EventsIn.DefineMany(this, NumberOfChannels, (register, idx) => { 84 register 85 .WithFlag(0, name: "EVENTS_IN", 86 valueProviderCallback: _ => channels[idx].EventPending, 87 writeCallback: (_, val) => channels[idx].EventPending = val) 88 .WithReservedBits(1, 31) 89 .WithWriteCallback((_, __) => UpdateInterrupt()); 90 }); 91 92 Registers.EventsPort.Define(this) 93 .WithFlag(0, out portInterruptPending) 94 .WithReservedBits(1, 31) 95 .WithWriteCallback((_, __) => UpdateInterrupt()) 96 ; 97 98 Registers.EnableInterrupt.Define(this) 99 .WithFlags(0, 8, name: "EVENT_IN", 100 valueProviderCallback: (idx, _) => channels[idx].EventEnabled, 101 writeCallback: (idx, _, val) => { if(val) channels[idx].EventEnabled = true; }) 102 .WithReservedBits(8, 23) 103 .WithFlag(31, out portInterruptEnabled, FieldMode.Read | FieldMode.Set, name: "PORT") 104 .WithWriteCallback((_, __) => UpdateInterrupt()) 105 ; 106 107 Registers.DisableInterrupt.Define(this) 108 .WithFlags(0, 8, name: "EVENT_IN", 109 valueProviderCallback: (idx, _) => channels[idx].EventEnabled, 110 writeCallback: (idx, _, val) => { if(val) channels[idx].EventEnabled = false; }) 111 .WithReservedBits(8, 23) 112 .WithFlag(31, FieldMode.Read | FieldMode.WriteOneToClear, name: "PORT", 113 valueProviderCallback: _ => portInterruptEnabled.Value, 114 writeCallback: (_, val) => { if(val) portInterruptEnabled.Value = false; }) 115 .WithWriteCallback((_, __) => UpdateInterrupt()) 116 ; 117 118 Registers.Configuration.DefineMany(this, NumberOfChannels, (register, idx) => { 119 register 120 .WithEnumField<DoubleWordRegister,Mode>(0, 2, name: "MODE", 121 valueProviderCallback: _ => channels[idx].Mode, 122 writeCallback: (_, val) => channels[idx].Mode = val) 123 .WithReservedBits(2, 6) 124 .WithValueField(8, 5, name: "PSEL", 125 valueProviderCallback: _ => channels[idx].SelectedPin, 126 writeCallback: (_, val) => channels[idx].SelectedPin = (uint)val) 127 .WithValueField(13, 1, name: "PORT", 128 valueProviderCallback: _ => channels[idx].SelectedPort, 129 writeCallback: (_, val) => channels[idx].SelectedPort = (uint)val) 130 .WithReservedBits(14, 2) 131 .WithEnumField<DoubleWordRegister, Polarity>(16, 2, name: "POLARITY", 132 valueProviderCallback: _ => channels[idx].Polarity, 133 writeCallback: (_, val) => channels[idx].Polarity = val) 134 .WithReservedBits(18, 2) 135 .WithFlag(20, name: "OUTINIT", 136 valueProviderCallback: _ => channels[idx].CurrentState, 137 writeCallback: (_, val) => channels[idx].CurrentState = val) 138 .WithReservedBits(21, 11) 139 .WithWriteCallback((_, __) => 140 { 141 pinToChannelMapping.Clear(); 142 UpdateInterrupt(); 143 }); 144 }); 145 } 146 TryGetChannel(NRF52840_GPIO.Pin pin, out Channel channel)147 private bool TryGetChannel(NRF52840_GPIO.Pin pin, out Channel channel) 148 { 149 if(pinToChannelMapping.TryGetValue(pin, out channel)) 150 { 151 return true; 152 } 153 154 foreach(var ch in channels) 155 { 156 if(pin.Id == ch.SelectedPin && pin.Parent == ports[ch.SelectedPort]) 157 { 158 pinToChannelMapping[pin] = ch; 159 channel = ch; 160 return true; 161 } 162 } 163 164 channel = null; 165 return false; 166 } 167 OnPinChanged(NRF52840_GPIO.Pin pin, bool value)168 private void OnPinChanged(NRF52840_GPIO.Pin pin, bool value) 169 { 170 if((pin.Direction != NRF52840_GPIO.PinDirection.Input && !pin.InputOverride) 171 || !TryGetChannel(pin, out var channel)) 172 { 173 return; 174 } 175 176 if(channel.Mode != Mode.Event) 177 { 178 channel.CurrentState = value; 179 return; 180 } 181 182 switch(channel.Polarity) 183 { 184 case Polarity.None: 185 channel.EventPending = false; 186 break; 187 188 case Polarity.LoToHi: 189 channel.EventPending = !channel.CurrentState && value; 190 break; 191 192 case Polarity.HiToLo: 193 channel.EventPending = channel.CurrentState && !value; 194 break; 195 196 case Polarity.Toggle: 197 channel.EventPending = channel.CurrentState != value; 198 break; 199 } 200 201 channel.CurrentState = value; 202 UpdateInterrupt(); 203 } 204 OnDetect()205 private void OnDetect() 206 { 207 portInterruptPending.Value = true; 208 UpdateInterrupt(); 209 } 210 UpdateInterrupt()211 private void UpdateInterrupt() 212 { 213 var flag = false; 214 foreach(var ch in channels) 215 { 216 portInterruptPending.Value |= ch.EventPending; 217 flag |= ch.EventPending && ch.EventEnabled; 218 } 219 220 flag |= portInterruptPending.Value && portInterruptEnabled.Value; 221 222 this.NoisyLog("Setting IRQ to {0}", flag); 223 IRQ.Set(flag); 224 } 225 226 private readonly uint NumberOfChannels = 8; 227 228 private IFlagRegisterField portInterruptPending; 229 private IFlagRegisterField portInterruptEnabled; 230 231 private readonly Dictionary<NRF52840_GPIO.Pin, Channel> pinToChannelMapping; 232 private readonly Channel[] channels; 233 private readonly NRF52840_GPIO[] ports; 234 235 private class Channel 236 { Channel(int id, NRF52840_GPIOTasksEvents parent)237 public Channel(int id, NRF52840_GPIOTasksEvents parent) 238 { 239 this.id = id; 240 this.parent = parent; 241 } 242 WritePin(bool value)243 public void WritePin(bool value) 244 { 245 switch(Polarity) 246 { 247 case Polarity.None: 248 break; 249 250 case Polarity.LoToHi: 251 WritePinInner(true); 252 break; 253 254 case Polarity.HiToLo: 255 WritePinInner(false); 256 break; 257 258 case Polarity.Toggle: 259 WritePinInner(toggle: true); 260 break; 261 } 262 } 263 SetPin()264 public void SetPin() 265 { 266 WritePinInner(true); 267 } 268 ClearPin()269 public void ClearPin() 270 { 271 WritePinInner(false); 272 } 273 Reset()274 public void Reset() 275 { 276 Mode = Mode.Disabled; 277 SelectedPin = 0; 278 SelectedPort = 0; 279 Polarity = Polarity.None; 280 CurrentState = false; 281 282 EventEnabled = false; 283 EventPending = false; 284 } 285 TryGetPin(out NRF52840_GPIO.Pin pin)286 private bool TryGetPin(out NRF52840_GPIO.Pin pin) 287 { 288 var port = parent.ports[SelectedPort]; 289 if(port == null) 290 { 291 parent.Log(LogLevel.Warning, "Trying to access a not connected port #{0}", SelectedPort); 292 pin = null; 293 return false; 294 } 295 296 if(SelectedPin >= port.Pins.Length) 297 { 298 parent.Log(LogLevel.Warning, "Trying to access a not existing pin #{0} in port #{1}", SelectedPin, SelectedPort); 299 pin = null; 300 return false; 301 } 302 303 pin = port.Pins[SelectedPin]; 304 return true; 305 } 306 WritePinInner(bool value = false, bool toggle = false)307 private void WritePinInner(bool value = false, bool toggle = false) 308 { 309 if(Mode != Mode.Task) 310 { 311 parent.Log(LogLevel.Warning, "Setting channel #{0} not configured as TASK", id); 312 return; 313 } 314 315 if(!TryGetPin(out var pin)) 316 { 317 return; 318 } 319 320 pin.Direction = NRF52840_GPIO.PinDirection.Output; 321 pin.OutputValue = toggle 322 ? !pin.OutputValue 323 : value; 324 } 325 326 public Mode Mode { get; set; } 327 328 public uint SelectedPin { get; set; } 329 public uint SelectedPort { get; set; } 330 331 public Polarity Polarity { get; set; } 332 333 public bool CurrentState { get; set; } 334 335 public bool EventPending { get; set; } 336 public bool EventEnabled { get; set; } 337 338 private readonly int id; 339 private readonly NRF52840_GPIOTasksEvents parent; 340 } 341 342 private enum Mode 343 { 344 Disabled = 0, 345 Event = 1, 346 Task = 3 347 } 348 349 private enum Polarity 350 { 351 None = 0, 352 LoToHi = 1, 353 HiToLo = 2, 354 Toggle = 3 355 } 356 357 private enum Registers 358 { 359 // this is a group of 8 registers 360 TasksOut = 0x0, 361 // this is a group of 8 registers 362 TasksSet = 0x30, 363 // this is a group of 8 registers 364 TasksClear = 0x60, 365 // this is a group of 8 registers 366 EventsIn = 0x100, 367 368 EventsPort = 0x17C, 369 370 EnableInterrupt = 0x304, 371 DisableInterrupt = 0x308, 372 373 // this is a group of 8 registers 374 Configuration = 0x510 375 } 376 } 377 } 378