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