Ejemplo n.º 1
0
    def __init__(self):

        self.busy = Signal()
        self.sink = Sink(CMD_REC)
        self.source = Source([('d',8), ('last',1)])

        sm = FSM(reset_state="IDLE")
        self.submodules += sm

        self.comb += [
            self.source.stb.eq(0),
            self.source.payload.last.eq(0)
            ]


        ssum = Signal(8)

        token_next = Record(CMD_REC)
        token = Record(CMD_REC)
        self.comb += token_next.eq(token)
        self.sync += token.eq(token_next)

        sm.act("IDLE",
                If(self.sink.stb,
                    self.sink.ack.eq(1),
                    token_next.eq(self.sink.payload),
                    NextState('c0')))

        _outs = [
            0x55,
            Cat(token.a[8:14], 0, token.wr),
            token.a[0:8],
            token.d,
            ssum
            ]

        s = _outs[0]
        for i in _outs[1:-1]:
            s = s + i
        self.sync += ssum.eq(s)


        for c, v in enumerate(_outs):
            _last = 1 if c == len(_outs) - 1 else 0
            _next = "IDLE" if _last else "c%d" % (c + 1)
            sm.act("c%d" % c,
                    self.source.stb.eq(1),
                    self.source.payload.d.eq(v),
                    self.source.payload.last.eq(_last),
                    If(self.source.ack,
                        NextState(_next)
                        ))
Ejemplo n.º 2
0
    def __init__(self):

        self.busy = Signal()
        self.sink = Sink(CMD_REC)
        self.source = Source([('d',8), ('last',1)])

        sm = FSM(reset_state="IDLE")
        self.submodules += sm

        self.comb += [
            self.source.stb.eq(0),
            self.source.payload.last.eq(0)
            ]


        ssum = Signal(8)

        token_next = Record(CMD_REC)
        token = Record(CMD_REC)
        self.comb += token_next.eq(token)
        self.sync += token.eq(token_next)

        sm.act("IDLE",
                If(self.sink.stb,
                    self.sink.ack.eq(1),
                    token_next.eq(self.sink.payload),
                    NextState('c0')))

        _outs = [
            0x55,
            Cat(token.a[8:14], 0, token.wr),
            token.a[0:8],
            token.d,
            ssum
            ]

        s = _outs[0]
        for i in _outs[1:-1]:
            s = s + i
        self.sync += ssum.eq(s)


        for c, v in enumerate(_outs):
            _last = 1 if c == len(_outs) - 1 else 0
            _next = "IDLE" if _last else "c%d" % (c + 1)
            sm.act("c%d" % c,
                    self.source.stb.eq(1),
                    self.source.payload.d.eq(v),
                    self.source.payload.last.eq(_last),
                    If(self.source.ack,
                        NextState(_next)
                        ))
Ejemplo n.º 3
0
Archivo: core.py Proyecto: cr1901/artiq
class _InputManager(Module):
    def __init__(self, interface, counter, fifo_depth):
        data_width = rtlink.get_data_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if interface.timestamped:
            ev_layout.append(("timestamp", counter.width + fine_ts_width))
        self.ev = Record(ev_layout)

        self.readable = Signal()
        self.re = Signal()
        
        self.overflow = Signal()  # pulsed

        # # #

        fifo = ClockDomainsRenamer({"read": "rsys", "write": "rio"})(
            AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # FIFO write
        if data_width:
            self.comb += fifo_in.data.eq(interface.data)
        if interface.timestamped:
            if fine_ts_width:
                full_ts = Cat(interface.fine_ts, counter.value_rio)
            else:
                full_ts = counter.value_rio
            self.comb += fifo_in.timestamp.eq(full_ts)
        self.comb += fifo.we.eq(interface.stb)

        # FIFO read
        self.comb += [
            self.ev.eq(fifo_out),
            self.readable.eq(fifo.readable),
            fifo.re.eq(self.re)
        ]

        overflow_sync = PulseSynchronizer("rio", "rsys")
        overflow_ack_sync = PulseSynchronizer("rsys", "rio")
        self.submodules += overflow_sync, overflow_ack_sync
        overflow_blind = Signal()
        self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable & ~overflow_blind)
        self.sync.rio += [
            If(fifo.we & ~fifo.writable, overflow_blind.eq(1)),
            If(overflow_ack_sync.o, overflow_blind.eq(0))
        ]
        self.comb += [
            overflow_ack_sync.i.eq(overflow_sync.o),
            self.overflow.eq(overflow_sync.o)
        ]
