コード例 #1
0
    def __init__(self, *, depth, addr_width, data_width, granularity):
        self.w = Record([("en", 1), ("rdy", 1),
                         ("op", [
                             ("addr", addr_width),
                             ("mask", data_width // granularity),
                             ("data", data_width),
                         ])])
        self.r = Record.like(self.w)

        self._fifo = SyncFIFOBuffered(width=len(self.w.op), depth=depth)
コード例 #2
0
ファイル: mnv2_cfu.py プロジェクト: tcal-x/CFU-Playground
 def _make_output_queue(self, m):
     m.submodules['FIFO'] = fifo = SyncFIFOBuffered(
         depth=config.OUTPUT_QUEUE_DEPTH, width=32)
     m.submodules['oq_get'] = oq_get = NextWordGetter()
     m.d.comb += [
         oq_get.data.eq(fifo.r_data),
         oq_get.ready.eq(fifo.r_rdy),
         fifo.r_en.eq(oq_get.next),
     ]
     self.register_xetter(34, oq_get)
     oq_has_space = fifo.w_level < (config.OUTPUT_QUEUE_DEPTH - 8)
     return fifo.w_data, fifo.w_en, oq_has_space
コード例 #3
0
ファイル: fifo.py プロジェクト: tcal-x/CFU-Playground
    def elab(self, m: Module):
        m.submodules.wrapped = fifo = SyncFIFOBuffered(depth=self.depth,
                                                       width=len(
                                                           self.input.payload))

        m.d.comb += [
            fifo.w_en.eq(self.input.valid),
            fifo.w_data.eq(self.input.payload),
            self.input.ready.eq(fifo.w_rdy),
            self.output.valid.eq(fifo.r_rdy),
            self.output.payload.eq(fifo.r_data),
            fifo.r_en.eq(self.output.ready),
            self.r_level.eq(fifo.r_level),
        ]
コード例 #4
0
ファイル: dll_tlp.py プロジェクト: ECP5-PCIe/ECP5-PCIe
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        ratio = self.ratio
        assert ratio == 4

        # Maybe these should be moved into PCIeDLLTLP class since it also involves RX a bit
        m.submodules.buffer = buffer = TLPBuffer(ratio = ratio, max_tlps = 2 ** len(self.replay_num))
        m.submodules.unacknowledged_tlp_fifo = unacknowledged_tlp_fifo = SyncFIFOBuffered(width = 12, depth = buffer.max_tlps)

        m.d.comb += self.dll.status.retry_buffer_occupation.eq(buffer.slots_occupied)
        m.d.comb += self.dll.status.tx_seq_num.eq(self.next_transmit_seq)

        source_from_buffer = Signal()
        sink_ready = Signal()
        m.d.comb += buffer.tlp_source.ready.eq(sink_ready & source_from_buffer)
        m.d.comb += self.tlp_sink.ready.eq(sink_ready & ~source_from_buffer & ~buffer.slots_full)
        sink_valid = Mux(source_from_buffer, buffer.tlp_source.all_valid, self.tlp_sink.all_valid)
        sink_symbol = [Mux(source_from_buffer, buffer.tlp_source.symbol[i], self.tlp_sink.symbol[i]) for i in range(ratio)]

        self.tlp_sink.connect(buffer.tlp_sink, m.d.comb)

        with m.If(self.dll.up):
            m.d.comb += buffer.store_tlp.eq(1) # TODO: Is this a good idea?
            m.d.rx += buffer.store_tlp_id.eq(self.next_transmit_seq)
            m.d.rx += buffer.send_tlp_id.eq(unacknowledged_tlp_fifo.r_data)
        
        with m.Else():
            m.d.rx += self.next_transmit_seq.eq(self.next_transmit_seq.reset)
            m.d.rx += self.ackd_seq.eq(self.ackd_seq.reset)
            m.d.rx += self.replay_num.eq(self.replay_num.reset)
        
        m.d.rx += self.accepts_tlps.eq((self.next_transmit_seq - self.ackd_seq) >= 2048) # mod 4096 is already applied since the signal is 12 bits long

        with m.If(self.replay_timer_running):
            m.d.rx += self.replay_timer.eq(self.replay_timer + 1)

        with m.If(unacknowledged_tlp_fifo.r_level == 0):
            m.d.rx += self.replay_timer_running.eq(0)
            m.d.rx += self.replay_timer.eq(0)

        with m.FSM(name="Replay_FSM", domain = "rx"):
            with m.State("Idle"):
                m.d.rx += source_from_buffer.eq(0)

                with m.If(self.replay_timer >= self.replay_timeout):
                    m.next = "Replay"
                
                with m.If(self.dll.received_ack_nak & ~self.dll.received_ack):
                    m.next = "Replay"

            with m.State("Replay"):
                m.d.rx += source_from_buffer.eq(1)
                m.d.rx += self.replay_timer.eq(0) # TODO: This should be after the TLP is sent

                with m.If(buffer.slots_empty):
                    m.d.rx += source_from_buffer.eq(0)
                    m.next = "Idle"
        
        m.d.rx += self.ackd_seq.eq(self.dll.received_ack_nak_id)

        # If ACK received:
        # Delete entry from retry buffer and advance unacknowledged_tlp_fifo
        # TODO: This doesn't check whether the ID stored in the FIFO was the one which was acknowledged. Maybe it can be replaced with a counter or that can be checked.
        with m.If(self.dll.received_ack_nak & self.dll.received_ack):
            m.d.comb += buffer.delete_tlp.eq(1)
            m.d.comb += buffer.delete_tlp_id.eq(self.dll.received_ack_nak_id)
            m.d.comb += unacknowledged_tlp_fifo.r_en.eq(1)

            m.d.comb += buffer.in_buffer_id.eq(self.dll.received_ack_nak_id)
            with m.If(buffer.in_buffer):
                m.d.rx += self.replay_timer.eq(0)
        
        reset_crc = Signal(reset = 1)
        # TODO Warning: Endianness
        crc_input = Signal(32)
        m.submodules.lcrc = lcrc = LCRC(crc_input, reset_crc)

        last_valid = Signal()
        m.d.rx += last_valid.eq(sink_valid)
        last_last_valid = Signal() # TODO: Maybe there is a better way
        m.d.rx += last_last_valid.eq(last_valid)
        last_last_last_valid = Signal() # TODO: Maybe there is a better way 😿 like a longer signal which gets shifted for example
        m.d.rx += last_last_last_valid.eq(last_last_valid)


        tlp_bytes = Signal(8 * self.ratio)
        tlp_bytes_before = Signal(8 * self.ratio)

        with m.If(sink_valid):
            m.d.comb += Cat(tlp_bytes[0 : 8 * ratio]).eq(Cat(sink_symbol)) # TODO: Endianness correct?
            m.d.rx += Cat(tlp_bytes_before[0 : 8 * ratio]).eq(Cat(sink_symbol)) # TODO: Endianness correct?

        with m.Else():
            with m.If(self.nullify):
                m.d.comb += Cat(tlp_bytes[0 : 8 * ratio]).eq(~lcrc.output) # ~~x = x
                m.d.rx += Cat(tlp_bytes_before[0 : 8 * ratio]).eq(~lcrc.output)
                m.d.comb += buffer.delete_tlp.eq(1)
                m.d.comb += buffer.delete_tlp_id.eq(self.next_transmit_seq)

            with m.Else():
                m.d.comb += Cat(tlp_bytes[0 : 8 * ratio]).eq(lcrc.output) # TODO: Endianness correct?
                m.d.rx += Cat(tlp_bytes_before[0 : 8 * ratio]).eq(lcrc.output) # TODO: Endianness correct?


        #m.d.rx += Cat(tlp_bytes[8 * ratio : 2 * 8 * ratio]).eq(Cat(tlp_bytes[0 : 8 * ratio]))

        even_more_delay = [Signal(9) for i in range(4)]

        m.d.rx += unacknowledged_tlp_fifo.w_en.eq(0)

        m.d.comb += sink_ready.eq(0) # TODO: maybe move to rx?

        delayed_symbol = Signal(32)
        m.d.rx += delayed_symbol.eq(Cat(sink_symbol))
        m.d.comb += crc_input.eq(delayed_symbol)

        for i in range(4):
            m.d.rx += self.dllp_source.valid[i].eq(0)


        with m.If(self.dllp_source.ready & unacknowledged_tlp_fifo.w_rdy):
            m.d.comb += sink_ready.eq(1) # TODO: maybe move to rx?
            with m.FSM(name = "TLP_transmit_FSM", domain = "rx"):
                with m.State("Idle"):
                    with m.If(~last_valid & sink_valid):
                        m.d.comb += reset_crc.eq(0)
                        m.d.comb += crc_input.eq(Cat(self.next_transmit_seq[8 : 12], Const(0, shape = 4), self.next_transmit_seq[0 : 8]))
                        m.d.rx += even_more_delay[0].eq(Ctrl.STP)
                        m.d.rx += even_more_delay[1].eq(self.next_transmit_seq[8 : 12])
                        m.d.rx += even_more_delay[2].eq(self.next_transmit_seq[0 : 8])
                        m.d.rx += even_more_delay[3].eq(tlp_bytes[8 * 0 : 8 * 1])
                        m.next = "Transmit"

                with m.State("Transmit"):
                    with m.If(last_valid & sink_valid):
                        m.d.comb += reset_crc.eq(0)
                        m.d.rx += even_more_delay[0].eq(tlp_bytes_before[8 * 1 : 8 * 2])
                        m.d.rx += even_more_delay[1].eq(tlp_bytes_before[8 * 2 : 8 * 3])
                        m.d.rx += even_more_delay[2].eq(tlp_bytes_before[8 * 3 : 8 * 4])
                        m.d.rx += even_more_delay[3].eq(tlp_bytes[8 * 0 : 8 * 1])
                        for i in range(4):
                            m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])
                        for i in range(4):
                            m.d.rx += self.dllp_source.valid[i].eq(1)

                    with m.Elif(~sink_valid):
                        m.d.comb += reset_crc.eq(0)
                        m.d.comb += sink_ready.eq(0) # TODO: maybe move to rx?
                        m.d.rx += even_more_delay[0].eq(tlp_bytes_before[8 * 1 : 8 * 2])
                        m.d.rx += even_more_delay[1].eq(tlp_bytes_before[8 * 2 : 8 * 3])
                        m.d.rx += even_more_delay[2].eq(tlp_bytes_before[8 * 3 : 8 * 4])
                        for i in range(4):
                            m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])
                        for i in range(4):
                            m.d.rx += self.dllp_source.valid[i].eq(1)
                        m.next = "Post-1"

                with m.State("Post-1"):
                    m.d.rx += self.dllp_source.symbol[3].eq(tlp_bytes[8 * 0 : 8 * 1])

                    for i in range(3):
                        m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])

                    for i in range(4):
                        m.d.rx += self.dllp_source.valid[i].eq(1)

                    m.next = "Post-2"
                
                with m.State("Post-2"):
                    m.d.comb += sink_ready.eq(0) # TODO: maybe move to rx?
                    m.d.rx += self.dllp_source.symbol[0].eq(tlp_bytes_before[8 * 1 : 8 * 2])
                    m.d.rx += self.dllp_source.symbol[1].eq(tlp_bytes_before[8 * 2 : 8 * 3])
                    m.d.rx += self.dllp_source.symbol[2].eq(tlp_bytes_before[8 * 3 : 8 * 4])

                    with m.If(self.nullify):
                        m.d.rx += self.dllp_source.symbol[3].eq(Ctrl.EDB)
                        m.d.rx += self.nullify.eq(0)

                    with m.Else():
                        m.d.rx += self.dllp_source.symbol[3].eq(Ctrl.END)
                        m.d.rx += unacknowledged_tlp_fifo.w_data.eq(self.next_transmit_seq)
                        m.d.rx += unacknowledged_tlp_fifo.w_en.eq(1)
                        m.d.rx += self.next_transmit_seq.eq(self.next_transmit_seq + 1)
                    
                    m.d.rx += self.replay_timer_running.eq(1) # TODO: Maybe this should be in the Else block above

                    for i in range(4):
                        m.d.rx += self.dllp_source.valid[i].eq(1)

                    m.next = "Idle"




        # TODO: This could be a FSM
        #with m.If(self.dllp_source.ready & unacknowledged_tlp_fifo.w_rdy):
        #    m.d.comb += sink_ready.eq(1) # TODO: maybe move to rx?
