예제 #1
0
    def __init__(self,
                 cmd=False,
                 data=False,
                 data_width=1,
                 skip_start_bit=False):
        assert cmd or data
        self.pads_in = pads_in = stream.Endpoint(_sdpads_layout)
        self.source = source = stream.Endpoint([("data", 8)])

        # # #

        pads_in_data = pads_in.cmd.i[:
                                     data_width] if cmd else pads_in.data.i[:
                                                                            data_width]
        print(len(pads_in_data))

        # Xfer starts when data == 0
        start = Signal()
        run = Signal()
        self.comb += start.eq(pads_in_data == 0)
        self.sync += If(pads_in.valid & pads_in.ready, run.eq(start | run))

        # Convert data to 8-bit stream
        converter = stream.Converter(data_width, 8, reverse=True)
        buf = stream.Buffer([("data", 8)])
        self.submodules += converter, buf
        self.comb += [
            converter.sink.valid.eq(pads_in.valid
                                    & (run if skip_start_bit else (start
                                                                   | run))),
            converter.sink.data.eq(pads_in_data),
            pads_in.ready.eq(converter.sink.ready),
            converter.source.connect(buf.sink),
            buf.source.connect(source)
        ]
예제 #2
0
파일: axi.py 프로젝트: yxist/litedram
    def __init__(self, axi, port, buffer_depth):
        self.cmd_request = Signal()
        self.cmd_grant = Signal()

        # # #

        ashift = log2_int(port.data_width // 8)

        # Burst to Beat
        aw_buffer = stream.Buffer(
            ax_description(axi.address_width, axi.id_width))
        self.submodules += aw_buffer
        self.comb += axi.aw.connect(aw_buffer.sink)
        aw = stream.Endpoint(ax_description(axi.address_width, axi.id_width))
        aw_burst2beat = AXIBurst2Beat(aw_buffer.source, aw)
        self.submodules.aw_burst2beat = aw_burst2beat

        # Write Buffer
        w_buffer = stream.SyncFIFO(w_description(axi.data_width, axi.id_width),
                                   buffer_depth,
                                   buffered=True)
        self.submodules.w_buffer = w_buffer

        # Write ID Buffer & Response
        id_buffer = stream.SyncFIFO([("id", axi.id_width)], buffer_depth)
        resp_buffer = stream.SyncFIFO([("id", axi.id_width), ("resp", 2)],
                                      buffer_depth)
        self.submodules += id_buffer, resp_buffer
        self.comb += [
            id_buffer.sink.valid.eq(aw.valid & aw.first & aw.ready),
            id_buffer.sink.id.eq(aw.id),
            If(
                w_buffer.source.valid & w_buffer.source.last
                & w_buffer.source.ready, resp_buffer.sink.valid.eq(1),
                resp_buffer.sink.resp.eq(RESP_OKAY),
                resp_buffer.sink.id.eq(id_buffer.source.id),
                id_buffer.source.ready.eq(1)),
            resp_buffer.source.connect(axi.b)
        ]

        # Command
        # Accept and send command to the controller only if:
        # - Address & Data request are *both* valid.
        # - Data buffer is not full.
        self.comb += [
            self.cmd_request.eq(aw.valid & axi.w.valid & w_buffer.sink.ready),
            If(
                self.cmd_request & self.cmd_grant, port.cmd.valid.eq(1),
                port.cmd.we.eq(1), port.cmd.addr.eq(aw.addr >> ashift),
                aw.ready.eq(port.cmd.ready),
                axi.w.connect(w_buffer.sink, omit={"valid", "ready"}),
                If(port.cmd.ready, w_buffer.sink.valid.eq(1),
                   axi.w.ready.eq(1)))
        ]

        # Write Data
        self.comb += [
            w_buffer.source.connect(port.wdata, omit={"strb", "id"}),
            port.wdata.we.eq(w_buffer.source.strb)
        ]
예제 #3
0
    def __init__(self, axi, port, buffer_depth):
        self.cmd_request = Signal()
        self.cmd_grant = Signal()

        # # #

        ashift = log2_int(port.data_width // 8)

        # Burst to Beat
        aw_buffer = stream.Buffer(
            ax_description(axi.address_width, axi.id_width))
        self.comb += axi.aw.connect(aw_buffer.sink)
        aw = stream.Endpoint(ax_description(axi.address_width, axi.id_width))
        aw_burst2beat = LiteDRAMAXIBurst2Beat(aw_buffer.source, aw)
        self.submodules += aw_buffer, aw_burst2beat

        # Write Buffer
        w_buffer = stream.SyncFIFO(w_description(axi.data_width), buffer_depth)
        self.submodules += w_buffer

        # Write ID Buffer & Response
        id_buffer = stream.SyncFIFO([("id", axi.id_width)], buffer_depth)
        resp_buffer = stream.SyncFIFO([("id", axi.id_width), ("resp", 2)],
                                      buffer_depth)
        self.submodules += id_buffer, resp_buffer
        self.comb += [
            id_buffer.sink.valid.eq(aw.valid & aw.first & aw.ready),
            id_buffer.sink.id.eq(aw.id),
            If(
                w_buffer.source.valid & w_buffer.source.last
                & w_buffer.source.ready, resp_buffer.sink.valid.eq(1),
                resp_buffer.sink.resp.eq(resp_types["okay"]),
                resp_buffer.sink.id.eq(id_buffer.source.id),
                id_buffer.source.ready.eq(1)),
            resp_buffer.source.connect(axi.b)
        ]

        # Command
        self.comb += [
            # Emits the command only if we have the data
            If(
                w_buffer.source.valid, self.cmd_request.eq(aw.valid),
                If(self.cmd_grant, port.cmd.valid.eq(aw.valid),
                   aw.ready.eq(port.cmd.ready), port.cmd.we.eq(1),
                   port.cmd.addr.eq(aw.addr >> ashift)))
        ]

        # Write Data
        self.comb += [
            axi.w.connect(w_buffer.sink),
            If(id_buffer.source.valid,
               w_buffer.source.connect(port.wdata, omit={"strb"}),
               port.wdata.we.eq(w_buffer.source.strb))
        ]
예제 #4
0
    def __init__(self, check_ctrl_only=False):
        self.enable = Signal(reset=1)
        self.sink = sink = stream.Endpoint([("data", 32), ("ctrl", 4)])
        self.source = source = stream.Endpoint([("data", 32), ("ctrl", 4)])

        # # #

        alignment = Signal(2)
        alignment_d = Signal(2)

        buf = stream.Buffer([("data", 32), ("ctrl", 4)])
        self.submodules += buf
        self.comb += [
            sink.connect(buf.sink),
            source.valid.eq(sink.valid & buf.source.valid),
            buf.source.ready.eq(sink.valid & source.ready),
        ]

        # Alignment detection
        for i in reversed(range(4)):
            self.comb += [
                If(
                    sink.valid & sink.ready,
                    If(
                        sink.ctrl[i] & (check_ctrl_only |
                                        (sink.data[8 * i:8 *
                                                   (i + 1)] == COM.value)),
                        alignment.eq(i)))
            ]
        self.sync += [
            If(
                sink.valid & sink.ready,
                If(
                    self.enable,
                    If(
                        (sink.ctrl != 0) & (buf.source.ctrl == 0),
                        alignment_d.eq(alignment),
                    ))),
        ]

        # Data selection
        data = Cat(buf.source.data, sink.data)
        ctrl = Cat(buf.source.ctrl, sink.ctrl)
        cases = {}
        for i in range(4):
            cases[i] = [
                source.data.eq(data[8 * i:]),
                source.ctrl.eq(ctrl[i:]),
            ]
        self.comb += Case(alignment_d, cases)
예제 #5
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)
예제 #6
0
파일: axi.py 프로젝트: xroumegue/litex
    def __init__(self, axi, axi_lite):
        assert axi.data_width == axi_lite.data_width
        assert axi.address_width == axi_lite.address_width

        ax_buffer = stream.Buffer(
            ax_description(axi.address_width, axi.id_width))
        ax_burst = stream.Endpoint(
            ax_description(axi.address_width, axi.id_width))
        ax_beat = stream.Endpoint(
            ax_description(axi.address_width, axi.id_width))
        self.comb += ax_burst.connect(ax_buffer.sink)
        ax_burst2beat = AXIBurst2Beat(ax_buffer.source, ax_beat)
        self.submodules += ax_buffer, ax_burst2beat

        _data = Signal(axi.data_width)
        _cmd_done = Signal()
        _last_ar_aw_n = Signal()

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE",
            NextValue(_cmd_done, 0),
            If(
                axi.ar.valid & axi.aw.valid,
                # If last access was a read, do a write
                If(_last_ar_aw_n, axi.aw.connect(ax_burst),
                   NextValue(_last_ar_aw_n, 0),
                   NextState("WRITE")
                   # If last access was a write, do a read
                   ).Else(
                       axi.ar.connect(ax_burst),
                       NextValue(_last_ar_aw_n, 1),
                       NextState("READ"),
                   )).Elif(
                       axi.ar.valid,
                       axi.ar.connect(ax_burst),
                       NextValue(_last_ar_aw_n, 1),
                       NextState("READ"),
                   ).Elif(axi.aw.valid, axi.aw.connect(ax_burst),
                          NextValue(_last_ar_aw_n, 0), NextState("WRITE")))
        fsm.act(
            "READ",
            # cmd
            axi_lite.ar.valid.eq(ax_beat.valid & ~_cmd_done),
            axi_lite.ar.addr.eq(ax_beat.addr),
            ax_beat.ready.eq(axi_lite.ar.ready & ~_cmd_done),
            If(
                ax_beat.valid & ax_beat.last,
                If(axi_lite.ar.ready, ax_beat.ready.eq(0),
                   NextValue(_cmd_done, 1))),
            # data
            axi.r.valid.eq(axi_lite.r.valid),
            axi.r.last.eq(_cmd_done),
            axi.r.resp.eq(RESP_OKAY),
            axi.r.id.eq(ax_beat.id),
            axi.r.data.eq(axi_lite.r.data),
            axi_lite.r.ready.eq(axi.r.ready),
            # exit
            If(axi.r.valid & axi.r.last & axi.r.ready, ax_beat.ready.eq(1),
               NextState("IDLE")))
        # always accept write responses
        self.comb += axi_lite.b.ready.eq(1)
        fsm.act(
            "WRITE",
            # cmd
            axi_lite.aw.valid.eq(ax_beat.valid & ~_cmd_done),
            axi_lite.aw.addr.eq(ax_beat.addr),
            ax_beat.ready.eq(axi_lite.aw.ready & ~_cmd_done),
            If(
                ax_beat.valid & ax_beat.last,
                If(axi_lite.aw.ready, ax_beat.ready.eq(0),
                   NextValue(_cmd_done, 1))),
            # data
            axi_lite.w.valid.eq(axi.w.valid),
            axi_lite.w.data.eq(axi.w.data),
            axi_lite.w.strb.eq(axi.w.strb),
            axi.w.ready.eq(axi_lite.w.ready),
            # exit
            If(axi.w.valid & axi.w.last & axi.w.ready,
               NextState("WRITE-RESP")))
        fsm.act("WRITE-RESP", axi.b.valid.eq(1), axi.b.resp.eq(RESP_OKAY),
                axi.b.id.eq(ax_beat.id),
                If(axi.b.ready, ax_beat.ready.eq(1), NextState("IDLE")))
