Exemple #1
0
    def __init__(self, clock):
        """
        The EMesh interface on the external ELinks is defined as having
        three EMeshPacket conduits.  These conduits are used to send
        write and read requests over the Elink.

        """

        self.clock = clock         # the interface clock
        self.txwr = EMeshPacket()  # TX write, send write commands
        self.txrd = EMeshPacket()  # TX read, send read commands
        self.txrr = EMeshPacket()  # TX read response, acknowledge external read commands

        self.rxwr = EMeshPacket()  # RX write, receive external write commands
        self.rxrd = EMeshPacket()  # RX read, receive external read commands
        self.rxrr = EMeshPacket()  # RX read response, receive read acknowledge

        # transmit and receive FIFOs - simulation only
        # @todo: want these to be private (_) but then a bunch of
        # @todo: methods need to be added to wait on packet events, etc.
        self.packet_types = ('wr', 'rd', 'rr',)
        self.txwr_fifo = FIFO()
        self.txrd_fifo = FIFO()
        self.txrr_fifo = FIFO()

        self.rxwr_fifo = FIFO()
        self.rxrd_fifo = FIFO()
        self.rxrr_fifo = FIFO()

        self._outstanding_reads = {}
Exemple #2
0
    def __init__(self):
        self._tx = ELinkChannel()
        self._rx = ELinkChannel()

        self._tx_fifo = FIFO()
        self._rx_fifo = FIFO()

        # Keep track how this interface is connected, only an east-west or
        # north-south connections can be established (not both).
        # The east-west and north-south are redundant but commonly used.
        self.connections = {"east": False, "west": False, "north": False, "south": False}
Exemple #3
0
    def __init__(self):
        self._tx = ELinkChannel()
        self._rx = ELinkChannel()

        self._tx_fifo = FIFO()
        self._rx_fifo = FIFO()

        # Keep track how this interface is connected, only an east-west or
        # north-south connections can be established (not both).
        # The east-west and north-south are redundant but commonly used.
        self.connections = {'east': False, 'west': False,
                            'north': False, 'south': False}
Exemple #4
0
def elink_asic_model(elink):
    """ Model a simple ELink device (something like Epiphany)

    Arguments:
        elink: Interface to the external ELink enabled device

    myhdl not convertible.
    """
    assert isinstance(elink, ELink)

    # get the tx and rx links based on this logical location
    tx, rx = elink.connect('south')
    gclk = tx.instances()

    pkt_i_fifo = FIFO(depth=128)
    pkt_o_fifo = FIFO(depth=128)

    @instance
    def p_rx_packets():
        """ receive packets and push onto processing FIFO """
        while True:
            yield rx.frame.posedge
            bytes = []
            yield rx.lclk.posedge
            while rx.frame:
                bytes.append(intbv(int(rx.data))[8:])
                if len(bytes) == 13:
                    pkt = EMeshPacket()
                    pkt.frombytes(bytes)
                    yield delay(1)
                    pkt_i_fifo.write(pkt)
                    # print("[easic] RX packet {} {}".format(pkt, pkt_i_fifo))
                    # @todo: if FIFO full assert wait
                    bytes = []
                yield rx.lclk.posedge
            # @todo: if len(bytes) != 13 report error - partial packet

    # @todo: simulate EMesh routing
    @instance
    def p_proc_packets():
        """ process packets """
        idelay = False
        while True:
            pkt = pkt_i_fifo.read()
            if pkt is not None and pkt.access:
                if not idelay:
                    yield delay(17)
                    idelay = True
                pkt_o_fifo.write(pkt)
                # print("[easic] PROC packet {} {}".format(pkt, pkt_o_fifo))

            if pkt_i_fifo.is_empty():
                idelay = False
                yield pkt_i_fifo.empty.negedge

    @instance
    def p_tx_packets():
        """ transmit processed packets """
        while True:
            if not pkt_o_fifo.is_empty():
                pkt = pkt_o_fifo.read()
                # print("[easic] TX packet {} {}".format(pkt, pkt_o_fifo))
                # @todo: if len of FIFO > 2, shuffle order
                bytes = pkt.tobytes()
                for bb in bytes:
                    tx.frame.next = True
                    tx.data.next = bb
                    yield tx.lclk.posedge
                # packet complete clear frame
                tx.frame.next = False

            if pkt_o_fifo.is_empty():
                yield pkt_o_fifo.empty.negedge
            else:
                yield tx.lclk.posedge

    return myhdl.instances()
