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.Peripherals.SPI;
12 using System.Collections.Generic;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Network;
15 using Antmicro.Renode.Utilities;
16 
17 namespace Antmicro.Renode.Peripherals.Network
18 {
19     public class KS8851 : ISPIPeripheral, IMACInterface
20     {
KS8851()21         public KS8851()
22         {
23             MAC = EmulationManager.Instance.CurrentEmulation.MACRepository.GenerateUniqueMAC();
24             currentLength = 4;
25             request = new byte[10240];
26             response = new byte[10240];
27             packetQueue = new Queue<EthernetFrame>();
28             IRQ = new GPIO();
29         }
30 
31         public GPIO IRQ { get; private set; }
32 
Reset()33         public void Reset()
34         {
35             interruptsEnabled = true;
36         }
37 
38         public MACAddress MAC { get; set; }
39 
ReceiveFrame(EthernetFrame frame)40         public void ReceiveFrame(EthernetFrame frame)
41         {
42             if(!frame.DestinationMAC.IsBroadcast && frame.DestinationMAC != MAC)
43             {
44                 return;
45             }
46             lock(packetQueue)
47             {
48                 packetQueue.Enqueue(frame);
49                 SignalInterrupt();
50             }
51         }
52 
Transmit(byte data)53         public byte Transmit(byte data)
54         {
55             if(mode == Mode.SendingPacket)
56             {
57                 goto RESULT;
58             }
59             if(counter == 1 && request[0] == 0x80)
60             {
61                 mode = Mode.SendingPacket;
62                 currentLength = nearestPacketLength;
63                 counter = 0;
64             }
65             request[counter] = data;
66             if(counter == 1)
67             {
68                 Message();
69             }
70         RESULT:
71             var result = response[counter];
72             counter = (counter + 1)%currentLength;
73             if(counter == 0)
74             {
75                 Finished();
76             }
77             return result;
78         }
79 
FinishTransmission()80         public void FinishTransmission()
81         {
82         }
83 
SignalInterrupt()84         public void SignalInterrupt()
85         {
86             if(!interruptsEnabled)
87             {
88                 return;
89             }
90             IRQ.Set(true);
91             IRQ.Set(false);
92         }
93 
94         public event Action<EthernetFrame> FrameReady;
95 
Align(int value)96         private int Align(int value)
97         {
98             return 4 * (int)Math.Ceiling(1.0 * value / 4);
99         }
100 
Message()101         private void Message()
102         {
103             var requestShort = BitConverter.ToUInt16(request, 0);
104             this.NoisyLog("Request 0x{0:X} {1}.", requestShort, mode);
105             var responseShort = (ushort)0;
106             if((byte)requestShort == 0xC0 && mode != Mode.WaitingForPacket)
107             {
108                 interruptAfterTransmision = (requestShort & 0x100) != 0;
109                 requestShort = 0xC0;
110             }
111             lastPacketType = requestShort;
112             if(mode == Mode.WaitingForPacket)
113             {
114                 return;
115             }
116             switch(requestShort)
117             {
118             case 0xF:
119                 responseShort = 0x8870;
120                 break;
121             case 0xC0:
122                 currentLength = 5;
123                 break;
124             case 0x4832:
125                 if(transmissionEnded)
126                 {
127                     responseShort = Consts.TransmissionEnded;
128                 }
129                 lock(packetQueue)
130                 {
131                     if(packetQueue.Count > 0)
132                     {
133                         responseShort |= Consts.PacketWaiting;
134                     }
135                 }
136                 break;
137             case 0xE00D:
138                 responseShort = 10000;
139                 break;
140             case 0x740A:
141                 // number of packets?
142                 responseShort = 1;
143                 currentLength = 3;
144                 mode = Mode.Special;
145                 break;
146             case 0x5448:
147                 currentLength = 3;
148                 mode = Mode.Special;
149                 break;
150             case 0xF03D:
151                 currentLength = 6;
152                 mode = Mode.Special;
153                 lock(packetQueue)
154                 {
155                     var frame = packetQueue.Dequeue();
156                     var length = frame.Length + 4;
157                     nearestPacketLength = Align(length) + 4;
158                     frame.Bytes.CopyTo(response, 8);
159                     response[4] = (byte)length;
160                     response[5] = (byte)(length >> 8);
161                 }
162                 break;
163             case 0x5408:
164                 PutMACInResponse(0, ref responseShort);
165                 break;
166             case 0x5004:
167                 PutMACInResponse(1, ref responseShort);
168                 break;
169             case 0x4C20:
170                 PutMACInResponse(2, ref responseShort);
171                 break;
172             case 0x4810:
173                 PutMACInResponse(3, ref responseShort);
174                 break;
175             case 0x4408:
176                 PutMACInResponse(4, ref responseShort);
177                 break;
178             case 0x4004:
179                 PutMACInResponse(5, ref responseShort);
180                 break;
181             case 0x200C:
182                 responseShort = 1 << 9; // CCR_EEPROM
183                 break;
184             case 0x404E:
185                 interruptsEnabled = true;
186                 this.DebugLog("Interrupts enabled.");
187                 break;
188             }
189             response[2] = (byte)responseShort;
190             response[3] = (byte)(responseShort >> 8);
191         }
192 
PutMACInResponse(int number, ref ushort responseShort)193         private void PutMACInResponse(int number, ref ushort responseShort)
194         {
195             currentLength = 3;
196             responseShort = MAC.Bytes[number];
197             mode = Mode.Special;
198         }
199 
Finished()200         private void Finished()
201         {
202             if(mode == Mode.WaitingForPacket)
203             {
204                 this.DebugLog("Packet received, LEN {7} {0:x} {1:x} {2:x} {3:x} (...) {4:x} {5:x} {6:x}", request[0], request[1], request[2], request[3], request[currentLength - 5], request[currentLength - 4], request[currentLength - 3], currentLength);
205                 var frame = new byte[currentLength];
206                 Array.Copy(request, 0, frame, 0, currentLength);
207                 //TODO: CRC handling
208                 if(!Misc.TryCreateFrameOrLogWarning(this, frame, out var ethernetFrame, addCrc: false))
209                 {
210                     return;
211                 }
212                 FrameReady?.Invoke(ethernetFrame);
213                 mode = Mode.Standard;
214                 currentLength = 4;
215                 transmissionEnded = true;
216                 if(interruptAfterTransmision)
217                 {
218                     SignalInterrupt();
219                 }
220             }
221             if(mode == Mode.SendingPacket)
222             {
223                 mode = Mode.Standard;
224                 currentLength = 4;
225                 lock(packetQueue)
226                 {
227                     if(packetQueue.Count > 0)
228                     {
229                         SignalInterrupt();
230                     }
231                 }
232             }
233             if(mode == Mode.Special)
234             {
235                 currentLength = 4;
236                 mode = Mode.Standard;
237                 return;
238             }
239             switch(lastPacketType)
240             {
241             case 0xC0:
242                 mode = Mode.WaitingForPacket;
243                 var encodedLength = request[3] + (request[4] << 8);
244                 this.DebugLog("Encoded length is 0x{0:X}.", encodedLength);
245                 currentLength = Align(encodedLength + 1 + 1);
246                 transmissionEnded = false;
247                 break;
248             case 0xF:
249                 lastPacketType = 0;
250                 break;
251             }
252         }
253 
254         private int counter;
255         private int currentLength = 4;
256         private int nearestPacketLength;
257         private Mode mode;
258         private ushort lastPacketType;
259         private bool interruptAfterTransmision;
260         private bool transmissionEnded;
261         private bool interruptsEnabled;
262         private readonly Queue<EthernetFrame> packetQueue;
263         private readonly byte[] request;
264         private readonly byte[] response;
265 
266         private static class Consts
267         {
268             public static ushort TransmissionEnded = 1 << 14;
269             public static ushort PacketWaiting = 1 << 13;
270         }
271 
272         private enum Mode
273         {
274             Standard,
275             Special,
276             WaitingForPacket,
277             SendingPacket
278         }
279     }
280 }
281 
282