예제 #7
0
    def __init__(self, clock_domain, mem_size=128):

        # *********************************************************
        # *                    Interface                          *
        # *********************************************************
        self.armed     = CSRStorage()    # Trigger is armed
        self.trigged   = CSRStatus()     # Pattern found
        self.size      = CSRStorage(8)   # Pattern size - 1

        self.enable   = Signal()
        self.trigExt  = Signal()

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

        # *********************************************************
        # *                      Signals                          *
        # *********************************************************
        matches  = Signal(8)
        addr     = Signal(log2_int(mem_size))
        trig     = Signal()

        _armed   = Signal()
        _trigged = Signal()
        _size    = Signal(8)

        # *********************************************************
        # *                         CDC                           *
        # *********************************************************
        self.specials += MultiReg(self.armed.storage, _armed, clock_domain)
        self.specials += MultiReg(_trigged, self.trigged.status, "sys")
        self.specials += MultiReg(self.size.storage, _size, clock_domain)

        # *********************************************************
        # *                     Specials                          *
        # *********************************************************
        self.specials.mem = Memory(20, mem_size)
        self.specials.rdport = self.mem.get_port(write_capable=False, async_read=True, clock_domain=clock_domain)

        # *********************************************************
        # *                     Submodules                        *
        # *********************************************************
        buf0 = stream.Buffer(trigger_layout)
        buf1 = stream.Buffer(trigger_layout)
        self.submodules += ClockDomainsRenamer(clock_domain)(buf0)
        self.submodules += ClockDomainsRenamer(clock_domain)(buf1)

        # *********************************************************
        # *                    Combinatorial                      *
        # *********************************************************
        self.comb += [
            sink.connect(buf0.sink),
            buf0.source.connect(buf1.sink),
            buf1.source.connect(source, omit={"trig"}),
            sink.ready.eq(source.ready),
            self.rdport.adr.eq(addr),
            source.trig.eq(buf1.source.trig | trig),
            self.trigExt.eq(trig),
        ]

        # *********************************************************
        # *                        FSM                            *
        # *********************************************************
        fsm = ResetInserter()(FSM(reset_state="IDLE"))
        self.submodules.fsm = ClockDomainsRenamer(clock_domain)(fsm)

        fsm.act("IDLE",
            If(_armed & self.enable,
                NextValue(addr, 0),
                NextValue(matches, 0),
                NextState("FIRST")
            ),
        )

        fsm.act("FIRST",
            # If we search "bc1c" we are in this situation: bc1c 1c1c xxxx
            If((((self.rdport.dat_r[UPPER_BYTE] == buf0.source.data[UPPER_BYTE])  | self.rdport.dat_r[UPPER_DONT_CARE]) &
               ((self.rdport.dat_r[LOWER_BYTE]  == buf0.source.data[LOWER_BYTE])  | self.rdport.dat_r[LOWER_DONT_CARE]) &
               ((self.rdport.dat_r[UPPER_K]     == buf0.source.ctrl[CTRL_UPPER_K])| self.rdport.dat_r[UPPER_DONT_CARE]) &
               ((self.rdport.dat_r[LOWER_K]     == buf0.source.ctrl[CTRL_LOWER_K])| self.rdport.dat_r[LOWER_DONT_CARE]) &
                ~buf0.source.time & buf0.source.valid),
                # Full word match
                NextValue(matches, matches + 1),
                NextValue(addr, addr + 1),
                NextState("ALIGNED_CHECK")
            ).Else(
                # If we search "bc1c" we are in this situation: xxbc 1c1c 1cxx
                If((((self.rdport.dat_r[UPPER_BYTE] == buf0.source.data[LOWER_BYTE])  | self.rdport.dat_r[UPPER_DONT_CARE]) &
                    ((self.rdport.dat_r[LOWER_BYTE] == sink.data[UPPER_BYTE])         | self.rdport.dat_r[LOWER_DONT_CARE]) &
                    ((self.rdport.dat_r[UPPER_K]    == buf0.source.ctrl[CTRL_LOWER_K])| self.rdport.dat_r[UPPER_DONT_CARE]) &
                    ((self.rdport.dat_r[LOWER_K]    == sink.ctrl[CTRL_UPPER_K])       | self.rdport.dat_r[UPPER_DONT_CARE]) &
                     ~buf0.source.time & ~sink.time & buf0.source.valid & sink.valid),
                        # Half word match
                        NextValue(matches, matches + 1),
                        NextValue(addr, addr + 1),
                        NextState("UNALIGNED_CHECK")
                )
            ),
            If(~self.enable,
                NextState("IDLE")
            )
        )

        fsm.act("ALIGNED_CHECK",
            If(matches == _size,
                NextState("DONE"),
                NextValue(_trigged, 1),
                trig.eq(1),
            ).Else(
                If((((self.rdport.dat_r[UPPER_BYTE] == buf0.source.data[UPPER_BYTE])  | self.rdport.dat_r[UPPER_DONT_CARE]) &
                   ((self.rdport.dat_r[LOWER_BYTE]  == buf0.source.data[LOWER_BYTE])  | self.rdport.dat_r[LOWER_DONT_CARE]) &
                   ((self.rdport.dat_r[UPPER_K]     == buf0.source.ctrl[CTRL_UPPER_K])| self.rdport.dat_r[UPPER_DONT_CARE]) &
                   ((self.rdport.dat_r[LOWER_K]     == buf0.source.ctrl[CTRL_LOWER_K])| self.rdport.dat_r[LOWER_DONT_CARE]) &
                    ~buf0.source.time & buf0.source.valid),
                    NextValue(matches, matches + 1),
                    NextValue(addr, addr + 1),
                    NextState("ALIGNED_CHECK")
                ).Else(
                    NextValue(matches, 0),
                    NextValue(addr, 0),
                    NextState("FIRST")
                )
            ),
            If(~self.enable,
                NextState("IDLE")
            )
        )

        fsm.act("UNALIGNED_CHECK",
            If(matches == _size,
                NextState("DONE"),
                NextValue(_trigged, 1),
                trig.eq(1),
            ).Else(
                If((((self.rdport.dat_r[UPPER_BYTE] == buf0.source.data[LOWER_BYTE])  | self.rdport.dat_r[UPPER_DONT_CARE]) &
                    ((self.rdport.dat_r[LOWER_BYTE] == sink.data[UPPER_BYTE])         | self.rdport.dat_r[LOWER_DONT_CARE]) &
                    ((self.rdport.dat_r[UPPER_K]    == buf0.source.ctrl[CTRL_LOWER_K])| self.rdport.dat_r[UPPER_DONT_CARE]) &
                    ((self.rdport.dat_r[LOWER_K]    == sink.ctrl[CTRL_UPPER_K])       | self.rdport.dat_r[UPPER_DONT_CARE]) &
                     ~buf0.source.time & ~sink.time & buf0.source.valid & sink.valid),
                        # Half word match
                        NextValue(matches, matches + 1),
                        NextValue(addr, addr + 1),
                        NextState("UNALIGNED_CHECK")
                ).Else(
                        NextValue(matches, 0),
                        NextValue(addr, 0),
                        NextState("FIRST")
                )
            ),
            If(~self.enable,
                NextState("IDLE")
            )
        )

        fsm.act("DONE",
            If(_armed == 0,
                NextState("IDLE"),
                NextValue(_trigged, 0),
            ),
            If(~self.enable,
                NextState("IDLE")
            )
        )
