Esempio n. 1
0
    def __init__(self, sample_clk_ticks, sample_width, full_width):
        self.freq_out = CSRStatus(full_width)
        self.num_events = CSRStatus(full_width)
        self.num_samples = CSRStatus(full_width)
        self.last_inc = CSRStatus(sample_width)

        # TODO: Perhaps configure the number of dest clk ticks before
        # number of events is latched?

        self.submodules.core = FreqCountCore(sample_width, full_width)

        ###
        self.comb += [
            self.freq_out.status.eq(self.core.count_latched),
            self.num_events.status.eq(self.core.count_curr),
            self.last_inc.status.eq(self.core.sampler.inc)
        ]

        # sample_clk_ticks = 0 is a legal sample period. It means sample each cycle.
        self.sync.dest += [
            self.core.latch.eq(0),
            If(self.num_samples.status == sample_clk_ticks,
               self.num_samples.status.eq(0), self.core.latch.eq(1)).Else(
                   self.num_samples.status.eq(self.num_samples.status + 1))
        ]
Esempio n. 2
0
def cross_connect(gpio, chains):
    state_names = ["force"] + ["di%i" % i for i in range(len(gpio.i))]
    states = [1, gpio.i]
    signal_names = ["zero"]
    signals = Array([0])

    for n, c in chains:
        for s in c.state_out:
            states.append(s)
            state_names.append("%s_%s" % (n, s.backtrace[-1][0]))
        for s in c.signal_out:
            signals.append(s)
            name = s.backtrace[-1][0]
            signal_names.append("%s_%s" % (n, name))
            sig = CSRStatus(len(s), name=name)
            clr = CSR(name="%s_clr" % name)
            max = CSRStatus(len(s), name="%s_max" % name)
            min = CSRStatus(len(s), name="%s_min" % name)
            # setattr(c, sig.name, sig)
            setattr(c, clr.name, clr)
            setattr(c, max.name, max)
            setattr(c, min.name, min)
            c.comb += sig.status.eq(s)
            c.sync += If(clr.re | (max.status < s), max.status.eq(s))
            c.sync += If(clr.re | (min.status > s), min.status.eq(s))

    states = Cat(states)
    state = Signal(len(states))
    gpio.comb += state.eq(states)
    gpio.state = CSRStatus(len(state))
    gpio.state_clr = CSR()
    gpio.sync += [
        If(
            gpio.state_clr.re,
            gpio.state.status.eq(0),
        ).Else(gpio.state.status.eq(gpio.state.status | state), )
    ]

    # connect gpio output to "doi%i_en"
    for i, s in enumerate(gpio.o):
        csr = CSRStorage(len(state), name="do%i_en" % i)
        setattr(gpio, csr.name, csr)
        gpio.sync += s.eq((state & csr.storage) != 0)

    # connect state ins to "%s_en" and signal ins to "%s_sel"
    for n, c in chains:
        for s in c.state_in:
            csr = CSRStorage(len(state), name="%s_en" % s.backtrace[-1][0])
            setattr(c, csr.name, csr)
            c.sync += s.eq((state & csr.storage) != 0)

        for s in c.signal_in:
            csr = CSRStorage(bits_for(len(signals) - 1),
                             name="%s_sel" % s.backtrace[-1][0])
            setattr(c, csr.name, csr)
            c.sync += s.eq(signals[csr.storage])

    return state_names, signal_names
Esempio n. 3
0
    def init_csr(self, width, signal_width, chain_factor_width):
        factor_reset = 1 << (chain_factor_width - 1)
        # we use chain_factor_width + 1 for the single channel mode
        self.dual_channel = CSRStorage(1)
        self.chain_a_factor = CSRStorage(chain_factor_width + 1, reset=factor_reset)
        self.chain_b_factor = CSRStorage(chain_factor_width + 1, reset=factor_reset)

        self.chain_a_offset = CSRStorage(width)
        self.chain_b_offset = CSRStorage(width)
        self.chain_a_offset_signed = Signal((width, True))
        self.chain_b_offset_signed = Signal((width, True))
        self.combined_offset = CSRStorage(width)
        self.combined_offset_signed = Signal((width, True))
        self.out_offset = CSRStorage(width)
        self.out_offset_signed = Signal((width, True))

        self.mod_channel = CSRStorage(1)
        self.control_channel = CSRStorage(1)
        self.sweep_channel = CSRStorage(2)

        self.slow_value = CSRStatus(width)

        max_decimation = 16
        self.slow_decimation = CSRStorage(bits_for(max_decimation))

        for i in range(4):
            if i == 0:
                continue
            name = "analog_out_%d" % i
            setattr(self, name, CSRStorage(15, name=name))
Esempio n. 4
0
    def __init__(self, width=14, N_points=16383, max_delay=16383):
        self.submodules.robust = RobustAutolock(max_delay=max_delay)

        self.submodules.fast = FastAutolock(width=width)

        self.request_lock = CSRStorage()
        self.autolock_mode = CSRStorage(2)
        self.lock_running = CSRStatus()

        self.comb += [
            self.fast.request_lock.eq(self.request_lock.storage),
            self.robust.request_lock.eq(self.request_lock.storage),
        ]

        self.sync += [
            If(
                ~self.request_lock.storage,
                self.lock_running.status.eq(0),
            ),
            If(
                self.request_lock.storage
                & self.fast.turn_on_lock
                & (self.autolock_mode.storage == FAST_AUTOLOCK),
                self.lock_running.status.eq(1),
            ),
            If(
                self.request_lock.storage
                & self.robust.turn_on_lock
                & (self.autolock_mode.storage == ROBUST_AUTOLOCK),
                self.lock_running.status.eq(1),
            ),
        ]
Esempio n. 5
0
 def _add_register(self, register, name):
     if not isinstance(register, _Register):
         register = register(
         )  # create a register instance to retrieve attributes in case a class was passed
     logger.debug(
         f"Creating register {name} of type {register.__class__.__name__}.")
     name_csr = f"{name}_csr"
     if register.depth == 1:
         if register.readonly:
             register_instance = CSRStatus(size=register.width,
                                           reset=register.default,
                                           name=name_csr)
             setattr(self, name_csr, register_instance)
             setattr(self, name, register_instance.status)
         else:
             register_instance = CSRStorage(size=register.width,
                                            reset=register.default,
                                            name=name_csr)
             setattr(self, name_csr, register_instance)
             setattr(self, name, register_instance.storage)
             setattr(self, f"{name}_re", register_instance.re)
     else:  # register has nontrivial depth
         if register.readonly:
             register_instance = CSRStorage(size=register.width,
                                            reset=register.default,
                                            name=name_csr,
                                            write_from_dev=True)
             setattr(self, name_csr, register_instance)
             setattr(self, name, register_instance.dat_w)
             setattr(self, f"{name}_re", register_instance.re)
             setattr(self, f"{name}_we", register_instance.we)
             setattr(self, f"{name}_index", register_instance.storage)
