Esempio n. 1
0
 def elab(self, m):
     results_counter = Signal.like(self.num_results.payload)
     accumulator = Signal.like(self.accumulated.payload)
     with m.FSM():
         with m.State('IDLE'):
             m.d.comb += self.num_results.ready.eq(1)
             with m.If(self.num_results.is_transferring()):
                 m.d.sync += results_counter.eq(self.num_results.payload)
                 m.next = 'ACCUMULATING'
         with m.State('ACCUMULATING'):
             m.d.comb += self.results.ready.eq(1)
             with m.If(self.results.is_transferring()):
                 m.d.sync += accumulator.eq(accumulator +
                                            self.results.payload)
                 with m.If(results_counter > 1):
                     m.d.sync += results_counter.eq(results_counter - 1)
                 with m.Else():
                     m.d.sync += results_counter.eq(0)
                     m.next = 'DONE'
         with m.State('DONE'):
             m.d.sync += self.accumulated.payload.eq(accumulator)
             m.d.sync += self.accumulated.valid.eq(1)
             m.d.sync += accumulator.eq(0)
             with m.If(self.accumulated.is_transferring()):
                 m.d.sync += self.accumulated.valid.eq(0)
                 m.next = 'IDLE'
Esempio n. 2
0
    def elab(self, m):
        # Track previous restart, next
        was_restart = Signal()
        m.d.sync += was_restart.eq(self.restart)
        was_next = Signal()
        m.d.sync += was_next.eq(self.next)

        # Decide address to be output (determines data available next cycle)
        last_mem_addr = Signal.like(self.mem_addr)
        m.d.sync += last_mem_addr.eq(self.mem_addr)
        incremented_addr = Signal.like(self.limit)
        m.d.comb += incremented_addr.eq(
            Mux(last_mem_addr == self.limit - 1, 0, last_mem_addr + 1))
        with m.If(self.restart):
            m.d.comb += self.mem_addr.eq(0)
        with m.Elif(was_next | was_restart):
            m.d.comb += self.mem_addr.eq(incremented_addr)
        with m.Else():
            m.d.comb += self.mem_addr.eq(last_mem_addr)

        # Decide data to be output
        last_data = Signal.like(self.data)
        m.d.sync += last_data.eq(self.data)
        with m.If(was_restart | was_next):
            m.d.comb += self.data.eq(self.mem_data)
        with m.Else():
            m.d.comb += self.data.eq(last_data)
Esempio n. 3
0
    def elab(self, m):
        # number of bytes received already
        byte_count = Signal(range(4))
        # output channel for next byte received
        pixel_index = Signal(range(self._num_pixels))
        # shift registers to buffer 3 incoming values
        shift_registers = Array(
            [Signal(24, name=f"sr_{i}") for i in range(self._num_pixels)])

        last_pixel_index = Signal.like(pixel_index)
        m.d.sync += last_pixel_index.eq(Mux(self.half_mode,
                                            self._num_pixels // 2 - 1,
                                            self._num_pixels - 1))
        next_pixel_index = Signal.like(pixel_index)
        m.d.comb += next_pixel_index.eq(Mux(pixel_index == last_pixel_index,
                                            0, pixel_index + 1))

        m.d.comb += self.input.ready.eq(1)
        with m.If(self.input.is_transferring()):
            sr = shift_registers[pixel_index]
            with m.If(byte_count == 3):
                # Output current value and shift register
                m.d.comb += self.output.valid.eq(1)
                payload = Cat(sr, self.input.payload)
                m.d.comb += self.output.payload.eq(payload)
            with m.Else():
                # Save input to shift register
                m.d.sync += sr[-8:].eq(self.input.payload)
                m.d.sync += sr[:-8].eq(sr[8:])

            # Increment pixel index
            m.d.sync += pixel_index.eq(next_pixel_index)
            with m.If(pixel_index == last_pixel_index):
                m.d.sync += pixel_index.eq(0)
                m.d.sync += byte_count.eq(byte_count + 1)  # allow rollover
