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.Linq;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Time;
11 using Antmicro.Renode.Peripherals.Timers;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.Bus;
15 using System.Collections.Generic;
16 using Antmicro.Renode.Network;
17 using Antmicro.Renode.Utilities;
18 using Antmicro.Renode.Core.Structure.Registers;
19 
20 namespace Antmicro.Renode.Peripherals.Network
21 {
22     // The register and field names are taken from the UltraScale+ GEM docs,
23     // because it is the most extensive description of this peripheral:
24     // https://www.xilinx.com/html_docs/registers/ug1087/mod___gem.html
25     // For further reference however, here are links to other sources:
26     // https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
27     // https://www.mouser.com/datasheet/2/268/SAM-E70S70V70V71-Family_DataSheet-DS60001527B-1374834.pdf
28     public class CadenceGEM : NetworkWithPHY, IDoubleWordPeripheral, IMACInterface, IKnownSize
29     {
30         // the default moduleRevision/moduleId are correct for Zynq with GEM p23
CadenceGEM(IMachine machine, ushort moduleRevision = 0x118, ushort moduleId = 0x2)31         public CadenceGEM(IMachine machine, ushort moduleRevision = 0x118, ushort moduleId = 0x2) : base(machine)
32         {
33             ModuleId = moduleId;
34             ModuleRevision = moduleRevision;
35             sysbus = machine.GetSystemBus(this);
36 
37             IRQ = new GPIO();
38             MAC = EmulationManager.Instance.CurrentEmulation.MACRepository.GenerateUniqueMAC();
39             sync = new object();
40 
41             interruptManager = new InterruptManager<Interrupts>(this);
42 
43             nanoTimer = new LimitTimer(machine.ClockSource, NanosPerSecond, this, "PTP nanos",
44                     limit: NanosPerSecond,
45                     direction: Direction.Ascending,
46                     workMode: WorkMode.Periodic,
47                     eventEnabled: true);
48 
49             nanoTimer.LimitReached += () => secTimer.Value++;
50 
51             var registersMap = new Dictionary<long, DoubleWordRegister>
52             {
53                 {(long)Registers.NetworkControl, new DoubleWordRegister(this)
54                     .WithTag("loopback", 0, 1)
55                     .WithTag("loopback_local", 1, 1)
56                     .WithFlag(2, out receiveEnabled, name: "enable_receive")
57                     .WithFlag(3, name: "enable_transmit",
58                         writeCallback: (_, value) =>
59                         {
60                             if(!value)
61                             {
62                                 isTransmissionStarted = false;
63                             }
64                             if(txDescriptorsQueue != null && !value)
65                             {
66                                 txDescriptorsQueue.GoToBaseAddress();
67                             }
68                         })
69                     .WithTag("man_port_en", 4, 1)
70                     .WithTag("clear_all_stats_regs", 5, 1)
71                     .WithTag("inc_all_stats_regs", 6, 1)
72                     .WithTag("stats_write_en", 7, 1)
73                     .WithTag("back_pressure", 8, 1)
74                     .WithFlag(9, FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_start_pclk",
75                         writeCallback: (_, value) =>
76                         {
77                             if(value)
78                             {
79                                 isTransmissionStarted = true;
80                                 SendFrames();
81                             }
82                         })
83                     .WithFlag(10, FieldMode.Read | FieldMode.WriteOneToClear, name: "tx_halt_pclk",
84                         writeCallback: (_, value) =>
85                         {
86                             if(value)
87                             {
88                                 isTransmissionStarted = false;
89                             }
90                         })
91                     .WithTag("tx_pause_frame_req", 11, 1)
92                     .WithTag("tx_pause_frame_zero", 12, 1)
93                     .WithReservedBits(13, 2)
94                     .WithTag("store_rx_ts", 15, 1)
95                     .WithTag("pfc_enable", 16, 1)
96                     .WithTag("transmit_pfc_priority_based_pause_frame", 17, 1)
97                     .WithTag("flush_rx_pkt_pclk", 18, 1)
98                     .WithTag("tx_lpi_en", 19, 1)
99                     .WithTag("ptp_unicast_ena", 20, 1)
100                     .WithTag("alt_sgmii_mode", 21, 1)
101                     .WithTag("store_udp_offset", 22, 1)
102                     .WithTag("ext_tsu_port_enable", 23, 1)
103                     .WithTag("one_step_sync_mode", 24, 1)
104                     .WithReservedBits(25, 7)
105                 },
106 
107                 {(long)Registers.NetworkConfiguration, new DoubleWordRegister(this, 0x80000)
108                     .WithTag("speed", 0, 1)
109                     .WithTag("full_duplex", 1, 1)
110                     .WithTag("discard_non_vlan_frames", 2, 1)
111                     .WithTag("jumbo_frames", 3, 1)
112                     .WithTag("copy_all_frames", 4, 1)
113                     .WithTag("no_broadcast", 5, 1)
114                     .WithTag("multicast_hash_enable", 6, 1)
115                     .WithTag("unicast_hash_enable", 7, 1)
116                     .WithTag("receive_1536_byte_frames", 8, 1)
117                     .WithTag("external_address_match_enable", 9, 1)
118                     .WithTag("gigabit_mode_enable", 10, 1)
119                     .WithTag("pcs_select", 11, 1)
120                     .WithTag("retry_test", 12, 1)
121                     .WithTag("pause_enable", 13, 1)
122                     .WithValueField(14, 2, out receiveBufferOffset, name: "receive_buffer_offset")
123                     .WithTag("length_field_error_frame_discard", 16, 1)
124                     .WithFlag(17, out removeFrameChecksum, name: "fcs_remove")
125                     .WithTag("mdc_clock_division", 18, 3)
126                     .WithTag("data_bus_width", 21, 2)
127                     .WithTag("disable_copy_of_pause_frames", 23, 1)
128                     .WithTag("receive_checksum_offload_enable", 24, 1)
129                     .WithTag("en_half_duplex_rx", 25, 1)
130                     .WithFlag(26, out ignoreRxFCS, name: "ignore_rx_fcs")
131                     .WithTag("sgmii_mode_enable", 27, 1)
132                     .WithTag("ipg_stretch_enable", 28, 1)
133                     .WithTag("nsp_change", 29, 1)
134                     .WithTag("ignore_ipg_rx_er", 30, 1)
135                     .WithTag("uni_direction_enable", 31, 1)
136                 },
137 
138                 {(long)Registers.NetworkStatus, new DoubleWordRegister(this)
139                     .WithTag("pcs_link_state", 0, 1)
140                     .WithTag("mdio_in", 1, 1)
141                     .WithFlag(2, FieldMode.Read, name: "man_done", valueProviderCallback: _ => true)
142                     .WithTag("mac_full_duplex", 3, 1)
143                     .WithTag("mac_pause_rx_en", 4, 1)
144                     .WithTag("mac_pause_tx_en", 5, 1)
145                     .WithTag("pfc_negotiate_pclk", 6, 1)
146                     .WithTag("lpi_indicate_pclk", 7, 1)
147                     .WithReservedBits(8, 24)
148                 },
149 
150                 {(long)Registers.DmaConfiguration, new DoubleWordRegister(this, 0x00020784)
151                     .WithTag("amba_burst_length", 0, 4)
152                     .WithReservedBits(5, 1)
153                     .WithTag("endian_swap_management", 6, 1)
154                     .WithTag("endian_swap_packet", 7, 1)
155                     .WithTag("rx_pbuf_size", 8, 2)
156                     .WithTag("tx_pbuf_size", 10, 1)
157                     .WithFlag(11, out checksumGeneratorEnabled, name: "tx_pbuf_tcp_en")
158                     .WithReservedBits(12, 4)
159                     .WithTag("rx_buf_size", 16, 8)
160                     .WithTag("force_discard_on_err", 24, 1)
161                     .WithTag("force_max_amba_burst_rx", 25, 1)
162                     .WithTag("force_max_amba_burst_tx", 26, 1)
163                     .WithReservedBits(27, 1)
164                     .WithFlag(28, out extendedRxBufferDescriptorEnabled, name: "rx_bd_extended_mode_en")
165                     .WithFlag(29, out extendedTxBufferDescriptorEnabled, name: "tx_bd_extended_mode_en")
166                     .WithEnumField(30, 1, out dmaAddressBusWith, name: "dma_addr_bus_width_1")
167                     .WithReservedBits(31, 1)
168                 },
169 
170                 {(long)Registers.TransmitStatus, new DoubleWordRegister(this)
171                     .WithFlag(0, out usedBitRead, FieldMode.Read | FieldMode.WriteOneToClear, name: "used_bit_read")
172                     .WithTag("collision_occurred", 1, 1)
173                     .WithTag("retry_limit_exceeded", 2, 1)
174                     .WithTag("transmit_go", 3, 1)
175                     .WithTag("amba_error", 4, 1)
176                     .WithFlag(5, out transmitComplete, FieldMode.Read | FieldMode.WriteOneToClear, name: "transmit_complete")
177                     .WithTag("transmit_under_run", 6, 1)
178                     .WithTag("late_collision_occurred", 7, 1)
179                     .WithTag("resp_not_ok", 8, 1)
180                     .WithReservedBits(9, 23)
181                 },
182 
183                 {(long)Registers.ReceiveBufferQueueBaseAddress, new DoubleWordRegister(this)
184                     .WithReservedBits(0, 2)
185                     .WithValueField(2, 30, name: "dma_rx_q_ptr",
186                         valueProviderCallback: _ =>
187                         {
188                             return rxDescriptorsQueue.CurrentDescriptor.LowerDescriptorAddress;
189                         },
190                         writeCallback: (oldValue, value) =>
191                         {
192                             if(receiveEnabled.Value)
193                             {
194                                 this.Log(LogLevel.Warning, "Changing value of receive buffer queue base address while reception is enabled is illegal");
195                                 return;
196                             }
197                             rxDescriptorsQueue = new DmaBufferDescriptorsQueue<DmaRxBufferDescriptor>(sysbus, (uint)value << 2, (sb, addr) => new DmaRxBufferDescriptor(sb, addr, dmaAddressBusWith.Value, extendedRxBufferDescriptorEnabled.Value));
198                         })
199                 },
200 
201                 {(long)Registers.ReceiveBufferQueueBaseAddressUpper, new DoubleWordRegister(this)
202                     .WithValueField(0, 32, name: "upper_rx_q_base_addr",
203                         valueProviderCallback: _ =>
204                         {
205                             return rxDescriptorsQueue.CurrentDescriptor.UpperDescriptorAddress;
206                         },
207                         writeCallback: (oldValue, value) =>
208                         {
209                             rxDescriptorsQueue.CurrentDescriptor.UpperDescriptorAddress = (uint)value;
210                         })
211                 },
212 
213                 {(long)Registers.ReceiveBufferDescriptorControl, new DoubleWordRegister(this)
214                     .WithReservedBits(0, 4)
215                     .WithEnumField(4, 2, out rxBufferDescriptorTimeStampMode, name: "rx_bd_ts_mode")
216                     .WithReservedBits(6, 26)
217                 },
218 
219                 {(long)Registers.TransmitBufferQueueBaseAddress, new DoubleWordRegister(this)
220                     .WithReservedBits(0, 2)
221                     .WithValueField(2, 30, name: "dma_tx_q_ptr",
222                         valueProviderCallback: _ =>
223                         {
224                             return txDescriptorsQueue.CurrentDescriptor.LowerDescriptorAddress;
225                         },
226                         writeCallback: (oldValue, value) =>
227                         {
228                             if(isTransmissionStarted)
229                             {
230                                 this.Log(LogLevel.Warning, "Changing value of transmit buffer queue base address while transmission is started is illegal");
231                                 return;
232                             }
233                             txDescriptorsQueue = new DmaBufferDescriptorsQueue<DmaTxBufferDescriptor>(sysbus, (uint)value << 2, (sb, addr) => new DmaTxBufferDescriptor(sb, addr, dmaAddressBusWith.Value, extendedTxBufferDescriptorEnabled.Value));
234                         })
235                 },
236 
237                 {(long)Registers.TransmitBufferQueueBaseAddressUpper, new DoubleWordRegister(this)
238                     .WithValueField(0, 32, name: "upper_tx_q_base_addr",
239                         valueProviderCallback: _ =>
240                         {
241                             return txDescriptorsQueue.CurrentDescriptor.UpperDescriptorAddress;
242                         },
243                         writeCallback: (oldValue, value) =>
244                         {
245                             txDescriptorsQueue.CurrentDescriptor.UpperDescriptorAddress = (uint)value;
246                         })
247                 },
248 
249                 {(long)Registers.TransmitBufferDescriptorControl, new DoubleWordRegister(this)
250                     .WithReservedBits(0, 4)
251                     .WithEnumField(4, 2, out txBufferDescriptorTimeStampMode, name: "tx_bd_ts_mode")
252                     .WithReservedBits(6, 26)
253                 },
254 
255                 {(long)Registers.ReceiveStatus, new DoubleWordRegister(this)
256                     .WithFlag(0, out bufferNotAvailable, FieldMode.Read | FieldMode.WriteOneToClear, name: "buffer_not_available")
257                     .WithFlag(1, out frameReceived, FieldMode.Read | FieldMode.WriteOneToClear, name: "frame_received")
258                     .WithTag("receive_overrun", 2, 1)
259                     .WithTag("resp_not_ok", 3, 1)
260                     .WithReservedBits(4, 28)
261                 },
262 
263                 {(long)Registers.InterruptStatus, interruptManager.GetRegister<DoubleWordRegister>(
264                     valueProviderCallback: (interrupt, oldValue) =>
265                     {
266                         var status = interruptManager.IsSet(interrupt) && interruptManager.IsEnabled(interrupt);
267                         interruptManager.ClearInterrupt(interrupt);
268 
269                         return status;
270                     },
271                     writeCallback: (interrupt, oldValue, newValue) =>
272                     {
273                         if(newValue)
274                         {
275                             interruptManager.ClearInterrupt(interrupt);
276                         }
277                     })
278                 },
279 
280                 {(long)Registers.InterruptEnable, interruptManager.GetRegister<DoubleWordRegister>(
281                     writeCallback: (interrupt, oldValue, newValue) =>
282                     {
283                         if(newValue)
284                         {
285                             interruptManager.EnableInterrupt(interrupt);
286                         }
287                     })
288                 },
289 
290                 {(long)Registers.InterruptDisable, interruptManager.GetRegister<DoubleWordRegister>(
291                     writeCallback: (interrupt, oldValue, newValue) =>
292                     {
293                         if(newValue)
294                         {
295                             interruptManager.DisableInterrupt(interrupt);
296                         }
297                     })
298                 },
299 
300                 {(long)Registers.InterruptMaskStatus, interruptManager.GetRegister<DoubleWordRegister>(
301                     valueProviderCallback: (interrupt, oldValue) => !interruptManager.IsEnabled(interrupt))
302                 },
303 
304                 {(long)Registers.PhyMaintenance, new DoubleWordRegister(this)
305                     .WithValueField(0, 31, name: "phy_management", writeCallback: (_, value) => HandlePhyWrite((uint)value), valueProviderCallback: _ => HandlePhyRead())
306                 },
307 
308                 {(long)Registers.SpecificAddress1Bottom, new DoubleWordRegister(this)
309                     .WithValueField(0, 32, valueProviderCallback: _ => BitConverter.ToUInt32(MAC.Bytes, 0))
310                 },
311 
312                 {(long)Registers.SpecificAddress1Top, new DoubleWordRegister(this)
313                     .WithValueField(0, 16, valueProviderCallback: _ => BitConverter.ToUInt16(MAC.Bytes, 4))
314                     .WithTag("filter_type", 16, 1)
315                     .WithReservedBits(17, 15)
316                 },
317 
318                 {(long)Registers.ModuleId, new DoubleWordRegister(this)
319                     .WithValueField(0, 16, FieldMode.Read, name: "module_revision", valueProviderCallback: _ => ModuleRevision)
320                     .WithValueField(16, 12, FieldMode.Read, name: "module_identification_number", valueProviderCallback: _ => ModuleId)
321                     .WithTag("fix_number", 28, 4)
322                 },
323 
324                 {(long)Registers.DesignConfiguration1, new DoubleWordRegister(this)
325                     .WithTag("no_pcs", 0, 1)
326                     .WithTag("serdes", 1, 1)
327                     .WithTag("RDC_50", 2, 1)
328                     .WithTag("TDC_50", 3, 1)
329                     .WithTag("int_loopback", 4, 1)
330                     .WithTag("no_int_loopback", 5, 1)
331                     .WithTag("ext_fifo_interface", 6, 1)
332                     .WithTag("apb_rev1", 7, 1)
333                     .WithTag("apb_rev2", 8, 1)
334                     .WithTag("user_io", 9, 1)
335                     .WithTag("user_out_width", 10, 5)
336                     .WithTag("user_in_width", 15, 5)
337                     .WithTag("no_scan_pins", 20, 1)
338                     .WithTag("no_stats", 21, 1)
339                     .WithTag("no_snapshot", 22, 1)
340                     .WithFlag(23, FieldMode.Read, name: "irq_read_clear", valueProviderCallback: _ => false)
341                     .WithReservedBits(24, 1)
342                     .WithValueField(25, 3, FieldMode.Read, name: "dma_bus_width", valueProviderCallback: _ => 1) // DMA data bus width - 32 bits
343                     .WithTag("axi_cache_value", 28, 4)
344                 },
345 
346                 {(long)Registers.DesignConfiguration2, new DoubleWordRegister(this)
347                     .WithTag("jumbo_max_length", 0, 16)
348                     .WithTag("hprot_value", 16, 4)
349                     .WithFlag(20, FieldMode.Read, name: "rx_pkt_buffer", valueProviderCallback: _ => true) // includes the receiver packet buffer
350                     .WithFlag(21, FieldMode.Read, name: "tx_pkt_buffer", valueProviderCallback: _ => true) // includes the transmitter packet buffer
351                     .WithTag("rx_pbuf_addr", 22, 4)
352                     .WithTag("tx_pbuf_addr", 26, 4)
353                     .WithTag("axi", 30, 1)
354                     .WithTag("spram", 31, 1)
355                 },
356 
357                 {(long)Registers.Timer1588SecondsLow, new DoubleWordRegister(this)
358                     .WithValueField(0, 32, out secTimer, name: "tsu_timer_sec")
359                 },
360 
361                 {(long)Registers.Timer1588SecondsHigh, new DoubleWordRegister(this)
362                     .WithValueField(0, 16, valueProviderCallback: _ => 0, writeCallback: (_, value) =>
363                     {
364                         if(value != 0)
365                         {
366                             this.Log(LogLevel.Warning, "Writing a non-zero value to the SecondsHigh register, timer values over 32 bits are not supported.");
367                         }
368                     }, name: "tsu_timer_msb_sec")
369                     .WithReservedBits(16, 16)
370                 },
371 
372                 {(long)Registers.Timer1588Nanoseconds, new DoubleWordRegister(this)
373                     .WithValueField(0, 30, valueProviderCallback: _ =>
374                     {
375                         return (uint)nanoTimer.Value;
376                     }, writeCallback: (_, value) =>
377                     {
378                         nanoTimer.Value = value;
379                     }, name: "tsu_timer_nsec")
380                     .WithReservedBits(30, 2)
381                 },
382 
383                 {(long)Registers.Timer1588Adjust, new DoubleWordRegister(this)
384                     .WithValueField(0, 30, out var timerIncrementDecrement, FieldMode.Write, name: "increment_value")
385                     .WithReservedBits(30, 1)
386                     .WithFlag(31, out var timerAdjust, FieldMode.Write, name: "add_subtract")
387                     .WithWriteCallback((_, __) =>
388                     {
389                         if(timerAdjust.Value)
390                         {
391                             secTimer.Value -= nanoTimer.Decrement(timerIncrementDecrement.Value);
392                         }
393                         else
394                         {
395                             secTimer.Value += nanoTimer.Increment(timerIncrementDecrement.Value);
396                         }
397                     })
398                 },
399 
400                 {(long)Registers.PtpEventFrameTransmittedSecondsHigh, new DoubleWordRegister(this)
401                     .WithValueField(0, 16, FieldMode.Read, valueProviderCallback: _ => 0, name: "tsu_ptp_tx_msb_sec")
402                     .WithReservedBits(16, 16)
403                 },
404 
405                 {(long)Registers.PtpEventFrameTransmittedSeconds, new DoubleWordRegister(this)
406                     .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => txPacketTimestamp.seconds, name: "tsu_ptp_tx_sec")
407                 },
408 
409                 {(long)Registers.PtpEventFrameTransmittedNanoseconds, new DoubleWordRegister(this)
410                     .WithValueField(0, 30, FieldMode.Read, valueProviderCallback: _ => txPacketTimestamp.nanos, name: "tsu_ptp_tx_nsec")
411                     .WithReservedBits(30, 2)
412                 },
413 
414                 {(long)Registers.PtpEventFrameReceivedSecondsHigh, new DoubleWordRegister(this)
415                     .WithValueField(0, 16, FieldMode.Read, valueProviderCallback: _ => 0, name: "tsu_ptp_rx_msb_sec")
416                     .WithReservedBits(16, 16)
417                 },
418 
419                 {(long)Registers.PtpEventFrameReceivedSeconds, new DoubleWordRegister(this)
420                     .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => rxPacketTimestamp.seconds, name: "tsu_ptp_rx_sec")
421                 },
422 
423                 {(long)Registers.PtpEventFrameReceivedNanoseconds, new DoubleWordRegister(this)
424                     .WithValueField(0, 30, FieldMode.Read, valueProviderCallback: _ => rxPacketTimestamp.nanos, name: "tsu_ptp_rx_nsec")
425                     .WithReservedBits(30, 2)
426                 },
427 
428                 {(long)Registers.PtpPeerEventFrameTransmittedSecondsHigh, new DoubleWordRegister(this)
429                     .WithValueField(0, 16, FieldMode.Read, valueProviderCallback: _ => 0, name: "tsu_peer_tx_msb_sec")
430                     .WithReservedBits(16, 16)
431                 },
432 
433                 {(long)Registers.PtpPeerEventFrameTransmittedSeconds, new DoubleWordRegister(this)
434                     .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => txPacketTimestamp.seconds, name: "tsu_peer_tx_sec")
435                 },
436 
437                 {(long)Registers.PtpPeerEventFrameTransmittedNanoseconds, new DoubleWordRegister(this)
438                     .WithValueField(0, 30, FieldMode.Read, valueProviderCallback: _ => txPacketTimestamp.nanos, name: "tsu_peer_tx_nsec")
439                     .WithReservedBits(30, 2)
440                 },
441 
442                 {(long)Registers.PtpPeerEventFrameReceivedSecondsHigh, new DoubleWordRegister(this)
443                     .WithValueField(0, 16, FieldMode.Read, valueProviderCallback: _ => 0, name: "tsu_peer_rx_msb_sec")
444                     .WithReservedBits(16, 16)
445                 },
446 
447                 {(long)Registers.PtpPeerEventFrameReceivedSeconds, new DoubleWordRegister(this)
448                     .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => rxPacketTimestamp.seconds, name: "tsu_peer_rx_sec")
449                 },
450 
451                 {(long)Registers.PtpPeerEventFrameReceivedNanoseconds, new DoubleWordRegister(this)
452                     .WithValueField(0, 30, FieldMode.Read, valueProviderCallback: _ => rxPacketTimestamp.nanos, name: "tsu_peer_rx_nsec")
453                     .WithReservedBits(30, 2)
454                 }
455             };
456 
457             registers = new DoubleWordRegisterCollection(this, registersMap);
458             Reset();
459         }
460 
Reset()461         public override void Reset()
462         {
463             registers.Reset();
464             interruptManager.Reset();
465             txDescriptorsQueue = null;
466             rxDescriptorsQueue = null;
467             phyDataRead = 0;
468             isTransmissionStarted = false;
469             nanoTimer.Reset();
470             nanoTimer.Enabled = true;
471         }
472 
ReadDoubleWord(long offset)473         public uint ReadDoubleWord(long offset)
474         {
475             lock(sync)
476             {
477                 return registers.Read(offset);
478             }
479         }
480 
WriteDoubleWord(long offset, uint value)481         public void WriteDoubleWord(long offset, uint value)
482         {
483             lock(sync)
484             {
485                 registers.Write(offset, value);
486             }
487         }
488 
ReceiveFrame(EthernetFrame frame)489         public void ReceiveFrame(EthernetFrame frame)
490         {
491             lock(sync)
492             {
493                 this.Log(LogLevel.Debug, "Received packet, length {0}", frame.Bytes.Length);
494                 if(!receiveEnabled.Value)
495                 {
496                     this.Log(LogLevel.Info, "Receiver not enabled, dropping frame");
497                     return;
498                 }
499 
500                 if(!ignoreRxFCS.Value && !EthernetFrame.CheckCRC(frame.Bytes))
501                 {
502                     this.Log(LogLevel.Info, "Invalid CRC, packet discarded");
503                     return;
504                 }
505 
506                 // the time obtained here is not single-instruction-precise (unless maximum block size is set to 1 and block chaining is disabled),
507                 // because timers are not updated instruction-by-instruction, but in batches when `TranslationCPU.ExecuteInstructions` finishes
508                 rxPacketTimestamp.seconds = (uint)secTimer.Value;
509                 rxPacketTimestamp.nanos = (uint)nanoTimer.Value;
510 
511                 rxDescriptorsQueue.CurrentDescriptor.Invalidate();
512                 if(!rxDescriptorsQueue.CurrentDescriptor.Ownership)
513                 {
514                     var actualLength = (uint)(removeFrameChecksum.Value ? frame.Bytes.Length - 4 : frame.Bytes.Length);
515                     if(!rxDescriptorsQueue.CurrentDescriptor.WriteBuffer(frame.Bytes, actualLength, (uint)receiveBufferOffset.Value))
516                     {
517                         // The current implementation doesn't handle packets that do not fit into a single buffer.
518                         // In case we encounter this error, we probably should implement partitioning/scattering procedure.
519                         this.Log(LogLevel.Warning, "Could not write the incoming packet to the DMA buffer: maximum packet length exceeded.");
520                         return;
521                     }
522 
523                     rxDescriptorsQueue.CurrentDescriptor.StartOfFrame = true;
524                     rxDescriptorsQueue.CurrentDescriptor.EndOfFrame = true;
525 
526                     if(rxBufferDescriptorTimeStampMode.Value != TimestampingMode.Disabled)
527                     {
528                         rxDescriptorsQueue.CurrentDescriptor.Timestamp = rxPacketTimestamp;
529                     }
530                     else
531                     {
532                         rxDescriptorsQueue.CurrentDescriptor.HasValidTimestamp = false;
533                     }
534 
535                     rxDescriptorsQueue.GoToNextDescriptor();
536 
537                     frameReceived.Value = true;
538                     interruptManager.SetInterrupt(Interrupts.ReceiveComplete);
539                 }
540                 else
541                 {
542                     this.Log(LogLevel.Warning, "Receive DMA buffer overflow");
543                     bufferNotAvailable.Value = true;
544                     interruptManager.SetInterrupt(Interrupts.ReceiveUsedBitRead);
545                 }
546             }
547         }
548 
549         public event Action<EthernetFrame> FrameReady;
550 
551         public long Size => 0x1000;
552 
553         public MACAddress MAC { get; set; }
554 
555         public ushort ModuleRevision { get; private set; }
556         public ushort ModuleId { get; private set; }
557 
558         [IrqProvider]
559         public GPIO IRQ { get; private set; }
560 
HandlePhyRead()561         private uint HandlePhyRead()
562         {
563             return phyDataRead;
564         }
565 
HandlePhyWrite(uint value)566         private void HandlePhyWrite(uint value)
567         {
568             var data = (ushort)(value & 0xFFFF);
569             var reg = (ushort)((value >> 18) & 0x1F);
570             var addr = (uint)((value >> 23) & 0x1F);
571             var op = (PhyOperation)((value >> 28) & 0x3);
572 
573             if(!TryGetPhy<ushort>(addr, out var phy))
574             {
575                 this.Log(LogLevel.Warning, "Write to PHY with unknown address {0}", addr);
576                 phyDataRead = 0xFFFFU;
577                 return;
578             }
579 
580             switch(op)
581             {
582                 case PhyOperation.Read:
583                     phyDataRead = phy.Read(reg);
584                     break;
585                 case PhyOperation.Write:
586                     phy.Write(reg, data);
587                     break;
588                 default:
589                     this.Log(LogLevel.Warning, "Unknown PHY operation code 0x{0:X}", op);
590                     break;
591             }
592 
593             interruptManager.SetInterrupt(Interrupts.ManagementDone);
594         }
595 
SendSingleFrame(IEnumerable<byte> bytes, bool isCRCIncluded)596         private void SendSingleFrame(IEnumerable<byte> bytes, bool isCRCIncluded)
597         {
598             var bytesArray = bytes.ToArray();
599             EnsureArrayLength(bytesArray, isCRCIncluded ? 64 : 60);
600 
601             EthernetFrame frame;
602             var addCrc = !isCRCIncluded && checksumGeneratorEnabled.Value;
603             if(!Misc.TryCreateFrameOrLogWarning(this, bytesArray, out frame, addCrc))
604             {
605                 return;
606             }
607             if(addCrc)
608             {
609                 frame.FillWithChecksums(new [] { EtherType.IpV4, EtherType.IpV6 },
610                     new [] { IPProtocolType.TCP, IPProtocolType.UDP });
611             }
612 
613             this.Log(LogLevel.Noisy, "Sending packet, length {0}", frame.Bytes.Length);
614             FrameReady?.Invoke(frame);
615 
616             // the time obtained here is not single-instruction-precise (unless maximum block size is set to 1 and block chaining is disabled),
617             // because timers are not updated instruction-by-instruction, but in batches when `TranslationCPU.ExecuteInstructions` finishes
618             txPacketTimestamp.seconds = (uint)secTimer.Value;
619             txPacketTimestamp.nanos = (uint)nanoTimer.Value;
620 
621             if(txBufferDescriptorTimeStampMode.Value != TimestampingMode.Disabled)
622             {
623                 txDescriptorsQueue.CurrentDescriptor.Timestamp = txPacketTimestamp;
624             }
625             else
626             {
627                 rxDescriptorsQueue.CurrentDescriptor.HasValidTimestamp = false;
628             }
629         }
630 
EnsureArrayLength(byte[] bytesArray, int length)631         private void EnsureArrayLength(byte[] bytesArray, int length)
632         {
633             if(bytesArray.Length < length)
634             {
635                 Array.Resize(ref bytesArray, length);
636             }
637         }
638 
SendFrames()639         private void SendFrames()
640         {
641             lock(sync)
642             {
643                 var packetBytes = new List<byte>();
644                 bool? isCRCIncluded = null;
645 
646                 txDescriptorsQueue.CurrentDescriptor.Invalidate();
647                 while(!txDescriptorsQueue.CurrentDescriptor.IsUsed)
648                 {
649                     if(!isCRCIncluded.HasValue)
650                     {
651                         // this information is interperted only for the first buffer in a frame
652                         isCRCIncluded = txDescriptorsQueue.CurrentDescriptor.IsCRCIncluded;
653                     }
654 
655                     // fill packet with data from memory
656                     packetBytes.AddRange(txDescriptorsQueue.CurrentDescriptor.ReadBuffer());
657                     if(txDescriptorsQueue.CurrentDescriptor.IsLast)
658                     {
659                         SendSingleFrame(packetBytes, isCRCIncluded.Value);
660                         packetBytes.Clear();
661                         isCRCIncluded = null;
662                     }
663 
664                     txDescriptorsQueue.GoToNextDescriptor();
665                 }
666 
667                 transmitComplete.Value = true;
668                 usedBitRead.Value = true;
669 
670                 interruptManager.SetInterrupt(Interrupts.TransmitUsedBitRead);
671                 interruptManager.SetInterrupt(Interrupts.TransmitComplete);
672             }
673         }
674 
675         private uint phyDataRead;
676         private bool isTransmissionStarted;
677         private DmaBufferDescriptorsQueue<DmaTxBufferDescriptor> txDescriptorsQueue;
678         private DmaBufferDescriptorsQueue<DmaRxBufferDescriptor> rxDescriptorsQueue;
679 
680         private readonly IFlagRegisterField checksumGeneratorEnabled;
681         private readonly IFlagRegisterField extendedRxBufferDescriptorEnabled;
682         private readonly IFlagRegisterField extendedTxBufferDescriptorEnabled;
683         private readonly IEnumRegisterField<DMAAddressWidth> dmaAddressBusWith;
684         private readonly IFlagRegisterField transmitComplete;
685         private readonly IFlagRegisterField usedBitRead;
686         private readonly IFlagRegisterField receiveEnabled;
687         private readonly IFlagRegisterField ignoreRxFCS;
688         private readonly IFlagRegisterField bufferNotAvailable;
689         private readonly IFlagRegisterField frameReceived;
690         private readonly IFlagRegisterField removeFrameChecksum;
691         private readonly IValueRegisterField receiveBufferOffset;
692         private readonly IEnumRegisterField<TimestampingMode> rxBufferDescriptorTimeStampMode;
693         private readonly IEnumRegisterField<TimestampingMode> txBufferDescriptorTimeStampMode;
694         private readonly IValueRegisterField secTimer;
695 
696         private readonly IBusController sysbus;
697         private readonly InterruptManager<Interrupts> interruptManager;
698         private readonly DoubleWordRegisterCollection registers;
699         private readonly object sync;
700 
701         private readonly LimitTimer nanoTimer;
702 
703         private PTPTimestamp txPacketTimestamp;
704         private PTPTimestamp rxPacketTimestamp;
705 
706         private class DmaBufferDescriptorsQueue<T> where T : DmaBufferDescriptor
707         {
DmaBufferDescriptorsQueue(IBusController bus, uint baseAddress, Func<IBusController, uint, T> creator)708             public DmaBufferDescriptorsQueue(IBusController bus, uint baseAddress, Func<IBusController, uint, T> creator)
709             {
710                 this.bus = bus;
711                 this.creator = creator;
712                 this.baseAddress = baseAddress;
713                 descriptors = new List<T>();
714 
715                 GoToNextDescriptor();
716             }
717 
GoToNextDescriptor()718             public void GoToNextDescriptor()
719             {
720                 if(descriptors.Count == 0)
721                 {
722                     // this is the first descriptor - read it from baseAddress
723                     descriptors.Add(creator(bus, baseAddress));
724                     currentDescriptorIndex = 0;
725                 }
726                 else
727                 {
728                     CurrentDescriptor.Update();
729 
730                     if(CurrentDescriptor.Wrap)
731                     {
732                         currentDescriptorIndex = 0;
733                     }
734                     else
735                     {
736                         if(currentDescriptorIndex == descriptors.Count - 1)
737                         {
738                             // we need to generate new descriptor
739                             descriptors.Add(creator(bus, CurrentDescriptor.LowerDescriptorAddress + CurrentDescriptor.SizeInBytes));
740                         }
741                         currentDescriptorIndex++;
742                     }
743                 }
744 
745                 CurrentDescriptor.Invalidate();
746             }
747 
GoToBaseAddress()748             public void GoToBaseAddress()
749             {
750                 currentDescriptorIndex = 0;
751                 CurrentDescriptor.Invalidate();
752             }
753 
754             public T CurrentDescriptor => descriptors[currentDescriptorIndex];
755 
756             private int currentDescriptorIndex;
757 
758             private readonly List<T> descriptors;
759             private readonly uint baseAddress;
760             private readonly IBusController bus;
761             private readonly Func<IBusController, uint, T> creator;
762         }
763 
764         private abstract class DmaBufferDescriptor
765         {
DmaBufferDescriptor(IBusController bus, uint address, DMAAddressWidth dmaAddressWidth, bool isExtendedModeEnabled)766             protected DmaBufferDescriptor(IBusController bus, uint address, DMAAddressWidth dmaAddressWidth, bool isExtendedModeEnabled)
767             {
768                 this.dmaAddressWidth = dmaAddressWidth;
769                 Bus = bus;
770                 LowerDescriptorAddress = address;
771                 IsExtendedModeEnabled = isExtendedModeEnabled;
772                 SizeInBytes = InitWords();
773             }
774 
Invalidate()775             public void Invalidate()
776             {
777                 var tempOffset = 0UL;
778                 for(var i = 0; i < words.Length; ++i)
779                 {
780                     words[i] = Bus.ReadDoubleWord(GetDescriptorAddress() + tempOffset);
781                     tempOffset += 4;
782                 }
783             }
784 
Update()785             public void Update()
786             {
787                 var tempOffset = 0UL;
788                 foreach(var word in words)
789                 {
790                     Bus.WriteDoubleWord(GetDescriptorAddress() + tempOffset, word);
791                     tempOffset += 4;
792                 }
793             }
794 
GetBufferAddress()795             public ulong GetBufferAddress()
796             {
797                 return dmaAddressWidth == DMAAddressWidth.Bit64 ? (((ulong)UpperBufferAddress << 32) | LowerBufferAddress) : LowerBufferAddress;
798             }
799 
800             public IBusController Bus { get; }
801             public uint SizeInBytes { get; }
802             public bool IsExtendedModeEnabled { get; }
803             public uint LowerDescriptorAddress { get; set; }
804             public uint UpperDescriptorAddress { get; set; }
805 
806             public uint UpperBufferAddress
807             {
808                 get { return BitHelper.GetMaskedValue(words[2], 0, 32); }
809                 set { BitHelper.SetMaskedValue(ref words[2], value, 0, 32); }
810             }
811 
812             public PTPTimestamp Timestamp
813             {
814                 get
815                 {
816                     var ptpTimestamp = new PTPTimestamp();
817                     if(!IsExtendedModeEnabled)
818                     {
819                         return ptpTimestamp;
820                     }
821                     ptpTimestamp.nanos = BitHelper.GetMaskedValue(words[4], 0, 30);
822                     ptpTimestamp.seconds = (BitHelper.GetMaskedValue(words[4], 30, 2) << 4) | BitHelper.GetMaskedValue(words[5], 0, 4);
823                     return ptpTimestamp;
824                 }
825                 set
826                 {
827                     if(IsExtendedModeEnabled)
828                     {
829                         BitHelper.SetMaskedValue(ref words[4], value.nanos, 0, 30);
830                         BitHelper.SetMaskedValue(ref words[4], value.seconds >> 4, 30, 2);
831                         BitHelper.SetMaskedValue(ref words[5], value.seconds & 0xF, 0, 4);
832                         HasValidTimestamp = true;
833                     }
834                 }
835             }
836 
837             public abstract bool Wrap { get; }
838             public abstract bool HasValidTimestamp { set; }
839             public abstract uint LowerBufferAddress { get; set; }
840 
841             protected uint[] words;
842 
InitWords()843             private uint InitWords()
844             {
845                 if(dmaAddressWidth == DMAAddressWidth.Bit64 && IsExtendedModeEnabled)
846                 {
847                     words = new uint[6];
848                 }
849                 else if((dmaAddressWidth == DMAAddressWidth.Bit32 && IsExtendedModeEnabled) || (dmaAddressWidth == DMAAddressWidth.Bit64 && !IsExtendedModeEnabled))
850                 {
851                     words = new uint[4];
852                 }
853                 else if(dmaAddressWidth == DMAAddressWidth.Bit32 && !IsExtendedModeEnabled)
854                 {
855                     words = new uint[2];
856                 }
857                 return (uint)words.Length * 4;
858             }
859 
GetDescriptorAddress()860             private ulong GetDescriptorAddress()
861             {
862                 return dmaAddressWidth == DMAAddressWidth.Bit64 ? (((ulong)UpperDescriptorAddress << 32) | LowerDescriptorAddress) : LowerDescriptorAddress;
863             }
864 
865             private readonly DMAAddressWidth dmaAddressWidth;
866         }
867 
868         /// RX buffer descriptor format:
869         /// * word 0:
870         ///     * 0: Ownership flag
871         ///     * 1: Wrap flag
872         ///     * 2: Address of beginning of buffer, or in extended buffer descriptor
873         ///          mode indicates a valid timestamp in the descriptor entry
874         ///     * In basic buffer descriptor mode:
875         ///     * 2-31: Address of the buffer [31:2]
876         ///     * In extended buffer descriptor mode:
877         ///     * 2: Valid timestamp flag
878         ///     * 3-31: Address of the buffer [31:3]
879         /// * word 1:
880         ///     * 0-12: Length of the received frame
881         ///     * 13: Bad FCS flag
882         ///     * 14: Start of frame flag
883         ///     * 15: End of frame flag
884         ///     * 16: Cannonical form indicator flag
885         ///     * 17-19: VLAN priority
886         ///     * 20: Priority tag detected flag
887         ///     * 21: VLAN tag detected flag
888         ///     * 22-23: Type ID match
889         ///     * 24: Type ID match meaning flag
890         ///     * 25-26: Specific address register match
891         ///     * 27: Specific address found flag
892         ///     * 28: External address match flag
893         ///     * 29: Unicast hash match flag
894         ///     * 30: Multicast hash match flag
895         ///     * 31: Broadcast address detected flag
896         /// * word 2 (64-bit addressing):
897         ///     * 0-31: Upper 32-bit address of the data buffer
898         /// * word 3 (64-bit addressing):
899         ///     * 0-31: Reserved
900         /// * word 2 (32-bit addressing) or word 4 (64-bit addressing):
901         ///     * 0-29: Timestamp nanosecods [29:0]
902         ///     * 30-31: Timestamp seconds [1:0]
903         /// * word 3 (32-bit addressing) or word 5 (64-bit addressing):
904         ///     * 0-3: Timestamp seconds [5:2]
905         ///     * 4-31: Reserved
906         private class DmaRxBufferDescriptor : DmaBufferDescriptor
907         {
DmaRxBufferDescriptor(IBusController bus, uint address, DMAAddressWidth addressWidth, bool extendedModeEnabled)908             public DmaRxBufferDescriptor(IBusController bus, uint address, DMAAddressWidth addressWidth, bool extendedModeEnabled) : base(bus, address, addressWidth, extendedModeEnabled)
909             {
910             }
911 
WriteBuffer(byte[] bytes, uint length, uint offset = 0)912             public bool WriteBuffer(byte[] bytes, uint length, uint offset = 0)
913             {
914                 if(Ownership || bytes.Length > MaximumBufferLength)
915                 {
916                     return false;
917                 }
918 
919                 Length = length;
920                 Bus.WriteBytes(bytes, GetBufferAddress() + offset, true);
921                 Ownership = true;
922 
923                 return true;
924             }
925 
926             public override uint LowerBufferAddress
927             {
928                 get
929                 {
930                     if(IsExtendedModeEnabled)
931                     {
932                         return BitHelper.GetMaskedValue(words[0], 3, 29);
933                     }
934                     return BitHelper.GetMaskedValue(words[0], 2, 30);
935                 }
936                 set
937                 {
938                     if(IsExtendedModeEnabled)
939                     {
940                         BitHelper.SetMaskedValue(ref words[0], value, 3, 29);
941                     }
942                     else
943                     {
944                         BitHelper.SetMaskedValue(ref words[0], value, 2, 30);
945                     }
946                 }
947             }
948 
949             public override bool Wrap => BitHelper.IsBitSet(words[0], 1);
950 
951             public override bool HasValidTimestamp
952             {
953                 set
954                 {
955                     if(IsExtendedModeEnabled)
956                     {
957                         BitHelper.SetBit(ref words[0], 2, value);
958                     }
959                 }
960             }
961 
962             public bool StartOfFrame { set { BitHelper.SetBit(ref words[1], 14, value); } }
963 
964             public bool EndOfFrame { set { BitHelper.SetBit(ref words[1], 15, value); } }
965 
966             public uint Length { set { BitHelper.SetMaskedValue(ref words[1], value, 0, 13); } }
967 
968             public bool Ownership
969             {
970                 get { return BitHelper.IsBitSet(words[0], 0); }
971                 set { BitHelper.SetBit(ref words[0], 0, value); }
972             }
973 
974             private const int MaximumBufferLength = (1 << 13) - 1;
975         }
976 
977         /// TX buffer descriptor format:
978         /// * word 0:
979         ///     * 0-31: Address of the buffer [31:0]
980         /// * word 1:
981         ///     * 0-13: Lenght of the buffer
982         ///     * 14: Reserved
983         ///     * 15: Last buffer flag
984         ///     * 16: CRC appended flag
985         ///     * 17-19: Reserved
986         ///     * 20-22: Transmit checksum errors
987         ///   * In basic buffer descriptor mode:
988         ///     * 23: Reserved
989         ///   * In extended buffer descriptor mode:
990         ///     * 23: Timestamp captured flag
991         ///     * 24-25: Reserved
992         ///     * 26: Late collision detected flag
993         ///     * 27: Transmit frame corruption flag
994         ///     * 28: Reserved
995         ///     * 29: Retry limit exceeded
996         ///     * 30: Wrap flag
997         ///     * 31: Used flag
998         /// * word 2 (64-bit addressing):
999         ///     * 0-31: Address of the buffer [63:32]
1000         /// * word 3 (64-bit addressing):
1001         ///     * 0-31: Reserved
1002         /// * word 2 (32-bit addressing) or word 4 (64-bit addressing):
1003         ///     * 0-29: Timestamp nanosecods [29:0]
1004         ///     * 30-31: Timestamp seconds [1:0]
1005         /// * word 3 (32-bit addressing) or word 5 (64-bit addressing):
1006         ///     * 0-3: Timestamp seconds [5:2]
1007         ///     * 4-31: Reserved
1008         private class DmaTxBufferDescriptor : DmaBufferDescriptor
1009         {
DmaTxBufferDescriptor(IBusController bus, uint address, DMAAddressWidth addressWidth, bool extendedModeEnabled)1010             public DmaTxBufferDescriptor(IBusController bus, uint address, DMAAddressWidth addressWidth, bool extendedModeEnabled) : base(bus, address, addressWidth, extendedModeEnabled)
1011             {
1012             }
1013 
ReadBuffer()1014             public byte[] ReadBuffer()
1015             {
1016                 var result = Bus.ReadBytes(GetBufferAddress(), Length, true);
1017                 IsUsed = true;
1018                 return result;
1019             }
1020 
1021             public ushort Length => (ushort)BitHelper.GetMaskedValue(words[1], 0, 14);
1022 
1023             public bool IsLast => BitHelper.IsBitSet(words[1], 15);
1024 
1025             public bool IsCRCIncluded => BitHelper.IsBitSet(words[1], 16);
1026 
1027             public bool IsUsed
1028             {
1029                 get { return BitHelper.IsBitSet(words[1], 31); }
1030                 set { BitHelper.SetBit(ref words[1], 31, value); }
1031             }
1032 
1033             public override bool HasValidTimestamp
1034             {
1035                 set
1036                 {
1037                     if(IsExtendedModeEnabled)
1038                     {
1039                         BitHelper.SetBit(ref words[1], 23, value);
1040                     }
1041                 }
1042             }
1043 
1044             public override uint LowerBufferAddress
1045             {
1046                 get
1047                 {
1048                     return words[0];
1049                 }
1050                 set
1051                 {
1052                     words[0] = value;
1053                 }
1054             }
1055 
1056             public override bool Wrap => BitHelper.IsBitSet(words[1], 30);
1057         }
1058 
1059         private const uint NanosPerSecond = 1000000000;
1060 
1061         private struct PTPTimestamp
1062         {
1063             public uint seconds;
1064             public uint nanos;
1065         }
1066 
1067         private enum TimestampingMode
1068         {
1069             Disabled = 0,
1070             PTPEventFrames = 1,
1071             PTPAllFrames = 2,
1072             AllFrames = 3
1073         }
1074 
1075         private enum DMAAddressWidth
1076         {
1077             Bit32 = 0,
1078             Bit64 = 1,
1079         }
1080 
1081         private enum Interrupts
1082         {
1083             ManagementDone = 0,
1084             ReceiveComplete = 1,
1085             ReceiveUsedBitRead = 2,
1086             TransmitUsedBitRead = 3,
1087             TransmitComplete = 7
1088         }
1089 
1090         private enum PhyOperation
1091         {
1092             Write = 0x1,
1093             Read = 0x2
1094         }
1095 
1096         private enum Registers : long
1097         {
1098             NetworkControl = 0x0,
1099             NetworkConfiguration = 0x4,
1100             NetworkStatus = 0x8,
1101             UserInputOutput = 0xC,
1102             DmaConfiguration = 0x10,
1103             TransmitStatus = 0x14,
1104             ReceiveBufferQueueBaseAddress = 0x18,
1105             TransmitBufferQueueBaseAddress = 0x1C,
1106             ReceiveStatus = 0x20,
1107             InterruptStatus = 0x24,
1108             InterruptEnable = 0x28,
1109             InterruptDisable = 0x2C,
1110             InterruptMaskStatus = 0x30,
1111             PhyMaintenance = 0x34,
1112             ReceivedPauseQuantum = 0x38,
1113             TransmitPauseQuantum = 0x3C,
1114             // gap intended
1115             HashRegisterBottom = 0x80,
1116             HashRegisterTop = 0x84,
1117             SpecificAddress1Bottom = 0x88,
1118             SpecificAddress1Top = 0x8C,
1119             SpecificAddress2Bottom = 0x90,
1120             SpecificAddress2Top = 0x94,
1121             SpecificAddress3Top = 0x98,
1122             SpecificAddress3Bottom = 0x9C,
1123             SpecificAddress4Top = 0xA0,
1124             SpecificAddress4Bottom = 0xA4,
1125             TypeIDMatch1 = 0xA8,
1126             TypeIDMatch2 = 0xAC,
1127             TypeIDMatch3 = 0xB0,
1128             TypeIDMatch4 = 0xB4,
1129             WakeOnLan = 0xB8,
1130             IpgStretch = 0xBC,
1131             StackedVlan = 0xC0,
1132             TransmitPfcPause = 0xC4,
1133             SpecificAddressMask1Bottom = 0xC8,
1134             SpecificAddressMask1Top = 0xCC,
1135             // gap intended
1136             PtpEventFrameTransmittedSecondsHigh = 0x0E8,
1137             PtpEventFrameReceivedSecondsHigh = 0x0EC,
1138             PtpPeerEventFrameTransmittedSecondsHigh = 0x0F0,
1139             PtpPeerEventFrameReceivedSecondsHigh = 0x0F4,
1140             ModuleId = 0xFC,
1141             OctetsTransmittedLow = 0x100,
1142             OctetsTransmittedHigh = 0x104,
1143             FramesTransmitted = 0x108,
1144             BroadcastFramesTx = 0x10C,
1145             MulticastFramesTx = 0x110,
1146             PauseFramesTx = 0x114,
1147             FramesTx64b = 0x118,
1148             FramesTx127b65b = 0x11C,
1149             FramesTx255b128b = 0x120,
1150             FramesTx511b256b = 0x124,
1151             FramesTx1023b512b = 0x128,
1152             FramesTx1518b1024b = 0x12C,
1153             // gap intended
1154             TransmitUnderRuns = 0x134,
1155             SingleCollisionFrames = 0x138,
1156             MultipleCollisionFrames = 0x13C,
1157             ExcessiveCollisions = 0x140,
1158             LateCollisions = 0x144,
1159             DeferredTransmissionFrames = 0x148,
1160             CarrierSenseErrors = 0x14C,
1161             OctetsReceivedLow = 0x150,
1162             OctetsReceivedHigh = 0x154,
1163             FramesReceived = 0x158,
1164             BroadcastFramesRx = 0x15C,
1165             MulticastFramesRx = 0x160,
1166             PauseFramesRx = 0x164,
1167             FramesRx64b = 0x168,
1168             FramesRx127b65b = 0x16C,
1169             FramesRx255b128b = 0x170,
1170             FramesRx511b256b = 0x174,
1171             FramesRx1023b512b = 0x178,
1172             FramesRx1518b1024b = 0x17C,
1173             UndersizeFramesReceived = 0x184,
1174             OversizeFramesReceived = 0x188,
1175             JabbersReceived = 0x18C,
1176             FrameCheckSequenceErrors = 0x190,
1177             LengthFieldFrameErrors = 0x194,
1178             ReceiveSymbolErrors = 0x198,
1179             AlignmentErrors = 0x19C,
1180             ReceiveResourceErrors = 0x1A0,
1181             ReceiveOverrunErrors = 0x1A4,
1182             IpHeaderChecksumErrors = 0x1A8,
1183             TcpCHecksumErrors = 0x1AC,
1184             UdpChecksumErrors = 0x1B0,
1185             // gap intended
1186             Timer1588IncrementSubnanoseconds = 0x1BC,
1187             Timer1588SecondsHigh = 0x1C0,
1188             // gap intended
1189             Timer1588SyncStrobeSeconds = 0x1C8,
1190             Timer1588SyncStrobeNanoseconds = 0x1CC,
1191             Timer1588SecondsLow = 0x1D0,
1192             Timer1588Nanoseconds = 0x1D4,
1193             Timer1588Adjust = 0x1D8,
1194             Timer1588Increment = 0x1DC,
1195             PtpEventFrameTransmittedSeconds = 0x1E0,
1196             PtpEventFrameTransmittedNanoseconds = 0x1E4,
1197             PtpEventFrameReceivedSeconds = 0x1E8,
1198             PtpEventFrameReceivedNanoseconds = 0x1EC,
1199             PtpPeerEventFrameTransmittedSeconds = 0x1F0,
1200             PtpPeerEventFrameTransmittedNanoseconds = 0x1F4,
1201             PtpPeerEventFrameReceivedSeconds = 0x1F8,
1202             PtpPeerEventFrameReceivedNanoseconds = 0x1FC,
1203             // gap intended
1204             DesignConfiguration1 = 0x280, // this register's implementation is based on linux driver as Zynq-7000 documentation does not mention it
1205             DesignConfiguration2 = 0x284,
1206             DesignConfiguration3 = 0x288,
1207             DesignConfiguration4 = 0x28C,
1208             DesignConfiguration5 = 0x290,
1209             // gap intended
1210             InterruptStatusPriorityQueue1 = 0x400,
1211             InterruptStatusPriorityQueue2 = 0x404,
1212             // gap intended
1213             TransmitBufferQueueBaseAddressPriorityQueue1 = 0x440,
1214             TransmitBufferQueueBaseAddressPriorityQueue2 = 0x444,
1215             // gap intended
1216             ReceiveBufferQueueBaseAddressPriorityQueue1 = 0x480,
1217             ReceiveBufferQueueBaseAddressPriorityQueue2 = 0x484,
1218             // gap intended
1219             ReceiveBufferSizePriorityQueue1 = 0x4A0,
1220             ReceiveBufferSizePriorityQueue2 = 0x4A4,
1221             // gap intended
1222             CreditBasedShapingControl = 0x4BC,
1223             CreditBasedShapingIdleSlopeQueueA = 0x4C0,
1224             CreditBasedShapingIdleSlopeQueueB = 0x4C4,
1225             TransmitBufferQueueBaseAddressUpper = 0x4C8,
1226             TransmitBufferDescriptorControl = 0x4CC,
1227             ReceiveBufferDescriptorControl = 0x4D0,
1228             ReceiveBufferQueueBaseAddressUpper = 0x4D4,
1229             // gap intended
1230             ScreeningType1PriorityQueues0 = 0x500,
1231             ScreeningType1PriorityQueues1 = 0x504,
1232             ScreeningType1PriorityQueues2 = 0x508,
1233             ScreeningType1PriorityQueues3 = 0x50C,
1234             // gap intended
1235             ScreeningType2PriorityQueues0 = 0x540,
1236             ScreeningType2PriorityQueues1 = 0x544,
1237             ScreeningType2PriorityQueues2 = 0x548,
1238             ScreeningType2PriorityQueues3 = 0x54C,
1239             ScreeningType2PriorityQueues4 = 0x550,
1240             ScreeningType2PriorityQueues5 = 0x554,
1241             ScreeningType2PriorityQueues6 = 0x55C,
1242             ScreeningType2PriorityQueues7 = 0x560,
1243             // gap intended
1244             InterruptEnablePriorityQueue1 = 0x600,
1245             InterruptEnablePriorityQueue2 = 0x604,
1246             // gap intended
1247             InterruptDisablePriorityQueue1 = 0x620,
1248             InterruptDisablePriorityQueue2 = 0x624,
1249             // gap intended
1250             InterruptMaskPriorityQueue1 = 0x640,
1251             InterruptMaskPriorityQueue2 = 0x644,
1252             // gap intended
1253             ScreeningType2Ethertype0 = 0x6E0,
1254             ScreeningType2Ethertype1 = 0x6E4,
1255             ScreeningType2Ethertype2 = 0x6E8,
1256             ScreeningType2Ethertype3 = 0x6EC,
1257             // gap intended
1258             ScreeningType2Compare0Word0 = 0x700,
1259             ScreeningType2Compare0Word1 = 0x704,
1260             ScreeningType2Compare1Word0 = 0x708,
1261             ScreeningType2Compare1Word1 = 0x70C,
1262             ScreeningType2Compare2Word0 = 0x710,
1263             ScreeningType2Compare2Word1 = 0x714,
1264             ScreeningType2Compare3Word0 = 0x718,
1265             ScreeningType2Compare3Word1 = 0x71C,
1266             ScreeningType2Compare4Word0 = 0x720,
1267             ScreeningType2Compare4Word1 = 0x724,
1268             ScreeningType2Compare5Word0 = 0x728,
1269             ScreeningType2Compare5Word1 = 0x72C,
1270             ScreeningType2Compare6Word0 = 0x730,
1271             ScreeningType2Compare6Word1 = 0x734,
1272             ScreeningType2Compare7Word0 = 0x738,
1273             ScreeningType2Compare7Word1 = 0x73C,
1274             ScreeningType2Compare8Word0 = 0x740,
1275             ScreeningType2Compare8Word1 = 0x744,
1276             ScreeningType2Compare9Word0 = 0x748,
1277             ScreeningType2Compare9Word1 = 0x74C,
1278             ScreeningType2Compare10Word0 = 0x750,
1279             ScreeningType2Compare10Word1 = 0x754,
1280             ScreeningType2Compare11Word0 = 0x758,
1281             ScreeningType2Compare11Word1 = 0x75C,
1282             ScreeningType2Compare12Word0 = 0x760,
1283             ScreeningType2Compare12Word1 = 0x764,
1284             ScreeningType2Compare13Word0 = 0x768,
1285             ScreeningType2Compare13Word1 = 0x76C,
1286             ScreeningType2Compare14Word0 = 0x770,
1287             ScreeningType2Compare14Word1 = 0x774,
1288             ScreeningType2Compare15Word0 = 0x778,
1289             ScreeningType2Compare15Word1 = 0x77C,
1290             ScreeningType2Compare16Word0 = 0x780,
1291             ScreeningType2Compare16Word1 = 0x784,
1292             ScreeningType2Compare17Word0 = 0x788,
1293             ScreeningType2Compare17Word1 = 0x78C,
1294             ScreeningType2Compare18Word0 = 0x790,
1295             ScreeningType2Compare18Word1 = 0x794,
1296             ScreeningType2Compare19Word0 = 0x798,
1297             ScreeningType2Compare19Word1 = 0x79C,
1298             ScreeningType2Compare20Word0 = 0x7A0,
1299             ScreeningType2Compare20Word1 = 0x7A4,
1300             ScreeningType2Compare21Word0 = 0x7A8,
1301             ScreeningType2Compare21Word1 = 0x7AC,
1302             ScreeningType2Compare22Word0 = 0x7B0,
1303             ScreeningType2Compare22Word1 = 0x7B4,
1304             ScreeningType2Compare23Word0 = 0x7B0,
1305             ScreeningType2Compare23Word1 = 0x7B4
1306         }
1307     }
1308 }
1309