Exemple #5
0
class ELink(object):
    """
    The ELink interface is the external interface between devices (typically
    the Adapteva Epiphany and an FPGA).

    @todo: more description ...

    The Epiphany datasheet (has a description of the chip-to-chip (ELink)
    interfaces):
    http://www.adapteva.com/docs/e16g301_datasheet.pdf

    The Parallella open-hardware (oh) repository:
    https://github.com/parallella/oh/tree/master/elink
    """
    def __init__(self):
        self._tx = ELinkChannel()
        self._rx = ELinkChannel()

        self._tx_fifo = FIFO()
        self._rx_fifo = FIFO()

        # Keep track how this interface is connected, only an east-west or
        # north-south connections can be established (not both).
        # The east-west and north-south are redundant but commonly used.
        self.connections = {
            'east': False,
            'west': False,
            'north': False,
            'south': False
        }

    def connect(self, pos):
        """ Return relative relation
        In this implementation the TX and RX are from the perspective of
        the external link (e.g. the FPGA link).  This function is used
        to get local perspective.
        :param pos: where the component is logically positioned (located)
        :return: tx link, rx link
        """
        pos = pos.lower()
        assert pos in self.connections
        assert not self.connections[pos], "{} connection exists".format(pos)
        self.connections[pos] = True
        if pos in ('east', 'north'):
            links = self._tx, self._rx
        elif pos in ('west', 'south'):
            links = self._rx, self._tx
        return links

    @myhdl.block
    def instances(self):
        return self._tx.instances(), self._rx.instances()

    def write(self, dstaddr, data, srcaddr=0, block=True):
        """A single ELink write transaction
        """
        packet = EMeshPacket(access=1,
                             write=1,
                             datamode=2,
                             dstaddr=dstaddr,
                             data=data,
                             srcaddr=srcaddr)
        bytes = packet.tobytes()
        bpkt = _ELinkTransaction(bytes)
        self._tx_fifo.write(bpkt)
        if block:
            yield bpkt.finished.posedge

    def read(self, dstaddr, data, srcaddr=0, block=True):
        """ A single ELink read transaction
        """
        packet = EMeshPacket(access=1,
                             write=0,
                             datamode=2,
                             dstaddr=dstaddr,
                             data=data,
                             srcaddr=srcaddr)
        bytes = packet.tobytes()
        tpkt = _ELinkTransaction(bytes)
        self._tx_fifo.append(tpkt)
        if block:
            yield tpkt.finished.posedge

    def send_packet(self, emesh, block=True):
        bytes = emesh.tobytes()
        tpkt = _ELinkTransaction(bytes)
        self._tx_fifo.write(tpkt)
        if block:
            yield tpkt.finished.posedge

    def receive_packet(self, emesh, block=True):
        if self._rx_fifo.is_empty() and block:
            yield self._rx_fifo.empty.negedge

        # if blocked will not be empty, if not block maybe
        if not self._rx_fifo.is_empty():
            tpkt = self._rx_fifo.read()
            emesh.frombytes(tpkt.bytes)
            # allow emesh to update
            yield self._rx.lclk.posedge

    def write_bytes(self, bytes, block=True):
        assert isinstance(bytes, (list, tuple))

    def read_bytes(self, bytes, block=True):
        assert isinstance(bytes, list)

    @myhdl.block
    def process(self):
        """ Drive the ELink signals
        This process mimics the behavior of the external ELink logic.

        @todo: this really needs to exist in a specific module model???

        myhdl not convertible
        """
        @instance
        def tx_bytes():
            while True:
                if not self._tx_fifo.is_empty():
                    pkt = self._tx_fifo.read()
                    assert isinstance(pkt, _ELinkTransaction)
                    yield self._send_bytes(pkt.bytes)
                    pkt.finished.next = True
                else:
                    yield self._tx_fifo.empty.negedge

        @instance
        def rx_bytes():
            while True:
                bytes = [None for _ in range(13)]
                yield self._receive_bytes(bytes)
                self._rx_fifo.write(_ELinkTransaction(bytes))

        return tx_bytes, rx_bytes

    def _send_bytes(self, bytes):
        yield self._tx.lclk.posedge
        self._tx.frame.next = True
        for ii in range(13):
            self._tx.data.next = bytes[ii]
            yield self._tx.lclk.posedge
        self._tx.frame.next = False
        yield self._tx.lclk.posedge

    def _receive_bytes(self, bytes):
        ri = 0
        while ri < 13:
            yield self._rx.lclk.posedge
            if self._rx.frame:
                bytes[ri] = intbv(int(self._rx.data))[8:0]
                ri += 1
