Пример #1
0
    def __init__(self, pad):
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(2, 2),
            rtlink.IInterface(1))
        self.overrides = []
        self.probes = []

        # # #

        sensitivity = Signal(2)

        sample = Signal()
        self.sync.rio += [
            sample.eq(0),
            If(self.rtlink.o.stb & self.rtlink.o.address[1],
                sensitivity.eq(self.rtlink.o.data),
                If(self.rtlink.o.address[0], sample.eq(1))
            )
        ]

        i = Signal()
        i_d = Signal()
        self.specials += MultiReg(pad, i, "rio_phy")
        self.sync.rio_phy += i_d.eq(i)
        self.comb += [
            self.rtlink.i.stb.eq(
                sample |
                (sensitivity[0] & ( i & ~i_d)) |
                (sensitivity[1] & (~i &  i_d))
            ),
            self.rtlink.i.data.eq(i)
        ]

        self.probes += [i]
Пример #2
0
 def __init__(self, o_width, i_width):
     self.rtlink = rtlink.Interface(
         rtlink.OInterface(o_width),
         rtlink.IInterface(i_width, timestamped=True))
     self.received_data = Signal(o_width)
     self.sync.rio_phy += If(self.rtlink.o.stb,
                             self.received_data.eq(self.rtlink.o.data))
Пример #3
0
    def __init__(self, address_width, wb=None):
        if wb is None:
            wb = wishbone.Interface()
        self.wb = wb
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(flen(wb.dat_w),
                              address_width + 1,
                              suppress_nop=False),
            rtlink.IInterface(flen(wb.dat_r), timestamped=False))

        # # #

        active = Signal()
        self.sync.rio += [
            If(self.rtlink.o.stb, active.eq(1),
               wb.adr.eq(self.rtlink.o.address[:address_width]),
               wb.we.eq(~self.rtlink.o.address[address_width]),
               wb.dat_w.eq(self.rtlink.o.data),
               wb.sel.eq(2**flen(wb.sel) - 1)),
            If(wb.ack, active.eq(0))
        ]
        self.comb += [
            self.rtlink.o.busy.eq(active),
            wb.cyc.eq(active),
            wb.stb.eq(active),
            self.rtlink.i.stb.eq(wb.ack & ~wb.we),
            self.rtlink.i.data.eq(wb.dat_r)
        ]
Пример #4
0
    def __init__(self, pins, roi_engine_count=16, res_width=12, count_shift=0):
        self.config = rtlink.Interface(
            rtlink.OInterface(res_width,
                              bits_for(4*roi_engine_count-1)))
        self.gate_data = rtlink.Interface(
            rtlink.OInterface(roi_engine_count),
            rtlink.IInterface(1+ROI.count_len(res_width, count_shift),
                              timestamped=False))

        self.submodules.deserializer = deserializer_7series.Deserializer(pins)
        self.submodules.frequency_counter = FrequencyCounter()
        self.submodules.parser = Parser(res_width)
        self.comb += self.parser.cl.eq(self.deserializer.q)
        self.roi_engines = [ROI(self.parser.pix, count_shift) for _ in range(roi_engine_count)]
        self.submodules += self.roi_engines
        self.submodules.synchronizer = Synchronizer(self.roi_engines)
        self.submodules.serializer = Serializer(self.synchronizer.update, self.synchronizer.counts,
                                                self.gate_data.i)

        for n, roi_engine in enumerate(self.roi_engines):
            for offset, target in enumerate([roi_engine.cfg.x0, roi_engine.cfg.y0,
                                             roi_engine.cfg.x1, roi_engine.cfg.y1]):
                roi_boundary = Signal.like(target)
                roi_boundary.attr.add("no_retiming")
                self.sync.rtio += If(self.config.o.stb & (self.config.o.address == 4*n+offset),
                    roi_boundary.eq(self.config.o.data))
                self.specials += MultiReg(roi_boundary, target, "cl")

        self.sync.rio += If(self.gate_data.o.stb,
            self.serializer.gate.eq(self.gate_data.o.data))
Пример #5
0
    def __init__(self, pad, pad_n=None):
        self.rtlink = rtlink.Interface(rtlink.OInterface(2, 2),
                                       rtlink.IInterface(1))
        self.overrides = []
        self.probes = []

        # # #

        sensitivity = Signal(2)

        sample = Signal()
        self.sync.rio += [
            sample.eq(0),
            If(self.rtlink.o.stb & self.rtlink.o.address[1],
               sensitivity.eq(self.rtlink.o.data),
               If(self.rtlink.o.address[0], sample.eq(1)))
        ]

        i = Signal()
        i_d = Signal(reset_less=True)
        pad_i = Signal()
        if pad_n is None:
            self.comb += pad_i.eq(pad)
        else:
            self.specials += DifferentialInput(pad, pad_n, pad_i)
        self.specials += MultiReg(pad_i, i, "rio_phy")
        self.sync.rio_phy += i_d.eq(i)
        self.comb += [
            self.rtlink.i.stb.eq(sample | (sensitivity[0] & (i & ~i_d))
                                 | (sensitivity[1] & (~i & i_d))),
            self.rtlink.i.data.eq(i)
        ]

        self.probes += [i]