예제 #8
0
    def __init__(self, n, address_width, address_align, nranks, settings):
        self.req = req = Record(cmd_layout(address_width))
        self.refresh_req = refresh_req = Signal()
        self.refresh_gnt = refresh_gnt = Signal()

        a  = settings.geom.addressbits
        ba = settings.geom.bankbits + log2_int(nranks)
        self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba))

        # # #

        auto_precharge = Signal()

        # Command buffer ---------------------------------------------------------------------------
        cmd_buffer_layout    = [("we", 1), ("addr", len(req.addr))]
        cmd_buffer_lookahead = stream.SyncFIFO(
            cmd_buffer_layout, settings.cmd_buffer_depth,
            buffered=settings.cmd_buffer_buffered)
        cmd_buffer = stream.Buffer(cmd_buffer_layout) # 1 depth buffer to detect row change
        self.submodules += cmd_buffer_lookahead, cmd_buffer
        self.comb += [
            req.connect(cmd_buffer_lookahead.sink, keep={"valid", "ready", "we", "addr"}),
            cmd_buffer_lookahead.source.connect(cmd_buffer.sink),
            cmd_buffer.source.ready.eq(req.wdata_ready | req.rdata_valid),
            req.lock.eq(cmd_buffer_lookahead.source.valid | cmd_buffer.source.valid),
        ]

        slicer = _AddressSlicer(settings.geom.colbits, address_align)

        # Row tracking -----------------------------------------------------------------------------
        row        = Signal(settings.geom.rowbits)
        row_opened = Signal()
        row_hit    = Signal()
        row_open   = Signal()
        row_close  = Signal()
        self.comb += row_hit.eq(row == slicer.row(cmd_buffer.source.addr))
        self.sync += \
            If(row_close,
                row_opened.eq(0)
            ).Elif(row_open,
                row_opened.eq(1),
                row.eq(slicer.row(cmd_buffer.source.addr))
            )

        # Address generation -----------------------------------------------------------------------
        row_col_n_addr_sel = Signal()
        self.comb += [
            cmd.ba.eq(n),
            If(row_col_n_addr_sel,
                cmd.a.eq(slicer.row(cmd_buffer.source.addr))
            ).Else(
                cmd.a.eq((auto_precharge << 10) | slicer.col(cmd_buffer.source.addr))
            )
        ]

        # tWTP (write-to-precharge) controller -----------------------------------------------------
        write_latency = math.ceil(settings.phy.cwl / settings.phy.nphases)
        precharge_time = write_latency + settings.timing.tWR + settings.timing.tCCD # AL=0
        self.submodules.twtpcon = twtpcon = tXXDController(precharge_time)
        self.comb += twtpcon.valid.eq(cmd.valid & cmd.ready & cmd.is_write)

        # tRC (activate-activate) controller -------------------------------------------------------
        self.submodules.trccon = trccon = tXXDController(settings.timing.tRC)
        self.comb += trccon.valid.eq(cmd.valid & cmd.ready & row_open)

        # tRAS (activate-precharge) controller -----------------------------------------------------
        self.submodules.trascon = trascon = tXXDController(settings.timing.tRAS)
        self.comb += trascon.valid.eq(cmd.valid & cmd.ready & row_open)

        # Auto Precharge generation ----------------------------------------------------------------
        if settings.with_auto_precharge:
            self.comb += \
                If(cmd_buffer_lookahead.source.valid & cmd_buffer.source.valid,
                    If(slicer.row(cmd_buffer_lookahead.source.addr) !=
                       slicer.row(cmd_buffer.source.addr),
                        auto_precharge.eq(row_close == 0)
                    )
                )

        # Control and command generation FSM -------------------------------------------------------
        # Note: tRRD, tFAW, tCCD, tWTR timings are enforced by the multiplexer
        self.submodules.fsm = fsm = FSM()
        fsm.act("REGULAR",
            If(refresh_req,
                NextState("REFRESH")
            ).Elif(cmd_buffer.source.valid,
                If(row_opened,
                    If(row_hit,
                        cmd.valid.eq(1),
                        If(cmd_buffer.source.we,
                            req.wdata_ready.eq(cmd.ready),
                            cmd.is_write.eq(1),
                            cmd.we.eq(1),
                        ).Else(
                            req.rdata_valid.eq(cmd.ready),
                            cmd.is_read.eq(1)
                        ),
                        cmd.cas.eq(1),
                        If(cmd.ready & auto_precharge,
                           NextState("AUTOPRECHARGE")
                        )
                    ).Else(
                        NextState("PRECHARGE")
                    )
                ).Else(
                    NextState("ACTIVATE")
                )
            )
        )
        fsm.act("PRECHARGE",
            # Note: we are presenting the column address, A10 is always low
            If(twtpcon.ready & trascon.ready,
                cmd.valid.eq(1),
                If(cmd.ready,
                    NextState("TRP")
                ),
                cmd.ras.eq(1),
                cmd.we.eq(1),
                cmd.is_cmd.eq(1)
            ),
            row_close.eq(1)
        )
        fsm.act("AUTOPRECHARGE",
            If(twtpcon.ready & trascon.ready,
                NextState("TRP")
            ),
            row_close.eq(1)
        )
        fsm.act("ACTIVATE",
            If(trccon.ready,
                row_col_n_addr_sel.eq(1),
                row_open.eq(1),
                cmd.valid.eq(1),
                cmd.is_cmd.eq(1),
                If(cmd.ready,
                    NextState("TRCD")
                ),
                cmd.ras.eq(1)
            )
        )
        fsm.act("REFRESH",
            If(twtpcon.ready,
                refresh_gnt.eq(1),
            ),
            row_close.eq(1),
            cmd.is_cmd.eq(1),
            If(~refresh_req,
                NextState("REGULAR")
            )
        )
        fsm.delayed_enter("TRP", "ACTIVATE", settings.timing.tRP - 1)
        fsm.delayed_enter("TRCD", "REGULAR", settings.timing.tRCD - 1)