Esempio n. 6
0
    def __init__(self, version=0b1000001):
        n = 64
        self.dna = CSRStatus(n, reset=version << 57)

        ###

        do = Signal()
        cnt = Signal(max=2 * n + 1)

        self.specials += Instance(
            "DNA_PORT",
            i_DIN=self.dna.status[-1],
            o_DOUT=do,
            i_CLK=cnt[0],
            i_READ=cnt < 2,
            i_SHIFT=1,
        )

        self.sync += [
            If(
                cnt < 2 * n,
                cnt.eq(cnt + 1),
                If(cnt[0], self.dna.status.eq(Cat(do, self.dna.status))),
            )
        ]
Esempio n. 7
0
    def __init__(self, io):
        self._program = CSRStorage()
        self._done = CSRStatus()
        self._error = CSRStatus()

        self._divisor = CSRStorage(32)
        self._data = CSRStorage(32)
        self._start = CSR()
        self._busy = CSRStatus()

        # # #

        ctr = Signal.like(self._divisor.storage)
        clk2x = Signal()
        self.comb += [
            clk2x.eq(ctr == 0),
        ]
        self.sync += [
            If(ctr == 0, ctr.eq(self._divisor.storage)).Else(ctr.eq(ctr - 1))
        ]

        shreg = Signal.like(self._data.storage)
        bits = Signal(max=shreg.nbits)
        busy = Signal()
        clk = Signal()
        self.comb += [busy.eq(bits != 0), self._busy.status.eq(busy)]
        self.sync += [
            If(self._start.re & self._start.r, clk.eq(0),
               bits.eq(shreg.nbits - 1), shreg.eq(self._data.storage)).Elif(
                   clk2x & busy, clk.eq(~clk),
                   If(clk, bits.eq(bits - 1), shreg.eq(shreg >> 1)))
        ]

        self.sync += [
            io.program_b.eq(~self._program.storage),
            io.din.eq(shreg[0]),
            io.cclk.eq(clk)
        ]
        self.specials += [
            MultiReg(io.done, self._done.status),
            MultiReg(~io.init_b, self._error.status)
        ]
Esempio n. 8
0
    def __init__(self, width):
        self.x = Signal((width, True))
        self.y = Signal((width, True))

        self.hold = Signal()
        self.clear = Signal()
        self.error = Signal()

        if False:
            self.y_current = CSRStatus(width)
            self.comb += self.y_current.status.eq(self.y)
Esempio n. 9
0
    def __init__(self, bus):
        self.burst_request = Signal()
        self._status = CSRStatus(10)

        ###

        dr, da = attrgetter("dr", "da")(bus)
        burst_type = dmac_bus.Type.burst
        flush_type = dmac_bus.Type.flush

        # control
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE",
            If(
                da.valid & (da.type == flush_type),
                NextState("ACK_FLUSH"),
            ).Elif(
                self.burst_request,
                dr.valid.eq(1),
                dr.type.eq(burst_type),
                If(
                    dr.ready,
                    NextState("READ"),
                ),
            ),
        )
        fsm.act("ACK_FLUSH", dr.valid.eq(1), dr.type.eq(flush_type),
                If(
                    dr.ready,
                    NextState("IDLE"),
                ))
        fsm.act(
            "READ",
            If(
                da.valid,
                If(
                    da.type == flush_type,
                    NextState("ACK_FLUSH"),
                ).Elif(
                    da.type == burst_type,
                    NextState("IDLE"),
                )))
        da_type = Signal(len(da.type), reset=0x3)
        self.sync += If(da.valid, da_type.eq(da.type))
        self.comb += [
            da.ready.eq(1),
            self._status.status.eq(
                Cat(self.burst_request, C(0, (3, False)), fsm.ongoing("IDLE"),
                    fsm.ongoing("READ"), C(0, (2, False)), da_type)),
        ]
Esempio n. 10
0
    def __init__(self, pins):
        n = len(pins)
        self.i = Signal(n)
        self.o = Signal(n)
        self.ins = CSRStatus(n)
        self.outs = CSRStorage(n)
        self.oes = CSRStorage(n)

        ###

        t = [TSTriple(1) for i in range(n)]
        self.specials += [ti.get_tristate(pins[i]) for i, ti in enumerate(t)]
        self.specials += MultiReg(Cat([ti.i for ti in t]), self.i)
        self.comb += [
            Cat([ti.o for ti in t]).eq(self.outs.storage | self.o),
            Cat([ti.oe for ti in t]).eq(self.oes.storage),
            self.ins.status.eq(self.i),
        ]
Esempio n. 11
0
def get_remote_csr_regions(offset, csv_file):
    busword = 32
    regions = []
    for region_name, csrs_info in _get_csr_data(csv_file).items():
        csrs_info = sorted(csrs_info, key=itemgetter(1))
        origin = csrs_info[0][1]
        next_address = origin
        csrs = []
        for csr_name, address, length, ro in csrs_info:
            if address != next_address:
                raise ValueError("CSRs are not contiguous")
            nr = (length + busword - 1) // busword
            next_address += nr * busword // 8
            if ro:
                csr = CSRStatus(length, name=csr_name)
            else:
                csr = CSRStorage(length, name=csr_name)
            csrs.append(csr)
        regions.append((region_name, offset + origin, busword, csrs))
    return regions
Esempio n. 12
0
 def __init__(self):
     self.id = CSRStatus(1, reset=1)
