luna-soc Documentation

eptri - SoC controller for the LUNA USB Device

General Description

eptri (endpoint-tri) is a three-interface CSR controller that allows a CPU or Wishbone design to control the endpoints of a LUNA USB Device.

Features

  • CONTROL peripheral for managing device connection, reset and connection speed.

  • SETUP interface peripheral for reading control transactions from the host.

  • OUT interface peripheral for reading data transfers from the host.

  • IN interface peripheral for writing data transactions to the host.

Introduction

Definitions

  • Controller refers to the eptri controller as a whole, including all peripherals.

  • Peripheral refers to USBDeviceController, SetupFIFOInterface, InFIFOInterface or OutFIFOInterface.

Block Diagram

                             ┌────────────────────────────────────────┐      ┌──────────────────────────────────────┐
                             │USBDevice                               │      │EPTRI                                 │
                             │                                        │      │                                      │
                             │                                        │      ├───────────────────────────┬──────────┤
                             │                                        │      │USBDeviceController        │Registers │◀─────────▶
                             ├─────────────┐      ┌───────────────────┤      │                           ├──────────┤
                             │UTMIInterface│      │EndpointMultiplexer│      │                           │IRQ       │──────────▶
                             │             │      │                   │      ├───────────────────────────┼──────────┤
           ┌──────────┐      │             │      │                   │      │SetupFIFOInterface┌───────▶│Registers │◀─────────▶
           │USB PHY   │      │             │      │                   │      ├──────────┐       │        ├──────────┤
◀─── D+ ──▶│          │      │             │      │                   │      │8B FIFO   │───────┘        │IRQ       │──────────▶
           │          │◀────▶│             │◀────▶│                   │◀────▶├──────────┴────────────────┼──────────┤              SoC
◀─── D- ──▶│          │      │             │      │                   │      │InFIFOInterface   ┌────────│Registers │◀─────────▶
           │          │      │             │      │                   │      ├──────────┐       │        ├──────────┤
           └──────────┘      │             │      │                   │      │512B FIFO │◀──────┘        │IRQ       │──────────▶
                             │             │      │                   │      ├──────────┴────────────────┼──────────┤
                             │             │      │                   │      │OutFIFOInterface  ┌───────▶│Registers │◀─────────▶
                             │             │      │                   │      ├──────────┐       │        ├──────────┤
                             │             │      │                   │      │512B FIFO │───────┘        │IRQ       │──────────▶
                             └─────────────┴──────┴───────────────────┘      └──────────┴────────────────┴──────────┘

Usage

The exact details for integrating a LUNA eptri peripheral into a design will depend on the SoC platform you are using.

For example, using luna-soc:

class Top(Elaboratable):
    def __init__(self):
        # instantiate the SoC
        self.soc = LunaSoC(
            cpu=VexRiscv(reset_addr=0x00000000, variant="cynthion"),
            clock_frequency=int(60e6),
        )

        # instantiate the eptri device controller peripheral
        self.usb0 = USBDeviceController()

        # instantiate the three endpoint interface peripherals
        self.usb0_ep_control = SetupFIFOInterface()
        self.usb0_ep_in = InFIFOInterface()
        self.usb0_ep_out = OutFIFOInterface()

        # add the peripherals to the SoC
        self.soc.add_peripheral(self.usb0)
        self.soc.add_peripheral(self.usb0_ep_control, as_submodule=False)
        self.soc.add_peripheral(self.usb0_ep_in, as_submodule=False)
        self.soc.add_peripheral(self.usb0_ep_out, as_submodule=False)

def elaborate(self, platform):
    m = Module()

    m.submodules.soc = self.soc

    # instantiate a LUNA USB device
    usb0_bus = platform.request(platform.default_usb_connection)
    usb0_device = USBDevice(bus=usb0_bus)

    # add the eptri endpoint interface peripherals to the LUNA USB device
    # as endpoint handlers
    usb0_device.add_endpoint(self.usb0_ep_control)
    usb0_device.add_endpoint(self.usb0_ep_in)
    usb0_device.add_endpoint(self.usb0_ep_out)

    # connect the eptri device controller to the LUNA USB device
    m.d.comb += self.usb0.attach(usb0_device)

    m.submodules.usb0_device = usb0_device

    return m

Registers

The eptri controller provides four sets of registers corresponding to each peripheral.

USBx - USBDeviceController

CONTROL Register

Offset

Range

Access

Field

0x0000

[0:0]

read-write

connect

0x0000

[8:8]

read-write

low_speed_only

0x0000

[9:9]

read-write

full_speed_only

Control register

        connect:         Set this bit to '1' to allow the associated USB device to connect to a host.
        low_speed_only:  Set this bit to '1' to force the device to operate at low speed.
        full_speed_only: Set this bit to '1' to force the device to operate at full speed.

STATUS Register

Offset

Range

Access

Field

0x0002

[1:0]

read-only

speed

Status register

        speed: Indicates the current speed of the USB device. 0 indicates High; 1 => Full,
               2 => Low, and 3 => SuperSpeed (incl SuperSpeed+).

EV_ENABLE Register

Offset

Range

Access

Field

0x0008

[0:0]

read-write

mask

EV_PENDING Register

Offset

Range

Access

Field

0x0009

[0:0]

read-write

mask

USBx_EP_CONTROL - SetupFIFOInterface

CONTROL Register

Offset

Range

Access

Field

0x0000

[7:0]

write-only

address

Control register

       address: Controls the current device's USB address. Should be written after a SET_ADDRESS
                request is received. Automatically resets back to zero on a USB reset.

STATUS Register

Offset

Range

Access

Field

0x0002

[7:0]

read-only

address

0x0002

[11:8]

read-only

epno

0x0002