Пример #6
0
    def __init__(self, pad):
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(2, 2),
            rtlink.IInterface(1))
        override_en = Signal()
        override_o = Signal()
        override_oe = Signal()
        self.overrides = [override_en, override_o, override_oe]
        self.probes = []

        # # #
        
        ts = TSTriple()
        self.specials += ts.get_tristate(pad)
        sensitivity = Signal(2)

        o_k = Signal()
        oe_k = Signal()
        self.sync.rio_phy += [
            If(self.rtlink.o.stb,
                If(self.rtlink.o.address == 0, o_k.eq(self.rtlink.o.data[0])),
                If(self.rtlink.o.address == 1, oe_k.eq(self.rtlink.o.data[0])),
            ),
            If(override_en,
                ts.o.eq(override_o),
                ts.oe.eq(override_oe)
            ).Else(
                ts.o.eq(o_k),
                ts.oe.eq(oe_k)
            )
        ]
        sample = Signal()
        self.sync.rio += [
            sample.eq(0),
            If(self.rtlink.o.stb & self.rtlink.o.address[1],
                sensitivity.eq(self.rtlink.o.data),
                If(self.rtlink.o.address[0], sample.eq(1))
            )
        ]
        
        i = Signal()
        i_d = Signal()
        self.specials += MultiReg(ts.i, i, "rio_phy")
        self.sync.rio_phy += i_d.eq(i)
        self.comb += [
            self.rtlink.i.stb.eq(
                sample |
                (sensitivity[0] & ( i & ~i_d)) |
                (sensitivity[1] & (~i &  i_d))
            ),
            self.rtlink.i.data.eq(i)
        ]

        self.probes += [i, ts.oe]
Пример #7
0
    def __init__(self, pad):
        self.rtlink = rtlink.Interface(rtlink.OInterface(2, 2),
                                       rtlink.IInterface(1))
        override_en = Signal()
        override_o = Signal()
        override_oe = Signal()
        self.overrides = [override_en, override_o, override_oe]
        self.probes = []

        # Output enable, for interfacing to external buffers.
        self.oe = Signal()
        # Registered copy of the input state, in the rio_phy clock domain.
        self.input_state = Signal()

        # # #

        ts = TSTriple()
        self.specials += ts.get_tristate(pad)
        sensitivity = Signal(2)

        o_k = Signal()
        oe_k = Signal()
        self.oe.attr.add("no_retiming")
        self.sync.rio_phy += [
            If(
                self.rtlink.o.stb,
                If(self.rtlink.o.address == 0, o_k.eq(self.rtlink.o.data[0])),
                If(self.rtlink.o.address == 1, oe_k.eq(self.rtlink.o.data[0])),
            ),
            If(override_en, ts.o.eq(override_o),
               self.oe.eq(override_oe)).Else(ts.o.eq(o_k), self.oe.eq(oe_k))
        ]
        self.comb += ts.oe.eq(self.oe)
        sample = Signal()
        self.sync.rio += [
            sample.eq(0),
            If(self.rtlink.o.stb & self.rtlink.o.address[1],
               sensitivity.eq(self.rtlink.o.data),
               If(self.rtlink.o.address[0], sample.eq(1)))
        ]

        i = Signal()
        i_d = Signal()
        self.specials += MultiReg(ts.i, i, "rio_phy")
        self.sync.rio_phy += i_d.eq(i)
        self.comb += [
            self.rtlink.i.stb.eq(sample | (sensitivity[0] & (i & ~i_d))
                                 | (sensitivity[1] & (~i & i_d))),
            self.rtlink.i.data.eq(i),
            self.input_state.eq(i)
        ]

        self.probes += [i, ts.oe]
Пример #8
0
    def __init__(self, serdes):
        serdes_width = len(serdes.o)
        assert len(serdes.i) == serdes_width
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)),
            rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width)))
        self.probes = [serdes.i[-1], serdes.oe]
        override_en = Signal()
        override_o = Signal()
        override_oe = Signal()
        self.overrides = [override_en, override_o, override_oe]

        # # #

        # Output
        self.submodules += _SerdesDriver(serdes_o=serdes.o,
                                         stb=self.rtlink.o.stb &
                                         (self.rtlink.o.address == 0),
                                         data=self.rtlink.o.data[0],
                                         fine_ts=self.rtlink.o.fine_ts,
                                         override_en=override_en,
                                         override_o=override_o)

        oe_k = Signal()
        self.sync.rio_phy += [
            If(self.rtlink.o.stb & (self.rtlink.o.address == 1),
               oe_k.eq(self.rtlink.o.data[0])),
            If(override_en, serdes.oe.eq(override_oe)).Else(serdes.oe.eq(oe_k))
        ]

        # Input
        sensitivity = Signal(2)
        sample = Signal()
        self.sync.rio += [
            sample.eq(0),
            If(self.rtlink.o.stb & self.rtlink.o.address[1],
               sensitivity.eq(self.rtlink.o.data),
               If(self.rtlink.o.address[0], sample.eq(1)))
        ]

        i = serdes.i[-1]
        i_d = Signal()
        self.sync.rio_phy += [
            i_d.eq(i),
            self.rtlink.i.stb.eq(sample | (sensitivity[0] & (i & ~i_d))
                                 | (sensitivity[1] & (~i & i_d))),
            self.rtlink.i.data.eq(i),
        ]

        pe = PriorityEncoder(serdes_width)
        self.submodules += pe
        self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width))
        self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o)
Пример #9
0
    def __init__(self, regs, name, identifier=None):
        self.name = name
        self.regs = regs

        data_width = max([x[1] for x in regs])

        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=data_width,
                              address_width=len(regs).bit_length() + 1),
            rtlink.IInterface(data_width=data_width, timestamped=False))

        write_enable = self.rtlink.o.address[0]
        address = self.rtlink.o.address[1:]

        data_signals_list = []
        for idx, r in enumerate(regs):
            if len(r) > 2:
                reset_value = r[2]
            else:
                reset_value = 0
            if len(r) > 3:
                mode = r[3]
            else:
                mode = "rw"
            signal = Signal(bits_sign=r[1], name=r[0], reset=reset_value)
            setattr(self, r[0], signal)
            data_signals_list.append(signal)

            if mode == "rw":
                ld_signal_name = r[0] + "_ld"
                setattr(self, ld_signal_name,
                        Signal(bits_sign=1, name=ld_signal_name))
                ld_signal = getattr(self, ld_signal_name)
                self.sync.rio_phy += [
                    ld_signal.eq(0),
                    If(self.rtlink.o.stb & write_enable & (address == idx),
                       signal.eq(self.rtlink.o.data), ld_signal.eq(1))
                ]

        data_signals = Array(data_signals_list)
        self.sync.rio_phy += [
            self.rtlink.i.stb.eq(0),
            If(self.rtlink.o.stb & ~write_enable, self.rtlink.i.stb.eq(1),
               self.rtlink.i.data.eq(data_signals[address]))
        ]

        if identifier is not None:
            self.add_rtio_channels(channel=Channel.from_phy(self),
                                   device_id=identifier,
                                   module="elhep_cores.coredevice.rtlink_csr",
                                   class_name="RtlinkCsr",
                                   arguments={"regs": regs})