Ejemplo n.º 4
0
    def __init__(self):
        self.sink = Sink(ULPI_DATA_D)
        self.source = Source(ULPI_DATA_D)

        self._ctl = CSRStorageEx(1)
        snapshot = self._ctl.re
        reset = self._ctl.storage[0]
        self._num_ovf = Perfcounter(snapshot, reset)
        self._num_total = Perfcounter(snapshot, reset)

        self.comb += If(self.sink.stb, self._num_total.inc())
        self.comb += If(self.source.stb & ~self.source.ack,
                        self._num_ovf.inc())

        valid = Signal()
        data = Record(ULPI_DATA_D)

        self.comb += [If(
            self.sink.stb,
            self.sink.ack.eq(1),
        )]

        self.sync += [
            If(
                self.sink.stb, valid.eq(1),
                If(
                    valid & ~self.source.ack,
                    data.rxcmd.eq(1),
                    data.d.eq(RXCMD_MAGIC_OVF),
                ).Else(data.eq(self.sink.payload))).Elif(
                    self.source.ack, valid.eq(0))
        ]

        self.comb += [self.source.stb.eq(valid), self.source.payload.eq(data)]
Ejemplo n.º 5
0
    def __init__(self):
        self.sink = Sink(ULPI_DATA_D)
        self.source = Source(ULPI_DATA_D)

        valid = Signal()
        data = Record(ULPI_DATA_D)


        self.comb += [
            If(self.sink.stb,
                self.sink.ack.eq(1),
            )]

        self.sync += [
            If(self.sink.stb,
                valid.eq(1),
                If(valid & ~self.source.ack,
                    data.rxcmd.eq(1),
                    data.d.eq(RXCMD_MAGIC_OVF),
                ).Else(
                    data.eq(self.sink.payload)
                )
            ).Elif(self.source.ack,
                valid.eq(0)
            )]

        self.comb += [
            self.source.stb.eq(valid),
            self.source.payload.eq(data)
            ]
Ejemplo n.º 6
0
class DownscalerCore(Module):
	def __init__(self, base_layout, N, res_bits):
		self.init = Signal()
		self.ready = Signal()
		self.ce = Signal()

		self.hres_in = Signal(res_bits)
		self.vres_in = Signal(res_bits)
		self.i = Record([("w"+str(i), base_layout) for i in range(N)])

		self.hres_out = Signal(res_bits)
		self.vres_out = Signal(res_bits)
		self.o = Record([("w"+str(i), base_layout) for i in range(N)])
		self.stb = Signal()

		###

		packbits = log2_int(N)
		hcounter = Signal(res_bits-packbits)
		self.sync += If(self.init,
				hcounter.eq(self.hres_in[packbits:] - 1)
			).Elif(self.ce,
				If(hcounter == 0,
					hcounter.eq(self.hres_in[packbits:] - 1)
				).Else(
					hcounter.eq(hcounter - 1)
				)
			)
		self.submodules.vselector = InsertReset(InsertCE(Chopper(res_bits)))
		self.comb += [
			self.vselector.reset.eq(self.init),
			self.vselector.ce.eq(self.ce & (hcounter == 0)),
			self.vselector.p.eq(self.vres_out),
			self.vselector.q.eq(self.vres_in)
		]

		self.submodules.hselector = MultiChopper(N, res_bits)
		self.comb += [
			self.hselector.init.eq(self.init),
			self.ready.eq(self.hselector.ready),
			self.hselector.next.eq(self.ce),
			self.hselector.p.eq(self.hres_out),
			self.hselector.q.eq(self.hres_in)
		]

		self.submodules.compacter = InsertReset(InsertCE(Compacter(base_layout, N)))
		self.submodules.packer = InsertReset(InsertCE(Packer(base_layout, N)))
		self.comb += [
			self.compacter.reset.eq(self.init),
			self.packer.reset.eq(self.init),
			self.compacter.ce.eq(self.ce),
			self.packer.ce.eq(self.ce),

			self.compacter.i.eq(self.i),
			self.compacter.sel.eq(self.hselector.chopper & Replicate(self.vselector.chopper, N)),
			self.packer.i.eq(self.compacter.o),
			self.packer.count.eq(self.compacter.count),
			self.o.eq(self.packer.o),
			self.stb.eq(self.packer.stb)
		]
Ejemplo n.º 7
0
class _InputManager(Module):
    def __init__(self, interface, counter, fifo_depth):
        data_width = rtlink.get_data_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if interface.timestamped:
            ev_layout.append(("timestamp", counter.width + fine_ts_width))
        self.ev = Record(ev_layout)

        self.readable = Signal()
        self.re = Signal()

        self.overflow = Signal()  # pulsed

        # # #

        fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), {
            "read": "rsys",
            "write": "rio"
        })
        self.submodules += fifo

        # FIFO write
        if data_width:
            self.comb += fifo.din.data.eq(interface.data)
        if interface.timestamped:
            if fine_ts_width:
                full_ts = Cat(interface.fine_ts, counter.value_rio)
            else:
                full_ts = counter.value_rio
            self.comb += fifo.din.timestamp.eq(full_ts)
        self.comb += fifo.we.eq(interface.stb)

        # FIFO read
        self.comb += [
            self.ev.eq(fifo.dout),
            self.readable.eq(fifo.readable),
            fifo.re.eq(self.re)
        ]

        overflow_sync = PulseSynchronizer("rio", "rsys")
        overflow_ack_sync = PulseSynchronizer("rsys", "rio")
        self.submodules += overflow_sync, overflow_ack_sync
        overflow_blind = Signal()
        self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable
                                        & ~overflow_blind)
        self.sync.rio += [
            If(fifo.we & ~fifo.writable, overflow_blind.eq(1)),
            If(overflow_ack_sync.o, overflow_blind.eq(0))
        ]
        self.comb += [
            overflow_ack_sync.i.eq(overflow_sync.o),
            self.overflow.eq(overflow_sync.o)
        ]