Esempio n. 4
0
    def elab(self, m):

        with m.If(self.reset):
            m.d.sync += self.value.eq(0)

        with m.Else():
            value_p1 = Signal.like(self.count)
            next_value = Signal.like(self.value)
            m.d.comb += [
                value_p1.eq(self.value + 1),
                self.last.eq(value_p1 == self.count),
                next_value.eq(Mux(self.last, 0, value_p1)),
            ]
            with m.If(self.next):
                m.d.sync += self.value.eq(next_value)
Esempio n. 5
0
    def _elab_write(self, m, dps, r_full):
        w_curr_buf = Signal()
        # Address within current buffer
        w_addr = Signal.like(self.input_depth)

        # Connect to memory write port
        for n, dp in enumerate(dps):
            m.d.comb += [
                dp.w_addr.eq(Cat(w_addr[2:], w_curr_buf)),
                dp.w_data.eq(self.w_data),
                dp.w_en.eq(self.w_en & self.w_ready & (n == w_addr[:2])),
            ]
        # Ready to write current buffer if reading is not allowed
        m.d.comb += self.w_ready.eq(~r_full[w_curr_buf])

        # Write address increment
        with m.If(self.w_en & self.w_ready):
            with m.If(w_addr == self.input_depth - 1):
                # at end of buffer - mark buffer ready for reading and go to
                # next
                m.d.sync += [
                    w_addr.eq(0),
                    r_full[w_curr_buf].eq(1),
                    w_curr_buf.eq(~w_curr_buf),
                ]
            with m.Else():
                m.d.sync += w_addr.eq(w_addr + 1)

        with m.If(self.restart):
            m.d.sync += [
                w_addr.eq(0),
                w_curr_buf.eq(0),
            ]