Exemple #6
0
class EMesh(object):
    def __init__(self, clock):
        """
        The EMesh interface on the external ELinks is defined as having
        three EMeshPacket conduits.  These conduits are used to send
        write and read requests over the Elink.

        """

        self.clock = clock         # the interface clock
        self.txwr = EMeshPacket()  # TX write, send write commands
        self.txrd = EMeshPacket()  # TX read, send read commands
        self.txrr = EMeshPacket()  # TX read response, acknowledge external read commands

        self.rxwr = EMeshPacket()  # RX write, receive external write commands
        self.rxrd = EMeshPacket()  # RX read, receive external read commands
        self.rxrr = EMeshPacket()  # RX read response, receive read acknowledge

        # transmit and receive FIFOs - simulation only
        # @todo: want these to be private (_) but then a bunch of
        # @todo: methods need to be added to wait on packet events, etc.
        self.packet_types = ('wr', 'rd', 'rr',)
        self.txwr_fifo = FIFO()
        self.txrd_fifo = FIFO()
        self.txrr_fifo = FIFO()

        self.rxwr_fifo = FIFO()
        self.rxrd_fifo = FIFO()
        self.rxrr_fifo = FIFO()

        self._outstanding_reads = {}

    def __str__(self):
        s = "txwr: {}, txrd: {}, txrr: {}, rxwr: {}, rxrd: {}, rxrr: {}".format(
             self.txwr_fifo.count, self.txrd_fifo.count, self.txrr_fifo.count,
             self.rxwr_fifo.count, self.rxrd_fifo.count, self.rxrr_fifo.count)
        return s

    def set_clock(self, clock):
        self.clock = clock

    def write(self, dstaddr, data, datau=0):
        """ send a write packet

        :param dstaddr: destination address for the write
        :param data: 32bit data for the write
        :param datau: upper 32bit data for the write (64bit write)
        :return:

        @todo: add explaination why a separate packet is used to push
        @todo: onto the transaction FIFOs (needs copies on the FIFOs
        @todo: and not actual bus interface).

        not convertible.
        """
        # get a new packet for the transaction emulation
        pkt = EMeshPacket(access=True, write=True,
                          dstaddr=dstaddr, data=data, srcaddr=datau)
        # push the packet onto the TX write FIFO
        # also assign the txwr packet to the new packet, the txwr
        # will mirror the transaction packet
        self.txwr.assign(pkt)
        self.txwr_fifo.write(pkt)
        yield self.clock.posedge
        self.txwr.clear()

    def read(self, dstaddr, data, srcaddr):
        """ send a read packet

        :param dstaddr:
        :param data:
        :param srcaddr:
        :return:

        not convertible.
        """
        # sent a read packet through the txrd fifo
        pkt = EMeshPacket(access=True, write=False,
                          dstaddr=dstaddr, data=data, srcaddr=srcaddr)
        # push the packet onto the TX read FIFO
        self.txrd_fifo.write(pkt)
        self._outstanding_reads[dstaddr] = pkt
        yield self.clock.posedge

    def read_response(self, read_packet):
        """ send a read response
        :param read_packet:
        :return:

        @todo: complete
        not convertible.
        """
        pass

    def route_to_fifo(self, pkt):
        """ take a freshly recieved packet from the ELink interface
        Take a freshly received packet from the ELink interface and route
        it to the correct RX fifo.
        :param pkt:
        :return:

        not convertible
        """
        # if the write bit is set pass it to RX write FIFO
        # @todo: how to determine the other packets??

        if pkt.write:
            self.rxwr_fifo.write(pkt)
        else:
            # determine if this is a read-request or read-response.
            pass

    def get_packet(self, pkt_type):
        """ Get a packet from one of the channels
        :param pkt_type:
        :return:
        """
        assert pkt_type in self.packet_types
        pkt = None
        if pkt_type == 'wr':
            pkt = self.rxwr_fifo.read()
        elif pkt_type == 'rd':
            pkt = self.rxrd_fifo.read()
        elif pkt_type == 'rr':
            pkt = self.rxrr_fifo.read()

        return pkt
Exemple #7
0
    def __init__(self, clock):
        """
        The EMesh interface on the external ELinks is defined as having
        three EMeshPacket conduits.  These conduits are used to send
        write and read requests over the Elink.

        """

        self.clock = clock  # the interface clock
        self.txwr = EMeshPacket()  # TX write, send write commands
        self.txrd = EMeshPacket()  # TX read, send read commands
        self.txrr = EMeshPacket(
        )  # TX read response, acknowledge external read commands

        self.rxwr = EMeshPacket()  # RX write, receive external write commands
        self.rxrd = EMeshPacket()  # RX read, receive external read commands
        self.rxrr = EMeshPacket()  # RX read response, receive read acknowledge

        # transmit and receive FIFOs - simulation only
        # @todo: want these to be private (_) but then a bunch of
        # @todo: methods need to be added to wait on packet events, etc.
        self.packet_types = (
            'wr',
            'rd',
            'rr',
        )
        self.txwr_fifo = FIFO()
        self.txrd_fifo = FIFO()
        self.txrr_fifo = FIFO()

        self.rxwr_fifo = FIFO()
        self.rxrd_fifo = FIFO()
        self.rxrr_fifo = FIFO()

        self._outstanding_reads = {}