예제 #9
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])
        ]
예제 #10
0
파일: video.py 프로젝트: fjullien/litex
    def __init__(self, hres=800, vres=600, with_csi_interpreter=True):
        self.enable    = Signal(reset=1)
        self.vtg_sink  = vtg_sink   = stream.Endpoint(video_timing_layout)
        self.uart_sink = uart_sink  = stream.Endpoint([("data", 8)])
        self.source    = source     = stream.Endpoint(video_data_layout)

        # # #

        csi_width = 8 if with_csi_interpreter else 0

        # Font Mem.
        # ---------
        os.system("wget https://github.com/enjoy-digital/litex/files/6076336/ter-u16b.txt") # FIXME: Store Font in LiteX?
        os.system("mv ter-u16b.txt ter-u16b.bdf")
        font        = import_bdf_font("ter-u16b.bdf")
        font_width  = 8
        font_heigth = 16
        font_mem    = Memory(width=8, depth=4096, init=font)
        font_rdport = font_mem.get_port(has_re=True)
        self.specials += font_mem, font_rdport

        # Terminal Mem.
        # -------------
        term_colums = 128 # 80 rounded to next power of two.
        term_lines  = math.floor(vres/font_heigth)
        term_depth  = term_colums * term_lines
        term_init   = [ord(c) for c in [" "]*term_colums*term_lines]
        term_mem    = Memory(width=font_width + csi_width, depth=term_depth, init=term_init)
        term_wrport = term_mem.get_port(write_capable=True)
        term_rdport = term_mem.get_port(has_re=True)
        self.specials += term_mem, term_wrport, term_rdport

        # UART Terminal Fill.
        # -------------------

        # Optional CSI Interpreter.
        if with_csi_interpreter:
            self.submodules.csi_interpreter = CSIInterpreter()
            self.comb += uart_sink.connect(self.csi_interpreter.sink)
            uart_sink = self.csi_interpreter.source
            self.comb += term_wrport.dat_w[font_width:].eq(self.csi_interpreter.color)

        self.submodules.uart_fifo = stream.SyncFIFO([("data", 8)], 8)
        self.comb += uart_sink.connect(self.uart_fifo.sink)
        uart_sink = self.uart_fifo.source

        # UART Reception and Terminal Fill.
        x_term = term_wrport.adr[:7]
        y_term = term_wrport.adr[7:]
        y_term_rollover = Signal()
        self.submodules.uart_fsm = uart_fsm = FSM(reset_state="RESET")
        uart_fsm.act("RESET",
            NextValue(x_term, 0),
            NextValue(y_term, 0),
            NextState("CLEAR-XY")
        )
        uart_fsm.act("CLEAR-XY",
            term_wrport.we.eq(1),
            term_wrport.dat_w[:font_width].eq(ord(" ")),
            NextValue(x_term, x_term + 1),
            If(x_term == (term_colums - 1),
                NextValue(x_term, 0),
                NextValue(y_term, y_term + 1),
                If(y_term == (term_lines - 1),
                    NextValue(y_term, 0),
                    NextState("IDLE")
                )
            )
        )
        uart_fsm.act("IDLE",
            If(uart_sink.valid,
                If(uart_sink.data == ord("\n"),
                    uart_sink.ready.eq(1), # Ack sink.
                    NextState("INCR-Y")
                ).Elif(uart_sink.data == ord("\r"),
                    uart_sink.ready.eq(1), # Ack sink.
                    NextState("RST-X")
                ).Else(
                    NextState("WRITE")
                )
            )
        )
        uart_fsm.act("WRITE",
            uart_sink.ready.eq(1),
            term_wrport.we.eq(1),
            term_wrport.dat_w[:font_width].eq(uart_sink.data),
            NextState("INCR-X")
        )
        uart_fsm.act("RST-X",
            NextValue(x_term, 0),
            NextState("CLEAR-X")
        )
        uart_fsm.act("INCR-X",
            NextValue(x_term, x_term + 1),
            NextState("IDLE"),
            If(x_term == (80 - 1),
                NextValue(x_term, 0),
                NextState("INCR-Y")
            )
        )
        uart_fsm.act("RST-Y",
            NextValue(y_term, 0),
            NextState("CLEAR-X")
        )
        uart_fsm.act("INCR-Y",
            NextValue(y_term, y_term + 1),
            NextState("CLEAR-X"),
            If(y_term == (term_lines - 1),
                NextValue(y_term_rollover, 1),
                NextState("RST-Y")
            )
        )
        uart_fsm.act("CLEAR-X",
            NextValue(x_term, x_term + 1),
            term_wrport.we.eq(1),
            term_wrport.dat_w[:font_width].eq(ord(" ")),
            If(x_term == (term_colums - 1),
                NextValue(x_term, 0),
                NextState("IDLE")
            )
        )

        # Video Generation.
        # -----------------
        ce = (vtg_sink.valid & vtg_sink.ready)

        # Timing delay line.
        latency     = 2
        timing_bufs = [stream.Buffer(video_timing_layout) for i in range(latency)]
        self.comb += vtg_sink.connect(timing_bufs[0].sink)
        for i in range(len(timing_bufs) - 1):
            self.comb += timing_bufs[i].source.connect(timing_bufs[i+1].sink)
        self.comb += timing_bufs[-1].source.connect(source, keep={"valid", "ready", "last", "de", "hsync", "vsync"})
        self.submodules += timing_bufs

        # Compute X/Y position.
        x = vtg_sink.hcount[int(math.log2(font_width)):]
        y = vtg_sink.vcount[int(math.log2(font_heigth)):]
        y_rollover = Signal(8)
        self.comb += [
            If(~y_term_rollover,
                y_rollover.eq(y)
            ).Else(
                # FIXME: Use Modulo.
                If((y + y_term + 1) >= term_lines,
                    y_rollover.eq(y + y_term + 1 - term_lines)
                ).Else(
                    y_rollover.eq(y + y_term + 1)
                ),
            )
        ]

        # Get character from Terminal Mem.
        term_dat_r = Signal(font_width)
        self.comb += term_rdport.re.eq(ce)
        self.comb += term_rdport.adr.eq(x + y_rollover*term_colums)
        self.comb += [
            term_dat_r.eq(term_rdport.dat_r[:font_width]),
            If((x >= 80) | (y >= term_lines),
                term_dat_r.eq(ord(" ")), # Out of range, generate space.
            )
        ]

        # Translate character to video data through Font Mem.
        self.comb += font_rdport.re.eq(ce)
        self.comb += font_rdport.adr.eq(term_dat_r*font_heigth + timing_bufs[0].source.vcount[:4])
        bit = Signal()
        cases = {}
        for i in range(font_width):
            cases[i] = [bit.eq(font_rdport.dat_r[font_width-1-i])]
        self.comb += Case(timing_bufs[1].source.hcount[:int(math.log2(font_width))], cases)
        # FIXME: Add Palette.
        self.comb += [
            If(bit,
                Case(term_rdport.dat_r[font_width:], {
                    0: [Cat(source.r, source.g, source.b).eq(0xffffff)],
                    1: [Cat(source.r, source.g, source.b).eq(0x34e289)],
                })
            ).Else(
                Cat(source.r, source.g, source.b).eq(0x000000),
            )
        ]