Esempio n. 13
0
    def __init__(self, hostif, host_burst_length=16):
        width = len(hostif.d_write)
        assert width == 16
        awidth = len(hostif.i_addr) + 1

        self.source = Endpoint([('d', 8), ('last', 1)])

        go = Signal()
        gor = Signal()
        rptr = Signal(awidth)
        self.rptr = rptr
        rptr_w = Signal(awidth)
        rptr_we = Signal()
        self.wptr = Signal(awidth)

        # CSRs

        ##

        self._debug_i_stb = CSRStatus(32)
        self._debug_i_ack = CSRStatus(32)
        self._debug_d_stb = CSRStatus(32)
        self._debug_d_term = CSRStatus(32)
        self._debug_s0 = CSRStatus(32)
        self._debug_s1 = CSRStatus(32)
        self._debug_s2 = CSRStatus(32)

        self.submodules.i_stb_acc = Acc_inc(32)
        self.submodules.i_ack_acc = Acc_inc(32)
        self.submodules.d_stb_acc = Acc_inc(32)
        self.submodules.d_term_acc = Acc_inc(32)

        self.comb += self._debug_i_stb.status.eq(self.i_stb_acc.v)
        self.comb += self._debug_i_ack.status.eq(self.i_ack_acc.v)
        self.comb += self._debug_d_stb.status.eq(self.d_stb_acc.v)
        self.comb += self._debug_d_term.status.eq(self.d_term_acc.v)
        self.comb += If(hostif.i_stb, self.i_stb_acc.inc())
        self.comb += If(hostif.i_ack, self.i_ack_acc.inc())
        self.comb += If(hostif.d_stb, self.d_stb_acc.inc())
        self.comb += If(hostif.d_term, self.d_term_acc.inc())

        self.submodules.s0_acc = Acc_inc(32)
        self.submodules.s1_acc = Acc_inc(32)
        self.submodules.s2_acc = Acc_inc(32)

        self.comb += self._debug_s0.status.eq(self.s0_acc.v)
        self.comb += self._debug_s1.status.eq(self.s1_acc.v)
        self.comb += self._debug_s2.status.eq(self.s2_acc.v)

        ##

        self._ring_base = CSRStorage(awidth)
        self._ring_end = CSRStorage(awidth)

        # rptr readback
        self._rptr_status = CSRStatus(awidth)
        self.comb += self._rptr_status.status.eq(rptr)

        # 'go' bit

        self._go = CSRStorage(1)

        self.comb += go.eq(self._go.storage[0])
        self.sync += gor.eq(go)

        # state machine to read

        self.submodules.sdram_read_fsm = FSM()

        sdram_fifo = SyncFIFO(width, host_burst_length)
        self.submodules += sdram_fifo

        # we always read (never write)
        self.comb += hostif.i_wr.eq(0)

        # blocked

        blocked = Signal()
        self.comb += blocked.eq(rptr == self.wptr)

        # wait until there's data and go, and then when the fifo has space, issue request.

        self.sdram_read_fsm.act("BLOCKED", self.s2_acc.inc(),
                                If(go & ~blocked, NextState("IDLE")))

        self.sdram_read_fsm.act(
            "IDLE", self.s0_acc.inc(), hostif.i_addr.eq(rptr),
            hostif.i_stb.eq(sdram_fifo.writable),
            If(hostif.i_stb & hostif.i_ack, NextState("DATA")))

        # read until fifo is full; when fifo is not writable but data was received,
        # abort SDRAM read request.

        wrap = Signal()
        self.comb += wrap.eq(self.rptr == self._ring_end.storage)

        self.sdram_read_fsm.act(
            "DATA", self.s1_acc.inc(),
            hostif.d_term.eq(~sdram_fifo.writable | ~go | blocked | wrap),
            If(hostif.d_term,
               If(hostif.d_stb, NextState("BLOCKED")).Else(NextState("WAIT"))))

        self.sdram_read_fsm.act("WAIT", hostif.d_term.eq(1),
                                If(hostif.d_stb, NextState("BLOCKED")))

        # allow rptr to be updated via CSR. Otherwise,
        # increment read point whenever valid data is fed into the fifo.

        rptr_next = Signal(awidth)
        self.comb += If(wrap, rptr_next.eq(self._ring_base.storage)).Else(
            rptr_next.eq(self.rptr + 1))

        self.sync += \
            If(go &~ gor,
                rptr.eq(self._ring_base.storage),
            ).Elif(hostif.d_stb &~hostif.d_term | wrap,
                rptr.eq(rptr_next))

        self.comb += sdram_fifo.we.eq(hostif.d_stb & ~hostif.d_term)
        self.comb += sdram_fifo.din.eq(hostif.d_read)

        # fifo to host interface

        self.submodules.host_write_fsm = FSM()

        burst_rem = Signal(max=host_burst_length)
        burst_rem_next = Signal(max=host_burst_length)

        self.comb += burst_rem_next.eq(burst_rem)
        self.sync += burst_rem.eq(burst_rem_next)

        # when the sdram_fifo is not anymore writable, start bursting out that data.

        self.host_write_fsm.act(
            "IDLE", self.source.payload.d.eq(0xD0),
            self.source.stb.eq(sdram_fifo.readable & ~sdram_fifo.writable),
            If(self.source.ack & self.source.stb, NextState("SEND_HEADER")))

        self.host_write_fsm.act(
            "SEND_HEADER", self.source.payload.d.eq(host_burst_length - 1),
            self.source.stb.eq(1),
            If(self.source.ack & self.source.stb,
               burst_rem_next.eq(host_burst_length - 1),
               NextState("SEND_DATA_ODD")))

        # when byte available, write low byte until ack'ed.

        self.host_write_fsm.act(
            "SEND_DATA_ODD", self.source.payload.d.eq(sdram_fifo.dout[0:8]),
            self.source.stb.eq(sdram_fifo.readable),
            If(self.source.stb & self.source.ack, NextState("SEND_DATA_EVEN")))

        # write high byte. when ack'ed, read next byte, unless we hit the burst length limit.

        self.host_write_fsm.act(
            "SEND_DATA_EVEN", self.source.payload.d.eq(sdram_fifo.dout[8:16]),
            self.source.payload.last.eq(burst_rem == 0), self.source.stb.eq(1),
            sdram_fifo.re.eq(self.source.ack),
            If(
                self.source.ack,
                If(burst_rem != 0, NextState("SEND_DATA_ODD"),
                   burst_rem_next.eq(burst_rem - 1)).Else(NextState("IDLE"))))
