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.SPI; 16 using Antmicro.Renode.Utilities; 17 18 namespace Antmicro.Renode.Peripherals.Network 19 { 20 public class ENC28J60 : ISPIPeripheral, IMACInterface 21 { ENC28J60()22 public ENC28J60() 23 { 24 sync = new object(); 25 ResetPointers(); 26 27 var econ1 = new ByteRegister(this).WithValueField(0, 2, out currentBank, name: "BSEL") 28 .WithFlag(2, out ethernetReceiveEnabled, name: "RXEN") 29 .WithFlag(3, FieldMode.Read, writeCallback: (_, value) => { if(value) TransmitPacket(); }, name: "TXRTS") 30 .WithFlag(7, name: "TXRST"); 31 32 var econ2 = new ByteRegister(this, 0x80).WithFlag(6, FieldMode.Read, writeCallback: delegate { 33 waitingPacketCount = Math.Max(0, waitingPacketCount - 1); 34 RefreshInterruptStatus(); }, name: "PKTDEC") 35 .WithFlag(7, out autoIncrement, name: "AUTOINC"); 36 37 var estat = new ByteRegister(this, 1).WithReadCallback(delegate { transmitPacketInterrupt.Value = false; RefreshInterruptStatus(); }) // not sure 38 .WithFlag(0, FieldMode.Read, name: "CLKRDY"); // we're always ready, so the reset value is 1 39 40 var eie = new ByteRegister(this).WithFlag(3, out transmitPacketInterruptEnabled, writeCallback: delegate { RefreshInterruptStatus(); }, name: "TXIE") 41 .WithFlag(6, out receivePacketInterruptEnabled, writeCallback: delegate { RefreshInterruptStatus(); }, name: "PKTIE") 42 .WithFlag(7, out interruptsEnabled, writeCallback: delegate { RefreshInterruptStatus(); }, name: "INTIE"); 43 44 var eir = new ByteRegister(this).WithFlag(0, name: "RXERIF") 45 .WithFlag(3, out transmitPacketInterrupt, writeCallback: delegate { RefreshInterruptStatus(); }, name: "TXIF") 46 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => IsReceiveInterruptActive(), name: "PKTIF"); 47 48 var bank0Map = new Dictionary<long, ByteRegister> 49 { 50 // ERDPTL 51 { 0x00, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(bufferReadPointer), 52 writeCallback: (_, value) => SetLowByteOf(ref bufferReadPointer, (byte)value)) }, 53 54 // ERDPTH 55 { 0x01, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(bufferReadPointer), 56 writeCallback: (_, value) => SetHighByteOf(ref bufferReadPointer, (byte)value)) }, 57 58 // EWRPTL 59 { 0x02, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(bufferWritePointer), 60 writeCallback: (_, value) => SetLowByteOf(ref bufferWritePointer, (byte)value)) }, 61 62 // EWRPTH 63 { 0x03, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(bufferWritePointer), 64 writeCallback: (_, value) => SetHighByteOf(ref bufferWritePointer, (byte)value)) }, 65 66 // ETXSTL 67 { 0x04, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(transmitBufferStart), 68 writeCallback: (_, value) => SetLowByteOf(ref transmitBufferStart, (byte)value)) }, 69 70 // ETXSTH 71 { 0x05, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(transmitBufferStart), 72 writeCallback: (_, value) => SetHighByteOf(ref transmitBufferStart, (byte)value)) }, 73 74 // ETXNDL 75 { 0x06, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(transmitBufferEnd), 76 writeCallback: (_, value) => SetLowByteOf(ref transmitBufferEnd, (byte)value)) }, 77 78 // ETXNDH 79 { 0x07, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(transmitBufferEnd), 80 writeCallback: (_, value) => SetHighByteOf(ref transmitBufferEnd, (byte)value)) }, 81 82 // ERXSTL 83 { 0x08, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(receiveBufferStart), 84 writeCallback: (_, value) => { SetLowByteOf(ref receiveBufferStart, (byte)value); currentReceiveWritePointer = receiveBufferStart; } ) }, 85 86 // ERXSTH 87 { 0x09, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(receiveBufferStart), 88 writeCallback: (_, value) => { SetHighByteOf(ref receiveBufferStart, (byte)value); currentReceiveWritePointer = receiveBufferStart; } ) }, 89 90 // ERXNDL 91 { 0x0A, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(receiveBufferEnd), 92 writeCallback: (_, value) => SetLowByteOf(ref receiveBufferEnd, (byte)value)) }, 93 94 // ERXNDH 95 { 0x0B, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(receiveBufferEnd), 96 writeCallback: (_, value) => SetHighByteOf(ref receiveBufferEnd, (byte)value)) }, 97 98 // ERXRDPTL 99 { 0x0C, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(receiveReadPointer), 100 writeCallback: (_, value) => bufferedLowByteOfReceiveReadPointer = (byte)value) }, 101 102 // ERXRDPTH 103 { 0x0D, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(receiveReadPointer), 104 writeCallback: (_, value) => receiveReadPointer = (int)(bufferedLowByteOfReceiveReadPointer | ((value << 8)))) } 105 }; 106 107 var bank1Map = new Dictionary<long, ByteRegister> 108 { 109 // ERXFCON 110 { 0x18, new ByteRegister(this, 0xA1).WithFlag(5, out crcEnabled, name: "CRCEN") }, 111 112 // EPKTCNT 113 { 0x19, new ByteRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (uint)waitingPacketCount) } 114 }; 115 116 var bank2Map = new Dictionary<long, ByteRegister> 117 { 118 // MACON1 119 // note that we currently ignore all the Pause Control Frame stuff 120 { 0x00, new ByteRegister(this).WithFlag(0, out macReceiveEnabled, name: "MARXEN").WithFlag(2, name: "RXPAUS").WithFlag(3, name: "TXPAUS")}, 121 122 // MACON3 123 { 0x02, new ByteRegister(this).WithFlag(0, name: "FULDPX") }, 124 125 // MABBIPG (too low level parameter for emulation) 126 { 0x04, new ByteRegister(this).WithValueField(0, 7) }, 127 128 // MAIPGL (same as above) 129 { 0x06, new ByteRegister(this).WithValueField(0, 7) }, 130 131 // MAIPGH (same as above) 132 { 0x07, new ByteRegister(this).WithValueField(0, 7) }, 133 134 // MICMD 135 { 0x12, new ByteRegister(this).WithFlag(0, writeCallback: (_, value) => { if(value) ReadPhyRegister(); }, name: "MIIRD") }, 136 137 // MIREGADR 138 { 0x14, new ByteRegister(this).WithValueField(0, 5, out miiRegisterAddress) }, 139 140 // MIWRL 141 { 0x16, new ByteRegister(this).WithValueField(0, 8, out phyWriteLow) }, 142 143 // MIWRH 144 { 0x17, new ByteRegister(this).WithValueField(0, 8, writeCallback: (_, value) => WritePhyRegister((ushort)(phyWriteLow.Value | (value << 8)))) }, 145 146 // MIRDL 147 { 0x18, new ByteRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)lastReadPhyRegisterValue) }, 148 149 // MIRDH 150 { 0x19, new ByteRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)(lastReadPhyRegisterValue >> 8)) } 151 }; 152 153 var bank3Map = new Dictionary<long, ByteRegister> 154 { 155 // MAADR5 156 { 0x00, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.E, writeCallback: (_, value) => MAC = MAC.WithNewOctets(e: (byte)value)) }, 157 158 // MADDR6 159 { 0x01, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.F, writeCallback: (_, value) => MAC = MAC.WithNewOctets(f: (byte)value)) }, 160 161 // MADDR3 162 { 0x02, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.C, writeCallback: (_, value) => MAC = MAC.WithNewOctets(c: (byte)value)) }, 163 164 // MADDR4 165 { 0x03, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.D, writeCallback: (_, value) => MAC = MAC.WithNewOctets(d: (byte)value)) }, 166 167 // MADDR1 168 { 0x04, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.A, writeCallback: (_, value) => MAC = MAC.WithNewOctets(a: (byte)value)) }, 169 170 // MADDR2 171 { 0x05, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.B, writeCallback: (_, value) => MAC = MAC.WithNewOctets(b: (byte)value)) }, 172 173 // MISTAT 174 { 0x0A, new ByteRegister(this).WithFlag(0, FieldMode.Read, name: "BUSY") } // we're never busy 175 }; 176 177 var maps = new[] { bank0Map, bank1Map, bank2Map, bank3Map }; 178 // registers below are available in all banks 179 foreach(var map in maps) 180 { 181 map.Add(0x1B, eie); // EIE 182 map.Add(0x1C, eir); // EIR 183 map.Add(0x1D, estat); // ESTAT 184 map.Add(0x1E, econ2); // ECON2 185 map.Add(0x1F, econ1); // ECON1 186 } 187 registers = maps.Select(x => new ByteRegisterCollection(this, x)).ToArray(); 188 189 ethernetBuffer = new byte[8.KB()]; 190 191 phyRegisters = new WordRegisterCollection(this, new Dictionary<long, WordRegister> 192 { 193 // PHCON1 194 { 0x00, new WordRegister(this).WithFlag(8, name: "PDPXMD") }, // full duplex stuff, ignored 195 196 // PHCON2 197 { 0x10, new WordRegister(this) } 198 }); 199 IRQ = new GPIO(); 200 IRQ.Set(); // the interrupt output is negated 201 } 202 203 public event Action<EthernetFrame> FrameReady; 204 205 public MACAddress MAC { get; set; } 206 ReceiveFrame(EthernetFrame frame)207 public void ReceiveFrame(EthernetFrame frame) 208 { 209 lock(sync) 210 { 211 if(!macReceiveEnabled.Value || !ethernetReceiveEnabled.Value) 212 { 213 return; 214 } 215 if(!TryReceivePacket(frame.Bytes)) 216 { 217 this.Log(LogLevel.Info, "Packet ignored."); 218 } 219 } 220 } 221 Reset()222 public void Reset() 223 { 224 lock(sync) 225 { 226 ResetPointers(); 227 foreach(var registerCollection in registers) 228 { 229 registerCollection.Reset(); 230 } 231 phyRegisters.Reset(); 232 waitingPacketCount = 0; 233 currentMode = Mode.Normal; 234 RefreshInterruptStatus(); 235 } 236 } 237 Transmit(byte data)238 public byte Transmit(byte data) 239 { 240 lock(sync) 241 { 242 switch(currentMode) 243 { 244 case Mode.Normal: 245 return HandleTransmissionInNormalMode(data); 246 case Mode.ReadMacOrMiiRegister: 247 currentMode = Mode.ReadControlRegister; 248 return 0x00; // dummy byte 249 case Mode.ReadControlRegister: 250 return HandleReadRegister(); 251 case Mode.WriteControlRegister: 252 HandleWriteRegister(data); 253 return 0x00; 254 case Mode.RegisterBitSet: 255 HandleBitSetOrClear(data, true); 256 return 0x00; 257 case Mode.RegisterBitClear: 258 HandleBitSetOrClear(data, false); 259 return 0x00; 260 case Mode.ReadBufferMemory: 261 return HandleReadBufferMemory(); 262 case Mode.WriteBufferMemory: 263 HandleWriteBufferMemory(data); 264 return 0x00; 265 default: 266 throw new InvalidOperationException("Internal error: unexpected mode."); 267 } 268 } 269 } 270 FinishTransmission()271 public void FinishTransmission() 272 { 273 lock(sync) 274 { 275 currentMode = Mode.Normal; 276 } 277 } 278 279 public GPIO IRQ { get; private set; } 280 ResetPointers()281 private void ResetPointers() 282 { 283 transmitBufferStart = 0; 284 transmitBufferEnd = 0; 285 receiveBufferStart = 0x5FA; 286 receiveBufferEnd = 0x1FFF; 287 bufferReadPointer = 0x5FA; 288 bufferWritePointer = 0; 289 receiveReadPointer = 0x5FA; 290 } 291 HandleTransmissionInNormalMode(byte data)292 private byte HandleTransmissionInNormalMode(byte data) 293 { 294 if(data == 0xFF) 295 { 296 // soft reset 297 return 0x00; 298 } 299 var commandType = data >> 5; 300 selectedRegister = data & 0x1F; 301 switch(commandType) 302 { 303 case 0: 304 currentMode = MacOrMiiRegisters.Contains(Tuple.Create((int)currentBank.Value, selectedRegister)) 305 ? Mode.ReadMacOrMiiRegister : Mode.ReadControlRegister; 306 break; 307 case 1: 308 currentMode = Mode.ReadBufferMemory; 309 break; 310 case 2: 311 currentMode = Mode.WriteControlRegister; 312 break; 313 case 3: 314 currentMode = Mode.WriteBufferMemory; 315 break; 316 case 4: 317 currentMode = Mode.RegisterBitSet; 318 break; 319 case 5: 320 currentMode = Mode.RegisterBitClear; 321 break; 322 default: 323 this.Log(LogLevel.Error, "Unhandled command type: {0}.", commandType); 324 break; 325 } 326 return 0x00; 327 } 328 HandleReadRegister()329 private byte HandleReadRegister() 330 { 331 var registerDetails = string.Format("0x{0:X}, bank {1}", selectedRegister, currentBank.Value); 332 this.Log(LogLevel.Debug, "Read from {0}.", registerDetails); 333 var result = default(byte); 334 if(!GetCurrentRegistersBank().TryRead(selectedRegister, out result)) 335 { 336 this.Log(LogLevel.Warning, "Read from unhandled register {0}.", registerDetails); 337 } 338 currentMode = Mode.Normal; 339 return result; 340 } 341 HandleWriteRegister(byte data)342 private void HandleWriteRegister(byte data) 343 { 344 var registerDetails = string.Format("0x{0:X}, bank {1}, value 0x{2:X}", selectedRegister, currentBank.Value, data); 345 this.Log(LogLevel.Debug, "Write to {0}.", registerDetails); 346 if(!GetCurrentRegistersBank().TryWrite(selectedRegister, data)) 347 { 348 this.Log(LogLevel.Warning, "Write to unhandled register {0}.", registerDetails); 349 } 350 currentMode = Mode.Normal; 351 } 352 HandleReadBufferMemory()353 private byte HandleReadBufferMemory() 354 { 355 this.Log(LogLevel.Debug, "Reading buffer memory at 0x{0:X}.", bufferReadPointer); 356 var result = ethernetBuffer[bufferReadPointer]; 357 if(autoIncrement.Value) 358 { 359 bufferReadPointer++; 360 if(bufferReadPointer > receiveBufferEnd) 361 { 362 bufferReadPointer = receiveBufferStart; 363 } 364 } 365 return result; 366 } 367 HandleWriteBufferMemory(byte value)368 private void HandleWriteBufferMemory(byte value) 369 { 370 this.Log(LogLevel.Debug, "Writing buffer memory at 0x{0:X}, value 0x{1:X}.", bufferWritePointer, value); 371 ethernetBuffer[bufferWritePointer] = value; 372 if(autoIncrement.Value) 373 { 374 bufferWritePointer++; 375 if(bufferWritePointer == ethernetBuffer.Length) 376 { 377 bufferWritePointer = 0; 378 } 379 } 380 } 381 HandleBitSetOrClear(byte data, bool set)382 private void HandleBitSetOrClear(byte data, bool set) 383 { 384 var registerDetails = string.Format("0x{0:X}, bank {1}, bits to {3}: {2}", selectedRegister, currentBank.Value, 385 BitHelper.GetSetBitsPretty(data), set ? "set" : "clear"); 386 this.Log(LogLevel.Debug, "Bit{1} to {0}.", registerDetails, set ? "Set" : "Clear"); 387 currentMode = Mode.Normal; 388 if(MacOrMiiRegisters.Contains(Tuple.Create((int)currentBank.Value, selectedRegister))) 389 { 390 this.Log(LogLevel.Warning, "Trying to set a bit on MAC or MII register {0}.", registerDetails); 391 return; 392 } 393 byte value; 394 if(!GetCurrentRegistersBank().TryRead(selectedRegister, out value)) 395 { 396 this.Log(LogLevel.Warning, "BitSet to unimplemented register {0}.", registerDetails); 397 return; 398 } 399 if(set) 400 { 401 value |= data; 402 } 403 else 404 { 405 value &= (byte)~data; 406 } 407 GetCurrentRegistersBank().Write(selectedRegister, value); 408 } 409 GetCurrentRegistersBank()410 private ByteRegisterCollection GetCurrentRegistersBank() 411 { 412 return registers[(int)currentBank.Value]; 413 } 414 ReadPhyRegister()415 private void ReadPhyRegister() 416 { 417 ushort result = 0; 418 var address = miiRegisterAddress.Value; 419 this.DebugLog("Read from PHY register 0x{0:X}.", address); 420 if(!phyRegisters.TryRead((long)address, out result)) 421 { 422 this.Log(LogLevel.Warning, "Read from unimplemented PHY register 0x{0:X}.", address); 423 } 424 lastReadPhyRegisterValue = result; 425 } 426 WritePhyRegister(ushort value)427 private void WritePhyRegister(ushort value) 428 { 429 var address = miiRegisterAddress.Value; 430 var registerFriendlyName = string.Format("PHY register 0x{0:X}, value 0x{1:X}", address, value); 431 this.DebugLog("Write to {0}.", registerFriendlyName); 432 if(!phyRegisters.TryWrite((long)address, value)) 433 { 434 this.Log(LogLevel.Warning, "Write to unimplemented {0}.", registerFriendlyName); 435 } 436 } 437 SetInterrupt(bool value)438 private void SetInterrupt(bool value) 439 { 440 IRQ.Set(!value); 441 } 442 RefreshInterruptStatus()443 private void RefreshInterruptStatus() 444 { 445 SetInterrupt(interruptsEnabled.Value && 446 (IsReceiveInterruptActive() || (transmitPacketInterrupt.Value && transmitPacketInterruptEnabled.Value))); 447 } 448 IsReceiveInterruptActive()449 private bool IsReceiveInterruptActive() 450 { 451 return waitingPacketCount > 0 && receivePacketInterruptEnabled.Value; 452 } 453 TryReceivePacket(byte[] data)454 private bool TryReceivePacket(byte[] data) 455 { 456 // first check whether the packet fits into buffer 457 var receiveBufferSize = receiveBufferEnd - receiveBufferStart + 1; 458 var freeSpace = receiveBufferSize - ((receiveBufferSize + currentReceiveWritePointer - receiveReadPointer) % receiveBufferSize); 459 var packetPlusHeadersLength = data.Length + 2 + 4; // next packet pointer and receive status vector 460 packetPlusHeadersLength += packetPlusHeadersLength % 2; // padding byte 461 if(freeSpace < packetPlusHeadersLength) 462 { 463 this.Log(LogLevel.Warning, "No free space for packet. Packet length (+ headers): {0}B, free space: {1}B.", 464 Misc.NormalizeBinary(packetPlusHeadersLength), Misc.NormalizeBinary(freeSpace)); 465 return false; 466 } 467 468 if(!EthernetFrame.CheckCRC(data) && crcEnabled.Value) 469 { 470 this.Log(LogLevel.Info, "Invalid CRC, packet discarded"); 471 return false; 472 } 473 474 var nextReceiveWritePointer = currentReceiveWritePointer + packetPlusHeadersLength; 475 if(nextReceiveWritePointer > receiveBufferEnd) 476 { 477 nextReceiveWritePointer -= receiveBufferSize; 478 } 479 var packetWithHeader = new byte[packetPlusHeadersLength]; 480 BitConverter.GetBytes((ushort)nextReceiveWritePointer).CopyTo(packetWithHeader, 0); 481 BitConverter.GetBytes((ushort)data.Length).CopyTo(packetWithHeader, 2); 482 BitConverter.GetBytes((ushort)(1 << 7)).CopyTo(packetWithHeader, 4); 483 data.CopyTo(packetWithHeader, 6); 484 485 var firstPartLength = Math.Min(packetPlusHeadersLength, receiveBufferEnd - currentReceiveWritePointer + 1); 486 Array.Copy(packetWithHeader, 0, ethernetBuffer, currentReceiveWritePointer, firstPartLength); 487 if(firstPartLength < packetPlusHeadersLength) 488 { 489 // packet overlaps buffer 490 Array.Copy(packetWithHeader, firstPartLength, ethernetBuffer, receiveBufferStart, packetWithHeader.Length - firstPartLength); 491 } 492 currentReceiveWritePointer = nextReceiveWritePointer; 493 494 waitingPacketCount++; 495 RefreshInterruptStatus(); 496 return true; 497 } 498 TransmitPacket()499 private void TransmitPacket() 500 { 501 var packetSize = transmitBufferEnd - transmitBufferStart; // -1 for the per packet control byte, but transmitBufferEnd points to the last byte of the packet 502 var data = new byte[packetSize]; 503 Array.Copy(ethernetBuffer, transmitBufferStart + 1, data, 0, packetSize); 504 if(!Misc.TryCreateFrameOrLogWarning(this, data, out var frame, addCrc: true)) 505 { 506 return; 507 } 508 // status vector is not implemented yet 509 this.Log(LogLevel.Debug, "Sending frame {0}.", frame); 510 FrameReady?.Invoke(frame); 511 transmitPacketInterrupt.Value = true; 512 RefreshInterruptStatus(); 513 } 514 SetLowByteOf(ref int ofWhat, byte with)515 private static void SetLowByteOf(ref int ofWhat, byte with) 516 { 517 ofWhat = (ofWhat & 0xFF00) | with; 518 } 519 SetHighByteOf(ref int ofWhat, byte with)520 private static void SetHighByteOf(ref int ofWhat, byte with) 521 { 522 ofWhat = (with << 8) | (ofWhat & 0xFF); 523 } 524 525 // methods below return uint because of the register infrastructure (it is more convenient) GetLowByteOf(int ofWhat)526 private static uint GetLowByteOf(int ofWhat) 527 { 528 return (uint)(ofWhat & 0xFF); 529 } 530 GetHighByteOf(int ofWhat)531 private static uint GetHighByteOf(int ofWhat) 532 { 533 return (uint)((ofWhat >> 8) & 0x1F); 534 } 535 536 private Mode currentMode; 537 private IValueRegisterField currentBank; 538 private int selectedRegister; 539 private int receiveBufferStart; 540 private int receiveBufferEnd; 541 private int transmitBufferStart; 542 private int transmitBufferEnd; 543 private int bufferReadPointer; 544 private int bufferWritePointer; 545 private byte bufferedLowByteOfReceiveReadPointer; 546 private int receiveReadPointer; 547 private int currentReceiveWritePointer; 548 private IFlagRegisterField macReceiveEnabled; 549 private IValueRegisterField miiRegisterAddress; 550 private ushort lastReadPhyRegisterValue; 551 private IValueRegisterField phyWriteLow; 552 private IFlagRegisterField interruptsEnabled; 553 private IFlagRegisterField receivePacketInterruptEnabled; 554 private IFlagRegisterField transmitPacketInterruptEnabled; 555 private IFlagRegisterField transmitPacketInterrupt; 556 private IFlagRegisterField ethernetReceiveEnabled; 557 private IFlagRegisterField autoIncrement; 558 private int waitingPacketCount; 559 private IFlagRegisterField crcEnabled; 560 561 private readonly WordRegisterCollection phyRegisters; 562 private readonly ByteRegisterCollection[] registers; 563 private readonly byte[] ethernetBuffer; 564 private readonly object sync; 565 566 // here is the list of MAC and MII registers in the format (bank, register_number) 567 // they have to be read in a slightly different way than ethernet registers 568 private static readonly HashSet<Tuple<int, int>> MacOrMiiRegisters = new HashSet<Tuple<int, int>> 569 { 570 Tuple.Create(2, 0x00), 571 Tuple.Create(2, 0x02), 572 Tuple.Create(2, 0x04), 573 Tuple.Create(2, 0x06), 574 Tuple.Create(2, 0x07), 575 Tuple.Create(2, 0x12), 576 Tuple.Create(2, 0x14), 577 Tuple.Create(2, 0x16), 578 Tuple.Create(2, 0x17), 579 Tuple.Create(2, 0x18), 580 Tuple.Create(2, 0x19), 581 Tuple.Create(3, 0x00), 582 Tuple.Create(3, 0x01), 583 Tuple.Create(3, 0x02), 584 Tuple.Create(3, 0x03), 585 Tuple.Create(3, 0x04), 586 Tuple.Create(3, 0x05), 587 Tuple.Create(3, 0x0A) 588 }; 589 590 private enum Mode 591 { 592 Normal, 593 ReadBufferMemory, 594 WriteBufferMemory, 595 ReadControlRegister, 596 ReadMacOrMiiRegister, 597 WriteControlRegister, 598 RegisterBitSet, 599 RegisterBitClear 600 } 601 } 602 } 603