示例#1
0
    def __init__(self, size=(8, 8), min=0, max=8):
        """

        Arguments:
            size (tuple):
            min (int): the min value of the data contained in the
                matrix
            max (int)L the max value of the data contained in the
                matrix

        """
        assert isinstance(size, tuple)
        assert len(size) == 2
        self.size = size
        nrows, ncols = size
        self.nitems = nrows * ncols
        dtype = intbv(0, min=min, max=max)
        self.nbits = len(dtype)
        self.dtype = dtype

        self.mat = [Signals(dtype, ncols) for _ in range(nrows)]

        self.data = self.get_bit_vector()
        self.valid = Signal(bool(0))
        self.ready = Signal(bool(0))
示例#2
0
文件: fifo_cdc.py 项目: wingel/rhea
def fifo_cdc(glbl, emesh_i, emesh_o):
    """
    map the packet interfaces to the FIFO interface
    """

    wr, rd = Signals(bool(0), 2)
    fifo_intf = FIFOBus(width=len(emesh_i.bits))

    @always_comb
    def beh_assign():
        wr.next = emesh_i.access and not fifo_intf.full
        rd.next = not fifo_intf.empty and not emesh_i.wait
        emesh_o.wait.next = fifo_intf.full

    @always(emesh_o.clock.posedge)
    def beh_access():
        if not emesh_i.wait:
            emesh_o.access.next = fifo_intf.read

    # assign signals ot the FIFO interface
    fifo_intf.write_data = emesh_i.bits
    fifo_intf.read_data = emesh_o.bits

    fifo_inst = cores.fifo.fifo_async(clock_write=emesh_i.clock,
                                      clock_read=emesh_o.clock,
                                      fifobus=fifo_intf,
                                      reset=glbl.reset,
                                      size=16)

    return beh_assign, beh_access, fifo_inst
示例#3
0
    def __init__(self, size=8, min=0, max=8):
        """

        Arguments:
            size: the number of items to have in the block
            min: the data min value
            max: the data max value
        """
        self.size = size
        dtype = intbv(0, min=min, max=max)
        self.data = Signals(dtype, size)
        self.valid = Signal(bool(0))
        self.ready = Signal(bool(0))
示例#4
0
def spi_slave_fifo(glbl, spibus, fifobus):
    """
    This is an SPI slave peripheral, when the master starts clocking
    any data in the TX FIFO (fifobus.write) will be sent (the next
    byte) and the received byte will be copied to RX FIFO
    (fifobus.read).  The `cso` interface can be used to configure
    how the SPI slave peripheral behaves.

    (Arguments == Ports)
    Arguments:
        glbl (Global): global clock and reset
        spibus  (SPIBus): the external SPI interface
        fifobus (FIFOBus): the fifo interface
        cso (ControlStatus): the control status signals
    """
    fifosize = 8

    # Use an async FIFO to transfer from the SPI SCK clock domain and
    # the internal clock domain.  This allows for high-speed SCK.
    clock, reset = glbl.clock, glbl.reset
    assert isinstance(spibus, SPIBus)
    assert isinstance(fifobus, FIFOBus)

    sck, csn = spibus.sck, spibus.csn
    # the FIFOs for the receive and transmit (external perspective)
    readpath = FIFOBus(width=fifobus.width)
    writepath = FIFOBus(width=fifobus.width)

    # the FIFO instances
    tx_fifo_inst = fifo_fast(glbl, writepath, size=fifosize)
    rx_fifo_inst = fifo_fast(glbl, readpath, size=fifosize)
    mp_fifo_inst = fifobus.assign_read_write_paths(readpath, writepath)

    spi_start = Signal(bool(0))
    ireg, icap, icaps = Signals(intbv(0)[8:], 3)
    oreg, ocap = Signals(intbv(0)[8:], 2)
    bitcnt, b2, b3 = Signals(intbv(0, min=0, max=10), 3)

    @always(sck.posedge, csn.negedge)
    def csn_falls():
        if sck:
            spi_start.next = False
        elif not csn:
            spi_start.next = True

    # SCK clock domain, this allows high SCK rates
    @always(sck.posedge, csn.posedge)
    def sck_capture_send():
        if csn:
            b2.next = 0
            bitcnt.next = 0
        else:
            if bitcnt == 0 or spi_start:
                spibus.miso.next = ocap[7]
                oreg.next = (ocap << 1) & 0xFF
            else:
                spibus.miso.next = oreg[7]
                oreg.next = (oreg << 1) & 0xFF

            ireg.next = concat(ireg[7:0], spibus.mosi)
            bitcnt.next = bitcnt + 1
            if bitcnt == (8 - 1):
                bitcnt.next = 0
                b2.next = 8
                icap.next = concat(ireg[7:0], spibus.mosi)
            else:
                b2.next = 0

    # synchronize the SCK domain to the clock domain
    syncro(clock, icap, icaps)
    syncro(clock, b2, b3)

    gotit = Signal(bool(0))

    @always(clock.posedge)
    def beh_io_capture():
        # default no writes
        readpath.write.next = False
        writepath.read.next = False

        if b3 == 0:
            gotit.next = False
        elif b3 == 8 and not gotit:
            readpath.write.next = True
            readpath.write_data.next = icaps
            gotit.next = True
            ocap.next = writepath.read_data
            if not writepath.empty:
                writepath.read.next = True

    return myhdl.instances()
