1 // 2 // Copyright (c) 2010-2021 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 Antmicro.Renode.Core; 10 using Antmicro.Renode.Peripherals.Bus; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 14 namespace Antmicro.Renode.Peripherals.GPIOPort 15 { 16 public class NRF52840_GPIO : BaseGPIOPort, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize 17 { NRF52840_GPIO(IMachine machine)18 public NRF52840_GPIO(IMachine machine) : base(machine, NumberOfPins) 19 { 20 Pins = new Pin[NumberOfPins]; 21 for(var i = 0; i < Pins.Length; i++) 22 { 23 Pins[i] = new Pin(this, i); 24 } 25 26 RegistersCollection = new DoubleWordRegisterCollection(this); 27 DefineRegisters(); 28 } 29 Reset()30 public override void Reset() 31 { 32 base.Reset(); 33 34 RegistersCollection.Reset(); 35 36 foreach(var pin in Pins) 37 { 38 pin.Reset(); 39 } 40 41 detectState = false; 42 } 43 ReadDoubleWord(long offset)44 public uint ReadDoubleWord(long offset) 45 { 46 return RegistersCollection.Read(offset); 47 } 48 WriteDoubleWord(long offset, uint value)49 public void WriteDoubleWord(long offset, uint value) 50 { 51 RegistersCollection.Write(offset, value); 52 } 53 OnGPIO(int number, bool value)54 public override void OnGPIO(int number, bool value) 55 { 56 if(CheckPinNumber(number)) 57 { 58 Pins[number].InputValue = value; 59 } 60 } 61 62 public DoubleWordRegisterCollection RegistersCollection { get; } 63 public Pin[] Pins { get; } 64 65 public long Size => 0x300; 66 67 public event Action<Pin, bool> PinChanged; 68 public event Action Detect; 69 DefineRegisters()70 private void DefineRegisters() 71 { 72 Registers.Out.Define(this) 73 .WithFlags(0, NumberOfPins, 74 valueProviderCallback: (id, _) => Pins[id].OutputValue, 75 writeCallback: (id, _, val) => Pins[id].OutputValue = val) 76 ; 77 78 Registers.OutSet.Define(this) 79 .WithFlags(0, NumberOfPins, 80 valueProviderCallback: (id, _) => Pins[id].OutputValue, 81 writeCallback: (id, _, val) => 82 { 83 if(val) 84 { 85 Pins[id].OutputValue = true; 86 } 87 }) 88 ; 89 90 Registers.OutClear.Define(this) 91 .WithFlags(0, NumberOfPins, 92 valueProviderCallback: (id, _) => Pins[id].OutputValue, 93 writeCallback: (id, _, val) => 94 { 95 if(val) 96 { 97 Pins[id].OutputValue = false; 98 } 99 }) 100 ; 101 102 Registers.In.Define(this) 103 .WithFlags(0, NumberOfPins, FieldMode.Read, 104 valueProviderCallback: (id, _) => Pins[id].InputValue) 105 ; 106 107 Registers.Direction.Define(this) 108 .WithFlags(0, NumberOfPins, 109 valueProviderCallback: (id, _) => Pins[id].Direction == PinDirection.Output, 110 writeCallback: (id, _, val) => Pins[id].Direction = val ? PinDirection.Output : PinDirection.Input) 111 ; 112 113 Registers.DirectionSet.Define(this) 114 .WithFlags(0, NumberOfPins, 115 valueProviderCallback: (id, _) => Pins[id].Direction == PinDirection.Output, 116 writeCallback: (id, _, val) => { if(val) Pins[id].Direction = PinDirection.Output; }) 117 ; 118 119 Registers.DirectionClear.Define(this) 120 .WithFlags(0, NumberOfPins, 121 valueProviderCallback: (id, _) => Pins[id].Direction == PinDirection.Output, 122 writeCallback: (id, _, val) => { if(val) Pins[id].Direction = PinDirection.Input; }) 123 ; 124 125 Registers.Latch.Define(this) 126 .WithTag("LATCH", 0, 32) 127 ; 128 129 Registers.DetectMode.Define(this) 130 .WithTaggedFlag("DETECTMODE", 0) 131 .WithReservedBits(1, 31) 132 ; 133 134 Registers.PinConfigure.DefineMany(this, NumberOfPins, (register, idx) => 135 { 136 register 137 .WithFlag(0, name: "DIR", 138 writeCallback: (_, val) => 139 { 140 var newValue = val ? PinDirection.Output : PinDirection.Input; 141 if(newValue != Pins[idx].Direction) 142 { 143 Pins[idx].Direction = newValue; 144 } 145 }, 146 valueProviderCallback: _ => Pins[idx].Direction == PinDirection.Output) 147 .WithFlag(1, name: "INPUT", 148 writeCallback: (_, val) => Pins[idx].InputOverride = !val, 149 valueProviderCallback: _ => !Pins[idx].InputOverride) 150 .WithEnumField<DoubleWordRegister, PullMode>(2, 2, name: "PULL", 151 writeCallback: (_, val) => 152 { 153 Pins[idx].PullMode = val; 154 switch(val) 155 { 156 case PullMode.PullUp: 157 Pins[idx].DefaultValue = true; 158 break; 159 case PullMode.PullDown: 160 Pins[idx].DefaultValue = false; 161 break; 162 default: 163 break; 164 } 165 }, 166 valueProviderCallback: _ => Pins[idx].PullMode) 167 .WithReservedBits(4, 4) 168 .WithEnumField<DoubleWordRegister, DriveMode>(8, 3, name: "DRIVE", 169 valueProviderCallback: _ => Pins[idx].DriveMode, 170 writeCallback: (_, val) => Pins[idx].DriveMode = val 171 ) 172 .WithReservedBits(11, 5) 173 .WithEnumField<DoubleWordRegister, SenseMode>(16, 2, name: "SENSE", 174 writeCallback: (_, val) => 175 { 176 if(Pins[idx].SenseMode != val) 177 { 178 Pins[idx].SenseMode = val; 179 UpdateDetect(); 180 } 181 }, 182 valueProviderCallback: _ => Pins[idx].SenseMode) 183 .WithReservedBits(18, 14) 184 ; 185 }); 186 } 187 UpdateDetect()188 private void UpdateDetect() 189 { 190 var nextDetectState = Pins.Any(x => x.IsSensing); 191 if(nextDetectState != detectState) 192 { 193 detectState = nextDetectState; 194 if(nextDetectState) 195 { 196 Detect?.Invoke(); 197 } 198 } 199 } 200 201 private bool detectState; 202 203 private const int NumberOfPins = 32; 204 205 public class Pin 206 { Pin(NRF52840_GPIO parent, int id)207 public Pin(NRF52840_GPIO parent, int id) 208 { 209 this.Parent = parent; 210 this.Id = id; 211 } 212 Reset()213 public void Reset() 214 { 215 Parent.Connections[Id].Set(false); 216 InputOverride = false; 217 everSet = false; 218 bufferedInputValue = false; 219 bufferedOutputValue = false; 220 direction = PinDirection.Input; 221 } 222 223 public bool OutputValue 224 { 225 get => GetCurrentValue(); 226 227 set 228 { 229 if(Direction != PinDirection.Output) 230 { 231 bufferedOutputValue = value; 232 return; 233 } 234 235 Parent.NoisyLog("Setting pin {0} output to {1}", Id, value); 236 Parent.Connections[Id].Set(value); 237 } 238 } 239 240 public bool InputValue 241 { 242 get => GetCurrentValue(); 243 244 set 245 { 246 everSet = true; 247 248 if(Direction != PinDirection.Input) 249 { 250 // buffer the value so that it can be used on a next direction change 251 bufferedInputValue = value; 252 return; 253 } 254 255 if(value == Parent.State[Id]) 256 { 257 return; 258 } 259 260 Parent.NoisyLog("Setting pin {0} input to {1}", Id, value); 261 Parent.State[Id] = value; 262 Parent.PinChanged(this, value); 263 Parent.UpdateDetect(); 264 } 265 } 266 267 // This property is needed as the pull-up and pull-down should be 268 // able to override Pin state not matter Direction it is set to. 269 public bool DefaultValue { get; set; } 270 271 public PinDirection Direction 272 { 273 get => direction; 274 275 set 276 { 277 if(direction == value) 278 { 279 return; 280 } 281 282 direction = value; 283 if(direction == PinDirection.Input) 284 { 285 InputValue = bufferedInputValue; 286 } 287 else 288 { 289 OutputValue = bufferedOutputValue; 290 } 291 } 292 } 293 294 public bool InputOverride { set; get; } 295 296 public DriveMode DriveMode { set; get; } 297 298 public SenseMode SenseMode { get; set; } 299 300 public PullMode PullMode { get; set; } 301 302 public bool IsSensing 303 { 304 get 305 { 306 if(SenseMode == SenseMode.Disabled) 307 { 308 return false; 309 } 310 311 return (SenseMode == SenseMode.High && InputValue) || (SenseMode == SenseMode.Low && !InputValue); 312 } 313 } 314 315 public NRF52840_GPIO Parent { get; } 316 public int Id { get; } 317 318 // returns the pin value depending on the currently set direction GetCurrentValue()319 private bool GetCurrentValue() 320 { 321 if(Direction == PinDirection.Output) 322 { 323 return Parent.Connections[Id].IsSet; 324 } 325 else 326 { 327 return everSet ? Parent.State[Id] : DefaultValue; 328 } 329 } 330 331 private bool everSet; 332 private bool bufferedInputValue; 333 private bool bufferedOutputValue; 334 private PinDirection direction; 335 } 336 337 public enum SenseMode 338 { 339 Disabled = 0, 340 High = 2, 341 Low = 3 342 } 343 344 public enum PullMode 345 { 346 Disabled = 0, 347 PullDown = 1, 348 PullUp = 3, 349 } 350 351 public enum DriveMode 352 { 353 Standard = 0, 354 HighDriveZero, 355 HighDriveOne, 356 HighDrive, 357 OpenZeroStandardOne, 358 OpenZeroHighDriveOne, 359 StandardZeroOpenOne, 360 HighDriveZeroOpenOne 361 } 362 363 public enum PinDirection 364 { 365 Input, 366 Output 367 } 368 369 private enum Registers 370 { 371 Out = 0x4, 372 OutSet = 0x8, 373 OutClear = 0xC, 374 In = 0x10, 375 Direction = 0x14, 376 DirectionSet = 0x18, 377 DirectionClear = 0x1C, 378 Latch = 0x20, 379 DetectMode = 0x24, 380 // this is a group of 32 registers for each pin 381 PinConfigure = 0x200 382 } 383 } 384 } 385