Пример #10
0
    def __init__(self):
        self.rtlink = rtlink.Interface(rtlink.OInterface(1),
                                       rtlink.IInterface(1))
        self.overrides = []
        self.probes = []

        # # #

        counter = Signal(2)
        trigger = Signal()
        self.sync += [
            Cat(counter, trigger).eq(counter + 1),
            self.rtlink.i.stb.eq(0),
            If(trigger, self.rtlink.i.stb.eq(1),
               self.rtlink.i.data.eq(~self.rtlink.i.data))
        ]
Пример #11
0
    def _add_rtlink(self):
        # Address 0: enabled
        # Address 1: pulse length
        # Address 2: mask

        mask_adr_no = (len(self.mask) + 31) // 32
        adr_width = len(Signal(max=mask_adr_no + 1)) + 2

        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=32, address_width=adr_width),
            rtlink.IInterface(data_width=32, timestamped=False))

        self.rtlink_address = rtlink_address = Signal.like(
            self.rtlink.o.address)
        self.rtlink_wen = rtlink_wen = Signal()
        self.comb += [
            rtlink_address.eq(self.rtlink.o.address[1:]),
            rtlink_wen.eq(self.rtlink.o.address[0]),
        ]

        mask_array = self.signal_to_array(self.mask)

        self.sync.rio_phy += [
            self.rtlink.i.stb.eq(0),
            If(
                self.rtlink.o.stb,
                # Write
                If(rtlink_wen & (rtlink_address == 0),
                   self.enabled.eq(self.rtlink.o.data[0])).Elif(
                       rtlink_wen & (rtlink_address == 1),
                       self.pulse_length.eq(self.rtlink.o.data)).Elif(
                           rtlink_wen & (rtlink_address >= 2),
                           mask_array[rtlink_address - 2].eq(
                               self.rtlink.o.data)).
                # Readout
                Elif(~rtlink_wen & (rtlink_address == 0),
                     self.rtlink.i.data.eq(self.enabled),
                     self.rtlink.i.stb.eq(1)).Elif(
                         ~rtlink_wen & (rtlink_address == 1),
                         self.rtlink.i.data.eq(self.pulse_length),
                         self.rtlink.i.stb.eq(1)).Elif(
                             ~rtlink_wen & (rtlink_address >= 2),
                             self.rtlink.i.data.eq(mask_array[rtlink_address -
                                                              2]),
                             self.rtlink.i.stb.eq(1)))
        ]
Пример #12
0
    def __init__(self, servo):
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=32, address_width=8,
                enable_replace=False),
            rtlink.IInterface(data_width=32))
        
        ###
        
        # reg addresses - starts with R/!W
        cases = {
            # control/config reg - rst, afe, dac_clr
            0x00: servo.ctrl[:4].eq(self.rtlink.o.data),
            # enable channels
            0x01: servo.ctrl[4:6].eq(self.rtlink.o.data),
            # enable ADC AFE X10 gain
            0x02: servo.ctrl[6:].eq(self.rtlink.o.data),
            # set dac
            0x03: servo.mode.eq(self.rtlink.o.data[-2:]), servo.dac_data.eq(self.rtlink.o.data[:-2])
            # init/status reg
            0x04: servo.init,
            # adc data
            0x05: servo.adc_data,
        }


        input_data = Signal(32, reset_less=True)

        self.sync.rio_phy += [
            If(self.rtlink.o.stb & ~self.rtlink.o.address[-1],
                Case(self.rtlink.o.address[:-1], cases)
            ),
            If(self.rtlink.i.stb,
                input_data.eq(Case(self.rtlink.o.address[:-1], cases))
            )
        ]

        self.comb += [
            self.rtlink.i.stb.eq(self.rtlink.o.stb & self.rtlink.o.address[-1]),
            self.rtlink.i.data.eq(input_data),
        ]
Пример #13
0
    def __init__(self,
                 address_width,
                 wb=None,
                 rtio_enable_replace=False,
                 write_only=False):
        if wb is None:
            wb = wishbone.Interface()
        self.wb = wb
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(len(wb.dat_w),
                              address_width +
                              1 if not write_only else address_width,
                              enable_replace=rtio_enable_replace),
            rtlink.IInterface(len(wb.dat_r), timestamped=False)
            if not write_only else None)

        # # #

        active = Signal()
        self.sync.rio += [
            If(
                self.rtlink.o.stb, active.eq(1),
                wb.adr.eq(self.rtlink.o.address[:address_width]),
                wb.we.eq(~self.rtlink.o.address[address_width]
                         if not write_only else 1),
                wb.dat_w.eq(self.rtlink.o.data),
                wb.sel.eq(2**len(wb.sel) - 1)),
            If(wb.ack, active.eq(0))
        ]
        self.comb += [
            self.rtlink.o.busy.eq(active),
            wb.cyc.eq(active),
            wb.stb.eq(active),
        ]

        if not write_only:
            self.comb += [
                self.rtlink.i.stb.eq(wb.ack & ~wb.we),
                self.rtlink.i.data.eq(wb.dat_r)
            ]