Esempio n. 14
0
    def __init__(self, pads, default=_default_edid):
        self._hpd_notif = CSRStatus()
        self._hpd_en = CSRStorage()
        self.specials.mem = Memory(8, 128, init=default)

        ###

        # HPD
        if hasattr(pads, "hpd_notif"):
            self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status)
        else:
            self.comb += self._hpd_notif.status.eq(1)
        if hasattr(pads, "hpd_en"):
            self.comb += pads.hpd_en.eq(self._hpd_en.storage)

        # EDID
        scl_raw = Signal()
        sda_i = Signal()
        sda_raw = Signal()
        sda_drv = Signal()
        _sda_drv_reg = Signal()
        _sda_i_async = Signal()
        self.sync += _sda_drv_reg.eq(sda_drv)
        self.specials += [
            MultiReg(pads.scl, scl_raw),
            Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
            MultiReg(_sda_i_async, sda_raw)
        ]

        scl_i = Signal()
        samp_count = Signal(6)
        samp_carry = Signal()
        self.sync += [
            Cat(samp_count, samp_carry).eq(samp_count + 1),
            If(samp_carry, scl_i.eq(scl_raw), sda_i.eq(sda_raw))
        ]

        scl_r = Signal()
        sda_r = Signal()
        scl_rising = Signal()
        sda_rising = Signal()
        sda_falling = Signal()
        self.sync += [scl_r.eq(scl_i), sda_r.eq(sda_i)]
        self.comb += [
            scl_rising.eq(scl_i & ~scl_r),
            sda_rising.eq(sda_i & ~sda_r),
            sda_falling.eq(~sda_i & sda_r)
        ]

        start = Signal()
        self.comb += start.eq(scl_i & sda_falling)

        din = Signal(8)
        counter = Signal(max=9)
        self.sync += [
            If(start, counter.eq(0)),
            If(
                scl_rising,
                If(counter == 8,
                   counter.eq(0)).Else(counter.eq(counter + 1),
                                       din.eq(Cat(sda_i, din[:7]))))
        ]

        is_read = Signal()
        update_is_read = Signal()
        self.sync += If(update_is_read, is_read.eq(din[0]))

        offset_counter = Signal(max=128)
        oc_load = Signal()
        oc_inc = Signal()
        self.sync += [
            If(oc_load, offset_counter.eq(din)).Elif(
                oc_inc, offset_counter.eq(offset_counter + 1))
        ]
        rdport = self.mem.get_port()
        self.specials += rdport
        self.comb += rdport.adr.eq(offset_counter)
        data_bit = Signal()

        zero_drv = Signal()
        data_drv = Signal()
        self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv,
                                                      sda_drv.eq(~data_bit))

        data_drv_en = Signal()
        data_drv_stop = Signal()
        self.sync += If(data_drv_en,
                        data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
        self.sync += If(
            data_drv_en,
            chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))

        fsm = FSM()
        self.submodules += fsm

        fsm.act("WAIT_START")
        fsm.act(
            "RCV_ADDRESS",
            If(
                counter == 8,
                If(din[1:] == 0x50, update_is_read.eq(1),
                   NextState("ACK_ADDRESS0")).Else(NextState("WAIT_START"))))
        fsm.act("ACK_ADDRESS0", If(~scl_i, NextState("ACK_ADDRESS1")))
        fsm.act("ACK_ADDRESS1", zero_drv.eq(1),
                If(scl_i, NextState("ACK_ADDRESS2")))
        fsm.act(
            "ACK_ADDRESS2", zero_drv.eq(1),
            If(~scl_i,
               If(is_read, NextState("READ")).Else(NextState("RCV_OFFSET"))))

        fsm.act("RCV_OFFSET",
                If(counter == 8, oc_load.eq(1), NextState("ACK_OFFSET0")))
        fsm.act("ACK_OFFSET0", If(~scl_i, NextState("ACK_OFFSET1")))
        fsm.act("ACK_OFFSET1", zero_drv.eq(1),
                If(scl_i, NextState("ACK_OFFSET2")))
        fsm.act("ACK_OFFSET2", zero_drv.eq(1),
                If(~scl_i, NextState("RCV_ADDRESS")))

        fsm.act(
            "READ",
            If(
                ~scl_i,
                If(counter == 8, data_drv_stop.eq(1),
                   NextState("ACK_READ")).Else(data_drv_en.eq(1))))
        fsm.act(
            "ACK_READ",
            If(scl_rising, oc_inc.eq(1),
               If(sda_i, NextState("WAIT_START")).Else(NextState("READ"))))

        for state in fsm.actions.keys():
            fsm.act(state, If(start, NextState("RCV_ADDRESS")))
            fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
