コード例 #1
0
ファイル: cache.py プロジェクト: AngelTerrones/Bellatrix
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        snoop_addr = Record(self.pc_layout)
        snoop_valid = Signal()

        # -------------------------------------------------------------------------
        # Performance counter
        # TODO: connect to CSR's performance counter
        with m.If(~self.s1_stall & self.s1_valid & self.s1_access):
            m.d.sync += self.access_cnt.eq(self.access_cnt + 1)
        with m.If(self.s2_valid & self.s2_miss & ~self.bus_valid
                  & self.s2_access):
            m.d.sync += self.miss_cnt.eq(self.miss_cnt + 1)
        # -------------------------------------------------------------------------

        way_layout = [('data', 32 * self.nwords),
                      ('tag', self.s1_address.tag.shape()), ('valid', 1),
                      ('sel_lru', 1), ('snoop_hit', 1)]
        if self.enable_write:
            way_layout.append(('sel_we', 1))

        ways = Array(
            Record(way_layout, name='way_idx{}'.format(_way))
            for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)

        # Check hit/miss
        way_hit = m.submodules.way_hit = Encoder(self.nways)
        for idx, way in enumerate(ways):
            m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag)
                                          & way.valid)

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            # Asumiendo que hay un HIT, indicar que la vía que dió hit es en la cual se va a escribir
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

        # set the LRU
        if self.nways == 1:
            # One way: LRU is useless
            lru = Const(0)  # self.nlines
        else:
            # LRU es un vector de N bits, cada uno indicado el set a reemplazar
            # como NWAY es máximo 2, cada LRU es de un bit
            lru = Signal(self.nlines)
            _lru = lru.bit_select(self.s2_address.line, 1)
            write_ended = self.bus_valid & self.bus_ack & self.bus_last  # err ^ ack = = 1
            access_hit = ~self.s2_miss & self.s2_valid & (way_hit.o == _lru)
            with m.If(write_ended | access_hit):
                m.d.sync += _lru.eq(~_lru)

        # read data from the cache
        m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(
            self.s2_address.offset, 32))

        # Internal Snoop
        snoop_use_cache = Signal()
        snoop_tag_match = Signal()
        snoop_line_match = Signal()
        snoop_cancel_refill = Signal()
        if not self.enable_write:
            bits_range = log2_int(self.end_addr - self.start_addr,
                                  need_pow2=False)

            m.d.comb += [
                snoop_addr.eq(self.dcache_snoop.addr),  # aux
                snoop_valid.eq(self.dcache_snoop.we & self.dcache_snoop.valid
                               & self.dcache_snoop.ack),
                snoop_use_cache.eq(snoop_addr[bits_range:] == (
                    self.start_addr >> bits_range)),
                snoop_tag_match.eq(snoop_addr.tag == self.s2_address.tag),
                snoop_line_match.eq(snoop_addr.line == self.s2_address.line),
                snoop_cancel_refill.eq(snoop_use_cache & snoop_valid
                                       & snoop_line_match & snoop_tag_match),
            ]
        else:
            m.d.comb += snoop_cancel_refill.eq(0)

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset +
                                                        1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush
                          | snoop_cancel_refill):
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

        # mark the way to use (replace)
        m.d.comb += ways[lru.bit_select(self.s2_address.line,
                                        1)].sel_lru.eq(self.bus_valid)

        # generate for N ways
        for way in ways:
            # create the memory structures for valid, tag and data.
            valid = Signal(self.nlines)  # Valid bits

            tag_m = Memory(width=len(way.tag), depth=self.nlines)  # tag memory
            tag_rp = tag_m.read_port()
            snoop_rp = tag_m.read_port()
            tag_wp = tag_m.write_port()
            m.submodules += tag_rp, tag_wp, snoop_rp

            data_m = Memory(width=len(way.data),
                            depth=self.nlines)  # data memory
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(
                granularity=32
            )  # implica que solo puedo escribir palabras de 32 bits.
            m.submodules += data_rp, data_wp

            # handle valid
            with m.If(self.s1_flush & self.s1_valid):  # flush
                m.d.sync += valid.eq(0)
            with m.Elif(way.sel_lru & self.bus_last
                        & self.bus_ack):  # refill ok
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1)
            with m.Elif(way.sel_lru & self.bus_err):  # refill error
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0)
            with m.Elif(self.s2_evict & self.s2_valid
                        & (way.tag == self.s2_address.tag)):  # evict
                m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0)

            # assignments
            m.d.comb += [
                tag_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                tag_wp.addr.eq(self.bus_addr.line),
                tag_wp.data.eq(self.bus_addr.tag),
                tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last),
                data_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            # El puerto de escritura se multiplexa debido a que la memoria solo puede tener un
            # puerto de escritura.
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we = Signal(len(data_wp.en))
                aux_wdata = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset,
                                             1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset,
                                             1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    # Aux data: no tengo granularidad de byte en el puerto de escritura. Así que para el
                    # caso en el cual el CPU tiene que escribir, hay que construir el dato (wrord) a reemplazar
                    aux_wdata.eq(
                        Cat(
                            Mux(self.s2_sel[0],
                                self.s2_wdata.word_select(0, 8),
                                self.s2_rdata.word_select(0, 8)),
                            Mux(self.s2_sel[1],
                                self.s2_wdata.word_select(1, 8),
                                self.s2_rdata.word_select(1, 8)),
                            Mux(self.s2_sel[2],
                                self.s2_wdata.word_select(2, 8),
                                self.s2_rdata.word_select(2, 8)),
                            Mux(self.s2_sel[3],
                                self.s2_wdata.word_select(3, 8),
                                self.s2_rdata.word_select(3, 8)))),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset,
                                          1).eq(way.sel_lru & self.bus_ack),
                ]

                # --------------------------------------------------------------
                # intenal snoop
                # for FENCE.i instruction
                _match_snoop = Signal()

                m.d.comb += [
                    snoop_rp.addr.eq(snoop_addr.line),  # read tag memory
                    _match_snoop.eq(snoop_rp.data == snoop_addr.tag),
                    way.snoop_hit.eq(snoop_use_cache & snoop_valid
                                     & _match_snoop
                                     & valid.bit_select(snoop_addr.line, 1)),
                ]
                # check is the snoop match a write from this core
                with m.If(way.snoop_hit):
                    m.d.sync += valid.bit_select(snoop_addr.line, 1).eq(0)
                # --------------------------------------------------------------

        return m
コード例 #2
0
ファイル: status.py プロジェクト: timb-machine-mirrors/luna
    def elaborate(self, platform):
        m = Module()

        # Shortcuts.
        tx = self.interface.tx
        tokenizer = self.interface.tokenizer

        # Grab a copy of the relevant signal that's in our USB domain; synchronizing if we need to.
        if self._signal_domain == "usb":
            target_signal = self.signal
        else:
            target_signal = synchronize(m, self.signal, o_domain="usb")

        # Store a latched version of our signal, captured before we start a transmission.
        latched_signal = Signal.like(self.signal)

        # Grab an byte-indexable reference into our signal.
        bytes_in_signal = (self._width + 7) // 8
        signal_bytes = Array(latched_signal[n * 8:n * 8 + 8]
                             for n in range(bytes_in_signal))

        # Store how many bytes we've transmitted.
        bytes_transmitted = Signal(range(0, bytes_in_signal + 1))

        #
        # Data transmission logic.
        #

        # If this signal is big endian, send them in reading order; otherwise, index our multiplexer in reverse.
        # Note that our signal is captured little endian by default, due the way we use Array() above. If we want
        # big endian; then we'll flip it.
        if self._endianness == "little":
            index_to_transmit = bytes_transmitted
        else:
            index_to_transmit = bytes_in_signal - bytes_transmitted - 1

        # Always transmit the part of the latched signal byte that corresponds to our
        m.d.comb += tx.payload.eq(signal_bytes[index_to_transmit])

        #
        # Core control FSM.
        #

        endpoint_number_matches = (tokenizer.endpoint == self._endpoint_number)
        targeting_endpoint = endpoint_number_matches & tokenizer.is_in
        packet_requested = targeting_endpoint & tokenizer.ready_for_response

        with m.FSM(domain="usb"):

            # IDLE -- we've not yet gotten an token requesting data. Wait for one.
            with m.State('IDLE'):

                # Once we're ready to send a response...
                with m.If(packet_requested):

                    m.d.usb += [
                        # ... clear our transmit counter ...
                        bytes_transmitted.eq(0),

                        # ... latch in our response...
                        latched_signal.eq(self.signal),
                    ]

                    # ...  and start transmitting it.
                    m.next = "TRANSMIT_RESPONSE"

            # TRANSMIT_RESPONSE -- we're now ready to send our latched response to the host.
            with m.State("TRANSMIT_RESPONSE"):
                is_last_byte = bytes_transmitted + 1 == bytes_in_signal

                # While we're transmitting, our Tx data is valid.
                m.d.comb += [
                    tx.valid.eq(1),
                    tx.first.eq(bytes_transmitted == 0),
                    tx.last.eq(is_last_byte)
                ]

                # Each time we receive a byte, move on to the next one.
                with m.If(tx.ready):
                    m.d.usb += bytes_transmitted.eq(bytes_transmitted + 1)

                    # If this is the last byte to be transmitted, move to waiting for an ACK.
                    with m.If(is_last_byte):
                        m.next = "WAIT_FOR_ACK"

            # WAIT_FOR_ACK -- we've now transmitted our full packet; we need to wait for the host to ACK it
            with m.State("WAIT_FOR_ACK"):

                # If the host does ACK, we're done! Move back to our idle state.
                with m.If(self.interface.handshakes_in.ack):
                    m.d.comb += self.status_read_complete.eq(1)
                    m.d.usb += self.interface.tx_pid_toggle[0].eq(
                        ~self.interface.tx_pid_toggle[0])
                    m.next = "IDLE"

                # If the host starts a new packet without ACK'ing, we'll need to retransmit.
                # Wait for a new IN token.
                with m.If(self.interface.tokenizer.new_token):
                    m.next = "RETRANSMIT"

            # RETRANSMIT -- the host failed to ACK the data we've most recently sent.
            # Wait here for the host to request the data again.
            with m.State("RETRANSMIT"):

                # Once the host does request the data again...
                with m.If(packet_requested):

                    # ... retransmit it, starting from the beginning.
                    m.d.usb += bytes_transmitted.eq(0),
                    m.next = "TRANSMIT_RESPONSE"

        return m