예제 #11
0
파일: axi.py 프로젝트: yxist/litedram
    def __init__(self, axi, port, buffer_depth):
        self.cmd_request = Signal()
        self.cmd_grant = Signal()

        # # #

        can_read = Signal()

        ashift = log2_int(port.data_width // 8)

        # Burst to Beat
        ar_buffer = stream.Buffer(
            ax_description(axi.address_width, axi.id_width))
        self.submodules += ar_buffer
        self.comb += axi.ar.connect(ar_buffer.sink)
        ar = stream.Endpoint(ax_description(axi.address_width, axi.id_width))
        ar_burst2beat = AXIBurst2Beat(ar_buffer.source, ar)
        self.submodules.ar_burst2beat = ar_burst2beat

        # Read buffer
        r_buffer = stream.SyncFIFO(r_description(axi.data_width, axi.id_width),
                                   buffer_depth,
                                   buffered=True)
        self.submodules.r_buffer = r_buffer

        # Read Buffer reservation
        # - Incremented when data is planned to be queued
        # - Decremented when data is dequeued
        r_buffer_queue = Signal()
        r_buffer_dequeue = Signal()
        r_buffer_level = Signal(max=buffer_depth + 1)
        self.comb += [
            r_buffer_queue.eq(port.cmd.valid & port.cmd.ready & ~port.cmd.we),
            r_buffer_dequeue.eq(r_buffer.source.valid & r_buffer.source.ready)
        ]
        self.sync += [
            If(r_buffer_queue,
               If(~r_buffer_dequeue,
                  r_buffer_level.eq(r_buffer_level + 1))).Elif(
                      r_buffer_dequeue, r_buffer_level.eq(r_buffer_level - 1))
        ]
        self.comb += can_read.eq(r_buffer_level != buffer_depth)

        # Read ID Buffer
        id_buffer = stream.SyncFIFO([("id", axi.id_width)], buffer_depth)
        self.submodules += id_buffer
        self.comb += [
            id_buffer.sink.valid.eq(ar.valid & ar.ready),
            id_buffer.sink.last.eq(ar.last),
            id_buffer.sink.id.eq(ar.id),
            axi.r.last.eq(id_buffer.source.last),
            axi.r.id.eq(id_buffer.source.id),
            id_buffer.source.ready.eq(axi.r.valid & axi.r.ready)
        ]

        # Command
        self.comb += [
            self.cmd_request.eq(ar.valid & can_read),
            If(self.cmd_grant, port.cmd.valid.eq(ar.valid & can_read),
               ar.ready.eq(port.cmd.ready & can_read), port.cmd.we.eq(0),
               port.cmd.addr.eq(ar.addr >> ashift))
        ]

        # Read data
        self.comb += [
            port.rdata.connect(r_buffer.sink, omit={"bank"}),
            r_buffer.source.connect(axi.r, omit={"id", "last"}),
            axi.r.resp.eq(RESP_OKAY)
        ]
    def __init__(self, cfg):
        self.pads = pads = _sdpads()
        self.sink = sink = stream.Endpoint([("data", 8)])
        self.source = source = stream.Endpoint([("data", 8), ("status", 3)])

        # # #

        datarfb_reset = Signal()

        self.submodules.datarfb = SDPHYRFB(pads.data.i, True)
        self.submodules.cdc = ClockDomainsRenamer({"write": "sd_fb", "read": "sd"})(
            stream.AsyncFIFO(self.datarfb.source.description, 4)
        )
        self.submodules.buffer = ClockDomainsRenamer("sd")(stream.Buffer(self.datarfb.source.description))
        self.comb += self.datarfb.source.connect(self.buffer.sink)

        dtimeout = Signal(32)

        read = Signal(10)
        toread = Signal(10)
        cnt = Signal(8)

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

        fsm.act("IDLE",
            pads.data.oe.eq(0),
            pads.clk.eq(1),
            datarfb_reset.eq(1),
            self.buffer.source.ready.eq(1),
            If(sink.valid,
                NextValue(dtimeout, 0),
                NextValue(read, 0),
                # Read 1 block + 8*8 == 64 bits CRC
                NextValue(toread, cfg.blocksize + 8),
                NextState("DATA_READSTART")
            )
        )

        self.specials += MultiReg(datarfb_reset, self.datarfb.reset, "sd_fb")

        fsm.act("DATA_READSTART",
            pads.data.oe.eq(0),
            pads.clk.eq(1),
            NextValue(dtimeout, dtimeout + 1),
            If(self.buffer.source.valid,
                NextState("DATA_READ")
            ).Elif(dtimeout > cfg.datatimeout,
                NextState("TIMEOUT")
            )
        )

        fsm.act("DATA_READ",
            pads.data.oe.eq(0),
            pads.clk.eq(1),
            source.valid.eq(self.buffer.source.valid),
            source.data.eq(self.buffer.source.data),
            source.status.eq(SDCARD_STREAM_STATUS_OK),
            source.last.eq(read == (toread - 1)),
            self.buffer.source.ready.eq(source.ready),
            If(source.valid & source.ready,
                NextValue(read, read + 1),
                If(read == (toread - 1),
                    If(sink.last,
                        NextState("DATA_CLK40")
                    ).Else(
                        sink.ready.eq(1),
                        NextState("DATA_FLUSH")
                    )
                )
            )
        )

        fsm.act("DATA_FLUSH",
            pads.data.oe.eq(0),
            datarfb_reset.eq(1),
            self.buffer.source.ready.eq(1),
            If(cnt < 5,
                NextValue(cnt, cnt + 1),
            ).Else(
                NextValue(cnt, 0),
                NextState("IDLE")
            )
        )

        fsm.act("DATA_CLK40",
            pads.data.oe.eq(1),
            pads.data.o.eq(0xf),
            If(cnt < 40,
                NextValue(cnt, cnt + 1),
                pads.clk.eq(1)
            ).Else(
                NextValue(cnt, 0),
                sink.ready.eq(1),
                NextState("IDLE")
            )
        )

        fsm.act("TIMEOUT",
            source.valid.eq(1),
            source.data.eq(0),
            source.status.eq(SDCARD_STREAM_STATUS_TIMEOUT),
            source.last.eq(1),
            If(source.valid & source.ready,
                sink.ready.eq(1),
                NextState("IDLE")
            )
        )
예제 #13
0
    def __init__(self, n, aw, address_align, settings):
        self.req = req = Record(cmd_layout(aw))
        self.refresh_req = Signal()
        self.refresh_gnt = Signal()
        a = settings.geom.addressbits
        ba = settings.geom.bankbits
        self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba))

        # # #

        # Command buffer
        cmd_buffer_layout = [("we", 1), ("adr", len(req.adr))]
        if settings.cmd_buffer_depth < 2:
            cmd_buffer = stream.Buffer(cmd_buffer_layout)
        else:
            cmd_buffer = stream.SyncFIFO(cmd_buffer_layout,
                                         settings.cmd_buffer_depth)
        self.submodules += cmd_buffer
        self.comb += [
            req.connect(cmd_buffer.sink,
                        omit=[
                            "wdata_valid", "wdata_ready", "rdata_valid",
                            "rdata_ready", "lock"
                        ]),
            cmd_buffer.source.ready.eq(req.wdata_ready | req.rdata_valid),
            req.lock.eq(cmd_buffer.source.valid),
        ]

        slicer = _AddressSlicer(settings.geom.colbits, address_align)

        # Row tracking
        has_openrow = Signal()
        openrow = Signal(settings.geom.rowbits, reset_less=True)
        hit = Signal()
        self.comb += hit.eq(openrow == slicer.row(cmd_buffer.source.adr))
        track_open = Signal()
        track_close = Signal()
        self.sync += \
            If(track_close,
                has_openrow.eq(0)
            ).Elif(track_open,
                has_openrow.eq(1),
                openrow.eq(slicer.row(cmd_buffer.source.adr))
            )

        # Address generation
        sel_row_adr = Signal()
        self.comb += [
            cmd.ba.eq(n),
            If(sel_row_adr, cmd.a.eq(slicer.row(cmd_buffer.source.adr))).Else(
                cmd.a.eq(slicer.col(cmd_buffer.source.adr)))
        ]

        # Respect write-to-precharge specification
        precharge_time = 2 + settings.timing.tWR - 1 + 1
        self.submodules.precharge_timer = WaitTimer(precharge_time)
        self.comb += self.precharge_timer.wait.eq(~(cmd.valid & cmd.ready
                                                    & cmd.is_write))

        # Control and command generation FSM
        self.submodules.fsm = fsm = FSM()
        fsm.act(
            "REGULAR",
            If(self.refresh_req, NextState("REFRESH")).Elif(
                cmd_buffer.source.valid,
                If(
                    has_openrow,
                    If(
                        hit,
                        # Note: write-to-read specification is enforced by
                        # multiplexer
                        cmd.valid.eq(1),
                        If(
                            cmd_buffer.source.we,
                            req.wdata_ready.eq(cmd.ready),
                            cmd.is_write.eq(1),
                            cmd.we.eq(1),
                        ).Else(req.rdata_valid.eq(cmd.ready),
                               cmd.is_read.eq(1)),
                        cmd.cas.eq(1)).Else(NextState("PRECHARGE"))).Else(
                            NextState("ACTIVATE"))))
        fsm.act(
            "PRECHARGE",
            # Note: we are presenting the column address, A10 is always low
            If(self.precharge_timer.done, cmd.valid.eq(1),
               If(cmd.ready, NextState("TRP")), cmd.ras.eq(1), cmd.we.eq(1),
               cmd.is_cmd.eq(1)),
            track_close.eq(1))
        fsm.act("ACTIVATE", sel_row_adr.eq(1), track_open.eq(1),
                cmd.valid.eq(1), cmd.is_cmd.eq(1),
                If(cmd.ready, NextState("TRCD")), cmd.ras.eq(1))
        fsm.act("REFRESH",
                If(
                    self.precharge_timer.done,
                    self.refresh_gnt.eq(1),
                ), track_close.eq(1), cmd.is_cmd.eq(1),
                If(~self.refresh_req, NextState("REGULAR")))
        fsm.delayed_enter("TRP", "ACTIVATE", settings.timing.tRP - 1)
        fsm.delayed_enter("TRCD", "REGULAR", settings.timing.tRCD - 1)