[12:12]

read-only

have

Status register

       address: Holds the current device's active USB address.
       epno:    The endpoint number associated with the most recently captured SETUP packet.
       have:    `1` iff data is available in the FIFO.

RESET Register

Offset

Range

Access

Field

0x0004

[0:0]

write-only

fifo

Reset register

       fifo: Local reset control for the SETUP handler; writing a '1' to this register clears
             the handler state.

DATA Register

Offset

Range

Access

Field

0x0005

[7:0]

read-only

byte

Data register

       A FIFO that returns the bytes from the most recently captured SETUP packet.
       Reading a byte from this register advances the FIFO. The first eight bytes read
       from this contain the core SETUP packet.

EV_ENABLE Register

Offset

Range

Access

Field

0x0010

[0:0]

read-write

mask

EV_PENDING Register

Offset

Range

Access

Field

0x0011

[0:0]

read-write

mask

USBx_EP_IN - InFIFOInterface

ENDPOINT Register

Offset

Range

Access

Field

0x0000

[3:0]

write-only

number

Endpoint register

       number: Contains the endpoint the enqueued packet is to be transmitted on. Writing to this field
               marks the relevant packet as ready to transmit; and thus should only be written after a
               full packet has been written into the FIFO. If no data has been placed into the DATA FIFO,
               a zero-length packet is generated.
               Note that any IN requests that do not match the endpoint number are automatically NAK'd.

STALL Register

Offset

Range

Access

Field

0x0001

[0:0]

write-only

stalled

Stall register

       stalled: When this field contains '1', any IN tokens targeting `epno` will be responded to with a
                STALL token, rather than DATA or a NAK.
                For EP0, this field will automatically be cleared when a new SETUP token is received.

PID Register

Offset

Range

Access

Field

0x0002

[0:0]

write-only

toggle

Pid register

       toggle: Sets the current PID toggle bit for the given endpoint.

STATUS Register

Offset

Range

Access

Field

0x0004

[15:0]

read-only

nak

0x0004

[19:16]

read-only

epno

0x0004

[24:24]

read-only

idle

0x0004

[25:25]

read-only

have

0x0004

[26:26]

read-only

pid

Status register

       nak:  Contains a bitmask of endpoints that have responded with a NAK since the
             last read of this register.
       epno: Contains the endpoint being transmitted on.
       idle: This value is `1` if no packet is actively being transmitted.
       have: This value is `1` if data is present in the transmit FIFO.
       pid:  Contains the current PID toggle bit for the given endpoint.

RESET Register

Offset

Range

Access

Field

0x0008

[0:0]

write-only

fifo

Reset register

       fifo: A write to this field Clears the FIFO without transmitting.

DATA Register

Offset

Range

Access

Field

0x0009

[7:0]

write-only

byte

Data register

       Each write enqueues a byte to be transmitted; gradually building a single packet to
       be transmitted. This queue should only ever contain a single packet; it is the software's
       responsibility to handle breaking requests down into packets.

EV_ENABLE Register

Offset

Range

Access

Field

0x0010

[0:0]

read-write

mask

EV_PENDING Register

Offset

Range

Access

Field

0x0011

[0:0]

read-write

mask

USBx_EP_OUT - OutFIFOInterface

CONTROL Register

Offset

Range

Access

Field

0x0000

[7:0]

read-write

address

Control register

       address: Controls the current device's USB address. Should be written after a SET_ADDRESS request
                is received. Automatically resets back to zero on a USB reset.

ENDPOINT Register

Offset

Range

Access

Field

0x0001

[3:0]

read-write

number

Endpoint register

       number: Selects the endpoint number to prime. This interface allows priming multiple endpoints
       at once. That is, multiple endpoints can be ready to receive data at a time. See the `prime`
       and `enable` bits for usage.

ENABLE Register

Offset

Range

Access

Field

0x0002

[0:0]

write-only

enabled

Enable register

       enabled: Controls whether any data can be received on any primed OUT endpoint. This bit is
                automatically cleared on receive in order to give the controller time to read data
                from the FIFO. It must be re-enabled once the FIFO has been emptied.

PRIME Register

Offset

Range

Access

Field

0x0003

[0:0]

write-only

primed

Prime register

       primed: Controls "priming" an out endpoint. To receive data on any endpoint, the CPU must first
               select the endpoint with the `epno` register; and then write a '1' into the prime and
               enable register. This prepares our FIFO to receive data; and the next OUT transaction will
               be captured into the FIFO.

               When a transaction is complete, the `enable` bit is reset; the `prime` is not. This
               effectively means that `enable` controls receiving on _any_ of the primed endpoints;
               while `prime` can be used to build a collection of endpoints willing to participate in
               receipt.

               Note that this does not apply to the control endpoint. Once the control endpoint has
               received a packet it will be un-primed and need to be re-primed before it can receive
               again. This is to ensure that we can establish an order on the receipt of the setup
               packet and any associated data.

               Only one transaction / data packet is captured per `enable` write; repeated enabling is
               necessary to capture multiple packets.

STALL Register

Offset

Range

Access

Field

0x0004

[0:0]

write-only

stalled

Stall register

       stalled: Controls STALL'ing the active endpoint. Setting or clearing this bit will set or clear
                STALL on the provided endpoint. Endpoint STALLs persist even after `epno` is changed; so
                multiple endpoints can be stalled at once by writing their respective endpoint numbers
                into `epno` register and then setting their `stall` bits.

PID Register

Offset

Range

Access

Field

0x0005

[0:0]

write-only

toggle

Pid register

       toggle: Sets the current PID toggle bit for the given endpoint.

STATUS Register

Offset

Range

Access

Field

0x0006

[3:0]

read-only

epno