コード例 #3
0
ファイル: transfer.py プロジェクト: zyp/luna
    def elaborate(self, platform):
        m = Module()

        #
        # Transciever state.
        #

        # Handle our PID-sequence reset.
        # Note that we store the _inverse_ of our data PID, as we'll toggle our DATA PID
        # before sending.
        with m.If(self.reset_sequence):
            m.d.usb += self.data_pid.eq(~self.start_with_data1)

        #
        # Transmit buffer.
        #
        # Our USB connection imposed a few requirements on our stream:
        # 1) we must be able to transmit packets at a full rate; i.e.
        #    must be asserted from the start to the end of our transfer; and
        # 2) we must be able to re-transmit data if a given packet is not ACK'd.
        #
        # Accordingly, we'll buffer a full USB packet of data, and then transmit
        # it once either a) our buffer is full, or 2) the transfer ends (last=1).
        #
        # This implementation is double buffered; so a buffer fill can be pipelined
        # with a transmit.
        #

        # We'll create two buffers; so we can fill one as we empty the other.
        # Since each buffer will be used for every other transaction, and our PID toggle flips every other transcation,
        # we'll identify which buffer we're targeting by the current PID toggle.
        buffer = Array(
            Memory(width=8,
                   depth=self._max_packet_size,
                   name=f"transmit_buffer_{i}") for i in range(2))
        buffer_write_ports = Array(buffer[i].write_port(domain="usb")
                                   for i in range(2))
        buffer_read_ports = Array(buffer[i].read_port(domain="usb")
                                  for i in range(2))

        m.submodules.read_port_0, m.submodules.read_port_1 = buffer_read_ports
        m.submodules.write_port_0, m.submodules.write_port_1 = buffer_write_ports

        # Create values equivalent to the buffer numbers for our read and write buffer; which switch
        # whenever we swap our two buffers.
        write_buffer_number = self.data_pid[0]
        read_buffer_number = ~self.data_pid[0]

        # Create a shorthand that refers to the buffer to be filled; and the buffer to send from.
        # We'll call these the Read and Write buffers.
        buffer_write = buffer_write_ports[write_buffer_number]
        buffer_read = buffer_read_ports[read_buffer_number]

        # Buffer state tracking:
        # - Our ``fill_count`` keeps track of how much data is stored in a given buffer.
        # - Our ``stream_ended`` bit keeps track of whether the stream ended while filling up
        #   the given buffer. This indicates that the buffer cannot be filled further; and, when
        #   ``generate_zlps`` is enabled, is used to determine if the given buffer should end in
        #   a short packet; which determines whether ZLPs are emitted.
        buffer_fill_count = Array(
            Signal(range(0, self._max_packet_size + 1)) for _ in range(2))
        buffer_stream_ended = Array(
            Signal(name=f"stream_ended_in_buffer{i}") for i in range(2))

        # Create shortcuts to active fill_count / stream_ended signals for the buffer being written.
        write_fill_count = buffer_fill_count[write_buffer_number]
        write_stream_ended = buffer_stream_ended[write_buffer_number]

        # Create shortcuts to the fill_count / stream_ended signals for the packet being sent.
        read_fill_count = buffer_fill_count[read_buffer_number]
        read_stream_ended = buffer_stream_ended[read_buffer_number]

        # Keep track of our current send position; which determines where we are in the packet.
        send_position = Signal(range(0, self._max_packet_size + 1))

        # Shortcut names.
        in_stream = self.transfer_stream
        out_stream = self.packet_stream

        # Use our memory's two ports to capture data from our transfer stream; and two emit packets
        # into our packet stream. Since we'll never receive to anywhere else, or transmit to anywhere else,
        # we can just unconditionally connect these.
        m.d.comb += [

            # We'll only ever -write- data from our input stream...
            buffer_write_ports[0].data.eq(in_stream.payload),
            buffer_write_ports[0].addr.eq(write_fill_count),
            buffer_write_ports[1].data.eq(in_stream.payload),
            buffer_write_ports[1].addr.eq(write_fill_count),

            # ... and we'll only ever -send- data from the Read buffer.
            buffer_read.addr.eq(send_position),
            out_stream.payload.eq(buffer_read.data),

            # We're ready to receive data iff we have space in the buffer we're currently filling.
            in_stream.ready.eq((write_fill_count != self._max_packet_size)
                               & ~write_stream_ended),
            buffer_write.en.eq(in_stream.valid & in_stream.ready)
        ]

        # Increment our fill count whenever we accept new data.
        with m.If(buffer_write.en):
            m.d.usb += write_fill_count.eq(write_fill_count + 1)

        # If the stream ends while we're adding data to the buffer, mark this as an ended stream.
        with m.If(in_stream.last & buffer_write.en):
            m.d.usb += write_stream_ended.eq(1)

        # Shortcut for when we need to deal with an in token.
        # Pulses high an interpacket delay after receiving an IN token.
        in_token_received = self.active & self.tokenizer.is_in & self.tokenizer.ready_for_response

        with m.FSM(domain='usb'):

            # WAIT_FOR_DATA -- We don't yet have a full packet to transmit, so  we'll capture data
            # to fill the our buffer. At full throughput, this state will never be reached after
            # the initial post-reset fill.
            with m.State("WAIT_FOR_DATA"):

                # We can't yet send data; so NAK any packet requests.
                m.d.comb += self.handshakes_out.nak.eq(in_token_received)

                # If we have valid data that will end our packet, we're no longer waiting for data.
                # We'll now wait for the host to request data from us.
                packet_complete = (write_fill_count +
                                   1 == self._max_packet_size)
                will_end_packet = packet_complete | in_stream.last

                with m.If(in_stream.valid & will_end_packet):

                    # If we've just finished a packet, we now have data we can send!
                    with m.If(packet_complete | in_stream.last):
                        m.next = "WAIT_TO_SEND"
                        m.d.usb += [

                            # We're now ready to take the data we've captured and _transmit_ it.
                            # We'll swap our read and write buffers, and toggle our data PID.
                            self.data_pid[0].eq(~self.data_pid[0]),

                            # Mark our current stream as no longer having ended.
                            read_stream_ended.eq(0)
                        ]

            # WAIT_TO_SEND -- we now have at least a buffer full of data to send; we'll
            # need to wait for an IN token to send it.
            with m.State("WAIT_TO_SEND"):
                m.d.usb += send_position.eq(0),

                # Once we get an IN token, move to sending a packet.
                with m.If(in_token_received):

                    # If we have a packet to send, send it.
                    with m.If(read_fill_count):
                        m.next = "SEND_PACKET"
                        m.d.usb += out_stream.first.eq(1)

                    # Otherwise, we entered a transmit path without any data in the buffer.
                    with m.Else():
                        m.d.comb += [
                            # Send a ZLP...
                            out_stream.valid.eq(1),
                            out_stream.last.eq(1),
                        ]
                        # ... and clear the need to follow up with one, since we've just sent a short packet.
                        m.d.usb += read_stream_ended.eq(0)
                        m.next = "WAIT_FOR_ACK"

            with m.State("SEND_PACKET"):
                last_packet = (send_position + 1 == read_fill_count)

                m.d.comb += [
                    # We're always going to be sending valid data, since data is always
                    # available from our memory.
                    out_stream.valid.eq(1),

                    # Let our transmitter know when we've reached our last packet.
                    out_stream.last.eq(last_packet)
                ]

                # Once our transmitter accepts our data...
                with m.If(out_stream.ready):

                    m.d.usb += [
                        # ... move to the next byte in our packet ...
                        send_position.eq(send_position + 1),

                        # ... and mark our packet as no longer the first.
                        out_stream.first.eq(0)
                    ]

                    # Move our memory pointer to its next position.
                    m.d.comb += buffer_read.addr.eq(send_position + 1),

                    # If we've just sent our last packet, we're now ready to wait for a
                    # response from our host.
                    with m.If(last_packet):
                        m.next = 'WAIT_FOR_ACK'

            # WAIT_FOR_ACK -- We've just sent a packet; but don't know if the host has
            # received it correctly. We'll wait to see if the host ACKs.
            with m.State("WAIT_FOR_ACK"):

                # If the host does ACK...
                with m.If(self.handshakes_in.ack):
                    # ... clear the data we've sent from our buffer.
                    m.d.usb += read_fill_count.eq(0)

                    # Figure out if we'll need to follow up with a ZLP. If we have ZLP generation enabled,
                    # we'll make sure we end on a short packet. If this is max-packet-size packet _and_ our
                    # transfer ended with this packet; we'll need to inject a ZLP.
                    follow_up_with_zlp = \
                        self.generate_zlps & (read_fill_count == self._max_packet_size) & read_stream_ended

                    # If we're following up with a ZLP, move back to our "wait to send" state.
                    # Since we've now cleared our fill count; this next go-around will emit a ZLP.
                    with m.If(follow_up_with_zlp):
                        m.next = "WAIT_TO_SEND"

                    # Otherwise, there's a possibility we already have a packet-worth of data waiting
                    # for us in our "write buffer", which we've been filling in the background.
                    # If this is the case, we'll flip which buffer we're working with, toggle our data pid,
                    # and then ready ourselves for transmit.
                    packet_completing = in_stream.valid & (
                        write_fill_count + 1 == self._max_packet_size)
                    with m.Elif(~in_stream.ready | packet_completing):
                        m.next = "WAIT_TO_SEND"
                        m.d.usb += [
                            self.data_pid[0].eq(~self.data_pid[0]),
                            read_stream_ended.eq(0)
                        ]

                    # If neither of the above conditions are true; we now don't have enough data to send.
                    # We'll wait for enough data to transmit.
                    with m.Else():
                        m.next = "WAIT_FOR_DATA"

                # If the host starts a new packet without ACK'ing, we'll need to retransmit.
                # We'll move back to our "wait for token" state without clearing our buffer.
                with m.If(self.tokenizer.new_token):
                    m.next = 'WAIT_TO_SEND'

        return m
