Beispiel #1
0
    def __init__(self, step_width=None, step_shift=0, **kwargs):
        Filter.__init__(self, **kwargs)

        # required by tests
        self.step_shift = step_shift

        width = len(self.y)
        if step_width is None:
            step_width = width

        self.shift = CSRConstant(step_shift, bits_for(step_shift))
        self.step = CSRStorage(step_width)
        self.min = CSRStorage(width, reset=1 << (width - 1))
        self.max = CSRStorage(width, reset=(1 << (width - 1)) - 1)
        self.run = CSRStorage(1)

        ###

        self.submodules.sweep = Sweep(width + step_shift + 1)
        self.submodules.limit = Limit(width + 1)

        min, max = self.min.storage, self.max.storage
        self.comb += [
            self.sweep.run.eq(~self.clear & self.run.storage),
            self.sweep.hold.eq(self.hold),
            self.limit.x.eq(self.sweep.y >> step_shift),
            self.sweep.step.eq(self.step.storage),
        ]
        self.sync += [
            self.limit.min.eq(Cat(min, min[-1])),
            self.limit.max.eq(Cat(max, max[-1])),
            self.sweep.turn.eq(self.limit.railed),
            self.y.eq(self.limit.y),
        ]
Beispiel #2
0
    def __init__(self, m, phy_ref, phy_sig):
        """Define the gateware to gate & latch inputs."""
        self.clear = Signal()

        self.triggered = Signal()

        n_fine = len(phy_ref.fine_ts)

        full_timestamp_width = counter_width + n_fine

        self.ref_ts = Signal(full_timestamp_width)
        self.sig_ts = Signal(full_timestamp_width)

        # In mu
        self.gate_start = Signal(full_timestamp_width)
        self.gate_stop = Signal(full_timestamp_width)

        # # #

        self.got_ref = Signal()

        # Absolute gate times, calculated when we get the reference event
        abs_gate_start = Signal(full_timestamp_width)
        abs_gate_stop = Signal(full_timestamp_width)

        t_ref = Signal(full_timestamp_width)
        self.comb += t_ref.eq(Cat(phy_ref.fine_ts, m))

        self.sync += [
            If(
                phy_ref.stb_rising,
                self.got_ref.eq(1),
                self.ref_ts.eq(t_ref),
                abs_gate_start.eq(self.gate_start + t_ref),
                abs_gate_stop.eq(self.gate_stop + t_ref),
            ),
            If(self.clear, self.got_ref.eq(0), self.triggered.eq(0)),
        ]

        past_window_start = Signal()
        before_window_end = Signal()
        triggering = Signal()
        t_sig = Signal(full_timestamp_width)
        self.comb += [
            t_sig.eq(Cat(phy_sig.fine_ts, m)),
            past_window_start.eq(t_sig >= abs_gate_start),
            before_window_end.eq(t_sig <= abs_gate_stop),
            triggering.eq(past_window_start & before_window_end),
        ]

        self.sync += [
            If(
                phy_sig.stb_rising & ~self.triggered & triggering,
                self.triggered.eq(triggering),
                self.sig_ts.eq(t_sig),
            )
        ]
Beispiel #3
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.platform.add_extension(ltc.ltc_pads)
        self.submodules.lvds = LTCPhy(self.platform, self.sys_clk_freq, 120e6)
        self.platform.add_false_path_constraints(self.crg.cd_sys.clk,
                                                 self.lvds.pads_dco)
        # Frequency counter for received sample clock
        self.submodules.f_sample = FreqMeter(self.sys_clk_freq)
        self.comb += self.f_sample.clk.eq(ClockSignal("sample"))

        spi_pads = self.platform.request("LTC_SPI")
        self.submodules.spi = spi.SPIMaster(spi_pads, 16, self.sys_clk_freq,
                                            self.sys_clk_freq / 32)

        width, depth = 16 * 2, 8192
        storage = Memory(width, depth, init=[0x1234, 0xCAFECAFE, 0x00C0FFEE])
        self.specials += storage
        self.submodules.adc_data_buffer = wishbone.SRAM(storage,
                                                        read_only=True)
        port = storage.get_port(write_capable=True, clock_domain="sample")
        self.register_mem("adc_data_buffer", 0x10000000,
                          self.adc_data_buffer.bus, depth * 8)

        self.specials += port
        self.submodules.acq = DumpToRAM(width, depth, port)
        self.sync.sample += self.acq.adc_data.eq(
            Cat(Signal(2), self.lvds.sample_outs[0], Signal(2),
                self.lvds.sample_outs[1]))
        self.sync += self.lvds.init_running.eq(self.ctrl.reset)
        for p in LTCSocDev.csr_peripherals:
            self.add_csr(p)
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
Beispiel #5
0
    def __init__(self, vga, sin_t, col_t):
        pos1 = Signal(bits_sign=9)
        pos3 = Signal(bits_sign=9)
        tpos1 = Signal(bits_sign=9)
        tpos2 = Signal(bits_sign=9)
        tpos3 = Signal(bits_sign=9)
        tpos4 = Signal(bits_sign=9)

        index = Signal(bits_sign=6)
        count = Signal()

        self.specials.col_t = Memory(4, 256, init=col_t)
        self.specials.sin_t = Memory(32, 512, init=sin_t)
        sin_p = self.sin_t.get_port(async_read=True)
        col_p = self.col_t.get_port(async_read=True)

        self.specials += sin_p
        self.specials += col_p
        self.ios = {sin_p.adr, sin_p.dat_r, col_p.adr, col_p.dat_r}

        sin = Signal(bits_sign=(32, True))

        self.sync += If(vga.hc < VGA.hpixels - 1, [
            If((vga.hc >= VGA.hbp) & (vga.hc < VGA.hfp), [
                tpos1.eq(tpos1 + 5),
                tpos2.eq(tpos2 + 3)
            ])
        ]).Else([
            If(vga.vc < VGA.vlines - 1, [
                If((vga.vc >= VGA.vbp) & (vga.vc < VGA.vfp), [
                    tpos1.eq(pos1 + 5),
                    tpos2.eq(3),
                    tpos3.eq(tpos3 + 1),
                    tpos4.eq(tpos4 + 3)
                ])
            ]).Else([
                pos1.eq(pos1 + 9),
                pos3.eq(pos3 + 8),
                tpos4.eq(0),
                tpos3.eq(0),
                count.eq(count + 1)
            ])
        ])

        self.sync += If((vga.vc >= VGA.vbp) & (vga.vc < VGA.vfp), [
            If((vga.hc >= VGA.hbp) & (vga.hc < VGA.hfp), [
                calc_index(tpos1, sin, sin_p, acc=False, zero=True),
                calc_index(tpos2, sin, sin_p),
                calc_index(tpos3, sin, sin_p),
                calc_index(tpos4, sin, sin_p),

                index.eq(sin >> 4),

                col_p.adr.eq(index),
                Cat(vga.color.g1, vga.color.g0, vga.color.r1, vga.color.r0).eq(col_p.dat_r)
            ]).Else(vga.color.black())
        ]).Else(vga.color.black())
Beispiel #6
0
 def _setup(self, platform):
     exp = platform.request("exp")
     gpio_pins = Cat(exp.p, exp.n)  #[:width]
     ###
     self.submodules.gpio = MigenGpio(
         gpio_pins=gpio_pins,
         is_output=self.is_output,
         output=self.output,
     )
     self.comb += self.input.eq(self.gpio.input)
Beispiel #7
0
    def __init__(self, period=0, on=True, high_after_on=True):
        """
        Pulse generator that emits a pulse every ``period + 2`` clock cycles. 

        Args:
            period (int or Signal): period of low clock cycles between pulses.
              Set this to a negative number to indicate that the output should 
              be constantly high.
            on (bool or Signal): enables the pulse generator sequence when high.
            high_after_on (bool): when True, the output goes high for a single 
              clock cycle when ``on`` goes high, otherwise it only goes high 
              after the first period.

        Output signals:
            out: the pulse sequence, 0 between pulses and 1 for a single clock 
              cycle during a pulse.
        """
        self.out = Signal(reset=0)
        ###
        try:
            count_reset = period.reset
        except AttributeError:
            count_reset = period
        try:
            width = len(period)
        except TypeError:
            width = count_reset.bit_length()
        self.count = Signal(width, reset=count_reset)
        self.carry = Signal(1, reset=high_after_on)
        self.sync += [
            self.out.eq(self.carry & on),
            If(
                on == 0,  # prepare for the first pulse when off
                self.carry.eq(high_after_on),
                self.count.eq(period),
            ).Elif(
                self.carry,  # restart countdown
                self.carry.eq(0),
                self.count.eq(period),
            ).Else(  # regular countdown
                Cat(self.count, self.carry).eq(Cat(self.count, 0) - 1), )
        ]
Beispiel #8
0
 def __init__(self, nch=4, bits=16, cycles_per_sample=1, ramp=True):
     self.dw = nch * bits
     self.source = source = stream.Endpoint([("data", self.dw)])
     assert cycles_per_sample == 1
     self.submodules.ramp = ramp = Counter(bits)
     valid = Signal(reset=0)
     self.sync += valid.eq(~valid)
     self.comb += [
         source.data.eq(Cat(*[ramp.count + ch for ch in range(nch)])),
         source.valid.eq(valid)
     ]
Beispiel #9
0
    def __init__(self,
                 start=0,
                 stop=None,
                 step=1,
                 reset=0,
                 on=1,
                 width=32,
                 direction="up"):
        """
        Counter that can count either "up" or "down".

        Args:
            start (int or Signal): value to start counting from.
            stop (int, Signal, or None): value at or beyond which to stop
              counting. If ``None``, the counter will wrap through zero.
            step (int or Signal): counting step.
            reset (bool or Signal): when high, the counter will to its starting
              configuration.
            on (bool or Signal): the counter will only keep counting when this
              signal is high.
            width (int): width of the count register.
            direction (str, "up" or "down"): the direction to count in. step
              should always be positive.

        Output signals:
            count: the current counter value.
            carry: the carry bit of the counter, which goes high every time
              the counter wraps through zero.
            done: high when the counter value is equal or beyond ``stop``.
        """
        self.count = Signal(width + 1)
        self.carry = Signal(1)
        self.done = Signal(reset=0)
        ###
        if isinstance(start, int):
            initial_count = start
        else:
            initial_count = start.reset
        count_with_carry = Signal(width + 1, reset=initial_count)
        self.comb += [
            self.count.eq(Cat(count_with_carry[:-1], 0)),
            self.carry.eq(count_with_carry[-1]),
        ]
        if stop is not None:
            self.comb += If((self.count == stop),
                            self.done.eq(1)).Else(self.done.eq(0))
        self.sync += [
            If(
                reset == 1,
                count_with_carry.eq(start),
            ).Elif((~self.done & on) == 1,
                   count_with_carry.eq(self.count + step) if direction == "up"
                   else count_with_carry.eq(self.count - step))
        ]