Пример #14
0
    def __init__(self,
                 data_i,
                 stb_i,
                 trigger_dclk,
                 trigger_id_dclk=None,
                 circular_buffer_length=128):

        iiface_width = len(data_i) + len(trigger_id_dclk)
        assert iiface_width <= 32, f"Data width summarized with trigger " \
            "ID width ({iiface_width}) must be <= 32"

        self.data_i = data_i
        pretrigger_rio_phy = Signal(max=circular_buffer_length)
        posttrigger_rio_phy = Signal.like(pretrigger_rio_phy)
        pretrigger_dclk = Signal.like(pretrigger_rio_phy)
        posttrigger_dclk = Signal.like(posttrigger_rio_phy)

        # Interface - rtlink
        self.rtlink = rtlink_iface = rtlink.Interface(
            rtlink.OInterface(data_width=len(pretrigger_rio_phy),
                              address_width=1),
            rtlink.IInterface(data_width=iiface_width, timestamped=False))

        self.sync.rio_phy += [
            If(
                rtlink_iface.o.stb,
                If(self.rtlink.o.address == 0,
                   pretrigger_rio_phy.eq(rtlink_iface.o.data)),
                If(self.rtlink.o.address == 1,
                   posttrigger_rio_phy.eq(rtlink_iface.o.data)),
            )
        ]

        # We're embedding stb into data stream going into the cyclic buffer
        cb_data_in = Signal(len(data_i) + 1)
        self.comb += [cb_data_in.eq(Cat(stb_i, data_i))]

        self.cbuf = circular_buffer = ClockDomainsRenamer({"sys": "dclk"})(
            TriggeredCircularBuffer(data_width=len(cb_data_in),
                                    trigger_id_width=len(trigger_id_dclk),
                                    length=circular_buffer_length))
        async_fifo = ClockDomainsRenamer({
            "write": "dclk",
            "read": "rio_phy"
        })(AsyncFIFOBuffered(width=len(circular_buffer.data_out), depth=16))
        trigger_cdc = PulseSynchronizer("rio_phy", "dclk")
        pretrigger_cdc = MultiReg(pretrigger_rio_phy, pretrigger_dclk, "dclk")
        posttrigger_cdc = MultiReg(posttrigger_rio_phy, posttrigger_dclk,
                                   "dclk")
        self.submodules += [circular_buffer, async_fifo, trigger_cdc]
        self.specials += [pretrigger_cdc, posttrigger_cdc]

        self.comb += [
            circular_buffer.data_in.eq(cb_data_in),
            circular_buffer.we.eq(1),
            circular_buffer.trigger.eq(trigger_dclk),
            circular_buffer.trigger_id.eq(trigger_id_dclk),
            circular_buffer.pretrigger.eq(pretrigger_dclk),
            circular_buffer.posttrigger.eq(posttrigger_dclk),
            async_fifo.din.eq(circular_buffer.data_out),
            async_fifo.re.eq(async_fifo.readable),
            async_fifo.we.eq(circular_buffer.stb_out),
            rtlink_iface.i.data.eq(async_fifo.dout[1:]),
            rtlink_iface.i.stb.eq(
                async_fifo.dout[0]
                & async_fifo.readable)  # stb if there is data and frame
        ]
Пример #15
0
    def __init__(self, pins, pins_n, log2_width=0):
        width = 1 << log2_width
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=max(16 * width, 32),
                              address_width=8,
                              enable_replace=False),
            rtlink.IInterface(data_width=32))

        self.submodules.serializer = SerDes(pins, pins_n)

        # Support staging DAC data (in `dacs`) by writing to the
        # DAC RTIO addresses, if a channel is not "held" by its
        # bit in `hold` the next frame will contain the update.
        # For the DACs held, the update is triggered by setting the
        # corresponding bit in `update`. Update is self-clearing.
        # This enables atomic DAC updates synchronized to a frame edge.
        #
        # The `log2_width=0` RTIO layout uses one DAC channel per RTIO address
        # and a dense RTIO address space. The RTIO words are narrow.
        # (32 bit compared to 512) and few-channel updates are efficient.
        # There is the least amount of DAC state tracking in kernels,
        # at the cost of more DMA and RTIO data ((n*(32+32+64) vs
        # 32+32*16+64))
        #
        # Other `log2_width` (up to `log2_width=5) settings pack multiple
        # (in powers of two) DAC channels into one group and
        # into one RTIO write.
        # The RTIO data width increases accordingly. The `log2_width`
        # LSBs of the RTIO address for a DAC channel write must be zero and the
        # address space is sparse.

        hold = Signal.like(self.serializer.enable)

        # TODO: stb, timestamp
        read_regs = Array(
            [self.serializer.dat_r[i * 7:(i + 1) * 7] for i in range(1 << 4)])

        cases = {
            # update
            0x20:
            self.serializer.enable.eq(self.serializer.enable
                                      | self.rtlink.o.data),
            # hold
            0x21:
            hold.eq(self.rtlink.o.data),
            # cfg
            0x22:
            self.serializer.cfg[:4].eq(self.rtlink.o.data),
            # leds
            0x23:
            self.serializer.cfg[4:12].eq(self.rtlink.o.data),
            # reserved
            0x24:
            self.serializer.cfg[12:].eq(self.rtlink.o.data),
        }
        for i in range(0, len(self.serializer.dacs), width):
            cases[i] = [
                Cat(self.serializer.dacs[i:i + width]).eq(self.rtlink.o.data),
                [
                    If(
                        ~hold[i + j],
                        self.serializer.enable[i + j].eq(1),
                    ) for j in range(width)
                ]
            ]

        self.sync.rio_phy += [
            If(
                self.serializer.stb,
                self.serializer.enable.eq(0),
            ),
            If(
                self.rtlink.o.stb & ~self.rtlink.o.address[-1],
                Case(self.rtlink.o.address[:-1], cases),
            ),
        ]

        self.sync.rtio += [
            self.rtlink.i.stb.eq(self.rtlink.o.stb
                                 & self.rtlink.o.address[-1]),
            self.rtlink.i.data.eq(read_regs[self.rtlink.o.address[:-1]]),
        ]
