CSRs

Bus

class torii.lib.soc.csr.bus.Decoder(*, addr_width: int, data_width: int, alignment: int = 0, name: str | None = None) None

CSR bus decoder.

An address decoder for subordinate CSR buses.

Although there is no functional difference between adding a set of registers directly to a Multiplexer and adding a set of registers to multiple Multiplexer that are aggregated with a Decoder, hierarchical CSR buses are useful for organizing a hierarchical design. If many peripherals are directly served by a single Multiplexer, a very large amount of ports will connect the peripheral registers with the decoder, and the cost of decoding logic would not be attributed to specific peripherals. With a decoder, only five signals per peripheral will be used, and the logic could be kept together with the peripheral.

Parameters:
Attributes:

bus (torii.lib.soc.csr.bus.Interface) – CSR bus providing access to subordinate buses.

property bus: Interface

Todo

Document Me

align_to(alignment: int) int

Align the implicit address of the next window.

See torii.lib.mem.map.MemoryMap.align_to() for details.

Return type:

int

add(sub_bus: Interface, *, addr: int | None = None, extend: bool = False) tuple[int, int, int]

Add a window to a subordinate bus.

See torii.lib.mem.map.MemoryMap.add_resource() for details.

Return type:

tuple[int, int, int]

elaborate(_: Platform | None) Module
Return type:

Module

Todo

Document Me

class torii.lib.soc.csr.bus.Element(width: int, access: Access, *, name: str | None = None, src_loc_at: int = 0) None

Peripheral-side CSR interface.

A low-level interface to a single atomically readable and writable register in a peripheral. This interface supports any register width and semantics, provided that both reads and writes always succeed and complete in one cycle.

Parameters:
  • width (int) – Width of the register.

  • access (Access) – Register access mode.

  • name (str) – Name of the underlying record.

Attributes:
  • r_data (Signal(width)) – Read data. Must be always valid, and is sampled when r_stb is asserted.

  • r_stb (Signal) – Read strobe. Registers with read side effects should perform the read side effect when this strobe is asserted.

  • w_data (Signal(width)) – Write data. Valid only when w_stb is asserted.

  • w_stb (Signal) – Write strobe. Registers should update their value or perform the write side effect when this strobe is asserted.

class Access(value)

Register access mode.

Coarse access mode for the entire register. Individual fields can have more restrictive access mode, e.g. R/O fields can be a part of an R/W register.

R = 'r'
W = 'w'
RW = 'rw'
readable() bool

Check to see if this Access mode is readable.

Return type:

bool

Returns:

boolTrue if Access is R or RW otherwise false.

writable() bool

Check to see if this Access mode is writeable.

Return type:

bool

Returns:

boolTrue if Access is W or RW otherwise false.

class torii.lib.soc.csr.bus.Interface(*, addr_width: int, data_width: int, name: str | None = None) None

CPU-side CSR interface.

A low-level interface to a set of atomically readable and writable peripheral CSR registers.

Operation

CSR registers mapped to the CSR bus are split into chunks according to the bus data width. Each chunk is assigned a consecutive address on the bus. This allows accessing CSRs of any size using any datapath width.

When the first chunk of a register is read, the value of a register is captured, and reads from subsequent chunks of the same register return the captured values. When any chunk except the last chunk of a register is written, the written value is captured; a write to the last chunk writes the captured value to the register. This allows atomically accessing CSRs larger than datapath width.

Parameters:
  • addr_width (int) – Address width. At most (2 ** addr_width) * data_width register bits will be available.

  • data_width (int) – Data width. Registers are accessed in data_width sized chunks.

  • name (str) – Name of the underlying record.

Attributes:
  • addr (Signal(addr_width)) – Address for reads and writes.

  • r_data (Signal(data_width)) – Read data. Valid on the next cycle after r_stb is asserted. Otherwise, zero. (Keeping read data of an unused interface at zero simplifies multiplexers.)

  • r_stb (Signal) – Read strobe. If addr points to the first chunk of a register, captures register value and causes read side effects to be performed (if any). If addr points to any chunk of a register, latches the captured value to r_data. Otherwise, latches zero to r_data.

  • w_data (Signal(data_width)) – Write data. Must be valid when w_stb is asserted.

  • w_stb (Signal) – Write strobe. If addr points to the last chunk of a register, writes captured value to the register and causes write side effects to be performed (if any). If addr points to any chunk of a register, latches w_data to the captured value. Otherwise, does nothing.

property memory_map: MemoryMap

Map of the bus.

class torii.lib.soc.csr.bus.Multiplexer(*, addr_width: int, data_width: int, alignment: int = 0, name: str | None = None, shadow_overlaps: int | None = None) None