Exemple #8
0
class EMesh(object):
    def __init__(self, clock):
        """
        The EMesh interface on the external ELinks is defined as having
        three EMeshPacket conduits.  These conduits are used to send
        write and read requests over the Elink.

        """

        self.clock = clock  # the interface clock
        self.txwr = EMeshPacket()  # TX write, send write commands
        self.txrd = EMeshPacket()  # TX read, send read commands
        self.txrr = EMeshPacket(
        )  # TX read response, acknowledge external read commands

        self.rxwr = EMeshPacket()  # RX write, receive external write commands
        self.rxrd = EMeshPacket()  # RX read, receive external read commands
        self.rxrr = EMeshPacket()  # RX read response, receive read acknowledge

        # transmit and receive FIFOs - simulation only
        # @todo: want these to be private (_) but then a bunch of
        # @todo: methods need to be added to wait on packet events, etc.
        self.packet_types = (
            'wr',
            'rd',
            'rr',
        )
        self.txwr_fifo = FIFO()
        self.txrd_fifo = FIFO()
        self.txrr_fifo = FIFO()

        self.rxwr_fifo = FIFO()
        self.rxrd_fifo = FIFO()
        self.rxrr_fifo = FIFO()

        self._outstanding_reads = {}

    def __str__(self):
        s = "txwr: {}, txrd: {}, txrr: {}, rxwr: {}, rxrd: {}, rxrr: {}".format(
            self.txwr_fifo.count, self.txrd_fifo.count, self.txrr_fifo.count,
            self.rxwr_fifo.count, self.rxrd_fifo.count, self.rxrr_fifo.count)
        return s

    def set_clock(self, clock):
        self.clock = clock

    def write(self, dstaddr, data, datau=0):
        """ send a write packet

        Arguments:
            dstaddr: destination address for the write
            data: 32bit data for the write
            datau: upper 32bit data for the write (64bit write)

        @todo: add explanation why a separate packet is used to push
               onto the transaction FIFOs (needs copies on the FIFOs
               and not actual bus interface).

        myhdl not convertible.
        """
        # get a new packet for the transaction emulation
        pkt = EMeshPacket(access=True,
                          write=True,
                          dstaddr=dstaddr,
                          data=data,
                          srcaddr=datau)
        # push the packet onto the TX write FIFO
        # also assign the txwr packet to the new packet, the txwr
        # will mirror the transaction packet
        self.txwr.assign(pkt)
        self.txwr_fifo.write(pkt)
        yield self.clock.posedge
        self.txwr.clear()

    def read(self, dstaddr, data, srcaddr):
        """ send a read packet

        Arguments:
            dstaddr:
            data:
            srcaddr:

        myhdl not convertible.
        """
        # sent a read packet through the txrd fifo
        pkt = EMeshPacket(access=True,
                          write=False,
                          dstaddr=dstaddr,
                          data=data,
                          srcaddr=srcaddr)
        # push the packet onto the TX read FIFO
        self.txrd_fifo.write(pkt)
        self._outstanding_reads[dstaddr] = pkt
        yield self.clock.posedge

    def read_response(self, read_packet):
        """ send a read response

        Arguments:
            read_packet:

        @todo: complete
        myhdl not convertible.
        """
        pass

    def route_to_fifo(self, pkt):
        """ take a freshly received packet from the ELink interface
        Take a freshly received packet from the ELink interface and route
        it to the correct RX fifo.

        Arguments:
            pkt:

        myhdl not convertible
        """
        # if the write bit is set pass it to RX write FIFO
        # @todo: how to determine the other packets??

        if pkt.write:
            self.rxwr_fifo.write(pkt)
        else:
            # determine if this is a read-request or read-response.
            pass

    def get_packet(self, pkt_type):
        """ Get a packet from one of the channels
        :param pkt_type:
        :return:
        """
        assert pkt_type in self.packet_types
        pkt = None
        if pkt_type == 'wr':
            pkt = self.rxwr_fifo.read()
        elif pkt_type == 'rd':
            pkt = self.rxrd_fifo.read()
        elif pkt_type == 'rr':
            pkt = self.rxrr_fifo.read()

        return pkt
