From: Christian Klarhorst Date: Sun, 26 Jul 2020 11:19:32 +0000 (+0200) Subject: Merge sequential reads for the UART litex_server backend X-Git-Tag: 24jan2021_ls180~44^2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2034c563b0db9ab2b772b68463dd22043251c08b;p=litex.git Merge sequential reads for the UART litex_server backend 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. --- diff --git a/litex/tools/litex_server.py b/litex/tools/litex_server.py index b35bda5d..b7843c40 100755 --- a/litex/tools/litex_server.py +++ b/litex/tools/litex_server.py @@ -15,6 +15,22 @@ import threading 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): @@ -74,8 +90,12 @@ class RemoteServer(EtherboneIPC): # 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)