コード例 #4
0
ファイル: osc.py プロジェクト: kbob/icebreaker-synth
    def elaborate(self, platform):
        phase = Signal(self.phase_depth)
        note = Signal.like(self.note_in.i_data.note)
        mod = Signal.like(self.mod_in)
        pw = Signal.like(self.pw_in)
        octave = Signal(range(OCTAVES))
        step = Signal(range(STEPS))
        base_inc = Signal(self.inc_depth)
        step_incs = Array(
            [Signal.like(base_inc, reset=inc) for inc in self._base_incs])
        inc = Signal.like(phase)
        pulse_sample = Signal.like(self.pulse_out.o_data)
        saw_sample = Signal.like(self.saw_out.o_data)

        m = Module()
        with m.If(self.sync_in):
            m.d.sync += [
                phase.eq(0),
                # self.rdy_out.eq(False),
            ]

        m.d.comb += [
            self.note_in.o_ready.eq(True),
        ]
        with m.If(self.note_in.received()):
            m.d.sync += [
                note.eq(self.note_in.i_data.note),
                octave.eq(div12(self.note_in.i_data.note)),
            ]
        # Calculate pulse wave edges.  The pulse must rise and fall
        # exactly once per cycle.
        prev_msb = Signal()
        new_cycle = Signal()
        pulse_up = Signal()
        up_latch = Signal()
        pw8 = Cat(pw, Const(0, unsigned(1)))
        m.d.sync += [
            prev_msb.eq(phase[-1]),
        ]
        m.d.comb += [
            new_cycle.eq(~phase[-1] & prev_msb),
            # Widen pulse to one sample period minimum.
            pulse_up.eq(new_cycle | (up_latch & (phase[-8:] <= pw8))),
        ]
        m.d.sync += [
            up_latch.eq((new_cycle | up_latch) & pulse_up),
        ]

        with m.FSM():

            with m.State(FSM.START):
                m.d.sync += [
                    # note.eq(self.note_in),
                    mod.eq(self.mod_in),
                    pw.eq(self.pw_in),
                    # octave.eq(div12(self.note_in)),
                ]
                m.next = FSM.MODULUS

            with m.State(FSM.MODULUS):
                m.d.sync += [
                    step.eq(note - mul12(octave)),
                ]
                m.next = FSM.LOOKUP

            with m.State(FSM.LOOKUP):
                m.d.sync += [
                    base_inc.eq(step_incs[step]),
                ]
                # m.next = FSM.MODULATE
                m.next = FSM.SHIFT

            # with m.State(FSM.MODULATE):
            #     ...
            #     m.next = FSM.SHIFT

            with m.State(FSM.SHIFT):
                m.d.sync += [
                    inc.eq((base_inc << octave)[-self.shift:]),
                ]
                m.next = FSM.ADD

            with m.State(FSM.ADD):
                m.d.sync += [
                    phase.eq(phase + inc),
                ]
                m.next = FSM.SAMPLE

            with m.State(FSM.SAMPLE):
                samp_depth = self.saw_out.o_data.shape()[0]
                samp_max = 2**(samp_depth - 1) - 1
                m.d.sync += [
                    pulse_sample.eq(Mux(pulse_up, samp_max, -samp_max)),
                    saw_sample.eq(samp_max - phase[-samp_depth:]),
                ]
                m.next = FSM.EMIT

            with m.State(FSM.EMIT):
                with m.If(self.saw_out.i_ready & self.pulse_out.i_ready):
                    m.d.sync += [
                        self.pulse_out.o_valid.eq(True),
                        self.pulse_out.o_data.eq(pulse_sample),
                        self.saw_out.o_valid.eq(True),
                        self.saw_out.o_data.eq(saw_sample),
                    ]
                    m.next = FSM.START

        with m.If(self.pulse_out.sent()):
            m.d.sync += [
                self.pulse_out.o_valid.eq(False),
            ]
        with m.If(self.saw_out.sent()):
            m.d.sync += [
                self.saw_out.o_valid.eq(False),
            ]
        return m
コード例 #5
0
    def elaborate(self, platform):
        m = Module()

        max_size_with_crc = self._max_packet_size + 2

        # Submodule: CRC16 generator.
        m.submodules.crc = crc = USBDataPacketCRC()
        last_byte_crc = Signal(16)
        last_word_crc = Signal(16)

        # Currently captured PID.
        active_pid = Signal(4)

        # Active packet transfer.
        active_packet = Array(Signal(8) for _ in range(max_size_with_crc))
        position_in_packet = Signal(range(0, max_size_with_crc))

        # Keeps track of the
        last_word = Signal(16)

        # Keep our control signals + strobes un-asserted unless otherwise specified.
        m.d.ulpi += self.new_packet.eq(0)
        m.d.comb += crc.clear.eq(0)

        with m.FSM(domain="ulpi"):

            # IDLE -- waiting for a packet to be presented
            with m.State("IDLE"):

                with m.If(self.utmi.rx_active):
                    m.next = "READ_PID"

            # READ_PID -- read the packet's ID.
            with m.State("READ_PID"):
                # Clear our CRC; as we're potentially about to start a new packet.
                m.d.comb += crc.clear.eq(1)

                with m.If(~self.utmi.rx_active):
                    m.next = "IDLE"

                with m.Elif(self.utmi.rx_valid):
                    is_data = (self.utmi.rx_data[0:2] == self.DATA_SUFFIX)
                    is_valid_pid = (
                        self.utmi.rx_data[0:4] == ~self.utmi.rx_data[4:8])

                    # If this is a data packet, capture it.
                    with m.If(is_valid_pid & is_data):
                        m.d.ulpi += [
                            active_pid.eq(self.utmi.rx_data),
                            position_in_packet.eq(0)
                        ]
                        m.next = "CAPTURE_DATA"

                    # Otherwise, ignore this packet.
                    with m.Else():
                        m.next = "IRRELEVANT"

            with m.State("CAPTURE_DATA"):

                # Keep a running CRC of any data observed.
                m.d.comb += [
                    crc.valid.eq(self.utmi.rx_valid),
                    crc.data.eq(self.utmi.rx_data)
                ]

                # If we have a new byte of data, capture it.
                with m.If(self.utmi.rx_valid):

                    # If this would over-fill our internal buffer, fail out.
                    with m.If(position_in_packet >= max_size_with_crc):
                        # TODO: potentially signal the babble?
                        m.next = "IRRELEVANT"

                    with m.Else():
                        m.d.ulpi += [
                            active_packet[position_in_packet].eq(
                                self.utmi.rx_data),
                            position_in_packet.eq(position_in_packet + 1),
                            last_word.eq(Cat(self.utmi.rx_data,
                                             last_word[0:8])),
                            last_word_crc.eq(last_byte_crc),
                            last_byte_crc.eq(crc.crc),
                        ]

                # If this is the end of our packet, validate our CRC and finish.
                with m.If(~self.utmi.rx_active):

                    with m.If(last_word_crc == last_word):
                        m.d.ulpi += [
                            self.packet_id.eq(active_pid),
                            self.length.eq(position_in_packet - 2),
                            self.new_packet.eq(1)
                        ]

                        for i in range(self._max_packet_size):
                            m.d.ulpi += self.packet[i].eq(active_packet[i]),

            # IRRELEVANT -- we've encountered a malformed or non-handshake packet
            with m.State("IRRELEVANT"):

                with m.If(~self.utmi.rx_active):
                    m.next = "IDLE"

        return m
コード例 #6
0
    def __init__(self, *, max_line_length=128):

        self.line_in = Array(Signal(8) for _ in range(max_line_length))
        self.line_length = Signal(range(0, max_line_length + 1))