Beispiel #10
0
        def _dac_settings(self, platform):
            dac = platform.request("dac")
            dac_dat_a = Signal(bits, reset=0)
            dac_dat_b = Signal(bits, reset=0)
            dac_rst = Signal()

            # convert output registers + signed to unsigned and to negative slope
            self.sync += [
                dac_dat_a.eq(Cat(~self.out1[:-1], self.out1[-1])),
                dac_dat_b.eq(Cat(~self.out2[:-1], self.out2[-1])),
            ]
            self.specials += [
                Instance("ODDR", o_Q=dac.clk, i_D1=0, i_D2=1, i_C=ClockSignal("clk_dac_2p"), i_CE=1, i_R=0, i_S=0),
                Instance("ODDR", o_Q=dac.wrt, i_D1=0, i_D2=1, i_C=ClockSignal("clk_dac_2x"), i_CE=1, i_R=0, i_S=0),
                Instance("ODDR", o_Q=dac.sel, i_D1=1, i_D2=0, i_C=ClockSignal("clk_dac_1p"), i_CE=1, i_R=dac_rst, i_S=0),
                Instance("ODDR", o_Q=dac.rst, i_D1=dac_rst, i_D2=dac_rst, i_C=ClockSignal("clk_dac_1p"), i_CE=1, i_R=0, i_S=0),
            ]
            self.specials += [
                Instance("ODDR", o_Q=dac.data[i], i_D1=dac_dat_b[i], i_D2=dac_dat_a[i], i_C=ClockSignal("clk_dac_1p"),  i_CE=1, i_R=dac_rst, i_S=0)
                for i in range(len(dac.data))
            ]
Beispiel #11
0
    def __init__(self, platform):
        serial = platform.request("fast_serial")

        clk12 = platform.request("clk12")

        self.clock_domains.cd_sys = ClockDomain()

        if True:
            self.specials.pll = Instance("pll_test",
                                         i_clock_in=clk12,
                                         o_clock_out=self.cd_sys.clk)
        else:
            self.comb += self.cd_sys.clk.eq(clk12)

        self.clock_domains.cd_por = ClockDomain(reset_less=True)
        reset_delay = Signal(max=1024)
        self.comb += [
            self.cd_por.clk.eq(self.cd_sys.clk),
            self.cd_sys.rst.eq(reset_delay != 1023)
        ]
        self.sync.por += If(reset_delay != 1023,
                            reset_delay.eq(reset_delay + 1))

        self.submodules.tx = FastSerialTX(serial)
        self.submodules.packager = Packager(0x47)
        self.comb += self.packager.source.connect(self.tx.sink)
        self.comb += self.tx.sink.payload.port.eq(1)

        counter = Signal(5)

        self.comb += [
            self.packager.sink.stb.eq(1),
            self.packager.sink.payload.data.eq(counter),
            self.packager.sink.eop.eq(counter == 2**counter.nbits - 1)
        ]

        self.sync += [
            If(self.packager.sink.stb & self.packager.sink.ack,
               counter.eq(counter + 1)),
        ]

        debug = platform.request("debug")
        self.comb += [
            debug.eq(Cat(serial.clk, serial.di, serial.cts)),
        ]
