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.Linq; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Peripherals.Bus; 11 using Antmicro.Renode.Utilities; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Exceptions; 14 15 namespace Antmicro.Renode.Peripherals.GPIOPort 16 { 17 public class LiteX_GPIO : BaseGPIOPort, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IDoubleWordPeripheral, IKnownSize 18 { LiteX_GPIO(IMachine machine, Type type, bool enableIrq = false)19 public LiteX_GPIO(IMachine machine, Type type, bool enableIrq = false) : base(machine, NumberOfPins) 20 { 21 this.type = type; 22 this.enableIrq = enableIrq; 23 24 if(type == Type.Out && enableIrq) 25 { 26 throw new ConstructionException("Out GPIO does not support interrupts"); 27 } 28 29 IRQ = new GPIO(); 30 31 previousState = new bool[NumberOfPins]; 32 33 RegistersCollection = new DoubleWordRegisterCollection(this); 34 Size = DefineRegisters(); 35 } 36 ReadDoubleWord(long offset)37 public uint ReadDoubleWord(long offset) 38 { 39 return RegistersCollection.Read(offset); 40 } 41 WriteDoubleWord(long offset, uint value)42 public void WriteDoubleWord(long offset, uint value) 43 { 44 RegistersCollection.Write(offset, value); 45 } 46 Reset()47 public override void Reset() 48 { 49 base.Reset(); 50 RegistersCollection.Reset(); 51 52 for(var i = 0; i < previousState.Length; i++) 53 { 54 previousState[i] = false; 55 } 56 57 IRQ.Unset(); 58 } 59 60 public GPIO IRQ { get; } 61 62 public long Size { get; } 63 64 public DoubleWordRegisterCollection RegistersCollection { get; } 65 OnGPIO(int number, bool value)66 public override void OnGPIO(int number, bool value) 67 { 68 if(!CheckPinNumber(number)) 69 { 70 return; 71 } 72 73 base.OnGPIO(number, value); 74 75 if(!enableIrq) 76 { 77 // irq support is not enabled 78 return; 79 } 80 81 if(State[number] == previousState[number]) 82 { 83 // nothing to do 84 return; 85 } 86 87 previousState[number] = State[number]; 88 89 if(irqMode[number].Value == IrqMode.Edge) 90 { 91 if(irqEdge[number].Value == IrqEdge.Rising) 92 { 93 if(State[number]) 94 { 95 irqPending[number].Value = true; 96 UpdateInterrupts(); 97 } 98 } 99 else // it must be Falling 100 { 101 if(!State[number]) 102 { 103 irqPending[number].Value = true; 104 UpdateInterrupts(); 105 } 106 } 107 } 108 else // it must be Change 109 { 110 irqPending[number].Value = true; 111 UpdateInterrupts(); 112 } 113 } 114 DefineRegisters()115 private int DefineRegisters() 116 { 117 var offset = 0; 118 if(type != Type.Out) 119 { 120 offset += DefineInRegisters(offset); 121 } 122 123 if(type != Type.In) 124 { 125 offset += DefineOutRegisters(offset); 126 } 127 128 return offset; 129 } 130 DefineInRegisters(long offset)131 private int DefineInRegisters(long offset) 132 { 133 var size = 0; 134 135 ((Registers)offset).Define(this) 136 .WithValueField(0, NumberOfPins, FieldMode.Read, name: "In", 137 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(State)); 138 size += 0x4; 139 140 if(enableIrq) 141 { 142 ((Registers)offset + 0x4).Define(this) 143 .WithEnumFields<DoubleWordRegister, IrqMode>(0, 1, NumberOfPins, out irqMode, name: "IRQ mode"); 144 size += 0x4; 145 146 ((Registers)offset + 0x8).Define(this) 147 .WithEnumFields<DoubleWordRegister, IrqEdge>(0, 1, NumberOfPins, out irqEdge, name: "IRQ edge"); 148 size += 0x4; 149 150 // status - return 0s for now 151 ((Registers)offset + 0xc).Define(this) 152 .WithFlags(0, NumberOfPins, FieldMode.Read, name: "IRQ status"); 153 size += 0x4; 154 155 ((Registers)offset + 0x10).Define(this) 156 .WithFlags(0, NumberOfPins, out irqPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "IRQ pending") 157 .WithWriteCallback((_, __) => UpdateInterrupts()); 158 size += 0x4; 159 160 ((Registers)offset + 0x14).Define(this) 161 .WithFlags(0, NumberOfPins, out irqEnable, name: "IRQ enable") 162 .WithWriteCallback((_, __) => UpdateInterrupts()); 163 size += 0x4; 164 } 165 166 return size; 167 } 168 DefineOutRegisters(long offset)169 private int DefineOutRegisters(long offset) 170 { 171 var size = 0; 172 173 ((Registers)offset).Define(this) 174 .WithValueField(0, NumberOfPins, name: "Out", 175 writeCallback: (_, val) => 176 { 177 var bits = BitHelper.GetBits((uint)val); 178 for(var i = 0; i < bits.Length; i++) 179 { 180 Connections[i].Set(bits[i]); 181 } 182 }, 183 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(Connections.Where(x => x.Key >= 0).OrderBy(x => x.Key).Select(x => x.Value.IsSet))); 184 size += 0x4; 185 186 return size; 187 } 188 UpdateInterrupts()189 private void UpdateInterrupts() 190 { 191 var flag = false; 192 for(var i = 0; i < NumberOfPins; i++) 193 { 194 flag |= irqEnable[i].Value && irqPending[i].Value; 195 } 196 197 if(IRQ.IsSet != flag) 198 { 199 this.Log(LogLevel.Debug, "Setting IRQ to {0}", flag); 200 } 201 IRQ.Set(flag); 202 } 203 204 private readonly Type type; 205 private readonly bool enableIrq; 206 207 private IEnumRegisterField<IrqEdge>[] irqEdge; 208 private IEnumRegisterField<IrqMode>[] irqMode; 209 210 private IFlagRegisterField[] irqPending; 211 private IFlagRegisterField[] irqEnable; 212 213 private readonly bool[] previousState; 214 215 private const int NumberOfPins = 32; 216 217 public enum Type 218 { 219 In, 220 Out, 221 InOut 222 } 223 224 private enum IrqMode 225 { 226 Edge = 0, 227 Change = 1 228 } 229 230 private enum IrqEdge 231 { 232 Rising = 0, 233 Falling = 1 234 } 235 236 private enum Registers 237 { 238 Register1 = 0x0, 239 Register2 = 0x4, 240 Register3 = 0x8, 241 Register4 = 0xc, 242 Register5 = 0x10, 243 Register6 = 0x14, 244 Register7 = 0x18, 245 // the actual layout of registers 246 // depends on the model configuration 247 } 248 } 249 } 250 251