Ejemplo n.º 8
0
    def __init__(self, nimages, pack_factor, latency):
        epixel_layout = pixel_layout(pack_factor)
        sink_layout = [("i"+str(i), epixel_layout) for i in range(nimages)]
        self.sink = Sink(sink_layout)
        self.source = Source(epixel_layout)
        factors = []
        for i in range(nimages):
            name = "f"+str(i)
            csr = CSRStorage(8, name=name)
            setattr(self, name, csr)
            factors.append(csr.storage)
        PipelinedActor.__init__(self, latency)

        ###

        sink_registered = Record(sink_layout)
        self.sync += If(self.pipe_ce, sink_registered.eq(self.sink.payload))

        imgs = [getattr(sink_registered, "i"+str(i)) for i in range(nimages)]
        outval = Record(epixel_layout)
        for e in epixel_layout:
            name = e[0]
            inpixs = [getattr(img, name) for img in imgs]
            outpix = getattr(outval, name)
            for component in ["r", "g", "b"]:
                incomps = [getattr(pix, component) for pix in inpixs]
                outcomp = getattr(outpix, component)
                outcomp_full = Signal(19)
                self.comb += [
                    outcomp_full.eq(sum(incomp*factor for incomp, factor in zip(incomps, factors))),
                    If(outcomp_full[18],
                        outcomp.eq(2**10 - 1)  # saturate on overflow
                    ).Else(
                        outcomp.eq(outcomp_full[8:18])
                    )
                ]

        pipe_stmts = []
        for i in range(latency-1):
            new_outval = Record(epixel_layout)
            pipe_stmts.append(new_outval.eq(outval))
            outval = new_outval
        self.sync += If(self.pipe_ce, pipe_stmts)
        self.comb += self.source.payload.eq(outval)