Esempio n. 6
0
    def _elab_read(self, m, dps, r_full):
        r_curr_buf = Signal()
        # Address within current buffer
        r_addr = Signal.like(self.input_depth)

        # Create and connect sequential memory readers
        smrs = [
            SequentialMemoryReader(max_depth=self.max_depth // 2, width=32)
            for _ in range(4)
        ]
        for (n, dp, smr) in zip(range(4), dps, smrs):
            m.submodules[f"smr_{n}"] = smr
            m.d.comb += [
                dp.r_addr.eq(Cat(smr.mem_addr, r_curr_buf)),
                smr.mem_data.eq(dp.r_data),
                smr.limit.eq((self.input_depth + 3 - n) >> 2),
            ]

        smr_nexts = Array(smr.next for smr in smrs)

        # Ready if current buffer is full
        full = Signal()
        m.d.comb += full.eq(r_full[r_curr_buf])
        last_full = Signal()
        m.d.sync += last_full.eq(full)
        with m.If(full & ~last_full):
            m.d.sync += self.r_ready.eq(1)
            m.d.comb += [smr.restart.eq(1) for smr in smrs]

        # Increment address
        with m.If(self.r_next & self.r_ready):
            with m.If(r_addr == self.input_depth - 1):
                m.d.sync += r_addr.eq(0)
            with m.Else():
                m.d.sync += r_addr.eq(r_addr + 1)
            m.d.comb += smr_nexts[r_addr[:2]].eq(1)

        # Get data
        smr_datas = Array(smr.data for smr in smrs)
        m.d.comb += self.r_data.eq(smr_datas[r_addr[:2]])

        # On finished (overrides r_next)
        with m.If(self.r_finished):
            m.d.sync += [
                r_addr.eq(0),
                r_full[r_curr_buf].eq(0),
                last_full.eq(0),
                self.r_ready.eq(0),
                r_curr_buf.eq(~r_curr_buf),
            ]

        # On restart, reset addresses and Sequential Memory readers, go to not
        # ready
        with m.If(self.restart):
            m.d.sync += [
                r_addr.eq(0),
                last_full.eq(0),
                self.r_ready.eq(0),
                r_curr_buf.eq(0),
            ]
Esempio n. 7
0
def synchronize(m, signal, *, output=None, o_domain='sync', stages=2):
    """ Convenience function. Synchronizes a signal, or equivalent collection.

    Parameters:
        input   -- The signal to be synchronized.
        output  -- The signal to output the result of the synchronization
                   to, or None to have one created for you.
        domain  -- The name of the domain to be synchronized to.
        stages  -- The depth (in FFs) of the synchronization chain.
                   Longer incurs more delay. Must be >= 2 to avoid metastability.

    Returns:
        record  -- The post-synchronization signal. Will be equivalent to the
                   `output` record if provided, or a new, created signal otherwise.
    """

    # Quick function to create a synchronizer with our domain and stages.
    def create_synchronizer(signal, output):
        return FFSynchronizer(signal, output, o_domain=o_domain, stages=stages)

    if output is None:
        if isinstance(signal, Signal):
            output = Signal.like(signal)
        else:
            output = Record.like(signal)

    # If the object knows how to synchronize itself, let it.
    if hasattr(signal, '_synchronize_'):
        signal._synchronize_(m, output, o_domain=o_domain, stages=stages)
        return output

    # Trivial case: if this element doesn't have a layout,
    # we can just synchronize it directly.
    if not hasattr(signal, 'layout'):
        m.submodules += create_synchronizer(signal, output)
        return output

    # Otherwise, we'll need to make sure we only synchronize
    # elements with non-output directions.
    for name, layout, direction in signal.layout:

        # If this is a record itself, we'll need to recurse.
        if isinstance(signal[name], (Record, Pin)):
            synchronize(m,
                        signal[name],
                        output=output[name],
                        o_domain=o_domain,
                        stages=stages)
            continue

        # Skip any output elements, as they're already
        # in our clock domain, and we don't want to drive them.
        if (direction == DIR_FANOUT) or (hasattr(signal[name], 'o')
                                         and ~hasattr(signal[name], 'i')):
            m.d.comb += signal[name].eq(output[name])
            continue

        m.submodules += create_synchronizer(signal[name], output[name])

    return output
Esempio n. 8
0
    def elab(self, m):
        group = Signal(range(4))
        repeat_count = Signal.like(self.repeats)
        mem = Array([Signal(14, name=f"mem{i}") for i in range(4)])

        with m.If(repeat_count == 0):
            # On first repeat - pass through next and addr and record addresses
            m.d.comb += self.gen_next.eq(self.next)
            m.d.comb += self.addr.eq(self.gen_addr)
            with m.If(self.next):
                m.d.sync += mem[group].eq(self.gen_addr)
        with m.Else():
            # Subsequently use recorded data
            m.d.comb += self.addr.eq(mem[group])

        # Update group and repeat_count on next
        with m.If(self.next):
            m.d.sync += group.eq(group + 1)
            with m.If(group == 3):
                m.d.sync += repeat_count.eq(repeat_count + 1)
                with m.If(repeat_count + 1 == self.repeats):
                    m.d.sync += repeat_count.eq(0)

        with m.If(self.start):
            m.d.sync += repeat_count.eq(0)
            m.d.sync += group.eq(0)
Esempio n. 9
0
def delay(m, input_, cycles):
    result = [input_]
    for i in range(cycles):
        delayed = Signal.like(input_, name=f"{input_.name}_d{i+1}")
        m.d.sync += delayed.eq(result[-1])
        result.append(delayed)
    return result
Esempio n. 10
0
    def elab(self, m: Module):
        buffering = Signal()  # True if there is a value being buffered
        buffered_value = Signal.like(Value.cast(self.input.payload))

        # Pipe valid and ready back and forth
        m.d.comb += [
            self.input.ready.eq(~buffering | self.output.ready),
            self.output.valid.eq(buffering | self.input.valid),
            self.output.payload.eq(
                Mux(buffering, buffered_value, self.input.payload))
        ]

        # Buffer when have incoming value but cannot output just now
        with m.If(~buffering & ~self.output.ready & self.input.valid):
            m.d.sync += buffering.eq(True)
            m.d.sync += buffered_value.eq(self.input.payload)

        # Handle cases when transfering out from buffer
        with m.If(buffering & self.output.ready):
            with m.If(self.input.valid):
                m.d.sync += buffered_value.eq(self.input.payload)
            with m.Else():
                m.d.sync += buffering.eq(False)

        # Reset all state
        with m.If(self.reset):
            m.d.sync += buffering.eq(False)
            m.d.sync += buffered_value.eq(0)
Esempio n. 11
0
    def elaborate(self, platform):
        m = Module()

        with m.If(self.pending.w_stb):
            m.d.sync += self.pending.r_data.eq(self.pending.r_data
                                               & ~self.pending.w_data)

        with m.If(self.enable.w_stb):
            m.d.sync += self.enable.r_data.eq(self.enable.w_data)

        for i, event in enumerate(self._events):
            m.d.sync += self.status.r_data[i].eq(event.stb)

            if event.mode in ("rise", "fall"):
                event_stb_r = Signal.like(event.stb, name_suffix="_r")
                m.d.sync += event_stb_r.eq(event.stb)

            event_trigger = Signal(name="{}_trigger".format(event.name))
            if event.mode == "level":
                m.d.comb += event_trigger.eq(event.stb)
            elif event.mode == "rise":
                m.d.comb += event_trigger.eq(~event_stb_r & event.stb)
            elif event.mode == "fall":
                m.d.comb += event_trigger.eq(event_stb_r & ~event.stb)
            else:
                assert False  # :nocov:

            with m.If(event_trigger):
                m.d.sync += self.pending.r_data[i].eq(1)

        m.d.comb += self.irq.eq(
            (self.pending.r_data & self.enable.r_data).any())

        return m
Esempio n. 12
0
    def __init__(self, n, a_shape, b_shape, accumulator_shape):
        self._n = n
        self._a_shape = a_shape
        self._b_shape = b_shape
        self._accumulator_shape = accumulator_shape

        self.input_a = Signal(unsigned(n * a_shape.width))
        self.output_a = Signal.like(self.input_a)
        self.input_b = Signal(unsigned(n * b_shape.width))
        self.output_b = Signal.like(self.input_b)

        self.input_first = Signal()
        self.output_first = Signal()
        self.input_last = Signal()
        self.output_last = Signal()

        self.output_accumulator = Signal(accumulator_shape)
        self.output_accumulator_new = Signal()
Esempio n. 13
0
    def add_register(self,
                     address,
                     *,
                     value_signal=None,
                     size=None,
                     name=None,
                     read_strobe=None,
                     write_strobe=None,
                     reset=0):
        """ Adds a standard, memory-backed register.

            Parameters:
                address       -- the register's address, as a big-endian integer
                value_signal  -- the signal that will store the register's value; if omitted
                                 a storage register will be created automatically
                size          -- if value_signal isn't provided, this sets the size of the created register
                reset         -- if value_signal isn't provided, this sets the reset value of the created register
                read_strobe   -- a Signal to be asserted when the register is read; ignored if not provided
                write_strobe  -- a Signal to be asserted when the register is written; ignored if not provided

            Returns:
                value_signal  -- a signal that stores the register's value; which may be the value_signal arg,
                                 or may be a signal created during execution
        """
        self._ensure_register_is_unused(address)

        # Generate a name for the register, if we don't already have one.
        name = name if name else "register_{:x}".format(address)

        # Generate a backing store for the register, if we don't already have one.
        if value_signal is None:
            size = self.register_size if (size is None) else size
            value_signal = Signal(size, name=name, reset=reset)

        # If we don't have a write strobe signal, create an internal one.
        if write_strobe is None:
            write_strobe = Signal(name=name + "_write_strobe")

        # Create our register-value-input and our write strobe.
        write_value = Signal.like(value_signal, name=name + "_write_value")

        # Create a generator for a the fragments that will manage the register's memory.
        def _elaborate_memory_register(m):
            with m.If(write_strobe):
                m.d.sync += value_signal.eq(write_value)

        # Add the register to our collection.
        self.registers[address] = {
            'read': value_signal,
            'write_signal': write_value,
            'write_strobe': write_strobe,
            'read_strobe': read_strobe,
            'elaborate': _elaborate_memory_register,
        }

        return value_signal
Esempio n. 14
0
 def control(self, m):
     release_counter = Signal.like(self.release.payload)
     with m.If(release_counter > 0):
         m.d.comb += self.input.ready.eq(self.output.ready)
         m.d.comb += self.output.valid.eq(self.input.valid)
         with m.If(self.output.is_transferring()):
             m.d.sync += release_counter.eq(release_counter - 1)
     with m.Else():
         m.d.comb += self.release.ready.eq(1)
         with m.If(self.release.is_transferring()):
             m.d.sync += release_counter.eq(self.release.payload)
Esempio n. 15
0
    def elab(self, m):
        count = Signal.like(self.max)
        last_count = self.max - 1
        next_count = Mux(count == last_count, 0, count + 1)

        with m.If(self.en):
            m.d.sync += count.eq(next_count)
            m.d.comb += self.done.eq(count == last_count)

        with m.If(self.restart):
            m.d.sync += count.eq(0)
Esempio n. 16
0
    def build_multipliers(self, m, accumulator):
        # Pipeline cycle 0: calculate products
        products = []
        for i in range(self._n):
            a_bits = self.input_a.word_select(i, self._a_shape.width)
            b_bits = self.input_b.word_select(i, self._b_shape.width)
            a = Signal(self._a_shape, name=f"a_{i}")
            b = Signal(self._b_shape, name=f"b_{i}")
            m.d.comb += [
                a.eq(a_bits),
                b.eq(b_bits),
            ]
            ab = Signal.like(a * b)
            m.d.sync += ab.eq(a * b)
            products.append(ab)

        # Pipeline cycle 1: accumulate
        product_sum = Signal.like(tree_sum(products))
        m.d.comb += product_sum.eq(tree_sum(products))
        first_delayed = delay(m, self.input_first, 1)[-1]
        base = Mux(first_delayed, 0, accumulator)
        m.d.sync += accumulator.eq(base + product_sum)
Esempio n. 17
0
 def elaborate(self, platform):
     m = Module()
     ac = Signal(self.width+1)
     ac_next = Signal.like(ac)
     temp = Signal.like(ac)
     q1 = Signal(self.width)
     q1_next = Signal.like(q1)
     i = Signal(range(self.width))
     # combinatorial
     with m.If(ac >= self.y):
         m.d.comb += [temp.eq(ac-self.y),
                      Cat(q1_next, ac_next).eq(
                      Cat(1, q1, temp[0:self.width-1]))]
     with m.Else():
         m.d.comb += [Cat(q1_next, ac_next).eq(Cat(q1, ac) << 1)]
     # synchronized
     with m.If(self.start):
         m.d.sync += [self.valid.eq(0), i.eq(0)]
         with m.If(self.y == 0):
             m.d.sync += [self.busy.eq(0),
                          self.dbz.eq(1)]
         with m.Else():
             m.d.sync += [self.busy.eq(1),
                          self.dbz.eq(0),
                          Cat(q1, ac).eq(Cat(Const(0, 1),
                                         self.x, Const(0, self.width)))]
     with m.Elif(self.busy):
         with m.If(i == self.width-1):
             m.d.sync += [self.busy.eq(0),
                          self.valid.eq(1),
                          i.eq(0),
                          self.q.eq(q1_next),
                          self.r.eq(ac_next >> 1)]
         with m.Else():
             m.d.sync += [i.eq(i+1),
                          ac.eq(ac_next),
                          q1.eq(q1_next)]
     return m
Esempio n. 18
0
    def elab(self, m):
        # Current r_addr is the address being presented to memory this cycle
        # By default current address is last address, but this can be
        # modied by the reatart or next signals
        last_addr = Signal.like(self.r_addr)
        m.d.sync += last_addr.eq(self.r_addr)
        m.d.comb += self.r_addr.eq(last_addr)

        # Respond to inputs
        with m.If(self.restart):
            m.d.comb += self.r_addr.eq(0)
        with m.Elif(self.next):
            m.d.comb += self.r_addr.eq(
                Mux(last_addr >= self.limit - 1, 0, last_addr + 1))
Esempio n. 19
0
    def __init__(self, *, endpoint_number, max_packet_size):
        self._endpoint_number = endpoint_number
        self._max_packet_size = max_packet_size

        #
        # I/O Port
        #
        self.interface = EndpointInterface()

        self.bytes_in_frame = Signal(range(0, self._MAX_FRAME_DATA + 1))

        self.address = Signal(range(0, self._MAX_FRAME_DATA))
        self.next_address = Signal.like(self.address)
        self.value = Signal(8)
Esempio n. 20
0
    def elab(self, m):
        areg = Signal.like(self.a)
        breg = Signal.like(self.b)
        ab = Signal(signed(64))
        overflow = Signal()

        # for some reason negative nudge is not used
        nudge = 1 << 30

        # cycle 0, register a and b
        m.d.sync += [
            areg.eq(self.a),
            breg.eq(self.b),
        ]
        # cycle 1, decide if this is an overflow and multiply
        m.d.sync += [
            overflow.eq((areg == INT32_MIN) & (breg == INT32_MIN)),
            ab.eq(areg * breg),
        ]
        # cycle 2, apply nudge determine result
        m.d.sync += [
            self.result.eq(Mux(overflow, INT32_MAX, (ab + nudge)[31:])),
        ]
Esempio n. 21
0
 def elab(self, m):
     m.d.sync += self.finished.eq(0)
     m.d.comb += [
         self.stream_in.ready.eq(self.running),
         self.stream_out.valid.eq(self.stream_in.is_transferring()),
         self.stream_out.payload.eq(self.stream_in.payload),
     ]
     counter = Signal.like(self.num_allowed)
     with m.If(self.start):
         m.d.sync += counter.eq(self.num_allowed)
     with m.If(self.stream_in.is_transferring()):
         m.d.sync += counter.eq(counter - 1)
         with m.If(counter == 1):
             m.d.sync += self.finished.eq(1)
     m.d.comb += self.running.eq(counter != 0)
Esempio n. 22
0
def delay(m, signal, cycles):
    """Delays a signal by a number cycles.

    Parameters:
      m: Module
        The module to work in.
      signal: Signal(?)
        The signal to delay
      cycles: int
        The number of cycles to delay
    """
    name = signal.name
    for i in range(cycles):
        delayed = Signal.like(signal, name=f"{name}_delay_{i}")
        m.d.sync += delayed.eq(signal)
        signal = delayed
    return signal
Esempio n. 23
0
def delay(m, signal, interval, *, out=None):
    """ Creates a delayed copy of a given I/O signal.

    Currently only works at the FPGA's I/O boundary, and only on ECP5s.

    Parameters:
        signal -- The signal to be delayed. Must be either an I/O
                  signal connected directly to a platform resource.
        delay  -- Delay, in arbitrary units. These units will vary
                  from unit to unit, but seem to be around 300ps on
                  most ECP5 FPGAs. On ECP5s, maxes out at 127.
        out    -- The signal to received the delayed signal; or
                  None ot have a signal created for you.

    Returns:
        delayed -- The delayed signal. Will be equivalent to 'out'
                   if provided; or a new signal otherwise.
    """

    # If we're not being passed our output signal, create one.
    if out is None:
        out = Signal.like(signal)

    # If we have more than one signal, call this function on each
    # of the subsignals.
    if len(signal) > 1:

        # If we have a vector of signals, but a integer delay,
        # convert that integer to a vector of same-valued delays.
        if isinstance(interval, int):
            interval = [interval] * len(signal)

        return Cat(
            delay(m, s, d, out=o) for s, d, o in zip(signal, interval, out))

    #
    # Base case: create a delayed version of the relevant signal.
    #
    m.submodules += Instance("DELAYG",
                             i_A=signal,
                             o_Z=out,
                             p_DEL_VALUE=interval)

    return out
Esempio n. 24
0
    def __init__(self):

        #
        # I/O port.
        #

        self.tx_data         = Signal(8)
        self.tx_valid        = Signal()
        self.tx_ready        = Signal()

        self.op_mode         = Signal(2)
        self.bus_idle        = Signal()

        self.ulpi_out_req    = Signal()
        self.ulpi_data_out   = Signal.like(self.tx_data)
        self.ulpi_nxt        = Signal()
        self.ulpi_stp        = Signal()

        self.busy            = Signal()
Esempio n. 25
0
    def elaborate(self, platform):
        m = Module()

        beta = self.beta
        temp = Signal(signed(self.totalbits * 2))

        n = len(self.coeff)
        j = Signal(range(1, n))
        k = Signal.like(j)
        with m.FSM(reset='INIT') as algo:
            with m.State('INIT'):
                m.d.sync += self.done.eq(0)
                for i in range(n):
                    m.d.sync += beta[i].eq(self.coeff[i])
                m.d.sync += [k.eq(0), j.eq(1)]
                m.next = 'UPDATE'
            with m.FSM('UPDATE'):
                m.d.sync += temp.eq(beta[k] * (1 - self.t) +
                                    beta[k + 1] * self.t)
                m.next = 'MULTIPLICATIONFIX'
            # Fixed point arithmetic need fix
            # see multiplication as https://vha3.github.io/FixedPoint/FixedPoint.html
            with m.FSM('MULTIPLICATIONFIX'):
                m.d.sync += beta[k].eq(
                    temp[self.fractionalbits:self.fractionalbits +
                         self.totalbits])
                with m.If(k != n - j):
                    m.d.sync += k.eq(k + 1)
                    m.next = 'UPDATE'
                with m.Else():
                    with m.If(j != n):
                        m.d.sync += j.eq(j + 1)
                        m.d.sync += k.eq(0)
                        m.next = 'UPDATE'
                    with m.Else():
                        m.next = 'FINISH'
            with m.FSM('FINISH'):
                m.d.sync += self.done.eq(1)
                m.next = 'FINISH'
        return m
Esempio n. 26
0
    def __init__(self, command_size=8, word_size=32):

        self.command_size = command_size
        self.word_size = word_size

        #
        # I/O port.
        #

        # SPI
        self.spi = SPIBus()

        # Command I/O.
        self.command = Signal(self.command_size)
        self.command_ready = Signal()

        # Data I/O
        self.word_received = Signal(self.word_size)
        self.word_to_send = Signal.like(self.word_received)
        self.word_complete = Signal()

        # Status
        self.idle = Signal()
        self.stalled = Signal()
Esempio n. 27
0
 def elab(self, m):
     captured = Signal.like(self.input)
     with m.If(self.capture):
         m.d.sync += captured.eq(self.input)
     m.d.comb += self.output.eq(Mux(self.capture, self.input, captured))
Esempio n. 28
0
 def __init__(self, inp):
     self.capture = Signal()
     self.input = inp
     self.output = Signal.like(inp)
Esempio n. 29
0
    def elaborate(self, platform):
        m = Module()

        # Grab signals that detect when we should shift in and out.
        sample_edge, output_edge = self.spi_edge_detectors(m)

        # We'll use separate buffers for transmit and receive,
        # as this makes the code a little more readable.
        bit_count = Signal(range(0, self.word_size), reset=0)
        current_tx = Signal.like(self.word_out)
        current_rx = Signal.like(self.word_in)

        # Signal that tracks if this is our first bit of the word.
        is_first_bit = Signal()

        # A word is ready one cycle after we complete a transaction
        # (and latch in the next word to be sent).
        with m.If(self.word_accepted):
            m.d.sync += [self.word_in.eq(current_rx), self.word_complete.eq(1)]
        with m.Else():
            m.d.sync += self.word_complete.eq(0)

        # De-assert our control signals unless explicitly asserted.
        m.d.sync += [
            self.word_accepted.eq(0),
        ]

        # If the chip is selected, process our I/O:
        chip_selected = self.spi.cs if not self.cs_idles_high else ~self.spi.cs

        with m.If(chip_selected):

            # Shift in data on each sample edge.
            with m.If(sample_edge):
                m.d.sync += [bit_count.eq(bit_count + 1), is_first_bit.eq(0)]

                if self.msb_first:
                    m.d.sync += current_rx.eq(
                        Cat(self.spi.sdi, current_rx[:-1]))
                else:
                    m.d.sync += current_rx.eq(Cat(current_rx[1:],
                                                  self.spi.sdi))

                # If we're just completing a word, handle I/O.
                with m.If(bit_count + 1 == self.word_size):
                    m.d.sync += [
                        self.word_accepted.eq(1),
                        current_tx.eq(self.word_out)
                    ]

            # Shift out data on each output edge.
            with m.If(output_edge):
                if self.msb_first:
                    m.d.sync += Cat(current_tx[1:],
                                    self.spi.sdo).eq(current_tx)
                else:
                    m.d.sync += Cat(self.spi.sdo,
                                    current_tx[:-1]).eq(current_tx)

        with m.Else():
            m.d.sync += [
                current_tx.eq(self.word_out),
                bit_count.eq(0),
                is_first_bit.eq(1)
            ]

        return m
Esempio n. 30
0
    def elaborate(self, platform):

        m = Module()
        spi = self.spi

        sample_edge = Fell(spi.sck, domain="sync")

        # Bit counter: counts the number of bits received.
        max_bit_count = max(self.word_size, self.command_size)
        bit_count = Signal(range(0, max_bit_count + 1))

        # Shift registers for our command and data.
        current_command = Signal.like(self.command)
        current_word = Signal.like(self.word_received)

        # De-assert our control signals unless explicitly asserted.
        m.d.sync += [self.command_ready.eq(0), self.word_complete.eq(0)]

        with m.FSM() as fsm:
            m.d.comb += [
                self.idle.eq(fsm.ongoing('IDLE')),
                self.stalled.eq(fsm.ongoing('STALL')),
            ]

            # STALL: entered when we can't accept new bits -- either when
            # CS starts asserted, or when we've received more data than expected.
            with m.State("STALL"):

                # Wait for CS to clear.
                with m.If(~spi.cs):
                    m.next = 'IDLE'

            # We ignore all data until chip select is asserted, as that data Isn't For Us (TM).
            # We'll spin and do nothing until the bus-master addresses us.
            with m.State('IDLE'):
                m.d.sync += bit_count.eq(0)

                with m.If(spi.cs):
                    m.next = 'RECEIVE_COMMAND'

            # Once CS is low, we'll shift in our command.
            with m.State('RECEIVE_COMMAND'):

                # If CS is de-asserted early; our transaction is being aborted.
                with m.If(~spi.cs):
                    m.next = 'IDLE'

                # Continue shifting in data until we have a full command.
                with m.If(bit_count < self.command_size):
                    with m.If(sample_edge):
                        m.d.sync += [
                            bit_count.eq(bit_count + 1),
                            current_command.eq(
                                Cat(spi.sdi, current_command[:-1]))
                        ]

                # ... and then pass that command out to our controller.
                with m.Else():
                    m.d.sync += [
                        bit_count.eq(0),
                        self.command_ready.eq(1),
                        self.command.eq(current_command)
                    ]
                    m.next = 'PROCESSING'

            # Give our controller a wait state to prepare any response they might want to...
            with m.State('PROCESSING'):
                m.next = 'LATCH_OUTPUT'

            # ... and then latch in the response to transmit.
            with m.State('LATCH_OUTPUT'):
                m.d.sync += current_word.eq(self.word_to_send)
                m.next = 'SHIFT_DATA'

            # Finally, exchange data.
            with m.State('SHIFT_DATA'):

                # If CS is de-asserted early; our transaction is being aborted.
                with m.If(~spi.cs):
                    m.next = 'IDLE'

                m.d.sync += spi.sdo.eq(current_word[-1])

                # Continue shifting data until we have a full word.
                with m.If(bit_count < self.word_size):
                    with m.If(sample_edge):
                        m.d.sync += [
                            bit_count.eq(bit_count + 1),
                            current_word.eq(Cat(spi.sdi, current_word[:-1]))
                        ]

                # ... and then output that word on our bus.
                with m.Else():
                    m.d.sync += [
                        bit_count.eq(0),
                        self.word_complete.eq(1),
                        self.word_received.eq(current_word)
                    ]

                    # Stay in the stall state until CS is de-asserted.
                    m.next = 'STALL'

        return m