#
        #    with m.If(~last_valid & sink_valid):
        #        m.d.comb += reset_crc.eq(0)
        #        m.d.comb += crc_input.eq(Cat(self.next_transmit_seq[8 : 12], Const(0, shape = 4), self.next_transmit_seq[0 : 8]))
        #        m.d.rx += even_more_delay[0].eq(Ctrl.STP)
        #        m.d.rx += even_more_delay[1].eq(self.next_transmit_seq[8 : 12])
        #        m.d.rx += even_more_delay[2].eq(self.next_transmit_seq[0 : 8])
        #        m.d.rx += even_more_delay[3].eq(tlp_bytes[8 * 0 : 8 * 1])
        #        #for i in range(4):
        #        #    m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])
#
        #    with m.Elif(last_valid & sink_valid):
        #        m.d.comb += reset_crc.eq(0)
        #        m.d.rx += even_more_delay[0].eq(tlp_bytes_before[8 * 1 : 8 * 2])
        #        m.d.rx += even_more_delay[1].eq(tlp_bytes_before[8 * 2 : 8 * 3])
        #        m.d.rx += even_more_delay[2].eq(tlp_bytes_before[8 * 3 : 8 * 4])
        #        m.d.rx += even_more_delay[3].eq(tlp_bytes[8 * 0 : 8 * 1])
        #        for i in range(4):
        #            m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])
        #        for i in range(4):
        #            m.d.rx += self.dllp_source.valid[i].eq(1)
