3 # This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
4 # This file is Copyright (c) 2019 Sean Cross <sean@xobs.io>
5 # This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
15 from litex
.tools
.remote
.etherbone
import EtherbonePacket
, EtherboneRecord
, EtherboneWrites
16 from litex
.tools
.remote
.etherbone
import EtherboneIPC
18 def _read_merger(addrs
, max_length
=256):
19 """Sequential reads merger
21 Take a list of read addresses as input and merge the sequential reads in (base, length) tuples:
22 Example: [0x0, 0x4, 0x10, 0x14] input will return [(0x0,2), (0x10,2)].
24 This is useful for UARTBone/Etherbone where command/response roundtrip delay is responsible for
25 most of the access delay and allows minimizing number of commands by grouping them in UARTBone
31 if (addr
- (4*length
) != base
) or (length
== max_length
):
40 class RemoteServer(EtherboneIPC
):
41 def __init__(self
, comm
, bind_ip
, bind_port
=1234):
43 self
.bind_ip
= bind_ip
44 self
.bind_port
= bind_port
48 if hasattr(self
, "socket"):
50 self
.socket
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
51 if hasattr(socket
, "SO_REUSEADDR"):
52 self
.socket
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEADDR
, 1)
53 if hasattr(socket
, "SO_REUSEPORT"):
54 self
.socket
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEPORT
, 1)
55 self
.socket
.bind((self
.bind_ip
, self
.bind_port
))
56 print("tcp port: {:d}".format(self
.bind_port
))
62 if not hasattr(self
, "socket"):
67 def _serve_thread(self
):
69 client_socket
, addr
= self
.socket
.accept()
70 print("Connected with " + addr
[0] + ":" + str(addr
[1]))
74 packet
= self
.receive_packet(client_socket
)
79 packet
= EtherbonePacket(packet
)
82 record
= packet
.records
.pop()
92 if record
.writes
!= None:
93 self
.comm
.write(record
.writes
.base_addr
, record
.writes
.get_datas())
96 if record
.reads
!= None:
100 }.get(self
.comm
.__class
__.__name
__, 1)
102 for addr
, length
in _read_merger(record
.reads
.get_addrs(), max_length
=max_length
):
103 reads
+= self
.comm
.read(addr
, length
)
105 record
= EtherboneRecord()
106 record
.writes
= EtherboneWrites(datas
=reads
)
107 record
.wcount
= len(record
.writes
)
109 packet
= EtherbonePacket()
110 packet
.records
= [record
]
112 self
.send_packet(client_socket
, packet
)
119 client_socket
.close()
121 def start(self
, nthreads
):
122 for i
in range(nthreads
):
123 self
.serve_thread
= threading
.Thread(target
=self
._serve
_thread
)
124 self
.serve_thread
.setDaemon(True)
125 self
.serve_thread
.start()
129 print("LiteX remote server")
130 parser
= argparse
.ArgumentParser()
132 parser
.add_argument("--bind-ip", default
="localhost",
133 help="Host bind address")
134 parser
.add_argument("--bind-port", default
=1234,
135 help="Host bind port")
138 parser
.add_argument("--uart", action
="store_true",
139 help="Select UART interface")
140 parser
.add_argument("--uart-port", default
=None,
141 help="Set UART port")
142 parser
.add_argument("--uart-baudrate", default
=115200,
143 help="Set UART baudrate")
146 parser
.add_argument("--udp", action
="store_true",
147 help="Select UDP interface")
148 parser
.add_argument("--udp-ip", default
="192.168.1.50",
149 help="Set UDP remote IP address")
150 parser
.add_argument("--udp-port", default
=1234,
151 help="Set UDP remote port")
154 parser
.add_argument("--pcie", action
="store_true",
155 help="Select PCIe interface")
156 parser
.add_argument("--pcie-bar", default
=None,
160 parser
.add_argument("--usb", action
="store_true",
161 help="Select USB interface")
162 parser
.add_argument("--usb-vid", default
=None,
163 help="Set USB vendor ID")
164 parser
.add_argument("--usb-pid", default
=None,
165 help="Set USB product ID")
166 parser
.add_argument("--usb-max-retries", default
=10,
167 help="Number of times to try reconnecting to USB")
168 args
= parser
.parse_args()
172 from litex
.tools
.remote
.comm_uart
import CommUART
173 if args
.uart_port
is None:
174 print("Need to specify --uart-port, exiting.")
176 uart_port
= args
.uart_port
177 uart_baudrate
= int(float(args
.uart_baudrate
))
178 print("[CommUART] port: {} / baudrate: {} / ".format(uart_port
, uart_baudrate
), end
="")
179 comm
= CommUART(uart_port
, uart_baudrate
)
181 from litex
.tools
.remote
.comm_udp
import CommUDP
183 udp_port
= int(args
.udp_port
)
184 print("[CommUDP] ip: {} / port: {} / ".format(udp_ip
, udp_port
), end
="")
185 comm
= CommUDP(udp_ip
, udp_port
)
187 from litex
.tools
.remote
.comm_pcie
import CommPCIe
188 pcie_bar
= args
.pcie_bar
189 if args
.pcie_bar
is None:
190 print("Need to speficy --pcie-bar, exiting.")
192 print("[CommPCIe] bar: {} / ".format(args
.pcie_bar
), end
="")
193 comm
= CommPCIe(args
.pcie_bar
)
195 from litex
.tools
.remote
.comm_usb
import CommUSB
196 if args
.usb_pid
is None and args
.usb_vid
is None:
197 print("Need to speficy --usb-vid or --usb-pid, exiting.")
199 print("[CommUSB] vid: {} / pid: {} / ".format(args
.usb_vid
, args
.usb_pid
), end
="")
202 pid
= int(pid
, base
=0)
205 vid
= int(vid
, base
=0)
206 comm
= CommUSB(vid
=vid
, pid
=pid
, max_retries
=args
.usb_max_retries
)
211 server
= RemoteServer(comm
, args
.bind_ip
, int(args
.bind_port
))
216 while True: time
.sleep(100)
217 except KeyboardInterrupt:
220 if __name__
== "__main__":