CSR register multiplexer.

An address-based multiplexer for CSR registers implementing atomic updates.

This implementation assumes the following from the CSR bus:

  • an initiator must have exclusive ownership over the multiplexer for the full duration of

    a register transaction;

  • an initiator must access a register in ascending order of addresses, but it may abort a

    transaction after any bus cycle.

Writes are registered, and are performed 1 cycle after w_stb is asserted.

Alignment

Because the CSR bus conserves logic and routing resources, it is common to e.g. access a CSR bus with an n-bit data path from a CPU with a k-bit datapath (k>n) in cases where CSR access latency is less important than resource usage. In this case, two strategies are possible for connecting the CSR bus to the CPU:

  • The CPU could access the CSR bus directly (with no intervening logic other than simple

    translation of control signals). In this case, the register alignment should be set to 1 (i.e. alignment should be set to 0), and each w-bit register would occupy ceil(w/n) addresses from the CPU perspective, requiring the same amount of memory instructions to access.

  • The CPU could also access the CSR bus through a width down-converter, which would issue

    k/n CSR accesses for each CPU access. In this case, the register alignment should be set to k/n, and each w-bit register would occupy ceil(w/k) addresses from the CPU perspective, requiring the same amount of memory instructions to access.

If the register alignment (i.e. 2 ** alignment) is greater than 1, it affects which CSR bus write is considered a write to the last register chunk. For example, if a 24-bit register is used with a 8-bit CSR bus and a CPU with a 32-bit datapath, a write to this register requires 4 CSR bus writes to complete and the 4th write is the one that actually writes the value to the register. This allows determining write latency solely from the amount of addresses the register occupies in the CPU address space, and the width of the CSR bus.

Parameters:
  • addr_width (int) – Address width. See Interface.

  • data_width (int) – Data width. See Interface.

  • alignment (log2 of int) – Register alignment. See torii.lib.mem.map.MemoryMap.

  • name (str | None) – Window name

  • shadow_overlaps (int) – Maximum number of CSR registers that can share a chunk of a shadow register. Optional. If None, any number of CSR registers can share a shadow chunk. See Multiplexer._Shadow for details.

property bus: Interface

CSR bus providing access to registers.

align_to(alignment: int) int

Align the implicit address of the next register.

See torii.lib.mem.map.MemoryMap.align_to() for details.

Return type:

int

add(element: Element, *, addr: int | None = None, alignment: int | None = None, extend: bool = False) tuple[int, int]

Add a register.

See torii.lib.mem.map.MemoryMap.add_resource() for details.

Return type:

tuple[int, int]

elaborate(platform: Platform | None) Module
Return type:

Module

Todo

Document Me

Events

class torii.lib.soc.csr.event.EventMonitor(*, data_width: int, alignment: int = 0, trigger: Trigger | Literal['level', 'rise', 'fall'] = 'level') None

Event monitor.

A monitor for subordinate event sources, with a CSR bus interface.

Parameters:
Attributes:
freeze() None

Freeze the event monitor.

Once the event monitor is frozen, subordinate sources cannot be added anymore.

property src: Source

Event source.

Returns:

torii.lib.soc.event.Source – The event source whose input line is asserted by the monitor when a subordinate event is enabled and pending.

property bus: Interface

CSR bus interface.

Returns:

torii.lib.soc.csr.bus.Interface – Interface providing access to registers.

add(src: Source) None

Add a subordinate event source.

See torii.lib.soc.event.EventMap.add() for details.

elaborate(_: Platform | None) Module
Return type:

Module

Todo

Document Me

Wishbone

class torii.lib.soc.csr.wishbone.WishboneCSRBridge(csr_bus: Interface, *, data_width: int | None = None, name: str | None = None) None

Wishbone to CSR bridge.

A bus bridge for accessing CSR registers from Wishbone. This bridge supports any Wishbone data width greater or equal to CSR data width and performs appropriate address translation.

Reads and writes always take self.data_width // csr_bus.data_width + 1 cycles to complete, regardless of the select inputs. Write side effects occur simultaneously with acknowledgement.

Parameters:
  • csr_bus (torii.lib.soc.csr.bus.Interface) – CSR bus driven by the bridge.

  • data_width (int | None) – Wishbone bus data width. If not specified, defaults to csr_bus.data_width.

  • name (str | None) – Window name.

Attributes:

wb_bus (torii.lib.bus.wishbone.Interface) – Wishbone bus provided by the bridge.

elaborate(platform) Module
Return type:

Module

Todo

Document Me