Esempio n. 15
0
    def __init__(self,
                 pads,
                 dummy=15,
                 div=2,
                 with_bitbang=True,
                 endianness="big",
                 dw=32):
        """
        Simple SPI flash, e.g. N25Q128 on the LX9 Microboard.

        Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
        Read). Only supports mode0 (cpol=0, cpha=0).
        Optionally supports software bitbanging (for write, erase, or other commands).
        """
        adr_width = 32 - log2_int(dw // 8)
        self.bus = bus = wishbone.Interface(data_width=dw, adr_width=adr_width)
        spi_width = len(pads.dq)
        if with_bitbang:
            self.bitbang = CSRStorage(4)
            self.miso = CSRStatus()
            self.bitbang_en = CSRStorage()

        ###

        cs_n = Signal(reset=1)
        clk = Signal()
        dq_oe = Signal()

        read_cmd_params = {
            4: (_format_cmd(_QIOFR, 4), 4 * 8),
            2: (_format_cmd(_DIOFR, 2), 2 * 8),
            1: (_format_cmd(_FAST_READ, 1), 1 * 8)
        }
        read_cmd, cmd_width = read_cmd_params[spi_width]
        addr_width = 24

        pads.cs_n.reset = 1

        dq = TSTriple(spi_width)
        self.specials.dq = dq.get_tristate(pads.dq)

        sr = Signal(max(cmd_width, addr_width, dw))
        if endianness == "big":
            self.comb += bus.dat_r.eq(sr)
        else:
            self.comb += bus.dat_r.eq(reverse_bytes(sr))

        hw_read_logic = [
            pads.clk.eq(clk),
            pads.cs_n.eq(cs_n),
            dq.o.eq(sr[-spi_width:]),
            dq.oe.eq(dq_oe)
        ]

        if with_bitbang:
            bitbang_logic = [
                pads.clk.eq(self.bitbang.storage[1]),
                pads.cs_n.eq(self.bitbang.storage[2]),
                If(self.bitbang.storage[3], dq.oe.eq(0)).Else(dq.oe.eq(1)),
                If(self.bitbang.storage[1], self.miso.status.eq(dq.i[1]))
            ]
            if spi_width > 1:
                bitbang_logic += [
                    dq.o.eq(
                        Cat(self.bitbang.storage[0],
                            Replicate(1, spi_width - 1)))
                ]
            else:
                bitbang_logic += [dq.o.eq(self.bitbang.storage[0])]

            self.comb += \
                If(self.bitbang_en.storage,
                    bitbang_logic
                ).Else(
                    hw_read_logic
                )
        else:
            self.comb += hw_read_logic

        if div < 2:
            raise ValueError(
                "Unsupported value \'{}\' for div parameter for SpiFlash core".
                format(div))
        else:
            i = Signal(max=div)
            dqi = Signal(spi_width)
            self.sync += [
                If(
                    i == div // 2 - 1,
                    clk.eq(1),
                    dqi.eq(dq.i),
                ),
                If(i == div - 1, i.eq(0), clk.eq(0),
                   sr.eq(Cat(dqi, sr[:-spi_width]))).Else(i.eq(i + 1), ),
            ]

        # spi is byte-addressed, prefix by zeros
        z = Replicate(0, log2_int(dw // 8))

        seq = [
            (cmd_width // spi_width * div,
             [dq_oe.eq(1),
              cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]),
            (addr_width // spi_width * div,
             [sr[-addr_width:].eq(Cat(z, bus.adr))]),
            ((dummy + dw // spi_width) * div, [dq_oe.eq(0)]),
            (1, [bus.ack.eq(1), cs_n.eq(1)]),
            (
                div,  # tSHSL!
                [bus.ack.eq(0)]),
            (0, []),
        ]

        # accumulate timeline deltas
        t, tseq = 0, []
        for dt, a in seq:
            tseq.append((t, a))
            t += dt

        self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
Esempio n. 16
0
    def __init__(self, xadc):
        self.alarm = Signal(8)
        self.ot = Signal()
        self.adc = [Signal((12, True)) for i in range(4)]

        self.temp = CSRStatus(12)
        self.v = CSRStatus(12)
        self.a = CSRStatus(12)
        self.b = CSRStatus(12)
        self.c = CSRStatus(12)
        self.d = CSRStatus(12)

        ###

        self.comb += [
            self.adc[0].eq(self.a.status),
            self.adc[1].eq(self.b.status),
            self.adc[2].eq(self.c.status),
            self.adc[3].eq(self.d.status),
        ]

        busy = Signal()
        channel = Signal(7)
        eoc = Signal()
        eos = Signal()
        data = Signal(16)
        drdy = Signal()

        vin = Cat(xadc.n[:2], Replicate(0, 6), xadc.n[2:4], Replicate(0, 6), xadc.n[4])
        vip = Cat(xadc.p[:2], Replicate(0, 6), xadc.p[2:4], Replicate(0, 6), xadc.p[4])
        self.specials += Instance(
            "XADC",
            p_INIT_40=0x0000,
            p_INIT_41=0x2F0F,
            p_INIT_42=0x0400,  # config
            p_INIT_48=0x0900,
            p_INIT_49=0x0303,  # channels VpVn, Temp
            p_INIT_4A=0x47E0,
            p_INIT_4B=0x0000,  # avg VpVn, temp
            p_INIT_4C=0x0800,
            p_INIT_4D=0x0303,  # bipolar
            p_INIT_4E=0x0000,
            p_INIT_4F=0x0000,  # acq time
            p_INIT_50=0xB5ED,
            p_INIT_51=0x57E4,  # temp trigger, vccint upper alarms
            p_INIT_52=0xA147,
            p_INIT_53=0xCA33,  # vccaux upper, temp over upper
            p_INIT_54=0xA93A,
            p_INIT_55=0x52C6,  # temp reset, vccint lower
            p_INIT_56=0x9555,
            p_INIT_57=0xAE4E,  # vccaux lower, temp over reset
            p_INIT_58=0x5999,
            p_INIT_5C=0x5111,  # vbram uppper, vbram lower
            p_INIT_59=0x5555,
            p_INIT_5D=0x5111,  # vccpint upper lower
            p_INIT_5A=0x9999,
            p_INIT_5E=0x91EB,  # vccpaux upper lower
            p_INIT_5B=0x6AAA,
            p_INIT_5F=0x6666,  # vccdro upper lower
            o_ALM=self.alarm,
            o_OT=self.ot,
            o_BUSY=busy,
            o_CHANNEL=channel,
            o_EOC=eoc,
            o_EOS=eos,
            i_VAUXN=vin[:16],
            i_VAUXP=vip[:16],
            i_VN=vin[16],
            i_VP=vip[16],
            i_CONVST=0,
            i_CONVSTCLK=0,
            i_RESET=ResetSignal(),
            o_DO=data,
            o_DRDY=drdy,
            i_DADDR=channel,
            i_DCLK=ClockSignal(),
            i_DEN=eoc,
            i_DI=0,
            i_DWE=0,
            # o_JTAGBUSY=, o_JTAGLOCKED=, o_JTAGMODIFIED=, o_MUXADDR=,
        )

        channels = {
            0: self.temp,
            3: self.v,
            16: self.b,
            17: self.c,
            24: self.a,
            25: self.d,
        }

        self.sync += [
            If(
                drdy,
                Case(
                    channel,
                    dict((k, v.status.eq(data >> 4)) for k, v in channels.items()),
                ),
            )
        ]
Esempio n. 17
0
    def __init__(self, hostif, max_burst_length=256):
        width = len(hostif.d_write)
        assert width == 16

        awidth = len(hostif.i_addr) + 1

        self.sink = Endpoint([('d', 8), ('last', 1)])

        self.submodules.sdram_fifo = SyncFIFO(width, max_burst_length)

        self.submodules.fifo_write_fsm = FSM()

        self.wptr = Signal(awidth)

        # rptr (from SDRAM Source)
        self.rptr = Signal(awidth)

        # CSRs

        self._ptr_read = CSRStorage(1)
        ptr_read = self._ptr_read.re
        self._wptr = CSRStatus(awidth)
        self.sync += If(ptr_read, self._wptr.status.eq(self.wptr))
        self._rptr = CSRStatus(awidth)
        self.sync += If(ptr_read, self._rptr.status.eq(self.rptr))

        self._ring_base = CSRStorage(awidth)
        self._ring_end = CSRStorage(awidth)
        self._go = CSRStorage(1)

        go = self._go.storage[0]

        # 'go'-signal edge detect
        gor = Signal()
        self.sync += gor.eq(go)

        self._wrap_count = Perfcounter(ptr_read, go & ~gor)

        # wptr wrap around

        wrap = Signal()
        self.comb += wrap.eq(self.wptr == self._ring_end.storage)
        wptr_next = Signal(awidth)
        self.comb += If(wrap, wptr_next.eq(self._ring_base.storage)).Else(
            wptr_next.eq(self.wptr + 1))

        # debug

        self._debug_ctl = CSRStorage(1)
        snapshot = self._debug_ctl.re
        perf_reset = self._debug_ctl.storage[0]
        self._debug_i_stb = Perfcounter(snapshot, perf_reset)
        self._debug_i_ack = Perfcounter(snapshot, perf_reset)
        self._debug_d_stb = Perfcounter(snapshot, perf_reset)
        self._debug_d_term = Perfcounter(snapshot, perf_reset)
        self._debug_s0 = Perfcounter(snapshot, perf_reset)
        self._debug_s1 = Perfcounter(snapshot, perf_reset)
        self._debug_s2 = Perfcounter(snapshot, perf_reset)
        self._perf_busy = Perfcounter(snapshot, perf_reset)

        self.comb += If(hostif.i_stb, self._debug_i_stb.inc())
        self.comb += If(hostif.i_ack, self._debug_i_ack.inc())
        self.comb += If(hostif.d_stb, self._debug_d_stb.inc())
        self.comb += If(hostif.d_term, self._debug_d_term.inc())
        self.comb += If(~self.sdram_fifo.writable, self._perf_busy.inc())

        # FSM to move FIFO data to SDRAM

        burst_rem = Signal(max=max_burst_length)
        burst_rem_next = Signal(max=max_burst_length)

        self.comb += burst_rem_next.eq(burst_rem)
        self.sync += burst_rem.eq(burst_rem_next)

        self.comb += hostif.i_wr.eq(1)

        blocked = Signal()

        self.comb += blocked.eq(self.rptr == wptr_next)

        # start writing data if
        # - 'go'-signal set, and
        # - input data available
        # - not blocked

        self.fifo_write_fsm.act(
            "IDLE", self._debug_s0.inc(),
            If(self.sdram_fifo.readable & go & ~blocked,
               hostif.i_addr.eq(self.wptr), hostif.i_stb.eq(1),
               burst_rem_next.eq(max_burst_length - 1)),
            If(hostif.i_ack, NextState("WRITE")))

        self.comb += hostif.d_write.eq(self.sdram_fifo.dout)

        # stop writing if
        # - max burst length reached, or
        # - no more input data, or
        # - wrap
        # - blocked

        self.fifo_write_fsm.act(
            "WRITE",
            self._debug_s1.inc(),
            hostif.d_term.eq((burst_rem == 0) | ~self.sdram_fifo.readable
                             | wrap | blocked),
            self.sdram_fifo.re.eq(hostif.d_stb & ~hostif.d_term),
            If(
                ~hostif.d_term & hostif.d_stb,
                burst_rem_next.eq(
                    burst_rem -
                    1)  # CHECKME: was burst_rem_next - 1 which is a comb loop
            ),
            If(hostif.d_term & ~hostif.d_stb,
               NextState("WAIT")).Elif(hostif.d_term & hostif.d_stb,
                                       NextState("IDLE")))

        self.fifo_write_fsm.act("WAIT", self._debug_s2.inc(),
                                hostif.d_term.eq(1),
                                If(hostif.d_stb, NextState("IDLE")))

        # wrap around counter
        self.comb += If(wrap & hostif.d_stb & ~hostif.d_term,
                        self._wrap_count.inc())

        # update wptr
        self.sync += If(
            go & ~gor,
            self.wptr.eq(self._ring_base.storage),
        ).Elif((hostif.d_stb & ~hostif.d_term) | wrap, self.wptr.eq(wptr_next))

        # sink into fifo

        self.submodules.fifo_fsm = FSM()

        capture_low = Signal()
        din_low = Signal(8)

        self.comb += self.sdram_fifo.din.eq(Cat(din_low, self.sink.payload.d))

        self.sync += If(capture_low, din_low.eq(self.sink.payload.d))

        self.fifo_fsm.act("READ_LOW", capture_low.eq(1), self.sink.ack.eq(1),
                          If(self.sink.stb, NextState("READ_HI")))

        self.fifo_fsm.act(
            "READ_HI", self.sdram_fifo.we.eq(self.sink.stb),
            self.sink.ack.eq(self.sdram_fifo.writable),
            If(self.sink.ack & self.sink.stb, NextState("READ_LOW")))
Esempio n. 18
0
    def __init__(self, clk, cd_rst, ulpi_rst, ulpi_stp_ovr, ulpi_reg):

        # TESTING - UCFG_RST register
        #  - BRST: reseting of code in the ULPI cd
        #  - URST: reset of external phy
        #  - FSTP: Force assert of STP during reset
        #   (should be part of ULPI cd bringup code)
        #
        # Format:
        #
        #    7    6    5    4    3    2    1    0
        #    ---------------------------------------
        #    0    0    0    0    0    FSTP BRST URST
        #

        self._rst = CSRStorage(3)
        self.comb += ulpi_rst.eq(self._rst.storage[0])
        self.comb += cd_rst.eq(self._rst.storage[1])
        self.comb += ulpi_stp_ovr.eq(self._rst.storage[2])

        # TESTING - UCFG_STAT register
        #
        # CKACT: single status bit that indicates whether
        # the ULPI phy is providing a 60mhz clock signal on clk
        #
        # Format:
        #
        #    7    6    5    4    3    2    1    0
        #    ----------------------------------------
        #    0    0    0    0    0    0    0    CKACT
        #

        self._stat = CSRStatus(1)

        ulpi_clk_act_cd = Signal(8)

        # Resample ulpi_clk in sys
        sys_ulpi_clk = Signal(1)
        self.specials += MultiReg(clk, sys_ulpi_clk)

        # Edge detect the ULPI clk
        last_ulpi_clk = Signal(1)
        self.sync += [
            last_ulpi_clk.eq(sys_ulpi_clk),

            # On detected transistions, reset the countdown
            If(last_ulpi_clk != sys_ulpi_clk, ulpi_clk_act_cd.eq(0)).Elif(
                ulpi_clk_act_cd < 0xFF,
                ulpi_clk_act_cd.eq(ulpi_clk_act_cd + 1))
        ]

        self.comb += self._stat.status.eq(ulpi_clk_act_cd != 0xFF)

        # ULPI_xDATA and xCMD registers
        #
        # Used for reading/writing ULPI regs
        #
        # ULPI_xDATA Format: just 8 bit data reg
        #
        # ULPI_xCMD Format:
        #
        #    7    6    5    4    3    2    1    0
        #    ----------------------------------------
        #    GO   0    UA5  UA4  UA3  UA2  UA1  UA0
        #
        # GO:
        #    - write 1 to start ULPI reg transaction
        #    - stays 1 while transaction in progress
        #    - clears to 0 when transaction complete
        #
        # UA5..0 - ULPI register address

        # To do a write: write UCFG_WDATA with the value
        # and then write ULPI_WCMD with GO | addr
        #
        # To read: write ULPI_RCMD with GO | addr, poll
        # until GO clear, then read ULPI_RDATA

        self._wdata = CSRStorage(8)
        self._wcmd = _ULPI_cmd_reg(ulpi_reg.wreq, ulpi_reg.wack,
                                   ulpi_reg.waddr)
        self.submodules += self._wcmd
        self.comb += ulpi_reg.wdata.eq(self._wdata.storage)

        self._rdata = CSRStatus(8)
        self._rcmd = _ULPI_cmd_reg(ulpi_reg.rreq, ulpi_reg.rack,
                                   ulpi_reg.raddr)
        self.submodules += self._rcmd
        self.sync += If(ulpi_reg.rack, self._rdata.status.eq(ulpi_reg.rdata))
Esempio n. 19
0
 def __init__(self, snapshot, reset, bits=32):
     CSRStatus.__init__(self, bits)
     self.submodules.acc = Acc_inc_sat(bits)
     self.sync += If(snapshot, self.status.eq(self.acc.v))
     self.comb += If(reset, self.acc.set(0))
Esempio n. 20
0
    def __init__(self, depth):
        self._cfg = CSRStorage(1)

        debug_signals = 1

        storage = Memory(8, depth)
        self.specials += storage

        wrport = storage.get_port(write_capable=True)
        self.specials += wrport
        rdport = storage.get_port(async_read=False)
        self.specials += rdport

        self.submodules.consumer = Consumer(rdport, depth)
        self.submodules.producer = Producer(wrport, depth, self.consumer.pos,
                                            self._cfg.storage[0])

        self.sink = self.producer.ulpi_sink
        self.comb += self.producer.out_addr.connect(self.consumer.sink)
        self.source = self.consumer.source

        # Debug signals for state tracing
        if debug_signals:
            self._cons_lo = CSRStatus(8)
            self._cons_hi = CSRStatus(8)
            self._prod_lo = CSRStatus(8)
            self._prod_hi = CSRStatus(8)
            self._prod_hd_lo = CSRStatus(8)
            self._prod_hd_hi = CSRStatus(8)
            self._size_lo = CSRStatus(8)
            self._size_hi = CSRStatus(8)

            self._prod_state = CSRStatus(8)
            self._cons_status = CSRStatus(8)

            self._last_start_lo = CSRStatus(8)
            self._last_start_hi = CSRStatus(8)
            self._last_count_lo = CSRStatus(8)
            self._last_count_hi = CSRStatus(8)
            self._last_pw_lo = CSRStatus(8)
            self._last_pw_hi = CSRStatus(8)

            self.sync += [
                self._cons_lo.status.eq(self.consumer.pos[:8]),
                self._cons_hi.status.eq(self.consumer.pos[8:]),
                self._prod_lo.status.eq(self.producer.produce_write.v[:8]),
                self._prod_hi.status.eq(self.producer.produce_write.v[8:]),
                self._prod_hd_lo.status.eq(self.producer.produce_header.v[:8]),
                self._prod_hd_hi.status.eq(self.producer.produce_header.v[8:]),
                self._size_lo.status.eq(self.producer.size.v[:8]),
                self._size_hi.status.eq(self.producer.size.v[8:]),
                self._cons_status.status[0].eq(self.consumer.busy),
                #self._prod_state.status.eq(self.producer.fsm.state),
                If(
                    self.producer.out_addr.stb & self.producer.out_addr.ack,
                    self._last_start_lo.status.eq(
                        self.producer.out_addr.payload.start[:8]),
                    self._last_start_hi.status.eq(
                        self.producer.out_addr.payload.start[8:]),
                    self._last_count_lo.status.eq(
                        self.producer.out_addr.payload.count[:8]),
                    self._last_count_hi.status.eq(
                        self.producer.out_addr.payload.count[8:]),
                    self._last_pw_lo.status.eq(
                        self.producer.produce_write.v[:8]),
                    self._last_pw_hi.status.eq(
                        self.producer.produce_write.v[8:]),
                )
            ]
Esempio n. 21
0
    def __init__(self, width=14, signal_width=25, chain_factor_width=8):
        combined_error_signal = Signal((signal_width, True))
        self.control_signal = Signal((signal_width, True))

        s = signal_width - width

        factor_reset = 1 << (chain_factor_width - 1)
        # we use chain_factor_width + 1 for the single channel mode
        self.dual_channel = CSRStorage(1)
        self.chain_a_factor = CSRStorage(chain_factor_width + 1,
                                         reset=factor_reset)
        self.chain_b_factor = CSRStorage(chain_factor_width + 1,
                                         reset=factor_reset)

        self.chain_a_offset = CSRStorage(width)
        self.chain_b_offset = CSRStorage(width)
        self.chain_a_offset_signed = Signal((width, True))
        self.chain_b_offset_signed = Signal((width, True))
        self.combined_offset = CSRStorage(width)
        self.combined_offset_signed = Signal((width, True))
        self.out_offset = CSRStorage(width)
        self.out_offset_signed = Signal((width, True))

        self.mod_channel = CSRStorage(1)
        self.control_channel = CSRStorage(1)
        self.sweep_channel = CSRStorage(2)

        self.sync += [
            self.chain_a_offset_signed.eq(self.chain_a_offset.storage),
            self.chain_b_offset_signed.eq(self.chain_b_offset.storage),
            self.combined_offset_signed.eq(self.combined_offset.storage),
            self.out_offset_signed.eq(self.out_offset.storage)
        ]

        self.state_in = []
        self.signal_in = []
        self.state_out = []
        self.signal_out = [self.control_signal, combined_error_signal]

        self.slow_value = CSRStatus(width)

        self.submodules.mod = Modulate(width=width)
        self.submodules.sweep = SweepCSR(width=width,
                                         step_width=30,
                                         step_shift=24)
        self.submodules.limit_error_signal = LimitCSR(width=signal_width,
                                                      guard=4)
        self.submodules.limit_fast1 = LimitCSR(width=width, guard=5)
        self.submodules.limit_fast2 = LimitCSR(width=width, guard=5)
        self.submodules.pid = PID(width=signal_width)

        max_decimation = 16
        self.slow_decimation = CSRStorage(bits_for(max_decimation))

        self.comb += [
            self.sweep.clear.eq(0),
            self.sweep.hold.eq(0),
        ]

        self.comb += [
            combined_error_signal.eq(self.limit_error_signal.y),
            self.control_signal.eq(
                Array([self.limit_fast1.y, self.limit_fast2.y])[
                    self.control_channel.storage] << s),
        ]
Esempio n. 22
0
 def __init__(self, snapshot, reset, bits = 32):
     CSRStatus.__init__(self, bits)
     self.submodules.acc = Acc_inc_sat(bits)
     self.sync += If(snapshot, self.status.eq(self.acc.v))
     self.comb += If(reset, self.acc.set(0))
Esempio n. 23
0
    def __init__(self, lvds_in, _debug, sim = False):
        self._adjust = CSRStorage(16, atomic_write=True)
        self._adjust_direction = CSRStorage(1)
        
        self._adjptotal = CSRStatus(32)
        self._adjmtotal = CSRStatus(32)
        
        self._lock = CSRStatus(1)
        
        self._invert = CSRStorage(1)
        self._update_counter = CSRStorage(1)
        
        self._debug_mux = CSRStorage(8)
        
        self.submodules.adjptotal_sync = BusSynchronizer(32, "pix1x", "sys")
        self.submodules.adjmtotal_sync = BusSynchronizer(32, "pix1x", "sys")
    
        # IBUFDS        	
        lvds_se = Signal()
        if not sim:
            self.specials += Instance("IBUFDS", i_I=lvds_in[0], i_IB=lvds_in[1], o_O=lvds_se)

        debug = Signal(len(_debug))
        self.comb += _debug.eq(debug)
        
        d0 = Signal()
        self.sync.pix1x += [
            d0.eq(~d0)
        ]
        
        # SERDES
        self.i = Signal(8)
        
        self.comb += debug[0].eq(lvds_se)

        pd_valid = Signal()
        pd_incdec = Signal()
        pd_edge = Signal()
        pd_cascade = Signal()
        self.serdesstrobe = Signal()
        if not sim:
            self.specials += Instance("ISERDES2",
                                      p_SERDES_MODE="MASTER",
                                      p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=8,
                                      p_INTERFACE_TYPE="RETIMED",

                                      i_D=lvds_se,
                                      o_Q4=self.i[7], o_Q3=self.i[6], o_Q2=self.i[5], o_Q1=self.i[4],

                                      i_BITSLIP=0, i_CE0=1, i_RST=0,
                                      i_CLK0=ClockSignal("pix8x"), i_CLKDIV=ClockSignal("pix1x"),
                                      i_IOCE=self.serdesstrobe,

                                      o_VALID=pd_valid, o_INCDEC=pd_incdec,
                                      i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade)
            self.specials += Instance("ISERDES2",
                                      p_SERDES_MODE="SLAVE",
                                      p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=8,
                                      p_INTERFACE_TYPE="RETIMED",

                                      i_D=lvds_se,
                                      o_Q4=self.i[3], o_Q3=self.i[2], o_Q2=self.i[1], o_Q1=self.i[0],

                                      i_BITSLIP=0, i_CE0=1, i_RST=0,
                                      i_CLK0=ClockSignal("pix8x"), i_CLKDIV=ClockSignal("pix1x"),
                                      i_IOCE=self.serdesstrobe,
                                      i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge)

        self.lock = Signal()        
        self.submodules.sampler = ClockDomainsRenamer({"sys": "pix1x"})(Sampler())

        fifo = AsyncFIFO(28, 64)
        self.submodules.fifo = ClockDomainsRenamer(
            {"write":"pix1x", "read":"sys"})(fifo)

        self.submodules.slip = PulseSynchronizer(idomain = "sys", odomain = "pix1x")

        self.submodules.decoder = Decoder()
        
        # CDC for adjust set
        self.submodules.adjust_sync = BusSynchronizer(1 + 16, "sys", "pix1x")
        self.comb += [
            self.adjust_sync.i[-1].eq(self._adjust_direction.storage),
            self.adjust_sync.i[:16].eq(self._adjust.storage),
            self.sampler.adjust_direction.eq(self.adjust_sync.o[-1]),
            self.sampler.adjust_inc.eq(self.adjust_sync.o[:16]),
        ]
        
        self.comb += [
            # SERDES -> sampler
#            If(self._invert.storage,
#              self.sampler.i.eq(self.i[::-1]))
#            .Else(
#              self.sampler.i.eq(~self.i[::-1])),
            self.sampler.i.eq(self.i[::-1]),
            
            # sampler -> fifo
            self.fifo.din.eq(self.sampler.q),
            self.fifo.we.eq(self.sampler.s),
            self.fifo.re.eq(1),
            
            # fifo -> decoder
            self.decoder.i.eq(self.fifo.dout[::-1]),
            self.decoder.s.eq(self.fifo.readable),
            
            # decoder slip request -> pulse sync -> sampler slip
            self.slip.i.eq(self.decoder.slip),
            self.sampler.slip.eq(self.slip.o),

#            self.source.stb.eq(self.decoder.qs),
#            self.source.d.eq(self.decoder.q[24:32]),
            self.lock.eq(self.decoder.lock),
        ]
        
        # capture decoder output on decoder.qs
        self.decoder_q = Signal(32)
        self.sync += [
            If(self.decoder.qs,
              self.decoder_q.eq(self.decoder.q)
            )
        ]

#        self.comb += debug[11].eq(self.source.stb)
#        self.comb += debug[9].eq(self.lock)
        self.samplerq = Signal(28)
        self.submodules.samplerq_sync = BusSynchronizer(idomain = "pix1x", odomain = "sys", width=len(self.samplerq))
        self.comb += [
          self.samplerq_sync.i.eq(self.sampler.q),
          self.samplerq.eq(self.samplerq_sync.o)
        ]
        
        self.comb += [ 
          If(self._debug_mux.storage == 0,
              debug[1:9].eq(self.sampler.edge)).
          Elif(self._debug_mux.storage == 1,
            debug[1:9].eq(self.decoder.i[0:8])).
          Elif(self._debug_mux.storage == 2,
            debug[1:9].eq(self.decoder.i[8:16])).
          Elif(self._debug_mux.storage == 3,
            debug[1:9].eq(self.decoder.i[16:24])).
          Elif(self._debug_mux.storage == 4,
            debug[1:9].eq(self.decoder.i[24:28])).
          Elif(self._debug_mux.storage == 5,
            debug[1:9].eq(self.samplerq[0:8])).
          Elif(self._debug_mux.storage == 6,
            debug[1:9].eq(self.samplerq[8:16])).
          Elif(self._debug_mux.storage == 7,
            debug[1:9].eq(self.samplerq[16:24])).
          Elif(self._debug_mux.storage == 8,
            debug[1:9].eq(self.samplerq[24:28])).
          Elif(self._debug_mux.storage == 9,
            debug[1:9].eq(self.sampler.sr))
          ]
#        self.comb += debug[2].eq(self.sampler.numbits[0])
        self.comb += debug[0].eq(d0)

#        self.comb += debug[6].eq(self.i[0])
#        self.comb += debug[8].eq(self.sampler.s)
        self.comb += debug[10].eq(self.fifo.readable)
        self.comb += debug[11].eq(self.decoder.lock)
        self.comb += debug[12].eq(self.decoder.qs)

#        self.comb += debug[10].eq(self.sampler.phase[0])
#        self.comb += debug[11].eq(self.sampler.phase[1])
#        self.comb += debug[12].eq(self.sampler.phase[2])
        
        self.comb += self._lock.status.eq(self.decoder.lock)

        # status (via synchronizer)
        self.comb += [
            self.adjptotal_sync.i.eq(self.sampler.adjptotal),
            self.adjmtotal_sync.i.eq(self.sampler.adjmtotal),
        ]
        
        self.sync += [
            If(self._update_counter.storage, 
                self._adjptotal.status.eq(self.adjptotal_sync.o),
                self._adjmtotal.status.eq(self.adjmtotal_sync.o),
            )
        ]

        # output
        self.source = Endpoint([('d', 8)])
        
        self.submodules.fifo_read_fsm = FSM()
        self.fifo_read_fsm.act("B0",
            If (self.source.ack & self.decoder.qs & self.decoder.lock,
                NextState("B1")
            ),
            self.source.stb.eq(self.decoder.qs & self.decoder.lock,),
            self.source.payload.d.eq(Cat(self.decoder.q[8:14], self.decoder.q[15:17]))
        )

        self.fifo_read_fsm.act("B1",
            If (self.source.ack,
                NextState("B0")
            ),
            self.source.stb.eq(1),
            self.source.payload.d.eq(self.decoder_q[0:8])
        )