1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Renode.Peripherals.Bus; 10 using Antmicro.Renode.Peripherals.Miscellaneous; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Logging; 13 14 namespace Antmicro.Renode.Peripherals.GPIOPort 15 { 16 public class XilinxGPIOPS : BaseGPIOPort, IDoubleWordPeripheral, IKnownSize 17 { XilinxGPIOPS(IMachine machine, uint numberOfGpioBanks = 4)18 public XilinxGPIOPS(IMachine machine, uint numberOfGpioBanks = 4) : base (machine, 54 + 64) //54 MIO + 64 EMIO 19 { 20 portControllers = new GPIOController[numberOfGpioBanks]; 21 for(uint i = 0; i < numberOfGpioBanks; i++) 22 { 23 portControllers[i] = new GPIOController(this, i); 24 } 25 } 26 ReadDoubleWord(long offset)27 public uint ReadDoubleWord(long offset) 28 { 29 if(offset > 0x200) 30 { 31 var portNumber = (uint)((offset - 0x200) / 0x40); 32 return portControllers[portNumber].ReadRegister(offset % 0x40); 33 } 34 switch((registersOffsets)offset) 35 { 36 case registersOffsets.MaskableOutputData0Low: 37 return OutputData0 & 0xFFFF; 38 case registersOffsets.MaskableOutputData0Hi: 39 return OutputData0 >> 16; 40 case registersOffsets.MaskableOutputData1Low: 41 return OutputData1 & 0xFFFF; 42 case registersOffsets.MaskableOutputData1Hi: 43 return OutputData1 >> 16; 44 case registersOffsets.MaskableOutputData2Low: 45 return OutputData2 & 0xFFFF; 46 case registersOffsets.MaskableOutputData2Hi: 47 return OutputData2 >> 16; 48 case registersOffsets.MaskableOutputData3Low: 49 return OutputData3 & 0xFFFF; 50 case registersOffsets.MaskableOutputData3Hi: 51 return OutputData3 >> 16; 52 case registersOffsets.OutputData0: 53 return OutputData0; 54 case registersOffsets.OutputData1: 55 return OutputData1; 56 case registersOffsets.OutputData2: 57 return OutputData2; 58 case registersOffsets.OutputData3: 59 return OutputData3; 60 case registersOffsets.InputData0: 61 return 0; 62 case registersOffsets.InputData1: 63 return 0; 64 case registersOffsets.InputData2: 65 return 0; 66 case registersOffsets.InputData3: 67 return 0; 68 default: 69 this.LogUnhandledRead(offset); 70 return 0; 71 } 72 } 73 WriteDoubleWord(long offset, uint value)74 public void WriteDoubleWord(long offset, uint value) 75 { 76 if(offset > 0x200) 77 { 78 var portNumber = (uint)((offset - 0x200) / 0x40); 79 portControllers[portNumber].WriteRegister(offset % 0x40, value); 80 return; 81 } 82 switch((registersOffsets)offset) 83 { 84 case registersOffsets.MaskableOutputData0Low: 85 OutputData0 = (OutputData0 & 0xFFFF0000) | (value & 0xFFFF); 86 this.DoPinOperation(0, value & 0xFFFF, 0xFFFF0000 | value >> 16); 87 break; 88 case registersOffsets.MaskableOutputData0Hi: 89 OutputData0 = (OutputData0 & 0x0000FFFF) | (value << 16); 90 this.DoPinOperation(0, value & 0xFFFF, 0x0000FFFF | value >> 16); 91 break; 92 case registersOffsets.MaskableOutputData1Low: 93 OutputData1 = (OutputData1 & 0xFFFF0000) | (value & 0xFFFF); 94 this.DoPinOperation(1, value & 0xFFFF, 0xFFFF0000 | value >> 16); 95 break; 96 case registersOffsets.MaskableOutputData1Hi: 97 OutputData1 = (OutputData1 & 0x0000FFFF) | (value << 16); 98 this.DoPinOperation(1, value & 0xFFFF, 0x0000FFFF | value >> 16); 99 break; 100 case registersOffsets.MaskableOutputData2Low: 101 OutputData2 = (OutputData2 & 0xFFFF0000) | (value & 0xFFFF); 102 this.DoPinOperation(2, value & 0xFFFF, 0xFFFF0000 | value >> 16); 103 break; 104 case registersOffsets.MaskableOutputData2Hi: 105 OutputData2 = (OutputData2 & 0x0000FFFF) | (value << 16); 106 this.DoPinOperation(2, value & 0xFFFF, 0x0000FFFF | value >> 16); 107 break; 108 case registersOffsets.MaskableOutputData3Low: 109 OutputData3 = (OutputData3 & 0xFFFF0000) | (value & 0xFFFF); 110 this.DoPinOperation(3, value & 0xFFFF, 0xFFFF0000 | value >> 16); 111 break; 112 case registersOffsets.MaskableOutputData3Hi: 113 OutputData3 = (OutputData3 & 0x0000FFFF) | (value << 16); 114 this.DoPinOperation(3, value & 0xFFFF, 0x0000FFFF | value >> 16); 115 break; 116 case registersOffsets.OutputData0: 117 OutputData0 = value; 118 this.DoPinOperation(0, value, 0); 119 break; 120 case registersOffsets.OutputData1: 121 OutputData1 = value; 122 this.DoPinOperation(1, value, 0); 123 break; 124 case registersOffsets.OutputData2: 125 OutputData2 = value; 126 this.DoPinOperation(2, value, 0); 127 break; 128 case registersOffsets.OutputData3: 129 OutputData2 = value; 130 this.DoPinOperation(2, value, 0); 131 break; 132 case registersOffsets.InputData0: 133 this.Log(LogLevel.Warning, "Writing read only register offset: {0:X} value: {1:X}", offset, value); 134 break; 135 case registersOffsets.InputData1: 136 this.Log(LogLevel.Warning, "Writing read only register offset: {0:X} value: {1:X}", offset, value); 137 break; 138 case registersOffsets.InputData2: 139 this.Log(LogLevel.Warning, "Writing read only register offset: {0:X} value: {1:X}", offset, value); 140 break; 141 case registersOffsets.InputData3: 142 this.Log(LogLevel.Warning, "Writing read only register offset: {0:X} value: {1:X}", offset, value); 143 break; 144 default: 145 this.LogUnhandledWrite(offset, value); 146 break; 147 } 148 } 149 DoPinOperation(int portNumber, uint value, uint mask)150 private void DoPinOperation(int portNumber, uint value, uint mask) 151 { 152 /* Port 1 is only 22 bit long, while all the others are 32 bit*/ 153 var portLength = portNumber == 1 ? 21 : 31; 154 var outputEnabled = portControllers[portNumber].OutputEnabled(); 155 for(int i = 0; i < portLength; i++) 156 { 157 if((mask & (1u << i)) == 0) 158 { 159 if((outputEnabled & (1u << i)) != 0) 160 { 161 if((value & (1u << i)) != 0) 162 { 163 Connections[(int)portOffsets[portNumber] + i].Set(); 164 } 165 else 166 { 167 Connections[(int)portOffsets[portNumber] + i].Unset(); 168 } 169 } 170 } 171 } 172 } 173 174 public long Size 175 { 176 get 177 { 178 return 0x2E8; 179 } 180 } 181 182 private GPIOController[] portControllers; 183 184 /* Registers */ 185 private uint OutputData0; 186 private uint OutputData1; 187 private uint OutputData2; 188 private uint OutputData3; 189 /* For the future use 190 private uint InputData0; 191 private uint InputData1; 192 private uint InputData2; 193 private uint InputData3; 194 */ 195 /* Offsets */ 196 private enum registersOffsets : uint 197 { 198 MaskableOutputData0Low = 0x00, 199 MaskableOutputData0Hi = 0x04, 200 MaskableOutputData1Low = 0x08, 201 MaskableOutputData1Hi = 0x0C, 202 MaskableOutputData2Low = 0x10, 203 MaskableOutputData2Hi = 0x14, 204 MaskableOutputData3Low = 0x18, 205 MaskableOutputData3Hi = 0x1C, 206 OutputData0 = 0x40, 207 OutputData1 = 0x44, 208 OutputData2 = 0x48, 209 OutputData3 = 0x4C, 210 InputData0 = 0x60, 211 InputData1 = 0x64, 212 InputData2 = 0x68, 213 InputData3 = 0x6C 214 } 215 private uint[] portOffsets = new uint[] { 0, 32, 54, 86 }; 216 217 /* Common register sets for the all the banks */ 218 private class GPIOController 219 { GPIOController(XilinxGPIOPS parent, uint bankNumber)220 public GPIOController(XilinxGPIOPS parent, uint bankNumber) 221 { 222 this.parentClass = parent; 223 this.bankNumber = bankNumber; 224 } 225 WriteRegister(long offset, uint value)226 public void WriteRegister(long offset, uint value) 227 { 228 switch((registersOffsets)offset) 229 { 230 case registersOffsets.DirectionMode: 231 DirectionMode = value; 232 break; 233 case registersOffsets.OutputEnable: 234 OutputEnable = value; 235 break; 236 default: 237 this.parentClass.LogUnhandledWrite(0x204 + this.bankNumber * 0x40 + offset, value); 238 break; 239 } 240 } ReadRegister(long offset)241 public uint ReadRegister(long offset) 242 { 243 switch((registersOffsets)offset) 244 { 245 case registersOffsets.DirectionMode: 246 return DirectionMode; 247 case registersOffsets.OutputEnable: 248 return OutputEnable; 249 default: 250 this.parentClass.LogUnhandledRead(0x204 + this.bankNumber * 0x40 + offset); 251 return 0; 252 } 253 } OutputEnabled()254 public uint OutputEnabled() 255 { 256 return (uint)(DirectionMode & OutputEnable); 257 } 258 private XilinxGPIOPS parentClass; 259 private uint bankNumber; 260 261 /* Registers */ 262 private uint DirectionMode = 0x00; 263 private uint OutputEnable = 0x00; 264 265 266 private enum registersOffsets : uint 267 { 268 DirectionMode = 0x04, 269 OutputEnable = 0x08, 270 InterruptMaskStatus = 0x0C, 271 InterruptEnable = 0x10, 272 InterruptDisable = 0x14, 273 InterruptPolarity = 0x18, 274 InterruptAnyEdgeSensitive = 0x1C 275 } 276 } 277 } 278 } 279 280