コード例 #7
0
ファイル: decimator.py プロジェクト: kbob/icebreaker-synth
    def elaborate(self, platform):

        m = Module()

        # N is size of RAMs.
        N = self.M + 2
        assert _is_power_of_2(N)

        # kernel_RAM is a buffer of convolution kernel coefficents.
        # It is read-only.  The 0'th element is zero, because the kernel
        # has length N-1.
        kernel_RAM = Memory(width=COEFF_WIDTH, depth=256, init=kernel)
        # kernel_RAM = Memory(width=COEFF_WIDTH, depth=N, init=kernel)
        m.submodules.kr_port = kr_port = kernel_RAM.read_port()

        # sample_RAM is a circular buffer for incoming samples.
        # sample_RAM = Array(
        #     Signal(signed(self.sample_depth), reset_less=True, reset=0)
        #     for _ in range(N)
        # )
        sample_RAM = Memory(width=self.sample_depth, depth=N, init=[0] * N)
        m.submodules.sw_port = sw_port = sample_RAM.write_port()
        m.submodules.sr_port = sr_port = sample_RAM.read_port()

        # The rotors index through sample_RAM.  They have an extra MSB
        # so we can distinguish between buffer full and buffer empty.
        #
        #   w_rotor: write rotor.  Points to the next entry to be written.
        #   s_rotor: start rotor.  Points to the oldest valid entry.
        #   r_rotor: read rotor.  Points to the next entry to be read.
        #
        # The polyphase decimator reads each sample N / R times, so
        # `r_rotor` is **NOT** the oldest needed sample.  Instead,
        # `s_rotor` is the oldest.  `s_rotor` is incremented by `R`
        # at the start of each convolution.
        #
        # We initialize the rotors so that the RAM contains N-1 zero samples,
        # and `r_rotor` is pointing to the first sample to be used.
        # The convolution engine can start immediately and produce a zero
        # result.
        w_rotor = Signal(range(2 * N), reset=N)
        s_rotor = Signal(range(2 * N), reset=1)
        r_rotor = Signal(range(2 * N), reset=1)

        # `c_index` is the next kernel coefficient to read.
        # `c_index` == 0 indicates done, so start at 1.
        c_index = Signal(range(N), reset=1)  # kernel coefficient index

        # Useful conditions
        buf_n_used = Signal(range(N + 1))
        buf_is_empty = Signal()
        buf_is_full = Signal()
        buf_n_readable = Signal(range(N + 1))
        buf_has_readable = Signal()
        m.d.comb += [
            buf_n_used.eq(w_rotor - s_rotor),
            buf_is_empty.eq(buf_n_used == 0),
            buf_is_full.eq(buf_n_used == N),
            buf_n_readable.eq(w_rotor - r_rotor),
            buf_has_readable.eq(buf_n_readable != 0),
            # Assert(buf_n_used <= N),
            # Assert(buf_n_readable <= buf_n_used),
        ]

        # put incoming samples into sample_RAM.
        m.d.comb += [
            self.samples_in.o_ready.eq(~buf_is_full),
            sw_port.addr.eq(w_rotor[:-1]),
            sw_port.data.eq(self.samples_in.i_data),
        ]
        m.d.sync += sw_port.en.eq(self.samples_in.received())
        with m.If(self.samples_in.received()):
            m.d.sync += [
                # sample_RAM[w_rotor[:-1]].eq(self.samples_in.i_data),
                w_rotor.eq(w_rotor + 1),
            ]

        # The convolution is pipelined.
        #
        #   stage 0: fetch coefficient and sample from their RAMs.
        #   stage 1: multiply coefficient and sample.
        #   stage 2: add product to accumulator.
        #   stage 3: if complete, try to send accumulated sample.
        #
        p_valid = Signal(4)
        p_ready = Array(
            Signal(name=f'p_ready{i}', reset=True) for i in range(4))
        p_complete = Signal(4)
        m.d.sync += [
            p_valid[1:].eq(p_valid[:-1]),
            p_ready[0].eq(p_ready[1]),
            p_ready[1].eq(p_ready[2]),
            p_ready[2].eq(p_ready[3]),
        ]

        # calculation variables
        coeff = Signal(COEFF_SHAPE)
        sample = Signal(signed(self.sample_depth))
        prod = Signal(signed(COEFF_WIDTH + self.sample_depth))
        acc = Signal(signed(self.acc_width))

        # Stage 0.
        en0 = Signal()
        m.d.comb += en0.eq(buf_has_readable & p_ready[0] * (c_index != 0))

        # with m.If(en0):
        #     m.d.sync += [
        #         coeff.eq(kernel_RAM[c_index]),
        #     ]
        m.d.comb += coeff.eq(kr_port.data)
        with m.If(en0):
            m.d.sync += [
                sample.eq(sample_RAM[r_rotor[:-1]]),
            ]
        with m.If(en0):
            m.d.sync += [
                c_index.eq(c_index + 1),
                r_rotor.eq(r_rotor + 1),
                p_valid[0].eq(True),
                p_complete[0].eq(False),
                # kr_port.addr.eq(c_index + 1),
            ]
        m.d.comb += kr_port.addr.eq(c_index)
        # with m.If(buf_has_readable & p_ready[0] & (c_index != 0)):
        #     m.d.sync += [
        #         coeff.eq(kernel_RAM[c_index]),
        #         sample.eq(sample_RAM[r_rotor[:-1]]),
        #         c_index.eq(c_index + 1),
        #         r_rotor.eq(r_rotor + 1),
        #         p_valid[0].eq(True),
        #         p_complete[0].eq(False),
        #     ]
        with m.If((~buf_has_readable | ~p_ready[0]) & (c_index != 0)):
            m.d.sync += [
                p_valid[0].eq(False),
                p_complete[0].eq(False),
            ]
        # When c_index is zero, all convolution samples have been read.
        # Set up the rotors for the next sample.  (and pause the
        # pipelined calculation.)
        with m.If(c_index == 0):
            m.d.sync += [
                c_index.eq(c_index + 1),
                s_rotor.eq(s_rotor + self.R),
                r_rotor.eq(s_rotor + self.R),
                p_valid[0].eq(False),
                p_complete[0].eq(True),
            ]

        # Stage 1.
        with m.If(p_valid[1] & p_ready[1]):
            m.d.sync += [
                prod.eq(coeff * sample),
                p_complete[1].eq(p_complete[0]),
            ]

        # Stage 2.
        with m.If(p_valid[2] & p_ready[2]):
            m.d.sync += [
                acc.eq(acc + prod),
                p_complete[2].eq(p_complete[1]),
            ]

        # Stage 3.
        m.d.comb += p_ready[3].eq(~self.samples_out.full())
        m.d.sync += p_complete[3].eq(p_complete[3] | p_complete[2])
        with m.If(p_valid[3] & p_ready[3] & p_complete[2]):
            m.d.sync += [
                self.samples_out.o_valid.eq(1),
                self.samples_out.o_data.eq(acc[self.shift:]),
                acc.eq(0),
                p_complete[3].eq(False),
            ]

        with m.If(self.samples_out.sent()):
            m.d.sync += [
                self.samples_out.o_valid.eq(0),
            ]

        # # s_in_index = Signal(range(2 * N), reset=N)
        # # s_out_index = Signal(range(2 * N), reset=self.R + 1)
        # # c_index = Signal(range(N), reset=1)
        # # start_index = Signal(range(2 *  N), reset=self.R)
        # s_in_index = Signal(range(2 * N), reset=N)
        # s_out_index = Signal(range(2 * N))
        # c_index = Signal(range(N))
        # start_index = Signal(range(2 *  N))
        #
        # coeff = Signal(signed(16))
        # sample = Signal(signed(self.sample_depth))
        # prod = Signal(signed(2 * self.sample_depth))
        # acc = Signal(signed(self.acc_width))
        #
        # m = Module()
        #
        # n_full = (s_in_index - start_index - 1)[:s_in_index.shape()[0]]
        # n_avail = (s_in_index - s_out_index)[:-1]
        # print(f's_in_index shape = {s_in_index.shape()}')
        # print(f'start_index shape = {start_index.shape()}')
        # print(f'n_full shape = {n_full.shape()}')
        # print(f'n_avail shape = {n_avail.shape()}')
        # full = Signal(n_full.shape())
        # avail = Signal(n_avail.shape())
        # m.d.comb += full.eq(n_full)
        # m.d.comb += avail.eq(n_avail)
        #
        #
        # # input process stores new samples in the ring buffer.
        # # with m.If(self.samples_in.received()):
        # #     m.d.sync += [
        # #         sample_RAM[s_in_index[:-1]].eq(self.samples_in.i_data),
        # #     ]
        # with m.If(self.samples_in.received()):
        #     m.d.sync += [
        #         sample_RAM[s_in_index[:-1]].eq(self.samples_in.i_data),
        #         s_in_index.eq(s_in_index + 1),
        #     ]
        # m.d.sync += [
        #     self.samples_in.o_ready.eq(n_full < N),
        # ]
        #
        # # convolution process
        # sample_ready = Signal()
        # sample_ready = n_avail > 0
        #
        # # with m.If(c_index == 1):
        # #     with m.If(sample_ready):
        # #         m.d.sync += [
        # #             start_index.eq(start_index + self.R),
        # #             s_out_index.eq(start_index + self.R + 1),
        # #         ]
        # #     with m.Else():
        # #         with m.If(sample_ready):
        # #             m.d.sync += [
        # #                 s_out_index.eq(s_out_index + 1),
        # #          ]
        # # with m.Else():
        # #     with m.If(sample_ready):
        # #         m.d.sync += [
        # #             s_out_index.eq(s_out_index + 1),
        # #         ]
        #
        # with m.If(sample_ready):
        #     with m.If(c_index == 1):
        #         m.d.sync += [
        #             start_index.eq(start_index + self.R),
        #             s_out_index.eq(start_index + self.R + 1),
        #         ]
        #     with m.Else():
        #         m.d.sync += [
        #             s_out_index.eq(s_out_index + 1),
        #         ]
        #
        # with m.If(c_index == 2):
        #     with m.If(~self.samples_out.full()):
        #         m.d.sync += [
        #             self.samples_out.o_valid.eq(True),
        #             self.samples_out.o_data.eq(acc[self.shift:]),
        #             acc.eq(0),
        #             c_index.eq(c_index + 1),
        #         ]
        # with m.Else():
        #     with m.If(sample_ready):
        #         m.d.sync += [
        #             acc.eq(acc + prod),
        #             c_index.eq(c_index + 1),
        #         ]
        #
        # with m.If(sample_ready):
        #     m.d.sync += [
        #         prod.eq(coeff * sample),
        #     ]
        #
        # with m.If(sample_ready):
        #     m.d.sync += [
        #         coeff.eq(kernel_RAM[c_index]),
        #     ]
        #
        # with m.If(sample_ready):
        #     m.d.sync += [
        #         sample.eq(sample_RAM[s_out_index]),
        #     ]
        #
        # with m.If(self.samples_out.sent()):
        #     m.d.sync += [
        #         self.samples_out.o_valid.eq(False),
        #     ]
        # # # convolution process
        # # if c_index == 0:
        # #     if sample_ready:
        # #         start_index += R
        # #         s_out_index = start_index + R + 1
        # # else:
        # #     if sample_ready:
        # #         s_out_index += 1
        # #
        # # if c_index == 1:
        # #     if not out_full:
        # #         out_sample = acc[shift:]
        # #         out_valid = True
        # #         acc = 0
        # #         c_index += 1
        # # else
        # #     if sample_ready:
        # #         acc += prod
        # #         c_index += 1
        # #
        # # if sample_ready:
        # #     prod = coeff * sample
        # #
        # # if sample_ready:
        # #    coeff = kernel_RAM[c_index]
        # #
        # # if sample_ready:
        # #    sample = sample_RAM[s_out_index]
        #
        # # # convolution process
        # # fill = Signal(range(N + 1))
        # # m.d.comb += fill.eq(s_in_index - s_out_index)
        # # with m.FSM():
        # #
        # #     with m.State('RUN'):
        # #         # when s_out_index MSB is zero, sample is ready.
        # #         # when MSB is one, test out_idx < in_idx.
        # #         # extended_in_index = Cat(s_in_index, 1)
        # #         sample_ready = (fill > 0) & (fill <= N)
        # #         # sample_ready = s_out_index < extended_in_index
        # #         # xii = Signal.like(s_out_index)
        # #         sr = Signal()
        # #         # m.d.comb += xii.eq(extended_in_index)
        # #         m.d.comb += sr.eq(sample_ready)
        # #         with m.If(sample_ready):
        # #             m.d.sync += [
        # #                 acc.eq(acc + prod),   # sign extension is automatic
        # #                 prod.eq(coeff * sample),
        # #                 coeff.eq(kernel_RAM[c_index]),
        # #                 sample.eq(sample_RAM[s_out_index[:-1]]),
        # #                 c_index.eq(c_index + 1),
        # #                 s_out_index.eq(s_out_index + 1),
        # #             ]
        # #             with m.If(c_index == 0):
        # #                 m.next = 'DONE'
        # #         with m.If(self.samples_out.sent()):
        # #             m.d.sync += [
        # #                 self.samples_out.o_valid.eq(False),
        # #             ]
        # #
        # #     with m.State('DONE'):
        # #         with m.If(~self.samples_out.full()):
        # #             m.d.sync += [
        # #                 self.samples_out.o_valid.eq(True),
        # #                 self.samples_out.o_data.eq(acc[self.shift:]),
        # #                 c_index.eq(1),
        # #                 start_index.eq(start_index + self.R),
        # #                 # s_out_index[:-1].eq(start_index + self.R + 1),
        # #                 # s_out_index[-1].eq(0),
        # #                 s_out_index.eq(start_index + self.R + 1),
        # #                 coeff.eq(0),
        # #                 sample.eq(0),
        # #                 prod.eq(0),
        # #                 acc.eq(0),
        # #             ]
        # #             m.next = 'RUN'
        #
        #
        # # i_ready = true
        # # if received:
        # #     sample_RAM[in_index] = samples_in.i_data
        # #     in_index += 1
        # #
        # # FSM:
        # #     start:
        # #         if start_index + cv_index < in_index:  <<<<< Wrong
        # #             acc += sign_extend(prod)
        # #             prod = coeff * sample
        # #             coeff = kernel_RAM[cv_index]
        # #             sample = sample_RAM[(start_index + cv_index)[:-1]]
        # #
        # #             if cv_index + 1 == 0:
        # #                 goto done
        # #
        # #     done:
        # #         o_valid = true
        # #         o_data = acc[shift:shift + 16]
        # #         acc = 0
        # #         start_index = (start_index + R) % Mp2
        # #         cv_index = 0
        # #         prod = 0
        # #         coeff = 0
        # #         sample = 0
        # #
        # # if sent:
        # #     o_valid = false

        return m
