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 System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.Bus;
14 using Antmicro.Renode.Network;
15 using Antmicro.Renode.Utilities;
16 using MiscUtil.Conversion;
17 
18 namespace Antmicro.Renode.Peripherals.Network
19 {
20     public class GaislerEth : NetworkWithPHY, IDoubleWordPeripheral, IGaislerAPB, IMACInterface, IKnownSize
21     {
GaislerEth(IMachine machine)22         public GaislerEth(IMachine machine) : base(machine)
23         {
24             sysbus = machine.GetSystemBus(this);
25             IRQ = new GPIO();
26             Reset();
27         }
28 
Reset()29         public override void Reset()
30         {
31             registers = new regs();
32             MAC = new MACAddress();
33             transmitDescriptorBase = 0;
34             transmitDescriptorOffset = 0;
35             receiveDescriptorBase = 0;
36             transmitDescriptorOffset = 0;
37         }
38 
39         public GPIO IRQ { get; private set; }
40 
41         #region IDoubleWordPeripheral implementation
42 
ReadDoubleWord(long offset)43         public uint ReadDoubleWord(long offset)
44         {
45             switch((Registers)offset)
46             {
47             case Registers.Control:
48                 return registers.Control;
49             case Registers.Status:
50                 return registers.Status;
51             case Registers.MacAddressHi:
52                 //return registers.MacAddresHi;
53                 return (uint)EndianBitConverter.Big.ToUInt16(MAC.Bytes, 4);
54             case Registers.MacAddressLo:
55                 //return registers.MacAddresLo;
56                 return EndianBitConverter.Big.ToUInt32(MAC.Bytes, 0);
57             case Registers.MDIOControlStatus:
58                 return registers.MDIOControlStatus;
59             case Registers.TxDescriptorPointer:
60                 return registers.TxDescriptorPointer;
61             case Registers.RxDescriptorPointer:
62                 return registers.RxDescriptorPointer;
63             case Registers.HashTableHi:
64                 return registers.HashTableHi;
65             case Registers.HashTableLo:
66                 return registers.HashTableLo;
67             default:
68                 this.LogUnhandledRead(offset);
69                 return 0u;
70             }
71         }
72 
WriteDoubleWord(long offset, uint value)73         public void WriteDoubleWord(long offset, uint value)
74         {
75             switch((Registers)offset)
76             {
77             case Registers.Control:
78                 if(value == 0x40)
79                 {
80                     break;
81                 }
82                 if((value & 0x01u) != 0)
83                 {
84                     this.transmitFrame();
85                 }
86                 registers.Control = value;
87                 break;
88             case Registers.Status:
89                 //registers.Status = value;
90                 registers.Status &= ~(value & 0xffu);
91                 break;
92             case Registers.MacAddressHi:
93                 registers.MacAddresHi = value;
94                 var macBytes = EndianBitConverter.Big.GetBytes(value);
95                 MAC = MAC.WithNewOctets(a: macBytes[2], b: macBytes[3]);
96                 break;
97             case Registers.MacAddressLo:
98                 registers.MacAddresLo = value;
99                 macBytes = EndianBitConverter.Big.GetBytes(value);
100                 MAC = MAC.WithNewOctets(c: macBytes[0], d: macBytes[1], e: macBytes[2], f: macBytes[3]);
101                 break;
102             case Registers.MDIOControlStatus:
103 
104                 var id = ((value >> 11) & 0x1f);
105                 var reg = ((value >> 6) & 0x1f);
106                 var read = (value & 0x02) != 0;
107                 var write = (value & 0x01) != 0;
108 
109                 if(!TryGetPhy<ushort>(id, out var phy))
110                 {
111                     this.Log(LogLevel.Warning, "Write to phy with unknown ID {0}", id);
112                     return;
113                 }
114                 if(read)
115                 {
116                     var phyRead = phy.Read((ushort)reg);
117                     registers.MDIOControlStatus &= 0x0000FFFF;//clear data
118                     registers.MDIOControlStatus |= (uint)(phyRead << 16);
119                 }
120                 else if(write)
121                 {
122                     phy.Write((ushort)reg, (ushort)((value >> 16) & 0xFFFF));
123                 }
124                 else//unknown
125                 {
126                     this.Log(LogLevel.Warning, "Unknown phy operation - neither read nor write ");
127                 }
128                 /*if ( (registers.InterruptMask & (1u<<0)) == 0 )
129                 {
130                     registers.InterruptStatus |= 1u<<0;
131                     IRQ.Set();
132                 }*/
133                 break;
134             case Registers.TxDescriptorPointer:
135                 registers.TxDescriptorPointer = value;
136                 transmitDescriptorBase = value & ~(0x3ffu);
137                 transmitDescriptorOffset = value & 0x3ffu;
138                 break;
139             case Registers.RxDescriptorPointer:
140                 registers.RxDescriptorPointer = value;
141                 receiveDescriptorBase = value & ~(0x3ffu);
142                 receiveDescriptorOffset = value & 0x3ffu;
143                 break;
144             case Registers.HashTableHi:
145                 registers.HashTableHi = value;
146                 break;
147             case Registers.HashTableLo:
148                 registers.HashTableLo = value;
149                 break;
150             default:
151                 this.LogUnhandledWrite(offset, value);
152                 break;
153             }
154         }
155 
156         #endregion
157 
158 
159         #region IGaislerAPB implementation
160 
GetVendorID()161         public uint GetVendorID()
162         {
163             return vendorID;
164         }
165 
GetDeviceID()166         public uint GetDeviceID()
167         {
168             return deviceID;
169         }
170 
GetInterruptNumber()171         public uint GetInterruptNumber()
172         {
173             return this.GetCpuInterruptNumber(IRQ);
174         }
175 
GetSpaceType()176         public GaislerAPBPlugAndPlayRecord.SpaceType GetSpaceType()
177         {
178             return GaislerAPBPlugAndPlayRecord.SpaceType.APBIOSpace;
179         }
180 
181         public event Action<EthernetFrame> FrameReady;
182 
183         private readonly uint vendorID = 0x01;
184         // Aeroflex Gaisler
185         private readonly uint deviceID = 0x1D;
186         // GRLIB GRETH
187 
188         #endregion
189 
190         #region IKnownSize implementation
191 
192         public long Size
193         {
194             get
195             {
196                 return 0x100;
197             }
198         }
199 
200         #endregion
201 
202         #region INetworkInterface implementation
203 
ReceiveFrame(EthernetFrame frame)204         public void ReceiveFrame(EthernetFrame frame)
205         {
206             if((registers.Control & (1u << 1)) == 0)
207             {
208                 //if receiving is disabled discard packet
209                 return;
210             }
211 
212             var rd = new receiveDescriptor(sysbus);
213 
214             if(!EthernetFrame.CheckCRC(frame.Bytes))
215             {
216                 rd.CRCError = true;
217                 this.Log(LogLevel.Warning, "Invalid CRC, packet discarded");
218                 return;
219             }
220 
221             rd.Fetch(receiveDescriptorBase | receiveDescriptorOffset);
222             if(!rd.Enable)
223             {
224                 //if receive descritptor disabled discard packet
225                 return;
226             }
227 
228             sysbus.WriteBytes(frame.Bytes, rd.PacketAddress);
229             registers.Status = 1u << 2;
230             if(rd.Wrap)
231             {
232                 receiveDescriptorOffset = 0;
233             }
234             else
235             {
236                 if(receiveDescriptorOffset != 0x3f8)
237                 {
238                     receiveDescriptorOffset += 8;
239                 }
240                 else
241                 {
242                     receiveDescriptorOffset = 0;
243                 }
244             }
245             if(rd.InterruptEnable && ((registers.Control & (1u << 3)) != 0))
246             {
247                 registers.Status |= 1u << 2;
248                 this.IRQ.Set();
249                 this.IRQ.Unset();
250             }
251             rd.Length = (uint)frame.Bytes.Length;
252             rd.Enable = false;
253             rd.Wrap = false;
254             rd.WriteBack();
255         }
256 
transmitFrame()257         private void transmitFrame()
258         {
259             var td = new transmitDescriptor(sysbus);
260             td.Fetch(transmitDescriptorBase | transmitDescriptorOffset);
261 
262             if(!td.Enable)
263             {
264                 return; //if decriptor is disabled there is nothing to send (just return)
265             }
266 
267             var packetBytes = sysbus.ReadBytes(td.PacketAddress, (int)td.Length);
268             if(!Misc.TryCreateFrameOrLogWarning(this, packetBytes, out var packet, addCrc: true))
269             {
270                 return;
271             }
272 
273             this.Log(LogLevel.Noisy, "Sending packet length {0}, packet address = 0x{1:X}", packet.Bytes.Length, td.PacketAddress);
274             FrameReady?.Invoke(packet);
275 
276             registers.Status |= 1u << 3;
277 
278             if(td.Wrap)
279             {
280                 transmitDescriptorOffset = 0;
281             }
282             else
283             {
284                 if(transmitDescriptorOffset != 0x3f8)
285                 {
286                     transmitDescriptorOffset += 8;
287                 }
288                 else
289                 {
290                     transmitDescriptorOffset = 0;
291                 }
292             }
293 
294             if(td.InterruptEnable && ((registers.Control & (1u << 2)) != 0))
295             {
296                 //if interrupts enabled
297                 registers.Status |= 1u << 3; //transmitter interrupt bit
298                 this.IRQ.Set();
299                 this.IRQ.Unset();
300             }
301 
302             td.Enable = false;
303             td.Wrap = false;
304             td.InterruptEnable = false;
305             td.Length = 0;
306             td.UnderrunError = false;
307             td.AttemptLimitError = false;
308             td.WriteBack();
309 
310         }
311 
312         #endregion
313 
314         #region IMACInterface implementation
315 
316         public MACAddress MAC { get; set; }
317 
318         #endregion
319 
320         private readonly IBusController sysbus;
321 
322         #region registers
323 
324         private regs registers;
325 
326         private class regs
327         {
328             public uint Control = 1u << 7;
329             public uint Status;
330             public uint MacAddresHi;
331             public uint MacAddresLo;
332             public uint MDIOControlStatus;
333             public uint TxDescriptorPointer;
334             public uint RxDescriptorPointer;
335             public uint HashTableHi;
336             public uint HashTableLo;
337         }
338 
339         private enum Registers : uint
340         {
341             Control = 0x00,
342             Status = 0x04,
343             MacAddressHi = 0x08,
344             MacAddressLo = 0x0C,
345             MDIOControlStatus = 0x10,
346             TxDescriptorPointer = 0x14,
347             RxDescriptorPointer = 0x18,
348             HashTableHi = 0x20,
349             HashTableLo = 0x24
350         }
351 
352         #endregion
353 
354         #region descriptors
355 
356         private uint transmitDescriptorBase;
357         private uint transmitDescriptorOffset;
358 
359         private uint receiveDescriptorBase;
360         private uint receiveDescriptorOffset;
361 
362         private class transmitDescriptor
363         {
transmitDescriptor(IBusController sysbus)364             public transmitDescriptor(IBusController sysbus)
365             {
366                 sbus = sysbus;
367             }
368 
369             private IBusController sbus;
370 
371             private uint word0;
372             private uint word1;
373             private uint ramAddress;
374 
375             public bool AttemptLimitError;
376             public bool UnderrunError;
377             public bool InterruptEnable;
378             public bool Wrap;
379             public bool Enable;
380             public uint Length;
381             public uint PacketAddress;
382 
Fetch(uint address)383             public void Fetch(uint address)
384             {
385                 ramAddress = address;
386 
387                 word0 = sbus.ReadDoubleWord(ramAddress);
388                 word1 = sbus.ReadDoubleWord(ramAddress + 4);
389 
390                 AttemptLimitError = (word0 & (1u << 15)) != 0;
391                 UnderrunError = (word0 & (1u << 14)) != 0;
392                 InterruptEnable = (word0 & (1u << 13)) != 0;
393                 Wrap = (word0 & (1u << 12)) != 0;
394                 Enable = (word0 & (1u << 11)) != 0;
395                 Length = word0 & 0x7ffu;
396 
397                 PacketAddress = word1 & ~(0x03u);
398             }
399 
WriteBack()400             public void WriteBack()
401             {
402                 word0 = (AttemptLimitError ? 1u << 15 : 0) | (UnderrunError ? 1u << 14 : 0) | (InterruptEnable ? 1u << 13 : 0);
403                 word0 |= (Wrap ? 1u << 12 : 0) | (Enable ? 1u << 11 : 0) | (Length & 0x7ffu);
404 
405                 word1 = PacketAddress & ~(0x03u);
406 
407                 sbus.WriteDoubleWord(ramAddress, word0);
408                 sbus.WriteDoubleWord(ramAddress + 4, word1);
409             }
410         }
411 
412         private class receiveDescriptor
413         {
receiveDescriptor(IBusController sysbus)414             public receiveDescriptor(IBusController sysbus)
415             {
416                 sbus = sysbus;
417             }
418 
419             private IBusController sbus;
420 
421             private uint word0;
422             private uint word1;
423             private uint ramAddress;
424 
425             public bool MulticastAddress;
426             public bool LengthError;
427             public bool OverrunError;
428             public bool CRCError;
429             public bool FrameTooLong;
430             public bool AlignmentError;
431             public bool InterruptEnable;
432             public bool Wrap;
433             public bool Enable;
434             public uint Length;
435             public uint PacketAddress;
436 
Fetch(uint address)437             public void Fetch(uint address)
438             {
439                 ramAddress = address;
440                 word0 = sbus.ReadDoubleWord(ramAddress);
441                 word1 = sbus.ReadDoubleWord(ramAddress + 4);
442 
443                 MulticastAddress = (word0 & (1u << 26)) != 0;
444                 LengthError = (word0 & (1u << 18)) != 0;
445                 OverrunError = (word0 & (1u << 17)) != 0;
446                 CRCError = (word0 & (1u << 16)) != 0;
447                 FrameTooLong = (word0 & (1u << 15)) != 0;
448                 AlignmentError = (word0 & (1u << 14)) != 0;
449                 InterruptEnable = (word0 & (1u << 13)) != 0;
450                 Wrap = (word0 & (1u << 12)) != 0;
451                 Enable = (word0 & (1u << 11)) != 0;
452                 Length = word0 & (0x7ffu);
453 
454                 PacketAddress = word1 & ~(0x03u);
455             }
456 
WriteBack()457             public void WriteBack()
458             {
459                 word0 = (MulticastAddress ? 1u << 26 : 0) | (LengthError ? 1u << 18 : 0) | (OverrunError ? 1u << 17 : 0);
460                 word0 |= (CRCError ? 1u << 16 : 0) | (FrameTooLong ? 1u << 15 : 0) | (AlignmentError ? 1u << 14 : 0);
461                 word0 |= (InterruptEnable ? 1u << 13 : 0) | (Wrap ? 1u << 12 : 0) | (Enable ? 1u << 18 : 0) | (Length & (0x7ffu));
462 
463                 word1 = PacketAddress & ~(0x03u);
464 
465                 sbus.WriteDoubleWord(ramAddress, word0);
466                 sbus.WriteDoubleWord(ramAddress + 4, word1);
467             }
468         }
469 
470         #endregion
471     }
472 }
473 
474