Ejemplo n.º 9
0
class _InputManager(Module):
    def __init__(self, interface, counter, fifo_depth):
        data_width = rtlink.get_data_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if interface.timestamped:
            ev_layout.append(("timestamp", counter.width + fine_ts_width))
        self.ev = Record(ev_layout)

        self.readable = Signal()
        self.re = Signal()

        self.overflow = Signal()  # pulsed

        # # #

        fifo = ClockDomainsRenamer({
            "read": "rsys",
            "write": "rio"
        })(AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # FIFO write
        if data_width:
            self.comb += fifo_in.data.eq(interface.data)
        if interface.timestamped:
            if fine_ts_width:
                full_ts = Cat(interface.fine_ts, counter.value_rtio)
            else:
                full_ts = counter.value_rtio
            self.comb += fifo_in.timestamp.eq(full_ts)
        self.comb += fifo.we.eq(interface.stb)

        # FIFO read
        self.comb += [
            self.ev.eq(fifo_out),
            self.readable.eq(fifo.readable),
            fifo.re.eq(self.re)
        ]

        overflow_transfer = _BlindTransfer()
        self.submodules += overflow_transfer
        self.comb += [
            overflow_transfer.i.eq(fifo.we & ~fifo.writable),
            self.overflow.eq(overflow_transfer.o),
        ]
Ejemplo n.º 10
0
    def __init__(self):
        self.busy=Signal()
        self.sink = Sink([('d',8)])
        self.source = Source(CMD_REC)

        sm = FSM(reset_state="IDLE")
        self.submodules += sm

        # Basic checksum

        token = self.source.payload
        token_next = Record(CMD_REC)

        self.sync += token.eq(token_next)
        self.comb += token_next.eq(token)



        sm.act("IDLE",
                self.sink.ack.eq(1),
                If(self.sink.stb,
                    If(self.sink.payload.d == 0x55,
                        NextState("ADRH")
                    )))

        def parse_state(st, to, *update):
            sm.act(st, 
                self.sink.ack.eq(1),
                If(self.sink.stb,
                    NextState(to),
                    *update
                    ))

        parse_state('ADRH', 'ADRL', 
                token_next.wr.eq(self.sink.payload.d[7]), 
                token_next.a[8:14].eq(self.sink.payload.d[:6]))

        parse_state('ADRL', 'DATA',  token_next.a[0:8].eq(self.sink.payload.d)),
        parse_state('DATA', 'CKSUM', token_next.d.eq(self.sink.payload.d)),

        sm.act("CKSUM",
                self.sink.ack.eq(1),
                If(self.sink.stb,
                        NextState('ISSUE')
                )    
        )

        sm.act("ISSUE",
                self.source.stb.eq(1),
                If(self.source.ack,
                    NextState('IDLE')))
Ejemplo n.º 11
0
    def __init__(self):
        self.busy=Signal()
        self.sink = Sink([('d',8)])
        self.source = Source(CMD_REC)

        sm = FSM(reset_state="IDLE")
        self.submodules += sm

        # Basic checksum

        token = self.source.payload
        token_next = Record(CMD_REC)

        self.sync += token.eq(token_next)
        self.comb += token_next.eq(token)



        sm.act("IDLE",
                self.sink.ack.eq(1),
                If(self.sink.stb,
                    If(self.sink.payload.d == 0x55,
                        NextState("ADRH")
                    )))

        def parse_state(st, to, *update):
            sm.act(st, 
                self.sink.ack.eq(1),
                If(self.sink.stb,
                    NextState(to),
                    *update
                    ))

        parse_state('ADRH', 'ADRL', 
                token_next.wr.eq(self.sink.payload.d[7]), 
                token_next.a[8:14].eq(self.sink.payload.d[:6]))

        parse_state('ADRL', 'DATA',  token_next.a[0:8].eq(self.sink.payload.d)),
        parse_state('DATA', 'CKSUM', token_next.d.eq(self.sink.payload.d)),

        sm.act("CKSUM",
                self.sink.ack.eq(1),
                If(self.sink.stb,
                        NextState('ISSUE')
                )    
        )

        sm.act("ISSUE",
                self.source.stb.eq(1),
                If(self.source.ack,
                    NextState('IDLE')))
Ejemplo n.º 12
0
    def __init__(self):
        self.sink = Sink(ULPI_DATA_D)
        self.source = Source(ULPI_DATA_D)

        self._ctl = CSRStorageEx(1)
        snapshot = self._ctl.re
        reset = self._ctl.storage[0]
        self._num_ovf = Perfcounter(snapshot, reset)
        self._num_total = Perfcounter(snapshot, reset)

        self.comb += If(self.sink.stb, self._num_total.inc())
        self.comb += If(self.source.stb &~ self.source.ack, self._num_ovf.inc())

        valid = Signal()
        data = Record(ULPI_DATA_D)


        self.comb += [
            If(self.sink.stb,
                self.sink.ack.eq(1),
            )]

        self.sync += [
            If(self.sink.stb,
                valid.eq(1),
                If(valid & ~self.source.ack,
                    data.rxcmd.eq(1),
                    data.d.eq(RXCMD_MAGIC_OVF),
                ).Else(
                    data.eq(self.sink.payload)
                )
            ).Elif(self.source.ack,
                valid.eq(0)
            )]

        self.comb += [
            self.source.stb.eq(valid),
            self.source.payload.eq(data)
            ]
Ejemplo n.º 13
0
    def __init__(self):
        self.sink = Sink(ULPI_DATA_D)
        self.source = Source(ULPI_DATA_D)

        valid = Signal()
        data = Record(ULPI_DATA_D)

        self.comb += [If(
            self.sink.stb,
            self.sink.ack.eq(1),
        )]

        self.sync += [
            If(
                self.sink.stb, valid.eq(1),
                If(
                    valid & ~self.source.ack,
                    data.rxcmd.eq(1),
                    data.d.eq(RXCMD_MAGIC_OVF),
                ).Else(data.eq(self.sink.payload))).Elif(
                    self.source.ack, valid.eq(0))
        ]

        self.comb += [self.source.stb.eq(valid), self.source.payload.eq(data)]
Ejemplo n.º 14
0
    def __init__(self, pack_factor):
        hbits_dyn = _hbits - log2_int(pack_factor)
        timing_layout = [
            ("hres", hbits_dyn),
            ("hsync_start", hbits_dyn),
            ("hsync_end", hbits_dyn),
            ("hscan", hbits_dyn),
            ("vres", _vbits),
            ("vsync_start", _vbits),
            ("vsync_end", _vbits),
            ("vscan", _vbits)]
        self.timing = Sink(timing_layout)
        self.pixels = Sink(pixel_layout(pack_factor))
        self.phy = Source(phy_layout(pack_factor))
        self.busy = Signal()

        ###

        hactive = Signal()
        vactive = Signal()
        active = Signal()

        hcounter = Signal(hbits_dyn)
        vcounter = Signal(_vbits)

        skip = bpc - bpc_phy
        self.comb += [
            active.eq(hactive & vactive),
            If(active,
                [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:])
                    for p in ["p"+str(i) for i in range(pack_factor)] for c in ["y", "cb_cr"]],
                self.phy.de.eq(1)
            ),
            self.pixels.ack.eq(self.phy.ack & active)
        ]

        load_timing = Signal()
        tr = Record(timing_layout)
        self.sync += If(load_timing, tr.eq(self.timing.payload))

        generate_en = Signal()
        generate_frame_done = Signal()
        self.sync += [
            generate_frame_done.eq(0),
            If(generate_en,
                hcounter.eq(hcounter + 1),

                If(hcounter == 0, hactive.eq(1)),
                If(hcounter == tr.hres, hactive.eq(0)),
                If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)),
                If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)),
                If(hcounter == tr.hscan,
                    hcounter.eq(0),
                    If(vcounter == tr.vscan,
                        vcounter.eq(0),
                        generate_frame_done.eq(1)
                    ).Else(
                        vcounter.eq(vcounter + 1)
                    )
                ),

                If(vcounter == 0, vactive.eq(1)),
                If(vcounter == tr.vres, vactive.eq(0)),
                If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)),
                If(vcounter == tr.vsync_end, self.phy.vsync.eq(0))
            )
        ]

        self.submodules.fsm = FSM()
        self.fsm.act("GET_TIMING",
            self.timing.ack.eq(1),
            load_timing.eq(1),
            If(self.timing.stb, NextState("GENERATE"))
        )
        self.fsm.act("GENERATE",
            self.busy.eq(1),
            If(~active | self.pixels.stb,
                self.phy.stb.eq(1),
                If(self.phy.ack, generate_en.eq(1))
            ),
            If(generate_frame_done,    NextState("GET_TIMING"))
        )