コード例 #8
0
    def elaborate(self, platform):
        #Instantiate the Module
        m = Module()

        #Instantiate a decoder/validator for each bit-flip combination of the input codeword
        for i in range(0, self.codeword_width + 1):
            m.submodules["decoder" + str(i)] = LDPC_Decoder_Validator(
                self.ParityCheckMatrixPythonArray, self.codeword_width)

        #codeword_list - An array containing the input codeword and copies of the input codeword, each with a different bit flipped
        codeword_list = Array([
            Signal(unsigned(self.codeword_width), reset=0)
            for _ in range(self.codeword_width + 1)
        ])

        #decoder_output_list - An array containing the parity check status of each parity check row for an input codeword
        decoder_output_list = Array([
            Signal(unsigned(self.ParityCheckMatrixRows), reset=0)
            for _ in range(self.codeword_width + 1)
        ])

        #decoders_done - A signal which lets the top level know when the submodules have finished decoding/validating
        decoders_done = Signal(1)
        m.d.comb += decoders_done.eq(
            m.submodules["decoder" + str(self.codeword_width)].done)

        #counter - A timeout counter for catching when the decoder never finishes decoding
        counter = Signal(self.codeword_width)

        #pipeline_stage - A signal for keeping track of the pipeline stage
        pipeline_stage = Signal(3, reset=0)

        #pipeline_stage - A signal for starting the submodules
        start_submodules = Signal(1, reset=0)

        for i in range(0, self.codeword_width + 1):
            m.d.comb += m.submodules["decoder" +
                                     str(i)].start.eq(start_submodules)
            m.d.sync += m.submodules["decoder" + str(i)].data_input.eq(
                codeword_list[i])
            m.d.comb += decoder_output_list[i].eq(
                m.submodules["decoder" + str(i)].data_output)

        #Reset the relevant registers/wires and load the input codeword into a decoder input register
        with m.If(self.start):
            m.d.sync += [
                codeword_list[self.codeword_width].eq(self.data_input),
                self.data_output.eq(0),
                self.done.eq(0),
                self.success.eq(0),
                counter.eq(0),
                pipeline_stage.eq(1)
            ]
        #Load the input codeword into the codeword list
        with m.Elif(pipeline_stage == 1):
            for i in range(0, self.codeword_width):
                m.d.sync += [
                    codeword_list[i].eq(codeword_list[self.codeword_width]),
                    pipeline_stage.eq(pipeline_stage + 1)
                ]
        #Flip the relevant bit on the codewords in the codeword list
        with m.Elif(pipeline_stage == 2):
            for i in range(0, self.codeword_width):
                m.d.sync += [
                    codeword_list[i][i].eq(~codeword_list[i][i]),
                    pipeline_stage.eq(pipeline_stage + 1)
                ]
        #Start validating all the codeword variations (Set Start Bit to 1)
        with m.Elif(pipeline_stage == 3):
            for i in range(0, self.codeword_width):
                m.d.sync += [
                    start_submodules.eq(1),
                    pipeline_stage.eq(pipeline_stage + 1)
                ]
        #Start validating all the codeword variations (Set Start Bit to 0)
        with m.Elif(pipeline_stage == 4):
            for i in range(0, self.codeword_width):
                m.d.sync += [
                    start_submodules.eq(0),
                    pipeline_stage.eq(pipeline_stage + 1)
                ]
        #Start counting the timeout and validating if any of the submodules was successful in validating the codeword.
        #Finally, output success or failure along with output data and STOP.
        with m.Elif(pipeline_stage == 5 & (~self.done) & (~self.start)):
            for i in range(0, self.codeword_width + 1):
                m.d.sync += counter.eq(counter + 1)
            with m.If((decoders_done) & (counter > (self.codeword_width + 2))):
                m.d.sync += [self.done.eq(1), self.success.eq(0)]
            with m.Elif((decoders_done)):
                for i in range(0, self.codeword_width + 1):
                    with m.If(decoder_output_list[i] == 0b000):
                        m.d.sync += [
                            self.data_output.eq(codeword_list[
                                self.codeword_width][self.codeword_width -
                                                     self.data_output_width:]),
                            self.done.eq(1),
                            self.success.eq(1)
                        ]
        return m
