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.Collections.Generic; 9 using System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.Peripherals.GPIOPort 16 { 17 public class CC2538_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IKnownSize 18 { CC2538_GPIO(IMachine machine)19 public CC2538_GPIO(IMachine machine) : base(machine, NumberOfGPIOs) 20 { 21 locker = new object(); 22 IRQ = new GPIO(); 23 irqManager = new GPIOInterruptManager(IRQ, State); 24 25 PrepareRegisters(); 26 } 27 ReadDoubleWord(long offset)28 public uint ReadDoubleWord(long offset) 29 { 30 lock(locker) 31 { 32 if(offset < 0x400) 33 { 34 var mask = BitHelper.GetBits((uint)(offset >> 2) & 0xFF); 35 var bits = BitHelper.GetBits(registers.Read(0)); 36 var result = new bool[8]; 37 for(var i = 0; i < 8; i++) 38 { 39 if(mask[i]) 40 { 41 result[i] = bits[i]; 42 } 43 } 44 45 return BitHelper.GetValueFromBitsArray(result); 46 } 47 48 return registers.Read(offset); 49 } 50 } 51 WriteDoubleWord(long offset, uint value)52 public void WriteDoubleWord(long offset, uint value) 53 { 54 lock(locker) 55 { 56 if(offset < 0x400) 57 { 58 var mask = BitHelper.GetBits((uint)(offset >> 2) & 0xFF); 59 var bits = BitHelper.GetBits(value); 60 for(var i = 0; i < 8; i++) 61 { 62 if(mask[i]) 63 { 64 Connections[i].Set(bits[i]); 65 State[i] = bits[i]; 66 } 67 } 68 } 69 else 70 { 71 registers.Write(offset, value); 72 } 73 } 74 } 75 OnGPIO(int number, bool value)76 public override void OnGPIO(int number, bool value) 77 { 78 if(number < 0 || number >= NumberOfGPIOs) 79 { 80 throw new ArgumentOutOfRangeException(string.Format("Gpio #{0} called, but only {1} lines are available", number, NumberOfGPIOs)); 81 } 82 83 lock(locker) 84 { 85 base.OnGPIO(number, value); 86 irqManager.RefreshInterrupts(); 87 } 88 } 89 Reset()90 public override void Reset() 91 { 92 lock(locker) 93 { 94 base.Reset(); 95 irqManager.Reset(); 96 registers.Reset(); 97 IRQ.Unset(); 98 } 99 } 100 101 public GPIO IRQ { get; private set; } 102 public long Size => 0x1000; 103 PrepareRegisters()104 private void PrepareRegisters() 105 { 106 registers = new DoubleWordRegisterCollection(this, new Dictionary<long, DoubleWordRegister> 107 { 108 {(long)Registers.Data, new DoubleWordRegister(this) 109 .WithValueField(0, 8, 110 writeCallback: (_, val) => 111 { 112 var bits = BitHelper.GetBits((uint)val); 113 for(int i = 0; i < 8; i++) 114 { 115 if(irqManager.PinDirection[i] == GPIOInterruptManager.Direction.Input) 116 { 117 Connections[i].Set(bits[i]); 118 State[i] = bits[i]; 119 } 120 } 121 }, 122 valueProviderCallback: _ => { return BitHelper.GetValueFromBitsArray(State); }) 123 }, 124 {(long)Registers.DataDirection, new DoubleWordRegister(this) 125 .WithValueField(0, 8, writeCallback: (_, val) => 126 { 127 var bits = BitHelper.GetBits((uint)val); 128 for(var i = 0; i < 8; i++) 129 { 130 irqManager.PinDirection[i] = bits[i] ? GPIOInterruptManager.Direction.Output : GPIOInterruptManager.Direction.Input; 131 } 132 }, 133 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(irqManager.PinDirection.Select(x => x == GPIOInterruptManager.Direction.Output))) 134 }, 135 {(long)Registers.InterruptSense, new DoubleWordRegister(this) 136 .WithValueField(0, 8, out interruptSenseField, writeCallback: (_, val) => CalculateInterruptTypes()) 137 }, 138 {(long)Registers.InterruptBothEdges, new DoubleWordRegister(this) 139 .WithValueField(0, 8, out interruptBothEdgeField, writeCallback: (_, val) => CalculateInterruptTypes()) 140 }, 141 {(long)Registers.InterruptEvent, new DoubleWordRegister(this) 142 .WithValueField(0, 8, out interruptEventField, writeCallback: (_, val) => CalculateInterruptTypes()) 143 }, 144 {(long)Registers.InterruptEnable, new DoubleWordRegister(this) 145 .WithValueField(0, 8, writeCallback: (_, val) => 146 { 147 var bits = BitHelper.GetBits((uint)val); 148 for(var i = 0; i < 8; i++) 149 { 150 irqManager.InterruptEnable[i] = bits[i]; 151 irqManager.InterruptMask[i] = bits[i]; 152 } 153 irqManager.RefreshInterrupts(); 154 }, 155 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(irqManager.InterruptEnable)) 156 }, 157 {(long)Registers.RawInterruptStatus, new DoubleWordRegister(this) 158 .WithValueField(0, 8, valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(irqManager.ActiveInterrupts))}, 159 {(long)Registers.MaskedInterruptStatus, new DoubleWordRegister(this) 160 .WithValueField(0, 8, valueProviderCallback: _ => CalculateMaskedInterruptValue())}, 161 {(long)Registers.InterruptClear, new DoubleWordRegister(this) 162 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, val) => 163 { 164 var bits = BitHelper.GetBits((uint)val); 165 for(var i = 0; i < 8; i++) 166 { 167 if(bits[i]) 168 { 169 irqManager.ClearInterrupt(i); 170 } 171 } 172 }) 173 }, 174 {(long)Registers.ModeControlSelect, new DoubleWordRegister(this) 175 .WithTag("AFSEL", 0, 32) 176 }, 177 {(long)Registers.PortEdgeControl, new DoubleWordRegister(this) 178 .WithTag("P_EDGE_CTRL", 0, 32) 179 }, 180 {(long)Registers.PowerUpInterruptEnable, new DoubleWordRegister(this) 181 .WithTag("PI_IEN", 0, 32) 182 }, 183 {(long)Registers.IOPortsIRQDetectACK, new DoubleWordRegister(this) 184 .WithTag("IRQ_DETECT_ACK", 0, 32) 185 }, 186 {(long)Registers.MaskedIRQDetectACK, new DoubleWordRegister(this) 187 .WithTag("IRQ_DETECT_UNMASK", 0, 32) 188 } 189 }); 190 } 191 CalculateInterruptTypes()192 private void CalculateInterruptTypes() 193 { 194 lock(locker) 195 { 196 var isBothEdgesSensitive = BitHelper.GetBits((uint)interruptBothEdgeField.Value); 197 var isLevelSensitive = BitHelper.GetBits((uint)interruptSenseField.Value); 198 var isActiveHighOrRisingEdge = BitHelper.GetBits((uint)interruptEventField.Value); 199 200 for(int i = 0; i < 8; i++) 201 { 202 if(isLevelSensitive[i]) 203 { 204 irqManager.InterruptType[i] = isActiveHighOrRisingEdge[i] 205 ? GPIOInterruptManager.InterruptTrigger.ActiveHigh 206 : GPIOInterruptManager.InterruptTrigger.ActiveLow; 207 } 208 else 209 { 210 if(isBothEdgesSensitive[i]) 211 { 212 irqManager.InterruptType[i] = GPIOInterruptManager.InterruptTrigger.BothEdges; 213 } 214 else 215 { 216 irqManager.InterruptType[i] = isActiveHighOrRisingEdge[i] 217 ? GPIOInterruptManager.InterruptTrigger.RisingEdge 218 : GPIOInterruptManager.InterruptTrigger.FallingEdge; 219 } 220 } 221 } 222 irqManager.RefreshInterrupts(); 223 } 224 } 225 CalculateMaskedInterruptValue()226 private uint CalculateMaskedInterruptValue() 227 { 228 var result = new bool[8]; 229 for(var i = 0; i < 8; i++) 230 { 231 result[i] = irqManager.ActiveInterrupts.ElementAt(i) && irqManager.InterruptMask[i]; 232 } 233 return BitHelper.GetValueFromBitsArray(result); 234 } 235 236 private DoubleWordRegisterCollection registers; 237 private readonly GPIOInterruptManager irqManager; 238 private readonly object locker; 239 240 private IValueRegisterField interruptSenseField; 241 private IValueRegisterField interruptBothEdgeField; 242 private IValueRegisterField interruptEventField; 243 244 private const int NumberOfGPIOs = 8; 245 246 private enum Registers 247 { 248 Data = 0x0, 249 DataDirection = 0x400, 250 InterruptSense = 0x404, 251 InterruptBothEdges = 0x408, 252 InterruptEvent = 0x40C, 253 InterruptEnable = 0x410, 254 RawInterruptStatus = 0x414, 255 MaskedInterruptStatus = 0x418, 256 InterruptClear = 0x41C, 257 ModeControlSelect = 0x420, 258 GPIOCommitUnlock = 0x520, 259 GPIOCommit = 0x524, 260 PMUX = 0x700, 261 PortEdgeControl = 0x704, 262 USBInputPowerUpEdgeControl = 0x708, 263 PowerUpInterruptEnable = 0x710, 264 IOPortsIRQDetectACK = 0x718, 265 USBIRQDetectACK = 0x71C, 266 MaskedIRQDetectACK = 0x720 267 } 268 } 269 } 270