Fakernet tested with a Digilent Arty A7-35 board (100 Mbps)

Page content

Setup

Load the gateware (while the FPGA vendor tools can be used to load the FPGA gateware, the author really enjoys the speed and simplicity of openFPGALoader):
openFPGALoader -b arty boards/Arty_A7-35/a35_fnet/a35_fnet.bit
To write the gateware to flash storage (used after reset / powercycling), add the flag -f. If openFPGALoader is just locally installed, the path to the SPI writing gateware is also needed:
OPENFPGALOADER_SOJ_DIR=<path-to-openFPGALoader>/spiOverJtag/ openFPGALoader -b arty boards/Arty_A7-35/a35_fnet/a35_fnet.bit -f

Debugging

The Arty A7 board LEDs show some basic operation of Fakernet:

LD7 LD6 LD5 LD4
Green GPS PPS
(only useful with
Pmod GPS).
GPS UART RX
(only useful with
Pmod GPS).
Incoming packet count
(low two bits).
LD3 LD2 LD1 LD0
Red Output ARP/ICMP/NTP. Good NTP in. Good ICMP in
(ping).
Good ARP in.
Green Output TCP. Good TCP in. Output UDP
(register access).
Good UDP in
(register access).
Blue GPS PPS
(only useful with
Pmod GPS).
Output of generated
RARP/BOOTP/
NTP-query.
Good RARP in. Good BOOTP in.

With 'good' is meant an incoming packet which passes all checks, and is intended for us, i.e. has the MAC and/or IP address of the Fakernet instance. The incoming packet count registers all packet starts from the PHY, i.e. regardless of destination or content.

The Arty A7 onboard USB-UART (serial) connection also emits single characters to mark the occurrence of some events which can be useful for debugging:

The UART interface is available on the second port of the onboard USB-UART interface, i.e. typically accessible via /dev/ttyUSB1 on the PC (when no other USB serial devices are attached). (The first is used to load gatewares.) A good program for connecting is kermit (often found as packet ckermit).

kermit
C-Kermit>set line /dev/ttyUSB1
C-Kermit>set carrier-watch off
C-Kermit>set flow-control none
C-Kermit>set speed 921600
/dev/ttyUSB1, 921600 bps
C-Kermit>connect
_PP____PP____PP____PP____PP_

To use the serial information for debugging, it should be left running in a terminal while performing other tests that generate traffic. The P marks above would come when Fakernet issues RARP and BOOTP request packets to configure a dynamic IP address. After starting a process pinging the board, it may look like this:

_aAiA_PPiA_iA_iAiA_iA_PPiA_iAiA_iA_iA_iAPPiA_iA_iA_iAiA_PPiA

The a comes from the ARP query broadcast by the PC to find the MAC address for the given IP number. The following A is the Fakernet response. Each i is then an ICMP echo request packet, with a following A marking the response. (Note: the a and i will only be seen if the ARP and ICMP requests are for the correct IP address. Without an ARP response, the PC will not send any ICMP requests.)

Testing

By default Fakernet on the Arty board has a fixed IP address 192.168.1.192 (or .193, .194, or .195 set by SW0-SW1).

Ping (ICMP echo request and reply)

ping 192.168.1.192
PING 192.168.1.192 (192.168.1.192) 56(84) bytes of data.
64 bytes from 192.168.1.192: icmp_seq=1 ttl=63 time=0.134 ms
64 bytes from 192.168.1.192: icmp_seq=2 ttl=63 time=0.127 ms

TCP connection (the fnetctrl program is part of the Fakernet source distribution):

client/fnetctrl 192.168.1.192 --tcp
read: 59085454180352 (59085454.2 MB)  11788.1 kB/s [slow avg 11787.3 kB/s]
read: 127195601436672 (127195601.4 MB)  11785.0 kB/s [slow avg 11785.7 kB/s]

UDP debug counters:

client/fnetctrl 192.168.1.192 --stat
...
UDP: connected 00, active 00               Compiled: 2020-03-29 17:09:52 UTC
TCP: connected

Total counts:   25020628 (100.001 MHz +/- 0.062)
Slow ticks:       781894 (32) (1.28 us)

tcp_stat.base_seqno  0x96125884 = 2517784708 ;   11797440
tcp_stat.max_sent    0x    6824 =      26660
tcp_stat.filled      0x    1440 =       5184
tcp_stat.unsent      0x     4a0 =       1184
tcp_stat.unfilled    0x     bc0 =       3008
tcp_stat.window_sz   0x    fe00 =      65024
tcp_stat.rtt_trip    0x    5884 =      22660
tcp_astat.cur_off    0x     fa0 =       4000
tcp_stat.same_ack    0x       0 =          0
tcp_stat.rtt_est     0x     137 =        311 = 398.1 us