예제 #14
0
    def __init__(self, clock_domain, fifo_size):

        # *********************************************************
        # *                    Interface                          *
        # *********************************************************
        self.filterEnable      = CSRStorage()
        self.filterConfig      = CSRStorage(32)  # Filter configuration
        self.tlpDllpTimeoutCnt = CSRStorage(32)  # Payload size used for error detection

        self.ts           = Signal(32)      # Global time stamp
        self.trigExt      = Signal()        # Insert a trigger flag

        self.source       = source = stream.Endpoint(trigger_layout)
        self.sink         = sink   = stream.Endpoint(descrambler_layout)

        # *********************************************************
        # *                      Signals                          *
        # *********************************************************
        _ts           = Signal(32)
        _filterConfig = Signal(32)
        _tlpDllpTimeoutCnt  = Signal(32)

        _filterEnable = Signal()
        _trigExt      = Signal()

        trigPending   = Signal()
        clearTrig     = Signal()
        enabledDatas  = Signal()

        self.trigPending = trigPending
        self._trigExt = _trigExt
        self.clearTrig = clearTrig

        skipEnabled  = Signal()
        ftsEnabled   = Signal()
        tlpEnabled   = Signal()
        dllpEnabled  = Signal()
        ts1Enabled   = Signal()
        ts2Enabled   = Signal()
        idleEnabled  = Signal()

        count        = Signal(8)
        insert_ts    = Signal()
        state_after  = Signal(4)
        last_ts      = Signal(32)
        payload_cnt  = Signal(32)
        from_error   = Signal()
        ts_trig      = Signal()

        # *********************************************************
        # *                         CDC                           *
        # *********************************************************
        self.specials += MultiReg(self.ts, _ts, clock_domain)
        self.specials += MultiReg(self.filterConfig.storage, _filterConfig, clock_domain)
        self.specials += MultiReg(self.filterEnable.storage, _filterEnable, clock_domain)
        self.specials += MultiReg(self.tlpDllpTimeoutCnt.storage, _tlpDllpTimeoutCnt, clock_domain)
        self.specials += MultiReg(self.trigExt, _trigExt, clock_domain)

        # *********************************************************
        # *                     Submodules                        *
        # *********************************************************
        fifo = ResetInserter()(stream.SyncFIFO(filter_fifo_layout, fifo_size))
        self.submodules.fifo   = ClockDomainsRenamer(clock_domain)(fifo)

        buf_in = stream.Buffer(descrambler_layout)
        self.submodules += ClockDomainsRenamer(clock_domain)(buf_in)

        buf_out = stream.Buffer(filter_fifo_layout)
        self.submodules += ClockDomainsRenamer(clock_domain)(buf_out)

        # *********************************************************
        # *                    Combinatorial                      *
        # *********************************************************
        self.comb += [
            sink.connect(buf_in.sink),
            buf_in.source.connect(fifo.sink, omit={"valid", "ts", "error"}),
            self.sink.ready.eq(1),

            fifo.source.connect(buf_out.sink),

            skipEnabled.eq(_filterConfig[0]),
            ftsEnabled.eq( _filterConfig[1]),
            tlpEnabled.eq( _filterConfig[2]),
            dllpEnabled.eq(_filterConfig[3]),
            ts1Enabled.eq( _filterConfig[4]),
            ts2Enabled.eq( _filterConfig[5]),
            idleEnabled.eq( _filterConfig[6]),
        ]

        sync = getattr(self.sync, clock_domain)
        sync += [
            If(_trigExt, trigPending.eq(1)),
            If(clearTrig, trigPending.eq(0))
        ]

        # *********************************************************
        # *                        FSM                            *
        # *********************************************************
        fsmWriter = FSM(reset_state="NO_FILTER")
        self.submodules.fsmWriter = ClockDomainsRenamer(clock_domain)(fsmWriter)

        fsmReader = FSM(reset_state="NO_FILTER")
        self.submodules.fsmReader = ClockDomainsRenamer(clock_domain)(fsmReader)

        # *********************************************************
        # *                  Filter control                       *
        # *********************************************************
        fsmWriter.act("NO_FILTER",
            NextValue(fifo.sink.valid, 0),
            NextValue(buf_out.source.ready, 0),
            If(_filterEnable,
                self.fifo.reset.eq(1),
                NextState("FIND_DELIMITER"),
            )
        )