示例#5
0
    def process(self, skip_init=True):
        """
        @todo: documentation
        """
        intf = self.intf   # external SDRAM memory interface

        state = Signal(self.States.IDLE)
        cmdmn = Signal(self.Commands.NOP)

        Commands, States = self.Commands, self.States

        @instance
        def mproc():
            cmd = self.Commands.NOP
            refresh_counter = 0

            # emulate the initialization sequence / requirement
            if skip_init:
                pass  # don't do anything
            else:
                pass  # @todo: do init

            while True:
                # check the refresh counter
                if refresh_counter >= intf.cyc_ref:
                    # @todo: create specific exception for refresh error
                    raise ValueError
                refresh_counter += 1

                intf.dqi.next = None   # release the bi-dir bus (default)
                bs, addr = int(intf.bs), int(intf.addr)
                if intf.cke:
                    cmd = intf.get_command()

                    # @todo: need to add the device specific states
                    if cmd == Commands.NOP:
                        pass  # print("[SDRAM] nop commands")
                    elif cmd == Commands.ACT:
                        pass  # print("[SDRAM] ack commands")
                    elif cmd == Commands.WR:
                        # @todo look at the intf.dq bus and only get if valid
                        data = 0
                        if intf.dq is not None:
                            data = int(intf.dq)
                        assert intf.dq == intf.wdq
                        self.banks[bs][addr] = data
                    elif cmd == Commands.RD:
                        data = 0
                        if addr in self.banks[bs]:
                            data = self.banks[bs][addr]
                        intf.rdq.next = data
                        intf.dqi.next = data

                # this command, will always be one clock delayed
                cmdmn.next = cmd
                # synchronous RAM :)
                # @todo: if 'ddr' in intf.ver yield intf.clk.posedge, intf.clk.negedge
                yield intf.clk.posedge

        # in the model the following signals are not used in a generator.
        # The traceSignals will skip over these signals because it doesn't
        # think it is used.  Mirror the signals here so they are traced.
        cs, ras, cas, we = Signals(bool(0), 4)

        @always_comb
        def mon():
            cs.next = intf.cs
            ras.next = intf.ras
            cas.next = intf.cas
            we.next = intf.we

        return mproc, mon