Пример #16
0
    def __init__(self, pins, pins_n):
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=32, address_width=8,
                enable_replace=False),
            rtlink.IInterface(data_width=32))

        self.submodules.serializer = SerDes(pins, pins_n)

        # Support staging DAC data (in `dacs`) by writing to the
        # 32 DAC RTIO addresses, if a channel is not "held" by its
        # bit in `hold` the next frame will contain the update.
        # For the DACs held, the update is triggered by setting the
        # corresponding bit in `update`. Update is self-clearing.
        # This enables atomic DAC updates synchronized to a frame edge.
        #
        # This RTIO layout enables narrow RTIO words (32 bit
        # compared to 512), efficient few-channel updates,
        # least amount of DAC state tracking in kernels,
        # at the cost of more DMA and RTIO data ((n*(32+32+64) vs
        # 32+32*16+64))

        hold = Signal.like(self.serializer.enable)

        # TODO: stb, timestamp
        read_regs = Array([
            self.serializer.dat_r[i*7:(i + 1)*7]
            for i in range(1 << 4)
        ])

        cases = {
            # update
            0x20: self.serializer.enable.eq(self.serializer.enable | self.rtlink.o.data),
            # hold
            0x21: hold.eq(self.rtlink.o.data),
            # cfg
            0x22: self.serializer.cfg[:4].eq(self.rtlink.o.data),
            # leds
            0x23: self.serializer.cfg[4:12].eq(self.rtlink.o.data),
            # reserved
            0x24: self.serializer.cfg[12:].eq(self.rtlink.o.data),
        }
        for i in range(len(self.serializer.dacs)):
            cases[i] = [
                self.serializer.dacs[i].eq(self.rtlink.o.data),
                If(~hold[i],
                    self.serializer.enable[i].eq(1),
                )
            ]

        self.sync.rio_phy += [
            If(self.serializer.stb,
                self.serializer.enable.eq(0),
            ),
            If(self.rtlink.o.stb & ~self.rtlink.o.address[-1],
                Case(self.rtlink.o.address[:-1], cases),
            ),
        ]

        self.sync.rtio += [
            self.rtlink.i.stb.eq(self.rtlink.o.stb &
                self.rtlink.o.address[-1]),
            self.rtlink.i.data.eq(
                read_regs[self.rtlink.o.address[:-1]]),
        ]
Пример #17
0
    def __init__(self, pins):
        self.config = rtlink.Interface(rtlink.OInterface(10))
        self.gate_data = rtlink.Interface(rtlink.OInterface(1),
                                          rtlink.IInterface(10))

        self.submodules.deserializer = deserializer_7series.Deserializer(pins)
Пример #18
0
    def __init__(self, pins, pins_n, log2_width=0):
        width = 1 << log2_width
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=max(16 * width, 32),
                              address_width=8,
                              enable_replace=False),
            rtlink.IInterface(data_width=14))

        self.submodules.serializer = SerDes(n_data=8,
                                            t_clk=7,
                                            d_clk=0b1100011,
                                            n_frame=14,
                                            n_crc=12,
                                            poly=0x80f)
        self.submodules.intf = SerInterface(pins, pins_n)
        self.comb += [
            Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])),
            self.serializer.data[-1].eq(self.intf.data[-1]),
        ]

        # dac data words
        dacs = [Signal(16) for i in range(32)]

        header = Record([
            ("cfg", 4),
            ("leds", 8),
            ("typ", 1),
            ("reserved", 7),
            ("addr", 4),
            ("enable", len(dacs)),
        ])
        assert len(Cat(header.raw_bits(),
                       dacs)) == len(self.serializer.payload)

        # # #

        # Support staging DAC data (in `dacs`) by writing to the
        # DAC RTIO addresses, if a channel is not "held" by its
        # bit in `hold` the next frame will contain the update.
        # For the DACs held, the update is triggered by setting the
        # corresponding bit in `update`. Update is self-clearing.
        # This enables atomic DAC updates synchronized to a frame edge.
        #
        # The `log2_width=0` RTIO layout uses one DAC channel per RTIO address
        # and a dense RTIO address space. The RTIO words are narrow.
        # (32 bit compared to 512) and few-channel updates are efficient.
        # There is the least amount of DAC state tracking in kernels,
        # at the cost of more DMA and RTIO data ((n*(32+32+64) vs
        # 32+32*16+64))
        #
        # Other `log2_width` (up to `log2_width=5) settings pack multiple
        # (in powers of two) DAC channels into one group and
        # into one RTIO write.
        # The RTIO data width increases accordingly. The `log2_width`
        # LSBs of the RTIO address for a DAC channel write must be zero and the
        # address space is sparse.

        hold = Signal.like(header.enable)
        continuous = Signal.like(header.enable)
        cic_config = Signal(16)

        read_regs = Array([
            Signal.like(self.serializer.readback)
            for _ in range(1 << len(header.addr))
        ])

        cases = {
            # update
            0x20: [
                header.enable.eq(self.rtlink.o.data),
                header.typ.eq(0),
            ],
            # hold
            0x21: hold.eq(self.rtlink.o.data),
            # cfg
            0x22: header.cfg.eq(self.rtlink.o.data),
            # leds
            0x23: header.leds.eq(self.rtlink.o.data),
            # reserved bits
            0x24: header.reserved.eq(self.rtlink.o.data),
            # force continuous DAC updates
            0x25: continuous.eq(self.rtlink.o.data),
            # interpolator configuration stage
            0x26: cic_config.eq(self.rtlink.o.data),
            # interpolator update flags
            0x27: [
                header.enable.eq(self.rtlink.o.data),
                header.typ.eq(1),
            ],
        }
        for i in range(0, len(dacs), width):
            cases[i] = [
                Cat(dacs[i:i + width]).eq(self.rtlink.o.data),
                [
                    If(
                        ~hold[i + j] & (header.typ == 0),
                        header.enable[i + j].eq(1),
                    ) for j in range(width)
                ]
            ]

        self.comb += [
            If(
                header.typ == 0,
                self.serializer.payload.eq(Cat(header.raw_bits(), dacs)),
            ).Else(
                self.serializer.payload.eq(
                    Cat(header.raw_bits(), Replicate(cic_config,
                                                     len(dacs)))), ),
        ]

        self.sync.rio_phy += [
            If(
                self.serializer.stb,
                header.typ.eq(0),
                header.enable.eq(continuous),
                read_regs[header.addr].eq(self.serializer.readback),
                header.addr.eq(header.addr + 1),
            ),
            If(
                self.rtlink.o.stb,
                Case(self.rtlink.o.address, cases),
            ),
        ]

        self.sync.rtio += [
            self.rtlink.i.stb.eq(self.rtlink.o.stb
                                 & self.rtlink.o.address[-1]),
            self.rtlink.i.data.eq(read_regs[self.rtlink.o.address[:-1]]),
        ]