#
        #    with m.Elif(last_valid & ~sink_valid): # Maybe this can be done better and replaced by the two if blocks above
        #        m.d.comb += reset_crc.eq(0)
        #        m.d.comb += sink_ready.eq(0) # TODO: maybe move to rx?
        #        m.d.rx += even_more_delay[0].eq(tlp_bytes_before[8 * 1 : 8 * 2])
        #        m.d.rx += even_more_delay[1].eq(tlp_bytes_before[8 * 2 : 8 * 3])
        #        m.d.rx += even_more_delay[2].eq(tlp_bytes_before[8 * 3 : 8 * 4])
        #        for i in range(4):
        #            m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])
        #        for i in range(4):
        #            m.d.rx += self.dllp_source.valid[i].eq(1)
#
        #    with m.Elif(last_last_valid & ~sink_valid):
        #        m.d.rx += self.dllp_source.symbol[3].eq(tlp_bytes[8 * 0 : 8 * 1])
#
        #        for i in range(3):
        #            m.d.rx += self.dllp_source.symbol[i].eq(even_more_delay[i])
#
        #        for i in range(4):
        #            m.d.rx += self.dllp_source.valid[i].eq(1)
#
        #    with m.Elif(last_last_last_valid & ~sink_valid):
        #        m.d.comb += sink_ready.eq(0) # TODO: maybe move to rx?
        #        m.d.rx += self.dllp_source.symbol[0].eq(tlp_bytes_before[8 * 1 : 8 * 2])
        #        m.d.rx += self.dllp_source.symbol[1].eq(tlp_bytes_before[8 * 2 : 8 * 3])
        #        m.d.rx += self.dllp_source.symbol[2].eq(tlp_bytes_before[8 * 3 : 8 * 4])
#
        #        with m.If(self.nullify):
        #            m.d.rx += self.dllp_source.symbol[3].eq(Ctrl.EDB)
        #            m.d.rx += self.nullify.eq(0)