# ********************************************************************
# * Writing side of the FIFO.                                        *
# * All frames are written to the FIFO, software IDLE are removed.   *
# * A timestamp is added to each symbol to keep track of the timing. *
# ********************************************************************

        # *********************************************************
        # *               Detect frames delimiter                 *
        # *********************************************************
        fsmWriter.act("FIND_DELIMITER",
            NextValue(fifo.sink.valid, 0),
            NextValue(fifo.sink.error, 0),

            # Ordered sets
            If(sink.osets & (sink.data[8:16] == COM.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(fifo.sink.ts, _ts),
                NextState("ORDERED_SETS"),
            ),

            # TLP
            If((sink.ctrl == 0b10) & (sink.data[8:16] == STP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(fifo.sink.ts, _ts),
                NextValue(payload_cnt, 0),
                NextState("TLP"),
            ),

            # DLLP
            If((sink.ctrl == 0b10) & (sink.data[8:16] == SDP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(fifo.sink.ts, _ts),
                NextValue(payload_cnt, 0),
                NextState("DLLP"),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *             An ordered set is detected                *
        # *********************************************************
        fsmWriter.act("ORDERED_SETS",
            NextValue(fifo.sink.ts, _ts),
            NextValue(fifo.sink.error, 0),

            # We are done
            If(sink.osets == 0,
                NextValue(fifo.sink.valid, 0),
                NextState("FIND_DELIMITER"),
            ),

            # It's a nested frame. Get directly to TLP
            If(sink.ctrl[1] & (sink.data[8:16] == STP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(payload_cnt, 0),
                NextState("TLP"),
            ),

            # It's a nested frame. Get directly to DLLP
            If(sink.ctrl[1] & (sink.data[8:16] == SDP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(payload_cnt, 0),
                NextState("DLLP"),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *                An TLP is detected                     *
        # *********************************************************
        fsmWriter.act("TLP",
            NextValue(fifo.sink.ts, _ts),
            NextValue(fifo.sink.error, 0),
            NextValue(payload_cnt, payload_cnt + 1),

            # By default, is we have a K symbol before END, that's an error
            If((sink.ctrl[0] & (sink.data[0:8] != END.value)) | sink.ctrl[1] | (payload_cnt > _tlpDllpTimeoutCnt),
                NextValue(fifo.sink.error, 1),
                NextValue(fifo.sink.valid, 1),
                NextState("FIND_DELIMITER"),
            ).Else(
                NextValue(fifo.sink.error, 0),
            ),

            If((buf_in.source.ctrl[0]) & (buf_in.source.data[0:8] == END.value),
                NextValue(fifo.sink.valid, 0),
                NextValue(fifo.sink.error, 0),
                NextState("FIND_DELIMITER"),
            ),

            If(sink.ctrl[1] & (sink.data[8:16] == STP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(payload_cnt, 0),
                NextState("TLP"),
            ),

            If(sink.ctrl[1] & (sink.data[8:16] == SDP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(payload_cnt, 0),
                NextState("DLLP"),
            ),

            If(sink.osets & (sink.data[8:16] == COM.value),
                NextValue(fifo.sink.valid, 1),
                NextState("ORDERED_SETS"),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *                An DLLP is detected                    *
        # *********************************************************
        fsmWriter.act("DLLP",
            NextValue(fifo.sink.ts, _ts),
            NextValue(fifo.sink.error, 0),
            NextValue(payload_cnt, payload_cnt + 1),

            # By default, is we have a K symbol before END, that's an error
            If((sink.ctrl[0] & (sink.data[0:8] != END.value)) | sink.ctrl[1]| (payload_cnt > _tlpDllpTimeoutCnt),
                NextValue(fifo.sink.error, 1),
                NextValue(fifo.sink.valid, 1),
                NextState("FIND_DELIMITER"),
            ).Else(
                NextValue(fifo.sink.error, 0),
            ),

            If((buf_in.source.ctrl[0]) & (buf_in.source.data[0:8] == END.value),
                NextValue(fifo.sink.valid, 0),
                NextValue(fifo.sink.error, 0),
                NextState("FIND_DELIMITER"),
            ),

            If(sink.ctrl[1] & (sink.data[8:16] == STP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(payload_cnt, 0),
                NextState("TLP"),
            ),

            If(sink.ctrl[1] & (sink.data[8:16] == SDP.value),
                NextValue(fifo.sink.valid, 1),
                NextValue(payload_cnt, 0),
                NextState("DLLP"),
            ),

            If(sink.osets & (sink.data[8:16] == COM.value),
                NextValue(fifo.sink.valid, 1),
                NextState("ORDERED_SETS"),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

# ******************************************************************
# * Reading side of the FIFO.                                      *
# * Filtering takes place on the reading side of the FIFO.         *
# * A timestamp is added to each frame (or frame group) to keep    *
# * track of the timing.                                           *
# ******************************************************************

        # *********************************************************
        # *                   Filtering control                   *
        # *********************************************************
        fsmReader.act("NO_FILTER",
            NextValue(source.data, sink.data),
            NextValue(source.ctrl, sink.ctrl),
            NextValue(source.valid, sink.valid),
            NextValue(source.time, 0),
            If(_filterEnable,
                NextState("FILTER"),
            )
        )

        # *********************************************************
        # *                   Frame filtering                     *
        # *********************************************************
        fsmReader.act("FILTER",
            NextValue(source.valid, 0),
            NextValue(source.time, 0),
            NextValue(buf_out.source.ready, 0),
            NextValue(from_error, 0),
            NextValue(source.eof, 0),
            NextValue(clearTrig, 0),
            NextValue(source.trig, 0),

            If(from_error,
                NextValue(buf_out.source.ready, 1),
            ),

            If(buf_out.source.valid,

                # Don't insert a new timestamp
                If(last_ts == buf_out.source.ts,
                    insert_ts.eq(0),
                ).Else(
                    insert_ts.eq(1),
                    NextValue(last_ts, buf_out.source.ts),
                ),

                # ---- SKIP ----
                If(buf_out.source.osets & (buf_out.source.type == osetsType.SKIP) & (buf_out.source.data[8:16] == COM.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        # When this frame is disabled, we need to change last_ts
                        # in order to force ts insertion on the next frame.
                        If(skipEnabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.SKIP),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("SKIP"),
                    ),
                    If(~skipEnabled, NextValue(last_ts, 0)),
                ),

                # ---- IDLE ----
                If(buf_out.source.osets & (buf_out.source.type == osetsType.IDLE) & (buf_out.source.data[8:16] == COM.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        # When this frame is disabled, we need to change last_ts
                        # in order to force ts insertion on the next frame.
                        If(idleEnabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.IDLE),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("IDLE"),
                    ),
                    If(~idleEnabled, NextValue(last_ts, 0)),
                ),

                # ---- FTS ----
                If(buf_out.source.osets & (buf_out.source.type == osetsType.FTS) & (buf_out.source.data[8:16] == COM.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        If(ftsEnabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.FTS),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("FTS"),
                    ),
                    If(~ftsEnabled, NextValue(last_ts, 0)),
                ),

                # ---- TS1 ----
                If(buf_out.source.osets & (buf_out.source.type == osetsType.TS1) & (buf_out.source.data[8:16] == COM.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        If(ts1Enabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.TS1),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("TS1"),
                    ),
                    If(~ts1Enabled, NextValue(last_ts, 0)),
                ),

                # ---- TS2 ----
                If(buf_out.source.osets & (buf_out.source.type == osetsType.TS2) & (buf_out.source.data[8:16] == COM.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        If(ts2Enabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.TS2),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("TS2"),
                    ),
                    If(~ts2Enabled, NextValue(last_ts, 0)),
                ),

                # ---- TLP ----
                If(buf_out.source.ctrl[1] & (buf_out.source.data[8:16] == STP.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        If(tlpEnabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.TLP),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("TLP"),
                    ),
                    If(~tlpEnabled, NextValue(last_ts, 0)),
                ),

                # ---- DLLP ----
                If(buf_out.source.ctrl[1] & (buf_out.source.data[8:16] == SDP.value),
                    If(insert_ts,
                        NextValue(source.data, buf_out.source.ts[16:32]),
                        If(dllpEnabled,
                            NextValue(source.valid, 1),
                            NextValue(source.time, 1),
                        ),
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.DLLP),
                        NextValue(ts_trig, 0),
                        NextState("TIMESTAMP_LSB"),
                    ).Else(
                        NextValue(count, 0),
                        NextValue(buf_out.source.ready, 1),
                        NextState("DLLP"),
                    ),
                    If(~dllpEnabled, NextValue(last_ts, 0)),
                ),
            # buf_out.source is not valid
            ).Else(
                    If(trigPending,
                        NextValue(buf_out.source.ready, 0),
                        NextValue(state_after, state.FILTER),
                        NextState("TIMESTAMP_MSB_TRIG"),
                    )
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Insert LSB part of timestamp               *
        # *********************************************************
        
        fsmReader.act("TIMESTAMP_MSB_TRIG",
                NextValue(source.time, 1),
                NextValue(source.valid, 1),
                NextValue(source.data, _ts[16:32]),
                NextState("TIMESTAMP_LSB"),
                NextValue(source.trig, 1),
                NextValue(clearTrig, 1),
                NextValue(ts_trig, 1),
        ),

        # *********************************************************
        # *            Insert LSB part of timestamp               *
        # *********************************************************
        fsmReader.act("TIMESTAMP_LSB",
            NextValue(source.data, buf_out.source.ts[0:16]),
            If(ts_trig,
                NextValue(source.data, _ts[0:16]),
                NextValue(source.trig, 1),
            ).Else(
                NextValue(count, 0),
            ),

            NextValue(ts_trig, 0),

            NextValue(buf_out.source.ready, 1),

            If((state_after == state.FILTER),
                NextState("FILTER"),
            ),

            If((state_after == state.SKIP),
                If(skipEnabled,
                    NextValue(source.valid, 1),
                ),
                NextState("SKIP"),
            ),

            If((state_after == state.IDLE),
                If(ftsEnabled,
                    NextValue(source.valid, 1),
                ),
                NextState("IDLE"),
            ),

            If((state_after == state.FTS),
                If(ftsEnabled,
                    NextValue(source.valid, 1),
                ),
                NextState("FTS"),
            ),

            If((state_after == state.TS1),
                If(ts1Enabled,
                    NextValue(source.valid, 1),
                ),
                NextState("TS1"),
            ),

            If((state_after == state.TS2),
                If(ts2Enabled,
                    NextValue(source.valid, 1),
                ),
                NextState("TS2"),
            ),

            If((state_after == state.DLLP),
                If(dllpEnabled,
                    NextValue(source.valid, 1),
                ),
                NextState("DLLP"),
            ),

            If((state_after == state.TLP),
                If(tlpEnabled,
                    NextValue(source.valid, 1),
                ),
                NextState("TLP"),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a SKIP from the FIFO                  *
        # *********************************************************
        fsmReader.act("SKIP",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.SKIP),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If(count == 1,
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextState("FILTER"),
            ),

            If(skipEnabled,
                If(count == 0, NextValue(source.sof, 1)),
                If(count == 1, NextValue(source.eof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a IDLE from the FIFO                   *
        # *********************************************************
        fsmReader.act("IDLE",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.IDLE),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If(count == 1,
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextValue(source.sof, 0),
                NextValue(source.eof, 1),
                NextState("FILTER"),
            ),

            If(idleEnabled,
                If(count == 0, NextValue(source.sof, 1)),
                If(count == 1, NextValue(source.eof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a FTS from the FIFO                   *
        # *********************************************************
        fsmReader.act("FTS",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.FTS),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If(count == 1,
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextValue(source.sof, 0),
                NextValue(source.eof, 1),
                NextState("FILTER"),
            ),

            If(ftsEnabled,
                If(count == 0, NextValue(source.sof, 1)),
                If(count == 1, NextValue(source.eof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a TS1 from the FIFO                   *
        # *********************************************************
        fsmReader.act("TS1",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.TS1),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If(count == 7,
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextValue(source.sof, 0),
                NextValue(source.eof, 1),
                NextState("FILTER"),
            ),

            If(ts1Enabled,
                If(count == 0, NextValue(source.sof, 1)),
                If(count == 7, NextValue(source.eof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a TS2 from the FIFO                   *
        # *********************************************************
        fsmReader.act("TS2",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.TS2),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If(count == 7,
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextValue(source.sof, 0),
                NextValue(source.eof, 1),
                NextState("FILTER"),
            ),

            If(ts2Enabled,
                If(count == 0, NextValue(source.sof, 1)),
                If(count == 7, NextValue(source.eof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a TLP from the FIFO                   *
        # *********************************************************
        fsmReader.act("TLP",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.TLP),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If((buf_out.source.ctrl[0] & (buf_out.source.data[0:8] == END.value)) | fifo.source.error,
                If(tlpEnabled, NextValue(source.eof, 1)),
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextState("FILTER"),
                If(fifo.source.error,
                    NextValue(from_error, 1),
                ),
            ),

            If(tlpEnabled,
                If(count == 0, NextValue(source.sof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )

        # *********************************************************
        # *            Read a DLLP from the FIFO                  *
        # *********************************************************
        fsmReader.act("DLLP",
            NextValue(source.data, buf_out.source.data),
            NextValue(source.ctrl, buf_out.source.ctrl),
            NextValue(count, count + 1),
            NextValue(source.valid, 1),
            NextValue(last_ts, last_ts + 1),
            NextValue(source.time, 0),
            NextValue(source.trig, 0),

            NextValue(source.sof, 0),
            NextValue(source.eof, 0),

            If(trigPending,
                NextValue(buf_out.source.ready, 0),
                NextValue(state_after, state.DLLP),
                NextState("TIMESTAMP_MSB_TRIG"),
            ),

            If((buf_out.source.ctrl[0] & (buf_out.source.data[0:8] == END.value)) | fifo.source.error,
                If(dllpEnabled, NextValue(source.eof, 1)),
                NextValue(buf_out.source.ready, 0),
                NextValue(source.valid, 0),
                NextState("FILTER"),
                If(fifo.source.error,
                    NextValue(from_error, 1),
                ),
            ),

            If(dllpEnabled,
                If(count == 0, NextValue(source.sof, 1)),
                NextValue(source.valid, 1),
            ).Else(
                NextValue(source.valid, 0),
            ),

            If(~_filterEnable,
                NextState("NO_FILTER"),
            )
        )