示例#6
0
    def bench_command_bridge():
        tbclk = clock.gen()
        tbdut = command_bridge(glbl, fifobus, memmap)

        readpath, writepath = FIFOBus(), FIFOBus()
        readpath.clock = writepath.clock = clock
        tbmap = fifobus.assign_read_write_paths(readpath, writepath)
        tbftx = fifo_fast(glbl, writepath)   # user write path
        tbfrx = fifo_fast(glbl, readpath)    # user read path

        # @todo: add other bus types
        tbmem = memmap_peripheral_bb(clock, reset, memmap)

        # save the data read ...
        read_value = []

        @instance
        def tbstim():
            yield reset.pulse(32)
            fifobus.read.next = False
            fifobus.write.next = False
            assert not fifobus.full
            assert fifobus.empty
            assert fifobus.read_data == 0
            fifobus.write_data.next = 0

            try:
                # test a single address
                pkt = CommandPacket(True, 0x0000)
                yield pkt.put(readpath)
                yield pkt.get(writepath, read_value, [0])

                pkt = CommandPacket(False, 0x0000, [0x5555AAAA])
                yield pkt.put(readpath)
                yield pkt.get(writepath, read_value, [0x5555AAAA])

                # test a bunch of random addresses
                for ii in range(nloops):
                    randaddr = randint(0, (2**20)-1)
                    randdata = randint(0, (2**32)-1)
                    pkt = CommandPacket(False, randaddr, [randdata])
                    yield pkt.put(readpath)
                    yield pkt.get(writepath, read_value, [randdata])

            except Exception as err:
                print("Error: {}".format(str(err)))
                traceback.print_exc()

            yield delay(2000)
            raise StopSimulation

        wp_read, wp_valid = Signals(bool(0), 2)
        wp_read_data = Signal(intbv(0)[8:])
        wp_empty, wp_full = Signals(bool(0), 2)

        @always_comb
        def tbmon():
            wp_read.next = writepath.read
            wp_read_data.next = writepath.read_data
            wp_valid.next = writepath.read_valid
            wp_full.next = writepath.full
            wp_empty.next = writepath.empty

        return tbclk, tbdut, tbmap, tbftx, tbfrx, tbmem, tbstim, tbmon