#
        #        with m.Else():
        #            m.d.rx += self.dllp_source.symbol[3].eq(Ctrl.END)
        #            m.d.rx += unacknowledged_tlp_fifo.w_data.eq(self.next_transmit_seq)
        #            m.d.rx += unacknowledged_tlp_fifo.w_en.eq(1)
        #            m.d.rx += self.next_transmit_seq.eq(self.next_transmit_seq + 1)
        #        
        #        m.d.rx += self.replay_timer_running.eq(1) # TODO: Maybe this should be in the Else block above
#
        #        for i in range(4):
        #            m.d.rx += self.dllp_source.valid[i].eq(1)


        return m
コード例 #5
0
ファイル: dll_tlp.py プロジェクト: ECP5-PCIe/ECP5-PCIe
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        ratio = self.ratio
        assert ratio == 4

        # TODO: Send NAK if buffer is full
        m.submodules.buffer = buffer = self.buffer
        m.submodules.received_tlp_fifo = received_tlp_fifo = SyncFIFOBuffered(width = 12, depth = buffer.max_tlps)

        m.d.comb += self.dll.status.receive_buffer_occupation.eq(buffer.slots_occupied)
        m.d.comb += self.dll.status.rx_seq_num.eq(self.actual_receive_seq)

        with m.If(~self.dll.up):
            m.d.rx += self.ack_nak_latency_timer.eq(self.ack_nak_latency_timer.reset)
        
        #m.d.rx += self.accepts_tlps.eq((self.next_transmit_seq - self.ackd_seq) >= 2048) # mod 4096 is already applied since the signal is 12 bits long

        #with m.If(self.timer_running):
        #    m.d.rx += self.replay_timer.eq(self.replay_timer + 1)

        source_3_delayed = Signal(8)
        m.d.rx += source_3_delayed.eq(self.dllp_sink.symbol[3][0:8])

        # Aligned as received by TLP layer from other end of the link
        source_symbols = [source_3_delayed, self.dllp_sink.symbol[0][0:8], self.dllp_sink.symbol[1][0:8], self.dllp_sink.symbol[2][0:8]]
        last_symbols = Signal(32)
        m.d.rx += last_symbols.eq(Cat(source_symbols))


        reset_crc = Signal(reset = 1)
        # TODO Warning: Endianness
        crc_input = Signal(32)
        m.submodules.lcrc = lcrc = LCRC(crc_input, reset_crc)

        m.d.rx += crc_input.eq(Cat(source_symbols))

        for i in range(4):
            m.d.rx += buffer.tlp_sink.symbol[i].eq(Cat(source_symbols[i]))
        
        end_good = Signal()

        def ack():
            m.d.comb += self.dll.schedule_ack_nak.eq(1)
            m.d.rx += [
                self.dll.scheduled_ack.eq(1),
                self.dll.scheduled_ack_nak_id.eq(self.actual_receive_seq),
                self.ack_nak_latency_timer.eq(self.ack_nak_latency_timer.reset),
            ]
        
        def nak():
            with m.If(~self.nak_scheduled):
                m.d.comb += self.dll.schedule_ack_nak.eq(1)
                m.d.rx += [
                    self.dll.scheduled_ack.eq(0),
                    self.dll.scheduled_ack_nak_id.eq(self.next_receive_seq - 1),
                    self.nak_scheduled.eq(1),
                    self.ack_nak_latency_timer.eq(self.ack_nak_latency_timer.reset),
                ]

        with m.If(self.ack_nak_latency_timer < self.ack_nak_latency_limit):
            m.d.rx += self.ack_nak_latency_timer.eq(self.ack_nak_latency_timer + 1)

        with m.FSM(name = "TLP_rx_FSM", domain = "rx"):
            with m.State("Idle"):
                with m.If(self.dllp_sink.symbol[0] == Ctrl.STP):
                    tlp_id = Cat(source_symbols[3], source_symbols[2][0:4])

                    m.d.comb += buffer.store_tlp.eq(1)
                    m.d.rx += buffer.store_tlp_id.eq(tlp_id)

                    m.d.rx += reset_crc.eq(0)
                    m.d.rx += crc_input.eq(Cat(source_symbols[2], source_symbols[3]))
                    m.d.rx += self.actual_receive_seq.eq(tlp_id)
                    m.next = "Receive"
                
                #with m.If(self.dll.up  & (self.ack_nak_latency_timer == self.ack_nak_latency_limit) & ~ self.nak_scheduled)
            
            with m.State("Receive"):
                with m.If((self.dllp_sink.symbol[3] == Ctrl.END) | (self.dllp_sink.symbol[3] == Ctrl.EDB)):
                    for i in range(4):
                        m.d.rx += buffer.tlp_sink.valid[i].eq(0)

                    m.d.rx += end_good.eq(self.dllp_sink.symbol[3] == Ctrl.END)

                    m.next = "LCRC"

                with m.Else():
                    for i in range(4):
                        m.d.rx += buffer.tlp_sink.valid[i].eq(1)
            
            with m.State("LCRC"):
                m.d.rx += reset_crc.eq(1)
                with m.If((lcrc.output == last_symbols) & end_good):
                    with m.If(self.actual_receive_seq == self.next_receive_seq):
                        m.d.comb += received_tlp_fifo.w_en.eq(1)
                        m.d.comb += received_tlp_fifo.w_data.eq(self.actual_receive_seq)
                        m.d.rx += self.next_receive_seq.eq(self.next_receive_seq + 1)
                        m.d.rx += self.nak_scheduled.eq(0)
                        with m.If(~buffer.slots_full):
                            ack() # This should be fine, really, see PCIe Base 1.1 Page 157 Point 2

                        with m.Else():
                            m.next = "Wait"

                    with m.Elif((self.next_receive_seq - self.actual_receive_seq) <= 2048): # Duplicate received
                        ack()

                    with m.Else():
                        nak()
                
                with m.Else():
                    with m.If((~lcrc.output == last_symbols) & ~end_good):
                        m.d.comb += buffer.delete_tlp.eq(1)
                        m.d.comb += buffer.delete_tlp_id.eq(self.actual_receive_seq)

                    with m.Else(): # TODO: Delete TLP here too?
                        nak()

                m.next = "Idle"
            
            with m.State("Wait"): # It goes in this state if there is no free space, after space has been freed it is acknowledged such that the next TLP can be received.
                with m.If(~buffer.slots_full):
                    ack()
                    m.next = "Idle"

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

        in_fifo = self.in_fifo
        out_fifo = self.out_fifo
        buf_fifo = m.submodules.buf_fifo = SyncFIFOBuffered(
            width=8, depth=_COMMAND_BUFFER_SIZE)

        m.d.comb += bus.ce.eq(1)

        with m.FSM():
            # Page writes in parallel EEPROMs do not tolerate delays, so the entire page needs
            # to be buffered before programming starts. After receiving the QUEUE command, all
            # subsequent commands except for RUN are placed into the buffer. The RUN command
            # restarts command processing. Until the buffer is empty, only buffered commands are
            # processed.
            cmd_fifo = Array([out_fifo, buf_fifo])[buf_fifo.r_rdy]

            a_bytes = (bus.a_bits + 7) // 8
            dq_bytes = (bus.dq_bits + 7) // 8
            a_index = Signal(range(a_bytes + 1))
            dq_index = Signal(range(dq_bytes + 1))
            a_latch = Signal(bus.a_bits)
            dq_latch = Signal(bus.dq_bits)

            read_cycle_cyc = (math.ceil(
                self._read_cycle_delay * platform.default_clk_frequency) + 2
                              )  # FFSynchronizer latency
            write_cycle_cyc = math.ceil(self._write_cycle_delay *
                                        platform.default_clk_frequency)
            write_hold_cyc = math.ceil(self._write_hold_delay *
                                       platform.default_clk_frequency)
            timer = Signal(
                range(
                    max(read_cycle_cyc, write_cycle_cyc, write_hold_cyc) + 1))

            with m.State("COMMAND"):
                with m.If(cmd_fifo.r_rdy):
                    m.d.comb += cmd_fifo.r_en.eq(1)
                    with m.Switch(cmd_fifo.r_data):
                        with m.Case(_Command.QUEUE):
                            m.next = "QUEUE-RECV"
                        with m.Case(_Command.SEEK):
                            m.d.sync += a_index.eq(0)
                            m.next = "SEEK-RECV"
                        with m.Case(_Command.INCR):
                            m.d.sync += bus.a.eq(bus.a + 1)
                            m.next = "SEEK-WAIT"
                        with m.Case(_Command.READ):
                            m.d.sync += dq_index.eq(0)
                            m.next = "READ-PULSE"
                        with m.Case(_Command.WRITE):
                            m.d.sync += dq_index.eq(0)
                            m.next = "WRITE-RECV"
                        with m.Case(_Command.POLL):
                            m.next = "POLL-PULSE"
                with m.Else():
                    m.d.comb += in_fifo.flush.eq(1)

            with m.State("QUEUE-RECV"):
                with m.If(out_fifo.r_rdy):
                    escaped = Signal()
                    with m.If(~escaped & (out_fifo.r_data == _Command.QUEUE)):
                        m.d.comb += out_fifo.r_en.eq(1)
                        m.d.sync += escaped.eq(1)
                    with m.Elif(escaped & (out_fifo.r_data == _Command.RUN)):
                        m.d.comb += out_fifo.r_en.eq(1)
                        m.next = "COMMAND"
                    with m.Else():
                        m.d.sync += escaped.eq(0)
                        m.d.comb += out_fifo.r_en.eq(buf_fifo.w_rdy)
                        m.d.comb += buf_fifo.w_data.eq(out_fifo.r_data)
                        m.d.comb += buf_fifo.w_en.eq(1)

            with m.State("SEEK-RECV"):
                with m.If(a_index == a_bytes):
                    m.d.sync += bus.a.eq(a_latch)
                    m.next = "SEEK-WAIT"
                with m.Elif(cmd_fifo.r_rdy):
                    m.d.comb += cmd_fifo.r_en.eq(1)
                    m.d.sync += a_latch.word_select(a_index,
                                                    8).eq(cmd_fifo.r_data)
                    m.d.sync += a_index.eq(a_index + 1)

            with m.State("SEEK-WAIT"):
                with m.If(bus.rdy):
                    m.next = "COMMAND"

            with m.State("READ-PULSE"):
                m.d.sync += bus.oe.eq(1)
                m.d.sync += timer.eq(read_cycle_cyc)
                m.next = "READ-CYCLE"

            with m.State("READ-CYCLE"):
                with m.If(timer == 0):
                    # Normally, this would be the place to deassert OE. However, this would reduce
                    # metastability (during burst reads) in the output buffers of a memory that is
                    # reading bits close to the buffer threshold. Wait, isn't metastability bad?
                    # Normally yes, but this is a special case! Metastability causes unstable
                    # bits, and unstable bits reduce the chance that corrupt data will slip
                    # through undetected.
                    m.d.sync += dq_latch.eq(bus.q)
                    m.next = "READ-SEND"
                with m.Else():
                    m.d.sync += timer.eq(timer - 1)

            with m.State("READ-SEND"):
                with m.If(dq_index == dq_bytes):
                    m.next = "COMMAND"
                with m.Elif(in_fifo.w_rdy):
                    m.d.comb += in_fifo.w_en.eq(1)
                    m.d.comb += in_fifo.w_data.eq(
                        dq_latch.word_select(dq_index, 8))
                    m.d.sync += dq_index.eq(dq_index + 1)

            with m.State("WRITE-RECV"):
                with m.If(dq_index == dq_bytes):
                    m.d.sync += bus.d.eq(dq_latch)
                    m.d.sync += bus.oe.eq(0)  # see comment in READ-CYCLE
                    m.d.sync += bus.we.eq(1)
                    m.d.sync += timer.eq(write_cycle_cyc)
                    m.next = "WRITE-CYCLE"
                with m.Elif(cmd_fifo.r_rdy):
                    m.d.comb += cmd_fifo.r_en.eq(1)
                    m.d.sync += dq_latch.word_select(dq_index,
                                                     8).eq(cmd_fifo.r_data)
                    m.d.sync += dq_index.eq(dq_index + 1)

            with m.State("WRITE-CYCLE"):
                with m.If(timer == 0):
                    m.d.sync += bus.we.eq(0)
                    m.d.sync += timer.eq(write_hold_cyc)
                    m.next = "WRITE-HOLD"
                with m.Else():
                    m.d.sync += timer.eq(timer - 1)

            with m.State("WRITE-HOLD"):
                with m.If(timer == 0):
                    m.next = "COMMAND"
                with m.Else():
                    m.d.sync += timer.eq(timer - 1)

            with m.State("POLL-PULSE"):
                m.d.sync += bus.oe.eq(1)
                m.d.sync += timer.eq(read_cycle_cyc)
                m.next = "POLL-CYCLE"

            with m.State("POLL-CYCLE"):
                with m.If(timer == 0):
                    # There are many different ways EEPROMs can signal readiness, but if they do it
                    # on data lines, they are common in that they all present something else other
                    # than the last written byte on DQ lines.
                    with m.If(bus.q == dq_latch):
                        with m.If(in_fifo.w_rdy):
                            m.d.comb += in_fifo.w_en.eq(1)
                            m.d.sync += bus.oe.eq(0)
                            m.next = "COMMAND"
                with m.Else():
                    m.d.sync += timer.eq(timer - 1)

        return m