[ 0] idle_cnt                           543097957 ;   23981922
[26] slow_tick                          157647553 ;     781894
[27] timeout_tick                             151 ;          1
[58] in_words_div_32                       879305 ;       4591
     bytes                               56275520 ;     293824
[ 1] +-in_info.start_packet                877861 ;       4579
[ 3] | `-in_info.start_arp                     22 ;          0
[ 4] |   in_info.arp_our_ip                     0 ;          0
[ 8] |   in_info.good_arp                       0 ;          0
[ 2] `-in_info.mac_for_us                  877642 ;       4578
[ 5]   in_info.start_ipv4                  877644 ;       4578
[ 6]   in_info.ip_hdr_ok                   877716 ;       4578
[ 7]   in_info.ip_for_us                   877642 ;       4578
[ 9]   +-in_info.start_icmp                     0 ;          0
[12]   | in_info.good_icmp                      0 ;          0
[10]   +-in_info.start_udp                     93 ;          1
[15]   | in_info.udp_arm                        1 ;          0
[16]   | in_info.udp_badactivearm               0 ;          0
[17]   | in_info.udp_reset                      1 ;          0
[18]   | in_info.udp_badreset                   0 ;          0
[19]   | in_info.udp_disconnect                 1 ;          0
[20]   | in_info.udp_baddisconnect              0 ;          0
[21]   | in_info.udp_regaccess                  1 ;          0
[22]   | +-in_info.udp_ra_otherip               1 ;          0
[23]   |   +-in_info.udp_ra_seqplus1            1 ;          0
[24]   |   +-in_info.udp_ra_repeat              0 ;          0
[25]   |   `-in_info.udp_ra_busy                0 ;          0
[60]   | in_info.udp_regaccess_idp             89 ;          1
[61]   | `-in_info.udp_ra_idp_busy              0 ;          0
[13]   | in_info.good_udp                      93 ;          1
[11]   `-in_info.start_tcp                 877549 ;       4577
[14]     in_info.good_tcp                  877542 ;       4577
[59] out_words_div_32                    36713731 ;     192620
     bytes                             2349678784 ;   12327680
[44] out_info.packets                     1746053 ;       9131
[33] +-out_info.arp_icmp                        3 ;          0
[62] +-out_info.udp_idp                        88 ;          1
[34] +-out_info.udp[0]                          1 ;          0
[35] +-out_info.udp[1]                          0 ;          0
[36] +-out_info.udp[2]                          0 ;          0
[37] +-out_info.udp[3]                          0 ;          0
[43] +-out_info.tcp                       1745961 ;       9130
[55] tcp_state.got_syn                          1 ;          0
[54] tcp_state.connected                        1 ;          0
[49] tcp_state.got_ack                     877539 ;       4577
[51] +-tcp_state.same_ack                      26 ;          0
[52]   +-tcp_state.twice_same_ack               0 ;          0
[48] tcp_state.did_repeat                      25 ;          0
[53] tcp_state.abort_repeat                     0 ;          0
[57] tcp_state.did_keepalive                    0 ;          0
[47] +-tcp_state.start_meas_rtt            437369 ;       2285
[50]   +-tcp_state.got_meas_rtt            437345 ;       2285
[56]     +-tcp_state.new_rtt_est            27335 ;        143

UDP requests (100 register accesses / packet):

client/fnetctrl 192.168.1.192 --udp-flood=100
packets: 0, incr: 0 (0/s ; inf us/pkt) 0.00 MB/s, (to: 0, mf: 0, to_us: 36)
packets: 38189, incr: 38189 (4022/s ; 248.6 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 794)
packets: 78375, incr: 40186 (4019/s ; 248.8 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 874)
packets: 118619, incr: 40244 (4024/s ; 248.5 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 874)
packets: 158932, incr: 40313 (4031/s ; 248.1 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 838)
packets: 199258, incr: 40326 (4033/s ; 248.0 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 820)
packets: 239573, incr: 40315 (4032/s ; 248.0 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 820)
packets: 279899, incr: 40326 (4033/s ; 248.0 us/pkt) 1.61 MB/s, (to: 0, mf: 0, to_us: 865)
packets: 320314, incr: 40415 (4042/s ; 247.4 us/pkt) 1.62 MB/s, (to: 0, mf: 0, to_us: 839)

Generate TCP data with test pattern, verify on PC:

client/fnetctrl 192.168.1.192 --tcp-lcl-datagen=1
client/fnetctrl 192.168.1.192 --tcp-lcl-data-chance=100000000
client/fnetctrl 192.168.1.192 --tcp-lcl-data-valmask=8191
client/fnetctrl 192.168.1.192 --tcp=local

(or for simpler copy-paste:)

FNETIP=192.168.1.192 ; \
client/fnetctrl $FNETIP --tcp-lcl-datagen=1 ; \
client/fnetctrl $FNETIP --tcp-lcl-data-chance=100000000 ; \
client/fnetctrl $FNETIP --tcp-lcl-data-valmask=8191 ; \
client/fnetctrl $FNETIP --tcp=local

Read and decode some MDIO information:

client/fnetctrl 192.168.1.192 --mdio=1
PHY:          OUI 08:00:17  v/model: 09 rev: 0
autoneg:      on    100baseT/F
ability:      100baseT/F 100baseT/H 10baseT/F 10baseT/H
advertise:    100baseT/F 100baseT/H 10baseT/F 10baseT/H
lp-advertise: 100baseT/F 100baseT/H 10baseT/F 10baseT/H

Only advertise 10baseT, and run TCP test:
(Note: it can take half a minute to complete auto-negotiation.)

client/fnetctrl 192.168.1.192 --mdio=1,adv10
client/fnetctrl 192.168.1.192 --mdio=1,autoneg_restart
autoneg:      on    10baseT/F
client/fnetctrl 192.168.1.192 --tcp
read: 10497600 (10.5 MB)  1184.8 kB/s [slow avg 1055.0 kB/s] mark:ffffffff

Disable auto-negotiation and disable duplex, and run TCP test:

client/fnetctrl 192.168.1.192 --mdio=1,autoneg_off
client/fnetctrl 192.168.1.192 --mdio=1,-fixduplex
autoneg:      off   100baseT/H
client/fnetctrl 192.168.1.192 --tcp
read: 55731040 (55.7 MB)  9286.8 kB/s [slow avg 7208.4 kB/s] mark:ffffffff

Advertise all modes, enable and restart auto-negotiation, and run TCP test:

client/fnetctrl 192.168.1.192 --mdio=1,adv10/100
client/fnetctrl 192.168.1.192 --mdio=1,autoneg_restart
autoneg:      on    100baseT/F
client/fnetctrl 192.168.1.192 --tcp
read: 106576256 (106.6 MB)  11857.1 kB/s [slow avg 10602.7 kB/s] mark:ffffffff

IP and MAC address

By default Fakernet has a fixed IP address configured in the gateware. For the Arty board demo, this is 192.168.1.192 (or .193, .194, or .195 set by SW0-SW1).

Fakernet can also obtain a dynamic IP address by RARP, DHCP (or BOOTP). (BOOTP is normally disabled..)

The Arty A7 board does not have any way of retrieving the MAC address assigned by the manufacturer and printed on a label on the RJ45 8P8C connector. Therefore, the Arty A7 demo of Fakernet uses the DNA port of the Artix 7 FPGA. The DNA identifier is however not an EUI-48, and it is also not necessarily unique (may be same on 32 devices), so using it as a MAC address, which must be unique in a broadcast-domain, is at best a hack! The MAC address is taken as:

47..42 41..40 39..4 3..2 0..1
DNA bits 41..36, Fixed 10
(locally administered and unicast),
DNA bits 35..0, 00, SW1, SW0.

SPI flash text config

Some settings can be stored as text block in SPI flash, at an address offset beyond the gateware bitstream. The configuration options are parsed by the gateware at startup.

An easy way to write the settings is to create a file with the desired content an write to flash storage using openFPGALoader:

openFPGALoader -b arty -o 0x3c0000 my_arty_config.txt

If the gateware is also stored in flash, it does not need to be updated. The FPGA is restarted by openFPGALoader after the write and the gateware stored in flash is automatically loaded.

To read the configuration:

openFPGALoader -b arty -o 0x3c0000 --dump-flash --file-size 0x400 tmp_read_config.txt
cat tmp_read_config.txt | sed -e "s/\(\xff\|\x00\)/\r/g"

Available configuration options:

fixed_ip = aaa.bbb.ccc.ddd    # Fixed IP address (switch-configured address disabled).
mac      = aa:bb:cc:dd:ee:ff  # MAC address (DNA-based hack not used).

Other functions

NTP server with a Arty A7-35 board and GPS.

0.5 ns signal sampler with a Arty A7-35 board.

1 Gbps operation with a ALINX AX7101 board.


Comments? f96hajo@chalmers.se

Last modified: Thu Jun 12 18:30:53 CEST 2021