Exemple #9
0
class ELink(object):
    """
    The ELink interface is the external interface between devices (typically
    the Adapteva Epiphany and an FPGA).

    @todo: more description ...

    The Epiphany datasheet (has a description of the chip-to-chip (ELink)
    interfaces):
    http://www.adapteva.com/docs/e16g301_datasheet.pdf

    The Parallella open-hardware (oh) repository:
    https://github.com/parallella/oh/tree/master/elink
    """

    def __init__(self):
        self._tx = ELinkChannel()
        self._rx = ELinkChannel()

        self._tx_fifo = FIFO()
        self._rx_fifo = FIFO()

        # Keep track how this interface is connected, only an east-west or
        # north-south connections can be established (not both).
        # The east-west and north-south are redundant but commonly used.
        self.connections = {'east': False, 'west': False,
                            'north': False, 'south': False}

    def connect(self, pos):
        """ Return relative relation
        In this implementation the TX and RX are from the perspective of
        the external link (e.g. the FPGA link).  This function is used
        to get local perspective.
        :param pos: where the component is logically positioned (located)
        :return: tx link, rx link
        """
        pos = pos.lower()
        assert pos in self.connections
        assert not self.connections[pos], "{} connection exists".format(pos)
        self.connections[pos] = True
        if pos in ('east', 'north'):
            links = self._tx, self._rx
        elif pos in ('west', 'south'):
            links = self._rx, self._tx
        return links

    @myhdl.block
    def instances(self):
        return self._tx.instances(), self._rx.instances()

    def write(self, dstaddr, data, srcaddr=0, block=True):
        """A single ELink write transaction
        """
        packet = EMeshPacket(access=1, write=1, datamode=2,
                             dstaddr=dstaddr, data=data, srcaddr=srcaddr)
        bytes = packet.tobytes()
        bpkt = _ELinkTransaction(bytes)
        self._tx_fifo.write(bpkt)
        if block:
            yield bpkt.finished.posedge

    def read(self, dstaddr, data, srcaddr=0, block=True):
        """ A single ELink read transaction
        """
        packet = EMeshPacket(access=1, write=0, datamode=2,
                             dstaddr=dstaddr, data=data, srcaddr=srcaddr)
        bytes = packet.tobytes()
        tpkt = _ELinkTransaction(bytes)
        self._tx_fifo.append(tpkt)
        if block:
            yield tpkt.finished.posedge

    def send_packet(self, emesh, block=True):
        bytes = emesh.tobytes()
        tpkt = _ELinkTransaction(bytes)
        self._tx_fifo.write(tpkt)
        if block:
            yield tpkt.finished.posedge

    def receive_packet(self, emesh, block=True):
        if self._rx_fifo.is_empty() and block:
            yield self._rx_fifo.empty.negedge

        # if blocked will not be empty, if not block maybe
        if not self._rx_fifo.is_empty():
            tpkt = self._rx_fifo.read()
            emesh.frombytes(tpkt.bytes)
            # allow emesh to update
            yield self._rx.lclk.posedge

    def write_bytes(self, bytes, block=True):
        assert isinstance(bytes, (list, tuple))

    def read_bytes(self, bytes, block=True):
        assert isinstance(bytes, list)

    @myhdl.block
    def process(self):
        """ Drive the ELink signals
        This process mimics the behavior of the external ELink logic.

        @todo: this really needs to exist in a specific module model???

        myhdl not convertible
        """
        @instance
        def tx_bytes():
            while True:
                if not self._tx_fifo.is_empty():
                    pkt = self._tx_fifo.read()
                    assert isinstance(pkt, _ELinkTransaction)
                    yield self._send_bytes(pkt.bytes)
                    pkt.finished.next = True
                else:
                    yield self._tx_fifo.empty.negedge

        @instance
        def rx_bytes():
            while True:
                bytes = [None for _ in range(13)]
                yield self._receive_bytes(bytes)
                self._rx_fifo.write(_ELinkTransaction(bytes))

        return tx_bytes, rx_bytes

    def _send_bytes(self, bytes):
        yield self._tx.lclk.posedge
        self._tx.frame.next = True
        for ii in range(13):
            self._tx.data.next = bytes[ii]
            yield self._tx.lclk.posedge
        self._tx.frame.next = False
        yield self._tx.lclk.posedge

    def _receive_bytes(self, bytes):
        ri = 0
        while ri < 13:
            yield self._rx.lclk.posedge
            if self._rx.frame:
                bytes[ri] = intbv(int(self._rx.data))[8:0]
                ri += 1