コード例 #9
0
    def elaborate(self, platform):
        #Instantiate the Module
        m = Module()

        #[ARRAY[SIGNAL]] - working_matrix - An array of signals which represents the matrix used to calculate the output codeword.
        working_matrix = Array([
            Signal(unsigned(self.codeword_width), reset=0)
            for _ in range(self.data_input_length)
        ])

        #[ARRAY[SIGNAL]] - adder_buffer - An array of signals which is used to accumulate the columns of the working matrix to calculate the codeword
        adder_buffer = Array([
            Signal(unsigned(self.data_input_length), reset=0)
            for _ in range(self.codeword_width)
        ])

        #[SIGNAL] - cnt - A signal to count the steps completed in the encoding process
        cnt = Signal(self.data_input_length)

        #[SIGNAL] - running - A signal which is used to indicate the pipeline is running.
        running = Signal(1, reset=0)

        #[SIGNAL] - accumulation_completed - A signal which is used to indicate when the accumulation process has completed.
        accumulation_completed = Signal(1)

        #[SIGNAL] - data_input_copy - Internal copy of the data_input
        data_input_copy = Signal(self.data_input_length)

        #The accumulation process completes in fixed time complexity in (n-1) clock cycles, where n is the length of the data input
        m.d.comb += accumulation_completed.eq(cnt == self.data_input_length -
                                              1)

        #If 'start' is asserted, reset the adder_buffer, cnt, done and output variables.
        with m.If(self.start):
            for i in range(0, self.codeword_width):
                m.d.sync += [adder_buffer[i].eq(0)]
            m.d.sync += [
                cnt.eq(0),
                self.done.eq(0),
                self.data_output.eq(0),
                data_input_copy.eq(self.data_input),
                running.eq(1)
            ]

        #If 'accumulation_completed' is not satisfied, increment cnt
        with m.Elif(~accumulation_completed & running):
            m.d.sync += [cnt.eq(cnt + 1)]

            #Complete the first stage of the accumulation - AND the input data with the genmatrix
            #Since this is in the combinatorial domain, there is 'no penalty' as the size of the generator matrix and data input increases
            for i in range(0, self.codeword_width):
                for n in range(0, self.data_input_length):
                    m.d.comb += [
                        working_matrix[n][i].
                        eq(self.gen_matrix[n][i]
                           & data_input_copy[(self.data_input_length - n) - 1])
                    ]

        #Accumulate the columns of the matrix, with the Gallagher Modulo 2 rules
        #https://ieeexplore.ieee.org/document/1057683
            for i in range(0, self.codeword_width):
                for n in range(1, self.data_input_length):
                    if (n == 1):
                        m.d.sync += [
                            adder_buffer[i][n].eq(working_matrix[n][i]
                                                  ^ working_matrix[n - 1][i])
                        ]
                    else:
                        m.d.sync += [
                            adder_buffer[i][n].eq(adder_buffer[i][n - 1]
                                                  ^ working_matrix[n][i])
                        ]

        #Present the result on the output register and set the 'done' flag.
        with m.Elif(accumulation_completed & running):
            for i in range(0, self.codeword_width):
                m.d.sync += [
                    self.data_output[i].eq(
                        adder_buffer[i][self.data_input_length - 1]),
                    self.done.eq(1),
                    running.eq(0)
                ]

        return m
コード例 #10
0
    def elaborate(self, platform):
        #Instantiate the Module
        m = Module()

        #[ARRAY[SIGNAL]] - stage_1_working_matrix - An array of signals which represents the parity matrix used to validate the input codeword
        stage_1_working_matrix = Array([
            Signal(unsigned(self.codeword_width), reset=0)
            for _ in range(self.data_output_matrix_rows)
        ])

        #[ARRAY[SIGNAL]] - stage_2_adder_buffer - An array of signals which are used to calculate whether there are an even number of 1s in each parity check row
        stage_2_adder_buffer = Array([
            Signal(unsigned(self.codeword_width),
                   reset=0,
                   name="stage_2_adder_buffer")
            for _ in range(self.data_output_matrix_rows)
        ])

        #[SIGNAL] - stage_2_counter - Counts the worst case scenario for the even 1s calculation
        stage_2_counter = Signal(self.codeword_width)

        #[SIGNAL] - pipeline_stage - Signal to indicate whether we are in pipeline stage 0 or 1
        pipeline_stage = Signal(1)
        #[SIGNAL] - running - Signal to indicate that we are currently running
        running = Signal(1, reset=0)

        #if start bit is asserted, reset the system
        with m.If(self.start):
            for i in range(0, self.data_output_matrix_rows):
                m.d.sync += [
                    running.eq(1),
                    stage_1_working_matrix[i].eq(0),
                    stage_2_adder_buffer[i].eq(0),
                    stage_2_counter.eq(0),
                    self.done.eq(0),
                    self.data_output.eq(0b000),
                    pipeline_stage.eq(0),
                ]
        #First Pipeline Stage (0)
        #Data_input ANDed with each row of the parity check matrix
        with m.If(running & (pipeline_stage == 0)):
            for i in range(0, self.data_output_matrix_rows):
                m.d.sync += [
                    stage_1_working_matrix[i].eq(self.data_input
                                                 & self.parity_check_matrix[i])
                ]
            m.d.sync += [pipeline_stage.eq(1)]

        #Second Pipeline Stage (1)
        #Accumulate the ANDed data to calculate if there are an even number of 1s.
        with m.If(running & (pipeline_stage == 1)):
            m.d.sync += [stage_2_counter.eq(stage_2_counter + 1)]
            for i in range(0, self.data_output_matrix_rows):
                for n in range(1, self.codeword_width):
                    if (n == 1):
                        m.d.sync += [
                            stage_2_adder_buffer[i]
                            [n].eq(stage_1_working_matrix[i][n]
                                   ^ stage_1_working_matrix[i][n - 1])
                        ]
                    else:
                        m.d.sync += [
                            stage_2_adder_buffer[i]
                            [n].eq(stage_2_adder_buffer[i][n - 1]
                                   ^ stage_1_working_matrix[i][n])
                        ]
        #Output the result of each parity check row comparison (1=Fail, 0=Pass)
            with m.If(stage_2_counter == (self.codeword_width)):
                for i in range(0, self.data_output_matrix_rows):
                    m.d.sync += [
                        self.data_output[(self.data_output_matrix_rows - 1) -
                                         i].eq(stage_2_adder_buffer[i][
                                             self.codeword_width - 1]),
                        running.eq(0),
                        self.done.eq(1)
                    ]

        return m
コード例 #11
0
    0x64,
    OLED_INIT.SET_PRECHARGE_B,
    0x78,
    OLED_INIT.SET_PRECHARGE_C,
    0x64,
    OLED_INIT.SET_PRECHARGE_LEVEL,
    0x31,
    OLED_INIT.SET_CONTRAST_COLOR_A,
    0xFF,
    OLED_INIT.SET_CONTRAST_COLOR_B,
    0xFF,
    OLED_INIT.SET_CONTRAST_COLOR_C,
    0xFF,
    OLED_INIT.SET_VCOMH,
    0x3E,
    OLED_INIT.SET_MASTER_CURRENT_CONTROL,
    0x06,
    OLED_INIT.SET_COLUMN_ADDRESS,
    0x00,
    0x5F,
    OLED_INIT.SET_ROW_ADDRESS,
    0x00,
    0x3F,
    OLED_INIT.SET_DISPLAY_ON,
    OLED_INIT.NOP1,
]

oled_init_seq = Array(Value for _ in range(len(oled_init_seq_list)))
for i in range(len(oled_init_seq_list)):
    oled_init_seq[i] = oled_init_seq_list[i]
コード例 #12
0
    def elab(self, m):
        # break out the functionid
        funct3 = Signal(3)
        funct7 = Signal(7)
        m.d.comb += [
            funct3.eq(self.cmd_function_id[:3]),
            funct7.eq(self.cmd_function_id[-7:]),
        ]
        stored_function_id = Signal(3)
        current_function_id = Signal(3)
        current_function_done = Signal()
        stored_output = Signal(32)

        # Response is always OK.
        m.d.comb += self.rsp_ok.eq(1)

        instruction_outputs = Array(Signal(32) for _ in range(8))
        instruction_dones = Array(Signal() for _ in range(8))
        instruction_starts = Array(Signal() for _ in range(8))
        for (i, instruction) in self.instructions.items():
            m.d.comb += instruction_outputs[i].eq(instruction.output)
            m.d.comb += instruction_dones[i].eq(instruction.done)
            m.d.comb += instruction.start.eq(instruction_starts[i])

        def check_instruction_done():
            with m.If(current_function_done):
                m.d.comb += self.rsp_valid.eq(1)
                m.d.comb += self.rsp_out.eq(
                    instruction_outputs[current_function_id])
                with m.If(self.rsp_ready):
                    m.next = "WAIT_CMD"
                with m.Else():
                    m.d.sync += stored_output.eq(
                        instruction_outputs[current_function_id])
                    m.next = "WAIT_TRANSFER"
            with m.Else():
                m.next = "WAIT_INSTRUCTION"

        with m.FSM():
            with m.State("WAIT_CMD"):
                # We're waiting for a command from the CPU.
                m.d.comb += current_function_id.eq(funct3)
                m.d.comb += current_function_done.eq(
                    instruction_dones[current_function_id])
                m.d.comb += self.cmd_ready.eq(1)
                with m.If(self.cmd_valid):
                    m.d.sync += stored_function_id.eq(self.cmd_function_id[:3])
                    m.d.comb += instruction_starts[current_function_id].eq(1)
                    check_instruction_done()
            with m.State("WAIT_INSTRUCTION"):
                # An instruction is executing on the CFU. We're waiting until it
                # completes.
                m.d.comb += current_function_id.eq(stored_function_id)
                m.d.comb += current_function_done.eq(
                    instruction_dones[current_function_id])
                check_instruction_done()
            with m.State("WAIT_TRANSFER"):
                # Instruction has completed, but the CPU isn't ready to receive
                # the result.
                m.d.comb += self.rsp_valid.eq(1)
                m.d.comb += self.rsp_out.eq(stored_output)
                with m.If(self.rsp_ready):
                    m.next = "WAIT_CMD"

        for (i, instruction) in self.instructions.items():
            m.d.comb += [
                instruction.in0.eq(self.cmd_in0),
                instruction.in1.eq(self.cmd_in1),
                instruction.funct7.eq(funct7),
            ]
            m.submodules[f"fn{i}"] = instruction
