Пример #1
0
    def __init__(self, size, init=None):
        self.source = source = stream.Endpoint(spi_phy_data_layout)
        self.sink = sink = stream.Endpoint(spi_phy_ctl_layout)
        mem = Memory(32, size // 4, init=init)
        read_addr = Signal(32)
        self.cs_n = Signal()

        read_port = mem.get_port(async_read=True)
        self.comb += read_port.adr.eq(read_addr)

        self.specials += mem, read_port

        commands = {
            CMD: [NextValue(read_addr,
                            sink.data[2:31])],  # word addressed memory
            READ: [NextState("DATA")],
        }

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE",
            sink.ready.eq(1),
            If(
                sink.ready & sink.valid,
                Case(sink.cmd, commands),
            ),
        )
        fsm.act(
            "DATA",
            source.valid.eq(1),
            source.data.eq(read_port.dat_r),
            If(
                source.ready & source.valid,
                NextValue(read_addr, read_addr + 1),
                NextState("IDLE"),
            ),
        )
Пример #2
0
    def __init__(self, endpoint, address_decoder):
        self.wishbone = wishbone.Interface()

        # # #

        port = endpoint.crossbar.get_slave_port(address_decoder)
        self.submodules.fsm = fsm = FSM()

        fsm.act(
            "IDLE",
            If(port.sink.stb & port.sink.sop,
               If(
                   port.sink.we,
                   NextState("WRITE"),
               ).Else(NextState("READ"))).Else(port.sink.ack.eq(
                   port.sink.stb)))
        fsm.act("WRITE", self.wishbone.adr.eq(port.sink.adr[2:]),
                self.wishbone.dat_w.eq(port.sink.dat[:32]),
                self.wishbone.sel.eq(0xf), self.wishbone.stb.eq(1),
                self.wishbone.we.eq(1), self.wishbone.cyc.eq(1),
                If(self.wishbone.ack, port.sink.ack.eq(1), NextState("IDLE")))
        fsm.act("READ", self.wishbone.adr.eq(port.sink.adr[2:]),
                self.wishbone.stb.eq(1), self.wishbone.we.eq(0),
                self.wishbone.cyc.eq(1),
                If(self.wishbone.ack, NextState("COMPLETION")))
        self.sync += \
            If(self.wishbone.stb & self.wishbone.ack,
                port.source.dat.eq(self.wishbone.dat_r),
            )
        fsm.act("COMPLETION", port.source.stb.eq(1), port.source.sop.eq(1),
                port.source.eop.eq(1), port.source.len.eq(1),
                port.source.err.eq(0), port.source.tag.eq(port.sink.tag),
                port.source.adr.eq(port.sink.adr),
                port.source.cmp_id.eq(endpoint.phy.id),
                port.source.req_id.eq(port.sink.req_id),
                If(port.source.ack, port.sink.ack.eq(1), NextState("IDLE")))
Пример #3
0
    def __init__(self):
        self.busy = Signal()
        self.sink = Endpoint([('d', 8)])
        self.source = Endpoint(CMD_REC)

        sm = FSM(reset_state="IDLE")
        self.submodules += sm

        # Basic checksum

        token = self.source.payload
        token_next = Record(CMD_REC)

        self.sync += token.eq(token_next)
        self.comb += token_next.eq(token)

        sm.act(
            "IDLE", self.sink.ack.eq(1),
            If(self.sink.stb, If(self.sink.payload.d == 0x55,
                                 NextState("ADRH"))))

        def parse_state(st, to, *update):
            sm.act(st, self.sink.ack.eq(1),
                   If(self.sink.stb, NextState(to), *update))

        parse_state('ADRH', 'ADRL', token_next.wr.eq(self.sink.payload.d[7]),
                    token_next.a[8:14].eq(self.sink.payload.d[:6]))

        parse_state('ADRL', 'DATA', token_next.a[0:8].eq(self.sink.payload.d)),
        parse_state('DATA', 'CKSUM', token_next.d.eq(self.sink.payload.d)),

        sm.act("CKSUM", self.sink.ack.eq(1),
               If(self.sink.stb, NextState('ISSUE')))

        sm.act("ISSUE", self.source.stb.eq(1),
               If(self.source.ack, NextState('IDLE')))
Пример #4
0
        def delay_gen(next_state, width=xfer_width, bits=xfer_len, op=[]):
            res = [
                If(
                    delay_cnt == (bits - width + latency * width),
                    source.valid.eq(1),
                    If(
                        source.ready,
                        NextValue(delay_cnt, 0),
                        NextState(next_state),
                        *op,
                    ),
                ).Else(NextValue(delay_cnt, delay_cnt + width), )
            ]

            return res