コード例 #7
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        m.submodules.serdes = serdes = self.__serdes

        m.submodules += self.lane

        #m.d.comb += serdes.lane.speed.eq(self.lane.speed)

        m.d.comb += serdes.lane.reset.eq(self.lane.reset)

        data_width = len(serdes.lane.rx_symbol)

        m.domains.rxf = ClockDomain()
        m.domains.txf = ClockDomain()
        m.d.comb += [
            #ClockSignal("sync").eq(serdes.refclk),
            ClockSignal("rxf").eq(serdes.rx_clk),
            ClockSignal("txf").eq(serdes.tx_clk),
        ]

        platform.add_clock_constraint(
            self.rx_clk, 125e6 if self.speed_5GTps else 625e5
        )  # For NextPNR, set the maximum clock frequency such that errors are given
        platform.add_clock_constraint(self.tx_clk,
                                      125e6 if self.speed_5GTps else 625e5)

        m.submodules.lane = lane = PCIeSERDESInterface(
            4
        )  # TODO: Uhh is this supposed to be here? // I think it might be the fast lane

        # IF SOMETHING IS BROKE: Check if the TX actually transmits good data and not order-swapped data
        # TODO: Maybe use hardware divider? Though this seems to be fine
        m.d.rxf += self.rx_clk.eq(~self.rx_clk)

        with m.If(~self.rx_clk):
            m.d.rxf += lane.rx_symbol[data_width:data_width * 2].eq(
                serdes.lane.rx_symbol)
            m.d.rxf += lane.rx_valid[serdes.gearing:serdes.gearing * 2].eq(
                serdes.lane.rx_valid)
        with m.Else():
            m.d.rxf += lane.rx_symbol[0:data_width].eq(serdes.lane.rx_symbol)
            m.d.rxf += lane.rx_valid[0:serdes.gearing].eq(serdes.lane.rx_valid)

            # To ensure that it outputs consistent data
            # m.d.rxf += self.lane.rx_symbol.eq(lane.rx_symbol)
            # m.d.rxf += self.lane.rx_valid.eq(lane.rx_valid)

        m.d.txf += self.tx_clk.eq(~self.tx_clk)

        m.d.txf += serdes.lane.tx_symbol.eq(
            Mux(self.tx_clk, lane.tx_symbol[data_width:data_width * 2],
                lane.tx_symbol[0:data_width]))
        m.d.txf += serdes.lane.tx_disp.eq(
            Mux(self.tx_clk, lane.tx_disp[serdes.gearing:serdes.gearing * 2],
                lane.tx_disp[0:serdes.gearing]))
        m.d.txf += serdes.lane.tx_set_disp.eq(
            Mux(self.tx_clk,
                lane.tx_set_disp[serdes.gearing:serdes.gearing * 2],
                lane.tx_set_disp[0:serdes.gearing]))
        m.d.txf += serdes.lane.tx_e_idle.eq(
            Mux(self.tx_clk, lane.tx_e_idle[serdes.gearing:serdes.gearing * 2],
                lane.tx_e_idle[0:serdes.gearing]))

        # CDC
        # TODO: Keep the SyncFIFO? Its faster but is it reliable?
        #rx_fifo = m.submodules.rx_fifo = AsyncFIFOBuffered(width=(data_width + serdes.gearing) * 2, depth=4, r_domain="rx", w_domain="rxf")
        rx_fifo = m.submodules.rx_fifo = DomainRenamer("rxf")(SyncFIFOBuffered(
            width=(data_width + serdes.gearing) * 2, depth=4))
        m.d.rxf += rx_fifo.w_data.eq(Cat(lane.rx_symbol, lane.rx_valid))
        m.d.comb += Cat(self.lane.rx_symbol,
                        self.lane.rx_valid).eq(rx_fifo.r_data)
        m.d.comb += rx_fifo.r_en.eq(1)
        m.d.rxf += rx_fifo.w_en.eq(self.rx_clk)

        #tx_fifo = m.submodules.tx_fifo = AsyncFIFOBuffered(width=(data_width + serdes.gearing * 3) * 2, depth=4, r_domain="txf", w_domain="tx")
        tx_fifo = m.submodules.tx_fifo = DomainRenamer("txf")(SyncFIFOBuffered(
            width=(data_width + serdes.gearing * 3) * 2, depth=4))
        m.d.comb += tx_fifo.w_data.eq(
            Cat(self.lane.tx_symbol, self.lane.tx_set_disp, self.lane.tx_disp,
                self.lane.tx_e_idle))
        m.d.txf += Cat(lane.tx_symbol, lane.tx_set_disp, lane.tx_disp,
                       lane.tx_e_idle).eq(tx_fifo.r_data)
        m.d.txf += tx_fifo.r_en.eq(self.tx_clk)
        m.d.comb += tx_fifo.w_en.eq(1)
        #m.d.txf  += Cat(lane.tx_symbol, lane.tx_set_disp, lane.tx_disp, lane.tx_e_idle).eq(Cat(self.lane.tx_symbol, self.lane.tx_set_disp, self.lane.tx_disp, self.lane.tx_e_idle))

        return m
