예제 #1
0
 def get_port(self, udp_port, dw=8):
     if udp_port in self.users.keys():
         raise ValueError("Port {0:#x} already assigned".format(udp_port))
     user_port = LiteEthUDPUserPort(dw)
     internal_port = LiteEthUDPUserPort(8)
     if dw != 8:
         converter = stream.StrideConverter(
             eth_udp_user_description(user_port.dw),
             eth_udp_user_description(8))
         self.submodules += converter
         self.comb += [
             user_port.sink.connect(converter.sink),
             converter.source.connect(internal_port.sink)
         ]
         converter = stream.StrideConverter(
             eth_udp_user_description(8),
             eth_udp_user_description(user_port.dw))
         self.submodules += converter
         self.comb += [
             internal_port.source.connect(converter.sink),
             converter.source.connect(user_port.source)
         ]
         self.users[udp_port] = internal_port
     else:
         self.users[udp_port] = user_port
     return user_port
예제 #2
0
    def __init__(self, with_converter=False):
        self.submodules.host = Host(64, root_id, endpoint_id,
            phy_debug=False,
            chipset_debug=False, chipset_split=True, chipset_reordering=True,
            host_debug=True)
        self.submodules.endpoint = LitePCIeEndpoint(self.host.phy, max_pending_requests=8, with_reordering=True)
        self.submodules.dma_reader = LitePCIeDMAReader(self.endpoint, self.endpoint.crossbar.get_master_port(read_only=True))
        self.submodules.dma_writer = LitePCIeDMAWriter(self.endpoint, self.endpoint.crossbar.get_master_port(write_only=True))

        if with_converter:
                self.submodules.up_converter = stream.StrideConverter(dma_layout(16), dma_layout(64))
                self.submodules.down_converter = stream.StrideConverter(dma_layout(64), dma_layout(16))
                self.submodules += stream.Pipeline(self.dma_reader,
                                                   self.down_converter,
                                                   self.up_converter,
                                                   self.dma_writer)
        else:
            self.comb += self.dma_reader.source.connect(self.dma_writer.sink)

        self.submodules.msi = LitePCIeMSI(2)
        self.comb += [
            self.msi.irqs[log2_int(DMA_READER_IRQ)].eq(self.dma_reader.irq),
            self.msi.irqs[log2_int(DMA_WRITER_IRQ)].eq(self.dma_writer.irq)
        ]
        self.submodules.irq_handler = InterruptHandler(debug=False)
        self.comb += self.msi.source.connect(self.irq_handler.sink)
예제 #3
0
    def __init__(self, port_from, port_to, reverse=False):
        assert port_from.clock_domain == port_to.clock_domain
        assert port_from.data_width > port_to.data_width
        assert port_from.mode == port_to.mode
        if port_from.data_width % port_to.data_width:
            raise ValueError("Ratio must be an int")

        # # #

        ratio = port_from.data_width//port_to.data_width
        mode = port_from.mode

        counter = Signal(max=ratio)
        counter_reset = Signal()
        counter_ce = Signal()
        self.sync += \
            If(counter_reset,
                counter.eq(0)
            ).Elif(counter_ce,
                counter.eq(counter + 1)
            )

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE",
            counter_reset.eq(1),
            If(port_from.cmd.valid,
                NextState("CONVERT")
            )
        )
        fsm.act("CONVERT",
            port_to.cmd.valid.eq(1),
            port_to.cmd.we.eq(port_from.cmd.we),
            port_to.cmd.addr.eq(port_from.cmd.addr*ratio + counter),
            If(port_to.cmd.ready,
                counter_ce.eq(1),
                If(counter == ratio - 1,
                    port_from.cmd.ready.eq(1),
                    NextState("IDLE")
                )
            )
        )

        if mode == "write" or mode == "both":
            wdata_converter = stream.StrideConverter(
                port_from.wdata.description,
                port_to.wdata.description,
                reverse=reverse)
            self.submodules += wdata_converter
            self.submodules += stream.Pipeline(
                port_from.wdata, wdata_converter, port_to.wdata)

        if mode == "read" or mode == "both":
            rdata_converter = stream.StrideConverter(
                port_to.rdata.description,
                port_from.rdata.description,
                reverse=reverse)
            self.submodules += rdata_converter
            self.submodules += stream.Pipeline(
                port_to.rdata, rdata_converter, port_from.rdata)