Пример #19
0
    def __init__(self, serdes):
        serdes_width = len(serdes.o)
        assert len(serdes.i) == serdes_width
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)),
            rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width)))
        self.probes = [serdes.i[-1], serdes.oe]
        override_en = Signal()
        override_o = Signal()
        override_oe = Signal()
        self.overrides = [override_en, override_o, override_oe]

        # Output enable, for interfacing to external buffers.
        self.oe = Signal()
        # input state exposed for edge_counter: latest serdes sample
        # support for short pulses will need a more involved solution
        self.input_state = Signal()

        # # #

        # Output
        self.submodules += _SerdesDriver(serdes_o=serdes.o,
                                         stb=self.rtlink.o.stb &
                                         (self.rtlink.o.address == 0),
                                         data=self.rtlink.o.data[0],
                                         fine_ts=self.rtlink.o.fine_ts,
                                         override_en=override_en,
                                         override_o=override_o)

        oe_k = Signal()
        self.oe.attr.add("no_retiming")
        self.sync.rio_phy += [
            If(self.rtlink.o.stb & (self.rtlink.o.address == 1),
               oe_k.eq(self.rtlink.o.data[0])),
            If(override_en, self.oe.eq(override_oe)).Else(self.oe.eq(oe_k))
        ]
        self.comb += serdes.oe.eq(self.oe)

        # Input
        sensitivity = Signal(2)
        sample = Signal()
        self.sync.rio += [
            sample.eq(0),
            If(self.rtlink.o.stb & self.rtlink.o.address[1],
               sensitivity.eq(self.rtlink.o.data),
               If(self.rtlink.o.address[0], sample.eq(1)))
        ]

        i = serdes.i[-1]
        self.comb += self.input_state.eq(i)
        i_d = Signal()
        self.sync.rio_phy += [
            i_d.eq(i),
            self.rtlink.i.data.eq(i),
        ]

        pe = PriorityEncoder(serdes_width)
        self.submodules += pe
        self.comb += pe.i.eq((serdes.i ^ Cat(i_d, serdes.i)) & (
            (serdes.i & Replicate(sensitivity[0], serdes_width))
            | (~serdes.i & Replicate(sensitivity[1], serdes_width))))
        self.sync.rio_phy += [
            self.rtlink.i.fine_ts.eq(pe.o),
            self.rtlink.i.stb.eq(sample | ~pe.n),
        ]
Пример #20
0
    def __init__(self, w, servo):
        m_coeff = servo.iir.m_coeff.get_port(write_capable=True,
                                             mode=READ_FIRST,
                                             we_granularity=w.coeff,
                                             clock_domain="rio")
        assert len(m_coeff.we) == 2
        m_state = servo.iir.m_state.get_port(
            write_capable=True,
            # mode=READ_FIRST,
            clock_domain="rio")
        self.specials += m_state, m_coeff

        # just expose the w.coeff (18) MSBs of state
        assert w.state >= w.coeff
        # ensure that we can split the coefficient storage correctly
        assert len(m_coeff.dat_w) == 2 * w.coeff
        # ensure that the DDS word data fits into the coefficient mem
        assert w.coeff >= w.word

        # coeff, profile, channel, 2 mems, rw
        # this exceeds the 8-bit RTIO address, so we move the extra ("overflow")
        # address bits into data.
        internal_address_width = 3 + w.profile + w.channel + 1 + 1
        rtlink_address_width = min(8, internal_address_width)
        overflow_address_width = internal_address_width - rtlink_address_width
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=overflow_address_width + w.coeff,
                              address_width=rtlink_address_width,
                              enable_replace=False),
            rtlink.IInterface(data_width=w.coeff, timestamped=False))

        # # #

        config = Signal(w.coeff, reset=0)
        status = Signal(w.coeff)
        pad = Signal(6)
        self.comb += [
            Cat(servo.start).eq(config),
            status.eq(
                Cat(servo.start, servo.done, pad,
                    [_.clip for _ in servo.iir.ctrl]))
        ]

        assert len(self.rtlink.o.address) + len(
            self.rtlink.o.data) - w.coeff == (
                1 +  # we
                1 +  # state_sel
                1 +  # high_coeff
                len(m_coeff.adr))
        # ensure that we can fit config/status into the state address space
        assert len(self.rtlink.o.address) + len(
            self.rtlink.o.data) - w.coeff >= (
                1 +  # we
                1 +  # state_sel
                1 +  # config_sel
                len(m_state.adr))

        internal_address = Signal(internal_address_width)
        self.comb += internal_address.eq(
            Cat(self.rtlink.o.address, self.rtlink.o.data[w.coeff:]))

        coeff_data = Signal(w.coeff)
        self.comb += coeff_data.eq(self.rtlink.o.data[:w.coeff])

        we = internal_address[-1]
        state_sel = internal_address[-2]
        config_sel = internal_address[-3]
        high_coeff = internal_address[0]
        self.comb += [
            self.rtlink.o.busy.eq(0),
            m_coeff.adr.eq(internal_address[1:]),
            m_coeff.dat_w.eq(Cat(coeff_data, coeff_data)),
            m_coeff.we[0].eq(self.rtlink.o.stb & ~high_coeff & we
                             & ~state_sel),
            m_coeff.we[1].eq(self.rtlink.o.stb & high_coeff & we & ~state_sel),
            m_state.adr.eq(internal_address),
            m_state.dat_w[w.state - w.coeff:].eq(self.rtlink.o.data),
            m_state.we.eq(self.rtlink.o.stb & we & state_sel & ~config_sel),
        ]
        read = Signal()
        read_state = Signal()
        read_high = Signal()
        read_config = Signal()
        self.sync.rio += [
            If(read, read.eq(0)),
            If(
                self.rtlink.o.stb,
                read.eq(~we),
                read_state.eq(state_sel),
                read_high.eq(high_coeff),
                read_config.eq(config_sel),
            )
        ]
        self.sync.rio_phy += [
            If(self.rtlink.o.stb & we & state_sel & config_sel,
               config.eq(self.rtlink.o.data)),
            If(read & read_config & read_state,
               [_.clip.eq(0) for _ in servo.iir.ctrl])
        ]
        self.comb += [
            self.rtlink.i.stb.eq(read),
            self.rtlink.i.data.eq(
                Mux(
                    read_state,
                    Mux(read_config, status,
                        m_state.dat_r[w.state - w.coeff:]),
                    Mux(read_high, m_coeff.dat_r[w.coeff:],
                        m_coeff.dat_r[:w.coeff])))
        ]