Ejemplo n.º 15
0
    def __init__(self, pack_factor):
        hbits_dyn = _hbits - log2_int(pack_factor)
        timing_layout = [("hres", hbits_dyn), ("hsync_start", hbits_dyn),
                         ("hsync_end", hbits_dyn), ("hscan", hbits_dyn),
                         ("vres", _vbits), ("vsync_start", _vbits),
                         ("vsync_end", _vbits), ("vscan", _vbits)]
        self.timing = Sink(timing_layout)
        self.pixels = Sink(pixel_layout(pack_factor))
        self.phy = Source(phy_layout(pack_factor))
        self.busy = Signal()

        ###

        hactive = Signal()
        vactive = Signal()
        active = Signal()

        hcounter = Signal(hbits_dyn)
        vcounter = Signal(_vbits)

        skip = bpc - bpc_phy
        self.comb += [
            active.eq(hactive & vactive),
            If(active, [
                getattr(getattr(self.phy.payload, p), c).eq(
                    getattr(getattr(self.pixels.payload, p), c)[skip:])
                for p in ["p" + str(i) for i in range(pack_factor)]
                for c in ["y", "cb_cr"]
            ], self.phy.de.eq(1)),
            self.pixels.ack.eq(self.phy.ack & active)
        ]

        load_timing = Signal()
        tr = Record(timing_layout)
        self.sync += If(load_timing, tr.eq(self.timing.payload))

        generate_en = Signal()
        generate_frame_done = Signal()
        self.sync += [
            generate_frame_done.eq(0),
            If(
                generate_en, hcounter.eq(hcounter + 1),
                If(hcounter == 0, hactive.eq(1)),
                If(hcounter == tr.hres, hactive.eq(0)),
                If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)),
                If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)),
                If(
                    hcounter == tr.hscan, hcounter.eq(0),
                    If(vcounter == tr.vscan, vcounter.eq(0),
                       generate_frame_done.eq(1)).Else(
                           vcounter.eq(vcounter + 1))),
                If(vcounter == 0, vactive.eq(1)),
                If(vcounter == tr.vres, vactive.eq(0)),
                If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)),
                If(vcounter == tr.vsync_end, self.phy.vsync.eq(0)))
        ]

        self.submodules.fsm = FSM()
        self.fsm.act("GET_TIMING", self.timing.ack.eq(1), load_timing.eq(1),
                     If(self.timing.stb, NextState("GENERATE")))
        self.fsm.act(
            "GENERATE", self.busy.eq(1),
            If(~active | self.pixels.stb, self.phy.stb.eq(1),
               If(self.phy.ack, generate_en.eq(1))),
            If(generate_frame_done, NextState("GET_TIMING")))