コード例 #13
0
    def elaborate(self, platform):
        m = Module()

        way_layout = [
            ('data',     32 * self.nwords),
            ('tag',      self.s1_address.tag.shape()),
            ('valid',    1),
            ('sel_lru',  1)
        ]
        if self.enable_write:
            way_layout.append(('sel_we',   1))

        ways     = Array(Record(way_layout) for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)
        # set the LRU
        if self.nways == 1:
            lru = Const(0)  # self.nlines
        else:
            lru = Signal(self.nlines)
            with m.If(self.bus_valid & self.bus_ack & self.bus_last):  # err ^ ack == 1
                _lru = lru.bit_select(self.s2_address.line, 1)
                m.d.sync += lru.bit_select(self.s2_address.line, 1).eq(~_lru)

        # hit/miss
        way_hit = m.submodules.way_hit = Encoder(self.nways)
        for idx, way in enumerate(ways):
            m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag) & way.valid)

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

        # read data
        m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(self.s2_address.offset, 32))

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),  # WARNING extra_bits
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset + 1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush):
                    # in case of flush, abort ongoing refill.
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

        # mark the way to use (replace)
        m.d.comb += ways[lru.bit_select(self.s2_address.line, 1)].sel_lru.eq(self.bus_valid)

        # generate for N ways
        for way in ways:
            # create the memory structures for valid, tag and data.
            valid = Signal(self.nlines)

            tag_m  = Memory(width=len(way.tag), depth=self.nlines)
            tag_rp = tag_m.read_port()
            tag_wp = tag_m.write_port()
            m.submodules += tag_rp, tag_wp

            data_m  = Memory(width=len(way.data), depth=self.nlines)
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(granularity=32)
            m.submodules += data_rp, data_wp

            # handle valid
            with m.If(self.s1_flush & self.s1_valid):  # flush
                m.d.sync += valid.eq(0)
            with m.Elif(way.sel_lru & self.bus_last & self.bus_ack):  # refill ok
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1)
            with m.Elif(way.sel_lru & self.bus_err):  # refill error
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0)
            with m.Elif(self.s2_evict & self.s2_valid & (way.tag == self.s2_address.tag)):  # evict
                m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0)

            # assignments
            m.d.comb += [
                tag_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)),
                tag_wp.addr.eq(self.bus_addr.line),
                tag_wp.data.eq(self.bus_addr.tag),
                tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last),

                data_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)),

                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we   = Signal(len(data_wp.en))
                aux_wdata   = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset, 1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    aux_wdata.eq(Cat(
                        Mux(self.s2_sel[0], self.s2_wdata.word_select(0, 8), self.s2_rdata.word_select(0, 8)),
                        Mux(self.s2_sel[1], self.s2_wdata.word_select(1, 8), self.s2_rdata.word_select(1, 8)),
                        Mux(self.s2_sel[2], self.s2_wdata.word_select(2, 8), self.s2_rdata.word_select(2, 8)),
                        Mux(self.s2_sel[3], self.s2_wdata.word_select(3, 8), self.s2_rdata.word_select(3, 8))
                    )),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack),
                ]

        return m
コード例 #14
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.bridge = self._bridge

        # Shortcuts to our components.
        token          = self.interface.tokenizer
        tx             = self.interface.tx
        handshakes_out = self.interface.handshakes_out

        #
        # Core FIFO.
        #


        # Create our FIFO; and set it to be cleared whenever the user requests.
        m.submodules.fifo = fifo = \
             ResetInserter(self.reset.w_stb)(SyncFIFOBuffered(width=8, depth=self.max_packet_size))

        m.d.comb += [
            # Whenever the user DATA register is written to, add the relevant data to our FIFO.
            fifo.w_en         .eq(self.data.w_stb),
            fifo.w_data       .eq(self.data.w_data),
        ]

        # Keep track of the amount of data in our FIFO.
        bytes_in_fifo = Signal(range(0, self.max_packet_size + 1))

        # If we're clearing the whole FIFO, reset our data count.
        with m.If(self.reset.w_stb):
            m.d.usb += bytes_in_fifo.eq(0)

        # Keep track of our FIFO's data count as data is added or removed.
        increment = fifo.w_en & fifo.w_rdy
        decrement = fifo.r_en & fifo.r_rdy

        with m.Elif(increment & ~decrement):
            m.d.usb += bytes_in_fifo.eq(bytes_in_fifo + 1)
        with m.Elif(decrement & ~increment):
            m.d.usb += bytes_in_fifo.eq(bytes_in_fifo - 1)


        #
        # Register updates.
        #

        # Active endpoint number.
        with m.If(self.epno.w_stb):
            m.d.usb += self.epno.r_data.eq(self.epno.w_data)

        # Keep track of which endpoints are stalled.
        endpoint_stalled = Array(Signal() for _ in range(16))

        # Set the value of our endpoint `stall` based on our `stall` register...
        with m.If(self.stall.w_stb):
            m.d.usb += endpoint_stalled[self.epno.r_data].eq(self.stall.w_data)

        # ... but clear our endpoint `stall` when we get a SETUP packet.
        with m.If(token.is_setup & token.new_token):
            m.d.usb += endpoint_stalled[token.endpoint].eq(0)

        # Manual data toggle control.
        # TODO: Remove this in favor of automated tracking?
        m.d.comb += self.interface.tx_pid_toggle.eq(self.pid.r_data)
        with m.If(self.pid.w_stb):
            m.d.usb += self.pid.r_data.eq(self.pid.w_data)


        #
        # Status registers.
        #
        m.d.comb += [
            self.have.r_data  .eq(fifo.r_rdy)
        ]

        #
        # Control logic.
        #

        # Logic shorthand.
        new_in_token     = (token.is_in & token.ready_for_response)
        endpoint_matches = (token.endpoint == self.epno.r_data)
        stalled          = endpoint_stalled[token.endpoint]

        with m.FSM(domain='usb') as f:

            # Drive our IDLE line based on our FSM state.
            m.d.comb += self.idle.r_data.eq(f.ongoing('IDLE'))

            # IDLE -- our CPU hasn't yet requested that we send data.
            # We'll wait for it to do so, and NAK any packets that arrive.
            with m.State("IDLE"):

                # If we get an IN token...
                with m.If(new_in_token):

                    # STALL it, if the endpoint is STALL'd...
                    with m.If(stalled):
                        m.d.comb += handshakes_out.stall.eq(1)

                    # Otherwise, NAK.
                    with m.Else():
                        m.d.comb += handshakes_out.nak.eq(1)


                # If the user request that we send data, "prime" the endpoint.
                # This means we have data to send, but are just waiting for an IN token.
                with m.If(self.epno.w_stb & ~stalled):
                    m.next = "PRIMED"

            # PRIMED -- our CPU has provided data, but we haven't been sent an IN token, yet.
            # Await that IN token.
            with m.State("PRIMED"):

                with m.If(new_in_token):

                    # If the target endpoint is STALL'd, reply with STALL no matter what.
                    with m.If(stalled):
                        m.d.comb += handshakes_out.stall.eq(1)

                    # If we have a new IN token to our endpoint, move to responding to it.
                    with m.Elif(endpoint_matches):

                        # If there's no data in our endpoint, send a ZLP.
                        with m.If(~fifo.r_rdy):
                            m.next = "SEND_ZLP"

                        # Otherwise, send our data, starting with our first byte.
                        with m.Else():
                            m.d.usb += tx.first.eq(1)
                            m.next = "SEND_DATA"

                    # Otherwise, we don't have a response; NAK the packet.
                    with m.Else():
                        m.d.comb += handshakes_out.nak.eq(1)

            # SEND_ZLP -- we're now now ready to respond to an IN token with a ZLP.
            # Send our response.
            with m.State("SEND_ZLP"):
                m.d.comb += [
                    tx.valid  .eq(1),
                    tx.last   .eq(1)
                ]
                m.next = 'IDLE'

            # SEND_DATA -- we're now ready to respond to an IN token to our endpoint.
            # Send our response.
            with m.State("SEND_DATA"):
                last_packet = (bytes_in_fifo == 1)

                m.d.comb += [
                    tx.valid    .eq(1),
                    tx.last     .eq(last_packet),

                    # Drive our transmit data directly from our FIFO...
                    tx.payload  .eq(fifo.r_data),

                    # ... and advance our FIFO each time a data byte is transmitted.
                    fifo.r_en   .eq(tx.ready)
                ]

                # After we've sent a byte, drop our first flag.
                with m.If(tx.ready):
                    m.d.usb += tx.first.eq(0)

                # Once we transmit our last packet, we're done transmitting. Move back to IDLE.
                with m.If(last_packet & tx.ready):
                    m.next = 'IDLE'

        return DomainRenamer({"sync": "usb"})(m)