0x0006

[8:8]

read-only

have

0x0006

[9:9]

read-only

pid

Status register

       epno: Contains the endpoint number associated with the data in the FIFO -- that is,
             the endpoint number on which the relevant data was received.
       have: `1` iff data is available in the FIFO.
       pid:  Contains the current PID toggle bit for the given endpoint.

RESET Register

Offset

Range

Access

Field

0x0008

[0:0]

write-only

fifo

Reset register

       fifo: Local reset for the OUT handler; clears the out FIFO.

DATA Register

Offset

Range

Access

Field

0x0009

[7:0]

read-only

byte

Data register

       Read-only register. A FIFO that returns the bytes from the most recently captured OUT transaction.
       Reading a byte from this register advances the FIFO.

       byte:    Contains the most recently received byte.

EV_ENABLE Register

Offset

Range

Access

Field

0x0020

[0:0]

read-write

mask

EV_PENDING Register

Offset

Range

Access

Field

0x0021

[0:0]

read-write

mask

Interrupts

Each of the eptri peripherals can generate the following interrupts:

USBDeviceController Registers

Interrupt

Peripheral

Description

USBx

USBDeviceController

Interrupt that triggers when the host issued a USB bus reset.

USBx_EP_CONTROL

SetupFIFOInterface

Interrupt that triggers when the host wrote a new SETUP packet to the bus.

USBx_EP_IN

InFIFOInterface

Interrupt that triggers after the peripheral has written a data packet to the bus and read back a PID ACK response from the host.

USBx_EP_OUT

OutFIFOInterface

Interrupt that triggers when the peripheral has read a data packet from the host.

Programming Guide

The programming guide provides sequence diagrams that detail the steps required to perform the various operations supported by the eptri controller.

The following pseudo-code is used through-out to indicate register operations:

Register Operations

Operation

Description

r(PERIPHERAL.register)

Read a value from the register belonging to PERIPHERAL.

w(PERIPHERAL.register, bits)

Write bits to the register belonging to PERIPHERAL.

Device Connection

Sequence diagram for USB device connection

Bus Reset

Sequence diagram for USB bus reset

Control OUT Transfers

Sequence diagram for Control OUT transfers

Control IN Transfers

Sequence diagram for Control IN transfers

Bulk OUT Transfers

Sequence diagram for Bulk OUT transfers

Bulk IN Transfers

Sequence diagram for Bulk IN transfers

luna_soc

luna_soc package

Subpackages

luna_soc.gateware package
Subpackages
luna_soc.gateware.core package
Subpackages
luna_soc.gateware.core.spiflash package
Submodules
luna_soc.gateware.core.spiflash.controller module
class luna_soc.gateware.core.spiflash.controller.SPIController(*args, src_loc_at=0, **kwargs)

Bases: Component

Wishbone generic SPI Flash Controller interface.

Provides a generic SPI Controller that can be interfaced using CSRs. Supports multiple access modes with the help of width and mask registers which can be used to configure the PHY into any supported SDR mode (single/dual/quad/octal).

class Cs(*args, src_loc_at=0, **kwargs)

Bases: Register

SPI chip select register

select : SPI chip select signal.

select: <amaranth_soc.csr.reg.Field object at 0x7f50daa057f0>
class Data(*args, src_loc_at=0, **kwargs)

Bases: Register

Data register

rx : Read the next byte in the RX FIFO tx : Write the given byte to the TX FIFO

class Phy(*args, src_loc_at=0, **kwargs)

Bases: Register

PHY control register

length : SPI transfer length in bits. width : SPI transfer bus width (1/2/4/8). mask : SPI DQ output enable mask.

class Status(*args, src_loc_at=0, **kwargs)

Bases: Register

Status register

rx_ready : RX FIFO contains data. tx_ready : TX FIFO ready to receive data.

rx_ready: <amaranth_soc.csr.reg.Field object at 0x7f50da9ec6b0>
tx_ready: <amaranth_soc.csr.reg.Field object at 0x7f50da9ec8d0>
elaborate(platform)
luna_soc.gateware.core.spiflash.mmap module
class luna_soc.gateware.core.spiflash.mmap.SPIFlashMemoryMap(*args, src_loc_at=0, **kwargs)

Bases: Component

Wishbone Memory-mapped SPI Flash controller.

Supports sequential accesses so that command and address is only sent when necessary.

MMAP_DEFAULT_TIMEOUT = 256
OE_MASK = {1: 1, 2: 3, 4: 15, 8: 255}
elaborate(platform)
static reverse_bytes(word)
luna_soc.gateware.core.spiflash.phy module
class luna_soc.gateware.core.spiflash.phy.ECP5ConfigurationFlashInterface(*args, src_loc_at=0, **kwargs)

Bases: Elaboratable

Gateware that creates a connection to an MSPI configuration flash.

Automatically uses appropriate platform resources; this abstracts away details necessary to e.g. drive the MCLK lines on an ECP5, which has special handling.

__init__(*, bus)

Params: bus – The SPI bus object to extend.

elaborate(platform)
class luna_soc.gateware.core.spiflash.phy.SPIClockGenerator(*args, src_loc_at=0, **kwargs)

Bases: Elaboratable

elaborate(platform)
class luna_soc.gateware.core.spiflash.phy.SPIPHYController(*args, src_loc_at=0, **kwargs)

Bases: Component

Provides a generic PHY that can be used by a SPI flash controller.

It supports single/dual/quad/octal output reads from the flash chips.

elaborate(platform)
luna_soc.gateware.core.spiflash.port module
class luna_soc.gateware.core.spiflash.port.SPIControlPort(data_width)

Bases: Signature

class luna_soc.gateware.core.spiflash.port.SPIControlPortCDC(*args, src_loc_at=0, **kwargs)