예제 #4
0
파일: wishbone.py 프로젝트: zsipos/litedram
    def __init__(self, wishbone, port, base_address=0x00000000):
        wishbone_data_width = len(wishbone.dat_w)
        port_data_width = 2**int(log2(len(
            port.wdata.data)))  # Round to lowest power 2
        assert wishbone_data_width >= port_data_width

        # # #

        adr_offset = base_address >> log2_int(port.data_width // 8)

        # Write Datapath ---------------------------------------------------------------------------
        wdata_converter = stream.StrideConverter(
            [("data", wishbone_data_width), ("we", wishbone_data_width // 8)],
            [("data", port_data_width), ("we", port_data_width // 8)],
        )
        self.submodules += wdata_converter
        self.comb += [
            wdata_converter.sink.valid.eq(wishbone.cyc & wishbone.stb
                                          & wishbone.we),
            wdata_converter.sink.data.eq(wishbone.dat_w),
            wdata_converter.sink.we.eq(wishbone.sel),
            wdata_converter.source.connect(port.wdata)
        ]

        # Read Datapath ----------------------------------------------------------------------------
        rdata_converter = stream.StrideConverter(
            [("data", port_data_width)],
            [("data", wishbone_data_width)],
        )
        self.submodules += rdata_converter
        self.comb += [
            port.rdata.connect(rdata_converter.sink),
            rdata_converter.source.ready.eq(1),
            wishbone.dat_r.eq(rdata_converter.source.data),
        ]

        # Control ----------------------------------------------------------------------------------
        ratio = wishbone_data_width // port_data_width
        count = Signal(max=max(ratio, 2))
        self.submodules.fsm = fsm = FSM(reset_state="CMD")
        fsm.act(
            "CMD", port.cmd.valid.eq(wishbone.cyc & wishbone.stb),
            port.cmd.we.eq(wishbone.we),
            port.cmd.addr.eq(wishbone.adr * ratio + count - adr_offset),
            If(
                port.cmd.valid & port.cmd.ready, NextValue(count, count + 1),
                If(
                    count == (ratio - 1), NextValue(count, 0),
                    If(wishbone.we,
                       NextState("WAIT-WRITE")).Else(NextState("WAIT-READ")))))
        fsm.act(
            "WAIT-WRITE",
            If(wdata_converter.sink.ready, wishbone.ack.eq(1),
               NextState("CMD")))
        fsm.act(
            "WAIT-READ",
            If(rdata_converter.source.valid, wishbone.ack.eq(1),
               NextState("CMD")))
예제 #5
0
    def __init__(self, axi_from, axi_to):
        dw_from  = len(axi_from.r.data)
        dw_to    = len(axi_to.r.data)
        ratio    = int(dw_to//dw_from)
        assert dw_from*ratio == dw_to

        # # #

        # Note: Assuming size of "axi_from" burst >= "axi_to" data_width.

        # Write path -------------------------------------------------------------------------------

        # AW Channel.
        self.comb += [
            axi_from.aw.connect(axi_to.aw, omit={"len", "size"}),
            axi_to.aw.len.eq( axi_from.aw.len >> log2_int(ratio)),
            axi_to.aw.size.eq(axi_from.aw.size + log2_int(ratio)),
        ]

        # W Channel.
        w_converter = stream.StrideConverter(
            description_from = [("data", dw_from), ("strb", dw_from//8)],
            description_to   = [("data",   dw_to), ("strb",   dw_to//8)],
        )
        self.submodules += w_converter
        self.comb += axi_from.w.connect(w_converter.sink, omit={"id"})
        self.comb += w_converter.source.connect(axi_to.w)
        self.comb += axi_to.w.id.eq(axi_from.w.id)

        # B Channel.
        self.comb += axi_to.b.connect(axi_from.b)

        # Read path --------------------------------------------------------------------------------

        # AR Channel.
        self.comb += [
            axi_from.ar.connect(axi_to.ar, omit={"len", "size"}),
            axi_to.ar.len.eq( axi_from.ar.len >> log2_int(ratio)),
            axi_to.ar.size.eq(axi_from.ar.size + log2_int(ratio)),
        ]

        # R Channel.
        r_converter = stream.StrideConverter(
            description_from = [("data",   dw_to)],
            description_to   = [("data", dw_from)],
        )
        self.submodules += r_converter
        self.comb += axi_to.r.connect(r_converter.sink, omit={"id", "resp"})
        self.comb += r_converter.source.connect(axi_from.r)
        self.comb += axi_from.r.resp.eq(axi_to.r.resp)
        self.comb += axi_from.r.id.eq(axi_to.r.id)
예제 #6
0
파일: udp.py 프로젝트: jersey99/liteeth
    def get_port(self, udp_port, dw=8, cd="sys"):
        if udp_port in self.users.keys():
            raise ValueError("Port {0:#x} already assigned".format(udp_port))

        user_port = LiteEthUDPUserPort(dw)
        internal_port = LiteEthUDPUserPort(self.dw)

        # TX
        # ---

        # CDC.
        self.submodules.tx_cdc = tx_cdc = stream.ClockDomainCrossing(
            layout=eth_udp_user_description(user_port.dw),
            cd_from=cd,
            cd_to="sys")
        self.comb += user_port.sink.connect(tx_cdc.sink)

        # Data-Width Conversion.
        self.submodules.tx_converter = tx_converter = stream.StrideConverter(
            description_from=eth_udp_user_description(user_port.dw),
            description_to=eth_udp_user_description(self.dw))
        self.comb += tx_cdc.source.connect(tx_converter.sink)

        # Interface.
        self.comb += tx_converter.source.connect(internal_port.sink)

        # RX
        # --
        # Data-Width Conversion.
        self.submodules.rx_converter = rx_converter = stream.StrideConverter(
            description_from=eth_udp_user_description(self.dw),
            description_to=eth_udp_user_description(user_port.dw))
        self.comb += internal_port.source.connect(rx_converter.sink)

        # CDC.
        self.submodules.rx_cdc = rx_cdc = stream.ClockDomainCrossing(
            layout=eth_udp_user_description(user_port.dw),
            cd_from="sys",
            cd_to=cd)
        self.comb += rx_converter.source.connect(rx_cdc.sink)

        # Interface.
        self.comb += rx_cdc.source.connect(user_port.source)

        # Expose/Return User Port.
        # ------------------------
        self.users[udp_port] = internal_port

        return user_port
예제 #7
0
    def __init__(self, port_from, port_to, reverse=False):
        assert port_from.clock_domain == port_to.clock_domain
        assert port_from.data_width    > port_to.data_width
        assert port_from.mode         == port_to.mode
        if port_from.data_width % port_to.data_width:
            raise ValueError("Ratio must be an int")

        # # #

        ratio = port_from.data_width//port_to.data_width
        mode  = port_from.mode
        count = Signal(max=ratio)

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE",
            NextValue(count, 0),
            If(port_from.cmd.valid,
                NextState("CONVERT")
            )
        )
        fsm.act("CONVERT",
            port_to.cmd.valid.eq(1),
            port_to.cmd.we.eq(port_from.cmd.we),
            port_to.cmd.addr.eq(port_from.cmd.addr*ratio + count),
            If(port_to.cmd.ready,
                NextValue(count, count + 1),
                If(count == (ratio - 1),
                    port_from.cmd.ready.eq(1),
                    NextState("IDLE")
                )
            )
        )

        if mode in ["write", "both"]:
            wdata_converter = stream.StrideConverter(
                description_from = port_from.wdata.description,
                description_to   = port_to.wdata.description,
                reverse          = reverse)
            self.submodules += wdata_converter
            self.submodules += stream.Pipeline(port_from.wdata, wdata_converter, port_to.wdata)

        if mode in ["read", "both"]:
            rdata_converter = stream.StrideConverter(
                description_from = port_to.rdata.description,
                description_to   = port_from.rdata.description,
                reverse          = reverse)
            self.submodules += rdata_converter
            self.submodules += stream.Pipeline(
                port_to.rdata, rdata_converter, port_from.rdata)
예제 #8
0
    def __init__(self, clock_domain="sys", phy_dw=16):
        self.sink   = stream.Endpoint([("data", phy_dw), ("ctrl", phy_dw//8)])
        self.source = stream.Endpoint([("data", 32), ("ctrl", 4)])

        # # #

        converter = stream.StrideConverter(
            [("data", phy_dw), ("ctrl", phy_dw//8)],
            [("data", 32), ("ctrl", 4)],
            reverse=False)
        converter = stream.BufferizeEndpoints({"sink":   stream.DIR_SINK})(converter)
        converter = ClockDomainsRenamer(clock_domain)(converter)
        self.submodules.converter = converter
        cdc = stream.AsyncFIFO([("data", 32), ("ctrl", 4)], 8, buffered=True)
        cdc = ClockDomainsRenamer({"write": clock_domain, "read": "sys"})(cdc)
        self.submodules.cdc = cdc
        skip_remover = RXSKPRemover()
        self.submodules.skip_remover = skip_remover
        word_aligner = RXWordAligner()
        word_aligner = stream.BufferizeEndpoints({"source": stream.DIR_SOURCE})(word_aligner)
        self.submodules.word_aligner = word_aligner
        self.comb += [
            self.sink.connect(converter.sink),
            converter.source.connect(cdc.sink),
            cdc.source.connect(skip_remover.sink),
            skip_remover.source.connect(word_aligner.sink),
            word_aligner.source.connect(self.source),
        ]
예제 #9
0
    def __init__(self, clock_domain="sys", phy_dw=16):
        self.sink = stream.Endpoint([("data", 32), ("ctrl", 4)])
        self.source = stream.Endpoint([("data", phy_dw),
                                       ("ctrl", phy_dw // 8)])

        # # #

        # Clock compensation
        skip_inserter = TXSKPInserter()
        self.submodules += skip_inserter

        # Clock domain crossing
        cdc = stream.AsyncFIFO([("data", 32), ("ctrl", 4)], 8, buffered=True)
        cdc = ClockDomainsRenamer({"write": "sys", "read": clock_domain})(cdc)
        self.submodules.cdc = cdc

        # Data-width adaptation
        converter = stream.StrideConverter([("data", 32), ("ctrl", 4)],
                                           [("data", phy_dw),
                                            ("ctrl", phy_dw // 8)],
                                           reverse=False)
        converter = stream.BufferizeEndpoints({"source":
                                               stream.DIR_SOURCE})(converter)
        converter = ClockDomainsRenamer(clock_domain)(converter)
        self.submodules.converter = converter

        # Flow
        self.comb += [
            self.sink.connect(skip_inserter.sink),
            skip_inserter.source.connect(cdc.sink),
            cdc.source.connect(converter.sink),
            converter.source.connect(self.source)
        ]
예제 #10
0
파일: core.py 프로젝트: matheos/daphne
    def __init__(self, phy, phy_cd):
        assert len(phy.source.data) in [16, 32]
        self.sink   =   sink = stream.Endpoint([("data", len(phy.source.data)), ("ctrl", len(phy.source.ctrl))])
        self.source = source = stream.Endpoint([("data", 32), ("ctrl", 4)])

        # # #

        use_ebuf = (len(phy.source.data) == 32)

        if use_ebuf:
            ebuf = ElasticBuffer(len(phy.source.data) + len(phy.source.ctrl), 4, phy_cd, "jesd")
            self.submodules.ebuf = ebuf
            self.comb += [
                sink.ready.eq(1),
                ebuf.din[:32].eq(sink.data),
                ebuf.din[32:].eq(sink.ctrl),
                source.valid.eq(1),
                source.data.eq(ebuf.dout[:32]),
                source.ctrl.eq(ebuf.dout[32:])
            ]
        else:
            converter = stream.StrideConverter(
                [("data", len(phy.source.data)), ("ctrl", len(phy.source.ctrl))],
                [("data", 32), ("ctrl", 4)],
                reverse=False)
            converter = ClockDomainsRenamer(phy_cd)(converter)
            self.submodules += converter
            cdc = stream.AsyncFIFO([("data", 32), ("ctrl", 4)], 4)
            cdc = ClockDomainsRenamer({"write": phy_cd, "read": "jesd"})(cdc)
            self.submodules += cdc
            self.comb += [
                sink.connect(converter.sink),
                converter.source.connect(cdc.sink),
                cdc.source.connect(source)
            ]
예제 #11
0
    def get_port(self, udp_port, dw=8, cd="sys"):
        if udp_port in self.users.keys():
            raise ValueError("Port {0:#x} already assigned".format(udp_port))

        user_port = LiteEthUDPUserPort(dw)
        internal_port = LiteEthUDPUserPort(8)

        # tx
        tx_stream = user_port.sink
        if cd is not "sys":
            tx_cdc = stream.AsyncFIFO(eth_udp_user_description(user_port.dw),
                                      4)
            tx_cdc = ClockDomainsRenamer({"write": cd, "read": "sys"})(tx_cdc)
            self.submodules += tx_cdc
            self.comb += tx_stream.connect(tx_cdc.sink)
            tx_stream = tx_cdc.source
        if dw != 8:
            tx_converter = stream.StrideConverter(
                eth_udp_user_description(user_port.dw),
                eth_udp_user_description(8))
            self.submodules += tx_converter
            self.comb += tx_stream.connect(tx_converter.sink)
            tx_stream = tx_converter.source
        self.comb += tx_stream.connect(internal_port.sink)

        # rx
        rx_stream = internal_port.source
        if dw != 8:
            rx_converter = stream.StrideConverter(
                eth_udp_user_description(8),
                eth_udp_user_description(user_port.dw))
            self.submodules += rx_converter
            self.comb += rx_stream.connect(rx_converter.sink)
            rx_stream = rx_converter.source
        if cd is not "sys":
            rx_cdc = stream.AsyncFIFO(eth_udp_user_description(user_port.dw),
                                      4)
            rx_cdc = ClockDomainsRenamer({"write": "sys", "read": cd})(rx_cdc)
            self.submodules += rx_cdc
            self.comb += rx_stream.connect(rx_cdc.sink)
            rx_stream = rx_cdc.source
        self.comb += rx_stream.connect(user_port.source)

        self.users[udp_port] = internal_port

        return user_port
예제 #12
0
    def __init__(self, port_from, port_to, reverse=False):
        assert port_from.clock_domain == port_to.clock_domain
        assert port_from.data_width < port_to.data_width
        assert port_from.mode == port_to.mode
        assert port_from.mode == "write"
        if port_to.data_width % port_from.data_width:
            raise ValueError("Ratio must be an int")

        # # #

        ratio = port_to.data_width // port_from.data_width

        we = Signal()
        address = Signal(port_to.address_width)

        counter = Signal(max=ratio)
        counter_reset = Signal()
        counter_ce = Signal()
        self.sync += \
            If(counter_reset,
                counter.eq(0)
            ).Elif(counter_ce,
                counter.eq(counter + 1)
            )

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE", port_from.cmd.ready.eq(1),
            If(port_from.cmd.valid, counter_ce.eq(1),
               NextValue(we, port_from.cmd.we),
               NextValue(address, port_from.cmd.addr), NextState("RECEIVE")))
        fsm.act(
            "RECEIVE", port_from.cmd.ready.eq(1),
            If(port_from.cmd.valid, counter_ce.eq(1),
               If(counter == ratio - 1, NextState("GENERATE"))))
        fsm.act("GENERATE", port_to.cmd.valid.eq(1), port_to.cmd.we.eq(we),
                port_to.cmd.addr.eq(address[log2_int(ratio):]),
                If(port_to.cmd.ready, NextState("IDLE")))

        wdata_converter = stream.StrideConverter(port_from.wdata.description,
                                                 port_to.wdata.description,
                                                 reverse=reverse)
        self.submodules += wdata_converter
        self.submodules += stream.Pipeline(port_from.wdata, wdata_converter,
                                           port_to.wdata)
예제 #13
0
파일: core.py 프로젝트: nondejus/litescope
    def __init__(self, dw, cd_ratio):
        self.sink = stream.Endpoint(core_layout(dw))
        self.source = stream.Endpoint(core_layout(dw * cd_ratio))

        # # #

        self.submodules.buffer = stream.Buffer(core_layout(dw))
        self.submodules.trigger = FrontendTrigger(dw)
        self.submodules.subsampler = FrontendSubSampler(dw)
        self.submodules.converter = stream.StrideConverter(
            core_layout(dw, 1), core_layout(dw * cd_ratio, cd_ratio))
        self.submodules.fifo = ClockDomainsRenamer({
            "write": "sys",
            "read": "new_sys"
        })(stream.AsyncFIFO(core_layout(dw * cd_ratio, cd_ratio), 8))
        self.submodules.pipeline = stream.Pipeline(self.sink, self.buffer,
                                                   self.trigger,
                                                   self.subsampler,
                                                   self.converter, self.fifo,
                                                   self.source)
예제 #14
0
    def __init__(self,
                 platform,
                 with_cpu=True,
                 with_sdram=True,
                 with_etherbone=True,
                 with_gtp=True,
                 gtp_connector="pcie",
                 gtp_refclk="pcie",
                 gtp_linerate=5e9,
                 with_gtp_bist=True,
                 with_gtp_freqmeter=True,
                 with_record=True):
        sys_clk_freq = int(100e6)

        # SoCSDRAM ---------------------------------------------------------------------------------
        SoCSDRAM.__init__(
            self,
            platform,
            sys_clk_freq,
            cpu_type="vexriscv" if with_cpu else None,
            csr_data_width=32,
            with_uart=with_cpu,
            uart_name="crossover",
            integrated_rom_size=0x8000 if with_cpu else 0x0000,
            integrated_main_ram_size=0x1000 if not with_sdram else 0x0000,
            ident="PCIe Analyzer LiteX SoC",
            ident_version=True)

        # CRG --------------------------------------------------------------------------------------
        self.submodules.crg = _CRG(platform, sys_clk_freq)

        # DDR3 SDRAM -------------------------------------------------------------------------------
        if not self.integrated_main_ram_size:
            self.submodules.ddrphy = s7ddrphy.A7DDRPHY(
                platform.request("ddram"),
                memtype="DDR3",
                nphases=4,
                sys_clk_freq=sys_clk_freq)
            self.add_csr("ddrphy")
            sdram_module = K4B2G1646F(sys_clk_freq, "1:4")
            self.register_sdram(self.ddrphy,
                                geom_settings=sdram_module.geom_settings,
                                timing_settings=sdram_module.timing_settings)

        # Etherbone --------------------------------------------------------------------------------
        if with_etherbone:
            # ethphy
            self.submodules.ethphy = LiteEthPHYRMII(
                clock_pads=self.platform.request("eth_clocks"),
                pads=self.platform.request("eth"))
            self.add_csr("ethphy")
            # ethcore
            self.submodules.ethcore = LiteEthUDPIPCore(
                phy=self.ethphy,
                mac_address=0x10e2d5000000,
                ip_address="192.168.1.50",
                clk_freq=self.clk_freq)
            # etherbone
            self.submodules.etherbone = LiteEthEtherbone(
                self.ethcore.udp, 1234)
            self.add_wb_master(self.etherbone.wishbone.bus)
            # timing constraints
            self.platform.add_period_constraint(self.ethphy.crg.cd_eth_rx.clk,
                                                1e9 / 50e6)
            self.platform.add_period_constraint(self.ethphy.crg.cd_eth_tx.clk,
                                                1e9 / 50e6)
            self.platform.add_false_path_constraints(
                self.crg.cd_sys.clk, self.ethphy.crg.cd_eth_rx.clk,
                self.ethphy.crg.cd_eth_tx.clk)

        # GTP RefClk -------------------------------------------------------------------------------
        if with_gtp:
            assert gtp_refclk in ["pcie", "internal"]
            if gtp_refclk == "pcie":
                refclk = Signal()
                refclk_freq = 100e6
                refclk_pads = platform.request("pcie_refclk")
                self.specials += Instance("IBUFDS_GTE2",
                                          i_CEB=0,
                                          i_I=refclk_pads.p,
                                          i_IB=refclk_pads.n,
                                          o_O=refclk)
            else:
                refclk = Signal()
                refclk_freq = 100e6
                self.comb += refclk.eq(ClockSignal("clk100"))
                platform.add_platform_command(
                    "set_property SEVERITY {{Warning}} [get_drc_checks REQP-49]"
                )

        # GTP PLL ----------------------------------------------------------------------------------
        if with_gtp:
            qpll = GTPQuadPLL(refclk, refclk_freq, gtp_linerate)
            print(qpll)
            self.submodules += qpll

        # GTPs -------------------------------------------------------------------------------------
        if with_gtp:
            for i in range(2):
                tx_pads = platform.request(gtp_connector + "_tx", i)
                rx_pads = platform.request(gtp_connector + "_rx", i)
                gtp = GTP(qpll,
                          tx_pads,
                          rx_pads,
                          sys_clk_freq,
                          data_width=20,
                          clock_aligner=False,
                          tx_buffer_enable=True,
                          rx_buffer_enable=True)
                gtp.add_stream_endpoints()
                setattr(self.submodules, "gtp" + str(i), gtp)
                platform.add_period_constraint(gtp.cd_tx.clk,
                                               1e9 / gtp.tx_clk_freq)
                platform.add_period_constraint(gtp.cd_rx.clk,
                                               1e9 / gtp.rx_clk_freq)
                self.platform.add_false_path_constraints(
                    self.crg.cd_sys.clk, gtp.cd_tx.clk, gtp.cd_rx.clk)

        # GTPs FreqMeters --------------------------------------------------------------------------
        if with_gtp_freqmeter:
            self.submodules.gtp0_tx_freq = FreqMeter(ClockSignal("gtp0_tx"))
            self.submodules.gtp0_rx_freq = FreqMeter(ClockSignal("gtp0_rx"))
            self.submodules.gtp1_tx_freq = FreqMeter(ClockSignal("gtp1_tx"))
            self.submodules.gtp1_rx_freq = FreqMeter(ClockSignal("gtp1_rx"))
            self.add_csr("gtp0_tx_freq")
            self.add_csr("gtp0_rx_freq")
            self.add_csr("gtp1_tx_freq")
            self.add_csr("gtp1_rx_freq")

        # GTPs BIST --------------------------------------------------------------------------------
        if with_gtp_bist:
            self.submodules.gtp0_tx_bist = GTPTXBIST(self.gtp0, "gtp0_tx")
            self.submodules.gtp0_rx_bist = GTPRXBIST(self.gtp0, "gtp0_rx")
            self.submodules.gtp1_tx_bist = GTPTXBIST(self.gtp1, "gtp1_tx")
            self.submodules.gtp1_rx_bist = GTPRXBIST(self.gtp1, "gtp1_rx")
            self.add_csr("gtp0_tx_bist")
            self.add_csr("gtp0_rx_bist")
            self.add_csr("gtp1_tx_bist")
            self.add_csr("gtp1_rx_bist")

        # Record -----------------------------------------------------------------------------------
        # FIXME: use better data/ctrl packing (or separate recorders)
        if with_record:
            # Convert RX stream from 16-bit@250MHz to 64-bit@sys_clk
            rx_converter = stream.StrideConverter([("data", 16), ("ctrl", 2)],
                                                  [("data", 96), ("ctrl", 12)],
                                                  reverse=False)
            rx_converter = ClockDomainsRenamer("gtp0_rx")(rx_converter)
            self.submodules.rx_converter = rx_converter
            rx_cdc = stream.AsyncFIFO([("data", 96), ("ctrl", 12)],
                                      8,
                                      buffered=True)
            rx_cdc = ClockDomainsRenamer({
                "write": "gtp0_rx",
                "read": "sys"
            })(rx_cdc)
            self.submodules.rx_cdc = rx_cdc
            # RX DMA Recorder
            self.submodules.rx_dma_recorder = LiteDRAMDMAWriter(
                self.sdram.crossbar.get_port("write", 128))
            self.rx_dma_recorder.add_csr()
            self.add_csr("rx_dma_recorder")
            self.comb += [
                gtp.source.connect(rx_converter.sink),
                rx_converter.source.connect(rx_cdc.sink),
                self.rx_dma_recorder.sink.valid.eq(rx_cdc.source.valid),
                self.rx_dma_recorder.sink.data[0:96].eq(rx_cdc.source.data),
                self.rx_dma_recorder.sink.data[96:108].eq(rx_cdc.source.ctrl),
            ]
예제 #15
0
    def __init__(self, phy):
        self.sink = stream.Endpoint([("data", 32)])
        self.source = stream.Endpoint([("data", 32)])

        self.argument = CSRStorage(32)
        self.command = CSRStorage(32)
        self.send = CSR()

        self.response = CSRStatus(128)

        self.cmdevt = CSRStatus(4)
        self.dataevt = CSRStatus(4)

        self.blocksize = CSRStorage(16)
        self.blockcount = CSRStorage(32)

        self.timeout = CSRStorage(32, reset=2**16)

        # # #

        argument = Signal(32)
        command = Signal(32)
        response = Signal(136)
        cmdevt = Signal(4)
        dataevt = Signal(4)
        blocksize = Signal(16)
        blockcount = Signal(32)
        timeout = Signal(32)

        # sys to sd cdc
        self.specials += [
            MultiReg(self.argument.storage, argument, "sd"),
            MultiReg(self.command.storage, command, "sd"),
            MultiReg(self.blocksize.storage, blocksize, "sd"),
            MultiReg(self.blockcount.storage, blockcount, "sd"),
            MultiReg(self.timeout.storage, timeout, "sd"),
        ]

        # sd to sys cdc
        response_cdc = BusSynchronizer(136, "sd", "sys")
        cmdevt_cdc = BusSynchronizer(4, "sd", "sys")
        dataevt_cdc = BusSynchronizer(4, "sd", "sys")
        self.submodules += response_cdc, cmdevt_cdc, dataevt_cdc
        self.comb += [
            response_cdc.i.eq(response),
            self.response.status.eq(response_cdc.o[:128]),
            cmdevt_cdc.i.eq(cmdevt),
            self.cmdevt.status.eq(cmdevt_cdc.o),
            dataevt_cdc.i.eq(dataevt),
            self.dataevt.status.eq(dataevt_cdc.o)
        ]

        self.submodules.new_command = PulseSynchronizer("sys", "sd")
        self.comb += self.new_command.i.eq(self.send.re)

        self.comb += phy.cfg.timeout.eq(timeout)
        self.comb += phy.cfg.blocksize.eq(blocksize)

        self.submodules.crc7_inserter = crc7_inserter = ClockDomainsRenamer(
            "sd")(CRC(9, 7, 40))
        self.submodules.crc16_inserter = crc16_inserter = ClockDomainsRenamer(
            "sd")(CRCUpstreamInserter())
        self.submodules.crc16_checker = crc16_checker = ClockDomainsRenamer(
            "sd")(CRCDownstreamChecker())

        self.submodules.upstream_cdc = ClockDomainsRenamer({
            "write": "sys",
            "read": "sd"
        })(stream.AsyncFIFO(self.sink.description, 4))
        self.submodules.downstream_cdc = ClockDomainsRenamer({
            "write": "sd",
            "read": "sys"
        })(stream.AsyncFIFO(self.source.description, 4))

        self.submodules.upstream_converter = ClockDomainsRenamer("sd")(
            stream.StrideConverter([('data', 32)], [('data', 8)],
                                   reverse=True))
        self.submodules.downstream_converter = ClockDomainsRenamer("sd")(
            stream.StrideConverter([('data', 8)], [('data', 32)],
                                   reverse=True))

        self.comb += [
            self.sink.connect(self.upstream_cdc.sink),
            self.upstream_cdc.source.connect(self.upstream_converter.sink),
            self.upstream_converter.source.connect(crc16_inserter.sink),
            crc16_checker.source.connect(self.downstream_converter.sink),
            self.downstream_converter.source.connect(self.downstream_cdc.sink),
            self.downstream_cdc.source.connect(self.source)
        ]

        cmd_type = Signal(2)
        cmd_count = Signal(3)
        cmd_done = Signal()
        cmd_error = Signal()
        cmd_timeout = Signal()

        data_type = Signal(2)
        data_count = Signal(32)
        data_done = Signal()
        data_error = Signal()
        data_timeout = Signal()

        self.comb += [
            cmd_type.eq(command[0:2]),
            data_type.eq(command[5:7]),
            cmdevt.eq(Cat(cmd_done, cmd_error, cmd_timeout,
                          0)),  # FIXME cmd response CRC.
            dataevt.eq(
                Cat(data_done, data_error, data_timeout,
                    ~crc16_checker.valid)),
            crc7_inserter.val.eq(Cat(argument, command[8:14], 1, 0)),
            crc7_inserter.clr.eq(1),
            crc7_inserter.enable.eq(1),
        ]

        self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM())
        fsm.act(
            "IDLE", NextValue(cmd_done, 1), NextValue(data_done, 1),
            NextValue(cmd_count, 0), NextValue(data_count, 0),
            If(self.new_command.o, NextValue(cmd_done, 0),
               NextValue(cmd_error, 0), NextValue(cmd_timeout, 0),
               NextValue(data_done, 0), NextValue(data_error, 0),
               NextValue(data_timeout, 0), NextState("CMD")))
        fsm.act(
            "CMD", phy.cmdw.sink.valid.eq(1),
            Case(
                cmd_count, {
                    0:
                    phy.cmdw.sink.data.eq(Cat(command[8:14], 1, 0)),
                    1:
                    phy.cmdw.sink.data.eq(argument[24:32]),
                    2:
                    phy.cmdw.sink.data.eq(argument[16:24]),
                    3:
                    phy.cmdw.sink.data.eq(argument[8:16]),
                    4:
                    phy.cmdw.sink.data.eq(argument[0:8]),
                    5: [
                        phy.cmdw.sink.data.eq(Cat(1, crc7_inserter.crc)),
                        phy.cmdw.sink.last.eq(
                            cmd_type == SDCARD_CTRL_RESPONSE_NONE)
                    ]
                }),
            If(
                phy.cmdw.sink.valid & phy.cmdw.sink.ready,
                NextValue(cmd_count, cmd_count + 1),
                If(
                    cmd_count == (6 - 1),
                    If(cmd_type == SDCARD_CTRL_RESPONSE_NONE,
                       NextValue(cmd_done, 1),
                       NextState("IDLE")).Else(NextState("CMD-RESPONSE")))))
        fsm.act(
            "CMD-RESPONSE",
            phy.cmdr.sink.valid.eq(1),
            phy.cmdr.sink.last.eq(data_type == SDCARD_CTRL_DATA_TRANSFER_NONE),
            If(
                cmd_type == SDCARD_CTRL_RESPONSE_LONG,
                phy.cmdr.sink.length.eq(17)  # 136bits
            ).Else(phy.cmdr.sink.length.eq(6)  # 48bits
                   ),
            If(
                phy.cmdr.source.valid, phy.cmdr.source.ready.eq(1),
                If(phy.cmdr.source.status == SDCARD_STREAM_STATUS_TIMEOUT,
                   NextValue(cmd_timeout, 1), NextState("IDLE")).Elif(
                       phy.cmdr.source.last,
                       If(data_type == SDCARD_CTRL_DATA_TRANSFER_WRITE,
                          NextState("DATA-WRITE")).Elif(
                              data_type == SDCARD_CTRL_DATA_TRANSFER_READ,
                              NextState("DATA-READ")).Else(NextState("IDLE")),
                   ).Else(
                       NextValue(response, Cat(phy.cmdr.source.data,
                                               response)))))
        fsm.act(
            "DATA-WRITE", crc16_inserter.source.connect(phy.dataw.sink),
            If(
                phy.dataw.sink.valid & phy.dataw.sink.last
                & phy.dataw.sink.ready, NextValue(data_count, data_count + 1),
                If(data_count == (blockcount - 1), NextState("IDLE"))),
            phy.datar.source.ready.eq(1),
            If(
                phy.datar.source.valid,
                If(
                    phy.datar.source.status
                    != SDCARD_STREAM_STATUS_DATAACCEPTED,
                    NextValue(data_error, 1))))
        fsm.act(
            "DATA-READ", phy.datar.sink.valid.eq(1),
            phy.datar.sink.last.eq(data_count == (blockcount - 1)),
            phy.datar.source.ready.eq(1),
            If(
                phy.datar.source.valid,
                If(
                    phy.datar.source.status == SDCARD_STREAM_STATUS_OK,
                    phy.datar.source.connect(crc16_checker.sink,
                                             omit={"status"}),
                    If(phy.datar.source.last & phy.datar.source.ready,
                       NextValue(data_count, data_count + 1),
                       If(data_count == (blockcount - 1),
                          NextState("IDLE")))).Elif(
                              phy.datar.source.status ==
                              SDCARD_STREAM_STATUS_TIMEOUT,
                              NextValue(data_timeout, 1),
                              NextValue(data_count,
                                        0), phy.datar.source.ready.eq(1),
                              NextState("IDLE"))))
예제 #16
0
파일: core.py 프로젝트: cr1901/litesdcard
    def __init__(self, phy):
        self.sink = stream.Endpoint([("data", 32)])
        self.source = stream.Endpoint([("data", 32)])

        self.argument = CSRStorage(32)
        self.command = CSRStorage(32)
        self.response = CSRStatus(120)

        self.cmdevt = CSRStatus(32)
        self.dataevt = CSRStatus(32)

        self.blocksize = CSRStorage(16)
        self.blockcount = CSRStorage(32)

        self.datatimeout = CSRStorage(32, reset=2**16)
        self.cmdtimeout = CSRStorage(32, reset=2**16)

        self.datawcrcclear = CSRStorage()
        self.datawcrcvalids = CSRStatus(32)
        self.datawcrcerrors = CSRStatus(32)

        # # #

        argument = Signal(32)
        command = Signal(32)
        response = Signal(120)
        cmdevt = Signal(32)
        dataevt = Signal(32)
        blocksize = Signal(16)
        blockcount = Signal(32)
        datatimeout = Signal(32)
        cmdtimeout = Signal(32)

        # sys to sd cdc
        self.specials += [
            MultiReg(self.argument.storage, argument, "sd"),
            MultiReg(self.command.storage, command, "sd"),
            MultiReg(self.blocksize.storage, blocksize, "sd"),
            MultiReg(self.blockcount.storage, blockcount, "sd"),
            MultiReg(self.datatimeout.storage, datatimeout, "sd"),
            MultiReg(self.cmdtimeout.storage, cmdtimeout, "sd")
        ]

        # sd to sys cdc
        response_cdc = BusSynchronizer(120, "sd", "sys")
        cmdevt_cdc = BusSynchronizer(32, "sd", "sys")
        dataevt_cdc = BusSynchronizer(32, "sd", "sys")
        self.submodules += response_cdc, cmdevt_cdc, dataevt_cdc
        self.comb += [
            response_cdc.i.eq(response),
            self.response.status.eq(response_cdc.o),
            cmdevt_cdc.i.eq(cmdevt),
            self.cmdevt.status.eq(cmdevt_cdc.o),
            dataevt_cdc.i.eq(dataevt),
            self.dataevt.status.eq(dataevt_cdc.o)
        ]

        self.submodules.new_command = PulseSynchronizer("sys", "sd")
        self.comb += self.new_command.i.eq(self.command.re)

        self.comb += [
            phy.cfg.blocksize.eq(blocksize),
            phy.cfg.datatimeout.eq(datatimeout),
            phy.cfg.cmdtimeout.eq(cmdtimeout),
            phy.dataw.crc_clear.eq(self.datawcrcclear.storage),
            self.datawcrcvalids.status.eq(phy.dataw.crc_valids),
            self.datawcrcerrors.status.eq(phy.dataw.crc_errors)
        ]

        self.submodules.crc7inserter = ClockDomainsRenamer("sd")(CRC(9, 7, 40))
        self.submodules.crc7checker = ClockDomainsRenamer("sd")(CRCChecker(
            9, 7, 120))
        self.submodules.crc16inserter = ClockDomainsRenamer("sd")(
            CRCUpstreamInserter())
        self.submodules.crc16checker = ClockDomainsRenamer("sd")(
            CRCDownstreamChecker())

        self.submodules.upstream_cdc = ClockDomainsRenamer({
            "write": "sys",
            "read": "sd"
        })(stream.AsyncFIFO(self.sink.description, 4))
        self.submodules.downstream_cdc = ClockDomainsRenamer({
            "write": "sd",
            "read": "sys"
        })(stream.AsyncFIFO(self.source.description, 4))

        self.submodules.upstream_converter = ClockDomainsRenamer("sd")(
            stream.StrideConverter([('data', 32)], [('data', 8)],
                                   reverse=True))
        self.submodules.downstream_converter = ClockDomainsRenamer("sd")(
            stream.StrideConverter([('data', 8)], [('data', 32)],
                                   reverse=True))

        self.comb += [
            self.sink.connect(self.upstream_cdc.sink),
            self.upstream_cdc.source.connect(self.upstream_converter.sink),
            self.upstream_converter.source.connect(self.crc16inserter.sink),
            self.crc16checker.source.connect(self.downstream_converter.sink),
            self.downstream_converter.source.connect(self.downstream_cdc.sink),
            self.downstream_cdc.source.connect(self.source)
        ]

        self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM())

        csel = Signal(max=6)
        waitresp = Signal(2)
        dataxfer = Signal(2)
        cmddone = Signal(reset=1)
        datadone = Signal(reset=1)
        blkcnt = Signal(32)
        pos = Signal(2)

        cerrtimeout = Signal()
        cerrcrc_en = Signal()
        derrtimeout = Signal()
        derrwrite = Signal()
        derrread_en = Signal()

        self.comb += [
            waitresp.eq(command[0:2]),
            dataxfer.eq(command[5:7]),
            cmdevt.eq(
                Cat(cmddone, C(0, 1), cerrtimeout,
                    cerrcrc_en & ~self.crc7checker.valid)),
            dataevt.eq(
                Cat(datadone, derrwrite, derrtimeout,
                    derrread_en & ~self.crc16checker.valid)),
            self.crc7inserter.val.eq(Cat(argument, command[8:14], 1, 0)),
            self.crc7inserter.clr.eq(1),
            self.crc7inserter.enable.eq(1),
            self.crc7checker.val.eq(response)
        ]

        ccases = {}  # To send command and CRC
        ccases[0] = phy.sink.data.eq(Cat(command[8:14], 1, 0))
        for i in range(4):
            ccases[i + 1] = phy.sink.data.eq(argument[24 - 8 * i:32 - 8 * i])
        ccases[5] = [
            phy.sink.data.eq(Cat(1, self.crc7inserter.crc)),
            phy.sink.last.eq(waitresp == SDCARD_CTRL_RESPONSE_NONE)
        ]

        fsm.act(
            "IDLE", NextValue(pos, 0),
            If(self.new_command.o, NextValue(cmddone, 0),
               NextValue(cerrtimeout, 0), NextValue(cerrcrc_en, 0),
               NextValue(datadone, 0), NextValue(derrtimeout, 0),
               NextValue(derrwrite, 0), NextValue(derrread_en, 0),
               NextValue(response, 0), NextState("SEND_CMD")))

        fsm.act(
            "SEND_CMD", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1),
            phy.sink.rd_wr_n.eq(0), Case(csel, ccases),
            If(
                phy.sink.valid & phy.sink.ready,
                If(csel < 5, NextValue(csel, csel + 1)).Else(
                    NextValue(csel, 0),
                    If(waitresp == SDCARD_CTRL_RESPONSE_NONE,
                       NextValue(cmddone, 1),
                       NextState("IDLE")).Else(NextValue(cerrcrc_en, 1),
                                               NextState("RECV_RESP")))))

        fsm.act(
            "RECV_RESP",
            phy.sink.valid.eq(1),
            phy.sink.cmd_data_n.eq(1),
            phy.sink.rd_wr_n.eq(1),
            phy.sink.last.eq(dataxfer == SDCARD_CTRL_DATA_TRANSFER_NONE),
            If(
                waitresp == SDCARD_CTRL_RESPONSE_SHORT,
                phy.sink.data.eq(5)  # (5+1)*8 == 48bits
            ).Elif(
                waitresp == SDCARD_CTRL_RESPONSE_LONG,
                phy.sink.data.eq(16)  # (16+1)*8 == 136bits
            ),
            If(
                phy.source.valid,  # Wait for resp or timeout coming from phy
                phy.source.ready.eq(1),
                If(phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT,
                   NextValue(cerrtimeout, 1), NextValue(cmddone, 1),
                   NextValue(datadone, 1), NextState("IDLE")).Elif(
                       phy.source.last,
                       # Check response CRC
                       NextValue(self.crc7checker.check, phy.source.data[1:8]),
                       NextValue(cmddone, 1),
                       If(dataxfer == SDCARD_CTRL_DATA_TRANSFER_READ,
                          NextValue(derrread_en, 1),
                          NextState("RECV_DATA")).Elif(
                              dataxfer == SDCARD_CTRL_DATA_TRANSFER_WRITE,
                              NextState("SEND_DATA")).Else(
                                  NextValue(datadone, 1), NextState("IDLE")),
                   ).Else(
                       NextValue(response, Cat(phy.source.data,
                                               response[0:112])))))

        fsm.act(
            "RECV_DATA",
            phy.sink.valid.eq(1),
            phy.sink.cmd_data_n.eq(0),
            phy.sink.rd_wr_n.eq(1),
            phy.sink.last.eq(blkcnt == (blockcount - 1)),
            phy.sink.data.eq(0),  # Read 1 block
            If(
                phy.source.valid,
                phy.source.ready.eq(1),
                If(
                    phy.source.status == SDCARD_STREAM_STATUS_OK,
                    self.crc16checker.sink.data.eq(
                        phy.source.data),  # Manual connect streams except ctrl
                    self.crc16checker.sink.valid.eq(phy.source.valid),
                    self.crc16checker.sink.last.eq(phy.source.last),
                    phy.source.ready.eq(self.crc16checker.sink.ready),
                    If(
                        phy.source.last & phy.source.ready,  # End of block
                        If(blkcnt < (blockcount - 1),
                           NextValue(blkcnt,
                                     blkcnt + 1), NextState("RECV_DATA")).Else(
                                         NextValue(blkcnt, 0),
                                         NextValue(datadone, 1),
                                         NextState("IDLE")))).Elif(
                                             phy.source.status ==
                                             SDCARD_STREAM_STATUS_TIMEOUT,
                                             NextValue(derrtimeout, 1),
                                             NextValue(blkcnt, 0),
                                             NextValue(datadone, 1),
                                             phy.source.ready.eq(1),
                                             NextState("IDLE"))))

        fsm.act(
            "SEND_DATA", phy.sink.valid.eq(self.crc16inserter.source.valid),
            phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(0),
            phy.sink.last.eq(self.crc16inserter.source.last),
            phy.sink.data.eq(self.crc16inserter.source.data),
            self.crc16inserter.source.ready.eq(phy.sink.ready),
            If(
                self.crc16inserter.source.valid
                & self.crc16inserter.source.last
                & self.crc16inserter.source.ready,
                If(blkcnt < (blockcount - 1),
                   NextValue(blkcnt, blkcnt + 1)).Else(NextValue(blkcnt, 0),
                                                       NextValue(datadone, 1),
                                                       NextState("IDLE"))),
            If(
                phy.source.valid, phy.source.ready.eq(1),
                If(phy.source.status != SDCARD_STREAM_STATUS_DATAACCEPTED,
                   NextValue(derrwrite, 1))))
예제 #17
0
    def __init__(self, port_from, port_to, reverse=False):
        assert port_from.clock_domain == port_to.clock_domain
        assert port_from.data_width < port_to.data_width
        assert port_from.mode == port_to.mode
        if port_to.data_width % port_from.data_width:
            raise ValueError("Ratio must be an int")

        # # #

        ratio = port_to.data_width // port_from.data_width
        mode = port_from.mode

        # Command ----------------------------------------------------------------------------------

        # Defines cmd type and the chunks that have been requested for the current port_to command.
        sel = Signal(ratio)
        cmd_buffer = stream.SyncFIFO([("sel", ratio), ("we", 1)], 0)
        self.submodules += cmd_buffer
        # Store last received command.
        cmd_addr = Signal.like(port_from.cmd.addr)
        cmd_we = Signal()
        cmd_last = Signal()
        # Indicates that we need to proceed to the next port_to command.
        next_cmd = Signal()
        addr_changed = Signal()
        # Signals that indicate that write/read convertion has finished.
        wdata_finished = Signal()
        rdata_finished = Signal()
        # Used to prevent reading old memory value if previous command has written the same address.
        read_lock = Signal()
        read_unlocked = Signal()
        rw_collision = Signal()

        # Different order depending on read/write:
        # - read:  new -> cmd -> fill -> commit -> new
        # - write: new -> fill -> commit -> cmd -> new
        # For writes we have to send the command at the end to prevent situations when, during
        # a burst, LiteDRAM expects data (wdata_ready=1) but write converter is still converting.
        self.submodules.fsm = fsm = FSM()
        fsm.act(
            "NEW", port_from.cmd.ready.eq(port_from.cmd.valid & ~read_lock),
            If(
                port_from.cmd.ready, NextValue(cmd_addr, port_from.cmd.addr),
                NextValue(cmd_we, port_from.cmd.we),
                NextValue(cmd_last, port_from.cmd.last),
                NextValue(sel, 1 << port_from.cmd.addr[:log2_int(ratio)]),
                If(
                    port_from.cmd.we,
                    NextState("FILL"),
                ).Else(NextState("CMD"), )))
        fsm.act(
            "CMD", port_to.cmd.valid.eq(1), port_to.cmd.we.eq(cmd_we),
            port_to.cmd.addr.eq(cmd_addr[log2_int(ratio):]),
            If(port_to.cmd.ready,
               If(cmd_we, NextState("NEW")).Else(NextState("FILL"))))
        fsm.act(
            "FILL",
            If(next_cmd, NextState("COMMIT")).
            Else(  # Acknowledge incomming commands, while filling `sel`.
                port_from.cmd.ready.eq(port_from.cmd.valid),
                NextValue(cmd_last, port_from.cmd.last),
                If(
                    port_from.cmd.valid,
                    NextValue(sel, sel
                              | 1 << port_from.cmd.addr[:log2_int(ratio)]))))
        fsm.act(
            "COMMIT", cmd_buffer.sink.valid.eq(1), cmd_buffer.sink.sel.eq(sel),
            cmd_buffer.sink.we.eq(cmd_we),
            If(cmd_buffer.sink.ready,
               If(cmd_we, NextState("CMD")).Else(NextState("NEW"))))

        self.comb += [
            cmd_buffer.source.ready.eq(wdata_finished | rdata_finished),
            addr_changed.eq(cmd_addr[log2_int(ratio):] !=
                            port_from.cmd.addr[log2_int(ratio):]),
            # Collision happens on write to read transition when address does not change.
            rw_collision.eq(cmd_we & (port_from.cmd.valid & ~port_from.cmd.we)
                            & ~addr_changed),
            # Go to the next command if one of the following happens:
            #  - port_to address changes.
            #  - cmd type changes.
            #  - we received all the `ratio` commands.
            #  - this is the last command in a sequence.
            #  - master requests a flush (even after the command has been sent).
            next_cmd.eq(addr_changed | (cmd_we != port_from.cmd.we)
                        | (sel == 2**ratio - 1)
                        | cmd_last | port_from.flush),
        ]

        self.sync += [
            # Block sending read command if we have just written to that address
            If(
                wdata_finished,
                read_lock.eq(0),
                read_unlocked.eq(1),
            ).Elif(rw_collision & ~port_to.cmd.valid & ~read_unlocked,
                   read_lock.eq(1)),
            If(port_from.cmd.valid & port_from.cmd.ready, read_unlocked.eq(0))
        ]

        # Read Datapath ----------------------------------------------------------------------------

        if mode in ["read", "both"]:
            # Queue received data not to loose it when it comes too fast.
            rdata_fifo = stream.SyncFIFO(port_to.rdata.description, ratio - 1)
            rdata_converter = stream.StrideConverter(
                description_from=port_to.rdata.description,
                description_to=port_from.rdata.description,
                reverse=reverse)
            self.submodules += rdata_fifo, rdata_converter

            # Shift register with a bitmask of current chunk.
            rdata_chunk = Signal(ratio, reset=1)
            rdata_chunk_valid = Signal()
            self.sync += \
                If(rdata_converter.source.valid &
                   rdata_converter.source.ready,
                    rdata_chunk.eq(Cat(rdata_chunk[ratio-1], rdata_chunk[:ratio-1]))
                )

            self.comb += [
                # port_to -> rdata_fifo -> rdata_converter -> port_from
                port_to.rdata.connect(rdata_fifo.sink),
                rdata_fifo.source.connect(rdata_converter.sink),
                rdata_chunk_valid.eq(
                    (cmd_buffer.source.sel & rdata_chunk) != 0),
                If(
                    cmd_buffer.source.valid & ~cmd_buffer.source.we,
                    # If that chunk is valid we send it to the user port and wait for ready.
                    If(rdata_chunk_valid,
                       port_from.rdata.valid.eq(rdata_converter.source.valid),
                       port_from.rdata.data.eq(rdata_converter.source.data),
                       rdata_converter.source.ready.eq(port_from.rdata.ready)).
                    Else(  # If this chunk was not requested in `sel`, ignore it.
                        rdata_converter.source.ready.eq(1)),
                    rdata_finished.eq(rdata_converter.source.valid
                                      & rdata_converter.source.ready
                                      & rdata_chunk[ratio - 1])),
            ]

        # Write Datapath ---------------------------------------------------------------------------

        if mode in ["write", "both"]:
            # Queue write data not to miss it when the lower chunks haven't been reqested.
            wdata_fifo = stream.SyncFIFO(port_from.wdata.description,
                                         ratio - 1)
            wdata_buffer = stream.SyncFIFO(port_to.wdata.description, 1)
            wdata_converter = stream.StrideConverter(
                description_from=port_from.wdata.description,
                description_to=port_to.wdata.description,
                reverse=reverse)
            self.submodules += wdata_converter, wdata_fifo, wdata_buffer

            # Shift register with a bitmask of current chunk.
            wdata_chunk = Signal(ratio, reset=1)
            wdata_chunk_valid = Signal()
            self.sync += \
                If(wdata_converter.sink.valid & wdata_converter.sink.ready,
                    wdata_chunk.eq(Cat(wdata_chunk[ratio-1], wdata_chunk[:ratio-1]))
                )

            # Replicate `sel` bits to match the width of port_to.wdata.we.
            wdata_sel = Signal.like(port_to.wdata.we)
            if reverse:
                wdata_sel_parts = [
                    Replicate(cmd_buffer.source.sel[i],
                              port_to.wdata.we.nbits // sel.nbits)
                    for i in reversed(range(ratio))
                ]
            else:
                wdata_sel_parts = [
                    Replicate(cmd_buffer.source.sel[i],
                              port_to.wdata.we.nbits // sel.nbits)
                    for i in range(ratio)
                ]

            self.sync += \
                If(cmd_buffer.source.valid & cmd_buffer.source.we & wdata_chunk[ratio - 1],
                    wdata_sel.eq(Cat(wdata_sel_parts))
                )

            self.comb += [
                # port_from -> wdata_fifo -> wdata_converter
                port_from.wdata.connect(wdata_fifo.sink),
                wdata_buffer.source.connect(port_to.wdata),
                wdata_chunk_valid.eq(
                    (cmd_buffer.source.sel & wdata_chunk) != 0),
                If(
                    cmd_buffer.source.valid & cmd_buffer.source.we,
                    # When the current chunk is valid, read it from wdata_fifo.
                    If(
                        wdata_chunk_valid,
                        wdata_converter.sink.valid.eq(wdata_fifo.source.valid),
                        wdata_converter.sink.data.eq(wdata_fifo.source.data),
                        wdata_converter.sink.we.eq(wdata_fifo.source.we),
                        wdata_fifo.source.ready.eq(wdata_converter.sink.ready),
                    ).
                    Else(  # If chunk is not valid, send any data and do not advance fifo.
                        wdata_converter.sink.valid.eq(1), ),
                ),
                wdata_buffer.sink.valid.eq(wdata_converter.source.valid),
                wdata_buffer.sink.data.eq(wdata_converter.source.data),
                wdata_buffer.sink.we.eq(wdata_converter.source.we & wdata_sel),
                wdata_converter.source.ready.eq(wdata_buffer.sink.ready),
                wdata_finished.eq(wdata_converter.sink.valid
                                  & wdata_converter.sink.ready
                                  & wdata_chunk[ratio - 1]),
            ]
예제 #18
0
    def __init__(self,
                 layout,
                 depth,
                 base,
                 crossbar,
                 read_threshold=None,
                 write_threshold=None,
                 preserve_first_last=True):

        self.sink = sink = stream.Endpoint(layout)
        self.source = source = stream.Endpoint(layout)

        # # #

        # preserve first and last fields
        if preserve_first_last:
            self.submodules.pack = _FLPack(layout)
            self.submodules.unpack = _FLUnpack(layout)

            self.comb += [
                sink.connect(self.pack.sink),
                self.unpack.source.connect(source),
            ]

            fifo_in = self.pack.source
            fifo_out = self.unpack.sink
        else:
            fifo_in = sink
            fifo_out = source

        native_width = crossbar.controller.data_width
        dw = len(fifo_in.payload)
        if dw <= native_width:
            if native_width % dw:
                raise ValueError("Ratio must be an int")
            ctrl_ratio = native_width // dw
            ctrl_depth = ((depth - 1) // ctrl_ratio) + 1
            fifo_depth = ctrl_ratio
        else:
            raise NotImplementedError("Only upconverter support for now")

        # use native controller width
        read_port = crossbar.get_port(mode="read")
        write_port = crossbar.get_port(mode="write")

        if read_threshold is None:
            read_threshold = 0
        if write_threshold is None:
            write_threshold = ctrl_depth

        # ctrl counts blocks in native width
        self.submodules.ctrl = _LiteDRAMFIFOCtrl(base, ctrl_depth,
                                                 read_threshold,
                                                 write_threshold)
        self.submodules.writer = _LiteDRAMFIFOWriter(write_port, self.ctrl)
        self.submodules.reader = _LiteDRAMFIFOReader(read_port, self.ctrl)

        # router chooses bypass or dram
        self.submodules.router = _LiteDRAMFIFORouter(dw, fifo_depth, self.ctrl)
        self.submodules.conv_w = stream.StrideConverter(
            fifo_in.description, self.writer.sink.description)
        self.submodules.conv_r = stream.StrideConverter(
            self.reader.source.description, fifo_out.description)

        self.comb += [
            # bypass
            fifo_in.connect(self.router.sink0),
            self.router.source0.connect(fifo_out),

            # dram
            self.router.source1.connect(self.conv_w.sink),
            self.conv_w.source.connect(self.writer.sink),
            self.reader.source.connect(self.conv_r.sink),
            self.conv_r.source.connect(self.router.sink1),
        ]
예제 #19
0
    def __init__(self, port_from, port_to, reverse=False):
        assert port_from.clock_domain == port_to.clock_domain
        assert port_from.data_width < port_to.data_width
        assert port_from.mode == port_to.mode
        assert port_from.mode == "read"
        if port_to.data_width % port_from.data_width:
            raise ValueError("Ratio must be an int")

        # # #

        ratio = port_to.data_width//port_from.data_width


        # cmd

        cmd_buffer = stream.SyncFIFO([("sel", ratio)], 4)
        self.submodules += cmd_buffer

        counter = Signal(max=ratio)
        counter_ce = Signal()
        self.sync += \
            If(counter_ce,
                counter.eq(counter + 1)
            )

        self.comb += \
            If(port_from.cmd.valid,
                If(counter == 0,
                    port_to.cmd.valid.eq(1),
                    port_to.cmd.addr.eq(port_from.cmd.addr[log2_int(ratio):]),
                    port_from.cmd.ready.eq(port_to.cmd.ready),
                    counter_ce.eq(port_to.cmd.ready)
                ).Else(
                    port_from.cmd.ready.eq(1),
                    counter_ce.eq(1)
                )
            )

        # TODO: fix sel
        self.comb += \
            If(port_to.cmd.valid & port_to.cmd.ready,
                cmd_buffer.sink.valid.eq(1),
                cmd_buffer.sink.sel.eq(2**ratio-1)
            )

        # datapath

        rdata_buffer  = stream.Buffer(port_to.rdata.description)
        rdata_converter = stream.StrideConverter(
            port_to.rdata.description,
            port_from.rdata.description,
            reverse=reverse)
        self.submodules +=  rdata_buffer, rdata_converter

        rdata_chunk = Signal(ratio, reset=1)
        rdata_chunk_valid = Signal()
        self.sync += \
            If(rdata_converter.source.valid &
               rdata_converter.source.ready,
                rdata_chunk.eq(Cat(rdata_chunk[ratio-1], rdata_chunk[:ratio-1]))
            )

        self.comb += [
            port_to.rdata.connect(rdata_buffer.sink),
            rdata_buffer.source.connect(rdata_converter.sink),
            rdata_chunk_valid.eq((cmd_buffer.source.sel & rdata_chunk) != 0),
            If(port_from.flush,
                rdata_converter.source.ready.eq(1)
            ).Elif(cmd_buffer.source.valid,
                If(rdata_chunk_valid,
                    port_from.rdata.valid.eq(rdata_converter.source.valid),
                    port_from.rdata.data.eq(rdata_converter.source.data),
                    rdata_converter.source.ready.eq(port_from.rdata.ready)
                ).Else(
                    rdata_converter.source.ready.eq(1)
                )
            ),
            cmd_buffer.source.ready.eq(
                rdata_converter.source.ready & rdata_chunk[ratio-1])
        ]