1 // 2 // Copyright (c) 2010-2024 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.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Core.Structure.Registers; 14 15 namespace Antmicro.Renode.Peripherals.GPIOPort 16 { 17 abstract public class RenesasRA_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 18 { RenesasRA_GPIO(IMachine machine, int portNumber, int numberOfConnections, RenesasRA_GPIOMisc pfsMisc)19 public RenesasRA_GPIO(IMachine machine, int portNumber, int numberOfConnections, RenesasRA_GPIOMisc pfsMisc) : base(machine, numberOfConnections) 20 { 21 RegistersCollection = new DoubleWordRegisterCollection(this); 22 PinConfigurationRegistersCollection = new DoubleWordRegisterCollection(this); 23 24 pinDirection = new IEnumRegisterField<Direction>[numberOfConnections]; 25 usedAsIRQ = new IFlagRegisterField[numberOfConnections]; 26 27 this.pfsMisc = pfsMisc; 28 this.portNumber = portNumber; 29 30 IRQ0 = new GPIO(); 31 IRQ1 = new GPIO(); 32 IRQ2 = new GPIO(); 33 IRQ3 = new GPIO(); 34 IRQ4 = new GPIO(); 35 IRQ5 = new GPIO(); 36 IRQ6 = new GPIO(); 37 IRQ7 = new GPIO(); 38 IRQ8 = new GPIO(); 39 IRQ9 = new GPIO(); 40 IRQ10 = new GPIO(); 41 IRQ11 = new GPIO(); 42 IRQ12 = new GPIO(); 43 IRQ13 = new GPIO(); 44 IRQ14 = new GPIO(); 45 IRQ15 = new GPIO(); 46 47 DefineRegisters(); 48 DefinePinConfigurationRegisters(); 49 } 50 ReadDoubleWord(long offset)51 public uint ReadDoubleWord(long offset) 52 { 53 return RegistersCollection.Read(offset); 54 } 55 WriteDoubleWord(long offset, uint value)56 public void WriteDoubleWord(long offset, uint value) 57 { 58 RegistersCollection.Write(offset, value); 59 } 60 Reset()61 public override void Reset() 62 { 63 base.Reset(); 64 65 IRQ0.Unset(); 66 IRQ1.Unset(); 67 IRQ2.Unset(); 68 IRQ3.Unset(); 69 IRQ4.Unset(); 70 IRQ5.Unset(); 71 IRQ6.Unset(); 72 IRQ7.Unset(); 73 IRQ8.Unset(); 74 IRQ9.Unset(); 75 IRQ10.Unset(); 76 IRQ11.Unset(); 77 IRQ12.Unset(); 78 IRQ13.Unset(); 79 IRQ14.Unset(); 80 IRQ15.Unset(); 81 } 82 83 [ConnectionRegion("pinConfiguration")] ReadDoubleWordFromPinConfiguration(long offset)84 public uint ReadDoubleWordFromPinConfiguration(long offset) 85 { 86 return PinConfigurationRegistersCollection.Read(offset); 87 } 88 89 [ConnectionRegion("pinConfiguration")] WriteDoubleWordToPinConfiguration(long offset, uint value)90 public void WriteDoubleWordToPinConfiguration(long offset, uint value) 91 { 92 if(!pfsMisc.PFSWriteEnabled) 93 { 94 this.Log(LogLevel.Warning, "Trying to write to pin configuration registers (PFS) when PFSWE is deasserted"); 95 return; 96 } 97 98 PinConfigurationRegistersCollection.Write(offset, value); 99 } 100 OnGPIO(int number, bool value)101 public override void OnGPIO(int number, bool value) 102 { 103 if(!CheckPinNumber(number)) 104 { 105 return; 106 } 107 108 base.OnGPIO(number, value); 109 110 if(pinDirection[number].Value != Direction.Input) 111 { 112 this.Log(LogLevel.Warning, "Writing to an output GPIO pin #{0}", number); 113 return; 114 } 115 116 if(TryGetInterruptOutput(number, out var irq)) 117 { 118 irq.Set(value); 119 } 120 } 121 122 public GPIO IRQ0 { get; } 123 public GPIO IRQ1 { get; } 124 public GPIO IRQ2 { get; } 125 public GPIO IRQ3 { get; } 126 public GPIO IRQ4 { get; } 127 public GPIO IRQ5 { get; } 128 public GPIO IRQ6 { get; } 129 public GPIO IRQ7 { get; } 130 public GPIO IRQ8 { get; } 131 public GPIO IRQ9 { get; } 132 public GPIO IRQ10 { get; } 133 public GPIO IRQ11 { get; } 134 public GPIO IRQ12 { get; } 135 public GPIO IRQ13 { get; } 136 public GPIO IRQ14 { get; } 137 public GPIO IRQ15 { get; } 138 139 public DoubleWordRegisterCollection RegistersCollection { get; } 140 141 public DoubleWordRegisterCollection PinConfigurationRegistersCollection { get; } 142 143 public long Size => 0x20; 144 UpdateIRQOutput()145 private void UpdateIRQOutput() 146 { 147 for(var i = 0; i < NumberOfConnections; ++i) 148 { 149 if(pinDirection[i].Value != Direction.Input) 150 { 151 continue; 152 } 153 154 if(TryGetInterruptOutput(i, out var irq) && irq.IsSet != State[i]) 155 { 156 irq.Set(State[i]); 157 } 158 } 159 } 160 DefineRegisters()161 private void DefineRegisters() 162 { 163 Registers.DirectionOutput.Define(this) 164 .WithEnumFields(0, 1, NumberOfConnections, out pinDirection, name: "PDR", 165 changeCallback: (i, _, value) => { if(value == Direction.Input) UpdateIRQOutput(); }) 166 .WithFlags(16, NumberOfConnections, name: "PODR", 167 valueProviderCallback: (i, _) => Connections[i].IsSet, 168 changeCallback: (i, _, value) => SetOutput(i, value)) 169 ; 170 171 Registers.StateEventInput.Define(this) 172 .WithFlags(0, NumberOfConnections, FieldMode.Read, name: "PIDR", 173 valueProviderCallback: (i, _) => GetInput(i)) 174 .WithTag("EIDR", 16, NumberOfConnections) 175 ; 176 177 Registers.Output.Define(this) 178 .WithFlags(0, NumberOfConnections, FieldMode.Write, name: "POSR", 179 writeCallback: (i, _, value) => { if(value) SetOutput(i, true); }) 180 .WithFlags(16, NumberOfConnections, FieldMode.Write, name: "PORR", 181 writeCallback: (i, _, value) => { if(value) SetOutput(i, false); }) 182 ; 183 } 184 DefinePinConfigurationRegisters()185 private void DefinePinConfigurationRegisters() 186 { 187 for(var i = 0; i < NumberOfConnections; ++i) 188 { 189 var idx = i; 190 var offset = idx * 0x4; 191 var register = new DoubleWordRegister(this) 192 .WithFlag(0, name: "PODR", 193 valueProviderCallback: _ => Connections[idx].IsSet, 194 changeCallback: (_, value) => SetOutput(idx, value)) 195 .WithFlag(1, FieldMode.Read, name: "PIDR", 196 valueProviderCallback: _ => GetInput(idx)) 197 .WithEnumField(2, 1, out pinDirection[idx], name: "PDR", 198 changeCallback: (_, value) => { if(value == Direction.Input) UpdateIRQOutput(); }) 199 .WithReservedBits(3, 1) 200 .WithFlag(4, name: "PCR") 201 .WithReservedBits(5, 1) 202 .WithFlag(6, name: "NCODR") 203 .WithReservedBits(7, 3) 204 .WithTag("DSCR", 10, 2) 205 .WithTag("EOFR", 12, 2) 206 .WithFlag(14, out usedAsIRQ[idx], name: "ISEL", 207 changeCallback: (_, value) => UpdateIRQOutput()) 208 .WithTaggedFlag("ASEL", 15) 209 .WithTaggedFlag("PMR", 16) 210 .WithReservedBits(17, 7) 211 .WithTag("PSEL", 24, 5) 212 .WithReservedBits(29, 3) 213 ; 214 PinConfigurationRegistersCollection.AddRegister(offset, register); 215 } 216 } 217 GetInput(int index)218 private bool GetInput(int index) 219 { 220 var value = State[index]; 221 if(pinDirection[index].Value == Direction.Output) 222 { 223 value |= Connections[index].IsSet; 224 } 225 return value; 226 } 227 SetOutput(int index, bool value)228 private void SetOutput(int index, bool value) 229 { 230 if(pinDirection[index].Value != Direction.Output) 231 { 232 this.Log(LogLevel.Warning, "Trying to set pin level, but pin is not in output mode, ignoring"); 233 return; 234 } 235 236 Connections[index].Set(value); 237 } 238 TryGetInterruptOutput(int number, out GPIO irq)239 private bool TryGetInterruptOutput(int number, out GPIO irq) 240 { 241 irq = null; 242 if(!usedAsIRQ[number].Value) 243 { 244 return false; 245 } 246 247 var interruptOutput = PinInterruptOutputs[portNumber].SingleOrDefault(e => e.PinNumber == number); 248 if(interruptOutput == null) 249 { 250 this.Log(LogLevel.Warning, "Trying to use pin#{0} as interrupt, but it's not associated with any IRQn output", number); 251 return false; 252 } 253 254 irq = interruptOutput.IRQ; 255 return true; 256 } 257 258 abstract protected List<InterruptOutput>[] PinInterruptOutputs { get; } 259 260 private readonly RenesasRA_GPIOMisc pfsMisc; 261 private readonly int portNumber; 262 263 private IEnumRegisterField<Direction>[] pinDirection; 264 private IFlagRegisterField[] usedAsIRQ; 265 266 protected class InterruptOutput 267 { InterruptOutput(int pinNumber, GPIO irq)268 public InterruptOutput(int pinNumber, GPIO irq) 269 { 270 PinNumber = pinNumber; 271 IRQ = irq; 272 } 273 274 public int PinNumber { get; } 275 public GPIO IRQ { get; } 276 } 277 278 private enum Direction 279 { 280 Input, 281 Output, 282 } 283 284 private enum Registers 285 { 286 DirectionOutput = 0x00, 287 StateEventInput = 0x04, 288 Output = 0x08, 289 EventOutput = 0x0C, 290 } 291 } 292 } 293