Bases: Component

Converts one SPIControlPort between clock domains.

elaborate(platform)
class luna_soc.gateware.core.spiflash.port.SPIControlPortCrossbar(*args, src_loc_at=0, **kwargs)

Bases: Component

Merge multiple SPIControlPorts with a round-robin scheduler.

elaborate(platform)
get_port(index)
class luna_soc.gateware.core.spiflash.port.StreamCore2PHY(data_width)

Bases: Signature

create(*, path=None, src_loc_at=0)

Create an interface object from this signature.

The default Signature.create() implementation consists of one line:

def create(self, *, path=None, src_loc_at=0):
    return PureInterface(self, path=path, src_loc_at=1 + src_loc_at)

This implementation creates an interface object from this signature that serves purely as a container for the attributes corresponding to the signature members, and implements no behavior. Such an implementation is sufficient for signatures created ad-hoc using the :py:`Signature({ ... })` constructor as well as simple signature subclasses.

When defining a Signature subclass that needs to customize the behavior of the created interface objects, override this method with a similar implementation that references the class of your custom interface object:

class CustomSignature(wiring.Signature):
    def create(self, *, path=None, src_loc_at=0):
        return CustomInterface(self, path=path, src_loc_at=1 + src_loc_at)

class CustomInterface(wiring.PureInterface):
    @property
    def my_property(self):
        ...

The :py:`path` and :py:`src_loc_at` arguments are necessary to ensure the generated signals have informative names and accurate source location information.

The custom create() method may take positional or keyword arguments in addition to the two listed above. Such arguments must have a default value, because the SignatureMembers.create() method will call the Signature.create() member without these additional arguments when this signature is a member of another signature.

property data_width
class luna_soc.gateware.core.spiflash.port.StreamCore2PHYInterface(signature, *, path=None, src_loc_at=0)

Bases: PureInterface

property payload

Joint signal with all data.

class luna_soc.gateware.core.spiflash.port.StreamPHY2Core(data_width)

Bases: Signature

create(*, path=None, src_loc_at=0)

Create an interface object from this signature.

The default Signature.create() implementation consists of one line:

def create(self, *, path=None, src_loc_at=0):
    return PureInterface(self, path=path, src_loc_at=1 + src_loc_at)

This implementation creates an interface object from this signature that serves purely as a container for the attributes corresponding to the signature members, and implements no behavior. Such an implementation is sufficient for signatures created ad-hoc using the :py:`Signature({ ... })` constructor as well as simple signature subclasses.

When defining a Signature subclass that needs to customize the behavior of the created interface objects, override this method with a similar implementation that references the class of your custom interface object:

class CustomSignature(wiring.Signature):
    def create(self, *, path=None, src_loc_at=0):
        return CustomInterface(self, path=path, src_loc_at=1 + src_loc_at)

class CustomInterface(wiring.PureInterface):
    @property
    def my_property(self):
        ...

The :py:`path` and :py:`src_loc_at` arguments are necessary to ensure the generated signals have informative names and accurate source location information.

The custom create() method may take positional or keyword arguments in addition to the two listed above. Such arguments must have a default value, because the SignatureMembers.create() method will call the Signature.create() member without these additional arguments when this signature is a member of another signature.

property data_width
class luna_soc.gateware.core.spiflash.port.StreamPHY2CoreInterface(signature, *, path=None, src_loc_at=0)

Bases: PureInterface

property payload

Joint signal with all data.

luna_soc.gateware.core.spiflash.utils module
class luna_soc.gateware.core.spiflash.utils.RoundRobin(*args, src_loc_at=0, **kwargs)

Bases: Elaboratable

Round-robin scheduler.

For a given set of requests, the round-robin scheduler will grant one request. Once it grants a request, if any other requests are active, it grants the next active request with a greater number, restarting from zero once it reaches the highest one.

Use EnableInserter to control when the scheduler is updated.

Parameters
countint

Number of requests.

Attributes
requestsSignal(count), in

Set of requests.

grantSignal(range(count)), out

Number of the granted request. Does not change if there are no active requests.

validSignal(), out

Asserted if grant corresponds to an active request. Deasserted otherwise, i.e. if no requests are active.

elaborate(platform)
class luna_soc.gateware.core.spiflash.utils.WaitTimer(*args, src_loc_at=0, **kwargs)

Bases: Elaboratable

elaborate(platform)
Module contents
class luna_soc.gateware.core.spiflash.ECP5ConfigurationFlashInterface(*args, src_loc_at=0, **kwargs)

Bases: Elaboratable

Gateware that creates a connection to an MSPI configuration flash.

Automatically uses appropriate platform resources; this abstracts away details necessary to e.g. drive the MCLK lines on an ECP5, which has special handling.

__init__(*, bus)

Params: bus – The SPI bus object to extend.

elaborate(platform)
class luna_soc.gateware.core.spiflash.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

SPI Flash peripheral main module.

This class provides a wrapper that can instantiate both SPIController and SPIFlashMemoryMap and connect them to the PHY.

Both options share access to the PHY using a crossbar. Also, performs CDC if a different clock is used in the PHY.

elaborate(platform)
class luna_soc.gateware.core.spiflash.PinSignature

Bases: Signature

class luna_soc.gateware.core.spiflash.SPIPHYController(*args, src_loc_at=0, **kwargs)

Bases: Component

Provides a generic PHY that can be used by a SPI flash controller.

It supports single/dual/quad/octal output reads from the flash chips.

elaborate(platform)
luna_soc.gateware.core.usb2 package
Submodules
luna_soc.gateware.core.usb2.device module

Contains the organizing gateware used to add USB Device functionality to your own designs; including the core USBDevice class.

