The UART backend writes [read identifier, num_reads, addr] for
every read request.
Etherbone packets are able to include multiple read requests.
Therefore, it is beneficial to merge sequential read requests to reduce writes
(and possible latency overhead).
Benchmark:
A typical litescope fetch script with the following
signals [ddrphy.dfi,cpu.ibus.cyc,cpu.ibus.stb] results in 1 read for the
data_valid register and 24 sequential reads for the scope data per timestamp.
Fetching data for a capture length of 512 over a 921600 baud UART (arty board)
took:
205s (current master branch)
18s (with this merge function)
The proposed merger only merges read requests from one etherbone packet
at a time and doesn't change the read order.
from litex.tools.remote.etherbone import EtherbonePacket, EtherboneRecord, EtherboneWrites
from litex.tools.remote.etherbone import EtherboneIPC
from litex.tools.remote.etherbone import EtherbonePacket, EtherboneRecord, EtherboneWrites
from litex.tools.remote.etherbone import EtherboneIPC
+# Merges sequential reads:
+# input: list of addresses
+# output: list of (start_addr, read_size)
+# example: [0x0, 0x4, 0x10, 0x14] -> [(0x0,2), (0x10,2)]
+def _read_merger(addrs):
+ addr_start = addrs[0]
+ num_reads = 1
+ for addr in addrs[1:]:
+ if addr_start+4*num_reads != addr:
+ yield (addr_start, num_reads)
+ addr_start = addr
+ num_reads = 1
+ else:
+ num_reads += 1
+ yield (addr_start, num_reads)
+
class RemoteServer(EtherboneIPC):
def __init__(self, comm, bind_ip, bind_port=1234):
class RemoteServer(EtherboneIPC):
def __init__(self, comm, bind_ip, bind_port=1234):
# handle reads
if record.reads != None:
reads = []
# handle reads
if record.reads != None:
reads = []
- for addr in record.reads.get_addrs():
- reads.append(self.comm.read(addr))
+ if "CommUART" == self.comm.__class__.__name__:
+ for base_addr, num_reads in _read_merger(record.reads.get_addrs()):
+ reads += self.comm.read(base_addr, num_reads)
+ else:
+ for addr in record.reads.get_addrs():
+ reads.append(self.comm.read(addr))
record = EtherboneRecord()
record.writes = EtherboneWrites(datas=reads)
record = EtherboneRecord()
record.writes = EtherboneWrites(datas=reads)