コード例 #8
0
ファイル: eptri.py プロジェクト: greatscottgadgets/luna
    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

        # Logic condition for getting a new setup packet.
        new_setup = token.new_token & token.is_setup
        reset_requested = self.reset.w_stb & self.reset.w_data
        clear_fifo = new_setup | reset_requested

        #
        # Core FIFO.
        #
        m.submodules.fifo = fifo = ResetInserter(clear_fifo)(SyncFIFOBuffered(
            width=8, depth=8))

        m.d.comb += [

            # We'll write to the active FIFO whenever the last received token is a SETUP
            # token, and we have incoming data; and we'll always write the data received
            fifo.w_en.eq(token.is_setup & 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),

            # Always acknowledge SETUP packets as they arrive.
            handshakes_out.ack.eq(token.is_setup
                                  & interface.rx_ready_for_response),

            # Trigger a SETUP interrupt as we ACK the setup packet, since that's also the point
            # where we know we're done receiving data.
            self.setup_received.stb.eq(handshakes_out.ack)
        ]

        #
        # Control registers
        #

        # Our address register always reads the current address of the device;
        # but will generate a
        m.d.comb += self._address.r_data.eq(interface.active_address)
        with m.If(self._address.w_stb):
            m.d.comb += [
                interface.address_changed.eq(1),
                interface.new_address.eq(self._address.w_data),
            ]

        #
        # Status and interrupts.
        #

        with m.If(token.new_token):
            m.d.usb += self.epno.r_data.eq(token.endpoint)

        # TODO: generate interrupts

        return DomainRenamer({"sync": "usb"})(m)