class luna_soc.gateware.core.usb2.device.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

SoC controller for a USBDevice.

Breaks our USBDevice control and status signals out into registers so a CPU / Wishbone master can control our USB device.

The attributes below are intended to connect to a USBDevice. Typically, they’d be created by using the .controller() method on a USBDevice object, which will automatically connect all relevant signals.

Attributes
connect: Signal(), output

High when the USBDevice should be allowed to connect to a host.

class Control(*args, src_loc_at=0, **kwargs)

Bases: Register

Control register

connect: Set this bit to ‘1’ to allow the associated USB device to connect to a host. low_speed_only: Set this bit to ‘1’ to force the device to operate at low speed. full_speed_only: Set this bit to ‘1’ to force the device to operate at full speed.

connect: <amaranth_soc.csr.reg.Field object at 0x7f50da6f25b0>
full_speed_only: <amaranth_soc.csr.reg.Field object at 0x7f50da82b280>
low_speed_only: <amaranth_soc.csr.reg.Field object at 0x7f50da9674d0>
class Status(*args, src_loc_at=0, **kwargs)

Bases: Register

Status register

speed: Indicates the current speed of the USB device. 0 indicates High; 1 => Full,

2 => Low, and 3 => SuperSpeed (incl SuperSpeed+).

speed: <amaranth_soc.csr.reg.Field object at 0x7f50da804550>
attach(device: USBDevice)

Returns a list of statements necessary to connect this to a USB controller.

The returned values makes all of the connections necessary to provide control and fetch status from the relevant USB device. These can be made either combinationally or synchronously, but combinational is recommended; as these signals are typically fed from a register anyway.

Parameters
device: USBDevice

The USBDevice object to be controlled.

elaborate(platform)
luna_soc.gateware.core.usb2.ep_control module

Implementation of a Triple-FIFO endpoint manager.

Equivalent (but not binary-compatbile) implementation of ValentyUSB’s eptri.

For an example, see examples/usb/eptri or TinyUSB’s luna/dcd_eptri.c.

class luna_soc.gateware.core.usb2.ep_control.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

Setup component of our eptri-equivalent interface.

Implements the USB Setup FIFO, which handles SETUP packets on any endpoint.

This interface is similar to an OutFIFOInterface, but always ACKs packets, and does not allow for any flow control; as a USB device must always be ready to accept control packets. [USB2.0: 8.6.1]

Attributes
interface: EndpointInterface

Our primary interface to the core USB device hardware.

class Control(*args, src_loc_at=0, **kwargs)

Bases: Register

Control register

address: Controls the current device’s USB address. Should be written after a SET_ADDRESS

request is received. Automatically resets back to zero on a USB reset.

address: <amaranth_soc.csr.reg.Field object at 0x7f50da872960>
class Data(*args, src_loc_at=0, **kwargs)

Bases: Register

Data register

A FIFO that returns the bytes from the most recently captured SETUP packet. Reading a byte from this register advances the FIFO. The first eight bytes read from this contain the core SETUP packet.

byte: <amaranth_soc.csr.reg.Field object at 0x7f50da7387d0>
class Reset(*args, src_loc_at=0, **kwargs)

Bases: Register

Reset register

fifo: Local reset control for the SETUP handler; writing a ‘1’ to this register clears

the handler state.

fifo: <amaranth_soc.csr.reg.Field object at 0x7f50da7385f0>
class Status(*args, src_loc_at=0, **kwargs)

Bases: Register

Status register

address: Holds the current device’s active USB address. epno: The endpoint number associated with the most recently captured SETUP packet. have: 1 iff data is available in the FIFO.

address: <amaranth_soc.csr.reg.Field object at 0x7f50da8dbd50>
epno: <amaranth_soc.csr.reg.Field object at 0x7f50da8dbcd0>
have: <amaranth_soc.csr.reg.Field object at 0x7f50da810130>
elaborate(platform)
luna_soc.gateware.core.usb2.ep_in module

Implementation of a Triple-FIFO endpoint manager.

Equivalent (but not binary-compatbile) implementation of ValentyUSB’s eptri.

For an example, see examples/usb/eptri or TinyUSB’s luna/dcd_eptri.c.

class luna_soc.gateware.core.usb2.ep_in.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

IN component of our eptri-equivalent interface.

Implements the FIFO that handles eptri IN requests. This FIFO collects USB data, and transmits it in response to an IN token. Like all eptri interfaces; it can handle only one pending packet at a time.

Attributes
interface: EndpointInterface

Our primary interface to the core USB device hardware.

class Data(*args, src_loc_at=0, **kwargs)

Bases: Register

Data register

Each write enqueues a byte to be transmitted; gradually building a single packet to be transmitted. This queue should only ever contain a single packet; it is the software’s responsibility to handle breaking requests down into packets.

byte: <amaranth_soc.csr.reg.Field object at 0x7f50da739850>
class Endpoint(*args, src_loc_at=0, **kwargs)

Bases: Register

Endpoint register

number: Contains the endpoint the enqueued packet is to be transmitted on. Writing to this field

marks the relevant packet as ready to transmit; and thus should only be written after a full packet has been written into the FIFO. If no data has been placed into the DATA FIFO, a zero-length packet is generated. Note that any IN requests that do not match the endpoint number are automatically NAK’d.

number: <amaranth_soc.csr.reg.Field object at 0x7f50da738b30>
class Pid(*args, src_loc_at=0, **kwargs)

Bases: Register

Pid register

toggle: Sets the current PID toggle bit for the given endpoint.

toggle: <amaranth_soc.csr.reg.Field object at 0x7f50da738e90>
class Reset(*args, src_loc_at=0, **kwargs)

Bases: Register

Reset register

