dau_driver.device

Attributes

_DEVICE_MEMORY

Classes

DeviceTransport

Base class for protocol classes.

PathDeviceTransport

DeviceIdentity

What a device is called for keying purposes, and how stable that is.

DauDevice

Functions

read_u32(path, offset) → int

read_u64(path, offset) → int

_read_register_bytes(path, offset, byte_count, offset_name) → bytes

_write_register_bytes(path, offset, data) → None

_checked_offset(offset) → int

A register offset is a non-negative multiple of four; anything else is a

_offset_name(offset) → str

write_address(device, low_offset, high_offset, address, *) → None

Program an address across its LOW/HIGH register pair on any device.

Module Contents

class dau_driver.device.DeviceTransport[source]

Bases: Protocol

Base class for protocol classes.

Protocol classes are defined as:

class Proto(Protocol):
    def meth(self) -> int:
        ...

Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing).

For example:

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:

class GenProto[T](Protocol):
    def meth(self) -> T:
        ...
read_u32(offset: int) → int[source]
write_u32(offset: int, value: int) → None[source]
read_dma(device_address: int, byte_count: int) → bytes[source]
write_dma(device_address: int, data: bytes | bytearray | memoryview) → int[source]
class dau_driver.device.PathDeviceTransport[source]
user_path: pathlib.Path
h2c_path: pathlib.Path
c2h_path: pathlib.Path
read_u32(offset: int) → int[source]
write_u32(offset: int, value: int) → None[source]
read_dma(device_address: int, byte_count: int) → bytes[source]
write_dma(device_address: int, data: bytes | bytearray | memoryview) → int[source]
class dau_driver.device.DeviceIdentity[source]

What a device is called for keying purposes, and how stable that is.

kind is "bdf" when the value is the PCI endpoint the board sits at (0000:04:00.0), which survives a reboot and tells two boards of one platform apart; it is "node" when only the driver’s devnode name (xdma0) could be given, which a reboot can renumber. Callers that persist anything keyed by this should read kind before trusting it.

kind: str
value: str
__str__() → str[source]
class dau_driver.device.DauDevice[source]
name: str
backend: str
user_path: pathlib.Path
h2c_path: pathlib.Path
c2h_path: pathlib.Path
capabilities: dau_core.capabilities.DeviceCapabilities
register_window_offset: int = 0
transport: DeviceTransport | None = None
memory_bytes: int | None = None
property identity: DeviceIdentity

The most stable name this backend can give the device.

On linux-xdma that is the PCI endpoint (BDF) sysfs says owns the _user devnode, resolved through the node itself – so a device whose node is not present (a test fake) or whose backend has no sysfs to ask (macos-xdma reports no location) falls back to the devnode name, and says so through kind. Never raises.

property resolved_transport: DeviceTransport
read_register(offset: dau_core.registers.RegisterOffset | int) → int[source]
write_register(offset: dau_core.registers.RegisterOffset | int, value: int) → None[source]
write_address_register(low_offset: dau_core.registers.RegisterOffset | int, high_offset: dau_core.registers.RegisterOffset | int, address: int) → None[source]

Method form of write_address(), kept for direct callers.

check_bar_health(*, offsets: collections.abc.Sequence[dau_core.registers.RegisterOffset | int] = (RegisterOffset.MAGIC, RegisterOffset.STREAM_PROTOCOL_VERSION)) → None[source]
read_status() → dau_driver.status.DeviceStatus[source]
read_register_block_snapshot() → dau_core.registers.RegisterBlockSnapshot[source]
read_counters() → dau_driver.status.DeviceCounters[source]
_read_u64(offset: dau_core.registers.RegisterOffset | int) → int[source]
close() → None[source]
prepare_transfer(direction: dau_driver.transfer.DmaDirection, *, device_address: int, byte_count: int) → dau_driver.transfer.DmaTransfer[source]
read_dma(*, device_address: int, byte_count: int) → bytes[source]
write_dma(*, device_address: int, data: bytes | bytearray | memoryview) → dau_driver.transfer.DmaTransfer[source]
dau_driver.device.read_u32(path: pathlib.Path, offset: dau_core.registers.RegisterOffset | int) → int[source]
dau_driver.device.read_u64(path: pathlib.Path, offset: dau_core.registers.RegisterOffset | int) → int[source]
dau_driver.device._read_register_bytes(path: pathlib.Path, offset: int, byte_count: int, offset_name: str) → bytes[source]
dau_driver.device._write_register_bytes(path: pathlib.Path, offset: int, data: bytes) → None[source]
dau_driver.device._checked_offset(offset: dau_core.registers.RegisterOffset | int) → int[source]

A register offset is a non-negative multiple of four; anything else is a caller’s arithmetic error, and the transports would read or write a word somewhere unintended.

dau_driver.device._offset_name(offset: dau_core.registers.RegisterOffset | int) → str[source]
dau_driver.device._DEVICE_MEMORY
dau_driver.device.write_address(device, low_offset, high_offset, address: int, *, memory_bytes: int | None | object = _DEVICE_MEMORY) → None[source]

Program an address across its LOW/HIGH register pair on any device.

A FUNCTION, not a method, because devices here are duck-typed: test fakes and alternative transports implement write_register without subclassing DauDevice, and making this a method silently broke every one of them.

BOTH halves are always written, including a zero high half. A design whose master is wider than 32 bits keeps the high half across a LOW write, so writing only LOW inherits whatever the previous job left and quietly addresses the wrong region.

The offsets are passed explicitly rather than derived as low + 4: the job pair is adjacent but a LANE’s is not — its high half is at 0x14 because 0x04 is the result length.

memory_bytes bounds the address. It DEFAULTS to the device’s own declared memory rather than to None, because a guard that is off unless every call site remembers to switch it on is not a guard: the execution paths that program job addresses all used the plain function and so ran unbounded. Reading it off the device is a duck-typed probe on purpose — devices here are not required to subclass DauDevice, and one that does not declare its memory simply goes unbounded, as before. Pass an explicit value to override, or None to disable the check.