Пример #5
0
    def __init__(self, pads):

        STATUS_FULL = 1
        STATUS_EMPTY = 2

        self.shift_reg = shift_reg = CSRStorage(8, write_from_dev=True)
        self.status = status = CSRStorage(2,
                                          reset=STATUS_EMPTY,
                                          write_from_dev=True)
        self.slave_addr = slave_addr = CSRStorage(7)

        ###

        scl_raw = Signal()
        sda_i = Signal()
        sda_raw = Signal()
        sda_drv = Signal()
        scl_drv = Signal()
        _sda_drv_reg = Signal()
        self._sda_i_async = _sda_i_async = Signal()
        self._scl_i_async = _scl_i_async = Signal()
        _scl_drv_reg = Signal()
        self.sync += _sda_drv_reg.eq(sda_drv)
        self.sync += _scl_drv_reg.eq(scl_drv)
        self.comb += [
            pads.scl.w.eq(0),
            pads.scl.oe.eq(_scl_drv_reg),
            _scl_i_async.eq(pads.scl.r),
            pads.sda.w.eq(0),
            pads.sda.oe.eq(_sda_drv_reg),
            _sda_i_async.eq(pads.sda.r),
        ]
        self.specials += [
            MultiReg(_scl_i_async, scl_raw),
            MultiReg(_sda_i_async, sda_raw),
        ]

        # for debug
        self.scl = scl_raw
        self.sda_i = sda_i
        self.sda_o = Signal()
        self.comb += self.sda_o.eq(~_sda_drv_reg)
        self.sda_oe = _sda_drv_reg

        shift_reg_full = Signal()
        shift_reg_empty = Signal()
        scl_i = Signal()
        samp_count = Signal(3)
        samp_carry = Signal()
        self.sync += [
            Cat(samp_count, samp_carry).eq(samp_count + 1),
            If(samp_carry, scl_i.eq(scl_raw), sda_i.eq(sda_raw))
        ]

        scl_r = Signal()
        sda_r = Signal()
        scl_rising = Signal()
        scl_falling = Signal()
        sda_rising = Signal()
        sda_falling = Signal()
        self.sync += [scl_r.eq(scl_i), sda_r.eq(sda_i)]
        self.comb += [
            shift_reg_full.eq(status.storage[0]),
            shift_reg_empty.eq(status.storage[1]),
            scl_rising.eq(scl_i & ~scl_r),
            scl_falling.eq(~scl_i & scl_r),
            sda_rising.eq(sda_i & ~sda_r),
            sda_falling.eq(~sda_i & sda_r)
        ]

        start = Signal()
        self.comb += start.eq(scl_i & sda_falling)

        din = Signal(8)
        counter = Signal(max=9)
        counter_reset = Signal()
        self.sync += [
            If(start | counter_reset, counter.eq(0)),
            If(
                scl_rising,
                If(counter == 8,
                   counter.eq(0)).Else(counter.eq(counter + 1),
                                       din.eq(Cat(sda_i, din[:7]))))
        ]

        self.din = din
        self.counter = counter

        is_read = Signal()
        update_is_read = Signal()
        self.sync += If(update_is_read, is_read.eq(din[0]))
        data_bit = Signal()

        zero_drv = Signal()
        data_drv = Signal()
        pause_drv = Signal()
        self.comb += scl_drv.eq(pause_drv)
        self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv,
                                                      sda_drv.eq(~data_bit))

        data_drv_en = Signal()
        data_drv_stop = Signal()
        self.sync += If(data_drv_en,
                        data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
        self.sync += If(
            data_drv_en,
            chooser(shift_reg.storage, counter, data_bit, 8, reverse=True))
        self.submodules.fsm = fsm = FSM()

        fsm.act(
            "WAIT_START",
            data_drv_stop.eq(1),
        )
        fsm.act(
            "RCV_ADDRESS", data_drv_stop.eq(1),
            If(
                counter == 8,
                If(
                    din[1:] == slave_addr.storage,
                    update_is_read.eq(1),
                    NextState("ACK_ADDRESS0"),
                ).Else(NextState("WAIT_START"), )))
        fsm.act(
            "ACK_ADDRESS0",
            counter_reset.eq(1),
            If(~scl_i, NextState("ACK_ADDRESS1")),
        )
        fsm.act(
            "ACK_ADDRESS1",
            counter_reset.eq(1),
            zero_drv.eq(1),
            If(scl_i, NextState("ACK_ADDRESS2")),
        )
        fsm.act("ACK_ADDRESS2", counter_reset.eq(1), zero_drv.eq(1),
                If(~scl_i, NextState("PAUSE")))
        fsm.act(
            "PAUSE", counter_reset.eq(1), pause_drv.eq(1),
            If(
                ~shift_reg_empty & is_read,
                counter_reset.eq(1),
                NextState("DO_READ"),
            ).Elif(
                ~shift_reg_full & ~is_read,
                NextState("DO_WRITE"),
            ))
        fsm.act(
            "DO_READ",
            If(
                ~scl_i,
                If(
                    counter == 8,
                    data_drv_stop.eq(1),
                    status.we.eq(1),
                    status.dat_w.eq(STATUS_EMPTY),
                    NextState("ACK_READ0"),
                ).Else(data_drv_en.eq(1), )))
        fsm.act(
            "ACK_READ0", counter_reset.eq(1),
            If(
                scl_rising,
                If(
                    sda_i,
                    NextState("WAIT_START"),
                ).Else(NextState("ACK_READ1"), )))
        fsm.act("ACK_READ1", counter_reset.eq(1),
                If(
                    scl_falling,
                    NextState("PAUSE"),
                ))
        fsm.act(
            "DO_WRITE",
            If(
                counter == 8,
                shift_reg.dat_w.eq(din),
                shift_reg.we.eq(1),
                NextState("ACK_WRITE0"),
            ))
        fsm.act(
            "ACK_WRITE0",
            counter_reset.eq(1),
            If(~scl_i, NextState("ACK_WRITE1")),
        )
        fsm.act(
            "ACK_WRITE1",
            counter_reset.eq(1),
            zero_drv.eq(1),
            If(scl_i, NextState("ACK_WRITE2")),
        )
        fsm.act(
            "ACK_WRITE2", counter_reset.eq(1), zero_drv.eq(1),
            If(
                ~scl_i,
                NextState("PAUSE"),
                status.we.eq(1),
                status.dat_w.eq(STATUS_FULL),
            ))

        for state in fsm.actions.keys():
            fsm.act(state, If(start, NextState("RCV_ADDRESS")))

        for state in fsm.actions.keys():
            fsm.act(state, If(self.slave_addr.re, NextState("WAIT_START")))
Пример #6
0
 def skip(state):
     return [
         self.sink.ack.eq(1),
         NextState(state)
         ]
Пример #7
0
 def write_hdr(statename, nextname, hdr_offs, val):
     self.fsm.act(statename, NextState(nextname),
                  wrport.adr.eq(self.produce_header.v + hdr_offs),
                  wrport.dat_w.eq(val), wrport.we.eq(1))
Пример #8
0
    def __init__(self, master, slave):
        dw_from = len(master.dat_r)
        dw_to = len(slave.dat_w)
        ratio = dw_to // dw_from
        ratiobits = log2_int(ratio)

        # # #

        write = Signal()
        evict = Signal()
        refill = Signal()
        read = Signal()

        address = FlipFlop(30)
        self.submodules += address
        self.comb += address.d.eq(master.adr)

        counter = Signal(max=ratio)
        counter_ce = Signal()
        counter_reset = Signal()
        self.sync += \
            If(counter_reset,
                counter.eq(0)
            ).Elif(counter_ce,
                counter.eq(counter + 1)
            )
        counter_offset = Signal(max=ratio)
        counter_done = Signal()
        self.comb += [
            counter_offset.eq(address.q),
            counter_done.eq((counter + counter_offset) == ratio - 1)
        ]

        cached_data = Signal(dw_to)
        cached_sel = Signal(dw_to // 8)

        end_of_burst = Signal()
        self.comb += end_of_burst.eq(~master.cyc
                                     | (master.stb & master.cyc & master.ack
                                        & ((master.cti == 7) | counter_done)))

        need_refill = FlipFlop(reset=1)
        self.submodules += need_refill
        self.comb += [need_refill.reset.eq(end_of_burst), need_refill.d.eq(0)]

        # Main FSM
        self.submodules.fsm = fsm = FSM()
        fsm.act(
            "IDLE", counter_reset.eq(1),
            If(
                master.stb & master.cyc, address.ce.eq(1),
                If(master.we, NextState("WRITE")).Else(
                    If(need_refill.q,
                       NextState("REFILL")).Else(NextState("READ")))))
        fsm.act(
            "WRITE",
            If(master.stb & master.cyc, write.eq(1), counter_ce.eq(1),
               master.ack.eq(1),
               If(counter_done,
                  NextState("EVICT"))).Elif(~master.cyc, NextState("EVICT")))
        fsm.act("EVICT", evict.eq(1), slave.stb.eq(1), slave.we.eq(1),
                slave.cyc.eq(1), slave.dat_w.eq(cached_data),
                slave.sel.eq(cached_sel), If(slave.ack, NextState("IDLE")))
        fsm.act("REFILL", refill.eq(1), slave.stb.eq(1), slave.cyc.eq(1),
                If(slave.ack, need_refill.ce.eq(1), NextState("READ")))
        fsm.act("READ", read.eq(1),
                If(master.stb & master.cyc, master.ack.eq(1)),
                NextState("IDLE"))

        # Address
        self.comb += [
            slave.cti.eq(
                7),  # we are not able to generate bursts since up-converting
            slave.adr.eq(address.q[ratiobits:])
        ]

        # Datapath
        cached_datas = [FlipFlop(dw_from) for i in range(ratio)]
        cached_sels = [FlipFlop(dw_from // 8) for i in range(ratio)]
        self.submodules += cached_datas, cached_sels

        cases = {}
        for i in range(ratio):
            write_sel = Signal()
            cases[i] = write_sel.eq(1)
            self.comb += [
                cached_sels[i].reset.eq(counter_reset),
                If(
                    write,
                    cached_datas[i].d.eq(master.dat_w),
                ).Else(cached_datas[i].d.eq(slave.dat_r[dw_from * i:dw_from *
                                                        (i + 1)])),
                cached_sels[i].d.eq(master.sel),
                If((write & write_sel) | refill, cached_datas[i].ce.eq(1),
                   cached_sels[i].ce.eq(1))
            ]
        self.comb += Case(counter + counter_offset, cases)

        cases = {}
        for i in range(ratio):
            cases[i] = master.dat_r.eq(cached_datas[i].q)
        self.comb += Case(address.q[:ratiobits], cases)

        self.comb += [
            cached_data.eq(Cat([cached_data.q
                                for cached_data in cached_datas])),
            cached_sel.eq(Cat([cached_sel.q for cached_sel in cached_sels]))
        ]
Пример #9
0
    def __init__(self, dram_port, nslots):
        bus_aw = dram_port.aw
        bus_dw = dram_port.dw
        alignment_bits = bits_for(bus_dw // 8) - 1

        fifo_word_width = bus_dw
        self.frame = stream.Endpoint([("sof", 1), ("pixels", fifo_word_width)])
        self._frame_size = CSRStorage(bus_aw + alignment_bits)
        self.submodules._slot_array = _SlotArray(nslots, bus_aw,
                                                 alignment_bits)
        self.ev = self._slot_array.ev

        # # #

        # address generator + maximum memory word count to prevent DMA buffer
        # overrun
        reset_words = Signal()
        count_word = Signal()
        last_word = Signal()
        current_address = Signal(bus_aw)
        mwords_remaining = Signal(bus_aw)
        self.comb += [
            self._slot_array.address_reached.eq(current_address),
            last_word.eq(mwords_remaining == 1)
        ]
        self.sync += [
            If(reset_words, current_address.eq(self._slot_array.address),
               mwords_remaining.eq(
                   self._frame_size.storage[alignment_bits:])).Elif(
                       count_word, current_address.eq(current_address + 1),
                       mwords_remaining.eq(mwords_remaining - 1))
        ]

        memory_word = Signal(bus_dw)
        pixbits = []
        for i in range(bus_dw // 16):
            pixbits.append(self.frame.pixels)
        self.comb += memory_word.eq(Cat(*pixbits))

        # bus accessor
        self.submodules._bus_accessor = LiteDRAMDMAWriter(dram_port)
        self.comb += [
            self._bus_accessor.sink.address.eq(current_address),
            self._bus_accessor.sink.data.eq(memory_word)
        ]

        # control FSM
        fsm = FSM()
        self.submodules += fsm

        fsm.act(
            "WAIT_SOF", reset_words.eq(1),
            self.frame.ready.eq(~self._slot_array.address_valid
                                | ~self.frame.sof),
            If(
                self._slot_array.address_valid & self.frame.sof
                & self.frame.valid, NextState("TRANSFER_PIXELS")))
        fsm.act(
            "TRANSFER_PIXELS",
            self.frame.ready.eq(self._bus_accessor.sink.ready),
            If(
                self.frame.valid, self._bus_accessor.sink.valid.eq(1),
                If(self._bus_accessor.sink.ready, count_word.eq(1),
                   If(last_word, NextState("EOF")))))
        fsm.act(
            "EOF",
            If(~dram_port.wdata.valid, self._slot_array.address_done.eq(1),
               NextState("WAIT_SOF")))
Пример #10
0
	def __init__(self, ulpi_bus):
		self.ulpi_bus = ulpi_bus
		
		fsm = FSM()
		self.submodules += fsm
		
		self.WantRx = Signal()
		self.RxByte = Signal(8)
		self.RxCmd = Signal()
		self.NextCycleRx = Signal()
		
		self.RegWriteValid = Signal()
		self.RegAddrW = Signal(6)
		self.RegDataW = Signal(8)

		self.RegRead = Signal()
		self.RegAddrR = Signal(6)
		self.RegDataR = Signal(8)
		
		self.StateTX = Signal()
		
		SetRegAddrR = Signal()
		SetRegAddrW = Signal()
		SetRegDataW = Signal()
		
		fsm.act("TXCMD", 
			If(self.WantRx, NextState("TA1")
			).Elif(ulpi_bus.do[6:8] == 0b10, NextState("RW0") # REGW
			).Elif(ulpi_bus.do[6:8] == 0b11, NextState("RR0") # REGR
			).Else(NextState("TXCMD"), 
				ulpi_bus.dir.eq(0),
				self.StateTX.eq(1)
			))
		
		fsm.act("TA1", 
			NextState("RX"), 
			ulpi_bus.dir.eq(1),
			self.NextCycleRx.eq(1)
			)
		
		fsm.act("RX",
			If(self.WantRx, NextState("RX"),
				ulpi_bus.dir.eq(1),
				ulpi_bus.di.eq(self.RxByte),
				ulpi_bus.nxt.eq(self.RxCmd),
				self.NextCycleRx.eq(1)
			).Else(NextState("TA2")
			))
		
		fsm.act("TA2", 
				NextState("TXCMD"),
				ulpi_bus.dir.eq(0)
			)
		
		fsm.act("RW0", 
			If(self.WantRx, NextState("TA1")
			).Else(
				NextState("RW1"),
				ulpi_bus.dir.eq(0),
				ulpi_bus.nxt.eq(1),
				SetRegAddrW.eq(1)
			))
		
		fsm.act("RW1",
			NextState("RW2"),
			ulpi_bus.dir.eq(0),
			ulpi_bus.nxt.eq(1),
			SetRegDataW.eq(1)
			)
		
		fsm.act("RW2",
			NextState("TXCMD"),
			self.RegWriteValid.eq(ulpi_bus.stp))
		
		fsm.act("RR0",
			If(self.WantRx, NextState("TA1")
			).Else(
				NextState("RR1"),
				SetRegAddrR.eq(1),
				ulpi_bus.nxt.eq(1),
			))
		
		fsm.act("RR1", 
			ulpi_bus.dir.eq(1),
			If(self.WantRx, 
				NextState("RX"), 
				ulpi_bus.nxt.eq(1), # indicating abort
			).Else(
				NextState("RRD")
			))
		
		fsm.act("RRD",
			ulpi_bus.dir.eq(1),
			ulpi_bus.di.eq(self.RegDataR),
			NextState("TA2"
		))

		self.sync += If(SetRegAddrR, self.RegAddrR.eq(ulpi_bus.do[0:6]))
		self.sync += self.RegRead.eq(SetRegAddrR)

		self.sync += If(SetRegAddrW, self.RegAddrW.eq(ulpi_bus.do[0:6]))
		self.sync += If(SetRegDataW, self.RegDataW.eq(ulpi_bus.do))
Пример #11
0
    def __init__(self,
                 usb_core,
                 clk_freq=12000000,
                 magic_packet=0x43,
                 cdc=False):
        self.wishbone = wishbone.Interface()

        self.background = ModuleDoc(title="USB Wishbone Bridge",
                                    body="""
            This bridge provides a transparent bridge to the target device's Wishbone bus over USB.
            It can operate without interfering with the device's USB stack.  It is simple enough to
            be able to work even if the USB stack is not enumerated, though the host may not cooperate."""
                                    )

        self.protocol = ModuleDoc(title="USB Wishbone Debug Protocol",
                                  body="""
        The protocol transfers four bytes a time in big-endian (i.e. USB) order.  It uses SETUP packets
        with the special type (0x43) as an `attention` word.  This is then followed by an ``OUT`` packet.

            .. wavedrom::
                :caption: Write to Wishbone

                { "signal": [
                    ["Request",
                        {  "name": 'data',        "wave": 'x222...22x', "data": '0x43 0x00 [ADDRESS] 0x04 0x00'   },
                        {  "name": 'data bits',   "wave": 'xxx2222xxx', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x222.2.2.x', "data": 'bReq bTyp wValue wIndex wLength' },
                        {  "name": 'usb byte',    "wave": 'x22222222x', "data": '1 2 3 4 5 6 7 8'                 }
                    ],
                    {},
                    ["Payload",
                        {  "name": 'data',        "wave": 'x3...x', "data": '[DATA]'},
                        {  "name": 'data bits',   "wave": 'x3333x', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x3...x', "data": 'OUT'  },
                        {  "name": 'usb byte',    "wave": 'x3333x', "data": '1 2 3 4'}
                    ]
                ]}

        To read data from the device, set the top bit of the `bRequestType`, followed by an ``IN`` packet.

            .. wavedrom::
                :caption: Read from Wishbone

                { "signal": [
                    ['Request',
                        {  "name": 'data',        "wave": 'x222...22x', "data": '0xC3 0x00 [ADDRESS] 0x04 0x00'   },
                        {  "name": 'data bits',   "wave": 'xxx2222xxx', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x222.2.2.x', "data": 'bReq bTyp wValue wIndex wLength' },
                        {  "name": 'usb byte',    "wave": 'x22222222x', "data": '1 2 3 4 5 6 7 8'                 }
                    ],
                    {},
                    ["Payload",
                        {  "name": 'data',        "wave": 'x5...x', "data": '[DATA]'},
                        {  "name": 'data bits',   "wave": 'x5555x', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x5...x', "data": 'IN'  },
                        {  "name": 'usb byte',    "wave": 'x5555x', "data": '1 2 3 4'}
                    ]
                ]}
        """)
        # # #

        byte_counter = Signal(3, reset_less=True)
        byte_counter_reset = Signal()
        byte_counter_ce = Signal()
        self.sync.usb_12 += \
            If(byte_counter_reset,
                byte_counter.eq(0)
            ).Elif(byte_counter_ce,
                byte_counter.eq(byte_counter + 1)
            )

        # Unlike the UART or Ethernet bridges, we explicitly only
        # support two commands: reading and writing.  This gets
        # integrated into the USB protocol, so it's not really a
        # state.  1 is "USB Device to Host", and is therefore a "read",
        # while 0 is "USB Host to Device", and is therefore a "write".
        cmd = Signal(1, reset_less=True)
        cmd_ce = Signal()

        # Add a bridge to allow this module (in the usb_12 domain) to access
        # the main Wishbone bridge (potentially in some other domain).
        # Ensure this bridge is placed in the "sys" domain.
        send_to_wishbone = Signal()
        reply_from_wishbone = Signal()
        transfer_active = Signal()
        if cdc:
            self.submodules.wb_cd_bridge = wb_cd_bridge = FSM(
                reset_state="IDLE")
            self.submodules.usb_to_wb = usb_to_wb = PulseSynchronizer(
                "usb_12", "sys")
            self.submodules.wb_to_uwb = wb_to_usb = PulseSynchronizer(
                "sys", "usb_12")
            send_to_wishbone = usb_to_wb.i
            reply_from_wishbone = wb_to_usb.o
        else:
            self.comb += [
                If(
                    send_to_wishbone | transfer_active,
                    self.wishbone.stb.eq(1),
                    self.wishbone.we.eq(~cmd),
                    self.wishbone.cyc.eq(1),
                ),
                reply_from_wishbone.eq(self.wishbone.ack | self.wishbone.err),
            ]

        # Instead of self.source and self.sink, we let the wrapping
        # module handle packing and unpacking the data.
        self.sink_data = Signal(8)

        # True when the "sink" value has data
        self.sink_valid = Signal()

        self.send_ack = Signal()

        # Indicates whether a "debug" packet is currently being processed
        self.n_debug_in_progress = Signal(reset=1)

        address = Signal(32, reset_less=True)
        address_ce = Signal()

        data = Signal(32, reset_less=True)
        rd_data = Signal(32, reset_less=True)
        rx_data_ce = Signal()

        # wishbone_response = Signal(32, reset_less=True)
        self.sync.usb_12 += [
            If(cmd_ce, cmd.eq(usb_core.data_recv_payload[7:8])),
            If(address_ce,
               address.eq(Cat(address[8:32], usb_core.data_recv_payload))),
            If(rx_data_ce, data.eq(Cat(data[8:32],
                                       usb_core.data_recv_payload)))
        ]

        # The Litex Wishbone `dat_r` line is a shared medium, meaning the value
        # changes often.  Capture our own copy of this data when a wishbone ACK
        # occurs.
        self.sync.sys += [
            If(self.wishbone.ack, rd_data.eq(self.wishbone.dat_r))
        ]

        fsm = ResetInserter()(ClockDomainsRenamer("usb_12")(
            FSM(reset_state="IDLE")))
        self.submodules += fsm
        fsm.act(
            "IDLE",
            self.n_debug_in_progress.eq(1),
            If(
                usb_core.data_recv_put,
                If(
                    usb_core.tok == PID.SETUP,
                    If(
                        usb_core.endp == 0,
                        # If we get a SETUP packet with a "Vendor" type
                        # going to this device, treat that as a DEBUG packet.
                        cmd_ce.eq(1),
                        byte_counter_reset.eq(1),
                        If(
                            usb_core.data_recv_payload[0:7] == magic_packet,
                            NextState("RECEIVE_ADDRESS"),
                        ).Else(
                            # Wait for the end of the packet, to avoid
                            # messing with normal USB operation
                            NextState("WAIT_PKT_END"), ),
                    ))))

        # The target address comes as the wValue and wIndex in the SETUP
        # packet.  Once we get that data, we're ready to do the operation.
        fsm.act(
            "RECEIVE_ADDRESS",
            self.n_debug_in_progress.eq(0),
            If(
                usb_core.data_recv_put,
                byte_counter_ce.eq(1),
                If(
                    (byte_counter >= 1),
                    If(
                        (byte_counter <= 4),
                        address_ce.eq(1),
                    ),
                ),
            ),
            # We don't need to explicitly ACK the SETUP packet, because
            # they're always acknowledged implicitly.  Wait until the
            # packet ends (i.e. until we've sent the ACK packet) before
            # moving to the next state.
            If(
                usb_core.end,
                byte_counter_reset.eq(1),
                If(
                    cmd,
                    send_to_wishbone.eq(1),
                    NextState("READ_DATA"),
                ).Else(NextState("RECEIVE_DATA"), ),
            ),
        )

        fsm.act(
            "RECEIVE_DATA",
            # Set the "ACK" bit to 1, so we acknowledge the packet
            # once it comes in, and so that we're in a position to
            # receive data.
            self.send_ack.eq(usb_core.endp == 0),
            self.n_debug_in_progress.eq(0),
            If(
                usb_core.endp == 0,
                If(
                    usb_core.data_recv_put, rx_data_ce.eq(1),
                    byte_counter_ce.eq(1),
                    If(
                        byte_counter == 3,
                        NextState("WAIT_RECEIVE_DATA_END"),
                    ).Elif(
                        usb_core.end,
                        send_to_wishbone.eq(1),
                        NextState("WRITE_DATA"),
                    ))))
        fsm.act(
            "WAIT_RECEIVE_DATA_END",
            self.n_debug_in_progress.eq(0),
            self.send_ack.eq(1),
            # Wait for the end of the USB packet, if
            # it hasn't come already.
            If(usb_core.end, send_to_wishbone.eq(1), NextState("WRITE_DATA")))

        if cdc:
            wb_cd_bridge.act(
                "IDLE",
                If(
                    usb_to_wb.o,
                    NextState("DO_OP"),
                ),
            )
            wb_cd_bridge.act(
                "DO_OP",
                self.wishbone.stb.eq(1),
                self.wishbone.we.eq(~cmd),
                self.wishbone.cyc.eq(1),
                If(
                    self.wishbone.ack | self.wishbone.err,
                    NextState("IDLE"),
                    wb_to_usb.i.eq(1),
                ),
            )

        self.comb += [
            # Trim off the last two bits of the address, because wishbone addresses
            # are word-based, and a word is 32-bits.  Therefore, the last two bits
            # should always be zero.
            self.wishbone.adr.eq(address[2:]),
            self.wishbone.dat_w.eq(data),
            self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1)
        ]
        fsm.act("WRITE_DATA", self.n_debug_in_progress.eq(0),
                transfer_active.eq(1),
                If(
                    reply_from_wishbone,
                    NextState("WAIT_SEND_ACK_START"),
                ))

        fsm.act("READ_DATA", self.n_debug_in_progress.eq(0),
                transfer_active.eq(1),
                If(reply_from_wishbone, NextState("SEND_DATA_WAIT_START")))

        fsm.act(
            "SEND_DATA_WAIT_START",
            self.n_debug_in_progress.eq(0),
            byte_counter_reset.eq(1),
            If(
                usb_core.start,
                NextState("SEND_DATA"),
            ),
        )
        self.comb += \
            chooser(rd_data, byte_counter, self.sink_data, n=4, reverse=False)
        fsm.act(
            "SEND_DATA",
            self.n_debug_in_progress.eq(0),
            If(
                usb_core.endp != 0,
                NextState("SEND_DATA_WAIT_START"),
            ),

            # Keep sink_valid high during the packet, which indicates we have data
            # to send.  This also causes an "ACK" to be transmitted.
            self.sink_valid.eq(usb_core.endp == 0),
            If(
                usb_core.data_send_get,
                byte_counter_ce.eq(1),
            ),
            If(byte_counter == 4, NextState("WAIT_SEND_ACK_START")),
            If(usb_core.end, NextState("WAIT_SEND_ACK_START")))

        # To validate the transaction was successful, the host will now
        # send an "IN" request.  Acknowledge that by setting
        # self.send_ack, without putting anything in self.sink_data.
        fsm.act(
            "WAIT_SEND_ACK_START",
            self.n_debug_in_progress.eq(0),
            If(usb_core.start, NextState("SEND_ACK")),
        )

        # Send the ACK.  If the endpoint number is incorrect, go back and
        # wait again.
        fsm.act(
            "SEND_ACK",
            self.n_debug_in_progress.eq(0),
            If(usb_core.endp != 0, NextState("WAIT_SEND_ACK_START")),
            # If(usb_core.retry,
            #     If(cmd,
            #         byte_counter_reset.eq(1),
            #         NextState("SEND_DATA"),
            #     ),
            # ),
            self.send_ack.eq(usb_core.endp == 0),
            If(
                usb_core.end,
                NextState("IDLE"),
            ))

        fsm.act("WAIT_PKT_END", self.n_debug_in_progress.eq(1),
                If(
                    usb_core.end,
                    NextState("IDLE"),
                ))
Пример #12
0
    def __init__(self, usb_core, magic_packet=0x43):
        self.wishbone = wishbone.Interface()

        self.background = ModuleDoc(title="USB Wishbone Bridge", body="""
            This bridge provides a transparent bridge to the target device's Wishbone bus over USB.
            It can operate without interfering with the device's USB stack.  It is simple enough to
            be able to work even if the USB stack is not enumerated, though the host may not cooperate.""")

        self.protocol = ModuleDoc(title="USB Wishbone Debug Protocol", body="""
        The protocol transfers four bytes a time in big-endian (i.e. USB) order.  It uses SETUP packets
        with the special type (0x43) as an `attention` word.  This is then followed by an ``OUT`` packet.

            .. wavedrom::
                :caption: Write to Wishbone

                { "signal": [
                    ["Request",
                        {  "name": 'data',        "wave": 'x222...22x', "data": '0x43 0x00 [ADDRESS] 0x04 0x00'   },
                        {  "name": 'data bits',   "wave": 'xxx2222xxx', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x222.2.2.x', "data": 'bReq bTyp wValue wIndex wLength' },
                        {  "name": 'usb byte',    "wave": 'x22222222x', "data": '1 2 3 4 5 6 7 8'                 }
                    ],
                    {},
                    ["Payload",
                        {  "name": 'data',        "wave": 'x3...x', "data": '[DATA]'},
                        {  "name": 'data bits',   "wave": 'x3333x', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x3...x', "data": 'OUT'  },
                        {  "name": 'usb byte',    "wave": 'x3333x', "data": '1 2 3 4'}
                    ]
                ]}

        To read data from the device, set the top bit of the `bRequestType`, followed by an ``IN`` packet.

            .. wavedrom::
                :caption: Read from Wishbone

                { "signal": [
                    ['Request',
                        {  "name": 'data',        "wave": 'x222...22x', "data": '0xC3 0x00 [ADDRESS] 0x04 0x00'   },
                        {  "name": 'data bits',   "wave": 'xxx2222xxx', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x222.2.2.x', "data": 'bReq bTyp wValue wIndex wLength' },
                        {  "name": 'usb byte',    "wave": 'x22222222x', "data": '1 2 3 4 5 6 7 8'                 }
                    ],
                    {},
                    ["Payload",
                        {  "name": 'data',        "wave": 'x5...x', "data": '[DATA]'},
                        {  "name": 'data bits',   "wave": 'x5555x', "data": '7:0 15:8 23:16 31:24'},
                        {  "name": 'usb meaning', "wave": 'x5...x', "data": 'IN'  },
                        {  "name": 'usb byte',    "wave": 'x5555x', "data": '1 2 3 4'}
                    ]
                ]}
        """)
        # # #

        # Unlike the UART or Ethernet bridges, we explicitly only
        # support two commands: reading and writing.  This gets
        # integrated into the USB protocol, so it's not really a
        # state.  1 is "USB Device to Host", and is therefore a "read",
        # while 0 is "USB Host to Device", and is therefore a "write".
        self.cmd = cmd = Signal(1, reset_less=True)
        cmd_ce = Signal()

        self.data_phase = Signal()

        # Instead of self.source and self.sink, we let the wrapping
        # module handle packing and unpacking the data.
        self.sink_data = Signal(8)

        # True when the "sink" value has data
        self.sink_valid = Signal()

        self.send_ack = Signal()

        # Indicates whether a "debug" packet is currently being processed
        self.n_debug_in_progress = Signal(reset=1)


        byte_counter = Signal(17, reset_less=True) # up to 64k + 1
        byte_counter_reset = Signal()
        byte_counter_ce = Signal()
        self.sync.usb_12 += \
            If(byte_counter_reset,
                byte_counter.eq(0)
            ).Elif(byte_counter_ce,
                byte_counter.eq(byte_counter + 1)
            )

        burst_counter = Signal(7, reset_less=True) # up to 64 + 1
        burst_counter_ce = Signal()
        self.sync.usb_12 += \
            If(usb_core.start,
                burst_counter.eq(0)
            ).Elif(burst_counter_ce,
                burst_counter.eq(burst_counter + 1)
            )

        self.address = address = Signal(32, reset_less=True)
        address_ce = Signal()
        address_inc = Signal()

        self.length = length = Signal(16, reset_less=True)
        length_ce = Signal()

        self.data = data = Signal(32)
        self.rd_data = Signal(32)
        rx_data_ce = Signal()

        self.sync.usb_12 += [
            If(cmd_ce, cmd.eq(usb_core.data_recv_payload[7:8])),
            If(address_ce,
                address.eq(Cat(address[8:32], usb_core.data_recv_payload)),
            ),
            If(length_ce, length.eq(Cat(length[8:16],usb_core.data_recv_payload))),
            If(rx_data_ce,
                data.eq(Cat(data[8:32], usb_core.data_recv_payload))
            )
        ]

        # Add a bridge to allow this module (in the usb_12 domain) to access
        # the main Wishbone bridge (potentially in some other domain).
        # Ensure this bridge is placed in the "sys" domain.
        self.cmd_sys = cmd_sys = Signal()
        self.specials += MultiReg(cmd, cmd_sys)
        prefetch_go = Signal()
        prefetch_go_sys = Signal()
        self.specials += MultiReg(prefetch_go, prefetch_go_sys)

        ### cross clock domains using a FIFO. also makes burst access possible.
        self.submodules.write_fifo = ClockDomainsRenamer({"write": "usb_12", "read": "sys"})(AsyncFIFOBuffered(width=32, depth=64//4))
        self.submodules.read_fifo = ClockDomainsRenamer({"write": "sys", "read": "usb_12"})(AsyncFIFOBuffered(width=32, depth=64//4))
        self.comb += [
            # clk12 domain
            self.write_fifo.din.eq(data),      # data coming from USB interface
            self.rd_data.eq(self.read_fifo.dout),  # data going to USB interface
            # sys domain
            self.read_fifo.din.eq(self.wishbone.dat_r),
            self.wishbone.dat_w.eq(self.write_fifo.dout),
        ]

        self.submodules.address_synchronizer = BusSynchronizer(32, "usb_12", "sys")
        self.comb += self.address_synchronizer.i.eq(self.address),
        self.submodules.length_synchronizer = BusSynchronizer(16, "usb_12", "sys")
        self.length_sys = Signal(16)
        self.comb += [self.length_synchronizer.i.eq(self.length), self.length_sys.eq(self.length_synchronizer.o)]

        self.burstcount = Signal(16)
        addr_to_wb = Signal(32)
        self.sync += addr_to_wb.eq(self.address_synchronizer.o + self.burstcount) # must register this to meet timing
        self.comb += self.wishbone.adr.eq(addr_to_wb[2:])

        self.comb += self.wishbone.cti.eq(0),  # classic cycle

        wbmanager = FSM(reset_state="IDLE") # in sys domain
        self.submodules += wbmanager
        wbmanager.act("IDLE",
            NextValue(self.burstcount, 0),
            If(prefetch_go_sys & cmd_sys,  # 0xC3 (bit set) == read
                NextState("READER")
            ).Elif(prefetch_go_sys & ~cmd_sys,
                NextState("WRITER")
            ),
            If(self.write_fifo.readable, # clear entries in write fifo in case of e.g. error condition or previous abort
                self.write_fifo.re.eq(1),
            )
        )
        wb_cyc = Signal()
        self.comb += self.wishbone.cyc.eq(wb_cyc) # & ~(self.wishbone.ack | self.wishbone.err)) # not needed, but a reminder
        wbmanager.act("READER",
            If(self.burstcount < self.length_sys,
                If(self.read_fifo.writable,
                    NextValue(self.wishbone.stb, 1),
                    NextValue(self.wishbone.we, 0),
                    NextValue(wb_cyc, 1),
                    NextState("READER_WAIT")
                )
            ).Else(
                NextState("WAIT_DONE")
            )
        )
        wbmanager.act("READER_WAIT",
            If(self.wishbone.ack | self.wishbone.err,
                NextValue(self.wishbone.stb, 0),
                NextValue(wb_cyc, 0),
                self.read_fifo.we.eq(1),
                NextValue(self.burstcount, self.burstcount + 4),
                NextState("READER_ADDR_WAIT"),
            )
        )
        wbmanager.act("READER_ADDR_WAIT",
                # one cycle dead state to allow the burst count address to propagate
                NextState("READER")
        )
        wbmanager.act("WRITER",
            If(self.burstcount < self.length_sys,
                If(self.write_fifo.readable,
                    NextValue(self.wishbone.stb, 1),
                    NextValue(self.wishbone.we, 1),
                    NextValue(wb_cyc, 1),
                    NextState("WRITER_WAIT"),
                )
            ).Else(
                NextState("WAIT_DONE")
            )
        )
        wbmanager.act("WRITER_WAIT",
            If(self.wishbone.ack | self.wishbone.err,
                NextValue(self.wishbone.stb, 0),
                NextValue(self.wishbone.we, 0),
                NextValue(wb_cyc, 0),
                self.write_fifo.re.eq(1),
                NextValue(self.burstcount, self.burstcount + 4),
                NextState("WRITER")
            )
        )
        wbmanager.act("WAIT_DONE",
            If(~prefetch_go_sys,
                NextState("IDLE")
            )
        )
        self.comb += self.wishbone.sel.eq(2 ** len(self.wishbone.sel) - 1)



        not_first_byte=Signal()
        
        fsm = ResetInserter()(ClockDomainsRenamer("usb_12")(FSM(reset_state="IDLE")))
        self.submodules += fsm
        fsm.act("IDLE",
            NextValue(prefetch_go, 0),
            NextValue(not_first_byte, 0),
            NextValue(self.data_phase, 0),
            self.n_debug_in_progress.eq(1),
            # drain any excess entries in read FIFO, in case we are recovering from e.g. an error condition
            If(self.read_fifo.readable,
                self.read_fifo.re.eq(1),
            ),
            If(usb_core.data_recv_put,
                If(usb_core.tok == PID.SETUP,
                    If(usb_core.endp == 0,
                        # If we get a SETUP packet with a "Vendor" type
                        # going to this device, treat that as a DEBUG packet.
                        cmd_ce.eq(1),
                        byte_counter_reset.eq(1),
                        If(usb_core.data_recv_payload[0:7] == magic_packet,
                            NextState("RECEIVE_ADDRESS"),
                        ).Else(
                            # Wait for the end of the packet, to avoid
                            # messing with normal USB operation
                            NextState("WAIT_PKT_END"),
                        ),
                    )
                )
            )
        )

        # The target address comes as the wValue and wIndex in the SETUP
        # packet.  Once we get that data, we're ready to do the operation.
        fsm.act("RECEIVE_ADDRESS",
            self.n_debug_in_progress.eq(0),
            If(usb_core.data_recv_put,
                byte_counter_ce.eq(1),
                If((byte_counter >= 1),
                    If((byte_counter <= 4),
                        address_ce.eq(1),
                    ).Elif((byte_counter <= 6),
                        length_ce.eq(1),
                    )
                ),
            ),
            If(byte_counter == 8,
                NextValue(prefetch_go, 1),
            ),
            # We don't need to explicitly ACK the SETUP packet, because
            # they're always acknowledged implicitly.  Wait until the
            # packet ends (i.e. until we've sent the ACK packet) before
            # moving to the next state.
            If(usb_core.end,
                byte_counter_reset.eq(1),
                If(cmd,
                    NextState("READ_DATA"),
                ).Else(
                    NextState("RECEIVE_DATA"),
                ),
            ),
        )

        #################### WRITE MACHINE

        fsm.act("RECEIVE_DATA",
            # Set the "ACK" bit to 1, so we acknowledge the packet
            # once it comes in, and so that we're in a position to
            # receive data.
            self.send_ack.eq(usb_core.endp == 0),
            self.n_debug_in_progress.eq(0),
            If(usb_core.endp == 0,
                If(usb_core.data_recv_put,
                    rx_data_ce.eq(1),
                    If(burst_counter < 64,
                       byte_counter_ce.eq(1),
                    ),
                    burst_counter_ce.eq(1),
                    If((burst_counter <= 64) & ((burst_counter & 3) == 0) & (burst_counter != 0),
                       self.write_fifo.we.eq(1),
                       address_inc.eq(1),
                    ),
                    If(byte_counter == (length - 1) | (((byte_counter & 0x3F) == 0x3F) & not_first_byte),
                        NextState("WAIT_RECEIVE_DATA_END"),
                    ).Elif(usb_core.end,
                        NextState("WRITE_DATA"),
                    )
                )
            )
        )
        fsm.act("WAIT_RECEIVE_DATA_END",
            self.n_debug_in_progress.eq(0),
            self.send_ack.eq(1),
            # Wait for the end of the USB packet, if
            # it hasn't come already.
            If(usb_core.end,
                self.write_fifo.we.eq(1),
                NextState("WRITE_DATA")
            )
        )

        fsm.act("WRITE_DATA",
            self.n_debug_in_progress.eq(0),
            If(self.write_fifo.writable,
                NextState("WAIT_SEND_ACK_START_WRITE"),
            )
        )

        fsm.act("WAIT_SEND_ACK_START_WRITE",
            self.n_debug_in_progress.eq(0),
            If(usb_core.start,
               NextState("SEND_ACK_WRITE")
            ),
        )

        # Send the ACK.  If the endpoint number is incorrect, go back and
        # wait again.
        fsm.act("SEND_ACK_WRITE",
            self.n_debug_in_progress.eq(0),
            If(usb_core.endp != 0,
                NextState("WAIT_SEND_ACK_START")
            ),
            self.send_ack.eq(usb_core.endp == 0),
            If(usb_core.end,
               If( byte_counter != length, 
                   NextValue(not_first_byte, 0),
                   NextValue(self.data_phase, ~self.data_phase),
                   NextState("RECEIVE_DATA"),
                ).Else(
                   NextState("IDLE"),
                )
            ),
        )

        ############### READ MACHINE

        fsm.act("READ_DATA",
            self.n_debug_in_progress.eq(0),
            If(self.read_fifo.readable,
                NextState("SEND_DATA_WAIT_START"),
            )
        )

        fsm.act("SEND_DATA_WAIT_START",
            self.n_debug_in_progress.eq(0),
            If(usb_core.start,
                NextState("SEND_DATA"),
            ),
        )
        fsm.act("SEND_DATA_BURST_WAIT",
            self.n_debug_in_progress.eq(0),
            self.sink_valid.eq(usb_core.endp == 0),
            If(self.read_fifo.readable,
               NextState("SEND_DATA"),
            )
        )
        self.sync.usb_12 += \
            chooser(self.rd_data, byte_counter[0:2], self.sink_data, n=4, reverse=False)
        fsm.act("SEND_DATA",
            self.n_debug_in_progress.eq(0),
            If(usb_core.endp != 0,
                NextState("SEND_DATA_WAIT_START"),
            ),
            # Keep sink_valid high during the packet, which indicates we have data
            # to send.  This also causes an "ACK" to be transmitted.
            self.sink_valid.eq(usb_core.endp == 0),
            If(usb_core.data_send_get,
                NextValue(not_first_byte, 1),
                byte_counter_ce.eq(1),
                If( ((byte_counter & 3) == 3) & ((byte_counter + 1) != length),
                    self.read_fifo.re.eq(1), # advance the read fifo by one position
                    address_inc.eq(1),
                    NextState("SEND_DATA_BURST_WAIT"),
                )
            ),
            If( (byte_counter == length) | (((byte_counter & 0x3F) == 0x00) & not_first_byte),
                NextState("WAIT_SEND_ACK_START")
            ),
            If(usb_core.end,
                NextState("WAIT_SEND_ACK_START")
            )
        )

        # To validate the transaction was successful, the host will now
        # send an "IN" request.  Acknowledge that by setting
        # self.send_ack, without putting anything in self.sink_data.
        fsm.act("WAIT_SEND_ACK_START",
            self.n_debug_in_progress.eq(0),
            If(usb_core.start,
               NextState("SEND_ACK")
            ),
            If(usb_core.end & (byte_counter != length),
               #byte_counter_ce.eq(1),
                #address_inc.eq(1),
               NextValue(not_first_byte, 0),
               NextValue(self.data_phase, ~self.data_phase),
               NextState("READ_DATA"),
            ),
        )

        # Send the ACK.  If the endpoint number is incorrect, go back and
        # wait again.
        fsm.act("SEND_ACK",
            self.n_debug_in_progress.eq(0),
            If(usb_core.endp != 0,
                NextState("WAIT_SEND_ACK_START")
            ),
            # If(usb_core.retry,
            #     If(cmd,
            #         byte_counter_reset.eq(1),
            #         NextState("SEND_DATA"),
            #     ),
            # ),
            self.send_ack.eq(usb_core.endp == 0),
            If(usb_core.end,
                self.read_fifo.re.eq(1), # drain the last entry in the read fifo
                NextState("IDLE"),
            )
        )

        fsm.act("WAIT_PKT_END",
            self.n_debug_in_progress.eq(1),
            If(usb_core.end,
                NextState("IDLE"),
            )
        )
Пример #13
0
    def __init__(self, hostif, mem_size):
        width = flen(hostif.d_write)
        assert width == 16

        self.start = Signal()
        self.sel_test = Signal(4)
        self.busy = Signal()

        self.lat_test = Signal(4)

        self.ok = Signal()

        self.status = Signal()

        self.submodules.fsm = FSM()
        self.comb += self.busy.eq(~self.fsm.ongoing("IDLE"))
        pat = Signal(width)

        self.lfsr = Signal(32)

        self.sync += [
            If(
                self.fsm.ongoing("IDLE") & self.start,
                self.lat_test.eq(self.sel_test),
                self.ok.eq(1),
            ).Elif((self.fsm.ongoing("WAIT_ISSUE_READ")
                    | self.fsm.ongoing("READ")) & hostif.d_stb &
                   (hostif.d_read != pat), self.ok.eq(0))
        ]

        # Address calculation
        self.addr = Signal(max=mem_size)

        reset_addr = Signal()
        self.sync += If(
            reset_addr,
            self.addr.eq(0),
        ).Elif(hostif.d_stb, self.addr.eq(self.addr + 1))

        # Pattern selection

        if (flen(self.addr) >= 2 * width):
            addr_ext = self.addr
        else:
            addr_ext = Cat(self.addr, Replicate(0,
                                                2 * width - flen(self.addr)))

        self.comb += [
            Case(
                self.lat_test,
                {
                    TEST_ALT0: pat.eq(Replicate(self.addr[0], width)),
                    TEST_ALT1: pat.eq(Replicate(self.addr[0], width) ^ 0xAAAA),
                    TEST_LFSR: pat.eq(0),  # STUB
                    TEST_ADDR:
                    pat.eq(addr_ext[:width] ^ addr_ext[width:width * 2]),
                    TEST_ZERO: pat.eq(0),
                    TEST_ONES: pat.eq(0xFFFF)
                }),
            hostif.d_write.eq(pat)
        ]

        lastaddr = self.addr == (mem_size - 1)

        self.fsm.act(
            "IDLE", If(self.start, reset_addr.eq(1),
                       NextState("WAIT_ISSUE_WR")))

        self.fsm.act("WAIT_ISSUE_WR", hostif.i_wr.eq(1), hostif.i_stb.eq(1),
                     hostif.i_addr.eq(0), If(hostif.i_ack, NextState("WRITE")))

        self.fsm.act("WRITE",
                     If(lastaddr & hostif.d_stb, NextState("WRITE-TERM")))

        self.fsm.act(
            "WRITE-TERM", hostif.d_term.eq(1),
            If(hostif.d_stb, reset_addr.eq(1), NextState("WAIT_ISSUE_READ")))

        self.fsm.act("WAIT_ISSUE_READ", hostif.i_wr.eq(0), hostif.i_stb.eq(1),
                     hostif.i_addr.eq(0), If(hostif.i_ack, NextState("READ")))
        self.fsm.act("READ", If(lastaddr & hostif.d_stb,
                                NextState("READ-TERM")))
        self.fsm.act("READ-TERM", hostif.d_term.eq(1),
                     If(hostif.d_stb, NextState("IDLE")))
Пример #14
0
    def __init__(self, pack_factor):
        hbits_dyn = _hbits - log2_int(pack_factor)
        timing_layout = [("hres", hbits_dyn), ("hsync_start", hbits_dyn),
                         ("hsync_end", hbits_dyn), ("hscan", hbits_dyn),
                         ("vres", _vbits), ("vsync_start", _vbits),
                         ("vsync_end", _vbits), ("vscan", _vbits)]
        self.timing = Sink(timing_layout)
        self.pixels = Sink(pixel_layout(pack_factor))
        self.phy = Source(phy_layout(pack_factor))
        self.busy = Signal()

        ###

        hactive = Signal()
        vactive = Signal()
        active = Signal()

        hcounter = Signal(hbits_dyn)
        vcounter = Signal(_vbits)

        skip = bpc - bpc_phy
        self.comb += [
            active.eq(hactive & vactive),
            If(active, [
                getattr(getattr(self.phy.payload, p), c).eq(
                    getattr(getattr(self.pixels.payload, p), c)[skip:])
                for p in ["p" + str(i) for i in range(pack_factor)]
                for c in ["y", "cb_cr"]
            ], self.phy.de.eq(1)),
            self.pixels.ack.eq(self.phy.ack & active)
        ]

        load_timing = Signal()
        tr = Record(timing_layout)
        self.sync += If(load_timing, tr.eq(self.timing.payload))

        generate_en = Signal()
        generate_frame_done = Signal()
        self.sync += [
            generate_frame_done.eq(0),
            If(
                generate_en, hcounter.eq(hcounter + 1),
                If(hcounter == 0, hactive.eq(1)),
                If(hcounter == tr.hres, hactive.eq(0)),
                If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)),
                If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)),
                If(
                    hcounter == tr.hscan, hcounter.eq(0),
                    If(vcounter == tr.vscan, vcounter.eq(0),
                       generate_frame_done.eq(1)).Else(
                           vcounter.eq(vcounter + 1))),
                If(vcounter == 0, vactive.eq(1)),
                If(vcounter == tr.vres, vactive.eq(0)),
                If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)),
                If(vcounter == tr.vsync_end, self.phy.vsync.eq(0)))
        ]

        self.submodules.fsm = FSM()
        self.fsm.act("GET_TIMING", self.timing.ack.eq(1), load_timing.eq(1),
                     If(self.timing.stb, NextState("GENERATE")))
        self.fsm.act(
            "GENERATE", self.busy.eq(1),
            If(~active | self.pixels.stb, self.phy.stb.eq(1),
               If(self.phy.ack, generate_en.eq(1))),
            If(generate_frame_done, NextState("GET_TIMING")))
Пример #15
0
    def __init__(self, usb_core, clk_freq=12000000, magic_packet=0x43):
        self.wishbone = wishbone.Interface()

        # # #

        byte_counter = Signal(3, reset_less=True)
        byte_counter_reset = Signal()
        byte_counter_ce = Signal()
        self.sync += \
            If(byte_counter_reset,
                byte_counter.eq(0)
            ).Elif(byte_counter_ce,
                byte_counter.eq(byte_counter + 1)
            )

        # Unlike the UART or Ethernet bridges, we explicitly only
        # support two commands: reading and writing.  This gets
        # integrated into the USB protocol, so it's not really a
        # state.  1 is "USB Device to Host", and is therefore a "read",
        # while 0 is "USB Host to Device", and is therefore a "write".
        cmd = Signal(1, reset_less=True)
        cmd_ce = Signal()

        # Instead of self.source and self.sink, we let the wrapping
        # module handle packing and unpacking the data.
        self.sink_data = Signal(8)

        # True when the "sink" value has data
        self.sink_valid = Signal()

        self.send_ack = Signal()

        # Indicates whether a "debug" packet is currently being processed
        self.n_debug_in_progress = Signal()

        address = Signal(32, reset_less=True)
        address_ce = Signal()

        data = Signal(32, reset_less=True)
        rx_data_ce = Signal()
        tx_data_ce = Signal()

        self.sync += [
            If(cmd_ce, cmd.eq(usb_core.data_recv_payload[7:8])),
            If(address_ce,
               address.eq(Cat(address[8:32], usb_core.data_recv_payload))),
            If(rx_data_ce, data.eq(Cat(data[8:32],
                                       usb_core.data_recv_payload))).Elif(
                                           tx_data_ce,
                                           data.eq(self.wishbone.dat_r))
        ]

        fsm = ResetInserter()(FSM(reset_state="IDLE"))
        self.submodules += fsm
        fsm.act(
            "IDLE",
            self.n_debug_in_progress.eq(1),
            If(
                usb_core.data_recv_put,
                If(
                    usb_core.tok == PID.SETUP,
                    If(
                        usb_core.endp == 0,
                        # If we get a SETUP packet with a "Vendor" type
                        # going to this device, treat that as a DEBUG packet.
                        cmd_ce.eq(1),
                        byte_counter_reset.eq(1),
                        If(
                            usb_core.data_recv_payload[0:7] == magic_packet,
                            NextState("RECEIVE_ADDRESS"),
                        ).Else(
                            # Wait for the end of the packet, to avoid
                            # messing with normal USB operation
                            NextState("WAIT_PKT_END"), ),
                    ))))

        # The target address comes as the wValue and wIndex in the SETUP
        # packet.  Once we get that data, we're ready to do the operation.
        fsm.act(
            "RECEIVE_ADDRESS",
            If(
                usb_core.data_recv_put,
                byte_counter_ce.eq(1),
                If(
                    (byte_counter >= 1),
                    If(
                        (byte_counter <= 4),
                        address_ce.eq(1),
                    ),
                ),
            ),
            # We don't need to explicitly ACK the SETUP packet, because
            # they're always acknowledged implicitly.  Wait until the
            # packet ends (i.e. until we've sent the ACK packet) before
            # moving to the next state.
            If(
                usb_core.end,
                byte_counter_reset.eq(1),
                If(cmd,
                   NextState("READ_DATA")).Else(NextState("RECEIVE_DATA")),
            ),
        )

        fsm.act(
            "RECEIVE_DATA",
            # Set the "ACK" bit to 1, so we acknowledge the packet
            # once it comes in, and so that we're in a position to
            # receive data.
            If(
                usb_core.endp == 0,
                self.send_ack.eq(1),
                If(
                    usb_core.data_recv_put,
                    rx_data_ce.eq(1),
                    byte_counter_ce.eq(1),
                    If(byte_counter == 3, NextState("WAIT_RECEIVE_DATA_END"),
                       byte_counter_reset.eq(1)).Elif(
                           usb_core.end,
                           # NextState("WAIT_SEND_ACK_START"),
                           NextState("WRITE_DATA"),
                           byte_counter_reset.eq(1)))))
        fsm.act(
            "WAIT_RECEIVE_DATA_END",
            self.send_ack.eq(1),
            # Wait for the end of the USB packet, if
            # it hasn't come already.
            If(
                usb_core.end,
                # NextState("WAIT_SEND_ACK_START")
                NextState("WRITE_DATA")))

        self.comb += [
            # Trim off the last two bits of the address, because wishbone addresses
            # are word-based, and a word is 32-bits.  Therefore, the last two bits
            # should always be zero.
            self.wishbone.adr.eq(address[2:]),
            self.wishbone.dat_w.eq(data),
            self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1)
        ]
        fsm.act(
            "WRITE_DATA", byte_counter_reset.eq(1), self.wishbone.stb.eq(1),
            self.wishbone.we.eq(1), self.wishbone.cyc.eq(1),
            If(
                self.wishbone.ack | self.wishbone.err,
                NextState("WAIT_SEND_ACK_START"),
            ))

        fsm.act(
            "READ_DATA", byte_counter_reset.eq(1), self.wishbone.stb.eq(1),
            self.wishbone.we.eq(0), self.wishbone.cyc.eq(1),
            If(self.wishbone.ack | self.wishbone.err, tx_data_ce.eq(1),
               NextState("SEND_DATA_WAIT_START")))

        fsm.act(
            "SEND_DATA_WAIT_START",
            byte_counter_reset.eq(1),
            If(
                usb_core.start,
                NextState("SEND_DATA"),
            ),
        )
        self.comb += \
            chooser(data, byte_counter, self.sink_data, n=4, reverse=False)
        fsm.act(
            "SEND_DATA",
            If(
                usb_core.endp == 0,
                # Keep sink_valid high during the packet, which indicates we have data
                # to send.  This also causes an "ACK" to be transmitted.
                self.sink_valid.eq(1),
                If(
                    usb_core.data_send_get,
                    byte_counter_ce.eq(1),
                ),
                If(byte_counter == 4, NextState("WAIT_SEND_ACK_START")),
                If(usb_core.end, NextState("WAIT_SEND_ACK_START"))).Else(
                    NextState("SEND_DATA_WAIT_START"), ))

        # To validate the transaction was successful, the host will now
        # send an "IN" request.  Acknowledge that by setting
        # self.send_ack, without putting anything in self.sink_data.
        fsm.act(
            "WAIT_SEND_ACK_START",
            If(
                usb_core.endp == 0, self.send_ack.eq(1),
                If(
                    usb_core.retry,
                    byte_counter_reset.eq(1),
                    NextState("SEND_DATA"),
                ).Elif(
                    usb_core.start,
                    NextState("WAIT_PKT_END_DBG"),
                )))
        fsm.act("WAIT_PKT_END_DBG", self.send_ack.eq(1),
                If(
                    usb_core.end,
                    NextState("IDLE"),
                ))

        fsm.act("WAIT_PKT_END", self.n_debug_in_progress.eq(1),
                If(
                    usb_core.end,
                    NextState("IDLE"),
                ))
Пример #16
0
    def __init__(self, cachesize, lasmim):
        self.wishbone = wishbone.Interface()

        ###

        data_width = flen(self.wishbone.dat_r)
        if lasmim.dw > data_width and (lasmim.dw % data_width) != 0:
            raise ValueError(
                "LASMI data width must be a multiple of {dw}".format(
                    dw=data_width))
        if lasmim.dw < data_width and (data_width % lasmim.dw) != 0:
            raise ValueError(
                "WISHBONE data width must be a multiple of {dw}".format(
                    dw=lasmim.dw))

        # Split address:
        # TAG | LINE NUMBER | LINE OFFSET
        offsetbits = log2_int(max(lasmim.dw // data_width, 1))
        addressbits = lasmim.aw + offsetbits
        linebits = log2_int(cachesize) - offsetbits
        tagbits = addressbits - linebits
        wordbits = log2_int(max(data_width // lasmim.dw, 1))
        adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits,
                                              linebits, tagbits)
        word = Signal(wordbits) if wordbits else None

        # Data memory
        data_mem = Memory(lasmim.dw * 2**wordbits, 2**linebits)
        data_port = data_mem.get_port(write_capable=True, we_granularity=8)
        self.specials += data_mem, data_port

        write_from_lasmi = Signal()
        write_to_lasmi = Signal()
        if adr_offset is None:
            adr_offset_r = None
        else:
            adr_offset_r = Signal(offsetbits)
            self.sync += adr_offset_r.eq(adr_offset)

        self.comb += [
            data_port.adr.eq(adr_line),
            If(write_from_lasmi, displacer(lasmim.dat_r, word,
                                           data_port.dat_w),
               displacer(Replicate(1, lasmim.dw // 8), word,
                         data_port.we)).Else(
                             data_port.dat_w.eq(
                                 Replicate(self.wishbone.dat_w,
                                           max(lasmim.dw // data_width, 1))),
                             If(
                                 self.wishbone.cyc & self.wishbone.stb
                                 & self.wishbone.we & self.wishbone.ack,
                                 displacer(self.wishbone.sel,
                                           adr_offset,
                                           data_port.we,
                                           2**offsetbits,
                                           reverse=True))),
            If(write_to_lasmi, chooser(data_port.dat_r, word, lasmim.dat_w),
               lasmim.dat_we.eq(2**(lasmim.dw // 8) - 1)),
            chooser(data_port.dat_r,
                    adr_offset_r,
                    self.wishbone.dat_r,
                    reverse=True)
        ]

        # Tag memory
        tag_layout = [("tag", tagbits), ("dirty", 1)]
        tag_mem = Memory(layout_len(tag_layout), 2**linebits)
        tag_port = tag_mem.get_port(write_capable=True)
        self.specials += tag_mem, tag_port
        tag_do = Record(tag_layout)
        tag_di = Record(tag_layout)
        self.comb += [
            tag_do.raw_bits().eq(tag_port.dat_r),
            tag_port.dat_w.eq(tag_di.raw_bits())
        ]

        self.comb += [tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag)]
        if word is not None:
            self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag))
        else:
            self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag))

        # Lasmim word computation, word_clr and word_inc will be simplified
        # at synthesis when wordbits=0
        word_clr = Signal()
        word_inc = Signal()
        if word is not None:
            self.sync += \
             If(word_clr,
              word.eq(0),
             ).Elif(word_inc,
              word.eq(word+1)
             )

        def word_is_last(word):
            if word is not None:
                return word == 2**wordbits - 1
            else:
                return 1

        # Control FSM
        assert (lasmim.write_latency >= 1 and lasmim.read_latency >= 1)
        fsm = FSM(reset_state="IDLE")
        self.submodules += fsm

        fsm.delayed_enter("EVICT_DATAD", "EVICT_DATA",
                          lasmim.write_latency - 1)
        fsm.delayed_enter("REFILL_DATAD", "REFILL_DATA",
                          lasmim.read_latency - 1)

        fsm.act(
            "IDLE",
            If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT")))
        fsm.act(
            "TEST_HIT", word_clr.eq(1),
            If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1),
               If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1)),
               NextState("IDLE")).Else(
                   If(tag_do.dirty, NextState("EVICT_REQUEST")).Else(
                       NextState("REFILL_WRTAG"))))

        fsm.act("EVICT_REQUEST", lasmim.stb.eq(1), lasmim.we.eq(1),
                If(lasmim.req_ack, NextState("EVICT_WAIT_DATA_ACK")))
        fsm.act("EVICT_WAIT_DATA_ACK",
                If(lasmim.dat_ack, NextState("EVICT_DATAD")))
        fsm.act(
            "EVICT_DATA", write_to_lasmi.eq(1), word_inc.eq(1),
            If(
                word_is_last(word),
                NextState("REFILL_WRTAG"),
            ).Else(NextState("EVICT_REQUEST")))

        fsm.act(
            "REFILL_WRTAG",
            # Write the tag first to set the LASMI address
            tag_port.we.eq(1),
            word_clr.eq(1),
            NextState("REFILL_REQUEST"))
        fsm.act("REFILL_REQUEST", lasmim.stb.eq(1),
                If(lasmim.req_ack, NextState("REFILL_WAIT_DATA_ACK")))
        fsm.act("REFILL_WAIT_DATA_ACK",
                If(lasmim.dat_ack, NextState("REFILL_DATAD")))
        fsm.act(
            "REFILL_DATA", write_from_lasmi.eq(1), word_inc.eq(1),
            If(
                word_is_last(word),
                NextState("TEST_HIT"),
            ).Else(NextState("REFILL_REQUEST")))
Пример #17
0
    def __init__(self, pads):
        self.background = ModuleDoc(
            """MemLCD: Driver for the SHARP Memory LCD model LS032B7DD02

        The LS032B7DD02 is a 336x536 pixel black and white memory LCD, with a 200ppi dot pitch.
        Memory LCDs can be thought of as 'fast E-ink displays that consume a tiny bit of standby
        power', as seen by these properties:

        * Extremely low standby power (30uW typ hold mode)
        * No special bias circuitry required to maintain image in hold mode
        * 120 degree viewing angle, 1:35 contrast ratio
        * All control logic fabricated on-glass using TFT devices that are auditable with
          a common 40x power desktop microscope and a bright backlight source

        This last property in particular makes the memory LCD extremely well suited for situations
        where absolute visibility into the construction of a secure enclave is desired.

        The memory organization of the LS032B7DD02 is simple: 536 lines of pixel data 336 wide.
        Each pixel is 1 bit (the display is black and white), and is fed into the module from
        left to right as pixels 1 through 336, inclusive. Lines are enumerated from top to bottom,
        from 1 to 536, inclusive.

        The LCD can only receive serial data. The protocol is a synchronous serial interface with
        an active high chip select. All data words are transmitted LSB first. A line transfer is
        initiated by sending a 6-bit mode selection, a 10-bit row address, and the subsequent 336
        pixels, followed by 16 dummy bits which transfer the data from the LCD holding register to
        the display itself.

            .. wavedrom::
                :caption: Single line data transfer to memory LCD

                { "signal": [
                    { "name": "SCLK", "wave": "0.P.......|......|...|..l." },
                    { "name": "SCS", "wave": "01........|......|...|.0.." },
                    { "name": "SI", "wave": "0===x..===|======|==x|....", "data": ["M0", "M1", "M2", "R0", "R1", " ", "R8", "R9", "D0", "D1", "D2", " ", "D334", "D335"] },
                    { "node": ".....................a.b..."},
                ],
                  "edge": ['a<->b 16 cycles']
                }

        Alternatively, one can send successive lines without dropping SCS by substituting the 16 dummy
        bits at the end with a 6-bit don't care preamble (where the mode bits would have been), 10 bits
        of row address, and then the pixel data.

            .. wavedrom::
              :caption: Multiple line data transfer to memory LCD

              { "signal": [
                    { "name": "SCLK", "wave": "0.P.......|......|...|....|....." },
                    { "name": "SCS", "wave": "01........|......|...|....|....." },
                    { "name": "SI", "wave": "0===x..===|======|==x|.===|=====", "data": ["M0", "M1", "M2", "R0", "R1", " ", "R8", "R9", "D0", "D1", "D2", " ", "D334", "D335", "R0", "R1", " ", "R8", "R9", "D0", "D1"] },
                    { "node": ".....................a.b..."},
              ],
                "edge": ['a<->b 6 cycles']
              }

        The very last line in the multiple line data transfer must terminate with 16 dummy cycles.

        Mode bits M0-M2 have the following meaning:
           M0: Set to 1 when transferring data lines. Set to 0 for hold mode, see below.
           M1: VCOM inversion flag. Ignore when hardware strap pin EXTMODE is high. Betrusted
               sets EXTMODE high, so the VCOM inversion is handled by low-power aux hardware.
               When EXTMODE is low, software must explicitly manage the VCOM inversion flag such the
               flag polarity changes once every second "as much as possible".
           M2: Normally set to 0. Set to 1 for all clear (see below)

        Data bit polarity:
           1 = White
           0 = Black

        For 'Hold mode' and 'All clear', a total of 16 cycles are sent, the first three being
        the mode bit and the last 13 being dummy cycles.

            .. wavedrom::
              :caption: Hold and all clear timings

              { "signal": [
                    { "name": "SCLK", "wave": "0.P...|.l" },
                    { "name": "SCS", "wave": "01....|0." },
                    { "name": "SI", "wave": "0===x...", "data": ["M0", "M1", "M2", "R0", "R1", " ", "R8", "R9", "D0", "D1", "D2", " ", "D334", "D335", "R0", "R1", " ", "R8", "R9", "D0", "D1"] },
                    { "node": ".....a.b..."},
              ],
                "edge": ['a<->b 13 cycles']
            }

        All signals are 3.0V compatible, 5V tolerant (VIH is 2.7V-VDD). The display itself requires
        a single 5V power supply (4.8-5.5V typ 5.8V abs max). In hold mode, typical power is 30uW, max 330uW;
        with data updating at 1Hz, power is 250uW, max 750uW (SCLK=1MHz, EXTCOMMIN=1Hz).

        * The maximum clock frequency for SCLK is 2MHz (typ 1MHz).
        * EXTCOMMIN frequency is 1-10Hz, 1Hz typ
        * EXTCOMMIN minimum high duration is 1us
        * All rise/fall times must be less than 50ns
        * SCS setup time is 3us, hold time is 1us. Minimum low duration is 1us,
          minimum high is 188us for a data update, 12 us for a hold mode operation.
        * SI setup time is 120ns, 190ns hold time.
        * Operating temperature is -20 to 70C, storage temperature -30 to 80C.
        """)

        self.interface = ModuleDoc("""Wishbone interface for MemLCD

        MemLCD maintains a local framebuffer for the LCD. The CPU can read and write
        to the frame buffer to update pixel data, and then request a screen update to
        commit the frame buffer to the LCD.

        Only full lines can be updated on a memory LCD; partial updates are not possible.
        In order to optimize the update process, MemLCD maintains a "dirty bit" associated
        with each line. Only lines with modified pixels are written to the screen after an
        update request.

        A line is 336 bits wide. When padded to 32-bit words, this yields a line width of
        44 bytes (0x2C, or 352 bits). In order to simplify math, the frame buffer rounds
        the line width up to the nearest power of two, or 64 bytes.

        The unused bits can be used as a "hint" to the MemLCD block as to which lines
        require updating. If the unused bits have any value other than 0, the MemLCD block
        will update those lines when an "UpdateDirty" command is triggered. It is up
        to the CPU to set and clear the dirty bits, they are not automatically cleared
        by the block upon update. Typically the clearing of the bits would be handled
        during the update-finished interrupt handling routine. If the dirty bits are
        not used, an "UpdateAll" command can be invoked, which will update every
        line of the LCD regardless of the contents of the dirty bits.

        The total depth of the memory is thus 44 bytes * 536 lines = 23,584 bytes or
        5,896 words.

        Pixels are stored with the left-most pixel in the MSB of each 32-bit word, with
        the left-most pixels occupying the lowest address in the line.

        Lines are stored with the bottom line of the screen at the lowest address.

        These parameters are chosen so that a 1-bit BMP file can be copied into the frame
        buffer and it will render directly to the screen with no further transformations
        required.

        The CPU is responsible for not writing data to the LCD while it is updating. Concurrent
        writes to the LCD during updates can lead to unpredictable behavior.
        """)
        data_width = 32
        width = 336
        height = 536
        bytes_per_line = 44

        self.fb_depth = fb_depth = height * bytes_per_line // (data_width // 8)
        pixdata = Signal(32)
        pixadr_rd = Signal(max=fb_depth)

        # 1 is white, which is the "off" state
        fb_init = [0xffffffff] * int(fb_depth)
        for i in range(fb_depth // 11):
            fb_init[i * 11 + 10] = 0xffff
        mem = Memory(
            32, fb_depth, init=fb_init
        )  # may need to round up to 8192 if a power of 2 is required by migen
        # read port for pixel data out
        self.specials.rdport = mem.get_port(
            write_capable=False,
            mode=READ_FIRST)  # READ_FIRST allows BRAM to be used
        self.comb += self.rdport.adr.eq(pixadr_rd)
        self.comb += pixdata.eq(self.rdport.dat_r)
        # implementation note: vivado will complain about being unable to merge an output register, leading to
        # non-optimal timing, but a check of the timing path shows that at 100MHz there is about 4-5ns of setup margin,
        # so the merge is unnecessary in this case. Ergo, prefer comb over sync to reduce latency.

        # memory-mapped write port to wishbone bus
        self.bus = wishbone.Interface()
        self.submodules.wb_sram_if = wishbone.SRAM(mem, read_only=False)
        decoder_offset = log2_int(fb_depth, need_pow2=False)

        def slave_filter(a):
            return a[decoder_offset:32 -
                     decoder_offset] == 0  # no aliasing in the block

        self.submodules.wb_con = wishbone.Decoder(
            self.bus, [(slave_filter, self.wb_sram_if.bus)], register=True)

        self.command = CSRStorage(
            2,
            fields=[
                CSRField(
                    "UpdateDirty",
                    description="Write a ``1`` to flush dirty lines to the LCD",
                    pulse=True),
                CSRField(
                    "UpdateAll",
                    description="Update full screen regardless of tag state",
                    pulse=True),
            ])

        self.busy = CSRStatus(
            1,
            name="Busy",
            description=
            """A ``1`` indicates that the block is currently updating the LCD"""
        )

        self.prescaler = CSRStorage(8,
                                    reset=99,
                                    name="prescaler",
                                    description="""
        Prescaler value. LCD clock is module (clock / (prescaler+1)). Reset value: 99, so
        for a default sysclk of 100MHz this yields an LCD SCLK of 1MHz""")

        self.submodules.ev = EventManager()
        self.ev.done = EventSourceProcess()
        self.ev.finalize()
        self.comb += self.ev.done.trigger.eq(
            self.busy.status)  # Fire an interupt when busy drops

        self.sclk = sclk = getattr(pads, "sclk")
        self.scs = scs = getattr(pads, "scs")
        self.si = si = getattr(pads, "si")
        self.sendline = sendline = Signal()
        self.linedone = linedone = Signal()
        updateall = Signal()
        fetch_dirty = Signal()
        update_line = Signal(
            max=height
        )  # Keep track of both line and address to avoid instantiating a multiplier
        update_addr = Signal(max=height * bytes_per_line)

        fsm_up = FSM(reset_state="IDLE")
        self.submodules += fsm_up

        fsm_up.act(
            "IDLE",
            If(
                self.command.fields.UpdateDirty
                | self.command.fields.UpdateAll,
                NextValue(self.busy.status, 1), NextValue(fetch_dirty, 1),
                If(self.command.fields.UpdateAll,
                   NextValue(updateall, 1)).Else(NextValue(updateall, 0)),
                NextState("START")).Else(NextValue(self.busy.status, 0)))
        fsm_up.act(
            "START",
            NextValue(update_line, height),
            NextValue(
                update_addr, (height - 1) * bytes_per_line
            ),  # Represents the byte address of the beginning of the last line
            NextState("FETCHDIRTY"))
        fsm_up.act(
            "FETCHDIRTY",  # Wait one cycle delay for the pixel data to be retrieved before evaluating it
            NextState("CHECKDIRTY"))
        fsm_up.act(
            "CHECKDIRTY",
            If(update_line == 0, NextState("IDLE")).Else(
                If(
                    (pixdata[16:] != 0) | updateall,
                    NextState("DIRTYLINE"),
                ).Else(NextValue(update_line, update_line - 1),
                       NextValue(update_addr, update_addr - bytes_per_line),
                       NextState("FETCHDIRTY"))))
        fsm_up.act("DIRTYLINE", NextValue(fetch_dirty, 0), sendline.eq(1),
                   NextState("WAITDONE"))
        fsm_up.act(
            "WAITDONE",
            If(linedone, NextValue(fetch_dirty, 1),
               NextValue(update_line, update_line - 1),
               NextValue(update_addr, update_addr - bytes_per_line),
               NextState("FETCHDIRTY")))

        modeshift = Signal(16)
        mode = Signal(6)
        pixshift = Signal(32)
        pixcount = Signal(max=width)
        bitreq = Signal()
        bitack = Signal()
        self.comb += mode.eq(
            1
        )  # Always in line write mode, not clearing, no vcom management necessary
        fsm_phy = FSM(reset_state="IDLE")
        self.submodules += fsm_phy
        # Update_addr units is in bytes. [2:] turns bytes to words
        # pixcount units are in pixels. [3:] turns pixels to bytes
        self.comb += [
            If(fetch_dirty, pixadr_rd.eq(
                (update_addr + bytes_per_line - 4)[2:])).Else(
                    pixadr_rd.eq((update_addr + pixcount[3:])[2:]))
        ]
        scs_cnt = Signal(max=200)
        fsm_phy.act(
            "IDLE",
            NextValue(si, 0),
            NextValue(linedone, 0),
            If(
                sendline,
                NextValue(scs, 1),
                NextValue(scs_cnt, 200),  # 2 us setup
                NextValue(pixcount, 16),
                NextValue(modeshift, Cat(mode, update_line)),
                NextState("SCS_SETUP")).Else(NextValue(scs, 0)))
        fsm_phy.act(
            "SCS_SETUP",
            If(scs_cnt > 0,
               NextValue(scs_cnt, scs_cnt - 1)).Else(NextState("MODELINE")))
        fsm_phy.act(
            "MODELINE",
            If(pixcount > 0, NextValue(modeshift, modeshift[1:]),
               NextValue(si, modeshift[0]), NextValue(pixcount, pixcount - 1),
               bitreq.eq(1),
               NextState("MODELINEWAIT")).Else(NextValue(pixcount, 1),
                                               NextValue(pixshift, pixdata),
                                               NextState("DATA")))
        fsm_phy.act("MODELINEWAIT", If(bitack, NextState("MODELINE")))
        fsm_phy.act(
            "DATA",
            If(
                pixcount < width + 17,
                If(
                    pixcount[0:5] == 0,
                    NextValue(pixshift, pixdata),
                ).Else(NextValue(pixshift, pixshift[1:]), ), NextValue(scs, 1),
                NextValue(si, pixshift[0]), NextValue(pixcount, pixcount + 1),
                bitreq.eq(1), NextState("DATAWAIT")).Else(
                    NextValue(si, 0),
                    NextValue(scs_cnt, 100),  # 1 us hold
                    NextState("SCS_HOLD")))
        fsm_phy.act(
            "SCS_HOLD",
            If(scs_cnt > 0, NextValue(scs_cnt, scs_cnt - 1)).Else(
                NextValue(scs, 0),
                NextValue(scs_cnt, 100),  # 1us minimum low time
                NextState("SCS_LOW")))
        fsm_phy.act(
            "SCS_LOW",
            If(scs_cnt > 0,
               NextValue(scs_cnt, scs_cnt - 1)).Else(NextValue(linedone, 1),
                                                     NextState("IDLE")))
        fsm_phy.act("DATAWAIT", If(bitack, NextState("DATA")))

        # This handles clock division
        fsm_bit = FSM(reset_state="IDLE")
        self.submodules += fsm_bit
        clkcnt = Signal(8)
        fsm_bit.act("IDLE", NextValue(sclk, 0),
                    NextValue(clkcnt, self.prescaler.storage),
                    If(bitreq, NextState("SCLK_LO")))
        fsm_bit.act(
            "SCLK_LO", NextValue(clkcnt, clkcnt - 1),
            If(clkcnt < self.prescaler.storage[1:], NextValue(sclk, 1),
               NextState("SCLK_HI")))
        fsm_bit.act(
            "SCLK_HI", NextValue(clkcnt, clkcnt - 1),
            If(clkcnt == 0, NextValue(sclk, 0), NextState("IDLE"),
               bitack.eq(1)))
Пример #18
0
 def parse_state(st, to, *update):
     sm.act(st, self.sink.ack.eq(1),
            If(self.sink.stb, NextState(to), *update))
Пример #19
0
	def __init__(self, ulpi, ulpi_reg):
		

		ulpi_data_out = Signal(8)
		ulpi_data_tristate = Signal()
		
		ulpi_data_next = Signal(8)
		ulpi_data_tristate_next = Signal()
		ulpi_stp_next = Signal()

		ulpi_state_rx = Signal()
		ulpi_state_rrd = Signal()
		
		self.data_out_source = Source(ULPI_DATA)

		RegWriteReqR = Signal()
		RegReadReqR = Signal()
		RegWriteReq = Signal()
		RegReadReq = Signal()
		RegReadAckSet = Signal()
		RegWriteAckSet = Signal()

		# register the reg read/write requests
		self.sync += RegReadReqR.eq(ulpi_reg.rreq)
		self.sync += RegWriteReqR.eq(ulpi_reg.wreq)
		
		# signal when read/write is requested but not done
		self.comb += RegReadReq.eq(RegReadReqR & ~ulpi_reg.rack)
		v = (RegReadReqR & ~ulpi_reg.rack)
		self.comb += RegWriteReq.eq(RegWriteReqR & ~ulpi_reg.wack)
		
		# ack logic: set ack=0 when req=0, set ack=1 when access done
		self.sync += If(~RegReadReqR, ulpi_reg.rack.eq(0)
			).Elif(RegReadAckSet, ulpi_reg.rack.eq(1))
		self.sync += If(~RegWriteReqR, ulpi_reg.wack.eq(0)
			).Elif(RegWriteAckSet, ulpi_reg.wack.eq(1))
			
		exp = If(~RegWriteReqR, ulpi_reg.wack.eq(0)).Elif(RegWriteAckSet, ulpi_reg.wack.eq(1))

		# output data if required by state
		self.comb += ulpi.stp.eq(ulpi_stp_next)
		self.comb += ulpi_data_out.eq(ulpi_data_next)
		self.comb += ulpi_data_tristate.eq(ulpi_data_tristate_next)
		self.comb += ulpi.do.eq(ulpi_data_out)
		self.comb += ulpi.doe.eq(~ulpi_data_tristate)
		


		# capture RX data at the end of RX, but only if no turnaround was requested
		# We also support "stuffing" data, to indicate conditions such as:
		#  - Simultaneous DIR + NXT assertion
		#	(the spec doesn't require an RXCMD - DIR+NXT asserting may be the'
		#	only SOP signal)
		#  - End-of-packet 
		#	(Packets may end without an RXCMD, unless an error occurs)
		ulpi_rx_stuff   = Signal()
		ulpi_rx_stuff_d = Signal(8)

		self.sync += self.data_out_source.stb.eq(ulpi_state_rx & ulpi.dir | ulpi_rx_stuff)
		self.sync += If(ulpi_rx_stuff, 
						self.data_out_source.payload.d.eq(ulpi_rx_stuff_d),
						self.data_out_source.payload.rxcmd.eq(1)
					 ).Else(
						If(~ulpi.nxt,
							self.data_out_source.payload.d.eq(ulpi.di & RXCMD_MASK),
							self.data_out_source.payload.rxcmd.eq(1)
						).Else(
							self.data_out_source.payload.d.eq(ulpi.di),
							self.data_out_source.payload.rxcmd.eq(0)
						)
					 )
		# capture register reads at the end of RRD
		self.sync += If(ulpi_state_rrd,ulpi_reg.rdata.eq(ulpi.di))

		fsm = FSM()
		self.submodules += fsm
		
		fsm.act("IDLE", 
			ulpi_data_next.eq(0x00), # NOOP
			ulpi_data_tristate_next.eq(0),
			ulpi_stp_next.eq(0),
			If(~ulpi.dir & ~ulpi.nxt & ~(RegWriteReq | RegReadReq), 
				NextState("IDLE")
			).Elif(ulpi.dir, # TA, and then either RXCMD or Data
				NextState("RX"),
				ulpi_data_tristate_next.eq(1),
				# If dir & nxt, we're starting a packet, so stuff a custom SOP
				If(ulpi.nxt,
					ulpi_rx_stuff.eq(1),
					ulpi_rx_stuff_d.eq(RXCMD_MAGIC_SOP)
				)
			).Elif(RegWriteReq,
				NextState("RW0"),
				ulpi_data_next.eq(0x80 | ulpi_reg.waddr), # REGW
				ulpi_data_tristate_next.eq(0),
				ulpi_stp_next.eq(0)
			).Elif(RegReadReq,
				NextState("RR0"),
				ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR
				ulpi_data_tristate_next.eq(0),
				ulpi_stp_next.eq(0)
			).Else(
				NextState("ERROR")
			))

		fsm.act("RX", 
			If(ulpi.dir, # stay in RX
				NextState("RX"),
				ulpi_state_rx.eq(1),
				ulpi_data_tristate_next.eq(1)
			).Else( # TA back to idle
				# Stuff an EOP on return to idle
				ulpi_rx_stuff.eq(1),
				ulpi_rx_stuff_d.eq(RXCMD_MAGIC_EOP),
				ulpi_data_tristate_next.eq(0), 
				NextState("IDLE")
			))
	
		fsm.act("RW0", 
			If(ulpi.dir,
				NextState("RX"),
				ulpi_data_tristate_next.eq(1),
			).Elif(~ulpi.dir,
				ulpi_data_next.eq(0x80 | ulpi_reg.waddr), # REGW
				ulpi_data_tristate_next.eq(0),
				ulpi_stp_next.eq(0),
				If(ulpi.nxt, NextState("RWD")).Else(NextState("RW0")),
			).Else(
				NextState("ERROR")
			))
		
		fsm.act("RWD",
			If(ulpi.dir,
				NextState("RX"),
				ulpi_data_tristate_next.eq(1)
			).Elif(~ulpi.dir & ulpi.nxt,
				NextState("RWS"),
				ulpi_data_next.eq(ulpi_reg.wdata),
				ulpi_data_tristate_next.eq(0),
				ulpi_stp_next.eq(0)
			).Else(
				NextState("ERROR")
			),
			)
		
		fsm.act("RWS",
			If(~ulpi.dir,
				NextState("IDLE"),
				ulpi_data_next.eq(0x00), # NOOP
				ulpi_data_tristate_next.eq(0),
				ulpi_stp_next.eq(1),
				RegWriteAckSet.eq(1)
			).Elif(ulpi.dir,
				NextState("RX"),
				ulpi_data_tristate_next.eq(1),
			),
			)
		
		fsm.act("RR0",
			If(~ulpi.dir,
				ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR
				NextState("RR1")
			).Elif(ulpi.dir,
				NextState("RX"),
				RegWriteAckSet.eq(1)
			).Else(
				NextState("ERROR")
			))
		
		fsm.act("RR1",
			If(~ulpi.dir & ulpi.nxt, # PHY accepts REGR
				ulpi_data_tristate_next.eq(1), # TA
				NextState("RR2")
			).Elif(~ulpi.dir & ~ulpi.nxt, # PHY delays REGR
				ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR
				NextState("RR1")
			).Elif(ulpi.dir,
				NextState("RX"),
				RegWriteAckSet.eq(1)
			).Else(
				NextState("ERROR")
			))
		
		fsm.act("RR2",
			ulpi_data_tristate_next.eq(1),
			If(~ulpi.nxt, # REGR continue
				NextState("RRD")
			).Elif(ulpi.dir, # PHY indicates RX
				NextState("RX"),
				RegWriteAckSet.eq(1)
			).Else(
				NextState("ERROR")
			))
		
		fsm.act("RRD",
			If(ulpi.dir & ~ulpi.nxt,
				NextState("IDLE"),
				RegReadAckSet.eq(1),
				ulpi_state_rrd.eq(1),
			).Elif(ulpi.dir & ulpi.nxt,
				NextState("RX"),
				RegWriteAckSet.eq(1)
			).Else(
				NextState("ERROR")
			),
				ulpi_data_tristate_next.eq(1),
			)

		fsm.act("ERROR", NextState("IDLE"))
Пример #20
0
    def __init__(self, geom_settings, timing_settings, controller_settings,
                 address_align, bankn, req):
        self.refresh_req = Signal()
        self.refresh_gnt = Signal()
        self.cmd = CommandRequestRW(geom_settings.addressbits,
                                    geom_settings.bankbits)

        ###

        # Request FIFO
        layout = [("we", 1), ("adr", len(req.adr))]
        req_in = Record(layout)
        reqf = Record(layout)
        self.submodules.req_fifo = SyncFIFO(layout_len(layout),
                                            controller_settings.req_queue_size)
        self.comb += [
            self.req_fifo.din.eq(req_in.raw_bits()),
            reqf.raw_bits().eq(self.req_fifo.dout)
        ]
        self.comb += [
            req_in.we.eq(req.we),
            req_in.adr.eq(req.adr),
            self.req_fifo.we.eq(req.stb),
            req.req_ack.eq(self.req_fifo.writable),
            self.req_fifo.re.eq(req.dat_w_ack | req.dat_r_ack),
            req.lock.eq(self.req_fifo.readable)
        ]

        slicer = _AddressSlicer(geom_settings.colbits, address_align)

        # Row tracking
        has_openrow = Signal()
        openrow = Signal(geom_settings.rowbits)
        hit = Signal()
        self.comb += hit.eq(openrow == slicer.row(reqf.adr))
        track_open = Signal()
        track_close = Signal()
        self.sync += [
            If(track_open, has_openrow.eq(1),
               openrow.eq(slicer.row(reqf.adr))),
            If(track_close, has_openrow.eq(0))
        ]

        # Address generation
        s_row_adr = Signal()
        self.comb += [
            self.cmd.ba.eq(bankn),
            If(s_row_adr, self.cmd.a.eq(slicer.row(reqf.adr))).Else(
                self.cmd.a.eq(slicer.col(reqf.adr)))
        ]

        # Respect write-to-precharge specification
        precharge_ok = Signal()
        t_unsafe_precharge = 2 + timing_settings.tWR - 1
        unsafe_precharge_count = Signal(max=t_unsafe_precharge + 1)
        self.comb += precharge_ok.eq(unsafe_precharge_count == 0)
        self.sync += [
            If(self.cmd.stb & self.cmd.ack & self.cmd.is_write,
               unsafe_precharge_count.eq(t_unsafe_precharge)).Elif(
                   ~precharge_ok,
                   unsafe_precharge_count.eq(unsafe_precharge_count - 1))
        ]

        # Control and command generation FSM
        fsm = FSM()
        self.submodules += fsm
        fsm.act(
            "REGULAR",
            If(self.refresh_req, NextState("REFRESH")).Elif(
                self.req_fifo.readable,
                If(
                    has_openrow,
                    If(
                        hit,
                        # NB: write-to-read specification is enforced by multiplexer
                        self.cmd.stb.eq(1),
                        req.dat_w_ack.eq(self.cmd.ack & reqf.we),
                        req.dat_r_ack.eq(self.cmd.ack & ~reqf.we),
                        self.cmd.is_read.eq(~reqf.we),
                        self.cmd.is_write.eq(reqf.we),
                        self.cmd.cas_n.eq(0),
                        self.cmd.we_n.eq(~reqf.we)).Else(
                            NextState("PRECHARGE"))).Else(
                                NextState("ACTIVATE"))))
        fsm.act(
            "PRECHARGE",
            # Notes:
            # 1. we are presenting the column address, A10 is always low
            # 2. since we always go to the ACTIVATE state, we do not need
            # to assert track_close.
            If(precharge_ok, self.cmd.stb.eq(1),
               If(self.cmd.ack, NextState("TRP")), self.cmd.ras_n.eq(0),
               self.cmd.we_n.eq(0), self.cmd.is_cmd.eq(1)))
        fsm.act("ACTIVATE", s_row_adr.eq(1), track_open.eq(1),
                self.cmd.stb.eq(1), self.cmd.is_cmd.eq(1),
                If(self.cmd.ack, NextState("TRCD")), self.cmd.ras_n.eq(0))
        fsm.act("REFRESH", self.refresh_gnt.eq(precharge_ok),
                track_close.eq(1), self.cmd.is_cmd.eq(1),
                If(~self.refresh_req, NextState("REGULAR")))
        fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP - 1)
        fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD - 1)
Пример #21
0
    def __init__(self, master, slave):
        dw_from = len(master.dat_r)
        dw_to = len(slave.dat_w)
        ratio = dw_from // dw_to

        # # #

        read = Signal()
        write = Signal()

        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)
            )
        counter_done = Signal()
        self.comb += counter_done.eq(counter == ratio - 1)

        # Main FSM
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE", counter_reset.eq(1),
            If(master.stb & master.cyc,
               If(master.we, NextState("WRITE")).Else(NextState("READ"))))
        fsm.act(
            "WRITE", write.eq(1), slave.we.eq(1), slave.cyc.eq(1),
            If(
                master.stb & master.cyc, slave.stb.eq(1),
                If(slave.ack, counter_ce.eq(1),
                   If(counter_done, master.ack.eq(1),
                      NextState("IDLE")))).Elif(~master.cyc,
                                                NextState("IDLE")))
        fsm.act(
            "READ", read.eq(1), slave.cyc.eq(1),
            If(
                master.stb & master.cyc, slave.stb.eq(1),
                If(slave.ack, counter_ce.eq(1),
                   If(counter_done, master.ack.eq(1),
                      NextState("IDLE")))).Elif(~master.cyc,
                                                NextState("IDLE")))

        # Address
        self.comb += [
            If(
                counter_done,
                slave.cti.eq(7)  # indicate end of burst
            ).Else(slave.cti.eq(2)),
            slave.adr.eq(Cat(counter, master.adr))
        ]

        # Datapath
        cases = {}
        for i in range(ratio):
            cases[i] = [
                slave.sel.eq(master.sel[i * dw_to // 8:(i + 1) * dw_to // 8]),
                slave.dat_w.eq(master.dat_w[i * dw_to:(i + 1) * dw_to])
            ]
        self.comb += Case(counter, cases)

        cached_data = Signal(dw_from)
        self.comb += master.dat_r.eq(Cat(cached_data[dw_to:], slave.dat_r))
        self.sync += \
            If(read & counter_ce,
                cached_data.eq(master.dat_r)
            )
Пример #22
0
    def __init__(self, data_width=32, div_width=8):
        # Number of bits to transfer - 1
        self.length = Signal(max=data_width)
        # Freescale CPHA
        self.clk_phase = Signal()

        # Combinatorial cs and clk signals to be registered
        # in Interface on ce
        self.clk_next = Signal()
        self.cs_next = Signal()
        self.ce = Signal()

        # No transfer is in progress
        self.idle = Signal()
        # When asserted and writiable, load register and start transfer
        self.load = Signal()
        # reg.pdi valid and all bits transferred
        # Asserted at the end of the last hold interval.
        # For one cycle (if the transfer completes the transaction) or
        # until load is asserted.
        self.readable = Signal()
        # Asserted before a transfer until the data has been loaded
        self.writable = Signal()
        # When asserted during load end the transaction with
        # this transfer.
        self.end = Signal()

        self.submodules.reg = reg = Register(data_width)
        self.submodules.cg = cg = ClockGen(div_width)

        ###

        # Bit counter
        n = Signal.like(self.length, reset_less=True)
        # Capture end for the in-flight transfer
        end = Signal(reset_less=True)

        self.comb += [self.ce.eq(cg.done & cg.count)]
        self.sync += [
            If(reg.load, n.eq(self.length), end.eq(self.end)),
            If(reg.shift, n.eq(n - 1))
        ]

        fsm = FSM("IDLE")
        self.submodules += fsm

        fsm.act(
            "IDLE", self.idle.eq(1), self.writable.eq(1), self.cs_next.eq(1),
            If(
                self.load, cg.count.eq(1), reg.load.eq(1),
                If(
                    self.clk_phase,
                    NextState("PRE"),
                ).Else(
                    cg.extend.eq(1),
                    NextState("SETUP"),
                )))
        fsm.act(
            "PRE",
            # dummy half cycle after asserting CS in CPHA=1
            self.cs_next.eq(1),
            cg.count.eq(1),
            cg.extend.eq(1),
            self.clk_next.eq(1),
            If(cg.done, NextState("SETUP")))
        fsm.act("SETUP", self.cs_next.eq(1), cg.count.eq(1),
                self.clk_next.eq(~self.clk_phase),
                If(cg.done, reg.sample.eq(1), NextState("HOLD")))
        fsm.act(
            "HOLD", self.cs_next.eq(1), cg.count.eq(1), cg.extend.eq(1),
            self.clk_next.eq(self.clk_phase),
            If(
                cg.done,
                If(
                    n == 0, self.readable.eq(1), self.writable.eq(1),
                    If(
                        end, self.clk_next.eq(0), self.writable.eq(0),
                        If(self.clk_phase, self.cs_next.eq(0),
                           NextState("WAIT")).Else(NextState("POST"))).Elif(
                               self.load, reg.load.eq(1),
                               NextState("SETUP")).Else(cg.count.eq(0))).Else(
                                   reg.shift.eq(1), NextState("SETUP"))))
        fsm.act(
            "POST",
            # dummy half cycle before deasserting CS in CPHA=0
            cg.count.eq(1),
            If(cg.done, NextState("WAIT")))
        fsm.act(
            "WAIT",
            # dummy half cycle to meet CS deassertion minimum timing
            If(cg.done, NextState("IDLE")).Else(cg.count.eq(1)))
Пример #23
0
    def __init__(self, cachesize, master, slave):
        self.master = master
        self.slave = slave

        # # #

        dw_from = len(master.dat_r)
        dw_to = len(slave.dat_r)
        if dw_to > dw_from and (dw_to % dw_from) != 0:
            raise ValueError(
                "Slave data width must be a multiple of {dw}".format(
                    dw=dw_from))
        if dw_to < dw_from and (dw_from % dw_to) != 0:
            raise ValueError(
                "Master data width must be a multiple of {dw}".format(
                    dw=dw_to))

        # Split address:
        # TAG | LINE NUMBER | LINE OFFSET
        offsetbits = log2_int(max(dw_to // dw_from, 1))
        addressbits = len(slave.adr) + offsetbits
        linebits = log2_int(cachesize) - offsetbits
        tagbits = addressbits - linebits
        wordbits = log2_int(max(dw_from // dw_to, 1))
        adr_offset, adr_line, adr_tag = split(master.adr, offsetbits, linebits,
                                              tagbits)
        word = Signal(wordbits) if wordbits else None

        # Data memory
        data_mem = Memory(dw_to * 2**wordbits, 2**linebits)
        data_port = data_mem.get_port(write_capable=True, we_granularity=8)
        self.specials += data_mem, data_port

        write_from_slave = Signal()
        if adr_offset is None:
            adr_offset_r = None
        else:
            adr_offset_r = Signal(offsetbits)
            self.sync += adr_offset_r.eq(adr_offset)

        self.comb += [
            data_port.adr.eq(adr_line),
            If(write_from_slave, displacer(slave.dat_r, word, data_port.dat_w),
               displacer(Replicate(1, dw_to // 8), word, data_port.we)).Else(
                   data_port.dat_w.eq(
                       Replicate(master.dat_w, max(dw_to // dw_from, 1))),
                   If(
                       master.cyc & master.stb & master.we & master.ack,
                       displacer(master.sel,
                                 adr_offset,
                                 data_port.we,
                                 2**offsetbits,
                                 reverse=True))),
            chooser(data_port.dat_r, word, slave.dat_w),
            slave.sel.eq(2**(dw_to // 8) - 1),
            chooser(data_port.dat_r, adr_offset_r, master.dat_r, reverse=True)
        ]

        # Tag memory
        tag_layout = [("tag", tagbits), ("dirty", 1)]
        tag_mem = Memory(layout_len(tag_layout), 2**linebits)
        tag_port = tag_mem.get_port(write_capable=True)
        self.specials += tag_mem, tag_port
        tag_do = Record(tag_layout)
        tag_di = Record(tag_layout)
        self.comb += [
            tag_do.raw_bits().eq(tag_port.dat_r),
            tag_port.dat_w.eq(tag_di.raw_bits())
        ]

        self.comb += [tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag)]
        if word is not None:
            self.comb += slave.adr.eq(Cat(word, adr_line, tag_do.tag))
        else:
            self.comb += slave.adr.eq(Cat(adr_line, tag_do.tag))

        # slave word computation, word_clr and word_inc will be simplified
        # at synthesis when wordbits=0
        word_clr = Signal()
        word_inc = Signal()
        if word is not None:
            self.sync += \
                If(word_clr,
                    word.eq(0),
                ).Elif(word_inc,
                    word.eq(word+1)
                )

        def word_is_last(word):
            if word is not None:
                return word == 2**wordbits - 1
            else:
                return 1

        # Control FSM
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE", If(master.cyc & master.stb, NextState("TEST_HIT")))
        fsm.act(
            "TEST_HIT", word_clr.eq(1),
            If(tag_do.tag == adr_tag, master.ack.eq(1),
               If(master.we, tag_di.dirty.eq(1), tag_port.we.eq(1)),
               NextState("IDLE")).Else(
                   If(tag_do.dirty,
                      NextState("EVICT")).Else(NextState("REFILL_WRTAG"))))

        fsm.act(
            "EVICT", slave.stb.eq(1), slave.cyc.eq(1), slave.we.eq(1),
            If(slave.ack, word_inc.eq(1),
               If(word_is_last(word), NextState("REFILL_WRTAG"))))
        fsm.act(
            "REFILL_WRTAG",
            # Write the tag first to set the slave address
            tag_port.we.eq(1),
            word_clr.eq(1),
            NextState("REFILL"))
        fsm.act(
            "REFILL", slave.stb.eq(1), slave.cyc.eq(1), slave.we.eq(0),
            If(
                slave.ack, write_from_slave.eq(1), word_inc.eq(1),
                If(
                    word_is_last(word),
                    NextState("TEST_HIT"),
                ).Else(NextState("REFILL"))))
Пример #24
0
    def __init__(self, sink_description, source_description, header):
        self.sink = sink = stream.Endpoint(sink_description)
        self.source = source = stream.Endpoint(source_description)
        self.header = Signal(header.length * 8)

        # # #

        # Parameters -------------------------------------------------------------------------------
        data_width = len(self.sink.data)
        bytes_per_clk = data_width // 8
        header_words = (header.length * 8) // data_width
        header_leftover = header.length % bytes_per_clk

        # Signals ----------------------------------------------------------------------------------
        sr = Signal(header.length * 8, reset_less=True)
        sr_load = Signal()
        sr_shift = Signal()
        count = Signal(max=max(header_words, 2))
        sink_d = stream.Endpoint(sink_description)

        # Header Encode/Load/Shift -----------------------------------------------------------------
        self.comb += header.encode(sink, self.header)
        self.sync += If(sr_load, sr.eq(self.header))
        if header_words != 1:
            self.sync += If(sr_shift, sr.eq(sr[data_width:]))

        # FSM --------------------------------------------------------------------------------------
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm_from_idle = Signal()
        fsm.act(
            "IDLE", sink.ready.eq(1), NextValue(count, 1),
            If(
                sink.valid, sink.ready.eq(0), source.valid.eq(1),
                source.last.eq(0), source.data.eq(self.header[:data_width]),
                If(
                    source.valid & source.ready, sr_load.eq(1),
                    NextValue(fsm_from_idle, 1),
                    If(
                        header_words == 1,
                        If(header_leftover != 0,
                           NextState("UNALIGNED-DATA-COPY")).Else(
                               NextState("ALIGNED-DATA-COPY"))).Else(
                                   NextState("HEADER-SEND")))))
        fsm.act(
            "HEADER-SEND", source.valid.eq(1), source.last.eq(0),
            source.data.eq(sr[min(data_width,
                                  len(sr) - 1):]),
            If(
                source.valid & source.ready, sr_shift.eq(1),
                If(
                    count == (header_words - 1), sr_shift.eq(0),
                    If(header_leftover, NextState("UNALIGNED-DATA-COPY"),
                       NextValue(count, count + 1)).Else(
                           NextState("ALIGNED-DATA-COPY"))).Else(
                               NextValue(count, count + 1), )))
        fsm.act(
            "ALIGNED-DATA-COPY", source.valid.eq(sink.valid),
            source.last.eq(sink.last), source.data.eq(sink.data),
            If(source.valid & source.ready, sink.ready.eq(1),
               If(source.last, NextState("IDLE"))))
        header_offset_multiplier = 1 if header_words == 1 else 2
        self.sync += If(source.ready, sink_d.eq(sink))
        fsm.act(
            "UNALIGNED-DATA-COPY", source.valid.eq(sink.valid | sink_d.last),
            source.last.eq(sink_d.last),
            If(
                fsm_from_idle, source.data[:max(header_leftover * 8, 1)].eq(
                    sr[min(header_offset_multiplier * data_width,
                           len(sr) - 1):])).Else(
                               source.data[:max(header_leftover * 8, 1)].eq(
                                   sink_d.data[min((bytes_per_clk -
                                                    header_leftover) *
                                                   8, data_width - 1):])),
            source.data[header_leftover * 8:].eq(sink.data),
            If(source.valid & source.ready, sink.ready.eq(~source.last),
               NextValue(fsm_from_idle, 0), If(source.last,
                                               NextState("IDLE"))))

        # Error ------------------------------------------------------------------------------------
        if hasattr(sink, "error") and hasattr(source, "error"):
            self.comb += source.error.eq(sink.error)

        # Last BE ----------------------------------------------------------------------------------
        if hasattr(sink, "last_be") and hasattr(source, "last_be"):
            rotate_by = header.length % bytes_per_clk
            x = [
                sink.last_be[(i + rotate_by) % bytes_per_clk]
                for i in range(bytes_per_clk)
            ]
            self.comb += source.last_be.eq(Cat(*x))
Пример #25
0
    def __init__(self, wrport, depth, consume_watermark, ena, la_filters=[]):
        self.ulpi_sink = Endpoint(ULPI_DATA_TAG)

        self.out_addr = Endpoint(dmatpl(depth))

        # Produce side
        self.submodules.produce_write = Acc_inc(max=depth)
        self.submodules.produce_header = Acc(max=depth)

        self.consume_point = Acc(max=depth)

        self.submodules.size = Acc_inc(16)
        self.submodules.flags = Acc_or(16)

        self.submodules.to_start = Acc(1)

        # Header format:
        # A0 F0 F1 SL SH 00 00 00 d0....dN

        # Flags format
        #
        # F0.0 - ERR  - Line level error (ULPI.RXERR asserted during packet)
        # F0.1 - OVF  - RX Path Overflow (shouldn't happen - debugging)
        # F0.2 - CLIP - Filter clipped (we do not set yet)
        # F0.3 - PERR - Protocol level err (but ULPI was fine, ???)
        #
        # Following not implemented yet
        # F0.6 - SHORT - short packet, no size, fixed 4 byte data
        # F0.7 - EXT   - Extended header
        self.submodules.fsm = FSM()

        has_space = Signal()

        self.comb += has_space.eq(
            ((consume_watermark - self.produce_write.v - 1) & (depth - 1)) > 8)

        # Grab packet timestamp at SOP
        pkt_timestamp = Signal(len(self.ulpi_sink.payload.ts))
        self.sync += If(self.ulpi_sink.payload.is_start & self.ulpi_sink.ack,
                        pkt_timestamp.eq(self.ulpi_sink.payload.ts))

        payload_is_rxcmd = Signal()
        self.comb += payload_is_rxcmd.eq(self.ulpi_sink.payload.is_start
                                         | self.ulpi_sink.payload.is_end
                                         | self.ulpi_sink.payload.is_err
                                         | self.ulpi_sink.payload.is_ovf)

        # Packet first/last bits
        clear_acc_flags = Signal()

        en_last = Signal()
        self.sync += en_last.eq(ena)
        self.submodules.packet_first = Acc(1)
        self.submodules.packet_last = Acc(1)

        # Stuff-packet bit
        # At start-of-capture or end-of-capture, we stuff a packet to
        # indicate the exact time of capture
        stuff_packet = Signal()
        self.comb += stuff_packet.eq(self.packet_first.v | self.packet_last.v)

        self.comb += If(ena & ~en_last, self.packet_first.set(1)).Elif(
            clear_acc_flags, self.packet_first.set(0))

        self.comb += If(~ena & en_last,
                        self.packet_last.set(1)).Elif(clear_acc_flags,
                                                      self.packet_last.set(0))

        flags_ini = Signal(16)
        self.comb += flags_ini.eq(
            Mux(self.packet_last.v, HF0_LAST, 0)
            | Mux(self.packet_first.v, HF0_FIRST, 0))

        # Combine outputs of filters
        la_resets = [f.reset.eq(1) for f in la_filters]
        filter_done = 1
        filter_reject = 0
        for f in la_filters:
            filter_done = f.done & filter_done
            filter_reject = f.reject | filter_reject

        self.fsm.act(
            "IDLE",
            If(((self.ulpi_sink.stb | self.to_start.v) & ena
                | stuff_packet) & has_space,
               If(~self.to_start.v | (self.ulpi_sink.stb & stuff_packet),
                  self.ulpi_sink.ack.eq(1)),
               self.produce_write.set(self.produce_header.v + 8),
               self.size.set(0), self.flags.set(flags_ini),
               self.to_start.set(0), la_resets,
               If(self.ulpi_sink.payload.is_start | self.to_start.v,
                  NextState("DATA")).Elif(
                      stuff_packet,
                      NextState("WH0"),
                      clear_acc_flags.eq(1),
                  )

               # If not enabled, we just dump RX'ed data
               ).Elif(~ena, self.ulpi_sink.ack.eq(1)))

        def write_hdr(statename, nextname, hdr_offs, val):
            self.fsm.act(statename, NextState(nextname),
                         wrport.adr.eq(self.produce_header.v + hdr_offs),
                         wrport.dat_w.eq(val), wrport.we.eq(1))

        do_filter_write = Signal()

        # Feed data to lookaside filters
        for f in la_filters:
            self.comb += [
                f.write.eq(do_filter_write),
                f.dat_w.eq(self.ulpi_sink.payload)
            ]

        packet_too_long = Signal()
        self.comb += packet_too_long.eq(self.size.v >= MAX_PACKET_SIZE)

        self.fsm.act(
            "DATA",
            If(packet_too_long, self.flags._or(HF0_TRUNC),
               NextState("WH0")).Elif(
                   has_space & self.ulpi_sink.stb,
                   self.ulpi_sink.ack.eq(1),
                   If(
                       payload_is_rxcmd,

                       # Got another start-of-packet
                       If(
                           self.ulpi_sink.payload.is_start,
                           self.flags._or(HF0_OVF),

                           # If we got a SOP, we need to skip RXCMD det in IDLE
                           self.to_start.set(1)

                           # Mark error if we hit an error
                       ).Elif(
                           self.ulpi_sink.payload.is_err,
                           self.flags._or(HF0_ERR),

                           # Mark overflow if we got a stuffed overflow
                       ).Elif(self.ulpi_sink.payload.is_ovf,
                              self.flags._or(HF0_OVF)),

                       # In any case (including END), we're done RXing
                       NextState("waitdone")).Else(
                           self.size.inc(), self.produce_write.inc(),
                           wrport.adr.eq(self.produce_write.v),
                           wrport.dat_w.eq(self.ulpi_sink.payload.d),
                           wrport.we.eq(1), do_filter_write.eq(1))))

        self.fsm.act(
            "waitdone",
            If(
                filter_done,
                If(filter_reject,
                   NextState("IDLE")).Else(clear_acc_flags.eq(1),
                                           NextState("WH0"))))

        write_hdr("WH0", "WRF0", 0, 0xA0)

        # Write flags field
        write_hdr("WRF0", "WRF1", 1, self.flags.v[:8])
        write_hdr("WRF1", "WRSL", 2, self.flags.v[8:16])

        # Write size field
        write_hdr("WRSL", "WRSH", 3, self.size.v[:8])
        write_hdr("WRSH", "WRTL", 4, self.size.v[8:16])

        write_hdr("WRTL", "WRTM", 5, pkt_timestamp[:8])
        write_hdr("WRTM", "WRTH", 6, pkt_timestamp[8:16])
        write_hdr("WRTH", "SEND", 7, pkt_timestamp[16:24])

        self.fsm.act(
            "SEND", self.out_addr.stb.eq(1),
            self.out_addr.payload.start.eq(self.produce_header.v),
            self.out_addr.payload.count.eq(self.size.v + 8),
            If(self.out_addr.ack,
               self.produce_header.set(self.produce_write.v),
               NextState("IDLE")))
Пример #26
0
    def __init__(self, sink_description, source_description, header):
        self.sink = sink = stream.Endpoint(sink_description)
        self.source = source = stream.Endpoint(source_description)
        self.header = Signal(header.length * 8)

        # # #

        # Parameters -------------------------------------------------------------------------------
        data_width = len(sink.data)
        bytes_per_clk = data_width // 8
        header_words = (header.length * 8) // data_width
        header_leftover = header.length % bytes_per_clk

        # Signals ----------------------------------------------------------------------------------
        sr = Signal(header.length * 8, reset_less=True)
        sr_shift = Signal()
        sr_shift_leftover = Signal()
        count = Signal(max=max(header_words, 2))
        sink_d = stream.Endpoint(sink_description)

        # Header Shift/Decode ----------------------------------------------------------------------
        if (header_words) == 1 and (header_leftover == 0):
            self.sync += If(sr_shift, sr.eq(sink.data))
        else:
            self.sync += [
                If(sr_shift, sr.eq(Cat(sr[bytes_per_clk * 8:], sink.data))),
                If(sr_shift_leftover,
                   sr.eq(Cat(sr[header_leftover * 8:], sink.data)))
            ]
        self.comb += self.header.eq(sr)
        self.comb += header.decode(self.header, source)

        # FSM --------------------------------------------------------------------------------------
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm_from_idle = Signal()
        fsm.act(
            "IDLE", sink.ready.eq(1), NextValue(count, 1),
            If(
                sink.valid, sr_shift.eq(1), NextValue(fsm_from_idle, 1),
                If(
                    header_words == 1,
                    If(header_leftover, NextState("UNALIGNED-DATA-COPY")).Else(
                        NextState("ALIGNED-DATA-COPY")),
                ).Else(NextState("HEADER-RECEIVE"))))
        fsm.act(
            "HEADER-RECEIVE", sink.ready.eq(1),
            If(
                sink.valid, NextValue(count, count + 1), sr_shift.eq(1),
                If(
                    count == (header_words - 1),
                    If(header_leftover, NextValue(count, count + 1),
                       NextState("UNALIGNED-DATA-COPY")).Else(
                           NextState("ALIGNED-DATA-COPY")))))
        self.sync += If(sink.valid & sink.ready, sink_d.eq(sink))
        fsm.act(
            "UNALIGNED-DATA-COPY", source.valid.eq(sink.valid | sink_d.last),
            source.last.eq(sink.last | sink_d.last),
            sink.ready.eq(source.ready),
            source.data.eq(sink_d.data[header_leftover * 8:]),
            source.data[min((bytes_per_clk - header_leftover) * 8, data_width -
                            1):].eq(sink.data),
            If(
                fsm_from_idle, source.valid.eq(sink_d.last), sink.ready.eq(1),
                If(
                    sink.valid,
                    NextValue(fsm_from_idle, 0),
                    sr_shift_leftover.eq(1),
                )),
            If(source.valid & source.ready, If(source.last,
                                               NextState("IDLE"))))
        fsm.act(
            "ALIGNED-DATA-COPY", source.valid.eq(sink.valid | sink_d.last),
            source.last.eq(sink.last | sink_d.last),
            sink.ready.eq(source.ready), source.data.eq(sink.data),
            If(source.valid & source.ready, If(source.last,
                                               NextState("IDLE"))))

        # Error ------------------------------------------------------------------------------------
        if hasattr(sink, "error") and hasattr(source, "error"):
            self.comb += source.error.eq(sink.error)

        # Last BE ----------------------------------------------------------------------------------
        if hasattr(sink, "last_be") and hasattr(source, "last_be"):
            x = [
                sink.last_be[(i - (bytes_per_clk - header_leftover)) %
                             bytes_per_clk] for i in range(bytes_per_clk)
            ]
            self.comb += source.last_be.eq(Cat(*x))
Пример #27
0
    def __init__(self, data_width, clock_width, bits_width):
        ce = CEInserter()
        self.submodules.cg = ce(SPIClockGen(clock_width))
        self.submodules.reg = ce(SPIRegister(data_width))
        self.submodules.bits = ce(SPIBitCounter(bits_width))
        self.div_write = Signal.like(self.cg.load)
        self.div_read = Signal.like(self.cg.load)
        self.clk_phase = Signal()
        self.start = Signal()
        self.cs = Signal()
        self.cs_next = Signal()
        self.oe = Signal()
        self.done = Signal()

        # # #

        fsm = CEInserter()(FSM("IDLE"))
        self.submodules += fsm

        fsm.act(
            "IDLE",
            If(
                self.start,
                If(
                    self.clk_phase,
                    NextState("WAIT"),
                ).Else(NextState("SETUP"), )))
        fsm.act(
            "SETUP",
            self.reg.sample.eq(1),
            NextState("HOLD"),
        )
        fsm.act(
            "HOLD",
            If(
                self.bits.done & ~self.start,
                If(
                    self.clk_phase,
                    NextState("IDLE"),
                ).Else(NextState("WAIT"), )).Else(
                    self.reg.shift.eq(~self.start),
                    NextState("SETUP"),
                ))
        fsm.act(
            "WAIT",
            If(
                self.bits.done,
                NextState("IDLE"),
            ).Else(NextState("SETUP"), ))

        write0 = Signal()
        read0 = Signal()
        self.sync += [
            If(
                self.cg.edge & self.reg.shift,
                write0.eq(self.bits.write),
                read0.eq(self.bits.read),
            ),
            If(
                self.cg.edge & fsm.before_entering("IDLE"),
                write0.eq(0),
                read0.eq(0),
            ),
        ]
        self.comb += [
            self.cg.ce.eq(self.start | self.cs | ~self.cg.edge),
            If(
                (read0 | self.bits.read) & ~self.bits.write,
                self.cg.load.eq(self.div_read),
            ).Else(self.cg.load.eq(self.div_write), ),
            self.cg.bias.eq(self.clk_phase),
            fsm.ce.eq(self.cg.edge),
            self.cs.eq(~fsm.ongoing("IDLE")),
            self.cs_next.eq(
                fsm.before_leaving("IDLE")
                | (self.cs & ~fsm.before_entering("IDLE"))),
            self.reg.ce.eq(self.cg.edge),
            self.bits.ce.eq(self.cg.edge & self.reg.sample),
            self.done.eq(self.cg.edge & self.bits.done & fsm.ongoing("HOLD")),
            self.oe.eq(write0 | self.bits.write),
        ]
Пример #28
0
    def __init__(self, pads, default=_default_edid):
        self._hpd_notif = CSRStatus()
        self._hpd_en = CSRStorage()
        self.specials.mem = Memory(8, 128, init=default)

        ###

        # HPD
        if hasattr(pads, "hpd_notif"):
            self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status)
        else:
            self.comb += self._hpd_notif.status.eq(1)
        if hasattr(pads, "hpd_en"):
            self.comb += pads.hpd_en.eq(self._hpd_en.storage)

        # EDID
        scl_raw = Signal()
        sda_i = Signal()
        sda_raw = Signal()
        sda_drv = Signal()
        _sda_drv_reg = Signal()
        _sda_i_async = Signal()
        self.sync += _sda_drv_reg.eq(sda_drv)
        self.specials += [
            MultiReg(pads.scl, scl_raw),
            Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
            MultiReg(_sda_i_async, sda_raw)
        ]

        scl_i = Signal()
        samp_count = Signal(6)
        samp_carry = Signal()
        self.sync += [
            Cat(samp_count, samp_carry).eq(samp_count + 1),
            If(samp_carry, scl_i.eq(scl_raw), sda_i.eq(sda_raw))
        ]

        scl_r = Signal()
        sda_r = Signal()
        scl_rising = Signal()
        sda_rising = Signal()
        sda_falling = Signal()
        self.sync += [scl_r.eq(scl_i), sda_r.eq(sda_i)]
        self.comb += [
            scl_rising.eq(scl_i & ~scl_r),
            sda_rising.eq(sda_i & ~sda_r),
            sda_falling.eq(~sda_i & sda_r)
        ]

        start = Signal()
        self.comb += start.eq(scl_i & sda_falling)

        din = Signal(8)
        counter = Signal(max=9)
        self.sync += [
            If(start, counter.eq(0)),
            If(
                scl_rising,
                If(counter == 8,
                   counter.eq(0)).Else(counter.eq(counter + 1),
                                       din.eq(Cat(sda_i, din[:7]))))
        ]

        is_read = Signal()
        update_is_read = Signal()
        self.sync += If(update_is_read, is_read.eq(din[0]))

        offset_counter = Signal(max=128)
        oc_load = Signal()
        oc_inc = Signal()
        self.sync += [
            If(oc_load, offset_counter.eq(din)).Elif(
                oc_inc, offset_counter.eq(offset_counter + 1))
        ]
        rdport = self.mem.get_port()
        self.specials += rdport
        self.comb += rdport.adr.eq(offset_counter)
        data_bit = Signal()

        zero_drv = Signal()
        data_drv = Signal()
        self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv,
                                                      sda_drv.eq(~data_bit))

        data_drv_en = Signal()
        data_drv_stop = Signal()
        self.sync += If(data_drv_en,
                        data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
        self.sync += If(
            data_drv_en,
            chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))

        fsm = FSM()
        self.submodules += fsm

        fsm.act("WAIT_START")
        fsm.act(
            "RCV_ADDRESS",
            If(
                counter == 8,
                If(din[1:] == 0x50, update_is_read.eq(1),
                   NextState("ACK_ADDRESS0")).Else(NextState("WAIT_START"))))
        fsm.act("ACK_ADDRESS0", If(~scl_i, NextState("ACK_ADDRESS1")))
        fsm.act("ACK_ADDRESS1", zero_drv.eq(1),
                If(scl_i, NextState("ACK_ADDRESS2")))
        fsm.act(
            "ACK_ADDRESS2", zero_drv.eq(1),
            If(~scl_i,
               If(is_read, NextState("READ")).Else(NextState("RCV_OFFSET"))))

        fsm.act("RCV_OFFSET",
                If(counter == 8, oc_load.eq(1), NextState("ACK_OFFSET0")))
        fsm.act("ACK_OFFSET0", If(~scl_i, NextState("ACK_OFFSET1")))
        fsm.act("ACK_OFFSET1", zero_drv.eq(1),
                If(scl_i, NextState("ACK_OFFSET2")))
        fsm.act("ACK_OFFSET2", zero_drv.eq(1),
                If(~scl_i, NextState("RCV_ADDRESS")))

        fsm.act(
            "READ",
            If(
                ~scl_i,
                If(counter == 8, data_drv_stop.eq(1),
                   NextState("ACK_READ")).Else(data_drv_en.eq(1))))
        fsm.act(
            "ACK_READ",
            If(scl_rising, oc_inc.eq(1),
               If(sda_i, NextState("WAIT_START")).Else(NextState("READ"))))

        for state in fsm.actions.keys():
            fsm.act(state, If(start, NextState("RCV_ADDRESS")))
            fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
Пример #29
0
    def __init__(self, sdram, clk_out, clk_sample, databits, rowbits, colbits,
                 bankbits, burst, tRESET, tCL, tRP, tRFC, tRCD, tREFI, tWR):

        addrbits = rowbits + colbits + bankbits
        assert sdram.dq.nbits == databits
        colabits = colbits if colbits <= 10 else colbits + 1
        max_col = Replicate(1, colbits)
        assert sdram.a.nbits >= colabits
        assert sdram.a.nbits >= rowbits
        assert sdram.ba.nbits == bankbits
        dqmbits = max(databits // 8, 1)
        assert sdram.dqm.nbits == dqmbits
        assert burst <= 1 << colbits

        self.hostif = Record(sdramHostIf(databits, addrbits))

        # DQ handling, tristate, and sampling
        dq = TSTriple(databits)
        self.specials += dq.get_tristate(sdram.dq)
        dq_r = Signal(databits)
        self.clock_domains.cd_sample = ClockDomain(reset_less=True)
        self.comb += self.cd_sample.clk.eq(clk_sample)
        self.sync.sample += dq_r.eq(dq.i)

        # Signals used for driving SDRAM control signals
        # These registered and derived from the current FSM state.
        # However, the reset state actually determines the default value for
        # states where they are not explicitly assigned. For example, cmd is
        # INHIBIT at reset (because the FSM is in RESET state at reset and that
        # sets cmd to INHIBIT), but it's NOP for every other state where it
        # isn't assigned.
        cmd = Signal(4, reset=NOP)
        dqm = Signal()
        ba = Signal(bankbits)
        a = Signal(max(colabits, rowbits))
        cke = Signal()

        sdram.cs_n.reset = 1
        self.sync += [
            sdram.dqm.eq(Replicate(dqm, dqmbits)),
            sdram.cs_n.eq(cmd[3]),
            sdram.ras_n.eq(cmd[2]),
            sdram.cas_n.eq(cmd[1]),
            sdram.we_n.eq(cmd[0]),
            sdram.ba.eq(ba),
            sdram.a.eq(a),
            sdram.cke.eq(cke),
        ]
        self.comb += [
            sdram.clk.eq(clk_out),
        ]

        # Counter to time reset cycle of the SDRAM
        # We enable CKE on the first cycle after system reset, then wait tRESET
        reset_ctr = Signal(max=tRESET + 1)
        self.sync += [cke.eq(1), reset_ctr.eq(reset_ctr + 1)]

        # Counter to time refresh intervals
        # Note that this can go higher than tREFI, since we might be in the
        # middle of a burst, but long-term refresh cycles will be issued often
        # enough to meet refresh timing.
        refresh_interval = tREFI - 2  # A bit of leeway for safety
        refresh_ctr = Signal(max=(refresh_interval + 2 * burst + 128))
        self.sync += If(
            cmd == AUTO_REFRESH,
            If(refresh_ctr > refresh_interval,
               refresh_ctr.eq(refresh_ctr - refresh_interval)).Else(
                   refresh_ctr.eq(0))).Else(refresh_ctr.eq(refresh_ctr + 1))

        tMRD = 3  # JEDEC spec, Micron only needs 2

        # Mode: Full page burst mode, burst write
        mode = 0b0000000111 | (tCL << 4)

        # last_col indicates that the read/write is about to wrap, and so should end
        last_col = Signal()
        i_col_cnt = Signal(colbits)
        self.comb += last_col.eq(i_col_cnt == max_col)

        def delay_clocks(v, d):
            for i in range(d):
                n = Signal()
                self.sync += n.eq(v)
                v = n
            return v

        # Read cycle state signals
        read_cycle = Signal()

        # Reads come back tCL + 1 clocks later. The extra two cycles
        # are due to the registration of FIFO outputs and inputs
        dq_r_sample = Signal(databits)
        self.sync += dq_r_sample.eq(dq_r)

        returning_read = delay_clocks(read_cycle, tCL + 2)
        can_continue_read = Signal()
        kill_read = Signal()
        self.comb += [
            can_continue_read.eq(~self.hostif.d_term & ~last_col & ~kill_read),
            self.hostif.d_read.eq(dq_r_sample),
        ]
        self.sync += [
            # If the output FIFO becomes full, kill the current read
            If(returning_read & self.hostif.d_term,
               kill_read.eq(1)).Elif(~returning_read, kill_read.eq(0)),
        ]

        # Write state signals
        write_cycle = Signal()
        can_continue_write = Signal()

        self.sync += [
            dq.o.eq(self.hostif.d_write),
            dq.oe.eq(write_cycle),
        ]

        self.comb += [
            can_continue_write.eq(~self.hostif.d_term & ~last_col),
            dqm.eq(self.hostif.d_term & write_cycle),
        ]

        # Shared signals
        cmd_needs_reissue = Signal()
        cmd_reissue = Signal()

        self.sync += [
            If(write_cycle | read_cycle, i_col_cnt.eq(i_col_cnt + 1)),
            If(
                ~self.hostif.d_term & last_col & write_cycle
                | read_cycle & last_col & ~kill_read
                & ~(returning_read & self.hostif.d_term),
                cmd_needs_reissue.eq(1)).Elif(cmd_reissue,
                                              cmd_needs_reissue.eq(0))
        ]

        # Hostif streaming interface signal generation
        self.comb += [
            self.hostif.d_stb.eq(write_cycle | returning_read & ~kill_read),
        ]

        # Address generation
        def split(addr):
            col = addr[:colbits]
            if colbits > 10:
                col = Cat(col[:10], 0, col[10:])
            return col, addr[colbits:colbits + rowbits], addr[colbits +
                                                              rowbits:]

        # Issued cmd ptr
        latch_cmd = Signal()
        iwr = Signal(1)
        iptr = Signal(addrbits)
        i_col, i_row, i_bank = split(iptr)

        self.sync += If(latch_cmd, iptr.eq(self.hostif.i_addr),
                        iwr.eq(self.hostif.i_wr),
                        i_col_cnt.eq(split(self.hostif.i_addr)[0])).Elif(
                            cmd_reissue, iptr[:colbits].eq(0),
                            iptr[colbits:].eq(iptr[colbits:] + 1),
                            i_col_cnt.eq(0))

        # Finite state machine driving the controller
        fsm = self.submodules.fsm = FSM(reset_state="RESET")

        # Initialization sequence
        fsm.act("RESET", cmd.eq(INHIBIT),
                If(reset_ctr == tRESET, NextState("INIT_IDLE")))
        fsm.delayed_enter("INIT_IDLE", "INIT_PRECHARGE", 5)
        fsm.act("INIT_PRECHARGE", cmd.eq(PRECHARGE), a[10].eq(1))
        fsm.delayed_enter("INIT_PRECHARGE", "INIT_REFRESH1", tRP)
        fsm.act("INIT_REFRESH1", cmd.eq(AUTO_REFRESH))
        fsm.delayed_enter("INIT_REFRESH1", "INIT_REFRESH2", tRFC)
        fsm.act("INIT_REFRESH2", cmd.eq(AUTO_REFRESH))
        fsm.delayed_enter("INIT_REFRESH2", "INIT_MODE", tRFC)
        fsm.act("INIT_MODE", cmd.eq(LOAD_MODE), a.eq(mode))
        fsm.delayed_enter("INIT_MODE", "IDLE", tMRD)

        # Main loop
        fsm.act(
            "IDLE",
            If(refresh_ctr >= refresh_interval, NextState("REFRESH")).Elif(
                cmd_needs_reissue, cmd_reissue.eq(1),
                If(iwr, NextState("WRITE_ACTIVE")).Else(
                    NextState("READ_ACTIVE"))).Elif(
                        self.hostif.i_wr & self.hostif.i_stb,
                        self.hostif.i_ack.eq(1), latch_cmd.eq(1),
                        NextState("WRITE_ACTIVE")).Elif(
                            ~self.hostif.i_wr & self.hostif.i_stb,
                            self.hostif.i_ack.eq(1), latch_cmd.eq(1),
                            NextState("READ_ACTIVE")))
        # REFRESH
        fsm.act("REFRESH", cmd.eq(AUTO_REFRESH))
        fsm.delayed_enter("REFRESH", "IDLE", tRFC)

        # WRITE
        fsm.act("WRITE_ACTIVE", cmd.eq(ACTIVE), ba.eq(i_bank), a.eq(i_row))
        fsm.delayed_enter("WRITE_ACTIVE", "WRITE", tRCD)
        fsm.act(
            "WRITE", cmd.eq(WRITE), ba.eq(i_bank), a.eq(i_col),
            write_cycle.eq(1),
            If(can_continue_write, NextState("WRITING")).Else(
                If(dqm,
                   NextState("PRECHARGE")).Else(NextState("PRECHARGE_TWR"))))
        fsm.act(
            "WRITING", write_cycle.eq(1),
            If(
                ~can_continue_write,
                If(dqm,
                   NextState("PRECHARGE")).Else(NextState("PRECHARGE_TWR"))))

        # READ
        fsm.act("READ_ACTIVE", cmd.eq(ACTIVE), ba.eq(i_bank), a.eq(i_row))
        fsm.delayed_enter("READ_ACTIVE", "READ", tRCD)
        fsm.act(
            "READ", cmd.eq(READ), ba.eq(i_bank), a.eq(i_col), read_cycle.eq(1),
            If(can_continue_read,
               NextState("READING")).Else(NextState("PRECHARGE")))
        fsm.act("READING", read_cycle.eq(1),
                If(~can_continue_read, NextState("PRECHARGE")))

        if (tWR - 1) > 0:
            fsm.act("PRECHARGE_TWR", cmd.eq(BURST_TERM))

        fsm.delayed_enter("PRECHARGE_TWR", "PRECHARGE", tWR - 1),
        fsm.act("PRECHARGE", cmd.eq(PRECHARGE), a[10].eq(1)),
        fsm.delayed_enter("PRECHARGE", "IDLE", tRP)
Пример #30
0
    def __init__(self, phy, clk_freq):
        self.wishbone = wishbone.Interface()

        # # #

        byte_counter = Signal(3)
        byte_counter_reset = Signal()
        byte_counter_ce = Signal()
        self.sync += \
            If(byte_counter_reset,
                byte_counter.eq(0)
            ).Elif(byte_counter_ce,
                byte_counter.eq(byte_counter + 1)
            )

        word_counter = Signal(3)
        word_counter_reset = Signal()
        word_counter_ce = Signal()
        self.sync += \
            If(word_counter_reset,
                word_counter.eq(0)
            ).Elif(word_counter_ce,
                word_counter.eq(word_counter + 1)
            )

        cmd = Signal(8)
        cmd_ce = Signal()

        length = Signal(8)
        length_ce = Signal()

        address = Signal(32)
        address_ce = Signal()

        data = Signal(32)
        rx_data_ce = Signal()
        tx_data_ce = Signal()

        self.sync += [
            If(cmd_ce, cmd.eq(phy.source.data)),
            If(length_ce, length.eq(phy.source.data)),
            If(address_ce, address.eq(Cat(phy.source.data, address[0:24]))),
            If(rx_data_ce,
               data.eq(Cat(phy.source.data,
                           data[0:24]))).Elif(tx_data_ce,
                                              data.eq(self.wishbone.dat_r))
        ]

        fsm = ResetInserter()(FSM(reset_state="IDLE"))
        timer = WaitTimer(clk_freq // 10)
        self.submodules += fsm, timer
        self.comb += [fsm.reset.eq(timer.done), phy.source.ack.eq(1)]
        fsm.act(
            "IDLE",
            If(
                phy.source.stb, cmd_ce.eq(1),
                If((phy.source.data == self.cmds["write"]) |
                   (phy.source.data == self.cmds["read"]),
                   NextState("RECEIVE_LENGTH")), byte_counter_reset.eq(1),
                word_counter_reset.eq(1)))
        fsm.act(
            "RECEIVE_LENGTH",
            If(phy.source.stb, length_ce.eq(1), NextState("RECEIVE_ADDRESS")))
        fsm.act(
            "RECEIVE_ADDRESS",
            If(
                phy.source.stb, address_ce.eq(1), byte_counter_ce.eq(1),
                If(
                    byte_counter == 3,
                    If(cmd == self.cmds["write"],
                       NextState("RECEIVE_DATA")).Elif(
                           cmd == self.cmds["read"], NextState("READ_DATA")),
                    byte_counter_reset.eq(1),
                )))
        fsm.act(
            "RECEIVE_DATA",
            If(
                phy.source.stb, rx_data_ce.eq(1), byte_counter_ce.eq(1),
                If(byte_counter == 3, NextState("WRITE_DATA"),
                   byte_counter_reset.eq(1))))
        self.comb += [
            self.wishbone.adr.eq(address + word_counter),
            self.wishbone.dat_w.eq(data),
            self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1)
        ]
        fsm.act(
            "WRITE_DATA", self.wishbone.stb.eq(1), self.wishbone.we.eq(1),
            self.wishbone.cyc.eq(1),
            If(
                self.wishbone.ack, word_counter_ce.eq(1),
                If(word_counter == (length - 1),
                   NextState("IDLE")).Else(NextState("RECEIVE_DATA"))))
        fsm.act(
            "READ_DATA", self.wishbone.stb.eq(1), self.wishbone.we.eq(0),
            self.wishbone.cyc.eq(1),
            If(self.wishbone.ack, tx_data_ce.eq(1), NextState("SEND_DATA")))
        self.comb += \
            chooser(data, byte_counter, phy.sink.data, n=4, reverse=True)
        fsm.act(
            "SEND_DATA", phy.sink.stb.eq(1),
            If(
                phy.sink.ack, byte_counter_ce.eq(1),
                If(
                    byte_counter == 3, word_counter_ce.eq(1),
                    If(word_counter == (length - 1),
                       NextState("IDLE")).Else(NextState("READ_DATA"),
                                               byte_counter_reset.eq(1)))))

        self.comb += timer.wait.eq(~fsm.ongoing("IDLE"))

        self.comb += phy.sink.eop.eq((byte_counter == 3)
                                     & (word_counter == length - 1))

        if hasattr(phy.sink, "length"):
            self.comb += phy.sink.length.eq(4 * length)