fifo: A write to this field Clears the FIFO without transmitting.

fifo: <amaranth_soc.csr.reg.Field object at 0x7f50da739610>
class Stall(*args, src_loc_at=0, **kwargs)

Bases: Register

Stall register

stalled: When this field contains ‘1’, any IN tokens targeting epno will be responded to with a

STALL token, rather than DATA or a NAK. For EP0, this field will automatically be cleared when a new SETUP token is received.

stalled: <amaranth_soc.csr.reg.Field object at 0x7f50da738cb0>
class Status(*args, src_loc_at=0, **kwargs)

Bases: Register

Status register

nak: Contains a bitmask of endpoints that have responded with a NAK since the

last read of this register.

epno: Contains the endpoint being transmitted on. idle: This value is 1 if no packet is actively being transmitted. have: This value is 1 if data is present in the transmit FIFO. pid: Contains the current PID toggle bit for the given endpoint.

epno: <amaranth_soc.csr.reg.Field object at 0x7f50da739130>
have: <amaranth_soc.csr.reg.Field object at 0x7f50da739370>
idle: <amaranth_soc.csr.reg.Field object at 0x7f50da7392b0>
nak: <amaranth_soc.csr.reg.Field object at 0x7f50da739070>
pid: <amaranth_soc.csr.reg.Field object at 0x7f50da739430>
__init__(max_packet_size=512)
Parameters
max_packet_size: int, optional

Sets the maximum packet size that can be transmitted on this endpoint. This should match the value provided in the relevant endpoint descriptor.

elaborate(platform)
luna_soc.gateware.core.usb2.ep_out module

Implementation of a Triple-FIFO endpoint manager.

Equivalent (but not binary-compatbile) implementation of ValentyUSB’s eptri.

For an example, see examples/usb/eptri or TinyUSB’s luna/dcd_eptri.c.

class luna_soc.gateware.core.usb2.ep_out.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

OUT component of our eptri

Implements the OUT FIFO, which handles receiving packets from our host.

Attributes
interface: EndpointInterface

Our primary interface to the core USB device hardware.

class Control(*args, src_loc_at=0, **kwargs)

Bases: Register

Control register

address: Controls the current device’s USB address. Should be written after a SET_ADDRESS request

is received. Automatically resets back to zero on a USB reset.

address: <amaranth_soc.csr.reg.Field object at 0x7f50da739bb0>
class Data(*args, src_loc_at=0, **kwargs)

Bases: Register

Data register

Read-only register. A FIFO that returns the bytes from the most recently captured OUT transaction. Reading a byte from this register advances the FIFO.

byte: Contains the most recently received byte.

byte: <amaranth_soc.csr.reg.Field object at 0x7f50da73abd0>
class Enable(*args, src_loc_at=0, **kwargs)

Bases: Register

Enable register

enabled: Controls whether any data can be received on any primed OUT endpoint. This bit is

automatically cleared on receive in order to give the controller time to read data from the FIFO. It must be re-enabled once the FIFO has been emptied.

enabled: <amaranth_soc.csr.reg.Field object at 0x7f50da739e50>
class Endpoint(*args, src_loc_at=0, **kwargs)

Bases: Register

Endpoint register

number: Selects the endpoint number to prime. This interface allows priming multiple endpoints at once. That is, multiple endpoints can be ready to receive data at a time. See the prime and enable bits for usage.

number: <amaranth_soc.csr.reg.Field object at 0x7f50da739c70>
class Pid(*args, src_loc_at=0, **kwargs)

Bases: Register

Pid register

toggle: Sets the current PID toggle bit for the given endpoint.

toggle: <amaranth_soc.csr.reg.Field object at 0x7f50da73a3f0>
class Prime(*args, src_loc_at=0, **kwargs)

Bases: Register

Prime register

primed: Controls “priming” an out endpoint. To receive data on any endpoint, the CPU must first

select the endpoint with the epno register; and then write a ‘1’ into the prime and enable register. This prepares our FIFO to receive data; and the next OUT transaction will be captured into the FIFO.

When a transaction is complete, the enable bit is reset; the prime is not. This effectively means that enable controls receiving on _any_ of the primed endpoints; while prime can be used to build a collection of endpoints willing to participate in receipt.

Note that this does not apply to the control endpoint. Once the control endpoint has received a packet it will be un-primed and need to be re-primed before it can receive again. This is to ensure that we can establish an order on the receipt of the setup packet and any associated data.

Only one transaction / data packet is captured per enable write; repeated enabling is necessary to capture multiple packets.

primed: <amaranth_soc.csr.reg.Field object at 0x7f50da73a030>
class Reset(*args, src_loc_at=0, **kwargs)

Bases: Register

Reset register

fifo: Local reset for the OUT handler; clears the out FIFO.

fifo: <amaranth_soc.csr.reg.Field object at 0x7f50da73a9f0>
class Stall(*args, src_loc_at=0, **kwargs)

Bases: Register

Stall register

stalled: Controls STALL’ing the active endpoint. Setting or clearing this bit will set or clear

STALL on the provided endpoint. Endpoint STALLs persist even after epno is changed; so multiple endpoints can be stalled at once by writing their respective endpoint numbers into epno register and then setting their stall bits.

stalled: <amaranth_soc.csr.reg.Field object at 0x7f50da73a210>
class Status(*args, src_loc_at=0, **kwargs)

Bases: Register

Status register

epno: Contains the endpoint number associated with the data in the FIFO – that is,

the endpoint number on which the relevant data was received.

have: 1 iff data is available in the FIFO. pid: Contains the current PID toggle bit for the given endpoint.