Ejemplo n.º 16
0
    def __init__(self, rbus, counter, fine_ts_width, fifo_depth,
                 guard_io_cycles):
        self.sel = Signal(max=len(rbus))
        # timestamp and value must be valid 1 cycle before we
        self.timestamp = Signal(counter.width + fine_ts_width)
        self.value = Signal(2)
        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2
        self.underflow = Signal()  # valid 2 cycles after we
        self.underflow_reset = Signal()
        self.sequence_error = Signal()
        self.sequence_error_reset = Signal()

        # # #

        signal_underflow = Signal()
        signal_sequence_error = Signal()
        fifos = []
        ev_layout = [("timestamp", counter.width + fine_ts_width),
                     ("value", 2)]
        for n, chif in enumerate(rbus):
            # FIFO
            fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), {
                "write": "rsys",
                "read": "rio"
            })
            self.submodules += fifo
            fifos.append(fifo)

            # Buffer
            buf_pending = Signal()
            buf = Record(ev_layout)
            buf_just_written = Signal()

            # Special cases
            replace = Signal()
            sequence_error = Signal()
            nop = Signal()
            self.sync.rsys += [
                replace.eq(self.timestamp == buf.timestamp[fine_ts_width:]),
                sequence_error.eq(
                    self.timestamp < buf.timestamp[fine_ts_width:]),
                nop.eq(self.value == buf.value)
            ]
            self.comb += If(self.we & (self.sel == n) & sequence_error,
                            signal_sequence_error.eq(1))

            # Buffer read and FIFO write
            self.comb += fifo.din.eq(buf)
            in_guard_time = Signal()
            self.comb += in_guard_time.eq(
                buf.timestamp[fine_ts_width:] < counter.o_value_sys +
                guard_io_cycles)
            self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
            self.comb += \
                If(buf_pending,
                    If(in_guard_time,
                        If(buf_just_written,
                            signal_underflow.eq(1)
                        ).Else(
                            fifo.we.eq(1)
                        )
                    ),
                    If((self.we & (self.sel == n)
                            & ~replace & ~nop & ~sequence_error),
                       fifo.we.eq(1)
                    )
                )

            # Buffer write
            # Must come after read to handle concurrent read+write properly
            self.sync.rsys += [
                buf_just_written.eq(0),
                If(self.we & (self.sel == n) & ~nop & ~sequence_error,
                   buf_just_written.eq(1), buf_pending.eq(1),
                   buf.timestamp.eq(self.timestamp), buf.value.eq(self.value))
            ]

            # Buffer output of FIFO to improve timing
            dout_stb = Signal()
            dout_ack = Signal()
            dout = Record(ev_layout)
            self.sync.rio += \
                If(fifo.re,
                    dout_stb.eq(1),
                    dout.eq(fifo.dout)
                ).Elif(dout_ack,
                    dout_stb.eq(0)
                )
            self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

            # FIFO read through buffer
            self.comb += [
                dout_ack.eq(
                    dout.timestamp[fine_ts_width:] == counter.o_value_rio),
                chif.o_stb.eq(dout_stb & dout_ack),
                chif.o_value.eq(dout.value)
            ]
            if fine_ts_width:
                self.comb += chif.o_fine_ts.eq(dout.timestamp[:fine_ts_width])

        self.comb += \
            self.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel])
        self.sync.rsys += [
            If(self.underflow_reset, self.underflow.eq(0)),
            If(self.sequence_error_reset, self.sequence_error.eq(0)),
            If(signal_underflow, self.underflow.eq(1)),
            If(signal_sequence_error, self.sequence_error.eq(1))
        ]
Ejemplo n.º 17
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and collision
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision = Signal()
        self.busy = Signal()  # pulsed

        # # #

        # FIFO
        fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})(
            AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision = Signal()
        any_error = Signal()
        if interface.enable_replace:
            # Note: replace may be asserted at the same time as collision
            # when addresses are different. In that case, it is a collision.
            self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp)
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
        self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
                                            buf.timestamp[fine_ts_width:])
        if interface.enable_replace:
            if address_width:
                different_addresses = self.ev.address != buf.address
            else:
                different_addresses = 0
            if fine_ts_width:
                self.sync.rsys += collision.eq(
                    (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
                    & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
                       |different_addresses))
        else:
            self.sync.rsys += collision.eq(
                self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
        self.comb += [
            any_error.eq(sequence_error | collision),
            self.sequence_error.eq(self.we & sequence_error),
            self.collision.eq(self.we & collision)
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:]
                < counter.value_sys + guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~any_error,
                buf_just_written.eq(1),
                buf_pending.eq(1),
                buf.eq(self.ev)
            )
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo_out)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # FIFO read through buffer
        self.comb += [
            dout_ack.eq(
                dout.timestamp[fine_ts_width:] == counter.value_rtio),
            interface.stb.eq(dout_stb & dout_ack)
        ]

        busy_transfer = _BlindTransfer()
        self.submodules += busy_transfer
        self.comb += [
            busy_transfer.i.eq(interface.stb & interface.busy),
            self.busy.eq(busy_transfer.o),
        ]

        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Ejemplo n.º 18