示例#7
0
文件: spi.py 项目: wingel/rhea
def spi_controller(
        # ---[ Module Ports]---
        glbl,  # global interface, clock, reset, etc.
        spibus,  # external SPI bus
        # optional ports
    fifobus=None,  # streaming interface, FIFO bus
        mmbus=None,  # memory-mapped bus, control status access
        cso=None,  # control-status object

        # ---[ Module Parameters ]---
    include_fifo=True,  # include an 8 byte deep FIFO
):
    """ SPI (Serial Peripheral Interface) module
    This module is an SPI controller (master) and can be used to interface
    with various external SPI devices.

    Arguments:
        glbl (Global): clock and reset interface
        spibus (SPIBus): external (off-chip) SPI bus
        fifobus (FIFOBus): interface to the FIFOs, write side is to
          the TX the read side from the RX.
        mmbus (MemoryMapped): a memory-mapped bus used to access
          the control-status signals.
        cso (ControlStatus): the control-status object used to control
          this peripheral

        include_fifo (bool): include the FIFO ... this is not fully
          implemented

    Note:
        At last check the register-file automation was not complete, only
        the `cso` external control or `cso` configuration can be utilized.
    """
    clock, reset = glbl.clock, glbl.reset
    if cso is None:
        cso = spi_controller.cso()
    fifosize = 8

    # -- local signals --
    ena = Signal(False)
    clkcnt = Signal(modbv(0, min=0, max=2**12))
    bcnt = Signal(intbv(0, min=0, max=8))

    # separate tx and rx shift-registers (could be one in the same)
    treg = Signal(intbv(0)[8:])  # tx shift register
    rreg = Signal(intbv(0)[8:])  # rx shift register

    x_sck, x_ss, x_mosi, x_miso = Signals(bool(0), 4)

    # internal FIFO bus interfaces
    #   external FIFO side (FIFO to external SPI bus)
    itx = FIFOBus(width=fifobus.width)
    #   internal FIFO side (FIFO to internal bus)
    irx = FIFOBus(width=fifobus.width)

    states = enum('idle', 'wait_hclk', 'data_in', 'data_change', 'write_fifo',
                  'end')
    state = Signal(states.idle)

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # memory- mapped registers
    # add the peripheral's regfile to the bus (informational only)
    # @todo: the automatic building of the register files is incomplete
    if mmbus is not None:
        # the register-file (rf) will drive all the cso signals
        rf = cso.get_register_file()
        mmbus.add(rf, 'spi')

    # FIFO for the wishbone data transfer
    if include_fifo:
        fifo_fast.debug = spi_controller.debug
        fifo_tx_inst = fifo_fast(glbl, fifobus=itx, size=fifosize)
        fifo_rx_inst = fifo_fast(glbl, fifobus=irx, size=fifosize)

    @always_comb
    def beh_assign():
        cso.tx_fifo_count.next = itx.count
        cso.rx_fifo_count.next = irx.count

        if clkcnt > 0:
            ena.next = False
        else:
            ena.next = True

    clock_counts = tuple([(2**ii) - 1 for ii in range(13)])

    @always(clock.posedge)
    def beh_clk_div():
        if cso.enable and clkcnt != 0 and state != states.idle:
            clkcnt.next = (clkcnt - 1)
        else:
            clkcnt.next = clock_counts[cso.clock_divisor]

    @always_seq(clock.posedge, reset=reset)
    def beh_state_and_more():
        """
        Designed to the following timing diagram

        SCK   CPOL=0 ______/---\___/---\___/---\___/---\___/---\___/---\___/---\___/---\___/---\ 
              CPOL=1 ------\___/---\___/---\___/---\___/---\___/---\___/---\___/---\___/---\___/ 
        SS           ---\_______________________________________________________________________ 
        CPHA=0 MOSI  ...|.0....|.1.....|.2.....|.3.....|.4.....|.5.....|.6.....|.7.....|.0.....| 
               MISO  ...|.0....|.1.....|.2.....|.3.....|.4.....|.5.....|.6.....|.7.....|.0.....| 
        CPHA=1 MOSI  ...|....0.....|.1.....|.2.....|.3.....|.4.....|.5.....|.6.....|.7.....|.0...
               MISO  ......|.0.....|.1.....|.2.....|.3.....|.4.....|.5.....|.6.....|.7.....|.0...
        """
        if not cso.enable:
            state.next = states.idle
            bcnt.next = 0
            treg.next = 0

            itx.read.next = False
            irx.write.next = False

            x_sck.next = False
            x_ss.next = False
        else:
            if not cso.freeze:
                # ~~~~ Idle state ~~~~
                if state == states.idle:
                    bcnt.next = 7
                    treg.next = itx.read_data
                    x_sck.next = cso.clock_polarity
                    irx.write.next = False

                    if not itx.empty and not irx.full:
                        itx.read.next = True
                        x_ss.next = False
                        if cso.clock_phase:  # Clock in on second phase
                            state.next = states.wait_hclk
                        else:  # Clock in on first phase
                            state.next = states.data_in
                    else:
                        itx.read.next = False
                        x_ss.next = True

                # ~~~~ Wait half clock period for cpha=1 ~~~~
                elif state == states.wait_hclk:
                    itx.read.next = False
                    irx.write.next = False
                    if ena:
                        x_sck.next = not x_sck
                        state.next = states.data_in

                # ~~~~ Clock data in (and out) ~~~~
                elif state == states.data_in:
                    itx.read.next = False
                    irx.write.next = False
                    if ena:  # clk div
                        x_sck.next = not x_sck
                        rreg.next = concat(rreg[7:0], x_miso)

                        if cso.clock_phase and bcnt == 0:
                            irx.write.next = True
                            if itx.empty or irx.full:
                                state.next = states.end
                            else:
                                state.next = states.data_change
                        else:
                            state.next = states.data_change

                # ~~~~ Get ready for next byte out/in ~~~~
                elif state == states.data_change:
                    itx.read.next = False
                    irx.write.next = False
                    if ena:
                        x_sck.next = not x_sck
                        if bcnt == 0:
                            if not cso.clock_phase:
                                irx.write.next = True

                            if itx.empty or irx.full:
                                state.next = states.end
                            else:  # more data to transfer
                                bcnt.next = 7
                                state.next = states.data_in
                                itx.read.next = True
                                treg.next = itx.read_data
                        else:
                            treg.next = concat(treg[7:0], intbv(0)[1:])
                            bcnt.next = bcnt - 1
                            state.next = states.data_in

                # ~~~~ End state ~~~~
                elif state == states.end:
                    itx.read.next = False
                    irx.write.next = False
                    if ena:  # Wait half clock cycle go idle
                        state.next = states.idle

                # Shouldn't happen, error in logic
                else:
                    state.next = states.idle
                    assert False, "SPI Invalid State"

    @always_comb
    def beh_fifo_sel():
        """
        The `itx` and `irx` FIFO interfaces are driven by different
        logic depending on the configuration.  This modules accesses
        the `itx` read side and drives the `irx` write side.  The
        `itx` write side is driven by the `cso` or the `fifobus` port.
        The `irx` read side is accessed by the `cso` or the `fifobus`
        port.
        """
        if cso.bypass_fifo:
            # data comes from the register file
            cso.tx_empty.next = itx.empty
            cso.tx_full.next = itx.full
            itx.write_data.next = cso.tx_byte

            cso.rx_empty.next = irx.empty
            cso.rx_full.next = irx.full
            cso.rx_byte.next = irx.read_data
            cso.rx_byte_valid.next = irx.read_valid

            # @todo: if cso.tx_byte write signal (written by bus) drive the
            # @todo: FIFO write signals, same if the cso.rx_byte is accessed
            itx.write.next = cso.tx_write
            irx.read.next = cso.rx_read

        else:
            # data comes from external FIFO bus interface
            fifobus.full.next = itx.full
            itx.write_data.next = fifobus.write_data
            itx.write.next = fifobus.write

            fifobus.empty.next = irx.empty
            fifobus.read_data.next = irx.read_data
            fifobus.read_valid.next = irx.read_valid
            irx.read.next = fifobus.read

        # same for all modes
        irx.write_data.next = rreg

    @always_comb
    def beh_x_mosi():
        # @todo lsb control signal
        x_mosi.next = treg[7]

    @always_comb
    def beh_gate_mosi():
        if cso.loopback:
            spibus.mosi.next = False
        else:
            spibus.mosi.next = x_mosi

    @always_comb  # (clock.posedge)
    def beh_spi_sigs():
        spibus.sck.next = x_sck
        if cso.loopback:
            x_miso.next = x_mosi
        else:
            x_miso.next = spibus.miso

    @always_comb
    def beh_slave_select():
        if cso.manual_slave_select:
            spibus.ss.next = ~cso.slave_select
        elif x_ss:
            spibus.ss.next = 0xFF
        else:
            spibus.ss.next = ~cso.slave_select

    # myhdl generators in the __debug__ conditionals are not converted.
    if spi_controller.debug:

        @instance
        def mon_state():
            print("  :{:<8d}: initial state {}".format(now(), str(state)))

            while True:
                yield state
                print("  :{:<8d}: state transition --> {}".format(
                    now(), str(state)))

        fbidle = intbv('0000')[4:]

        @instance
        def mon_trace():
            while True:
                yield clock.posedge
                ccfb = concat(itx.write, itx.read, irx.write, irx.read)
                if ccfb != fbidle:
                    fstr = "  :{:<8d}: tx: w{} r{}, f{} e{}, rx: w{} r{} f{} e{}"
                    print(
                        fstr.format(
                            now(),
                            int(itx.write),
                            int(itx.read),
                            int(itx.full),
                            int(itx.empty),
                            int(irx.write),
                            int(irx.read),
                            int(irx.full),
                            int(irx.empty),
                        ))

        @always(clock.posedge)
        def mon_tx_fifo_write():
            if itx.write:
                print("   WRITE tx fifo {:02X}".format(int(itx.write_data)))
            if itx.read:
                print("   READ tx fifo {:02X}".format(int(itx.read_data)))

        @always(clock.posedge)
        def mon_rx_fifo_write():
            if irx.write:
                print("   WRITE rx fifo {:02X}".format(int(irx.write_data)))

            if irx.read:
                print("   READ rx fifo {:02X}".format(int(irx.read_data)))

    # return the myhdl generators and instances
    return myhdl.instances()