epno: <amaranth_soc.csr.reg.Field object at 0x7f50da73a5d0>
have: <amaranth_soc.csr.reg.Field object at 0x7f50da73a750>
pid: <amaranth_soc.csr.reg.Field object at 0x7f50da73a810>
__init__(max_packet_size=512)
Parameters
max_packet_size: int, optional

Sets the maximum packet size that can be transmitted on this endpoint. This should match the value provided in the relevant endpoint descriptor.

elaborate(platform)
luna_soc.gateware.core.usb2.ulpi module

ULPI interfacing hardware.

class luna_soc.gateware.core.usb2.ulpi.Signature

Bases: Signature

ULPI bus signature.

Interface attributes
iSignal

Input value of the ULPI data lines.

oSignal

Output value of the ULPI data lines.

oeSignal

True iff we’re trying to drive the ULPI data lines.

clkSignal

The ULPI clock signal.

nxtSignal

The ULPI ‘next’ throttle signal.

stpSignal

The ULPI ‘stop’ event signal.

dirSignal

The ULPI bus-direction signal.

rstSignal

The ULPI ‘reset’ signal.

Module contents
Submodules
luna_soc.gateware.core.blockram module
class luna_soc.gateware.core.blockram.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

SRAM storage peripheral.

Parameters
sizeint

Memory size in bytes.

data_widthint

The width of each memory word.

granularityint

The number of bits of data per each address.

writablebool

Memory is writable.

initlist[byte] Optional

The initial value of the relevant memory.

namestr

A descriptive name for the given memory.

Attributes
busamaranth_soc.wishbone.Interface

Wishbone bus interface.

property constant_map
elaborate(platform)
property init
luna_soc.gateware.core.ila module
class luna_soc.gateware.core.ila.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

A simple peripheral interface to the ila.

class Control(*args, src_loc_at=0, **kwargs)

Bases: Register

A CSR register.

Parameters
fieldsdict or list or Field

Collection of register fields. If None (default), a dict is populated from Python variable annotations. fields is used to create a FieldActionMap, FieldActionArray, or FieldAction, depending on its type (dict, list, or Field).

Interface attributes
elementElement

Interface between this register and a CSR bus primitive.

Attributes
fieldFieldActionMap or FieldActionArray or FieldAction

Collection of field instances.

fFieldActionMap or FieldActionArray or FieldAction

Shorthand for Register.field.

Raises
TypeError

If fields is neither None, a dict, a list, or a Field.

ValueError

If fields is not None and at least one variable annotation is a Field.

ValueError

If element.access is not readable and at least one field is readable.

ValueError

If element.access is not writable and at least one field is writable.

trigger: <amaranth_soc.csr.reg.Field object at 0x7f50db0aaba0>
class Trace(*args, src_loc_at=0, **kwargs)

Bases: Register

A CSR register.

Parameters
fieldsdict or list or Field

Collection of register fields. If None (default), a dict is populated from Python variable annotations. fields is used to create a FieldActionMap, FieldActionArray, or FieldAction, depending on its type (dict, list, or Field).

Interface attributes
elementElement

Interface between this register and a CSR bus primitive.

Attributes
fieldFieldActionMap or FieldActionArray or FieldAction

Collection of field instances.

fFieldActionMap or FieldActionArray or FieldAction

Shorthand for Register.field.

Raises
TypeError

If fields is neither None, a dict, a list, or a Field.

ValueError

If fields is not None and at least one variable annotation is a Field.

ValueError

If element.access is not readable and at least one field is readable.

ValueError

If element.access is not writable and at least one field is writable.

a: <amaranth_soc.csr.reg.Field object at 0x7f50daee4cd0>
b: <amaranth_soc.csr.reg.Field object at 0x7f50daee4e10>
c: <amaranth_soc.csr.reg.Field object at 0x7f50daf96780>
d: <amaranth_soc.csr.reg.Field object at 0x7f50daf96d70>
elaborate(platform)
luna_soc.gateware.core.timer module

A simple timer peripheral.

class luna_soc.gateware.core.timer.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

class Counter(*args, src_loc_at=0, **kwargs)

Bases: Register

A CSR register.

Parameters
fieldsdict or list or Field

Collection of register fields. If None (default), a dict is populated from Python variable annotations. fields is used to create a FieldActionMap, FieldActionArray, or FieldAction, depending on its type (dict, list, or Field).

Interface attributes
elementElement

Interface between this register and a CSR bus primitive.

Attributes
fieldFieldActionMap or FieldActionArray or FieldAction

Collection of field instances.

fFieldActionMap or FieldActionArray or FieldAction

Shorthand for Register.field.

Raises
TypeError

If fields is neither None, a dict, a list, or a Field.

ValueError

If fields is not None and at least one variable annotation is a Field.

ValueError

If element.access is not readable and at least one field is readable.

ValueError

If element.access is not writable and at least one field is writable.

__init__(width)

Counter value

class Enable(*args, src_loc_at=0, **kwargs)

Bases: Register

Counter enable

enable: <amaranth_soc.csr.reg.Field object at 0x7f50dac25c50>
class Mode(*args, src_loc_at=0, **kwargs)

Bases: Register

Timer mode. When periodic is set to 1 the counter will automatically be reset to the reload value.

periodic: <amaranth_soc.csr.reg.Field object at 0x7f50dac24050>
class Reload(*args, src_loc_at=0, **kwargs)

Bases: Register

Reload value of counter.

elaborate(platform)
luna_soc.gateware.core.uart module
class luna_soc.gateware.core.uart.Peripheral(*args, src_loc_at=0, **kwargs)

Bases: Component

class BaudRate(*args, src_loc_at=0, **kwargs)

Bases: Register

baud rate divider, defaults to init

class RxAvail(*args, src_loc_at=0, **kwargs)

Bases: Register

