1 // 2 // Copyright (c) 2010-2018 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.Core; 10 using Antmicro.Renode.Core.Structure; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Utilities; 14 using System.Collections.Generic; 15 using Antmicro.Renode.Network; 16 17 namespace Antmicro.Renode.Peripherals.Network 18 { 19 [AllowedTranslations(AllowedTranslation.ByteToWord)] 20 public class SMC91X : IKnownSize, IMACInterface, IWordPeripheral, IDoubleWordPeripheral 21 { SMC91X()22 public SMC91X() 23 { 24 MAC = EmulationManager.Instance.CurrentEmulation.MACRepository.GenerateUniqueMAC(); 25 IRQ = new GPIO(); 26 Reset(); 27 } 28 Reset()29 public void Reset() 30 { 31 IRQ.Unset(); 32 memoryBuffer = new MemoryRegion[NumberOfPackets]; 33 for(var i = 0; i < memoryBuffer.Length; ++i) 34 { 35 memoryBuffer[i] = new MemoryRegion(); 36 } 37 38 rxFifo.Clear(); 39 txFifo.Clear(); 40 sentFifo.Clear(); 41 42 currentBank = Bank.Bank0; 43 transmitControl = 0x0000; 44 receiveControl = 0x0000; 45 configuration = 0xA0B1; 46 generalPurposeRegister = 0x0000; 47 control = 0x1210; 48 packetNumber = 0x00; 49 allocationResult = 0x0; 50 pointer = 0x0000; 51 interruptMask = 0x0; 52 interruptStatus = TxEmptyInterrupt; 53 earlyReceive = 0x001f; 54 Update(); 55 } 56 57 public GPIO IRQ { get; private set; } 58 59 public event Action<EthernetFrame> FrameReady; 60 ReadBank0(long offset)61 private ushort ReadBank0(long offset) 62 { 63 ushort value = 0; 64 switch((Bank0Register)offset) 65 { 66 case Bank0Register.TransmitControl: 67 value = transmitControl; 68 break; 69 case Bank0Register.EthernetProtocolStatus: 70 value = 0x40 << 8; 71 break; 72 case Bank0Register.ReceiveControl: 73 value = receiveControl; 74 break; 75 case Bank0Register.MemoryInformation: 76 value = (ushort)(((memoryBuffer.Length - rxFifo.Count) << 8) | memoryBuffer.Length); 77 break; 78 } 79 return value; 80 } 81 ReadBank1(long offset)82 private ushort ReadBank1(long offset) 83 { 84 ushort value = 0; 85 switch((Bank1Register)offset) 86 { 87 case Bank1Register.Configuration: 88 value = configuration; 89 break; 90 case Bank1Register.IndividualAddress0: 91 case Bank1Register.IndividualAddress2: 92 case Bank1Register.IndividualAddress4: 93 value = (ushort)((MAC.Bytes[offset - 3] << 8) | MAC.Bytes[offset - 4]); 94 break; 95 case Bank1Register.GeneralPurposeRegister: 96 value = generalPurposeRegister; 97 break; 98 case Bank1Register.ControlRegister: 99 value = control; 100 break; 101 } 102 return value; 103 } 104 ReadBank2(long offset)105 private ushort ReadBank2(long offset) 106 { 107 ushort value = 0; 108 switch((Bank2Register)offset) 109 { 110 case Bank2Register.PacketNumber: 111 value = (ushort)((allocationResult << 8) | packetNumber); 112 break; 113 case Bank2Register.FIFOPorts: 114 byte low, high; 115 if(sentFifo.Count == 0) 116 { 117 low = FIFOEmpty; 118 } 119 else 120 { 121 low = sentFifo.Peek(); 122 } 123 if(rxFifo.Count == 0) 124 { 125 high = FIFOEmpty; 126 } 127 else 128 { 129 high = rxFifo.Peek(); 130 } 131 value = (ushort)((high << 8) | low); 132 break; 133 case Bank2Register.Pointer: 134 value = pointer; 135 break; 136 case Bank2Register.Data0: 137 case Bank2Register.Data1: 138 value = (ushort)(GetData(offset) | (GetData(offset + 1) << 8)); 139 break; 140 case Bank2Register.InterruptStatus: 141 value = (ushort)((interruptMask << 8) | interruptStatus); 142 break; 143 } 144 return value; 145 } 146 GetData(long offset)147 private byte GetData(long offset) 148 { 149 int p; 150 byte n; 151 152 if((pointer & ReceivePointer) != 0) 153 { 154 n = rxFifo.Peek(); 155 } 156 else 157 { 158 n = packetNumber; 159 } 160 p = pointer & PointerMask; 161 if((pointer & AutoIncrementPointer) != 0) 162 { 163 pointer = (ushort)((pointer & ~PointerMask) | ((pointer + 1) & PointerMask)); 164 } 165 else 166 { 167 p += (int)(offset & 3); 168 } 169 return memoryBuffer[n].Data[p]; 170 } 171 ReadBank3(long offset)172 private ushort ReadBank3(long offset) 173 { 174 ushort value = 0; 175 switch((Bank3Register)offset) 176 { 177 case Bank3Register.ManagementInterface: 178 value = 0x3330; 179 break; 180 case Bank3Register.Revision: 181 value = 0x3392; //According to datasheet 182 break; 183 case Bank3Register.ReceiveDiscard: 184 value = earlyReceive; 185 break; 186 } 187 return value; 188 } 189 WriteBank0(long offset, ushort value)190 private void WriteBank0(long offset, ushort value) 191 { 192 switch((Bank0Register)offset) 193 { 194 case Bank0Register.TransmitControl: 195 transmitControl = value; 196 break; 197 case Bank0Register.ReceiveControl: 198 receiveControl = value; 199 if((receiveControl & SoftwareReset) != 0) 200 { 201 Reset(); 202 } 203 break; 204 } 205 206 } 207 WriteBank1(long offset, ushort value)208 private void WriteBank1(long offset, ushort value) 209 { 210 switch((Bank1Register)offset) 211 { 212 case Bank1Register.Configuration: 213 configuration = value; 214 break; 215 case Bank1Register.GeneralPurposeRegister: 216 generalPurposeRegister = value; 217 break; 218 case Bank1Register.ControlRegister: 219 control = (ushort)(value & ~3); //EEPROM registers not implemented 220 break; 221 } 222 } 223 WriteBank2(long offset, ushort value)224 private void WriteBank2(long offset, ushort value) 225 { 226 switch((Bank2Register)offset) 227 { 228 case Bank2Register.MMUCommand: 229 ExecuteMMUCommand((byte)(value.LoByte() >> 5)); 230 break; 231 case Bank2Register.PacketNumber: 232 packetNumber = value.LoByte(); //only lower byte writable 233 break; 234 case Bank2Register.Pointer: 235 pointer = value; 236 break; 237 case Bank2Register.Data0: 238 case Bank2Register.Data1: 239 SetData(offset, value.LoByte()); 240 SetData(offset + 1, value.HiByte()); 241 break; 242 case Bank2Register.InterruptStatus: //Acknowledge interrupts 243 interruptStatus = (byte)(interruptStatus & ~(value.LoByte() & WritableInterrupts)); 244 if((value & TxInterrupt) != 0) 245 { 246 if(sentFifo.Count == 0) 247 { 248 return; 249 } 250 sentFifo.Dequeue(); 251 } 252 if(interruptMask != value.HiByte()) 253 { 254 interruptMask = value.HiByte(); 255 IRQ.Set(false); 256 } 257 Update(); 258 break; 259 } 260 } 261 ExecuteMMUCommand(byte value)262 private void ExecuteMMUCommand(byte value) 263 { 264 switch((MMUCommand)value) 265 { 266 case MMUCommand.Noop: 267 break; 268 case MMUCommand.AllocateForTX: 269 allocationResult = AllocationFailed; 270 interruptStatus = (byte)(interruptStatus & ~AllocationSuccessfulInterrupt); 271 Update(); 272 AllocateForTx(); 273 break; 274 case MMUCommand.ResetMMU: 275 foreach(var region in memoryBuffer) 276 { 277 region.IsAllocated = false; 278 } 279 txFifo.Clear(); 280 sentFifo.Clear(); 281 rxFifo.Clear(); 282 allocationResult = AllocationFailed; 283 break; 284 case MMUCommand.RemoveFromRxFifo: 285 PopRxFifo(); 286 break; 287 case MMUCommand.RemoveFromRxFifoAndRelease: 288 if(rxFifo.Count > 0) 289 { 290 memoryBuffer[rxFifo.Peek()].IsAllocated = false; 291 } 292 PopRxFifo(); 293 break; 294 case MMUCommand.ReleasePacket: 295 memoryBuffer[packetNumber].IsAllocated = false; 296 break; 297 case MMUCommand.EnqueuePacketIntoTxFifo: 298 txFifo.Enqueue(packetNumber); 299 Transmit(); 300 break; 301 case MMUCommand.ResetTxFifos: 302 txFifo.Clear(); 303 sentFifo.Clear(); 304 break; 305 } 306 } 307 SetData(long offset, byte value)308 private void SetData(long offset, byte value) 309 { 310 byte n; 311 312 if((pointer & ReceivePointer) != 0) 313 { 314 n = rxFifo.Peek(); 315 } 316 else 317 { 318 n = packetNumber; 319 } 320 int p = pointer & PointerMask; 321 if((pointer & AutoIncrementPointer) != 0) 322 { 323 pointer = (ushort)((pointer & ~PointerMask) | ((pointer + 1) & PointerMask)); 324 } 325 else 326 { 327 p += (int)(offset & 3); 328 } 329 memoryBuffer[n].Data[p] = value; 330 } 331 ReadWord(long offset)332 public ushort ReadWord(long offset) 333 { 334 lock(lockObj) 335 { 336 if(offset == (byte)Bank.BankSelectRegister) 337 { 338 return (ushort)((0x33 << 8) | ((byte)currentBank)); 339 } 340 switch(currentBank) 341 { 342 case Bank.Bank0: 343 return ReadBank0(offset); 344 case Bank.Bank1: 345 return ReadBank1(offset); 346 case Bank.Bank2: 347 return ReadBank2(offset); 348 case Bank.Bank3: 349 return ReadBank3(offset); 350 } 351 } 352 return 0; 353 } 354 ReadDoubleWord(long offset)355 public uint ReadDoubleWord(long offset) 356 { 357 lock(lockObj) 358 { 359 uint value; 360 value = (uint)ReadWord(offset); 361 value |= (uint)ReadWord(offset + 2) << 16; 362 return value; 363 } 364 } 365 WriteWord(long offset, ushort value)366 public void WriteWord(long offset, ushort value) 367 { 368 lock(lockObj) 369 { 370 if(offset == 14) 371 { 372 currentBank = (Bank)(value & 7); 373 return; 374 } 375 switch(currentBank) 376 { 377 case Bank.Bank0: 378 WriteBank0(offset, value); 379 break; 380 case Bank.Bank1: 381 WriteBank1(offset, value); 382 break; 383 case Bank.Bank2: 384 WriteBank2(offset, value); 385 break; 386 case Bank.Bank3: 387 //Not implemented 388 break; 389 } 390 } 391 } 392 WriteDoubleWord(long offset, uint value)393 public void WriteDoubleWord(long offset, uint value) 394 { 395 lock(lockObj) 396 { 397 //32b write to 0xC in fact writes to bank select 398 if(offset != 0xc) 399 { 400 WriteWord(offset, (ushort)(value & 0xffff)); 401 } 402 WriteWord(offset + 2, (ushort)(value >> 16)); 403 return; 404 } 405 } 406 407 public long Size 408 { 409 get 410 { 411 return 0x10000; 412 } 413 } 414 415 public MACAddress MAC { get; set; } 416 Transmit()417 public byte Transmit() 418 { 419 lock(lockObj) 420 { 421 int len; 422 byte whichPacket; 423 424 if((transmitControl & TransmitEnabled) == 0) 425 { 426 return 0; 427 } 428 if(txFifo.Count == 0) 429 { 430 return 0; 431 } 432 while(txFifo.Count > 0) 433 { 434 whichPacket = txFifo.Dequeue(); 435 var currentBuffer = memoryBuffer[whichPacket]; 436 len = currentBuffer.Data[2]; 437 len |= currentBuffer.Data[3] << 8; 438 len -= 6; 439 440 byte [] indata = new byte[len]; 441 442 for(int j=0; j<len; j++) 443 { 444 indata[j] = currentBuffer.Data[j + 4]; 445 } 446 447 if((control & ControlAutorelease) != 0) 448 { 449 currentBuffer.IsAllocated = false; 450 } 451 else 452 { 453 sentFifo.Enqueue((byte)whichPacket); 454 } 455 if(Misc.TryCreateFrameOrLogWarning(this, indata, out var frame, addCrc: true)) 456 { 457 FrameReady?.Invoke(frame); 458 } 459 } 460 Update(); 461 return 0; 462 } 463 } 464 ReceiveFrame(EthernetFrame frame)465 public void ReceiveFrame(EthernetFrame frame) 466 { 467 lock(lockObj) 468 { 469 this.NoisyLog("Received frame on MAC {0}. Frame destination MAC is {1}", this.MAC.ToString(), frame.DestinationMAC); 470 var size = frame.Bytes.Length; 471 var isEven = (size & 1) == 0; 472 if((receiveControl & ReceiveEnabled) == 0 || (receiveControl & SoftwareReset) != 0) 473 { 474 //Drop if reset is on or receiving is not enabled. 475 return; 476 } 477 var packetSize = Math.Max(64, size & ~1); 478 //64 is the minimal length 479 packetSize += 6; 480 var withCRC = (receiveControl & StripCRC) == 0; 481 if(withCRC) 482 { 483 packetSize += 4; 484 } 485 if(packetSize > MaxPacketSize) 486 { 487 //Maybe we should react to overruns. Now we just drop. 488 return; 489 } 490 byte whichPacket; 491 if(!TryAllocatePacket(out whichPacket)) 492 { 493 return; 494 } 495 rxFifo.Enqueue(whichPacket); 496 var status = 0; 497 if(size > 1518) 498 { 499 status |= 0x0800; 500 } 501 if(!isEven) 502 { 503 status |= 0x1000; 504 } 505 var currentBuffer = memoryBuffer[whichPacket]; 506 currentBuffer.Data[0] = (byte)(status & 0xff); 507 currentBuffer.Data[1] = (byte)(status >> 8); 508 currentBuffer.Data[2] = (byte)(packetSize & 0xff); 509 currentBuffer.Data[3] = (byte)(packetSize >> 8); 510 var frameBytes = frame.Bytes; 511 for(int i = 0; i < (size & ~1); i++) 512 { 513 currentBuffer.Data[4 + i] = frameBytes[i]; 514 } 515 //Pad with 0s 516 if(size < 64) 517 { 518 var pad = 64 - size; 519 if(!isEven) 520 { 521 for(int i = 0; i < pad; i++) 522 { 523 currentBuffer.Data[4 + i + size] = 0; 524 } 525 } 526 else 527 { 528 for(int i = 0; i < pad; i++) 529 { 530 currentBuffer.Data[4 + i + size + 1] = 0; 531 } 532 } 533 size = 64; 534 } 535 if(withCRC) 536 { 537 if(!EthernetFrame.CheckCRC(frame.Bytes)) 538 { 539 this.Log(LogLevel.Info, "Invalid CRC, packet discarded"); 540 return; 541 } 542 } 543 if(!isEven) 544 { 545 //TODO: For a short, odd-length packet, will it work? Should it not be written before? 546 currentBuffer.Data[packetSize - 2] = frameBytes[size - 1]; 547 currentBuffer.Data[packetSize - 1] = 0x60; 548 } 549 else 550 { 551 currentBuffer.Data[packetSize - 1] = 0x40; 552 } 553 interruptStatus |= RxInterrupt; 554 Update(); 555 } 556 } 557 Update()558 public void Update() 559 { 560 lock(lockObj) 561 { 562 if(txFifo.Count == 0) 563 { 564 interruptStatus |= TxEmptyInterrupt; 565 } 566 if(sentFifo.Count != 0) 567 { 568 interruptStatus |= TxInterrupt; 569 } 570 if((interruptMask & interruptStatus) != 0) 571 { 572 IRQ.Set(true); 573 } 574 } 575 } 576 TryAllocatePacket(out byte regionNumber)577 public bool TryAllocatePacket(out byte regionNumber) 578 { 579 lock(lockObj) 580 { 581 for(regionNumber = 0; regionNumber < memoryBuffer.Length; regionNumber++) 582 { 583 if(!memoryBuffer[regionNumber].IsAllocated) 584 { 585 memoryBuffer[regionNumber].IsAllocated = true; 586 return true; 587 } 588 } 589 regionNumber = AllocationFailed; //AllocationFailed is used as a flag in a register 590 return false; 591 } 592 } 593 AllocateForTx()594 public void AllocateForTx() 595 { 596 lock(lockObj) 597 { 598 if(TryAllocatePacket(out allocationResult)) 599 { 600 interruptStatus |= AllocationSuccessfulInterrupt; 601 Update(); 602 } 603 } 604 } 605 PopRxFifo()606 public void PopRxFifo() 607 { 608 lock(lockObj) 609 { 610 if(rxFifo.Count != 0) 611 { 612 rxFifo.Dequeue(); 613 } 614 if(rxFifo.Count != 0) //count changes after Dequeue! 615 { 616 interruptStatus |= RxInterrupt; 617 } 618 else 619 { 620 interruptStatus = (byte)(interruptStatus & ~RxInterrupt); 621 } 622 Update(); 623 } 624 } 625 626 private enum Bank 627 { 628 Bank0 = 0x0, 629 Bank1 = 0x1, 630 Bank2 = 0x2, 631 Bank3 = 0x3, 632 BankSelectRegister = 0xE 633 } 634 635 private enum Bank0Register : byte 636 { 637 TransmitControl = 0x0, 638 EthernetProtocolStatus = 0x2, 639 ReceiveControl = 0x4, 640 Counter = 0x6, 641 MemoryInformation = 0x8, 642 PHYControl = 0xA 643 } 644 645 private enum Bank1Register : byte 646 { 647 Configuration = 0x0, 648 BaseAddress = 0x2, 649 IndividualAddress0 = 0x4, 650 IndividualAddress2 = 0x6, 651 IndividualAddress4 = 0x8, 652 GeneralPurposeRegister = 0xA, 653 ControlRegister = 0xC 654 } 655 656 private enum Bank2Register : byte 657 { 658 MMUCommand = 0x0, 659 PacketNumber = 0x2, 660 FIFOPorts = 0x4, 661 Pointer = 0x6, 662 Data0 = 0x8, 663 Data1 = 0xA, 664 InterruptStatus = 0xC 665 } 666 667 private enum Bank3Register : byte 668 { 669 MulticastTable0 = 0x0, 670 MulticastTable2 = 0x2, 671 MulticastTable4 = 0x4, 672 MulticastTable6 = 0x6, 673 ManagementInterface = 0x8, 674 Revision = 0xA, 675 ReceiveDiscard = 0xC 676 677 } 678 679 private enum MMUCommand : byte 680 { 681 Noop = 0x0, 682 AllocateForTX = 0x1, 683 ResetMMU = 0x2, 684 RemoveFromRxFifo = 0x3, 685 RemoveFromRxFifoAndRelease = 0x4, 686 ReleasePacket = 0x5, 687 EnqueuePacketIntoTxFifo = 0x6, 688 ResetTxFifos = 0x7 689 } 690 691 private class MemoryRegion 692 { 693 private bool _allocated; 694 695 public bool IsAllocated 696 { 697 get 698 { 699 return _allocated; 700 } 701 set 702 { 703 if(!value) 704 { 705 Data = new byte[MaxPacketSize]; 706 } 707 _allocated = value; 708 } 709 } 710 711 public byte[] Data = new byte[MaxPacketSize]; 712 } 713 714 // Bank select register 715 private Bank currentBank; 716 // Bank 0 registers 717 private ushort transmitControl; 718 private ushort receiveControl; 719 // Bank 1 registers 720 private ushort configuration; 721 private ushort generalPurposeRegister; 722 private ushort control; 723 // Bank 2 registers 724 private byte packetNumber; 725 private byte allocationResult; 726 private ushort pointer; 727 private byte interruptStatus; 728 private byte interruptMask; 729 // Bank 3 registers 730 private ushort earlyReceive; 731 private Queue<byte> rxFifo = new Queue<byte>(); 732 private Queue<byte> txFifo = new Queue<byte>(); 733 private Queue<byte> sentFifo = new Queue<byte>(); 734 private MemoryRegion[] memoryBuffer; 735 private object lockObj = new object(); 736 737 private const byte NumberOfPackets = 4; 738 private const ushort MaxPacketSize = 2048; 739 private const ushort ControlAutorelease = 0x0800; 740 private const ushort TransmitEnabled = 0x0001; 741 private const ushort ReceiveEnabled = 0x0100; 742 private const ushort SoftwareReset = 0x8000; 743 private const ushort StripCRC = 0x0200; 744 private const ushort AutoIncrementPointer = 0x4000; 745 private const ushort ReceivePointer = 0x8000; 746 private const ushort PointerMask = 0x07FF; 747 private const byte AllocationFailed = 0x90; 748 private const byte FIFOEmpty = 0x80; 749 private const byte RxInterrupt = 0x01; 750 private const byte TxInterrupt = 0x02; 751 private const byte TxEmptyInterrupt = 0x04; 752 private const byte AllocationSuccessfulInterrupt = 0x08; 753 private const byte RxOverrunInterrupt = 0x10; 754 private const byte EthernetProtocolInterrupt = 0x20; 755 private const byte PHYInterrupt = 0x80; 756 private const byte WritableInterrupts = 0xDE; 757 } 758 } 759