Пример #21
0
    def __init__(self, pins, pins_n):
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=8,
                              address_width=8,
                              enable_replace=False),
            rtlink.IInterface(data_width=10))

        # share a CosSinGen LUT between the two channels
        self.submodules.ch0 = DDSChannel()
        self.submodules.ch1 = DDSChannel(share_lut=self.ch0.dds.cs.lut)
        n_channels = 2
        n_samples = 8
        n_bits = 14
        body = Signal(n_samples * n_channels * 2 * n_bits, reset_less=True)
        self.sync.rio_phy += [
            If(
                self.ch0.dds.valid,  # & self.ch1.dds.valid,
                # recent:ch0:i as low order in body
                Cat(body).eq(
                    Cat(self.ch0.dds.o.i[2:], self.ch0.dds.o.q[2:],
                        self.ch1.dds.o.i[2:], self.ch1.dds.o.q[2:], body)),
            ),
        ]

        self.submodules.serializer = SerDes(n_data=8,
                                            t_clk=8,
                                            d_clk=0b00001111,
                                            n_frame=10,
                                            n_crc=6,
                                            poly=0x2f)
        self.submodules.intf = SerInterface(pins, pins_n)
        self.comb += [
            Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])),
            self.serializer.data[-1].eq(self.intf.data[-1]),
        ]

        header = Record([("we", 1), ("addr", 7), ("data", 8), ("type", 4)])
        assert len(Cat(header.raw_bits(), body)) == \
                len(self.serializer.payload)
        self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body))

        re_dly = Signal(3)  # stage, send, respond
        self.sync.rtio += [
            header.type.eq(1),  # body type is baseband data
            If(
                self.serializer.stb,
                self.ch0.dds.stb.eq(1),  # synchronize
                self.ch1.dds.stb.eq(1),  # synchronize
                header.we.eq(0),
                re_dly.eq(re_dly[1:]),
            ),
            If(
                self.rtlink.o.stb,
                re_dly[-1].eq(~self.rtlink.o.address[-1]),
                header.we.eq(self.rtlink.o.address[-1]),
                header.addr.eq(self.rtlink.o.address),
                header.data.eq(self.rtlink.o.data),
            ),
            self.rtlink.i.stb.eq(re_dly[0] & self.serializer.stb),
            self.rtlink.i.data.eq(self.serializer.readback),
        ]
Пример #22
0
    def __init__(self, pads, pads_n=None):
        to_rio_phy = ClockDomainsRenamer("rio_phy")
        if pads_n is None:
            interface = SPIInterface(pads)
        else:
            interface = SPIInterfaceXC7Diff(pads, pads_n)
        interface = to_rio_phy(interface)
        spi = to_rio_phy(SPIMachine(data_width=32, div_width=8))
        self.submodules += interface, spi

        self.rtlink = rtlink.Interface(
            rtlink.OInterface(len(spi.reg.pdo),
                              address_width=1,
                              enable_replace=False),
            rtlink.IInterface(len(spi.reg.pdi), timestamped=False))

        ###

        config = Record([
            ("offline", 1),
            ("end", 1),
            ("input", 1),
            ("cs_polarity", 1),
            ("clk_polarity", 1),
            ("clk_phase", 1),
            ("lsb_first", 1),
            ("half_duplex", 1),
            ("length", 5),
            ("padding", 3),
            ("div", 8),
            ("cs", 8),
        ])
        assert len(config) == len(spi.reg.pdo) == len(spi.reg.pdi) == 32

        config.offline.reset = 1
        config.end.reset = 1
        read = Signal()

        self.sync.rio += [
            If(self.rtlink.i.stb, read.eq(0)),
            If(
                self.rtlink.o.stb & spi.writable,
                If(self.rtlink.o.address,
                   config.raw_bits().eq(self.rtlink.o.data)).Else(
                       read.eq(config.input))),
        ]

        self.comb += [
            spi.length.eq(config.length),
            spi.end.eq(config.end),
            spi.cg.div.eq(config.div),
            spi.clk_phase.eq(config.clk_phase),
            spi.reg.lsb_first.eq(config.lsb_first),
            interface.half_duplex.eq(config.half_duplex),
            interface.cs.eq(config.cs),
            interface.cs_polarity.eq(
                Replicate(config.cs_polarity, len(interface.cs_polarity))),
            interface.clk_polarity.eq(config.clk_polarity),
            interface.offline.eq(config.offline),
            interface.cs_next.eq(spi.cs_next),
            interface.clk_next.eq(spi.clk_next),
            interface.ce.eq(spi.ce),
            interface.sample.eq(spi.reg.sample),
            spi.reg.sdi.eq(interface.sdi),
            interface.sdo.eq(spi.reg.sdo),
            spi.load.eq(self.rtlink.o.stb & spi.writable
                        & ~self.rtlink.o.address),
            spi.reg.pdo.eq(self.rtlink.o.data),
            self.rtlink.o.busy.eq(~spi.writable),
            self.rtlink.i.stb.eq(spi.readable & read),
            self.rtlink.i.data.eq(spi.reg.pdi)
        ]
        self.probes = []