0
Archivo: core.py Proyecto: JQIamo/artiq
class _InputManager(Module):
    def __init__(self, interface, counter, fifo_depth):
        data_width = rtlink.get_data_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if interface.timestamped:
            ev_layout.append(("timestamp", counter.width + fine_ts_width))
        self.ev = Record(ev_layout)

        self.readable = Signal()
        self.re = Signal()

        self.overflow = Signal()  # pulsed

        # # #

        fifo = ClockDomainsRenamer({"read": "rsys", "write": "rio"})(
            AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # latency compensation
        if interface.delay:
            counter_rtio = Signal.like(counter.value_rtio, reset_less=True)
            self.sync.rtio += counter_rtio.eq(counter.value_rtio -
                                              (interface.delay + 1))
        else:
            counter_rtio = counter.value_rtio

        # FIFO write
        if data_width:
            self.comb += fifo_in.data.eq(interface.data)
        if interface.timestamped:
            if fine_ts_width:
                full_ts = Cat(interface.fine_ts, counter_rtio)
            else:
                full_ts = counter_rtio
            self.comb += fifo_in.timestamp.eq(full_ts)
        self.comb += fifo.we.eq(interface.stb)

        # FIFO read
        self.comb += [
            self.ev.eq(fifo_out),
            self.readable.eq(fifo.readable),
            fifo.re.eq(self.re)
        ]

        overflow_transfer = BlindTransfer()
        self.submodules += overflow_transfer
        self.comb += [
            overflow_transfer.i.eq(fifo.we & ~fifo.writable),
            self.overflow.eq(overflow_transfer.o),
        ]
Ejemplo n.º 19
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and nop
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision_error = Signal()

        # # #

        # FIFO
        fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), {
            "write": "rsys",
            "read": "rio"
        })
        self.submodules += fifo

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision_error = Signal()
        any_error = Signal()
        nop = Signal()
        self.sync.rsys += [
            # Note: replace does not perform any RTLink address checks,
            # i.e. a write to a different address will be silently replaced
            # as well.
            replace.eq(self.ev.timestamp == buf.timestamp),
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
            sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
                              buf.timestamp[fine_ts_width:])
        ]
        if fine_ts_width:
            self.sync.rsys += collision_error.eq(
                (self.ev.timestamp[fine_ts_width:] ==
                 buf.timestamp[fine_ts_width:])
                & (self.ev.timestamp[:fine_ts_width] !=
                   buf.timestamp[:fine_ts_width]))
        self.comb += any_error.eq(sequence_error | collision_error)
        if interface.suppress_nop:
            # disable NOP at reset: do not suppress a first write with all 0s
            nop_en = Signal(reset=0)
            self.sync.rsys += [
                nop.eq(nop_en & optree("&", [
                    getattr(self.ev, a) == getattr(buf, a)
                    for a in ("data", "address") if hasattr(self.ev, a)
                ],
                                       default=0)),
                # buf now contains valid data. enable NOP.
                If(self.we & ~any_error, nop_en.eq(1)),
                # underflows cancel the write. allow it to be retried.
                If(self.underflow, nop_en.eq(0))
            ]
        self.comb += [
            self.sequence_error.eq(self.we & sequence_error),
            self.collision_error.eq(self.we & collision_error)
        ]

        # Buffer read and FIFO write
        self.comb += fifo.din.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:] < counter.value_sys +
            guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~nop & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~nop & ~any_error, buf_just_written.eq(1),
               buf_pending.eq(1), buf.eq(self.ev))
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo.dout)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # FIFO read through buffer
        # TODO: report error on stb & busy
        self.comb += [
            dout_ack.eq(dout.timestamp[fine_ts_width:] == counter.value_rio),
            interface.stb.eq(dout_stb & dout_ack)
        ]
        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Ejemplo n.º 20
0
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and collision
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision = Signal()
        self.busy = Signal()  # pulsed

        # # #

        # FIFO
        fifo = ClockDomainsRenamer({
            "write": "rsys",
            "read": "rio"
        })(AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision = Signal()
        any_error = Signal()
        if interface.enable_replace:
            # Note: replace may be asserted at the same time as collision
            # when addresses are different. In that case, it is a collision.
            self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp)
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
        self.sync.rsys += sequence_error.eq(
            self.ev.timestamp[fine_ts_width:] < buf.timestamp[fine_ts_width:])
        if interface.enable_replace:
            if address_width:
                different_addresses = self.ev.address != buf.address
            else:
                different_addresses = 0
            if fine_ts_width:
                self.sync.rsys += collision.eq(
                    (self.ev.timestamp[fine_ts_width:] ==
                     buf.timestamp[fine_ts_width:])
                    & ((self.ev.timestamp[:fine_ts_width] !=
                        buf.timestamp[:fine_ts_width])
                       | different_addresses))
        else:
            self.sync.rsys += collision.eq(self.ev.timestamp[fine_ts_width:] ==
                                           buf.timestamp[fine_ts_width:])
        self.comb += [
            any_error.eq(sequence_error | collision),
            self.sequence_error.eq(self.we & sequence_error),
            self.collision.eq(self.we & collision)
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:] < counter.value_sys +
            guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~any_error, buf_just_written.eq(1), buf_pending.eq(1),
               buf.eq(self.ev))
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo_out)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # latency compensation
        if interface.delay:
            counter_rtio = Signal.like(counter.value_rtio)
            self.sync.rtio += counter_rtio.eq(counter.value_rtio -
                                              interface.delay + 1)
        else:
            counter_rtio = counter.value_rtio

        # FIFO read through buffer
        self.comb += [
            dout_ack.eq(dout.timestamp[fine_ts_width:] == counter_rtio),
            interface.stb.eq(dout_stb & dout_ack)
        ]

        busy_transfer = BlindTransfer()
        self.submodules += busy_transfer
        self.comb += [
            busy_transfer.i.eq(interface.stb & interface.busy),
            self.busy.eq(busy_transfer.o),
        ]

        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