Beispiel #12
0
    def __init__(self, clk_freq, baud_rate):
        self.data = Signal(8)
        self.ready = Signal()
        self.ack = Signal()
        self.error = Signal()
        self.rx = Signal(reset=1)

        divisor = clk_freq // baud_rate

        rx_counter = Signal(max=divisor)
        self.rx_strobe = Signal()
        self.comb += self.rx_strobe.eq(rx_counter == 0)
        self.sync += \
                If(rx_counter == 0,
                    rx_counter.eq(divisor - 1)
                ).Else(
                    rx_counter.eq(rx_counter - 1)
                )

        self.rx_bitno = Signal(3)
        self.submodules.rx_fsm = FSM(reset_state='IDLE')
        self.rx_fsm.act(
            'IDLE',
            If(~self.rx, NextValue(rx_counter, divisor // 2),
               NextState('START')))
        self.rx_fsm.act('START', If(self.rx_strobe, NextState('DATA')))
        self.rx_fsm.act(
            'DATA',
            If(self.rx_strobe,
               NextValue(self.data, Cat(self.data[1:8], self.rx)),
               NextValue(self.rx_bitno, self.rx_bitno + 1),
               If(self.rx_bitno == 7, NextState('STOP'))))
        self.rx_fsm.act(
            'STOP',
            If(self.rx_strobe,
               If(~self.rx, NextState('ERROR')).Else(NextState('FULL'), )))
        self.rx_fsm.act(
            'FULL', self.ready.eq(1),
            If(self.ack, NextState('IDLE')).Elif(~self.rx, NextState('ERROR')))
        self.rx_fsm.act('ERROR', self.error.eq(1))
Beispiel #13
0
    def __init__(self, pads):
        self.sink = stream.Endpoint([
            ("data", 8),
            ("port", 1),
        ])

        ###

        cts = Signal()
        self.specials += MultiReg(pads.cts, cts)

        di = Signal(reset=1)
        self.comb += pads.di.eq(di)

        tx_reg = Signal(9)
        tx_bit = Signal(max=10)

        self.sync += [
            self.sink.ack.eq(0),
            If(
                self.sink.stb & cts & (tx_bit == 0) & ~self.sink.ack,
                tx_reg.eq(Cat(self.sink.payload.data, self.sink.payload.port)),
                tx_bit.eq(9),
                di.eq(0),
            ).Elif(
                tx_bit > 0,
                tx_bit.eq(tx_bit - 1),
                di.eq(tx_reg[0]),
                tx_reg.eq(tx_reg[1:]),
                If(
                    tx_bit == 1,
                    self.sink.ack.eq(1),
                ),
            ).Else(di.eq(1), )
        ]

        self.comb += [
            pads.clk.eq(~ClockSignal()),
        ]
    def __init__(self, plat, superunit):
        self.garbage = Cat([plat.request("user_led") for _ in range(3)])
        self.bad_led = plat.request("user_led")
        self.good_led = plat.request("user_led")

        self.submodules += superunit

        self.comb += [
            [g.eq(0) for g in self.garbage]
        ]

        self.sync += [
            If(self.good_led == 0,
               self.good_led.eq(superunit.o_success & superunit.o_over))
            .Else(
                self.good_led.eq(1)),

            If(self.bad_led == 0,
               self.bad_led.eq(~superunit.o_success & superunit.o_over))
            .Else(
                self.bad_led.eq(0))
        ]
Beispiel #15
0
    def __init__(self, pads):
        self.intro = ModuleDoc("""Fomu Touchpads

        Fomu has four single-ended exposed pads on its side.  These pads are designed
        to be connected to some captouch block, or driven in a resistive touch mode
        in order to get simple touchpad support.

        This block simply provides CPU-controlled GPIO support for this block.  It has
        three registers which control the In, Out, and Output Enable functionality of
        each of these pins.
        """)
        touch1 = TSTriple()
        touch2 = TSTriple()
        touch3 = TSTriple()
        touch4 = TSTriple()
        self.specials += touch1.get_tristate(pads.t1)
        self.specials += touch2.get_tristate(pads.t2)
        self.specials += touch3.get_tristate(pads.t3)
        self.specials += touch4.get_tristate(pads.t4)

        self.o = CSRStorage(4, description="Output values for pads 1-4")
        self.oe = CSRStorage(4,
                             description="Output enable control for pads 1-4")
        self.i = CSRStatus(4, description="Input value for pads 1-4")

        self.comb += [
            touch1.o.eq(self.o.storage[0]),
            touch2.o.eq(self.o.storage[1]),
            touch3.o.eq(self.o.storage[2]),
            touch4.o.eq(self.o.storage[3]),
            touch1.oe.eq(self.oe.storage[0]),
            touch2.oe.eq(self.oe.storage[1]),
            touch3.oe.eq(self.oe.storage[2]),
            touch4.oe.eq(self.oe.storage[3]),
            self.i.status.eq(Cat(touch1.i, touch2.i, touch3.i, touch4.i))
        ]
Beispiel #16
0
    def __init__(self, platform, pads, size=16 * 1024 * 1024):
        self.size = size

        self.bus = bus = wishbone.Interface()

        self.reset = Signal()

        self.cfg1 = CSRStorage(fields=[
            CSRField(
                "bb_out", size=4, description="Output bits in bit-bang mode"),
            CSRField("bb_clk",
                     description="Serial clock line in bit-bang mode"),
            CSRField("bb_cs", description="Chip select line in bit-bang mode"),
        ])
        self.cfg2 = CSRStorage(fields=[
            CSRField("bb_oe",
                     size=4,
                     description="Output Enable bits in bit-bang mode"),
        ])
        self.cfg3 = CSRStorage(fields=[
            CSRField(
                "rlat", size=4, description="Read latency/dummy cycle count"),
            CSRField("crm", description="Continuous Read Mode enable bit"),
            CSRField("qspi", description="Quad-SPI enable bit"),
            CSRField("ddr", description="Double Data Rate enable bit"),
        ])
        self.cfg4 = CSRStorage(fields=[
            CSRField(
                "memio",
                offset=7,
                reset=1,
                description=
                "Enable memory-mapped mode (set to 0 to enable bit-bang mode)")
        ])

        self.stat1 = CSRStatus(fields=[
            CSRField(
                "bb_in", size=4, description="Input bits in bit-bang mode"),
        ])
        self.stat2 = CSRStatus(8, description="Reserved")
        self.stat3 = CSRStatus(8, description="Reserved")
        self.stat4 = CSRStatus(8, description="Reserved")

        cfg = Signal(32)
        cfg_we = Signal(4)
        cfg_out = Signal(32)
        self.comb += [
            cfg.eq(
                Cat(self.cfg1.storage, self.cfg2.storage, self.cfg3.storage,
                    self.cfg4.storage)),
            cfg_we.eq(
                Cat(self.cfg1.re, self.cfg2.re, self.cfg3.re, self.cfg4.re)),
            self.stat1.status.eq(cfg_out[0:4]),
            self.stat2.status.eq(0),
            self.stat3.status.eq(0),
            self.stat4.status.eq(0),
        ]

        reset = Signal()

        mosi_pad = TSTriple()
        miso_pad = TSTriple()
        cs_n_pad = TSTriple()
        clk_pad = TSTriple()
        wp_pad = TSTriple()
        hold_pad = TSTriple()

        clk = Signal()
        if hasattr(pads, "clk"):
            clk = pads.clk
            self.specials += clk_pad.get_tristate(clk)
            self.comb += clk_pad.oe.eq(~reset)
        else:
            self.specials += Instance("USRMCLK", i_USRMCLKI=clk, i_USRMCLKTS=0)

        self.specials += mosi_pad.get_tristate(pads.mosi)
        self.specials += miso_pad.get_tristate(pads.miso)
        self.specials += cs_n_pad.get_tristate(pads.cs_n)
        self.specials += wp_pad.get_tristate(pads.wp)
        self.specials += hold_pad.get_tristate(pads.hold)

        self.comb += [
            reset.eq(ResetSignal() | self.reset),
            cs_n_pad.oe.eq(~reset),
        ]

        flash_addr = Signal(24)
        # size/4 because data bus is 32 bits wide, -1 for base 0
        mem_bits = bits_for(int(size / 4) - 1)
        pad = Signal(2)
        self.comb += flash_addr.eq(Cat(pad, bus.adr[0:mem_bits - 1]))

        read_active = Signal()
        spi_ready = Signal()
        self.sync += [
            If(
                bus.stb & bus.cyc & ~read_active,
                read_active.eq(1),
                bus.ack.eq(0),
            ).Elif(
                read_active & spi_ready,
                read_active.eq(0),
                bus.ack.eq(1),
            ).Else(
                bus.ack.eq(0),
                read_active.eq(0),
            )
        ]

        o_rdata = Signal(32)
        self.comb += bus.dat_r.eq(o_rdata)

        self.specials += Instance(
            "spimemio",
            o_flash_io0_oe=mosi_pad.oe,
            o_flash_io1_oe=miso_pad.oe,
            o_flash_io2_oe=wp_pad.oe,
            o_flash_io3_oe=hold_pad.oe,
            o_flash_io0_do=mosi_pad.o,
            o_flash_io1_do=miso_pad.o,
            o_flash_io2_do=wp_pad.o,
            o_flash_io3_do=hold_pad.o,
            o_flash_csb=cs_n_pad.o,
            o_flash_clk=clk,
            i_flash_io0_di=mosi_pad.i,
            i_flash_io1_di=miso_pad.i,
            i_flash_io2_di=wp_pad.i,
            i_flash_io3_di=hold_pad.i,
            i_resetn=~reset,
            i_clk=ClockSignal(),
            i_valid=bus.stb & bus.cyc,
            o_ready=spi_ready,
            i_addr=flash_addr,
            o_rdata=o_rdata,
            i_cfgreg_we=cfg_we,
            i_cfgreg_di=cfg,
            o_cfgreg_do=cfg_out,
        )
        platform.add_source("rtl/spimemio.v")
Beispiel #17
0
    def __init__(self, platform, mem, minimal=False):

        self.intro = ModuleDoc("""FOMU Apple II+
            A virtual computer within a virtual computer inside a USB port.
            Instantiate 6502 processor with 1MHz core clock.
            Tie in to system memory as a wishbone master.
            Create virtual keyboard, video display and disk drive.
            """)

        addr = Signal(16)
        dout = Signal(8)
        din = Signal(8)
        wren = Signal()
        iosel = Signal()
        ior_addr = Signal(8)
        r_memsel = Signal()
        w_memsel = Signal()
        clk_en = Signal()  # Clock divider limits CPU activity
        active = Signal()  # CPU is active this cycle
        available = Signal()  # Key press ready for reading
        div1M = 4
        idlecount = Signal(div1M)  # Counter to slow CPU clock

        # Disk II Controller Registers
        disk_phase = Signal(4)
        disk_motor = Signal()
        disk_drive = Signal()
        #disk_write   = Signal()
        disk_reading = Signal()  # DOS trying to read sector
        disk_data_available = Signal()  # Data available for DOS to read
        disk_data_wanted = Signal()  # Data wanted by DOS
        disk_read = Signal()  # Data read by DOS so clear readable

        simulation = getenv("SIMULATION")
        synthesis = not simulation

        # Wishbone visible registers
        self.control = CSRStorage(fields=[
            CSRField(
                "Reset",
                reset=1 if synthesis else 0,  # auto-start in sim
                description="6502 Reset line - 1: Reset Asserted, 0: Running"),
            CSRField("RWROM", size=1, description="Allow writes to ROM"),
            #CSRField("Pause", description="Halt processor allowing stepping"),
            #CSRField("Step",  description="Single step 6502 one clock cycle"),
            #CSRField("NMI", size=1, description="Non-maskable interrupt"),
            #CSRField("IRQ", size=1, description="Maskable interrupt request"),
            #CSRField("RDY", size=1, description=""),
            CSRField(
                "Divisor",
                size=div1M,
                offset=8,
                reset=11 if synthesis else 0,  # Over-clock simulation
                description="Clock divider minius 1: 11 for 1MHz, 0 for 12MHz"
            ),
            #CSRField("DI", size=8, offset=16, description=""),
        ])
        self.keyboard = CSRStorage(8,
                                   write_from_dev=True,
                                   description="Keyboard input ($C000)")
        self.strobe = CSR(1)  #, description="Keyboard strobe ($C010)")
        self.screen = CSRStatus(
            fields=[
                CSRField("Character",
                         size=8,
                         description="Character written to screen"),
                CSRField("Valid", size=1, description="Character is valid"),
                CSRField(
                    "More",
                    size=1,
                    description="Additional characters are available to read"),
                #CSRField("Move", size=1,
                #    description="Character is not adjacent to previous"),
                CSRField("Repeat",
                         size=1,
                         offset=11,
                         description=
                         "Previous character repeated to current position"),
                CSRField("ScrollStart",
                         size=1,
                         offset=12,
                         description="Start of scroll region detected"),
                CSRField("ScrollEnd",
                         size=1,
                         offset=13,
                         description="End of scroll region"),
                CSRField(
                    "Horizontal",
                    size=6,
                    offset=16,
                    description="Location of current character in screen memory"
                ),
                CSRField(
                    "Vertical",
                    size=5,
                    offset=24,
                    description="Location of current character in screen memory"
                ),
            ],
            description="Video Display Output")
        self.diskctrl = CSRStatus(
            fields=[
                CSRField("Phase",
                         size=4,
                         description=
                         "Four phases of the track selection stepper motor"),
                CSRField("Motor", size=1, description="Drive is spinning"),
                CSRField(
                    "Drive",
                    size=1,
                    description="Drive select: drive 1 if clear, drive 2 if set"
                ),
                CSRField("Wanted",
                         size=1,
                         description="Drive is waiting for data"),
                CSRField("Pending",
                         size=1,
                         description="Drive has not yet read data written"),
                #CSRField("WriteMode", size=1,
                #    description="Drive is reading when clear, writing when set"),
            ],
            description="Disk drive control ($C0EX)")
        self.diskdata = CSRStorage(8, description="Disk drive data ($C0EC)")

        #self.bus=CSRStatus(32, fields=[
        #    CSRField("Addr", size=16, description="Address bus"),
        #    CSRField("Data", size=8, description="Data bus"),
        #    CSRField("WrEn", size=1, description="Write enable"),
        #    ], description="Address and data bus")
        #self.debug=CSRStatus(32, fields=[
        #    CSRField("PC", size=8,
        #        description="Program counter"),
        #    CSRField("A", size=8,
        #        description="Accumulator"),
        #    CSRField("X", size=8,
        #        description="X index register"),
        #    CSRField("Y", size=8,
        #        description="Y index register"),
        #    ], description="Address and data bus")

        if not minimal:
            # The minimal configuration provides all registers the host needs to
            # see so software can run unmodified. However, it does not implement
            # the 6502 to save gates. The video driver is also greatly reduced.

            # TODO eliminate wire [31:0] apple2_display_fifo_wrport_dat_r
            self.submodules.display_fifo = fifo.SyncFIFOBuffered(width=32,
                                                                 depth=256)

            self.comb += [
                mem.addr6502.eq(addr),
                mem.din6502.eq(dout),
                mem.wren6502.eq(wren),
                self.strobe.w.eq(available),
                #self.bus.fields.Addr.eq(addr),
                #self.bus.fields.Data.eq(dout),
                #self.bus.fields.WrEn.eq(wren),
                If(addr[8:16] == 0xC0, iosel.eq(1), w_memsel.eq(0),
                   mem.access6502.eq(0)).Else(iosel.eq(0), w_memsel.eq(1),
                                              mem.access6502.eq(active)),
                disk_read.eq(0),
                If(
                    r_memsel,
                    din.eq(mem.dout6502),
                ).Else(
                    # I/O Read Address Decoder (reading but not from memory)
                    If(
                        ior_addr[4:8] == 0x0,
                        din.eq(Cat(self.keyboard.storage[0:7], available)),
                    ),
                    # Disk II Controller Card in slot 6  (0x8 | 0x6)
                    # The only data to be read are locations C and D. Simplify the
                    # logic to only look at bit 0 of the address.
                    If(
                        ior_addr[4:8] == 0xE,
                        din[0:7].eq(self.diskdata.storage[0:7]),
                        # Write protect - TODO write is not supported
                        #If(ior_addr[0],
                        #    # Return high bit set - protected
                        #    din[7].eq(1)
                        #).Else(
                        disk_read.eq(1),
                        If(
                            disk_data_available | self.diskdata.re,
                            # Return byte given by host
                            din[7].eq(self.diskdata.storage[7]),
                        ).Else(
                            # Return high bit clear - data not available
                            din[7].eq(0), ),
                        #),
                    ),
                ),
                active.eq(clk_en & self.display_fifo.writable),
            ]

            self.sync += [
                # Slow clock to prototypical speed or as configured by user
                If(
                    idlecount == self.control.fields.Divisor,
                    idlecount.eq(0),
                    clk_en.eq(1),
                ).Else(
                    idlecount.eq(idlecount + 1),
                    clk_en.eq(0),
                ),
                # Read (DI) follows Write (AB/DO) by one clock cycle
                If(
                    active,
                    r_memsel.eq(w_memsel),
                    ior_addr.eq(addr[0:8]),
                ),
                # Keyboard key available when written by host
                If(
                    self.keyboard.re,
                    available.eq(1),
                ),
                If(
                    iosel,
                    # I/O Write Address Decoder
                    If(
                        addr[4:8] == 0x1,
                        # KBDSTRB
                        # Strobe cleared on read or write to KBDSTRB
                        # Any read or write to this address clears the pending key
                        available.eq(0),
                    ),
                ),
            ]

            self.specials += Instance(
                "cpu",
                i_clk=ClockSignal(),
                i_reset=ResetSignal() | self.control.storage[0],
                i_DI=din,
                # &(self.rand.we|self.cfg.storage[1])),
                o_AB=addr,  # .dat_w,
                o_DO=dout,  # .dat_w,
                o_WE=wren,
                i_IRQ=False,  # self.control.fields.IRQ,
                i_NMI=False,  # self.control.fields.NMI,  # seed.re,
                i_RDY=active,  # self.control.fields.RDY,
            )
            platform.add_source("rtl/verilog-6502/cpu.v")
            platform.add_source("rtl/verilog-6502/ALU.v")

            #===============================================================================
            #       Disk Drive - Emulate Disk II controller in slot 6
            #===============================================================================
            # The Disk II controller card has 16 addressable locations. Eight of these are
            # dedicated to moving the arm, two for motor control, two for drive selection
            # and four that handle read, write, and write protection detection.
            #===============================================================================

            self.comb += [
                self.diskctrl.fields.Phase.eq(disk_phase),
                self.diskctrl.fields.Motor.eq(disk_motor),
                self.diskctrl.fields.Drive.eq(disk_drive),
                #self.diskctrl.fields.WriteMode.eq(disk_write),
                self.diskctrl.fields.Wanted.eq(disk_data_wanted),
                self.diskctrl.fields.Pending.eq(disk_data_available),
            ]

            self.sync += [
                If(
                    self.diskdata.re,
                    disk_data_available.eq(1),
                ),
                # Set false again on read
                If(
                    active & disk_read,
                    disk_reading.eq(0),
                    If(
                        disk_data_available,
                        disk_data_wanted.eq(0),
                    ).Else(disk_data_wanted.eq(1), ),
                    disk_data_available.eq(0),
                ),
                If(
                    iosel,
                    # Disk II Controller Card in slot 6

                    # C0E0 PHASEOFF  Stepper motor phase 0 off.
                    # C0E1 PHASEON   Stepper motor phase 0 on.
                    # C0E2 PHASE1OFF Stepper motor phase 1 off.
                    # C0E3 PHASElON  Stepper motor phase 1 on.
                    # C0E4 PHASE2OFF Stepper motor phase 2 off.
                    # C0E5 PHASE2ON  Stepper notor phase 2 on.
                    # C0E6 PHASE3OFF Stepper motor phase 3 off.
                    # C0E7 PHASE3ON  Stepper motor phase 3 on.
                    # C0E8 MOTOROFF  Turn motor off.
                    # C0E9 MOTORON   Turn motor on.
                    # C0EA DRV0EN    Engage drive 1.
                    # C0EB DRV1EN    Engage drive 2.
                    # C0EC Q6L       Strobe Data Latch for I/O.
                    # C0ED Q6H       Load Data Latch.
                    # C0EE Q7H       Prepare latch for input (read from disk).
                    # C0EF Q7L       Prepare latch for output (write to disk).

                    # Q7L with Q6L = Read
                    # Q7L with Q6H = Sense Write Protect
                    # Q7H with Q6L = Write
                    # Q7H with Q6H = Load Write Latch
                    If(
                        addr[4:8] == 0xE,  # (8|6) 
                        # Addresses 0-7 simply update a bit in the status register
                        If(addr[0:4] == 0x0, disk_phase[0].eq(0)),
                        If(addr[0:4] == 0x1, disk_phase[0].eq(1)),
                        If(addr[0:4] == 0x2, disk_phase[1].eq(0)),
                        If(addr[0:4] == 0x3, disk_phase[1].eq(1)),
                        If(addr[0:4] == 0x4, disk_phase[2].eq(0)),
                        If(addr[0:4] == 0x5, disk_phase[2].eq(1)),
                        If(addr[0:4] == 0x6, disk_phase[3].eq(0)),
                        If(addr[0:4] == 0x7, disk_phase[3].eq(1)),
                        # Likewise, motor active and drive select update status
                        If(addr[0:4] == 0x8, disk_motor.eq(0)),
                        If(addr[0:4] == 0x9, disk_motor.eq(1)),
                        If(addr[0:4] == 0xA, disk_drive.eq(0)),
                        If(addr[0:4] == 0xB, disk_drive.eq(1)),
                        # Write is ignored and read must be delayed one clock tick
                        If(addr[0:4] == 0xC, disk_reading.eq(1)),
                        #If(addr[0:4]==0xD, disk_ior_wp.eq(1)),
                        #If(addr[0:4]==0xE, disk_write.eq(0)),
                        #If(addr[0:4]==0xF, disk_write.eq(1)),
                    ),
                ),
            ]

            #===============================================================================
            #       Video Output - Text Mode
            #===============================================================================
            # The Apple II screen memory contains 8 segments containing 3 rows each in a 128
            # byte block leaving 8 unused bytes in each of the 8 blocks To assist with
            # scroll detection, we convert memory addresses to screen coordinates.
            #===============================================================================

            # Video memory - Frame Buffer access shortcuts
            fbsel = Signal()
            fb_r = Signal()
            fb_w = Signal()

            # Conversion from memory address to X,Y screen coordinates
            segment = Signal(3)
            triple = Signal(7)
            third = Signal(2)
            horiz = Signal(6)
            vert = Signal(5)
            move = Signal()

            scroll_active = Signal()
            scroll_match = Signal()
            scroll_start = Signal()
            scroll_end = Signal()
            scroll_read = Signal()
            scroll_write_valid = Signal()
            scroll_next_col = Signal()
            scroll_next_row = Signal()
            scroll_sequential = Signal()
            read_horiz = Signal(6)
            read_vert = Signal(5)

            repeat_active = Signal()
            repeat_match = Signal()
            repeat_start = Signal()
            repeat_end = Signal()
            repeat_next_col = Signal()
            repeat_next_row = Signal()
            repeat_sequential = Signal()

            # Registers shared by scroll and repeat compression circuits
            #horiz_start = Signal(max=40)
            #vert_start = Signal(max=24)
            #horiz_end = Signal(max=40)
            #vert_end = Signal(max=24)
            prev_horiz = Signal(max=40)
            prev_vert = Signal(max=24)
            prev_char = Signal(8)
            prev_start = Signal()
            push_save = Signal()
            push_saving = Signal()

            fifo_out = Signal(32)

            self.comb += [
                # Detect access to frame memory: Address range 0x0400-0x7ff
                fbsel.eq((addr[10:15] == 0x1) & active),
                fb_r.eq(fbsel & ~wren),
                fb_w.eq(fbsel & wren),
                # Convert memory address to X,Y coordinates
                segment.eq(addr[7:10]),
                triple.eq(addr[0:7]),
                # TODO This generates reg - change to cause only wire
                If(
                    triple >= 80,
                    third.eq(2),
                    horiz.eq(addr[0:7] - 80),
                ).Else(
                    If(
                        triple >= 40,
                        third.eq(1),
                        horiz.eq(addr[0:7] - 40),
                    ).Else(
                        third.eq(0),
                        horiz.eq(addr[0:7]),
                    )),
                vert.eq(Cat(segment, third)),

                # TODO Detect scroll - frame buffer read immediately followed by
                # frame buffer write to character on previous line, directly above.
                # Scroll is Right to Left (asm: DEY at FC90 in Autostart ROM)
                scroll_match.eq((horiz == read_horiz)
                                & (vert + 1 == read_vert)),
                # & (din==read_char))  <== TODO Need to delay din by 1 cycle
                scroll_write_valid.eq(scroll_read & fb_w & scroll_match),
                scroll_start.eq(scroll_write_valid & ~scroll_active),
                # Scroll ends on any write that does not follow the required pattern
                scroll_end.eq(scroll_active & fb_w & ~scroll_write_valid),
                scroll_next_col.eq((horiz + 1 == prev_horiz)
                                   & (vert == prev_vert)),
                scroll_next_row.eq((horiz == 39) & (prev_horiz == 0)
                                   & (vert == prev_vert + 1)),
                scroll_sequential.eq(scroll_next_col | scroll_next_row),

                # Detect repeated charaters (spaces)
                # Clear is Left to Right (asm: INY at FCA2 in Autostart ROM)
                #               repeat_match.eq(fb_w & (dout==prev_char)),
                #               repeat_start.eq(repeat_match & repeat_sequential & ~repeat_active),
                #               repeat_end.eq(fb_w & repeat_active &
                #                   (~repeat_match |~repeat_sequential)),
                #               repeat_next_col.eq((horiz==prev_horiz+1) & (vert==prev_vert)),
                #               repeat_next_row.eq((horiz==0) & (prev_horiz==39) &
                #                   (vert==prev_vert+1)),
                #               repeat_sequential.eq(repeat_next_col | repeat_next_row),
                #               repeat_sequential.eq(repeat_next_col),  # This or the previous one

                # Place writes in the fifo
                self.display_fifo.din[8].eq(0),  # Valid is calculated
                self.display_fifo.din[9].eq(0),  # More is calculated
                #self.display_fifo.din[   10].eq(move),
                self.display_fifo.din[11].eq(repeat_end),
                If(
                    push_save,
                    self.display_fifo.din[0:8].eq(prev_char),
                    self.display_fifo.din[12].eq(prev_start),
                    self.display_fifo.din[13].eq(scroll_end),
                    #self.display_fifo.din[14:16].eq(0), # Reserved
                    self.display_fifo.din[16:22].eq(prev_horiz
                                                    ),  # 2 bits padding
                    self.display_fifo.din[24:29].eq(
                        prev_vert),  # 3 bits padding
                ).Elif(
                    push_saving,
                    # push_save will be valid on the next cycle - so push previous
                    self.display_fifo.din[0:8].eq(prev_char),
                    #self.display_fifo.din[    8].eq(0), # Valid is calculated
                    #self.display_fifo.din[    9].eq(0), # More is calculated
                    #self.display_fifo.din[   10].eq(move),
                    #self.display_fifo.din[   11].eq(repeat_end),
                    self.display_fifo.din[12].eq(scroll_start),
                    self.display_fifo.din[13].eq(scroll_end),
                    #self.display_fifo.din[14:16].eq(0), # Reserved
                    self.display_fifo.din[16:22].eq(prev_horiz
                                                    ),  # 2 bits padding
                    self.display_fifo.din[24:29].eq(
                        prev_vert),  # 3 bits padding
                ).Else(
                    #self.display_fifo.din.eq(Cat(dout, horiz, vert,
                    #    move, scroll_start, scroll_end, repeat_start, repeat_end)),
                    self.display_fifo.din[0:8].eq(dout),
                    #self.display_fifo.din[    8].eq(0), # Valid is calculated
                    #self.display_fifo.din[    9].eq(0), # More is calculated
                    #self.display_fifo.din[   10].eq(move),
                    #self.display_fifo.din[   11].eq(repeat_end),
                    self.display_fifo.din[12].eq(scroll_start),
                    self.display_fifo.din[13].eq(scroll_end),
                    #self.display_fifo.din[14:16].eq(0), # Reserved
                    self.display_fifo.din[16:22].eq(horiz),  # 2 bits padding
                    self.display_fifo.din[24:29].eq(vert),  # 3 bits padding
                ),
                self.display_fifo.we.eq(push_save | repeat_end | scroll_start
                                        | scroll_end
                                        | (fb_w & ~scroll_active
                                           & ~repeat_active & ~repeat_start)),
                push_saving.eq(((repeat_end & ~repeat_sequential) | scroll_end)
                               & ~push_save),

                # Retrieve characters from fifo
                self.display_fifo.re.eq(self.screen.we),
                self.screen.we.eq(self.display_fifo.re),
                self.screen.fields.Valid.eq(self.display_fifo.readable),
                self.screen.fields.More.eq(self.display_fifo.readable),
                self.screen.fields.Character.eq(fifo_out[0:8]),
                self.screen.fields.Horizontal.eq(fifo_out[16:22]),
                self.screen.fields.Vertical.eq(fifo_out[24:29]),
                #self.screen.fields.Move.eq(fifo_out[10]),
                self.screen.fields.Repeat.eq(fifo_out[11]),
                self.screen.fields.ScrollStart.eq(fifo_out[12]),
                self.screen.fields.ScrollEnd.eq(fifo_out[13]),
            ]

            self.sync += [
                fifo_out.eq(self.display_fifo.dout),

                # Scroll
                If(
                    scroll_start,
                    scroll_active.eq(1),
                    #horiz_start.eq(horiz),
                    #vert_start.eq(vert),
                    #horiz_end.eq(horiz),
                    #vert_end.eq(vert),
                ),
                If(
                    scroll_end,
                    push_save.eq(1),
                    scroll_active.eq(0),
                    # These happen on any write to the frame buffer
                    #prev_horiz.eq(horiz),
                    #prev_vert.eq(vert),
                    #prev_char.eq(dout),
                    prev_start.eq(scroll_start),
                ),
                If(
                    fb_r,
                    If((scroll_read & (scroll_sequential | ~scroll_active)) |
                       (repeat_active & repeat_sequential),
                       # A faithful 6502 model issues a read of the target
                       # address before the write cycle of an indirect store
                       # instruction.  Do nothing if we suspect the current read is
                       # actually part of a store instruction.
                       ).
                    Else(
                        scroll_read.eq(1),
                        read_horiz.eq(horiz),
                        read_vert.eq(vert),
                        # TODO read_char should be din on the next clock cycle
                        # read_char.eq(dout),
                    ),
                ),

                # Write to the frame buffer: remember the location and character
                # that generate the sequential and repeat signals which are used
                # by the scroll and clear functions. Also, update scroll signals.
                If(
                    fb_w,
                    scroll_read.eq(0),
                    prev_vert.eq(vert),
                    prev_horiz.eq(horiz),
                    prev_char.eq(dout),

                    # Repeat - Mostly needed for screen clearing operations but made
                    # generic to conserve bandwidth and allow any character to be
                    # repeated.
                    If(
                        repeat_match & repeat_sequential,
                        # Supress output, begin sequence if not started already
                        # Store location and character as this will be needed if the
                        # following write is not sequential
                        # Setting repeat is redundant if already active
                        repeat_active.eq(1),
                    ).Elif(
                        repeat_active & ~repeat_sequential,
                        # The cursor moved and we must terminate repeat mode
                        # indicating the last character in the sequence.  This is
                        # required whether or not the same character is present.
                        # Output saved location with Repeat flag set to mark end.
                        # Then output current signal set on next cycle
                        push_save.eq(1),
                        prev_start.eq(scroll_start),
                        repeat_active.eq(0),
                    ).Else(
                        # Push current character on stack either because:
                        # a. character is different breaking repeat
                        # b. character is different preventing repeat
                        # c. location is not sequential breaking repeat
                        # d. location is not sequential preventing repeat
                        # Cases a,c need to clear repeat. This is irrelevant for b,d
                        repeat_active.eq(0), ),
                ),
                # We can safely use the cycle after a write to frame memory as a
                # second push into the character fifo knowing that the only time the
                # 6502 has two consecutive write cycles is the JSR instruction which
                # writes the return address onto the stack, and the RMW instructions
                # INC, DEC, LSR, ASR, ROL, ROR which write the original and the new
                # values in two consecutive cycles. It is extremely poor programming
                # practice to keep the stack inside the frame buffer while clearing
                # or scrolling the screen so no special handling of these cases is
                # taken.
                If(
                    push_save,
                    # Auto-clear after one clock cycle
                    push_save.eq(0),
                ),
            ]
def rescale(mod, sig_i, QI, QO):
    """
    Change word length of input signal `sig_i` to `WO` bits, using the 
    quantization and saturation methods specified by ``QO['quant']`` and 
    ``QO['ovfl']``.
    
    Parameters
    ----------
    
    mod: Module (migen)
        instance of migen module
    
    sig_i: Signal (migen)
        Signal to be requantized
    
    QI: dict
        Quantization dict for input word, only the keys 'WI' and 'WF' for integer
        and fractional wordlength are evaluated. QI['WI'] = 2 and QI['WF'] = 13
        e.g. define Q-Format '2.13'  with 2 integer, 13 fractional bits and 1 implied 
        sign bit = 16 bits total.
    
    QO: dict
        Quantization dict for output word format; the keys 'WI' and 'WF' for 
        integer and fractional wordlength are evaluated as well as the keys 'quant'
        and 'ovfl' describing requantization and overflow behaviour.
    
    **Input and output word are aligned at their binary points.**
    
    The following shows an example of rescaling an input word from Q2.4 to Q0.3
    using wrap-around and truncation. It's easy to see that for simple wrap-around
    logic, the sign of the result may change.
    
    ::

      S | WI1 | WI0 * WF0 | WF1 | WF2 | WF3  :  WI = 2, WF = 4, W = 7
      0 |  1  |  0  *  1  |  0  |  1  |  1   =  43 (dec) or 43/16 = 2 + 11/16 (float)
                    *
              |  S  * WF0 | WF1 | WF2        :  WI = 0, WF = 3, W = 4
                 0  *  1  |  0  |  1         =  7 (dec) or 7/8 (float)

              
    The float or "real (world) value" is calculated by multiplying the integer 
    value by 2 ** (-WF).
    
    For requantizing two numbers to the same WI and WF, imagine both binary numbers
    to be right-aligned. Changes in the number of integer bits `dWI` and fractional
    bits `dWF` are handled separately.
    
    Fractional Bits:
    
    - For reducing the number of fractional bits by `dWF`, simply right-shift the
      integer number by `dWF`. For rounding, add '1' to the bit below the truncation
      point before right-shifting. 
    
    - Extend the number of fractional bits by left-shifting the integer by `dWF`,
      LSB's are filled with zeros.
      
    Integer Bits:
    
    - For reducing the number of integer bits by `dWI`, simply right-shift the
      integer by `dWI`.
    
    - The number of fractional bits is SIGN-EXTENDED by filling up the left-most
      bits with the sign bit.
    
    """
    WI_I = QI['WI']
    WI_F = QI['WF']
    WI = WI_I + WI_F + 1

    WO_I = QO['WI']
    WO_F = QO['WF']
    WO = WO_I + WO_F + 1

    dWF = WI_F - WO_F  # difference of fractional lengths
    dWI = WI_I - WO_I  # difference of integer lengths
    # max. resp. min, output values
    MIN_o = -1 << (WO - 1)
    MAX_o = -MIN_o - 1

    sig_i_q = Signal((max(WI, WO), True))
    sig_o = Signal((WO, True))

    logger.debug("rescale: dWI={0}, dWF={1}, QU:{2}, OV:{3}".format(
        dWI, dWF, QO['quant'], QO['ovfl']))
    if dWF <= 0:  # extend fractional word length of output word
        mod.comb += sig_i_q.eq(sig_i << -dWF)  # shift input right by -dWF
    else:  # dWF > 0, fractional output word length needs to be shortened
        if QO['quant'] == 'round':
            # add half an LSB (1 << (dWF - 1)) and divide by 2^dWF (shift left by dWF)
            mod.comb += sig_i_q.eq((sig_i + (1 << (dWF - 1))) >> dWF)
        elif QO['quant'] == 'floor':  # just divide by 2^dWF (shift left by dWF)
            mod.comb += sig_i_q.eq(sig_i >> dWF)
        elif QO['quant'] == 'fix':
            # add sign bit as LSB (1 << dWF) and divide by 2^dWF (shift left by dWF)
            mod.comb += sig_i_q.eq((sig_i + (sig_i[-1] << dWF)) >> dWF)
        else:
            raise Exception(u'Unknown quantization method "%s"!' %
                            (QI['quant']))

    if dWI < 0:  # WI_I < WO_I, sign extend integer part
        #mod.comb += sig_o.eq(sig_i_q >> -dWI)
        mod.comb += sig_o.eq(Cat(sig_i_q, Replicate(sig_i_q[-1], -dWI)))
    elif dWI == 0:  # WI = WO, don't change integer part
        mod.comb += sig_o.eq(sig_i_q)
    elif QO['ovfl'] == 'sat':
        mod.comb += \
            If(sig_i_q[-1] == 1,
               If(sig_i_q < MIN_o,
               #If(sig_i_q[-dWI-1:-1] != Replicate(sig_i_q[-1], dWI),
                    sig_o.eq(MIN_o)
                ).Else(sig_o.eq(sig_i_q))#[:-dWI-1]))# >> dWI
            ).Elif(sig_i_q > MAX_o,
            #).Elif(sig_i_q[WO-1:] == 0b01,
                sig_o.eq(MAX_o)
            ).Else(sig_o.eq(sig_i_q)#[:-dWI-1])# >> dWI)
            )
    elif QO['ovfl'] == 'wrap':  # wrap around (shift left)
        mod.comb += sig_o.eq(sig_i_q)  # >> dWI)
        #mod.comb += sig_o.eq(Replicate(sig_i_q[-1], abs(dWI)))
        #mod.comb += sig_o.eq(sig_i_q[-dWI-1:-1])
# =============================================================================
#             If(sig_i_q[-1] == 1,
#                If(sig_i_q[-1:-dWI-1] != Replicate(sig_i_q[-1], dWI),
#             #If(sig_i_q < MIN_o,
#             #If(sig_i_q[WO-1:] == 0b10,
#                     sig_o.eq(MIN_o)
#                 ).Else(sig_o.eq(sig_i_q)# >> dWI
#             ).Elif(sig_i_q > MAX_o,
#             #).Elif(sig_i_q[WO-1:] == 0b01,
#                 sig_o.eq(MAX_o)
#             ).Else(sig_o.eq(sig_i_q)# >> dWI)
#             )
# =============================================================================

    else:
        raise Exception(u'Unknown overflow method "%s"!' % (QI['ovfl']))

    return sig_o
Beispiel #19
0
    def init_submodules(
        self, width, signal_width, coeff_width, chain_factor_bits, platform
    ):
        sys_double = ClockDomainsRenamer("sys_double")

        self.submodules.logic = LinienLogic(chain_factor_width=chain_factor_bits)
        self.submodules.analog = PitayaAnalog(
            platform.request("adc"), platform.request("dac")
        )
        self.submodules.xadc = XADC(platform.request("xadc"))

        for i in range(4):
            pwm = platform.request("pwm", i)
            ds = sys_double(DeltaSigma(width=15))
            self.comb += pwm.eq(ds.out)
            setattr(self.submodules, "ds%i" % i, ds)

        exp = platform.request("exp")
        self.submodules.gpio_n = Gpio(exp.n)
        self.submodules.gpio_p = Gpio(exp.p)

        leds = Cat(*(platform.request("user_led", i) for i in range(8)))
        self.comb += leds.eq(self.gpio_n.o)

        self.submodules.dna = DNA(version=2)

        self.submodules.fast_a = FastChain(
            width,
            signal_width,
            coeff_width,
            self.logic.mod,
            offset_signal=self.logic.chain_a_offset_signed,
        )
        self.submodules.fast_b = FastChain(
            width,
            signal_width,
            coeff_width,
            self.logic.mod,
            offset_signal=self.logic.chain_b_offset_signed,
        )

        sys_slow = ClockDomainsRenamer("sys_slow")
        sys_double = ClockDomainsRenamer("sys_double")
        max_decimation = 16
        self.submodules.decimate = sys_double(Decimate(max_decimation))
        self.clock_domains.cd_decimated_clock = ClockDomain()
        decimated_clock = ClockDomainsRenamer("decimated_clock")
        self.submodules.slow = decimated_clock(SlowChain())

        self.submodules.scopegen = ScopeGen(signal_width)

        self.state_names, self.signal_names = cross_connect(
            self.gpio_n,
            [
                ("fast_a", self.fast_a),
                ("fast_b", self.fast_b),
                ("slow", self.slow),
                ("scopegen", self.scopegen),
                ("logic", self.logic),
                ("robust", self.logic.autolock.robust),
            ],
        )

        csr_map = {
            "dna": 28,
            "xadc": 29,
            "gpio_n": 30,
            "gpio_p": 31,
            "fast_a": 0,
            "fast_b": 1,
            "slow": 2,
            "scopegen": 6,
            "noise": 7,
            "logic": 8,
        }

        self.submodules.csrbanks = csr_bus.CSRBankArray(
            self,
            lambda name, mem: csr_map[
                name if mem is None else name + "_" + mem.name_override
            ],
        )
        self.submodules.sys2csr = Sys2CSR()
        self.submodules.csrcon = csr_bus.Interconnect(
            self.sys2csr.csr, self.csrbanks.get_buses()
        )
        self.submodules.syscdc = SysCDC()
        self.comb += self.syscdc.target.connect(self.sys2csr.sys)
Beispiel #20
0
    def add_xgmii(self):
        self.submodules.xgmii = XilinxXGMII(self.crg.cd_sys, self.platform)
        self.add_csr('xgmii')
        self.platform.add_period_constraint(self.xgmii.cd_clkmgt.clk, 1e9/156.25e6)
        self.platform.add_false_path_constraints(self.crg.cd_sys.clk, self.xgmii.cd_clkmgt.clk)

        self.submodules.xgmiiphy = LiteEthPHYXGMII(self.xgmii.pads, self.xgmii.pads)

        # Keeping this away from sys_clk domain, and strictly leaving it in 156.25e6
        self.submodules.teng_udp_core = ClockDomainsRenamer("clkmgt")(LiteEthUDPIPCore(self.xgmiiphy,
                                                                                       0xaa1233445566,
                                                                                       convert_ip("10.1.0.3"),
                                                                                       self.sys_clk_freq,
                                                                                       dw=64))
        self.add_csr("xgmiiphy")
        self.udp_port = udp_port = self.teng_udp_core.udp.crossbar.get_port(3000, 64)

        send_pkt = Signal(reset=0)
        always_xmit = True
        if always_xmit:
            send_pkt_counter_d = Signal()
            self.sync.clkmgt += [
                send_pkt_counter_d.eq(self.counter[26]),
                send_pkt.eq(send_pkt_counter_d ^ self.counter[26])
            ]

        sink_counter = Signal(16)
        SINK_LENGTH = 64           # 8 words
        shift = log2_int(64 // 8)  # bits required to represent bytes per word
        words_per_packet = SINK_LENGTH >> shift
        # Note the clkmgt domain
        self.sync.clkmgt += [
            If(send_pkt,
               sink_counter.eq(words_per_packet)),
            If((sink_counter > 0) & (udp_port.sink.ready == 1),
               sink_counter.eq(sink_counter - 1)
            ).Else(
                udp_port.sink.valid.eq(0),
                udp_port.sink.last.eq(0)
            ),
            udp_port.sink.valid.eq(sink_counter > 0),
            udp_port.sink.last.eq(sink_counter == 1),
            If(sink_counter == 1,
               udp_port.sink.last_be.eq(0x80)
            ).Else(
               udp_port.sink.last_be.eq(0x0)
            )
        ]

        self.comb += self.user_leds[1].eq(udp_port.sink.valid)
        self.comb += [
            # param
            udp_port.sink.src_port.eq(3000),
            udp_port.sink.dst_port.eq(7778),
            udp_port.sink.ip_address.eq(convert_ip("10.1.0.4")),
            udp_port.sink.length.eq(SINK_LENGTH),

            # payload
            udp_port.sink.data.eq(Cat(0xc0ffeec1ffee, sink_counter)),
            udp_port.sink.error.eq(0)
        ]
        self.add_csr("teng_udp_core")
    def __init__(self, pads):
        self.pads = pads
        self.bus = bus = Interface(adr_width=22)

        self.dly_io = delayf_pins()
        self.dly_clk = delayf_pins()

        # # #

        clk = Signal()
        cs = Signal()
        ca = Signal(48)
        sr_in = Signal(64)
        sr_out = Signal(64)
        sr_rwds_in = Signal(8)
        sr_rwds_out = Signal(8)

        timeout_counter = Signal(6)

        self.submodules.phy = phy = HyperBusPHY(pads)

        self.comb += [
            phy.dly_io.eq(self.dly_io),
            phy.dly_clk.eq(self.dly_clk),
        ]

        # Drive rst_n, from internal signals ---------------------------------------------
        if hasattr(pads, "rst_n"):
            self.comb += pads.rst_n.eq(1)

        self.comb += [phy.cs.eq(~cs), phy.clk_enable.eq(clk)]

        # Data In/Out Shift Registers -------------------------------------------------
        self.sync += [
            sr_out.eq(Cat(Signal(32), sr_out[:32])),
            sr_in.eq(Cat(phy.dq.i, sr_in[:32])),
            sr_rwds_in.eq(Cat(phy.rwds.i, sr_rwds_in[:4])),
            sr_rwds_out.eq(Cat(phy.rwds.i, sr_rwds_out[:4])),
        ]

        self.comb += [
            bus.dat_r.eq(Cat(phy.dq.i[-16:], sr_in[:16])),  # To Wishbone
            phy.dq.o.eq(sr_out[-32:]),  # To HyperRAM
            phy.rwds.o.eq(sr_rwds_out[-4:])  # To HyperRAM
        ]

        # Command generation -----------------------------------------------------------------------
        self.comb += [
            ca[47].eq(~self.bus.we),  # R/W#
            ca[45].eq(1),  # Burst Type (Linear)
            ca[16:35].eq(self.bus.adr[2:21]),  # Row & Upper Column Address
            ca[1:3].eq(self.bus.adr[0:2]),  # Lower Column Address
            ca[0].eq(0),  # Lower Column Address
        ]

        # FSM Sequencer --------------------------------------------------------------------------------
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE",
                If(bus.cyc & bus.stb, NextValue(cs, 1), NextState("CA-SEND")))
        fsm.act("CA-SEND", NextValue(clk, 1), NextValue(phy.dq.oe, 1),
                NextValue(sr_out, Cat(Signal(16), ca)), NextState("CA-WAIT"))
        fsm.act("CA-WAIT", NextValue(timeout_counter, 0), NextState("LATENCY"))
        fsm.act("LATENCY", NextValue(phy.dq.oe, 0), NextState("LATENCY-WAIT"))

        fsm.delayed_enter("LATENCY-WAIT", "READ-WRITE-SETUP", 3)

        fsm.act("READ-WRITE-SETUP", NextValue(phy.dq.oe, self.bus.we),
                NextValue(phy.rwds.oe, self.bus.we), NextState("READ-WRITE"))
        fsm.act(
            "READ-WRITE",
            NextState("READ-ACK"),
            If(
                self.bus.we,
                NextValue(phy.dq.oe, 1),  # Write Cycle
                NextValue(sr_out[:32], 0),
                NextValue(sr_out[32:], self.bus.dat_w),
                NextValue(sr_rwds_out[:4], 0),
                NextValue(sr_rwds_out[4:], ~bus.sel[0:4]),
                bus.ack.eq(1),  # Get next byte
                NextState("CLK-OFF"),
                If(
                    bus.cti == 0b010,
                    NextState("READ-WRITE"),
                )))

        fsm.act(
            "READ-ACK", NextValue(timeout_counter, timeout_counter + 1),
            If(phy.rwds.i[3], NextValue(timeout_counter, 0), bus.ack.eq(1),
               If(bus.cti != 0b010, NextValue(clk, 0), NextState("CLEANUP"))),
            If(~self.bus.cyc | (timeout_counter > 20), NextState("CLK-OFF")))

        fsm.act("CLK-OFF", NextValue(clk, 0), NextState("CLEANUP"))
        fsm.act("CLEANUP", NextValue(cs, 0), NextValue(phy.rwds.oe, 0),
                NextValue(phy.dq.oe, 0), NextState("HOLD-WAIT"))
        fsm.act("HOLD-WAIT", NextValue(sr_out, 0), NextValue(sr_rwds_out, 0),
                NextState("WAIT"))
        fsm.delayed_enter("WAIT", "IDLE", 10)

        # Signals that can be an ILA for debugging
        self.dbg = [
            bus,
            sr_out,
            sr_in,
            sr_rwds_in,
            sr_rwds_out,
            cs,
            clk,
            phy.dq.i,
            phy.dq.o,
            phy.dq.oe,
            phy.rwds.i,
            phy.rwds.o,
            phy.rwds.oe,
        ]
Beispiel #22
0
    def __init__(self, ddr_wr_port, ddr_rd_port, udp_port, adc_source, adc_dw):
        SIZE = 1024 * 1024
        self.fifo_full = CSRStatus(reset=0)
        self.fifo_error = CSRStatus(reset=0)
        self.fifo_load = CSRStorage(reset=0)
        self.fifo_read = CSRStorage(reset=0)
        self.fifo_size = CSRStorage(32, reset=SIZE)
        self.dst_ip = CSRStorage(32, reset=convert_ip("192.168.1.114"))
        self.dst_port = CSRStorage(16, reset=7778)

        self.fifo_counter = fifo_counter = Signal(24)
        self.load_fifo = load_fifo = Signal()

        dw = ddr_wr_port.data_width

        print(
            f"Write port: A ({ddr_wr_port.address_width})/ D ({ddr_wr_port.data_width})"
        )
        print(
            f"Read port: A ({ddr_rd_port.address_width})/ D ({ddr_rd_port.data_width})"
        )
        print(f"dw: {dw}; adc_dw: {adc_dw}")
        self.submodules.dram_fifo = dram_fifo = LiteDRAMFIFO(
            data_width=dw,
            base=0,
            depth=SIZE * (dw // 8),  # liteDRAM expects this in bytes
            write_port=ddr_wr_port,
            read_port=ddr_rd_port,
        )

        self.adc_data = adc_data = Signal(dw)
        DW_RATIO = dw // adc_dw
        log_dw_ratio = log2_int(DW_RATIO)
        word_count = Signal(log_dw_ratio)
        word_count_d = Signal(log_dw_ratio)

        self.sync += [
            If(adc_source.valid,
               adc_data.eq(Cat(adc_data[adc_dw:], adc_source.data)),
               word_count.eq(word_count + 1)),
            word_count_d.eq(word_count),
        ]

        self.comb += [
            dram_fifo.sink.valid.eq((word_count == 0) & (word_count_d != 0)
                                    & load_fifo),
            dram_fifo.sink.data.eq(adc_data)
        ]

        fifo_size = Signal(32)
        self.sync += [
            fifo_size.eq(self.fifo_size.storage),
            If(self.fifo_load.re & self.fifo_load.storage, fifo_counter.eq(0),
               load_fifo.eq(1)),
            If(load_fifo & adc_source.valid, self.fifo_full.status.eq(0),
               self.fifo_error.status.eq(~dram_fifo.dram_fifo.ctrl.writable),
               fifo_counter.eq(fifo_counter + 1)),
            If((fifo_counter == fifo_size - 1) & adc_source.valid,
               load_fifo.eq(0), self.fifo_full.status.eq(1)),
        ]

        # fifo --> stride converter
        self.submodules.stride_converter = sc = stream.Converter(
            dw, udp_port.dw)

        self.read_from_dram_fifo = read_from_dram_fifo = Signal()
        self.comb += [dram_fifo.source.connect(sc.sink)]
        self.receive_count = receive_count = Signal(24)
        self.sync += [
            If(dram_fifo.source.valid & dram_fifo.source.ready,
               receive_count.eq(receive_count + 1)).Elif(
                   read_from_dram_fifo == 0, receive_count.eq(0))
        ]
        # --> udp fragmenter -->
        self.submodules.udp_fragmenter = udp_fragmenter = UDPFragmenter(
            udp_port.dw)

        self.sync += read_from_dram_fifo.eq(self.fifo_read.storage)
        self.comb += If(
            read_from_dram_fifo,
            # TODO: There is a bug somewhere in the converter,
            # its source.last somehow gets set, no idea why. That signal is of no real use
            # for the fragmenter anyways, so we live without it
            sc.source.connect(udp_fragmenter.sink, omit={'total_size',
                                                         'last'}))

        # TODO: 8 should be adcstream data width // 8
        self.comb += udp_fragmenter.sink.length.eq(
            fifo_size << log2_int(adc_dw // 8))
        self.comb += udp_fragmenter.source.connect(udp_port.sink)
        self.comb += [
            # param
            udp_port.sink.src_port.eq(4321),
            udp_port.sink.dst_port.eq(self.dst_port.storage),
            udp_port.sink.ip_address.eq(self.dst_ip.storage),
            # udp_port.sink.ip_address.eq(convert_ip("192.168.88.101")),
            # payload
            udp_port.sink.error.eq(0)
        ]
Beispiel #23
0
    def __init__(self, c2):

        txwidth = 13
        txlen = Signal(max=txwidth + 1)
        txbuf = Signal(txwidth)
        rxbuf = Signal(8)
        rxlen = Signal(4)

        waitlen = Signal(7)
        rfull = Signal()
        readerror = Signal()

        reset_count = Signal(max=961)

        self._cmd = CSRStorage(8)
        self._stat = CSRStatus(8)
        self._rxbuf = CSRStatus(8)
        self.comb += self._rxbuf.status.eq(rxbuf)
        self._txdat = CSRStorage(8)

        c2d = TSTriple()
        c2ck = Signal(reset=1)
        self.comb += c2.c2ck.eq(c2ck)
        self.specials += c2d.get_tristate(c2.c2d)

        self._pwcon = CSRStorage(8, reset=1)
        self._glitchoff = CSRStorage(32)
        self._glitchlen = CSRStorage(8)
        glitchout = Signal()
        glitchmode = Signal()
        glitchtmr = Signal(32)
        self.comb += c2.power.eq(self._pwcon.storage[0] & glitchout)
        self.sync += If(self._pwcon.storage[1], self._pwcon.storage[1].eq(0),
                        glitchmode.eq(0),
                        glitchtmr.eq(self._glitchoff.storage))
        self.sync += If(glitchtmr == 0, glitchout.eq(1)).Else(
            glitchtmr.eq(glitchtmr - 1), glitchout.eq(~glitchmode),
            If(
                glitchtmr == 1,
                If(glitchmode == 0, glitchtmr[:8].eq(self._glitchlen.storage),
                   glitchmode.eq(1))))

        # when rxbuf is read, reset the buffer full flag
        self.sync += If(self._rxbuf.we, rfull.eq(0))

        fsm = FSM(reset_state="IDLE")
        self.submodules.fsm = fsm

        fsm.act(
            "IDLE",
            c2d.oe.eq(0),
            NextValue(c2ck, 1),
            If(
                self._cmd.storage == 1,  # data read
                NextValue(self._cmd.storage, 0),
                NextValue(txbuf, 1),  # start(1), data read (00), length (00)
                NextValue(txlen, 5),
                NextValue(rxlen, 8),
                NextValue(readerror, 0),
                NextValue(waitlen, 127),
                NextState("TX")).Elif(
                    self._cmd.storage == 2,  # address write
                    NextValue(self._cmd.storage, 0),
                    # start (1), address write (11), address
                    NextValue(txbuf, (self._txdat.storage << 3) | 7),
                    NextValue(txlen, 11),
                    NextValue(rxlen, 0),
                    NextValue(waitlen, 0),
                    NextState("TX")).Elif(
                        self._cmd.storage == 3,  # address read
                        NextValue(self._cmd.storage, 0),
                        NextValue(waitlen, 0),
                        NextValue(txbuf, 5),  # start (1), address read (01)
                        NextValue(txlen, 3),
                        NextValue(waitlen, 0),  # no wait
                        NextValue(rxlen, 8),  # read 8 bits
                        NextValue(readerror, 0),
                        NextState("TX")).Elif(
                            self._cmd.storage == 4,  # data write
                            NextValue(self._cmd.storage, 0),
                            NextValue(waitlen, 0),
                            # start (1), data write (10), length (00), data
                            NextValue(txbuf, (self._txdat.storage << 5) | 3),
                            NextValue(txlen, 13),
                            NextValue(waitlen, 127),  # wait at the end
                            NextValue(rxlen, 0),  # no read
                            NextState("TX")).Elif(
                                self._cmd.storage == 5,  # reset
                                NextValue(self._cmd.storage, 0),
                                NextValue(reset_count, 960),  # 20us at 48MHz
                                NextValue(c2ck, 0),
                                NextState("RESET")))

        fsm.act(
            "RESET",  # 20us reset line low
            NextValue(c2ck, 0),
            If(
                reset_count == 0,
                NextValue(reset_count, 96),  # 2us at 48MHz
                NextState("RESET2")).Else(
                    NextValue(reset_count, reset_count - 1), ))

        fsm.act(
            "RESET2",  # 2us reset line high
            NextValue(c2ck, 1),
            If(reset_count == 0,
               NextState("IDLE")).Else(NextValue(reset_count,
                                                 reset_count - 1), ))

        fsm.act(
            "TX",
            # clk initially 1 here
            c2d.oe.eq(1),
            If(
                txlen == 0,
                If(
                    waitlen != 0,
                    NextState("WAIT"),
                ).Elif(
                    rxlen != 0,
                    NextState("RX"),
                ).Else(NextState("STOP")), NextValue(c2ck, 0)).
            Else(
                If(
                    c2ck == 1,  # clock is high, about to drop the next bit
                    NextValue(c2d.o, txbuf[0]),
                    NextValue(txbuf, txbuf[1:])).
                Else(
                    # clock is low, about to raise it and potentially advance to the next state
                    NextValue(txlen, txlen - 1)),
                NextValue(c2ck, ~c2ck)))

        fsm.act(
            "WAIT",
            # must enter state with c2ck already at 0
            c2d.oe.eq(0),
            If((c2ck == 1) & (c2d.i == 1),
               If(rxlen != 0, NextState("RX")).Else(NextState("STOP")),
               NextValue(c2ck, 0)).Else(
                   If(waitlen == 0, NextValue(readerror, 1),
                      NextState("IDLE")).Else(NextValue(waitlen, waitlen - 1),
                                              NextValue(c2ck, ~c2ck))))

        fsm.act(
            "RX",
            # must enter state with c2ck already at 0
            c2d.oe.eq(0),
            If(
                c2ck == 1,  # clock is high, shift in bit as it falls
                NextValue(rxbuf, Cat(rxbuf[1:], c2d.i)),
                If(rxlen == 1, NextValue(rfull, 1), NextState("STOP")),
                NextValue(c2ck, 0),
                NextValue(rxlen, rxlen - 1),
            ).Else(NextValue(c2ck, 1)))

        fsm.act(
            "STOP",
            # must enter state with c2ck already at 0
            c2d.oe.eq(0),
            If(
                c2ck == 1,  # stop done
                NextState("IDLE")).Else(NextValue(c2ck, 1)))

        # status register byte:
        # |  7  |  6   | 5 | 4 |  3   |  2 |  1 |  0   |
        # | ERR | RRDY | . | . | WAIT | RX | TX | IDLE |
        self.comb += self._stat.status.eq(
            fsm.ongoing("IDLE") | (fsm.ongoing("TX") << 1)
            | (fsm.ongoing("RX") << 2) | (fsm.ongoing("WAIT") << 3)
            | (rfull << 6) | (readerror << 7))

        # for debugging, expose internals
        self._txlen = CSRStatus(5)
        self._txbuf = CSRStatus(12)
        self._rxlen = CSRStatus(4)
        self._waitlen = CSRStatus(7)

        self.comb += self._txlen.status.eq(txlen)
        self.comb += self._txbuf.status.eq(txbuf)
        self.comb += self._rxlen.status.eq(rxlen)
        self.comb += self._waitlen.status.eq(waitlen)
Beispiel #24
0
    def __init__(
        self,
        core_link_pads: typing.Sequence[platform.Pins],
        output_pads: typing.Sequence[platform.Pins],
        passthrough_sigs: typing.Sequence[Signal],
        input_phys: typing.Sequence["PHY"],
        simulate: bool = False,
    ):
        """Define the submodules & connections between them to form an ``Entangler``.

        Args:
            core_link_pads (typing.Sequence[platform.Pins]): A list of 4 FPGA pins
                used to link a master & slave ``Entangler`` device.
            output_pads (typing.Sequence[platform.Pins]): The output pins that will
                be driven by the state machines to output the entanglement generation
                signals.
            passthrough_sigs (typing.Sequence[Signal]): The signals that should be
                passed through to the ``output_pads`` when the ``Entangler`` is not
                running.
            input_phys (typing.Sequence["PHY"]): TTLInput physical gateware modules
                that register an input TTL event. Expects a list of 4, with
                the first 4 being the input APD/TTL signals, and the last one
                as a sync signal with the entanglement laser.
            simulate (bool, optional): If this should be instantiated in
                simulation mode. If it is simulated, it disables several options like
                the passthrough_sigs. Defaults to False.
        """
        self.enable = Signal()
        # # #

        phy_apds = input_phys[0:4]
        phy_422pulse = input_phys[4]

        self.submodules.msm = MainStateMachine()

        self.submodules.sequencers = [
            ChannelSequencer(self.msm.m) for _ in range(4)
        ]

        self.submodules.apd_gaters = [
            TriggeredInputGater(self.msm.m, phy_422pulse, phy_apd)
            for phy_apd in phy_apds
        ]

        self.submodules.heralder = PatternMatcher(num_inputs=4, num_patterns=4)

        if not simulate:
            # To be able to trigger the pulse picker from both systems without
            # re-plugging cables, we OR the output from the slave (transmitted over the
            # core link ribbon cable) into the master, as long as the entangler core is
            # not actually active. There is no mechanism to arbitrate between concurrent
            # users at this level; the application code must ensure only one experiment
            # requiring the pulsed laser runs at a time.
            local_422ps_out = Signal()
            slave_422ps_raw = Signal()

            # Connect output pads to sequencer output when enabled, otherwise use
            # the RTIO phy output
            for i, (sequencer, pad, passthrough_sig) in enumerate(
                    zip(self.sequencers, output_pads, passthrough_sigs)):
                if i == SEQUENCER_IDX_422ps:
                    local_422ps_out = Mux(self.enable, sequencer.output,
                                          passthrough_sig)
                    passthrough_sig = passthrough_sig | (slave_422ps_raw
                                                         & self.msm.is_master)
                self.specials += Instance(
                    "OBUFDS",
                    i_I=Mux(self.enable, sequencer.output, passthrough_sig),
                    o_O=pad.p,
                    o_OB=pad.n,
                )

            # Connect the "running" output, which is asserted when the core is
            # running, or controlled by the passthrough signal when the core is
            # not running.
            self.specials += Instance(
                "OBUFDS",
                i_I=Mux(self.msm.running, 1, passthrough_sigs[4]),
                o_O=output_pads[4].p,
                o_OB=output_pads[4].n,
            )

            def ts_buf(pad, sig_o, sig_i, en_out):
                # diff. IO.
                # sig_o: output from FPGA
                # sig_i: intput to FPGA
                # en_out: enable FPGA output driver
                self.specials += Instance(
                    "IOBUFDS_INTERMDISABLE",
                    p_DIFF_TERM="TRUE",
                    p_IBUF_LOW_PWR="TRUE",
                    p_USE_IBUFDISABLE="TRUE",
                    i_IBUFDISABLE=en_out,
                    i_INTERMDISABLE=en_out,
                    i_I=sig_o,
                    o_O=sig_i,
                    i_T=~en_out,
                    io_IO=pad.p,
                    io_IOB=pad.n,
                )

            # Interface between master and slave core.

            # Slave -> master:
            ts_buf(
                core_link_pads[0],
                self.msm.ready,
                self.msm.slave_ready_raw,
                ~self.msm.is_master & ~self.msm.standalone,
            )

            ts_buf(core_link_pads[4], local_422ps_out, slave_422ps_raw,
                   ~self.msm.is_master)

            # Master -> slave:
            ts_buf(
                core_link_pads[1],
                self.msm.trigger_out,
                self.msm.trigger_in_raw,
                self.msm.is_master,
            )
            ts_buf(
                core_link_pads[2],
                self.msm.success,
                self.msm.success_in_raw,
                self.msm.is_master,
            )
            ts_buf(
                core_link_pads[3],
                self.msm.timeout,
                self.msm.timeout_in_raw,
                self.msm.is_master,
            )

        # Connect heralder inputs.
        self.comb += self.heralder.sig.eq(
            Cat(*(g.triggered for g in self.apd_gaters)))

        # Clear gater and sequencer state at start of each cycle
        self.comb += [
            gater.clear.eq(self.msm.cycle_starting)
            for gater in self.apd_gaters
        ]
        self.comb += [
            sequencer.clear.eq(self.msm.cycle_starting)
            for sequencer in self.sequencers
        ]

        self.comb += self.msm.herald.eq(self.heralder.is_match)

        # 422ps trigger event counter. We use got_ref from the first gater for
        # convenience (any other channel would work just as well).
        self.triggers_received = Signal(14)
        self.sync += [
            If(self.msm.run_stb, self.triggers_received.eq(0)).Else(
                If(
                    self.msm.cycle_ending & self.apd_gaters[0].got_ref,
                    self.triggers_received.eq(self.triggers_received + 1),
                ))
        ]
Beispiel #25
0
    def __init__(self, cd_sys, platform, dw=64):
        self._reset = CSRStorage(reset=0)
        self._pcs_status = CSRStatus(fields=[
            CSRField("pcs_fault", size=1, offset=1),
            CSRField("pcs_fault_rx", size=1, offset=2),
            CSRField("pcs_fault_tx", size=1, offset=3),
        ])
        self._pcs_config = CSRStorage(reset=0, fields=[
            CSRField("pcs_clear", size=1, offset=0, pulse=True),
        ])


        self.clock_domains.cd_clkmgt = ClockDomain()

        self.tx_data = Signal(dw)
        self.tx_ctl = Signal(dw//8)

        self.rx_data = Signal(dw)
        self.rx_ctl = Signal(dw//8)
        self.pma_status = Signal(448)
        _pma_status = Signal(448)

        txusrclk = Signal()
        txusrclk2 = Signal()

        drp_req = Signal()

        drp_daddr_o = Signal(16)
        drp_den_o   = Signal()
        drp_di_o    = Signal(16)
        drp_dwe_o   = Signal()
        drp_drpdo_i = Signal(16)
        drp_drdy_i  = Signal()
        drp_den_i   = Signal()

        refclk_pads = platform.request("user_sma_mgt_refclk")
        rx_pads     = platform.request("sfp_rx")
        tx_pads     = platform.request("sfp_tx")
        self.tx_disable = Signal()
        self.qplllock   = Signal()
        self.gtrxreset  = Signal()
        self.gttxreset  = Signal()
        self.txusrrdy   = Signal()

        self.coreclk = Signal()

        self.comb += [
            platform.request("sfp_tx_disable_n").eq(~self.tx_disable),
        ]

        self.pcs_clear = pcs_clear = Signal()
        config_vector = Signal(536, reset=0)
        self.submodules.ps = PulseSynchronizer("sys", "clkmgt")
        self.pma_multi = pma_multi = Signal(3)
        self.specials += MultiReg(Cat(self.pma_status[250:252], self.pma_status[231]), pma_multi)
        self.comb += [
            self.ps.i.eq(self._pcs_config.fields.pcs_clear),
            pcs_clear.eq(self.ps.o),
            self._pcs_status.fields.pcs_fault_rx.eq(pma_multi[0]),
            self._pcs_status.fields.pcs_fault_tx.eq(pma_multi[1]),
            self._pcs_status.fields.pcs_fault.eq(pma_multi[2])
        ]

        self.comb += [
            ClockSignal("clkmgt").eq(self.coreclk)
        ]
        self.sync.clkmgt += [
            config_vector[517].eq(pcs_clear),
            self.pma_status.eq(_pma_status)
        ]

        self.specials += Instance(
            "ten_gig_eth_pcs_pma_0",
            i_refclk_p=refclk_pads.p,
            i_refclk_n=refclk_pads.n,
            i_reset=self._reset.storage,
            # o_resetdone_out=
            o_coreclk_out=self.coreclk,
            # rxrecclkout_0=rxrecclkout_0, # What is
            i_rxp=rx_pads.p,
            i_rxn=rx_pads.n,
            o_txp=tx_pads.p,
            o_txn=tx_pads.n,
            i_dclk=cd_sys.clk,
            i_sim_speedup_control=0,
            o_txusrclk_out=txusrclk,
            o_txusrclk2_out=txusrclk2,    # UltraScale only
            #o_areset_datapathclk_out=
            o_qplllock_out=self.qplllock,

            o_txuserrdy_out=self.txusrrdy,
            #o_reset_counter_done=,  # UltraScale only


            o_gttxreset_out=self.gttxreset,
            o_gtrxreset_out=self.gtrxreset, # TODO Set it to 5 seconds?

            o_xgmii_rxd=self.rx_data,
            o_xgmii_rxc=self.rx_ctl,
            i_xgmii_txd=self.tx_data,
            i_xgmii_txc=self.tx_ctl,

            i_configuration_vector=config_vector,
            o_status_vector=_pma_status,
            # o_core_status=,
            # tx_resetdone=,
            # rx_resetdone=,

            # Connects to sfp+
            i_signal_detect=1,
            i_tx_fault=0,  # Unused inside the core
            o_tx_disable=self.tx_disable,

            i_pma_pmd_type=0b111,

            # DRP Stuff
            o_drp_req=drp_req,
            i_drp_gnt=drp_req,

            o_drp_daddr_o=drp_daddr_o,
            o_drp_den_o=drp_den_o,
            o_drp_di_o=drp_di_o,
            o_drp_dwe_o=drp_dwe_o,
            i_drp_drpdo_i=drp_drpdo_i,
            i_drp_drdy_i=drp_drdy_i,

            i_drp_daddr_i=drp_daddr_o,
            i_drp_den_i=drp_den_o,
            i_drp_di_i=drp_di_o,
            i_drp_dwe_i=drp_dwe_o,
            o_drp_drpdo_o=drp_drpdo_i,
            o_drp_drdy_o=drp_drdy_i,
        )
        class Pads:
            rx = ClockSignal("clkmgt")
            rx_ctl = self.rx_ctl
            rx_data = self.rx_data
            tx = ClockSignal("clkmgt")
            tx_ctl = self.tx_ctl
            tx_data = self.tx_data
        self.pads = Pads()
Beispiel #26
0
    def __init__(self,
                 core_link_pads,
                 output_pads,
                 passthrough_sigs,
                 input_phys,
                 simulate=False):
        """
        Define the interface between an ARTIQ RTIO bus and low-level gateware.

        Args:
            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
        """
        self.rtlink = rtlink.Interface(
            rtlink.OInterface(data_width=32,
                              address_width=5,
                              enable_replace=False),
            rtlink.IInterface(data_width=14, timestamped=True),
        )

        # # #

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

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

        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]
        cases = {}
        for i in range(len(output_t_starts)):
            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], cases),
            ),
            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)]  # noqa
                    ) 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_timings = 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_timings.eq(self.rtlink.o.address[3:5] == 0b11),
                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_read = Signal(14)
        cases = {}
        cases[0] = [reg_read.eq(status)]
        cases[1] = [reg_read.eq(self.core.msm.cycles_completed)]
        cases[2] = [reg_read.eq(self.core.msm.time_remaining)]
        cases[3] = [reg_read.eq(self.core.triggers_received)]
        self.comb += Case(read_addr, cases)

        # 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_timings, timing_data, reg_read),
                )),
        ]
    def __init__(self, testcase, dut_class, args=None, specials=None):
        self.i_go = Signal()  # Unused for now.

        # Outputs

        #: Signal: up if the test process is over.
        self.o_over = Signal()

        #: Signal: up if the test result is successful. Relevant only when
        #          `o_over` is up.
        self.o_success = Signal(reset=1)

        # Locals

        #: dict: association between DUT's output signals names and signals.
        self._test_outs = self._make_outputs_signals(testcase.io_decl)

        #: Signal(n): concatenation of all signals contained in
        #             `self.test_outs`.
        self._cat_test_outs = Cat(
            [signal for _, signal in self._test_outs.items()])

        # Sub-modules

        #: Module: device under test's module instance.
        self._dut = dut_class() if args is None else dut_class(*args)

        self.submodules += self._dut

        # Specials
        if specials is not None:
            self.specials += specials

        ###

        cases = {}
        tick_count = 0

        in_q, exp_q = testcase.get_io_queues()

        while not in_q.empty() or not exp_q.empty():
            cases[tick_count] = []

            in_values = None if in_q.empty() else in_q.get()
            if in_values is not None:
                cases[tick_count] += self._make_inputs_applications(in_values)

            exp_values = None if exp_q.empty() else exp_q.get()
            if exp_values is not None:
                cases[tick_count] += self._make_outputs_checker(exp_values)

            tick_count += 1

        # Counter initialization using `tick_count`
        counter = Counter(tick_count + 2)
        self.submodules += counter

        self.sync += Case(counter.o, cases)

        # `self.o_over` control
        self.comb += [self.o_over.eq(counter.o == tick_count + 1)]

        # `self.o_success` control
        self.sync += [
            If(self.o_success == 1,
               self.o_success.eq(self._cat_test_outs == 0))
            .Else(
                self.o_success.eq(0))
        ]