1 // 2 // Copyright (c) 2010-2024 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 System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Network; 15 using Antmicro.Renode.Utilities; 16 using MiscUtil.Conversion; 17 18 namespace Antmicro.Renode.Peripherals.Network 19 { 20 public class GaislerEth : NetworkWithPHY, IDoubleWordPeripheral, IGaislerAPB, IMACInterface, IKnownSize 21 { GaislerEth(IMachine machine)22 public GaislerEth(IMachine machine) : base(machine) 23 { 24 sysbus = machine.GetSystemBus(this); 25 IRQ = new GPIO(); 26 Reset(); 27 } 28 Reset()29 public override void Reset() 30 { 31 registers = new regs(); 32 MAC = new MACAddress(); 33 transmitDescriptorBase = 0; 34 transmitDescriptorOffset = 0; 35 receiveDescriptorBase = 0; 36 transmitDescriptorOffset = 0; 37 } 38 39 public GPIO IRQ { get; private set; } 40 41 #region IDoubleWordPeripheral implementation 42 ReadDoubleWord(long offset)43 public uint ReadDoubleWord(long offset) 44 { 45 switch((Registers)offset) 46 { 47 case Registers.Control: 48 return registers.Control; 49 case Registers.Status: 50 return registers.Status; 51 case Registers.MacAddressHi: 52 //return registers.MacAddresHi; 53 return (uint)EndianBitConverter.Big.ToUInt16(MAC.Bytes, 4); 54 case Registers.MacAddressLo: 55 //return registers.MacAddresLo; 56 return EndianBitConverter.Big.ToUInt32(MAC.Bytes, 0); 57 case Registers.MDIOControlStatus: 58 return registers.MDIOControlStatus; 59 case Registers.TxDescriptorPointer: 60 return registers.TxDescriptorPointer; 61 case Registers.RxDescriptorPointer: 62 return registers.RxDescriptorPointer; 63 case Registers.HashTableHi: 64 return registers.HashTableHi; 65 case Registers.HashTableLo: 66 return registers.HashTableLo; 67 default: 68 this.LogUnhandledRead(offset); 69 return 0u; 70 } 71 } 72 WriteDoubleWord(long offset, uint value)73 public void WriteDoubleWord(long offset, uint value) 74 { 75 switch((Registers)offset) 76 { 77 case Registers.Control: 78 if(value == 0x40) 79 { 80 break; 81 } 82 if((value & 0x01u) != 0) 83 { 84 this.transmitFrame(); 85 } 86 registers.Control = value; 87 break; 88 case Registers.Status: 89 //registers.Status = value; 90 registers.Status &= ~(value & 0xffu); 91 break; 92 case Registers.MacAddressHi: 93 registers.MacAddresHi = value; 94 var macBytes = EndianBitConverter.Big.GetBytes(value); 95 MAC = MAC.WithNewOctets(a: macBytes[2], b: macBytes[3]); 96 break; 97 case Registers.MacAddressLo: 98 registers.MacAddresLo = value; 99 macBytes = EndianBitConverter.Big.GetBytes(value); 100 MAC = MAC.WithNewOctets(c: macBytes[0], d: macBytes[1], e: macBytes[2], f: macBytes[3]); 101 break; 102 case Registers.MDIOControlStatus: 103 104 var id = ((value >> 11) & 0x1f); 105 var reg = ((value >> 6) & 0x1f); 106 var read = (value & 0x02) != 0; 107 var write = (value & 0x01) != 0; 108 109 if(!TryGetPhy<ushort>(id, out var phy)) 110 { 111 this.Log(LogLevel.Warning, "Write to phy with unknown ID {0}", id); 112 return; 113 } 114 if(read) 115 { 116 var phyRead = phy.Read((ushort)reg); 117 registers.MDIOControlStatus &= 0x0000FFFF;//clear data 118 registers.MDIOControlStatus |= (uint)(phyRead << 16); 119 } 120 else if(write) 121 { 122 phy.Write((ushort)reg, (ushort)((value >> 16) & 0xFFFF)); 123 } 124 else//unknown 125 { 126 this.Log(LogLevel.Warning, "Unknown phy operation - neither read nor write "); 127 } 128 /*if ( (registers.InterruptMask & (1u<<0)) == 0 ) 129 { 130 registers.InterruptStatus |= 1u<<0; 131 IRQ.Set(); 132 }*/ 133 break; 134 case Registers.TxDescriptorPointer: 135 registers.TxDescriptorPointer = value; 136 transmitDescriptorBase = value & ~(0x3ffu); 137 transmitDescriptorOffset = value & 0x3ffu; 138 break; 139 case Registers.RxDescriptorPointer: 140 registers.RxDescriptorPointer = value; 141 receiveDescriptorBase = value & ~(0x3ffu); 142 receiveDescriptorOffset = value & 0x3ffu; 143 break; 144 case Registers.HashTableHi: 145 registers.HashTableHi = value; 146 break; 147 case Registers.HashTableLo: 148 registers.HashTableLo = value; 149 break; 150 default: 151 this.LogUnhandledWrite(offset, value); 152 break; 153 } 154 } 155 156 #endregion 157 158 159 #region IGaislerAPB implementation 160 GetVendorID()161 public uint GetVendorID() 162 { 163 return vendorID; 164 } 165 GetDeviceID()166 public uint GetDeviceID() 167 { 168 return deviceID; 169 } 170 GetInterruptNumber()171 public uint GetInterruptNumber() 172 { 173 return this.GetCpuInterruptNumber(IRQ); 174 } 175 GetSpaceType()176 public GaislerAPBPlugAndPlayRecord.SpaceType GetSpaceType() 177 { 178 return GaislerAPBPlugAndPlayRecord.SpaceType.APBIOSpace; 179 } 180 181 public event Action<EthernetFrame> FrameReady; 182 183 private readonly uint vendorID = 0x01; 184 // Aeroflex Gaisler 185 private readonly uint deviceID = 0x1D; 186 // GRLIB GRETH 187 188 #endregion 189 190 #region IKnownSize implementation 191 192 public long Size 193 { 194 get 195 { 196 return 0x100; 197 } 198 } 199 200 #endregion 201 202 #region INetworkInterface implementation 203 ReceiveFrame(EthernetFrame frame)204 public void ReceiveFrame(EthernetFrame frame) 205 { 206 if((registers.Control & (1u << 1)) == 0) 207 { 208 //if receiving is disabled discard packet 209 return; 210 } 211 212 var rd = new receiveDescriptor(sysbus); 213 214 if(!EthernetFrame.CheckCRC(frame.Bytes)) 215 { 216 rd.CRCError = true; 217 this.Log(LogLevel.Warning, "Invalid CRC, packet discarded"); 218 return; 219 } 220 221 rd.Fetch(receiveDescriptorBase | receiveDescriptorOffset); 222 if(!rd.Enable) 223 { 224 //if receive descritptor disabled discard packet 225 return; 226 } 227 228 sysbus.WriteBytes(frame.Bytes, rd.PacketAddress); 229 registers.Status = 1u << 2; 230 if(rd.Wrap) 231 { 232 receiveDescriptorOffset = 0; 233 } 234 else 235 { 236 if(receiveDescriptorOffset != 0x3f8) 237 { 238 receiveDescriptorOffset += 8; 239 } 240 else 241 { 242 receiveDescriptorOffset = 0; 243 } 244 } 245 if(rd.InterruptEnable && ((registers.Control & (1u << 3)) != 0)) 246 { 247 registers.Status |= 1u << 2; 248 this.IRQ.Set(); 249 this.IRQ.Unset(); 250 } 251 rd.Length = (uint)frame.Bytes.Length; 252 rd.Enable = false; 253 rd.Wrap = false; 254 rd.WriteBack(); 255 } 256 transmitFrame()257 private void transmitFrame() 258 { 259 var td = new transmitDescriptor(sysbus); 260 td.Fetch(transmitDescriptorBase | transmitDescriptorOffset); 261 262 if(!td.Enable) 263 { 264 return; //if decriptor is disabled there is nothing to send (just return) 265 } 266 267 var packetBytes = sysbus.ReadBytes(td.PacketAddress, (int)td.Length); 268 if(!Misc.TryCreateFrameOrLogWarning(this, packetBytes, out var packet, addCrc: true)) 269 { 270 return; 271 } 272 273 this.Log(LogLevel.Noisy, "Sending packet length {0}, packet address = 0x{1:X}", packet.Bytes.Length, td.PacketAddress); 274 FrameReady?.Invoke(packet); 275 276 registers.Status |= 1u << 3; 277 278 if(td.Wrap) 279 { 280 transmitDescriptorOffset = 0; 281 } 282 else 283 { 284 if(transmitDescriptorOffset != 0x3f8) 285 { 286 transmitDescriptorOffset += 8; 287 } 288 else 289 { 290 transmitDescriptorOffset = 0; 291 } 292 } 293 294 if(td.InterruptEnable && ((registers.Control & (1u << 2)) != 0)) 295 { 296 //if interrupts enabled 297 registers.Status |= 1u << 3; //transmitter interrupt bit 298 this.IRQ.Set(); 299 this.IRQ.Unset(); 300 } 301 302 td.Enable = false; 303 td.Wrap = false; 304 td.InterruptEnable = false; 305 td.Length = 0; 306 td.UnderrunError = false; 307 td.AttemptLimitError = false; 308 td.WriteBack(); 309 310 } 311 312 #endregion 313 314 #region IMACInterface implementation 315 316 public MACAddress MAC { get; set; } 317 318 #endregion 319 320 private readonly IBusController sysbus; 321 322 #region registers 323 324 private regs registers; 325 326 private class regs 327 { 328 public uint Control = 1u << 7; 329 public uint Status; 330 public uint MacAddresHi; 331 public uint MacAddresLo; 332 public uint MDIOControlStatus; 333 public uint TxDescriptorPointer; 334 public uint RxDescriptorPointer; 335 public uint HashTableHi; 336 public uint HashTableLo; 337 } 338 339 private enum Registers : uint 340 { 341 Control = 0x00, 342 Status = 0x04, 343 MacAddressHi = 0x08, 344 MacAddressLo = 0x0C, 345 MDIOControlStatus = 0x10, 346 TxDescriptorPointer = 0x14, 347 RxDescriptorPointer = 0x18, 348 HashTableHi = 0x20, 349 HashTableLo = 0x24 350 } 351 352 #endregion 353 354 #region descriptors 355 356 private uint transmitDescriptorBase; 357 private uint transmitDescriptorOffset; 358 359 private uint receiveDescriptorBase; 360 private uint receiveDescriptorOffset; 361 362 private class transmitDescriptor 363 { transmitDescriptor(IBusController sysbus)364 public transmitDescriptor(IBusController sysbus) 365 { 366 sbus = sysbus; 367 } 368 369 private IBusController sbus; 370 371 private uint word0; 372 private uint word1; 373 private uint ramAddress; 374 375 public bool AttemptLimitError; 376 public bool UnderrunError; 377 public bool InterruptEnable; 378 public bool Wrap; 379 public bool Enable; 380 public uint Length; 381 public uint PacketAddress; 382 Fetch(uint address)383 public void Fetch(uint address) 384 { 385 ramAddress = address; 386 387 word0 = sbus.ReadDoubleWord(ramAddress); 388 word1 = sbus.ReadDoubleWord(ramAddress + 4); 389 390 AttemptLimitError = (word0 & (1u << 15)) != 0; 391 UnderrunError = (word0 & (1u << 14)) != 0; 392 InterruptEnable = (word0 & (1u << 13)) != 0; 393 Wrap = (word0 & (1u << 12)) != 0; 394 Enable = (word0 & (1u << 11)) != 0; 395 Length = word0 & 0x7ffu; 396 397 PacketAddress = word1 & ~(0x03u); 398 } 399 WriteBack()400 public void WriteBack() 401 { 402 word0 = (AttemptLimitError ? 1u << 15 : 0) | (UnderrunError ? 1u << 14 : 0) | (InterruptEnable ? 1u << 13 : 0); 403 word0 |= (Wrap ? 1u << 12 : 0) | (Enable ? 1u << 11 : 0) | (Length & 0x7ffu); 404 405 word1 = PacketAddress & ~(0x03u); 406 407 sbus.WriteDoubleWord(ramAddress, word0); 408 sbus.WriteDoubleWord(ramAddress + 4, word1); 409 } 410 } 411 412 private class receiveDescriptor 413 { receiveDescriptor(IBusController sysbus)414 public receiveDescriptor(IBusController sysbus) 415 { 416 sbus = sysbus; 417 } 418 419 private IBusController sbus; 420 421 private uint word0; 422 private uint word1; 423 private uint ramAddress; 424 425 public bool MulticastAddress; 426 public bool LengthError; 427 public bool OverrunError; 428 public bool CRCError; 429 public bool FrameTooLong; 430 public bool AlignmentError; 431 public bool InterruptEnable; 432 public bool Wrap; 433 public bool Enable; 434 public uint Length; 435 public uint PacketAddress; 436 Fetch(uint address)437 public void Fetch(uint address) 438 { 439 ramAddress = address; 440 word0 = sbus.ReadDoubleWord(ramAddress); 441 word1 = sbus.ReadDoubleWord(ramAddress + 4); 442 443 MulticastAddress = (word0 & (1u << 26)) != 0; 444 LengthError = (word0 & (1u << 18)) != 0; 445 OverrunError = (word0 & (1u << 17)) != 0; 446 CRCError = (word0 & (1u << 16)) != 0; 447 FrameTooLong = (word0 & (1u << 15)) != 0; 448 AlignmentError = (word0 & (1u << 14)) != 0; 449 InterruptEnable = (word0 & (1u << 13)) != 0; 450 Wrap = (word0 & (1u << 12)) != 0; 451 Enable = (word0 & (1u << 11)) != 0; 452 Length = word0 & (0x7ffu); 453 454 PacketAddress = word1 & ~(0x03u); 455 } 456 WriteBack()457 public void WriteBack() 458 { 459 word0 = (MulticastAddress ? 1u << 26 : 0) | (LengthError ? 1u << 18 : 0) | (OverrunError ? 1u << 17 : 0); 460 word0 |= (CRCError ? 1u << 16 : 0) | (FrameTooLong ? 1u << 15 : 0) | (AlignmentError ? 1u << 14 : 0); 461 word0 |= (InterruptEnable ? 1u << 13 : 0) | (Wrap ? 1u << 12 : 0) | (Enable ? 1u << 18 : 0) | (Length & (0x7ffu)); 462 463 word1 = PacketAddress & ~(0x03u); 464 465 sbus.WriteDoubleWord(ramAddress, word0); 466 sbus.WriteDoubleWord(ramAddress + 4, word1); 467 } 468 } 469 470 #endregion 471 } 472 } 473 474