コード例 #9
0
ファイル: eptri.py プロジェクト: greatscottgadgets/luna
    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 primed.
        endpoint_primed = Array(Signal() for _ in range(16))

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

        # Keep track of the PIDs for each endpoint, which we'll toggle automatically.
        endpoint_data_pid = Array(Signal() for _ in range(16))

        # Keep track of whether we're enabled.
        with m.If(self.enable.w_stb):
            m.d.usb += self.enable.r_data.eq(self.enable.w_data)

        # If Prime is written to, mark the relevant endpoint as primed.
        with m.If(self.prime.w_stb):
            m.d.usb += endpoint_primed[self.epno.r_data].eq(self.prime.w_data)

        # If we've just ACK'd a receive, clear our enable and un-prime the given endpoint.
        with m.If(interface.handshakes_out.ack & token.is_out):
            m.d.usb += [
                self.enable.r_data.eq(0),
                endpoint_primed[token.endpoint].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)

        # Allow our controller to override our DATA pid, selectively.
        with m.If(self.pid.w_stb):
            m.d.usb += endpoint_data_pid[self.epno.r_data].eq(self.pid.w_data)

        # Clear our endpoint `stall` when we get a SETUP packet, and reset the endpoint's
        # data PID to DATA1, as per [USB2.0: 8.5.3], the first packet of the DATA or STATUS
        # phase always carries a DATA1 PID.
        with m.If(token.is_setup & token.new_token):
            m.d.usb += [
                endpoint_stalled[token.endpoint].eq(0),
                endpoint_data_pid[token.endpoint].eq(1)
            ]

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

        # 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_primed = endpoint_primed[token.endpoint]
        ready_to_receive = endpoint_primed & self.enable.r_data & ~stalled
        allow_receive = token.is_out & ready_to_receive
        nak_receives = token.is_out & ~ready_to_receive & ~stalled

        # Shortcut for when we have a "redundant"/incorrect PID. In these cases, we'll assume
        # the host missed our ACK, and per the USB spec, implicitly ACK the packet.
        is_redundant_pid = (interface.rx_pid_toggle !=
                            endpoint_data_pid[token.endpoint])
        is_redundant_packet = endpoint_primed & token.is_out & is_redundant_pid

        # Shortcut conditions under which we'll ACK and NAK a receive.
        ack_redundant_packet = (is_redundant_packet
                                & interface.rx_ready_for_response)
        ack_receive = allow_receive & interface.rx_ready_for_response
        nak_receive = nak_receives & interface.rx_ready_for_response & ~ack_redundant_packet

        # Conditions under which we'll ACK or NAK a ping.
        ack_ping = ready_to_receive & token.is_ping & token.ready_for_response
        nak_ping = ~ready_to_receive & token.is_ping & token.ready_for_response

        m.d.comb += [
            # We'll write to the endpoint iff we've valid data, and we're allowed receive.
            fifo.w_en.eq(allow_receive & rx.valid & rx.next
                         & ~is_redundant_packet),
            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(ack_receive | ack_ping
                                  | ack_redundant_packet),

            # Trigger our DONE interrupt once we ACK a received/allowed packet.
            self._done_irq.stb.eq(ack_receive),

            # 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_receive | nak_ping),

            # Always indicate the current DATA PID in the PID register.
            self.pid.r_data.eq(endpoint_data_pid[self.epno.r_data])
        ]

        # Whenever we capture data, update our associated endpoint number
        # to match the endpoint on which we received the relevant data.
        with m.If(fifo.w_en):
            m.d.usb += self.data_ep.r_data.eq(token.endpoint)

        # Whenever we ACK a non-redundant receive, toggle our DATA PID.
        # (unless the user happens to be overriding it by writing to the PID register).
        with m.If(ack_receive & ~is_redundant_packet & ~self.pid.w_stb):
            m.d.usb += endpoint_data_pid[token.endpoint].eq(
                ~endpoint_data_pid[token.endpoint])

        #
        # Interrupt/status
        #

        return DomainRenamer({"sync": "usb"})(m)
