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