コード例 #15
0
    def elaborate(self, platform):

        m = Module()

        # Create divided clock for MDC
        mdc_int = Signal()
        mdc_rise = Signal()
        mdc_fall = Signal()
        mdc_divider = Signal(range(self.clk_div))
        with m.If(mdc_divider == 0):
            m.d.sync += [
                mdc_divider.eq(self.clk_div - 1),
                mdc_int.eq(0),
                mdc_fall.eq(1),
                mdc_rise.eq(0),
            ]

        with m.Elif(mdc_divider == self.clk_div // 2):
            m.d.sync += [
                mdc_divider.eq(mdc_divider - 1),
                mdc_int.eq(1),
                mdc_fall.eq(0),
                mdc_rise.eq(1),
            ]

        with m.Else():
            m.d.sync += [
                mdc_divider.eq(mdc_divider - 1),
                mdc_fall.eq(0),
                mdc_rise.eq(0),
            ]

        # Latches for inputs
        _phy_addr = Signal.like(self.phy_addr)
        _reg_addr = Signal.like(self.reg_addr)
        _rw = Signal.like(self.rw)
        _write_data = Signal.like(self.write_data)

        # MDIO FSM
        bit_counter = Signal(6)
        with m.FSM() as fsm:
            m.d.comb += self.busy.eq(~fsm.ongoing("IDLE"))

            # Idle state
            # Constantly register input data and wait for START signal
            with m.State("IDLE"):
                m.d.comb += [
                    self.mdc.eq(0),
                    self.mdio.oe.eq(0),
                ]

                # Latch input signals while in idle
                m.d.sync += [
                    _phy_addr.eq(self.phy_addr),
                    _reg_addr.eq(self.reg_addr),
                    _rw.eq(self.rw),
                    _write_data.eq(self.write_data),
                ]

                with m.If(self.start):
                    m.next = "SYNC"

            # Synchronise to MDC. Enter this state at any time.
            # Will transition to PRE_32 immediately after the next
            # falling edge on MDC.
            with m.State("SYNC"):
                m.d.comb += [
                    self.mdc.eq(0),
                    self.mdio.oe.eq(0),
                ]

                with m.If(mdc_fall):
                    m.d.sync += bit_counter.eq(32)
                    m.next = "PRE_32"

            # PRE_32
            # Preamble field: 32 bits of 1
            with m.State("PRE_32"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),

                    # Output all 1s
                    self.mdio.o.eq(1),
                ]

                # Count falling edges of MDC,
                # transition to ST after 32 MDC clocks
                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        m.d.sync += bit_counter.eq(2)
                        m.next = "ST"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # ST
            # Start field: always 01
            with m.State("ST"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),
                    self.mdio.o.eq(bit_counter[0]),
                ]

                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        m.d.sync += bit_counter.eq(2)
                        m.next = "OP"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # OP
            # Opcode field: read=10, write=01
            with m.State("OP"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),
                ]
                with m.If(_rw):
                    m.d.comb += self.mdio.o.eq(bit_counter[0])
                with m.Else():
                    m.d.comb += self.mdio.o.eq(~bit_counter[0])

                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        m.d.sync += bit_counter.eq(5)
                        m.next = "PA5"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # PA5
            # PHY address field, 5 bits
            with m.State("PA5"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),
                    self.mdio.o.eq(Array(_phy_addr)[bit_counter - 1]),
                ]

                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        m.d.sync += bit_counter.eq(5)
                        m.next = "RA5"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # RA5
            # Register address field, 5 bits
            with m.State("RA5"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),
                    self.mdio.o.eq(Array(_reg_addr)[bit_counter - 1]),
                ]

                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        with m.If(_rw):
                            m.d.sync += bit_counter.eq(2)
                            m.next = "TA_W"
                        with m.Else():
                            m.d.sync += bit_counter.eq(1)
                            m.next = "TA_R"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # TA
            # Turnaround, 1 bits, OE released for read operations
            with m.State("TA_R"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(0),
                ]

                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        m.d.sync += bit_counter.eq(16)
                        m.next = "D16_R"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # TA
            # Turnaround, 2 bits, driven to 10 for write operations
            with m.State("TA_W"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),
                    self.mdio.o.eq(~bit_counter[0]),
                ]

                with m.If(mdc_fall):
                    with m.If(bit_counter == 1):
                        m.d.sync += bit_counter.eq(16)
                        m.next = "D16_W"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # D16
            # Data field, read operation
            with m.State("D16_R"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(0),
                ]

                with m.If(mdc_fall):
                    bit = Array(self.read_data)[bit_counter - 1]
                    m.d.sync += bit.eq(self.mdio.i)
                    with m.If(bit_counter == 1):
                        m.next = "READ_LAST_CLOCK"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

            # Because we sample MDIO on the falling edge, the final clock
            # pulse is not used for data, but should probably be emitted to
            # stop things getting confused.
            with m.State("READ_LAST_CLOCK"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(0),
                ]

                with m.If(mdc_fall):
                    m.next = "IDLE"

            # D16
            # Data field, write operation
            with m.State("D16_W"):
                m.d.comb += [
                    self.mdc.eq(mdc_int),
                    self.mdio.oe.eq(1),
                    self.mdio.o.eq(Array(_write_data)[bit_counter - 1]),
                ]

                with m.If(mdc_fall):
                    with m.If(bit_counter == 0):
                        m.next = "IDLE"
                    with m.Else():
                        m.d.sync += bit_counter.eq(bit_counter - 1)

        return m
コード例 #16
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.bridge = self._bridge

        # Shortcuts to our components.
        interface      = self.interface
        token          = self.interface.tokenizer
        rx             = self.interface.rx
        handshakes_out = self.interface.handshakes_out

        #
        # Control registers
        #

        # Active endpoint number.
        with m.If(self.epno.w_stb):
            m.d.usb += self.epno.r_data.eq(self.epno.w_data)

        # Keep track of which endpoints are stalled.
        endpoint_stalled = Array(Signal() for _ in range(16))

        # Allow the CPU to set our enable bit.
        with m.If(self.enable.w_stb):
            m.d.usb += self.enable.r_data.eq(self.enable.w_data)

        # If we've just ACK'd a receive, clear our enable.
        with m.If(interface.handshakes_out.ack):
            m.d.usb += self.enable.r_data.eq(0)


        # Set the value of our endpoint `stall` based on our `stall` register...
        with m.If(self.stall.w_stb):
            m.d.usb += endpoint_stalled[self.epno.r_data].eq(self.stall.w_data)

        # ... but clear our endpoint `stall` when we get a SETUP packet.
        with m.If(token.is_setup & token.new_token):
            m.d.usb += endpoint_stalled[token.endpoint].eq(0)

        #
        # Core FIFO.
        #
        m.submodules.fifo = fifo = ResetInserter(self.reset.w_stb)(SyncFIFOBuffered(width=8, depth=10))

        # Shortcut for when we should allow a receive. We'll read when:
        #  - Our `epno` register matches the target register; and
        #  - We've primed the relevant endpoint.
        #  - Our most recent token is an OUT.
        #  - We're not stalled.
        stalled          = token.is_out & endpoint_stalled[token.endpoint]
        endpoint_matches = (token.endpoint == self.epno.r_data)
        allow_receive    = endpoint_matches & self.enable.r_data & token.is_out & ~stalled
        nak_receives     = token.is_out & ~allow_receive & ~stalled

        m.d.comb += [

            # We'll write to the endpoint iff we have a primed
            fifo.w_en         .eq(allow_receive & rx.valid & rx.next),
            fifo.w_data       .eq(rx.payload),

            # We'll advance the FIFO whenever our CPU reads from the data CSR;
            # and we'll always read our data from the FIFO.
            fifo.r_en         .eq(self.data.r_stb),
            self.data.r_data  .eq(fifo.r_data),

            # Pass the FIFO status on to our CPU.
            self.have.r_data  .eq(fifo.r_rdy),

            # If we've just finished an allowed receive, ACK.
            handshakes_out.ack    .eq(allow_receive & interface.rx_ready_for_response),

            # If we were stalled, stall.
            handshakes_out.stall  .eq(stalled & interface.rx_ready_for_response),

            # If we're not ACK'ing or STALL'ing, NAK all packets.
            handshakes_out.nak    .eq(nak_receives & interface.rx_ready_for_response)
        ]


        #
        # Interrupt/status
        #

        return DomainRenamer({"sync": "usb"})(m)
コード例 #17
0
    def check(self, m: Module):
        self.assert_cycles(m, 2)
        input1 = self.data.pre_a
        pre_h = self.data.pre_ccs[Flags.H]
        pre_c = self.data.pre_ccs[Flags.C]
        lo = input1[:4]
        hi = input1[4:]

        with m.If(pre_h):
            m.d.comb += Assume(lo <= 3)
            with m.If(pre_c):
                m.d.comb += Assume(hi <= 3)

        # Conditions taken directly from Motorola 6800 Programming Reference Manual,
        # the DAA instruction operation table.

        # Conditions are: C before DAA, a condition on hi, H before DAA, a condition on lo.
        conds = Array(
            [
                Array([0, hi <= 9, 0, lo <= 9]),
                Array([0, hi <= 8, 0, lo >= 10]),
                Array([0, hi <= 9, 1, lo <= 3]),
                Array([0, hi >= 10, 0, lo <= 9]),
                Array([0, hi >= 9, 0, lo >= 10]),
                Array([0, hi >= 10, 1, lo <= 3]),
                Array([1, hi <= 2, 0, lo <= 9]),
                Array([1, hi <= 2, 0, lo >= 10]),
                Array([1, hi <= 3, 1, lo <= 3]),
            ]
        )

        # Results are: DAA adjustment, state of C after DAA
        results = Array(
            [
                Array([0, 0]),
                Array([6, 0]),
                Array([6, 0]),
                Array([0x60, 1]),
                Array([0x66, 1]),
                Array([0x66, 1]),
                Array([0x60, 1]),
                Array([0x66, 1]),
                Array([0x66, 1]),
            ]
        )

        input_is_valid = Signal()
        expected_output = Signal(8)
        expected_c = Signal()

        for i in range(len(conds)):
            with m.If(
                (pre_c == conds[i][0])
                & conds[i][1]
                & (pre_h == conds[i][2])
                & conds[i][3]
            ):
                m.d.comb += input_is_valid.eq(1)
                m.d.comb += expected_output.eq(input1 + results[i][0])
                m.d.comb += expected_c.eq(results[i][1])

        z = expected_output == 0
        n = expected_output[7]

        with m.If(input_is_valid):
            self.assert_registers(m, A=expected_output, PC=self.data.pre_pc + 1)
            self.assert_flags(m, Z=z, N=n, C=expected_c)