コード例 #10
0
ファイル: eptri.py プロジェクト: greatscottgadgets/luna
    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))

        # Keep track of the current DATA pid for each endpoint.
        endpoint_data_pid = Array(Signal() for _ in range(16))

        # Clear our system state on reset.
        with m.If(self.reset.w_stb):
            for i in range(16):
                m.d.usb += [
                    endpoint_stalled[i].eq(0),
                    endpoint_data_pid[i].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)

        # Clear our endpoint `stall` when we get a SETUP packet, and reset the endpoint's
        # data PID to DATA1, as per [USB2.0: 8.5.3], the first packet of the DATA or STATUS
        # phase always carries a DATA1 PID.
        with m.If(token.is_setup & token.new_token):
            m.d.usb += [
                endpoint_stalled[token.endpoint].eq(0),
                endpoint_data_pid[token.endpoint].eq(1)
            ]

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

        #
        # Data toggle control.
        #
        endpoint_matches = (token.endpoint == self.epno.r_data)
        packet_complete = self.interface.handshakes_in.ack & token.is_in & endpoint_matches

        # Always drive the DATA pid we're transmitting with our current data pid.
        m.d.comb += self.interface.tx_pid_toggle.eq(
            endpoint_data_pid[token.endpoint])

        # If our controller is overriding the data PID, accept the override.
        with m.If(self.pid.w_stb):
            m.d.usb += endpoint_data_pid[self.epno.r_data].eq(self.pid.w_data)

        # Otherwise, toggle our expected DATA PID once we receive a complete packet.
        with m.Elif(packet_complete):
            m.d.usb += endpoint_data_pid[token.endpoint].eq(
                ~endpoint_data_pid[token.endpoint])

        #
        # Control logic.
        #

        # Logic shorthand.
        new_in_token = (token.is_in & token.ready_for_response)
        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"

                # Always return to IDLE on reset.
                with m.If(self.reset.w_stb):
                    m.next = "IDLE"

            # 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)

                # Always return to IDLE on reset.
                with m.If(self.reset.w_stb):
                    m.next = "IDLE"

            # 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.d.comb += self._done_irq.stb.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_byte = (bytes_in_fifo == 1)

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

                    # 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_byte & tx.ready):
                    # Trigger our DONE interrupt.
                    m.d.comb += self._done_irq.stb.eq(1)
                    m.next = 'IDLE'

                # Always return to IDLE on reset.
                with m.If(self.reset.w_stb):
                    m.next = "IDLE"

        return DomainRenamer({"sync": "usb"})(m)