is ‘1’ when 1-byte receive buffer is full; reset by a read from rx_data

rxe: <amaranth_soc.csr.reg.Field object at 0x7f50dab55c50>
class RxData(*args, src_loc_at=0, **kwargs)

Bases: Register

valid to read from when rx_avail is high, last received byte

data: <amaranth_soc.csr.reg.Field object at 0x7f50da9909b0>
class TxData(*args, src_loc_at=0, **kwargs)

Bases: Register

valid to write to when tx_rdy is high, will trigger a transmit

data: <amaranth_soc.csr.reg.Field object at 0x7f50dac85a90>
class TxReady(*args, src_loc_at=0, **kwargs)

Bases: Register

is ‘1’ when 1-byte transmit buffer is empty

txe: <amaranth_soc.csr.reg.Field object at 0x7f50daea1a90>
elaborate(platform)
class luna_soc.gateware.core.uart.PinSignature

Bases: Signature

UART pin signature.

Interface attributes
txSignal

Output.

rxSignal

Input.

Module contents
luna_soc.gateware.cpu package
Submodules
luna_soc.gateware.cpu.ic module

The simplest interrupt controller.

class luna_soc.gateware.cpu.ic.InterruptController(*args, src_loc_at=0, **kwargs)

Bases: Component

add(peripheral, *, name, number=None)
elaborate(platform)
interrupts() dict[int, (<class 'str'>, <class 'amaranth.lib.wiring.Component'>)]
luna_soc.gateware.cpu.minerva module
luna_soc.gateware.cpu.vexriscv module
class luna_soc.gateware.cpu.vexriscv.VexRiscv(*args, src_loc_at=0, **kwargs)

Bases: Component

arch = 'riscv'
byteorder = 'little'
data_width = 32
elaborate(platform)
name = 'vexriscv'
property reset_addr
Module contents
Module contents
luna_soc.generate package
Submodules
luna_soc.generate.c module

Generate a C library for SoC designs.

class luna_soc.generate.c.Header(memory_map: ~amaranth_soc.memory.MemoryMap, interrupts: dict[int, (<class 'str'>, <class 'amaranth.lib.wiring.Component'>)])

Bases: object

generate(file=None, macro_name='SOC_RESOURCES', platform_name='Generic Platform')

Generate a C header file that simplifies access to the platform’s resources.

Parameters:
  • macro_name – Optional. The name of the guard macro for the C header, as a string without spaces.

  • file – Optional. If provided, this will be treated as the file= argument to the print() – function. This can be used to generate file content instead of printing to the terminal.

class luna_soc.generate.c.LinkerScript(memory_map: MemoryMap, reset_addr: int = 0)

Bases: object

generate(file=None, macro_name='SOC_RESOURCES', platform_name='Generic Platform')

Generates a ldscript that holds our primary RAM and ROM regions.

Parameters:

file – Optional. If provided, this will be treated as the file= argument to the print() – function. This can be used to generate file content instead of printing to the terminal.

luna_soc.generate.introspect module

Introspection tools for SoC designs.

luna_soc.generate.introspect.csr_base(memory_map: MemoryMap) int

Scan a memory map for the starting address for csr peripheral registers.

luna_soc.generate.introspect.csr_peripherals(memory_map: MemoryMap) dict[Name, list[ResourceInfo]]

Scan a memory map for csr peripheral registers.

luna_soc.generate.introspect.interrupts(fragment: Component) dict[int, (<class 'str'>, <class 'amaranth.lib.wiring.Component'>)]
luna_soc.generate.introspect.memory_map(fragment: Component) MemoryMap
luna_soc.generate.introspect.reset_addr(fragment: Component) MemoryMap
luna_soc.generate.introspect.soc(fragment: Component) Component
luna_soc.generate.introspect.wb_peripherals(memory_map: MemoryMap) dict[~amaranth_soc.memory.MemoryMap.Name, list[tuple[~amaranth.lib.wiring.Component, ~amaranth_soc.memory.MemoryMap.Name, (<class 'int'>, <class 'int'>)]]]

Scan a memory map for wishbone peripherals.

luna_soc.generate.rust module

Generate Rust support files for SoC designs.

class luna_soc.generate.rust.LinkerScript(memory_map: MemoryMap, reset_addr: int = 0)

Bases: object

generate(file=None)

Generate a memory.x file for the given SoC design

luna_soc.generate.svd module

Generate a SVD file for SoC designs.

class luna_soc.generate.svd.SVD(memory_map: ~amaranth_soc.memory.MemoryMap, interrupts: dict[int, (<class 'str'>, <class 'amaranth.lib.wiring.Component'>)])

Bases: object

generate(file=None, vendor='luna-soc', name='soc', description=None)
Module contents
luna_soc.util package
Submodules
luna_soc.util.readbin module
luna_soc.util.readbin.get_boot_address(filename_or_regions, offset=0)
luna_soc.util.readbin.get_mem_data(filename_or_regions, data_width=32, endianness='big', mem_size=None, offset=0)
luna_soc.util.readbin.get_mem_regions(filename_or_regions, offset)
Module contents

Submodules

luna_soc.top_level_cli module
luna_soc.top_level_cli.build(args, fragment, platform, build_dir)

Top-level build command. Invokes the build steps for each artifact to be generated.

luna_soc.top_level_cli.top_level_cli(fragment, *pos_args, **kwargs)

Runs a default CLI that assists in building and running SoC gateware.

If the user’s options resulted in the board being programmed, this returns the fragment that was programmed onto the board. Otherwise, it returns None.

Parameters:

fragment – The design to be built; or a callable that returns a fragment, – such as a Elaborable type. If the latter is provided, any keyword or positional arguments not specified here will be passed to this callable.

Module contents