Пример #23
0
    def __init__(self, core_link_pads, output_pads, passthrough_sigs, input_phys, simulate=False):
        """
        core_link_pads: EEM pads for inter-Kasli link
        output_pads: pads for 4 output signals (422sigma, 1092, 422 ps trigger, aux)
        passthrough_sigs: signals from output phys, connected to output_pads when core
            not running
        input_phys: serdes phys for 5 inputs – APD0-3 and 422ps trigger in
        """

        event_counter_width = 14
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(
                data_width=32,
                address_width=6,
                enable_replace=False),
            rtlink.IInterface(
                data_width=max(14, event_counter_width),
                timestamped=True)
            )

        # # #


        self.submodules.core = ClockDomainsRenamer("rio")(EntanglerCore(
            core_link_pads, output_pads, passthrough_sigs, input_phys,
            event_counter_width, simulate=simulate))

        read_en = self.rtlink.o.address[5]
        write_timings = Signal()
        write_patterns = Signal()
        self.comb += [
            self.rtlink.o.busy.eq(0),
            write_timings.eq(self.rtlink.o.address[3:6] == 1),
            write_patterns.eq(self.rtlink.o.address[3:6] == 2),
        ]

        output_t_starts = [seq.m_start for seq in self.core.sequencers]
        output_t_ends = [seq.m_stop for seq in self.core.sequencers]
        output_t_starts += [gater.gate_start for gater in self.core.apd_gaters]
        output_t_ends += [gater.gate_stop for gater in self.core.apd_gaters]
        write_timing_cases = {}
        for i in range(len(output_t_starts)):
            write_timing_cases[i] = [output_t_starts[i].eq(self.rtlink.o.data[:16]),
                        output_t_ends[i].eq(self.rtlink.o.data[16:])]

        # Write timeout counter and start core running
        self.comb += [
            self.core.msm.time_remaining_buf.eq(self.rtlink.o.data),
            self.core.msm.run_stb.eq( (self.rtlink.o.address==1) & self.rtlink.o.stb )
        ]

        self.sync.rio += [
            If(write_timings & self.rtlink.o.stb,
               Case(self.rtlink.o.address[:3], write_timing_cases)
            ),
            If(write_patterns & self.rtlink.o.stb,
                Cat(
                    *Array(p.patterns for p in self.core.pattern_counters)[
                        self.rtlink.o.address[:3]]).eq(self.rtlink.o.data)
            ),
            If((self.rtlink.o.address == 0) & self.rtlink.o.stb,
                # Write config
                self.core.enable.eq(self.rtlink.o.data[0]),
                self.core.msm.standalone.eq(self.rtlink.o.data[2]),
            ),
            If((self.rtlink.o.address == 2) & self.rtlink.o.stb,
                # Write cycle length
                self.core.msm.m_end.eq(self.rtlink.o.data[:10])
            ),
            If((self.rtlink.o.address == 3) & self.rtlink.o.stb,
                # Write herald patterns and enables
                *[
                    self.core.heralder.patterns[i].eq(
                        self.rtlink.o.data[4 * i:4 * (i + 1)]) for i in range(4)
                ],
                self.core.heralder.pattern_ens.eq(self.rtlink.o.data[16:20])
            ),
        ]

        # Write is_master bit in rio_phy reset domain to not break 422ps trigger
        # forwarding on core.reset().
        self.sync.rio_phy += If((self.rtlink.o.address == 0) & self.rtlink.o.stb,
            self.core.msm.is_master.eq(self.rtlink.o.data[1])
        )


        read = Signal()
        read_counters = Signal()
        read_timestamps = Signal()
        read_addr = Signal(3)

        # Input timestamps are [apd0, apd1, apd2, apd3, ref]
        input_timestamps = [gater.sig_ts for gater in self.core.apd_gaters]
        input_timestamps.append(self.core.apd_gaters[0].ref_ts)
        cases = {}
        timing_data = Signal(14)
        for i, ts in enumerate(input_timestamps):
            cases[i] = [timing_data.eq(ts)]
        self.comb += Case(read_addr, cases)


        self.sync.rio += [
                If(read,
                    read.eq(0)
                ),
                If(self.rtlink.o.stb,
                    read.eq(read_en),
                    read_counters.eq(self.rtlink.o.address[3:5] == 0b10),
                    read_timestamps.eq(self.rtlink.o.address[3:5] == 0b01),
                    read_addr.eq(self.rtlink.o.address[:3]),
                )
        ]

        status = Signal(3)
        self.comb += status.eq(Cat(self.core.msm.ready,
                                   self.core.msm.success,
                                   self.core.msm.timeout))

        reg_data = Signal(event_counter_width)
        cases = {}
        cases[0] = [reg_data.eq(status)]
        cases[1] = [reg_data.eq(self.core.msm.cycles_completed)]
        cases[2] = [reg_data.eq(self.core.msm.time_remaining)]
        cases[3] = [reg_data.eq(self.core.triggers_received)]
        self.comb += Case(read_addr, cases)

        counter_data = Signal(event_counter_width)
        self.comb += Case(read_addr,
            {i: [counter_data.eq(c.counter)]
             for i, c in enumerate(self.core.counters)})

        # Generate an input event if we have a read request RTIO Output event, or if the
        # core has finished. If the core is finished output the herald match, or 0x3fff
        # on timeout.
        #
        # Simultaneous read requests and core-done events are not currently handled, but
        # are easy to avoid in the client code.
        self.comb += [
            self.rtlink.i.stb.eq(read | self.core.enable & self.core.msm.done_stb),
            self.rtlink.i.data.eq(
                Mux(self.core.enable & self.core.msm.done_stb,
                    Mux(self.core.msm.success, self.core.heralder.matches, 0x3fff),
                    Mux(read_counters,
                        counter_data,
                        Mux(read_timestamps, timing_data, reg_data)
                    )
                )
            )
        ]