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; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Network; 15 using Antmicro.Renode.Peripherals.Bus; 16 using Antmicro.Renode.Utilities; 17 using PacketDotNet; 18 using IPProtocolType = Antmicro.Renode.Network.IPProtocolType; 19 20 namespace Antmicro.Renode.Peripherals.Network 21 { 22 public class K6xF_Ethernet : NetworkWithPHY, IDoubleWordPeripheral, IMACInterface, IKnownSize 23 { K6xF_Ethernet(IMachine machine)24 public K6xF_Ethernet(IMachine machine) : base(machine) 25 { 26 sysbus = machine.GetSystemBus(this); 27 RxIRQ = new GPIO(); 28 TxIRQ = new GPIO(); 29 PtpIRQ = new GPIO(); 30 MiscIRQ = new GPIO(); 31 TimerIRQ = new GPIO(); 32 33 innerLock = new object(); 34 35 interruptManager = new InterruptManager<Interrupts>(this); 36 37 var registerMap = new Dictionary<long, DoubleWordRegister> 38 { 39 {(long)Registers.InterruptEvent, interruptManager.GetRegister<DoubleWordRegister>( 40 valueProviderCallback: (interrupt, oldValue) => 41 { 42 return interruptManager.IsSet(interrupt); 43 }, 44 writeCallback: (interrupt, oldValue, newValue) => 45 { 46 if(newValue) 47 { 48 interruptManager.ClearInterrupt(interrupt); 49 } 50 }) 51 }, 52 {(long)Registers.InterruptMask, interruptManager.GetRegister<DoubleWordRegister>( 53 valueProviderCallback: (interrupt, oldValue) => 54 { 55 return interruptManager.IsEnabled(interrupt); 56 }, 57 writeCallback: (interrupt, oldValue, newValue) => 58 { 59 if(newValue) 60 { 61 interruptManager.EnableInterrupt(interrupt); 62 } 63 else 64 { 65 interruptManager.DisableInterrupt(interrupt); 66 interruptManager.ClearInterrupt(interrupt); 67 } 68 }) 69 }, 70 {(long)Registers.ReceiveDescriptorActive, new DoubleWordRegister(this) 71 .WithReservedBits(25, 7) 72 .WithFlag(24, out receiverEnabled, name: "RDAR") 73 .WithReservedBits(0, 24) 74 }, 75 {(long)Registers.TransmitDescriptorActive, new DoubleWordRegister(this) 76 .WithReservedBits(25, 7) 77 .WithFlag(24, FieldMode.Read | FieldMode.WriteOneToClear, name: "TDAR", 78 writeCallback: (_, value) => 79 { 80 // transmission should be started on *any* write to this field (i.e., including 0) 81 isTransmissionStarted = true; 82 this.Log(LogLevel.Debug, "Sending Frames"); 83 SendFrames(); 84 }) 85 .WithReservedBits(0, 24) 86 }, 87 {(long)Registers.EthernetControl, new DoubleWordRegister(this) 88 .WithReservedBits(17, 15) 89 .WithReservedBits(12, 5) 90 .WithReservedBits(11, 1) 91 .WithReservedBits(10, 1) 92 .WithReservedBits(9, 1) 93 .WithTaggedFlag("DBSWP", 8) 94 .WithTaggedFlag("STOPEN", 7) 95 .WithTaggedFlag("DBGEN", 6) 96 .WithReservedBits(5, 1) 97 .WithFlag(4, out extendedMode, name: "EN1588") 98 .WithTaggedFlag("SLEEP", 3) 99 .WithTaggedFlag("MAGICEN", 2) 100 .WithTaggedFlag("ETHEREN", 1) 101 .WithFlag(0, FieldMode.Write, 102 writeCallback: (_, b) => 103 { 104 if(b) 105 { 106 Reset(); 107 } 108 },name: "RESET") 109 }, 110 {(long)Registers.MIIManagementFrame, new DoubleWordRegister(this) 111 .WithValueField(0, 31, name: "phy_management", writeCallback: (_, value) => HandlePhyWrite((uint)value), valueProviderCallback: _ => HandlePhyRead()) 112 }, 113 {(long)Registers.ReceiveControl, new DoubleWordRegister(this) 114 .WithTaggedFlag("GRS", 31) 115 .WithTaggedFlag("NLC", 30) 116 .WithValueField(16, 14, name: "MAX_FL") 117 .WithTaggedFlag("CFEN", 15) 118 .WithTaggedFlag("CRCFWD", 14) 119 .WithTaggedFlag("PAUFWD", 13) 120 .WithTaggedFlag("PADEN", 12) 121 .WithReservedBits(10, 2) 122 .WithTaggedFlag("RMII_10T", 9) 123 .WithTaggedFlag("RMII_MODE", 8) 124 .WithReservedBits(7, 1) 125 .WithReservedBits(6, 1) 126 .WithTaggedFlag("FCE", 5) 127 .WithTaggedFlag("BC_REJ", 4) 128 .WithTaggedFlag("PROM", 3) 129 .WithTaggedFlag("MII_MODE", 2) 130 .WithTaggedFlag("DRT", 1) 131 .WithTaggedFlag("LOOP", 0) 132 }, 133 {(long)Registers.TransmitControl, new DoubleWordRegister(this) 134 .WithReservedBits(11, 21) 135 .WithReservedBits(10, 1) 136 .WithFlag(9, out forwardCRCFromApplication, name: "CRCFWD") 137 .WithTaggedFlag("ADDINS", 8) 138 .WithValueField(5, 3, name: "ADDSEL") 139 .WithTaggedFlag("RFC_PAUSE", 4) 140 .WithTaggedFlag("TFC_PAUSE", 3) 141 .WithTaggedFlag("FDEN", 2) 142 .WithReservedBits(1, 1) 143 .WithTaggedFlag("GTS", 0) 144 }, 145 {(long)Registers.PhysicalAddressLower, new DoubleWordRegister(this) 146 .WithValueField(0, 32, out lowerMAC, writeCallback: (_, value) => 147 { 148 UpdateMac(); 149 }, name: "PADDR1") 150 }, 151 {(long)Registers.PhysicalAddressUpper, new DoubleWordRegister(this) 152 .WithValueField(16, 16, out upperMAC, writeCallback: (_, value) => 153 { 154 UpdateMac(); 155 },name: "PADDR2") 156 .WithValueField(0, 16, name: "TYPE") 157 }, 158 {(long)Registers.TransmitFIFOWatermark, new DoubleWordRegister(this) 159 .WithReservedBits(9, 22) 160 .WithTaggedFlag("STRFWD", 8) 161 .WithReservedBits(6, 2) 162 .WithValueField(0, 6, name:"TFWR") 163 }, 164 {(long)Registers.ReceiveDescriptorRingStart, new DoubleWordRegister(this) 165 .WithValueField(2, 30, name:"R_DES_START", 166 writeCallback: (oldValue, value) => 167 { 168 if(receiverEnabled.Value) 169 { 170 this.Log(LogLevel.Warning, "Changing value of receive buffer queue base address while reception is enabled is illegal"); 171 return; 172 } 173 rxDescriptorsQueue = new DmaBufferDescriptorsQueue<DmaRxBufferDescriptor>(sysbus, (uint)value << 2, (sb, addr) => new DmaRxBufferDescriptor(sb, addr, extendedMode.Value)); 174 }) 175 .WithReservedBits(1, 1) 176 .WithReservedBits(0, 1) 177 }, 178 {(long)Registers.TransmitBufferDescriptorRingStart, new DoubleWordRegister(this) 179 .WithValueField(2, 30, name:"X_DES_START", 180 writeCallback: (oldValue, value) => 181 { 182 if(isTransmissionStarted) 183 { 184 this.Log(LogLevel.Warning, "Changing value of transmit buffer descriptor ring start address while transmission is started is illegal"); 185 return; 186 } 187 txDescriptorsQueue = new DmaBufferDescriptorsQueue<DmaTxBufferDescriptor>(sysbus, (uint)value << 2, (sb, addr) => new DmaTxBufferDescriptor(sb, addr, extendedMode.Value)); 188 }) 189 .WithReservedBits(1, 1) 190 .WithReservedBits(0, 1) 191 }, 192 {(long)Registers.TransmitAcceleratorFunctionConfiguration, new DoubleWordRegister(this) 193 .WithTaggedFlag("SHIFT16", 0) 194 .WithReservedBits(1, 2) 195 .WithFlag(3, out insertIPHeaderChecksum, name: "IPCHK") 196 .WithFlag(4, out insertProtocolChecksum, name: "PROCHK") 197 .WithReservedBits(5, 27) 198 }, 199 {(long)Registers.ReceiveAcceleratorFunctionConfiguration, new DoubleWordRegister(this) 200 .WithTaggedFlag("PADREM", 0) 201 .WithFlag(1, out discardIPHeaderInvalidChecksum, name: "IPDIS") 202 .WithFlag(2, out discardProtocolInvalidChecksum, name: "PRODIS") 203 .WithReservedBits(3, 3) 204 .WithFlag(6, out discardWithMACLayerError, name: "LINEDIS") 205 .WithTaggedFlag("SHIFT16", 7) 206 .WithReservedBits(8, 24) 207 } 208 }; 209 210 registers = new DoubleWordRegisterCollection(this, registerMap); 211 } 212 ReadDoubleWord(long offset)213 public uint ReadDoubleWord(long offset) 214 { 215 return registers.Read(offset); 216 } 217 ReceiveFrame(EthernetFrame frame)218 public void ReceiveFrame(EthernetFrame frame) 219 { 220 lock(innerLock) 221 { 222 this.Log(LogLevel.Debug, "Received packet, length {0}", frame.Bytes.Length); 223 if(!receiverEnabled.Value) 224 { 225 this.Log(LogLevel.Info, "Receiver not enabled, dropping frame"); 226 return; 227 } 228 229 if(discardWithMACLayerError.Value && !EthernetFrame.CheckCRC(frame.Bytes)) 230 { 231 this.Log(LogLevel.Info, "Invalid CRC, packet discarded"); 232 return; 233 } 234 235 if(discardIPHeaderInvalidChecksum.Value) 236 { 237 var packet = (IPv4Packet)frame.UnderlyingPacket.Extract(typeof(IPv4Packet)); 238 if(packet != null && !packet.ValidChecksum) 239 { 240 this.Log(LogLevel.Info, "Invalid IpV4 checksum, packet discarded"); 241 return; 242 } 243 } 244 245 if(discardProtocolInvalidChecksum.Value) 246 { 247 var tcpPacket = (TcpPacket)frame.UnderlyingPacket.Extract(typeof(TcpPacket)); 248 if(tcpPacket != null && !tcpPacket.ValidChecksum) 249 { 250 this.Log(LogLevel.Info, "Invalid TCP checksum, packet discarded"); 251 return; 252 } 253 254 var udpPacket = (UdpPacket)frame.UnderlyingPacket.Extract(typeof(UdpPacket)); 255 if(udpPacket != null && !udpPacket.ValidChecksum) 256 { 257 this.Log(LogLevel.Info, "Invalid UDP checksum, packet discarded"); 258 return; 259 } 260 261 var icmpv4Packet = (ICMPv4Packet)frame.UnderlyingPacket.Extract(typeof(ICMPv4Packet)); 262 if(icmpv4Packet != null) 263 { 264 var checksum = icmpv4Packet.Checksum; 265 icmpv4Packet.Checksum = 0x0; 266 icmpv4Packet.UpdateCalculatedValues(); 267 if(checksum != icmpv4Packet.Checksum) 268 { 269 this.Log(LogLevel.Info, "Invalid ICMPv4 checksum, packet discarded"); 270 return; 271 } 272 } 273 274 var icmpv6Packet = (ICMPv6Packet)frame.UnderlyingPacket.Extract(typeof(ICMPv6Packet)); 275 if(icmpv6Packet != null) 276 { 277 var checksum = icmpv6Packet.Checksum; 278 icmpv6Packet.Checksum = 0x0; 279 icmpv6Packet.UpdateCalculatedValues(); 280 if(checksum != icmpv6Packet.Checksum) 281 { 282 this.Log(LogLevel.Info, "Invalid ICMPv6 checksum, packet discarded"); 283 return; 284 } 285 } 286 } 287 288 rxDescriptorsQueue.CurrentDescriptor.Read(); 289 if(rxDescriptorsQueue.CurrentDescriptor.IsEmpty) 290 { 291 if(!rxDescriptorsQueue.CurrentDescriptor.WriteBuffer(frame.Bytes, (uint)frame.Bytes.Length)) 292 { 293 // The current implementation doesn't handle packets that do not fit into a single buffer. 294 // In case we encounter this error, we probably should implement partitioning/scattering procedure. 295 this.Log(LogLevel.Warning, "Could not write the incoming packet to the DMA buffer: maximum packet length exceeded."); 296 return; 297 } 298 299 rxDescriptorsQueue.CurrentDescriptor.Length = (ushort)frame.Bytes.Length; 300 // Packets going over several buffers not supported 301 rxDescriptorsQueue.CurrentDescriptor.IsLast = true; 302 rxDescriptorsQueue.CurrentDescriptor.IsEmpty = false; 303 // write this back to memory 304 rxDescriptorsQueue.CurrentDescriptor.Update(); 305 306 rxDescriptorsQueue.GoToNextDescriptor(); 307 308 interruptManager.SetInterrupt(Interrupts.ReceiveBufferInterrupt); 309 interruptManager.SetInterrupt(Interrupts.ReceiveFrameInterrupt); 310 } 311 else 312 { 313 this.Log(LogLevel.Warning, "Receive DMA buffer overflow"); 314 } 315 } 316 } 317 Reset()318 public override void Reset() 319 { 320 isTransmissionStarted = false; 321 registers.Reset(); 322 txDescriptorsQueue = null; 323 rxDescriptorsQueue = null; 324 interruptManager.Reset(); 325 } 326 WriteDoubleWord(long offset, uint value)327 public void WriteDoubleWord(long offset, uint value) 328 { 329 registers.Write(offset, value); 330 } 331 332 public MACAddress MAC { get; set; } 333 334 public long Size => 0x1000; 335 336 public event Action<EthernetFrame> FrameReady; 337 338 [IrqProvider("timer irq", 4)] 339 public GPIO TimerIRQ { get; } 340 341 [IrqProvider("ptp irq", 3)] 342 public GPIO PtpIRQ { get; } 343 344 [IrqProvider("misc irq", 2)] 345 public GPIO MiscIRQ { get; } 346 347 [IrqProvider("receive irq", 1)] 348 public GPIO RxIRQ { get; } 349 350 [IrqProvider("transmit irq", 0)] 351 public GPIO TxIRQ { get; } 352 UpdateMac()353 private void UpdateMac() 354 { 355 var finalMac = (ulong)((lowerMAC.Value << 32) + upperMAC.Value); 356 this.Log(LogLevel.Info, "Setting MAC to {0:X}", finalMac); 357 MAC = new MACAddress(finalMac); 358 } 359 SendSingleFrame(IEnumerable<byte> bytes, bool isCRCIncluded)360 private void SendSingleFrame(IEnumerable<byte> bytes, bool isCRCIncluded) 361 { 362 if(forwardCRCFromApplication.Value && !isCRCIncluded) 363 { 364 this.Log(LogLevel.Error, "CRC needs to be provided by the application but is missing"); 365 return; 366 } 367 368 var bytesArray = bytes.ToArray(); 369 var newLength = isCRCIncluded ? 64 : 60; 370 if(bytesArray.Length < newLength) 371 { 372 Array.Resize(ref bytesArray, newLength); 373 } 374 375 var addCrc = !isCRCIncluded && !forwardCRCFromApplication.Value; 376 if(!Misc.TryCreateFrameOrLogWarning(this, bytesArray, out var frame, addCrc)) 377 { 378 return; 379 } 380 381 if(insertProtocolChecksum.Value) 382 { 383 frame.FillWithChecksums(new EtherType[] {}, new [] { IPProtocolType.ICMP, IPProtocolType.ICMPV6, IPProtocolType.TCP, IPProtocolType.UDP }); 384 } 385 if(insertIPHeaderChecksum.Value) 386 { 387 frame.FillWithChecksums(new [] { EtherType.IpV4 }, new IPProtocolType[] {}); 388 } 389 390 this.Log(LogLevel.Debug, "Sending packet, length {0}", frame.Bytes.Length); 391 FrameReady?.Invoke(frame); 392 } 393 SendFrames()394 private void SendFrames() 395 { 396 lock(innerLock) 397 { 398 var packetBytes = new List<byte>(); 399 txDescriptorsQueue.CurrentDescriptor.Read(); 400 while(txDescriptorsQueue.CurrentDescriptor.IsReady) 401 { 402 // fill packet with data from memory 403 this.Log(LogLevel.Debug, "Buffer Length {0}", txDescriptorsQueue.CurrentDescriptor.Length); 404 packetBytes.AddRange(txDescriptorsQueue.CurrentDescriptor.ReadBuffer()); 405 if(txDescriptorsQueue.CurrentDescriptor.IsLast) 406 { 407 // IncludeCRC is only valid for the buffer with IsLast set 408 SendSingleFrame(packetBytes, !txDescriptorsQueue.CurrentDescriptor.IncludeCRC); 409 packetBytes.Clear(); 410 } 411 412 // Need to update the ready flag after processing 413 txDescriptorsQueue.CurrentDescriptor.IsReady = false; // free it up 414 txDescriptorsQueue.CurrentDescriptor.Update(); // write back to memory 415 txDescriptorsQueue.GoToNextDescriptor(); 416 } 417 418 this.Log(LogLevel.Debug, "Transmission completed"); 419 isTransmissionStarted = false; 420 421 interruptManager.SetInterrupt(Interrupts.TransmitFrameInterrupt); 422 interruptManager.SetInterrupt(Interrupts.TransmitBufferInterrupt); 423 } 424 } 425 HandlePhyRead()426 private uint HandlePhyRead() 427 { 428 return phyDataRead; 429 } 430 HandlePhyWrite(uint value)431 private void HandlePhyWrite(uint value) 432 { 433 lock(innerLock) 434 { 435 var data = (ushort)(value & 0xFFFF); 436 var reg = (ushort)((value >> 18) & 0x1F); 437 var addr = (uint)((value >> 23) & 0x1F); 438 var op = (PhyOperation)((value >> 28) & 0x3); 439 440 if(!TryGetPhy<ushort>(addr, out var phy)) 441 { 442 this.Log(LogLevel.Warning, "Write to PHY with unknown address {0}", addr); 443 phyDataRead = 0xFFFFU; 444 return; 445 } 446 447 switch(op) 448 { 449 case PhyOperation.Read: 450 phyDataRead = phy.Read(reg); 451 break; 452 case PhyOperation.Write: 453 phy.Write(reg, data); 454 break; 455 default: 456 this.Log(LogLevel.Warning, "Unknown PHY operation code 0x{0:X}", op); 457 break; 458 } 459 460 interruptManager.SetInterrupt(Interrupts.MIIInterrupt); 461 } 462 } 463 private uint phyDataRead; 464 private DmaBufferDescriptorsQueue<DmaTxBufferDescriptor> txDescriptorsQueue; 465 private DmaBufferDescriptorsQueue<DmaRxBufferDescriptor> rxDescriptorsQueue; 466 467 private readonly IBusController sysbus; 468 private readonly InterruptManager<Interrupts> interruptManager; 469 private readonly DoubleWordRegisterCollection registers; 470 private readonly object innerLock; 471 472 // Fields needed for the internal logic 473 private bool isTransmissionStarted = false; 474 475 //EthernetControl 476 private readonly IFlagRegisterField extendedMode; 477 478 //TransmitControl 479 private readonly IFlagRegisterField forwardCRCFromApplication; 480 481 //ReceiveControl 482 private readonly IFlagRegisterField receiverEnabled; 483 484 //TransmitAcceleratorFunctionConfiguration 485 private readonly IFlagRegisterField insertIPHeaderChecksum; 486 private readonly IFlagRegisterField insertProtocolChecksum; 487 488 //ReceiveAcceleratorFunctionConfiguration 489 private readonly IFlagRegisterField discardIPHeaderInvalidChecksum; 490 private readonly IFlagRegisterField discardProtocolInvalidChecksum; 491 private readonly IFlagRegisterField discardWithMACLayerError; 492 493 private readonly IValueRegisterField lowerMAC; 494 private readonly IValueRegisterField upperMAC; 495 496 private enum Registers 497 { 498 InterruptEvent = 0x0004, 499 InterruptMask = 0x0008, 500 ReceiveDescriptorActive = 0x0010, 501 TransmitDescriptorActive = 0x0014, 502 EthernetControl = 0x0024, 503 MIIManagementFrame = 0x0040, 504 MIISpeedControl = 0x0044, 505 MIBControl = 0x0064, 506 ReceiveControl = 0x0084, 507 TransmitControl = 0x00C4, 508 PhysicalAddressLower = 0x00E4, 509 PhysicalAddressUpper = 0x00E8, 510 OpcodePauseDuration = 0x00EC, 511 TransmitInterruptCoalescing = 0x00F0, 512 ReceiveInterruptCoalescing = 0x0100, 513 DescriptorIndividualUpperAddress = 0x0118, 514 DescriptorIndividualLowerAddress = 0x011C, 515 DescriptorGroupUpperAddress = 0x0120, 516 DescriptorGroupLowerAddress = 0x0124, 517 TransmitFIFOWatermark = 0x0144, 518 ReceiveDescriptorRingStart = 0x0180, 519 TransmitBufferDescriptorRingStart = 0x0184, 520 MaximumReceiveBufferSize = 0x0188, 521 ReceiveFIFOSectionFullThreshold = 0x0190, 522 ReceiveFIFOSectionEmptyThreshold = 0x0194, 523 ReceiveFIFOAlmostEmptyThreshold = 0x0198, 524 ReceiveFIFOAlmostFullThreshold = 0x019C, 525 TransmitFIFOSectionEmptyThreshold = 0x01A0, 526 TransmitFIFOAlmostEmptyThreshold = 0x01A4, 527 TransmitFIFOAlmostFullThreshold = 0x01A8, 528 TransmitInterPacketGap = 0x01AC, 529 FrameTruncationLength = 0x01B0, 530 TransmitAcceleratorFunctionConfiguration = 0x01C0, 531 ReceiveAcceleratorFunctionConfiguration = 0x01C4, 532 TxPacketCountStatistic = 0x0204, 533 TxBroadcastPacketsStatistic = 0x0208, 534 TxMulticastPacketsStatistic = 0x020C, 535 TxPacketswithCRCAlignErrorStatistic = 0x0210, 536 TxPacketsLessThanBytesandGoodCRCStatistic = 0x0214, 537 TxPacketsGTMAX_FLbytesandGoodCRCStatistic = 0x0218, 538 TxPacketsLessThan64BytesandBadCRCStatistic = 0x021C, 539 TxPacketsGreaterThanMAX_FLbytesandBadCRC = 0x0220, 540 TxCollisionCountStatistic = 0x0224, 541 Tx64BytePacketsStatistic = 0x0228, 542 Tx65to127bytePacketsStatistic = 0x022C, 543 Tx128to255bytePacketsStatistic = 0x0230, 544 Tx256to511bytePacketsStatistic = 0x0234, 545 Tx512to1023bytePacketsStatistic = 0x0238, 546 Tx1024to2047bytePacketsStatistic = 0x023C, 547 TxPacketsGreaterThan2048BytesStatistic = 0x0240, 548 TxOctetsStatistic = 0x0244, 549 FramesTransmittedOKStatistic = 0x024C, 550 FramesTransmittedwithSingleCollisionStatistic = 0x0250, 551 FramesTransmittedwithMultipleCollisionsStatistic = 0x0254, 552 FramesTransmittedafterDeferralDelayStatistic = 0x0258, 553 FramesTransmittedwithLateCollisionStatistic = 0x025C, 554 FramesTransmittedwithExcessiveCollisionsStatistic = 0x0260, 555 FramesTransmittedwithTxFIFOUnderrunStatistic = 0x0264, 556 FramesTransmittedwithCarrierSenseErrorStatistic = 0x0268, 557 FlowControlPauseFramesTransmittedStatistic = 0x0270, 558 OctetCountforFramesTransmittedwoErrorStatistic = 0x0274, 559 RxPacketCountStatistic = 0x0284, 560 RxBroadcastPacketsStatistic = 0x0288, 561 RxMulticastPacketsStatistic = 0x028C, 562 RxPacketswithCRCAlignErrorStatistic = 0x0290, 563 RxPacketswithLessThan64BytesandGoodCRC = 0x0294, 564 RxPacketsGreaterThanMAX_FLandGoodCRCStatistic = 0x0298, 565 RxPacketsLessThan64BytesandBadCRCStatistic = 0x029C, 566 RxPacketsGreaterThanMAX_FLBytesandBadCRC = 0x02A0, 567 Rx64BytePacketsStatistic = 0x02A8, 568 Rx65to127BytePacketsStatistic = 0x02AC, 569 Rx128to255BytePacketsStatistic = 0x02B0, 570 Rx256to511BytePacketsStatistic = 0x02B4, 571 Rx512to1023BytePacketsStatistic = 0x02B8, 572 Rx1024to2047BytePacketsStatistic = 0x02BC, 573 RxPacketsGreaterthan2048BytesStatistic = 0x02C0, 574 RxOctetsStatistic = 0x02C4, 575 FramesnotCountedCorrectlyStatistic = 0x02C8, 576 FramesReceivedOKStatistic = 0x02CC, 577 FramesReceivedwithCRCErrorStatistic = 0x02D0, 578 FramesReceivedwithAlignmentErrorStatistic = 0x02D4, 579 ReceiveFIFOOverflowCountStatistic = 0x02D8, 580 FlowControlPauseFramesReceivedStatistic = 0x02DC, 581 OctetCountforFramesReceivedwithoutErrorStatistic = 0x02E0, 582 AdjustableTimerControl = 0x0400, 583 TimerValue = 0x0404, 584 TimerOffset = 0x0408, 585 TimerPeriod = 0x040C, 586 TimerCorrection = 0x0410, 587 TimeStampingClockPeriod = 0x0414, 588 TimestampofLastTransmittedFrame = 0x0418, 589 TimerGlobalStatus = 0x0604, 590 TimerControlStatusR0 = 0x0608, 591 TimerCompareCaptureR0 = 0x060C, 592 TimerControlStatusR1 = 0x0610, 593 TimerCompareCaptureR1 = 0x0614, 594 TimerControlStatusR2 = 0x0618, 595 TimerCompareCaptureR2 = 0x061C, 596 TimerControlStatusR3 = 0x0620, 597 TimerCompareCaptureR3 = 0x0624 598 } 599 600 private enum Interrupts 601 { 602 [Subvector(1)] 603 BabblingReceiveError = 30, 604 [Subvector(0)] 605 BabblingTransmitError = 29, 606 [Subvector(2)] 607 GracefulStopComplete = 28, 608 [Subvector(0)] 609 TransmitFrameInterrupt = 27, 610 [Subvector(0)] 611 TransmitBufferInterrupt = 26, 612 [Subvector(1)] 613 ReceiveFrameInterrupt = 25, 614 [Subvector(1)] 615 ReceiveBufferInterrupt = 24, 616 [Subvector(2)] 617 MIIInterrupt = 23, 618 [Subvector(2)] 619 EthernetBusError = 22, 620 [Subvector(2)] 621 LateCollision = 21, 622 [Subvector(2)] 623 CollisionRetryLimit = 20, 624 [Subvector(2)] 625 TransmitFIFOUnderrun = 19, 626 [Subvector(2)] 627 PayloadReceiveError = 18, 628 [Subvector(2)] 629 NodeWakeupRequestIndication = 17, 630 [Subvector(3)] 631 TransmitTimestampAvailable = 16, 632 [Subvector(4)] 633 TimestampTimer = 15 634 } 635 636 private enum PhyOperation 637 { 638 Write = 0x1, 639 Read = 0x2 640 } 641 642 private class DmaBufferDescriptorsQueue<T> where T : DmaBufferDescriptor 643 { DmaBufferDescriptorsQueue(IBusController bus, uint baseAddress, Func<IBusController, uint, T> creator)644 public DmaBufferDescriptorsQueue(IBusController bus, uint baseAddress, Func<IBusController, uint, T> creator) 645 { 646 this.bus = bus; 647 this.creator = creator; 648 this.baseAddress = baseAddress; 649 descriptors = new List<T>(); 650 GoToNextDescriptor(); 651 } 652 GoToNextDescriptor()653 public void GoToNextDescriptor() 654 { 655 if(descriptors.Count == 0) 656 { 657 // this is the first descriptor - read it from baseAddress 658 descriptors.Add(creator(bus, baseAddress)); 659 currentDescriptorIndex = 0; 660 } 661 else 662 { 663 // If wrap is set, we have reached end of ring and need to start from the beginning 664 if(CurrentDescriptor.Wrap) 665 { 666 currentDescriptorIndex = 0; 667 } 668 else 669 { 670 descriptors.Add(creator(bus, CurrentDescriptor.DescriptorAddress + CurrentDescriptor.SizeInBytes)); 671 currentDescriptorIndex++; 672 } 673 } 674 CurrentDescriptor.Read(); 675 } 676 GoToBaseAddress()677 public void GoToBaseAddress() 678 { 679 currentDescriptorIndex = 0; 680 CurrentDescriptor.Read(); 681 } 682 683 public T CurrentDescriptor => descriptors[currentDescriptorIndex]; 684 685 private int currentDescriptorIndex; 686 687 private readonly List<T> descriptors; 688 private readonly uint baseAddress; 689 private readonly IBusController bus; 690 private readonly Func<IBusController, uint, T> creator; 691 } 692 693 private class DmaBufferDescriptor 694 { DmaBufferDescriptor(IBusController bus, uint address, bool isExtendedModeEnabled)695 protected DmaBufferDescriptor(IBusController bus, uint address, bool isExtendedModeEnabled) 696 { 697 Bus = bus; 698 DescriptorAddress = address; 699 IsExtendedModeEnabled = isExtendedModeEnabled; 700 SizeInBytes = InitWords(); 701 } 702 Read()703 public void Read() 704 { 705 var tempOffset = 0UL; 706 for(var i = 0; i < words.Length; ++i) 707 { 708 words[i] = Bus.ReadDoubleWord(DescriptorAddress + tempOffset); 709 tempOffset += 2; 710 } 711 } 712 Update()713 public void Update() 714 { 715 var tempOffset = 0UL; 716 foreach(var word in words) 717 { 718 Bus.WriteDoubleWord(DescriptorAddress + tempOffset, word); 719 tempOffset += 2; 720 } 721 } 722 723 public IBusController Bus { get; } 724 public uint SizeInBytes { get; } 725 public bool IsExtendedModeEnabled { get; } 726 public uint DescriptorAddress { get; } 727 728 public bool Wrap => BitHelper.IsBitSet(words[1], 13); 729 730 public uint DataBufferAddress => (words[3] << 16) | words[2]; 731 732 public bool IsLast => BitHelper.IsBitSet(words[1], 11); 733 734 protected uint[] words; 735 InitWords()736 private uint InitWords() 737 { 738 if(IsExtendedModeEnabled) 739 { 740 words = new uint[16]; 741 } 742 else 743 { 744 words = new uint[4]; 745 } 746 return (uint)words.Length * 2; 747 } 748 } 749 750 /// Legacy Transmit Buffer 751 /// 752 /// ================================================================================= 753 /// | Byte 1 | Byte 0 | 754 /// | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 755 /// ================================================================================= 756 /// Offset +0| Data Length | 757 /// Offset +2| R | TO1| W | TO2| L | TC |ABC | -- | -- | -- | -- | -- | -- | -- | -- | -- | 758 /// Offset +4| Tx Data Buffer Pointer -- low halfword | 759 /// Offset +6| Tx Data Buffer Pointer -- high halfword | 760 /// ================================================================================= 761 /// 762 /// 763 /// Enhanced Transmit Buffer 764 /// 765 /// ================================================================================= 766 /// | Byte 1 | Byte 0 | 767 /// | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 768 /// ================================================================================= 769 /// Offset +0| Data Length | 770 /// Offset +2| R | TO1| W | TO2| L | TC | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 771 /// Offset +4| Tx Data Buffer Pointer -- low halfword | 772 /// Offset +6| Tx Data Buffer Pointer -- high halfword | 773 /// Offset +8| TXE| -- | UE | EE | FE | LCE| OE | TSE| -- | -- | -- | -- | -- | -- | -- | -- | 774 /// Offset +A| -- | INT| TS |PINS|IINS| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 775 /// Offset +C| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 776 /// Offset +E| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 777 /// Offset+10| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 778 /// Offset+12| BDU| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 779 /// Offset+14| 1588 timestamp - low halfword | 780 /// Offset+16| 1588 timestamp - high halfword | 781 /// Offset+18| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 782 /// Offset+1A| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 783 /// Offset+1C| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 784 /// Offset+1E| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 785 /// ================================================================================= 786 private class DmaTxBufferDescriptor : DmaBufferDescriptor 787 { DmaTxBufferDescriptor(IBusController bus, uint address, bool isExtendedModeEnabled)788 public DmaTxBufferDescriptor(IBusController bus, uint address, bool isExtendedModeEnabled) : 789 base(bus, address, isExtendedModeEnabled) 790 { 791 } 792 ReadBuffer()793 public byte[] ReadBuffer() 794 { 795 return Bus.ReadBytes(DataBufferAddress, Length, true); 796 } 797 798 public ushort Length => (ushort)words[0]; 799 800 public bool IncludeCRC => BitHelper.IsBitSet(words[1], 10); 801 802 public bool IsReady 803 { 804 get 805 { 806 return BitHelper.IsBitSet(words[1], 15); 807 } 808 set 809 { 810 BitHelper.SetBit(ref words[1], 15, value); 811 } 812 } 813 } 814 815 /// Legacy Receive Buffer 816 /// 817 /// ================================================================================= 818 /// | Byte 1 | Byte 0 | 819 /// | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 820 /// ================================================================================= 821 /// Offset +0| Data Length | 822 /// Offset +2| E | RO1| W | RO2| L | -- | -- | M | BC | MC | LG | NO | -- | -- | -- | TR | 823 /// Offset +4| Rx Data Buffer Pointer -- low halfword | 824 /// Offset +6| Rx Data Buffer Pointer -- high halfword | 825 /// ================================================================================= 826 /// 827 /// 828 /// Enhanced Receive Buffer 829 /// 830 /// ================================================================================= 831 /// | Byte 1 | Byte 0 | 832 /// | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | 833 /// ================================================================================= 834 /// Offset +0| Data Length | 835 /// Offset +2| E | RO1| W | RO2| L | -- | -- | M | BC | MC | LG | NO | -- | CR | OV | TR | 836 /// Offset +4| Rx Data Buffer Pointer -- low halfword | 837 /// Offset +6| Rx Data Buffer Pointer -- high halfword | 838 /// Offset +8| VPCP | -- | -- | -- | -- | -- | -- | -- | ICE| PCR| -- |VLAN|IPV6|FRAG| 839 /// Offset +A| ME | -- | -- | -- | -- | PE | CE | UC | INT| -- | -- | -- | -- | -- | -- | -- | 840 /// Offset +C| Payload Checksum | 841 /// Offset +E| Header length | -- | -- | -- | Protocol Type | 842 /// Offset+10| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 843 /// Offset+12| BDU| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 844 /// Offset+14| 1588 timestamp - low halfword | 845 /// Offset+16| 1588 timestamp - high halfword | 846 /// Offset+18| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 847 /// Offset+1A| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 848 /// Offset+1C| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 849 /// Offset+1E| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | 850 /// ================================================================================= 851 private class DmaRxBufferDescriptor : DmaBufferDescriptor 852 { DmaRxBufferDescriptor(IBusController bus, uint address, bool isExtendedModeEnabled)853 public DmaRxBufferDescriptor(IBusController bus, uint address, bool isExtendedModeEnabled) : 854 base(bus, address, isExtendedModeEnabled) 855 { 856 } 857 ReadBuffer()858 public byte[] ReadBuffer() 859 { 860 return Bus.ReadBytes(DataBufferAddress, Length, true); 861 } 862 863 public ushort Length 864 { 865 get 866 { 867 return (ushort)words[0]; 868 } 869 set 870 { 871 words[0] = value; 872 } 873 } 874 875 public bool IsEmpty 876 { 877 get 878 { 879 return BitHelper.IsBitSet(words[1], 15); 880 } 881 set 882 { 883 BitHelper.SetBit(ref words[1], 15, value); 884 } 885 } 886 887 public new bool IsLast 888 { 889 set 890 { 891 BitHelper.SetBit(ref words[1], 11, value); 892 } 893 } 894 WriteBuffer(byte[] bytes, uint length)895 public bool WriteBuffer(byte[] bytes, uint length) 896 { 897 if(bytes.Length > MaximumBufferLength) 898 { 899 return false; 900 } 901 902 Length = (ushort)Length; 903 Bus.WriteBytes(bytes, DataBufferAddress, true); 904 905 return true; 906 } 907 908 private const int MaximumBufferLength = (1 << 13) - 1; 909 } 910 } 911 } 912