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 Antmicro.Renode.Peripherals.Bus; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Utilities; 14 using System.Collections.Generic; 15 using Antmicro.Renode.Network; 16 17 namespace Antmicro.Renode.Peripherals.Network 18 { 19 //TODO: Might be Word/BytePeripheral as well 20 public sealed class SynopsysEthernetMAC : NetworkWithPHY, IDoubleWordPeripheral, IMACInterface, IKnownSize 21 { SynopsysEthernetMAC(IMachine machine, SynopsysEthernetVersion version = SynopsysEthernetVersion.STM32F4)22 public SynopsysEthernetMAC(IMachine machine, SynopsysEthernetVersion version = SynopsysEthernetVersion.STM32F4) : base(machine) 23 { 24 sysbus = machine.GetSystemBus(this); 25 this.version = version; 26 MAC = EmulationManager.Instance.CurrentEmulation.MACRepository.GenerateUniqueMAC(); 27 IRQ = new GPIO(); 28 Reset(); 29 } 30 Reset()31 public override void Reset() 32 { 33 macConfiguration = 0x8000; 34 macFrameFilter = 0x0; 35 macMiiAddress = 0x0; 36 macMiiData = 0x0; 37 macFlowControl = 0x0; 38 dmaBusMode = 0x20100; 39 dmaReceiveDescriptorListAddress = 0x0; 40 dmaTransmitDescriptorListAddress = 0x0; 41 dmaOperationMode = 0x0; 42 dmaInterruptEnable = 0x0; 43 } 44 ReadDoubleWord(long offset)45 public uint ReadDoubleWord(long offset) 46 { 47 this.NoisyLog("Read from {0}", (Registers)offset); 48 switch((Registers)offset) 49 { 50 case Registers.MACConfiguration: 51 return macConfiguration; 52 case Registers.MACFrameFilter: 53 return macFrameFilter; 54 case Registers.MACMIIAddress: 55 return macMiiAddress; 56 case Registers.MACMIIData: 57 return macMiiData; 58 case Registers.MACFlowControl: 59 return macFlowControl; 60 case Registers.MACAddress0High: 61 return (uint)((MAC.F << 8) | MAC.E); 62 case Registers.MACAddress0Low: 63 return (uint)((MAC.D << 24) | (MAC.C << 16) | (MAC.B << 8) | MAC.A); 64 case Registers.DMABusMode: 65 return dmaBusMode; 66 case Registers.DMAReceiveDescriptorListAddress: 67 return dmaReceiveDescriptorListAddress; 68 case Registers.DMATransmitDescriptorListAddress: 69 return dmaTransmitDescriptorListAddress; 70 case Registers.DMAStatusRegister: 71 if((dmaStatus & ((1u << 14) | (1u << 6) | (1u << 2) | 1u)) != 0) 72 { 73 dmaStatus |= 1u << 16; //Normal interrupt summary 74 } 75 return dmaStatus; 76 case Registers.DMAOperationMode: 77 return dmaOperationMode; 78 case Registers.DMAInterruptEnable: 79 return dmaInterruptEnable; 80 default: 81 this.LogUnhandledRead(offset); 82 return 0; 83 } 84 } 85 WriteDoubleWord(long offset, uint value)86 public void WriteDoubleWord(long offset, uint value) 87 { 88 this.NoisyLog("Write {0:X} to {1}", value, (Registers)offset); 89 switch((Registers)offset) 90 { 91 case Registers.MACConfiguration: 92 macConfiguration = value; 93 crcStrippingForTypeFrames = (macConfiguration & 1u << 25) != 0; 94 automaticPadCRCStripping = (macConfiguration & 1u << 7) != 0; 95 break; 96 case Registers.MACFrameFilter: 97 macFrameFilter = value; 98 break; 99 case Registers.MACMIIAddress: 100 macMiiAddress = value; 101 var busyClear = (value & 0x1) != 0; 102 if(busyClear) 103 { 104 macMiiAddress = macMiiAddress & ~0x1u; 105 } 106 var phyId = (value >> 11) & 0x1F; 107 var register = (ushort)((value >> 6) & 0x1F); 108 var isRead = ((value >> 1) & 0x1) == 0; 109 if(!TryGetPhy<ushort>(phyId, out var phy)) 110 { 111 this.Log(LogLevel.Warning, "Access to unknown phy {0}", phyId); 112 break; 113 } 114 if(isRead) 115 { 116 macMiiData = phy.Read(register); 117 } 118 else 119 { 120 phy.Write(register, macMiiData); 121 } 122 123 break; 124 case Registers.MACMIIData: 125 macMiiData = (ushort)value; 126 break; 127 case Registers.MACFlowControl: 128 macFlowControl = value; 129 break; 130 case Registers.MACAddress0High: 131 MAC = MAC.WithNewOctets(f: (byte)(value >> 8), e: (byte)value); 132 break; 133 case Registers.MACAddress0Low: 134 MAC = MAC.WithNewOctets(d: (byte)(value >> 24), c: (byte)(value >> 16), b: (byte)(value >> 8), a: (byte)value); 135 break; 136 case Registers.DMABusMode: 137 dmaBusMode = value & ~0x1u; 138 if((value & 0x1) != 0) 139 { 140 Reset(); 141 } 142 break; 143 case Registers.DMATransmitPollDemand: 144 if((dmaStatus | StartStopTransmission) != 0) 145 { 146 SendFrames(); 147 } 148 break; 149 case Registers.DMAReceiveDescriptorListAddress: 150 this.Log(LogLevel.Info, "Setting RDLA to 0x{0:X}.", value); 151 dmaReceiveDescriptorListAddress = value & ~3u; 152 dmaReceiveDescriptorListAddressBegin = dmaReceiveDescriptorListAddress; 153 break; 154 case Registers.DMATransmitDescriptorListAddress: 155 dmaTransmitDescriptorListAddress = value & ~3u; 156 dmaTransmitDescriptorListAddressBegin = dmaReceiveDescriptorListAddress; 157 break; 158 case Registers.DMAStatusRegister: 159 dmaStatus &= ~value; //write 1 to clear; 160 if((value & 0x10000) > 0) 161 { 162 IRQ.Unset(); 163 TryDequeueFrame(); 164 } 165 break; 166 case Registers.DMAOperationMode: 167 dmaOperationMode = value; 168 if((value & StartStopTransmission) != 0) 169 { 170 SendFrames(); 171 } 172 break; 173 case Registers.DMAInterruptEnable: 174 if(BitHelper.IsBitSet(value, 16)) //normal interrupt summary enable 175 { 176 value |= (1u << 14) | (1u << 6) | (1u << 2) | 1u; 177 } 178 dmaInterruptEnable = value; 179 break; 180 default: 181 this.LogUnhandledWrite(offset, value); 182 break; 183 } 184 } 185 ReceiveFrame(EthernetFrame frame)186 public void ReceiveFrame(EthernetFrame frame) 187 { 188 /*if(machine.ElapsedTime < TimeSpan.FromSeconds(30)) 189 { 190 return; 191 }*/ 192 lock(receiveLock) 193 { 194 if((dmaStatus & ReceiveStatus) != 0) 195 { 196 queue.Enqueue(frame); 197 return; 198 } 199 if(frame.Bytes.Length < 14) 200 { 201 this.Log(LogLevel.Error, "DROPPING - packet too short."); 202 return; 203 } 204 if(this.machine.IsPaused) 205 { 206 this.Log(LogLevel.Debug, "DROPPING - cpu is halted."); 207 return; 208 } 209 var destinationMac = frame.DestinationMAC; 210 if(!destinationMac.IsBroadcast && !destinationMac.Equals(MAC)) 211 { 212 this.Log(LogLevel.Debug, "DROPPING - not for us."); 213 return; 214 } 215 /* 216 if((dmaInterruptEnable & (ReceiveStatus)) == 0) 217 { 218 this.Log(LogLevel.Debug, "DROPPING - rx irq is turned off."); 219 return; 220 } 221 */ 222 this.Log(LogLevel.Noisy, Misc.DumpPacket(frame, false, machine)); 223 if(dmaReceiveDescriptorListAddress < 0x20000000) 224 { 225 // TODO: not in ram 226 this.Log(LogLevel.Error, "DROPPING - descriptor is not valid."); 227 return; 228 } 229 var written = 0; 230 var first = true; 231 var bytes = frame.Bytes; 232 233 if(!EthernetFrame.CheckCRC(bytes)) 234 { 235 if(!(crcStrippingForTypeFrames && bytes.Length > 1536) || !(automaticPadCRCStripping && bytes.Length < 1500)) 236 { 237 this.Log(LogLevel.Info, "Invalid CRC, packet discarded"); 238 return; 239 } 240 } 241 242 var receiveDescriptor = new RxDescriptor(this, sysbus, version); 243 receiveDescriptor.Fetch(dmaReceiveDescriptorListAddress); 244 if(receiveDescriptor.IsOwnedByDMA) 245 { 246 this.Log(LogLevel.Error, "DROPPING - descriptor is used."); 247 return; 248 } 249 this.Log(LogLevel.Noisy, "DESCRIPTOR ADDR1={0:X}, ADDR2={1:X}", receiveDescriptor.Address1, receiveDescriptor.Address2); 250 while(!receiveDescriptor.IsOwnedByDMA) 251 { 252 if(receiveDescriptor.Address1 < 0x20000000) 253 { 254 this.Log(LogLevel.Error, "Descriptor points outside of ram, aborting... This should not happen!"); 255 break; 256 } 257 receiveDescriptor.IsOwnedByDMA = true; 258 receiveDescriptor.IsFirstSegment = first; 259 first = false; 260 var howManyBytes = Math.Min(receiveDescriptor.Buffer1Length, frame.Bytes.Length - written); 261 var toWriteArray = new byte[howManyBytes]; 262 263 Array.Copy(bytes, written, toWriteArray, 0, howManyBytes); 264 sysbus.WriteBytes(toWriteArray, receiveDescriptor.Address1); 265 written += howManyBytes; 266 //write second buffer 267 if(frame.Bytes.Length - written > 0 && !receiveDescriptor.IsNextDescriptorChained) 268 { 269 howManyBytes = Math.Min(receiveDescriptor.Buffer2Length, frame.Bytes.Length - written); 270 toWriteArray = new byte[howManyBytes]; 271 Array.Copy(bytes, written, toWriteArray, 0, howManyBytes); 272 sysbus.WriteBytes(toWriteArray, receiveDescriptor.Address2); 273 written += howManyBytes; 274 } 275 if(frame.Bytes.Length - written <= 0) 276 { 277 receiveDescriptor.IsLastSegment = true; 278 this.NoisyLog("Setting descriptor length to {0}", (uint)frame.Bytes.Length); 279 receiveDescriptor.FrameLength = (uint)frame.Bytes.Length; 280 } 281 this.NoisyLog("Writing descriptor at 0x{6:X}, first={0}, last={1}, written {2} of {3}. next_chained={4}, endofring={5}", receiveDescriptor.IsFirstSegment, receiveDescriptor.IsLastSegment, written, frame.Bytes.Length, receiveDescriptor.IsNextDescriptorChained, receiveDescriptor.IsEndOfRing, dmaReceiveDescriptorListAddress); 282 receiveDescriptor.WriteBack(); 283 if(!receiveDescriptor.IsNextDescriptorChained) 284 { 285 dmaReceiveDescriptorListAddress += 8; 286 } 287 else if(receiveDescriptor.IsEndOfRing) 288 { 289 dmaReceiveDescriptorListAddress = dmaReceiveDescriptorListAddressBegin; 290 } 291 else 292 { 293 dmaReceiveDescriptorListAddress = receiveDescriptor.Address2; 294 } 295 if(frame.Bytes.Length - written <= 0) 296 { 297 if((dmaInterruptEnable & (ReceiveStatus)) != 0)// receive interrupt 298 { 299 dmaStatus |= ReceiveStatus; 300 IRQ.Set(); 301 } 302 else 303 { 304 this.DebugLog("Exiting but not scheduling an interrupt!"); 305 } 306 break; 307 } 308 receiveDescriptor.Fetch(dmaReceiveDescriptorListAddress); 309 } 310 this.DebugLog("Packet of length {0} delivered.", frame.Bytes.Length); 311 if(written < frame.Bytes.Length) 312 { 313 this.Log(LogLevel.Error, "Delivered only {0} from {1} bytes!", written, frame.Bytes.Length); 314 } 315 } 316 } 317 318 public event Action<EthernetFrame> FrameReady; 319 320 public MACAddress MAC { get; set; } 321 322 public GPIO IRQ { get; private set; } 323 324 public long Size 325 { 326 get 327 { 328 return 0x1400; 329 } 330 } 331 SendFrames()332 private void SendFrames() 333 { 334 this.Log(LogLevel.Noisy, "Sending frame"); 335 var transmitDescriptor = new TxDescriptor(this, sysbus, version); 336 var packetData = new List<byte>(); 337 338 transmitDescriptor.Fetch(dmaTransmitDescriptorListAddress); 339 while(!transmitDescriptor.IsOwnedByDMA) 340 { 341 transmitDescriptor.IsOwnedByDMA = true; 342 this.Log(LogLevel.Noisy, "GOING TO READ FROM {0:X}, len={1}", transmitDescriptor.Address1, transmitDescriptor.Buffer1Length); 343 packetData.AddRange(sysbus.ReadBytes(transmitDescriptor.Address1, transmitDescriptor.Buffer1Length)); 344 if(!transmitDescriptor.IsNextDescriptorChained) 345 { 346 packetData.AddRange(sysbus.ReadBytes(transmitDescriptor.Address2, transmitDescriptor.Buffer2Length)); 347 } 348 349 transmitDescriptor.WriteBack(); 350 351 if(transmitDescriptor.IsEndOfRing) 352 { 353 dmaTransmitDescriptorListAddress = dmaTransmitDescriptorListAddressBegin; 354 } 355 else if(transmitDescriptor.IsNextDescriptorChained) 356 { 357 dmaTransmitDescriptorListAddress = transmitDescriptor.Address2; 358 } 359 else 360 { 361 dmaTransmitDescriptorListAddress += 8; 362 } 363 if(transmitDescriptor.IsLastSegment) 364 { 365 this.Log(LogLevel.Noisy, "Sending frame of {0} bytes.", packetData.Count); 366 367 if(!Misc.TryCreateFrameOrLogWarning(this, packetData.ToArray(), out var frame, addCrc: true)) 368 { 369 continue; 370 } 371 if(transmitDescriptor.ChecksumInstertionControl > 0) 372 { 373 this.Log(LogLevel.Noisy, "Calculating checksum (mode {0}).", transmitDescriptor.ChecksumInstertionControl); 374 if(transmitDescriptor.ChecksumInstertionControl == 1) 375 { 376 //IP only 377 frame.FillWithChecksums(supportedEtherChecksums, new IPProtocolType[] {}); 378 } 379 else 380 { 381 //IP and payload 382 frame.FillWithChecksums(supportedEtherChecksums, supportedIPChecksums); 383 } 384 } 385 this.Log(LogLevel.Debug, Misc.DumpPacket(frame, true, machine)); 386 387 if((dmaInterruptEnable & (TransmitStatus)) != 0) // transmit interrupt 388 { 389 dmaStatus |= TransmitStatus; 390 IRQ.Set(); 391 } 392 393 FrameReady?.Invoke(frame); 394 } 395 transmitDescriptor.Fetch(dmaTransmitDescriptorListAddress); 396 } 397 398 //set TransmitBufferUnavailable 399 dmaStatus |= TransmitBufferUnavailableStatus; 400 dmaStatus |= TransmitStatus; 401 if((dmaInterruptEnable & (StartStopTransmission)) == 0) 402 { 403 IRQ.Set(); 404 } 405 this.Log(LogLevel.Noisy, "Frame sent."); 406 } 407 TryDequeueFrame()408 private void TryDequeueFrame() 409 { 410 lock(receiveLock) 411 { 412 if(queue.Count > 0 && ((dmaStatus & ReceiveStatus) == 0)) 413 { 414 var frame = queue.Dequeue(); 415 ReceiveFrame(frame); 416 } 417 } 418 } 419 420 private bool automaticPadCRCStripping; 421 private bool crcStrippingForTypeFrames; 422 private uint macConfiguration; 423 private uint macFrameFilter; 424 private uint macMiiAddress; 425 private ushort macMiiData; 426 private uint macFlowControl; 427 private uint dmaBusMode; 428 private uint dmaReceiveDescriptorListAddress; 429 private uint dmaReceiveDescriptorListAddressBegin; 430 private uint dmaTransmitDescriptorListAddress; 431 private uint dmaTransmitDescriptorListAddressBegin; 432 private uint dmaStatus; 433 private uint dmaOperationMode; 434 private uint dmaInterruptEnable; 435 private readonly IBusController sysbus; 436 private readonly object receiveLock = new object(); 437 private readonly Queue<EthernetFrame> queue = new Queue<EthernetFrame>(); 438 private readonly EtherType[] supportedEtherChecksums = { EtherType.IpV4, EtherType.Arp }; 439 private readonly IPProtocolType[] supportedIPChecksums = { 440 IPProtocolType.TCP, 441 IPProtocolType.UDP, 442 IPProtocolType.ICMP 443 }; 444 private readonly SynopsysEthernetVersion version; 445 private const uint StartStopTransmission = 1 << 13; 446 private const uint TransmitBufferUnavailableStatus = 1 << 2; 447 private const uint ReceiveStatus = 1 << 6; 448 private const uint TransmitStatus = 1 << 0; 449 450 public enum SynopsysEthernetVersion 451 { 452 STM32F4, 453 BeagleV, 454 } 455 456 private class Descriptor 457 { Descriptor(SynopsysEthernetMAC parent, IBusController sysbus, SynopsysEthernetVersion version)458 public Descriptor(SynopsysEthernetMAC parent, IBusController sysbus, SynopsysEthernetVersion version) 459 { 460 this.sysbus = sysbus; 461 this.version = version; 462 this.parent = parent; 463 } 464 Fetch(uint address)465 public void Fetch(uint address) 466 { 467 this.address = address; 468 469 word0 = sysbus.ReadDoubleWord(address); 470 word1 = sysbus.ReadDoubleWord(address + 4); 471 word2 = sysbus.ReadDoubleWord(address + 8); 472 word3 = sysbus.ReadDoubleWord(address + 12); 473 } 474 WriteBack()475 public void WriteBack() 476 { 477 sysbus.WriteDoubleWord(address, word0); 478 sysbus.WriteDoubleWord(address + 4, word1); 479 sysbus.WriteDoubleWord(address + 8, word2); 480 sysbus.WriteDoubleWord(address + 12, word3); 481 } 482 483 public bool IsOwnedByDMA 484 { 485 get => !BitHelper.IsBitSet(word0, 31); 486 set => BitHelper.SetBit(ref word0, 31, !value); 487 } 488 489 public uint Address1 490 { 491 get => word2; 492 } 493 494 public uint Address2 495 { 496 get => word3; 497 } 498 499 public int Buffer1Length 500 { 501 get 502 { 503 switch(version) 504 { 505 case SynopsysEthernetVersion.BeagleV: 506 return (int)BitHelper.GetValue(word1, 0, 10); 507 case SynopsysEthernetVersion.STM32F4: 508 return (int)BitHelper.GetValue(word1, 0, 13); 509 default: 510 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 511 return 0; 512 } 513 } 514 } 515 516 public int Buffer2Length 517 { 518 get 519 { 520 switch(version) 521 { 522 case SynopsysEthernetVersion.BeagleV: 523 return (int)BitHelper.GetValue(word1, 11, 10); 524 case SynopsysEthernetVersion.STM32F4: 525 return (int)BitHelper.GetValue(word1, 16, 13); 526 default: 527 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 528 return 0; 529 } 530 } 531 } 532 533 protected const uint UsedField = 1u << 31; 534 protected uint address; 535 protected uint word0; 536 protected uint word1; 537 protected uint word2; 538 protected uint word3; 539 protected readonly SynopsysEthernetVersion version; 540 protected readonly SynopsysEthernetMAC parent; 541 private readonly IBusController sysbus; 542 } 543 544 private class TxDescriptor : Descriptor 545 { TxDescriptor(SynopsysEthernetMAC parent, IBusController sysbus, SynopsysEthernetVersion version)546 public TxDescriptor(SynopsysEthernetMAC parent, IBusController sysbus, SynopsysEthernetVersion version) : base(parent, sysbus, version) 547 { 548 } 549 550 public uint ChecksumInstertionControl 551 { 552 get 553 { 554 switch(version) 555 { 556 case SynopsysEthernetVersion.BeagleV: 557 return BitHelper.GetValue(word1, 27, 2); 558 case SynopsysEthernetVersion.STM32F4: 559 return BitHelper.GetValue(word0, 22, 2); 560 default: 561 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 562 return 0; 563 } 564 } 565 } 566 567 public bool IsLastSegment 568 { 569 get 570 { 571 switch(version) 572 { 573 case SynopsysEthernetVersion.BeagleV: 574 return BitHelper.IsBitSet(word1, 30); 575 case SynopsysEthernetVersion.STM32F4: 576 return BitHelper.IsBitSet(word0, 29); 577 default: 578 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 579 return false; 580 } 581 } 582 } 583 584 public bool IsNextDescriptorChained 585 { 586 get 587 { 588 switch(version) 589 { 590 case SynopsysEthernetVersion.BeagleV: 591 return BitHelper.IsBitSet(word1, 24); 592 case SynopsysEthernetVersion.STM32F4: 593 return BitHelper.IsBitSet(word0, 20); 594 default: 595 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 596 return false; 597 } 598 } 599 } 600 601 public bool IsEndOfRing 602 { 603 get 604 { 605 switch(version) 606 { 607 case SynopsysEthernetVersion.BeagleV: 608 return BitHelper.IsBitSet(word1, 25); 609 case SynopsysEthernetVersion.STM32F4: 610 return BitHelper.IsBitSet(word0, 21); 611 default: 612 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 613 return false; 614 } 615 } 616 } 617 } 618 619 private class RxDescriptor : Descriptor 620 { RxDescriptor(SynopsysEthernetMAC parent, IBusController sysbus, SynopsysEthernetVersion version)621 public RxDescriptor(SynopsysEthernetMAC parent, IBusController sysbus, SynopsysEthernetVersion version) : base(parent, sysbus, version) 622 { 623 } 624 625 public bool IsNextDescriptorChained 626 { 627 get 628 { 629 switch(version) 630 { 631 case SynopsysEthernetVersion.BeagleV: 632 return BitHelper.IsBitSet(word1, 24); 633 case SynopsysEthernetVersion.STM32F4: 634 return BitHelper.IsBitSet(word1, 14); 635 default: 636 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 637 return false; 638 } 639 640 } 641 } 642 643 public bool IsEndOfRing 644 { 645 get 646 { 647 switch(version) 648 { 649 case SynopsysEthernetVersion.BeagleV: 650 return BitHelper.IsBitSet(word1, 25); 651 case SynopsysEthernetVersion.STM32F4: 652 return BitHelper.IsBitSet(word1, 15); 653 default: 654 parent.ErrorLog("Unsupported {0}: {1}, returning 0", nameof(SynopsysEthernetVersion), version); 655 return false; 656 } 657 } 658 } 659 660 public bool IsLastSegment 661 { 662 set 663 { 664 BitHelper.SetBit(ref word0, 8, value); 665 } 666 get 667 { 668 return BitHelper.IsBitSet(word0, 8); 669 } 670 } 671 672 public bool IsFirstSegment 673 { 674 set 675 { 676 BitHelper.SetBit(ref word0, 9, value); 677 } 678 get 679 { 680 return BitHelper.IsBitSet(word0, 9); 681 } 682 } 683 684 public uint FrameLength 685 { 686 set 687 { 688 BitHelper.ReplaceBits(ref word0, value, width: 14, destinationPosition: 16); 689 } 690 } 691 } 692 693 private enum Registers 694 { 695 MACConfiguration = 0x0000, 696 MACFrameFilter = 0x0004, 697 MACMIIAddress = 0x0010, 698 MACMIIData = 0x0014, 699 MACFlowControl = 0x0018, 700 MACAddress0High = 0x0040, 701 MACAddress0Low = 0x0044, 702 DMABusMode = 0x1000, 703 DMATransmitPollDemand = 0x1004, 704 DMAReceiveDescriptorListAddress = 0x100C, 705 DMATransmitDescriptorListAddress = 0x1010, 706 DMAStatusRegister = 0x1014, 707 DMAOperationMode = 0x1018, 708 DMAInterruptEnable = 0x101C 709 } 710 } 711 } 712