From d8aa75b7420ada8d9f03798f9171d4c5cfc733aa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Sep 2017 11:27:57 +0800 Subject: [PATCH] rtio/sed: add minimum buffer space reporting --- artiq/gateware/rtio/cri.py | 3 ++ artiq/gateware/rtio/sed/core.py | 7 +++-- artiq/gateware/rtio/sed/fifos.py | 49 +++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 7a4359ba7..5dad6b886 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -27,6 +27,9 @@ layout = [ # o_status bits: # <0:wait> <1:underflow> <2:sequence_error> ("o_status", 3, DIR_S_TO_M), + # targets may optionally report a pessimistic estimate of the number + # of outputs events that can be written without waiting. + ("o_buffer_space", 16, DIR_S_TO_M), ("i_data", 32, DIR_S_TO_M), ("i_timestamp", 64, DIR_S_TO_M), diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 3cea2cf85..d31161efc 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -13,7 +13,7 @@ __all__ = ["SED"] class SED(Module): def __init__(self, channels, glbl_fine_ts_width, mode, lane_count=8, fifo_depth=128, enable_spread=True, - quash_channels=[], interface=None): + quash_channels=[], interface=None, report_min_space=False): if mode == "sync": lane_dist_cdr = lambda x: x fifos_cdr = lambda x: x @@ -37,7 +37,7 @@ class SED(Module): interface=interface)) self.submodules.fifos = fifos_cdr( FIFOs(lane_count, fifo_depth, - layouts.fifo_payload(channels), mode)) + layouts.fifo_payload(channels), mode, report_min_space)) self.submodules.gates = gates_cdr( Gates(lane_count, seqn_width, layouts.fifo_payload(channels), @@ -52,6 +52,9 @@ class SED(Module): for o, i in zip(self.gates.output, self.output_driver.input): self.comb += i.eq(o) + if report_min_space: + self.comb += self.cri.o_buffer_space.eq(self.fifos.min_space) + @property def cri(self): return self.lane_dist.cri diff --git a/artiq/gateware/rtio/sed/fifos.py b/artiq/gateware/rtio/sed/fifos.py index da0f4fcfe..43b0079e8 100644 --- a/artiq/gateware/rtio/sed/fifos.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -1,3 +1,6 @@ +from operator import or_ +from functools import reduce + from migen import * from migen.genlib.fifo import * @@ -8,13 +11,18 @@ __all__ = ["FIFOs"] class FIFOs(Module): - def __init__(self, lane_count, fifo_depth, layout_payload, mode): + def __init__(self, lane_count, fifo_depth, layout_payload, mode, report_min_space=False): seqn_width = layouts.seqn_width(lane_count, fifo_depth) self.input = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] self.output = [Record(layouts.fifo_egress(seqn_width, layout_payload)) for _ in range(lane_count)] + if report_min_space: + self.min_space = Signal(max=fifo_depth+1) + + # # # + if mode == "sync": fifo_cls = SyncFIFOBuffered elif mode == "async": @@ -22,9 +30,11 @@ class FIFOs(Module): else: raise ValueError + fifos = [] for input, output in zip(self.input, self.output): fifo = fifo_cls(layout_len(layout_payload), fifo_depth) self.submodules += fifo + fifos.append(fifo) self.comb += [ fifo.din.eq(input.payload.raw_bits()), @@ -35,3 +45,40 @@ class FIFOs(Module): output.readable.eq(fifo.readable), fifo.re.eq(output.re) ] + + if report_min_space: + if mode != "sync": + raise NotImplementedError + + def compute_max(elts): + l = len(elts) + if l == 1: + return elts[0], 0 + else: + maximum1, latency1 = compute_max(elts[:l//2]) + maximum2, latency2 = compute_max(elts[l//2:]) + maximum = Signal(max(len(maximum1), len(maximum2))) + self.sync += [ + If(maximum1 > maximum2, + maximum.eq(maximum1) + ).Else( + maximum.eq(maximum2) + ) + ] + latency = max(latency1, latency2) + 1 + return maximum, latency + + max_level, latency = compute_max([fifo.level for fifo in fifos]) + max_level_valid = Signal() + max_level_valid_counter = Signal(max=latency) + self.sync += [ + If(reduce(or_, [fifo.we for fifo in fifos]), + max_level_valid.eq(0), + max_level_valid_counter.eq(latency - 1) + ).Elif(max_level_valid_counter == 0, + max_level_valid.eq(1) + ).Else( + max_level_valid_counter.eq(max_level_valid_counter - 1) + ) + ] + self.comb += If(max_level_valid, self.min_space.eq(fifo_depth - max_level))