Ejemplo n.º 21
0
Archivo: core.py Proyecto: cr1901/artiq
    def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
        data_width = rtlink.get_data_width(interface)
        address_width = rtlink.get_address_width(interface)
        fine_ts_width = rtlink.get_fine_ts_width(interface)

        ev_layout = []
        if data_width:
            ev_layout.append(("data", data_width))
        if address_width:
            ev_layout.append(("address", address_width))
        ev_layout.append(("timestamp", counter.width + fine_ts_width))
        # ev must be valid 1 cycle before we to account for the latency in
        # generating replace, sequence_error and nop
        self.ev = Record(ev_layout)

        self.writable = Signal()
        self.we = Signal()  # maximum throughput 1/2

        self.underflow = Signal()  # valid 1 cycle after we, pulsed
        self.sequence_error = Signal()
        self.collision_error = Signal()

        # # #

        # FIFO
        fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})(
            AsyncFIFO(layout_len(ev_layout), fifo_depth))
        self.submodules += fifo
        fifo_in = Record(ev_layout)
        fifo_out = Record(ev_layout)
        self.comb += [
            fifo.din.eq(fifo_in.raw_bits()),
            fifo_out.raw_bits().eq(fifo.dout)
        ]

        # Buffer
        buf_pending = Signal()
        buf = Record(ev_layout)
        buf_just_written = Signal()

        # Special cases
        replace = Signal()
        sequence_error = Signal()
        collision_error = Signal()
        any_error = Signal()
        nop = Signal()
        self.sync.rsys += [
            # Note: replace does not perform any RTLink address checks,
            # i.e. a write to a different address will be silently replaced
            # as well.
            replace.eq(self.ev.timestamp == buf.timestamp),
            # Detect sequence errors on coarse timestamps only
            # so that they are mutually exclusive with collision errors.
            sequence_error.eq(self.ev.timestamp[fine_ts_width:]
                              < buf.timestamp[fine_ts_width:])
        ]
        if fine_ts_width:
            self.sync.rsys += collision_error.eq(
                (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
                & (self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]))
        self.comb += any_error.eq(sequence_error | collision_error)
        if interface.suppress_nop:
            # disable NOP at reset: do not suppress a first write with all 0s
            nop_en = Signal(reset=0)
            addresses_equal = [getattr(self.ev, a) == getattr(buf, a)
                               for a in ("data", "address")
                               if hasattr(self.ev, a)]
            if addresses_equal:
                self.sync.rsys += nop.eq(
                    nop_en & reduce(and_, addresses_equal))
            else:
                self.comb.eq(nop.eq(0))
            self.sync.rsys += [
                # buf now contains valid data. enable NOP.
                If(self.we & ~any_error, nop_en.eq(1)),
                # underflows cancel the write. allow it to be retried.
                If(self.underflow, nop_en.eq(0))
            ]
        self.comb += [
            self.sequence_error.eq(self.we & sequence_error),
            self.collision_error.eq(self.we & collision_error)
        ]

        # Buffer read and FIFO write
        self.comb += fifo_in.eq(buf)
        in_guard_time = Signal()
        self.comb += in_guard_time.eq(
            buf.timestamp[fine_ts_width:]
                < counter.value_sys + guard_io_cycles)
        self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
        self.comb += \
            If(buf_pending,
                If(in_guard_time,
                    If(buf_just_written,
                        self.underflow.eq(1)
                    ).Else(
                        fifo.we.eq(1)
                    )
                ),
                If(self.we & ~replace & ~nop & ~any_error,
                   fifo.we.eq(1)
                )
            )

        # Buffer write
        # Must come after read to handle concurrent read+write properly
        self.sync.rsys += [
            buf_just_written.eq(0),
            If(self.we & ~nop & ~any_error,
                buf_just_written.eq(1),
                buf_pending.eq(1),
                buf.eq(self.ev)
            )
        ]
        self.comb += self.writable.eq(fifo.writable)

        # Buffer output of FIFO to improve timing
        dout_stb = Signal()
        dout_ack = Signal()
        dout = Record(ev_layout)
        self.sync.rio += \
            If(fifo.re,
                dout_stb.eq(1),
                dout.eq(fifo_out)
            ).Elif(dout_ack,
                dout_stb.eq(0)
            )
        self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))

        # FIFO read through buffer
        # TODO: report error on stb & busy
        self.comb += [
            dout_ack.eq(
                dout.timestamp[fine_ts_width:] == counter.value_rio),
            interface.stb.eq(dout_stb & dout_ack)
        ]
        if data_width:
            self.comb += interface.data.eq(dout.data)
        if address_width:
            self.comb += interface.address.eq(dout.address)
        if fine_ts_width:
            self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])