vhdmmio

vhdmmio concerns itself with the generation of register files. To vhdmmio, a register file is an AXI4-lite slave, consisting of any number of fields, occupying the full 4GiB address range provided by AXI4-lite for as far as the register file is concerned. Normally, not the whole 4GiB range will be accessible; this is up to the unit that's generating the addresses. For the "toplevel" register file, this would normally be some shell or bus infrastructure that only maps a certain address range to it.

vhdmmio does not provide any bus infrastructure blocks such as address decoders/demuxers. Nevertheless, it is possible to connect multiple register files together in a hierarchical way; one of the field types vhdmmio provides behaves like an AXI4-lite passthrough.

Each register file maps to a single VHDL entity and an accompanying support package for the component declaration and type definitions needed for the ports. There is also a common support package (vhdmmio_pkg.vhd) that defines shared data types, most importantly the AXI4-lite records that vhdmmio uses on the entity interfaces (intended to save you a whole lot of typing when connecting stuff together).

Because of the above, register files in a design are largely independent. However, AXI4-Lite passthrough fields can refer to other register files in the design to indicate how the register files are hooked up in the design. vhdmmio can/will be able to use this information to generate more complete documentation, and to generate C(++) header files/classes and Python classes for accessing the register file hierarchy as a whole.

The generated register files are human-readable, so if you need to debug or change something after generation, you should be able to. The entities consist of a single one-process-style FSM that use variables for state information, so for debugging you'll need a tool that can trace variables. Note that this code style implies that all output ports of vhdmmio generated entities are register outputs. This should help a little with timing closure, but the register files are not intended to be clocked insanely high. If your active logic requires a high clock speed and vhdmmio's register files can't keep up, consider a multi-clock design.

Table of contents

Register files

This is the root configuration structure for vhdmmio register files.

This structure supports the following configuration keys.

metadata

This configuration structure is used to name and document the register file.

This key must be set to a dictionary. Its structure is defined here. Not specifying the key is equivalent to specifying an empty dictionary.

features

This configuration structure is used to specify some options that affect register file as a whole.

This key must be set to a dictionary. Its structure is defined here. Not specifying the key is equivalent to specifying an empty dictionary.

entity

This configuration structure is used to configure how the MMIO entity is generated.

This key must be set to a dictionary. Its structure is defined here. Not specifying the key is equivalent to specifying an empty dictionary.

interface

This key specifies the default VHDL entity interface generation options for fields and interrupts alike.

This key must be set to a dictionary. Its structure is defined here. Not specifying the key is equivalent to specifying an empty dictionary.

fields

This key describes the fields that the register file contains.

This key must be set to a list of dictionaries, of which the structure is defined here. In addition, the subfields key can be used to define the list elements as a tree; if it is present in one of the dictionaries, the dictionary becomes a non-leaf node, with the subfields key specifying the list of child nodes. This tree is flattened during parsing, in such a way that the configuration for a flattened node becomes the root dictionary, updated with its child dictionary, all the way down to the leaf node; the non-leaf nodes essentially set the default values for their children. For example,

fields:
- a: 1
  b: 2
  c: 3
  subfields:
  - a: 5
  - d: 4

is equivalent to

fields:
- a: 5
  b: 2
  c: 3
- a: 1
  b: 2
  c: 3
  d: 4

This can be useful for specifying repetetive structures.

This key is optional. Not specifying it is equivalent to specifying an empty list.

interrupts

This key describes the interrupts that the register file contains.

This key must be set to a list of dictionaries, of which the structure is defined here.

This key is optional. Not specifying it is equivalent to specifying an empty list.

internal-io

This configuration structure can be used to expose internal signals to the VHDL entity's interface, essentially making them external.

This key must be set to a list of dictionaries, of which the structure is defined here.

This key is optional. Not specifying it is equivalent to specifying an empty list.

Metadata

This configuration structure is used to identify and document objects within vhdmmio.

This structure supports the following configuration keys.

mnemonic

The mnemonic of the object. Mnemonics are usually very short, uppercase identifiers, idiomatically used within register file descriptions. vhdmmio requires that they are unique within the current context only; that is, two fields in a single logical register cannot have the same mnemonic, but if they were in different logical registers this would be fine. However, chains of mnemonics separated by underscores must still be unique. For instance, it's illegal to have a register X containing field Y_Z and another register X_Y containing field Z.

If the mnemonic names an array, it cannot end in a number, since the array index is added to the mnemonic in various contexts.

If no mnemonic is specified, it is generated from the name by simply uppercasing it. Either name, mnemonic, or both must be specified.

This key is optional unless required by context.

name

The name of the object. Names are generally longer and more descriptive than mnemonics, but also need to be more unique; no two fields within a register file can have the same name. Matching is case-insensitive since VHDL is case-insensitive, but vhdmmio never changes the case of a name.

Like mnemonics, if the name names an array, it cannot end in a number, since the array index is added to the name in various contexts.

If no name is specified, it is generated from the mnemonic by simply lowercasing it. Either name, mnemonic, or both must be specified.

This key is optional unless required by context.

brief

A brief, one-line description of the object. This will be rendered as markdown in the documentation output. Idiomatically, the brief description should start with a lowercase letter and end in a period, so it looks good when used in a list like "<name>: <brief>". The brief may also be used as a standalone sentence; in this case, the first letter is automatically uppercased. When printed in source code comments, the description is automatically wrapped to an appropriate line length. All spacing characters, including newlines, are collapsed into a single space before the brief is used.

Brief documentation may be printed once for an array of fields or for each field index independently depending on context. To this end, the magic string {index} is replaced with the index or range as required by context:

  • If the object is not an array, it is replaced with an empty string.
  • If the object is an array and the brief refers to the entire array or a slice thereof, it is replaced with <low>..<high>.
  • If the object is an array and the brief refers to a single index, it is simply replaced with just that index.

This key is optional unless required by context.

doc

Extended documentation for the object. This is only used for documentation output, and can therefore be any valid markdown. However, avoid using ---- and ==== underlining for headers; instead use the # prefix notation. vhdmmio will automatically prefix such headers with additional hashes to get to the right header level. The brief documentation is always added as a single paragraph before the extended documentation.

Like the brief documentation, extended documentation may be printed once for an array of fields or for each field index independently depending on context. Therefore, {index} is replaced for doc in exactly the same way.

This key is optional unless required by context.

Register file options

This configuration structure specifies some miscellaneous options that affect the functionality and generation of the register file as a whole.

This structure supports the following configuration keys.

bus-width

This key specifies the width of the generated AXI4-lite slave bus.

The following values are supported:

  • 32 (default): the bus uses 32-bit data words.

  • 64: the bus uses 64-bit data words.

This key is optional unless required by context. If not specified, the default value (32) is used.

endianness

This key specifies the default endianness used for multi-block fields.

The following values are supported:

  • little (default): the default is little endian. That is, when multiple blocks are needed to describe the field(s), bit 0 of the register resides in the first block.

  • big: the default is big endian. That is, when multiple blocks are needed to describe the field(s), bit 0 of the register resides in the last block.

This key is optional unless required by context. If not specified, the default value (little) is used.

max-outstanding

This key specifies the maximum number of outstanding requests per operation (read/write) for fields that support this. This value is essentially the depth of a FIFO that stores the order in which supporting fields were accessed. Since the width of the FIFO is the 2log of the number of supporting fields, the depth configuration has very little effect if there is only one such field (everything but the FIFO control logic will be optimized away) and no effect if there is no such field.

The following values are supported:

  • 16 (default): there can be up to 16 outstanding requests.

  • an integer above or equal to 2: there can be up to this many outstanding requests.

This key is optional unless required by context. If not specified, the default value (16) is used.

insecure

This key allows you to disable the multi-word register protection features normally inferred by vhdmmio when any of the fields in the register file are sensitive to aw_prot or ar_prot. This may save some area. More information about vhdmmio's security features is available here.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

optimize

Normally, vhdmmio infers address comparators that match all word address bits in the incoming request to the field bitranges, such that decode errors are properly generated. This can be quite costly in terms of area and timing however, since in the worst case each register will get its own 30-bit address comparator. Setting this flag to yes allows vhdmmio to assign undefined behavior to unused addresses, which lets it minimize the width of these comparators.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

VHDL entity configuration

This configuration structure can be used to configure the common interfaces of the generated entity, such as the bus and the clock.

This structure supports the following configuration keys.

clock-name

This key specifies the name of the clock input port. The clock is always rising-edge-sensitive.

The value must be a string matching [a-zA-Z][a-zA-Z0-9_]* (default clk): name of the clock input port.

This key is optional unless required by context. If not specified, the default value (clk) is used.

reset-name

This key specifies the name of the reset input port. The reset input is always synchronous, but can be set to either active-high or active-low using the reset-active parameter. The default reset name can only be used when the reset is active-high due to limitations in the template; it is suggested to suffix an n when the reset signal is active-low to avoid this problem.

The value must be a string matching [a-zA-Z][a-zA-Z0-9_]* (default reset): name of the reset input port.

This key is optional unless required by context. If not specified, the default value (reset) is used.

reset-active

This key specifies for which signal level the reset signal is considered to be asserted.

The following values are supported:

  • high (default): the reset signal is active-high.

  • low: the reset signal is active-low. The default reset port name cannot be used.

This key is optional unless required by context. If not specified, the default value (high) is used.

bus-prefix

This key specifies the prefix used for the AXI4-lite bus signals, including underscore separator if one is desired. When the bus is not flattened, the signals <prefix>i and <prefix>o are generated. When flattened, the standard names for the AXI4-lite interface channels are suffixed:

  • Write address channel: awvalid, awready, awaddr and awprot;
  • Write data channel: wvalid, wready, wdata, and wstrb;
  • Write response channel: bvalid, bready, and bresp;
  • Read address channel: arvalid, arready, araddr, and arprot;
  • Read data channel: rvalid, rready, rdata, and rresp.

The value must be a string matching [a-zA-Z][a-zA-Z0-9_]* (default bus_): prefix for the bus ports.

This key is optional unless required by context. If not specified, the default value (bus_) is used.

bus-flatten

This key specifies whether records or flattened signals are desired for the bus interface.

The following values are supported:

  • no (default): the bus is not flattened; the records from vhdmmio_pkg.vhd are used.

  • yes: the bus is flattened; the standard AXI4-lite signal names are used.

This key is optional unless required by context. If not specified, the default value (no) is used.

VHDL interface configuration

Each field and interrupt in vhdmmio can register scalar and vector inputs and outputs, as well as generics. This configuration structure determines how these interfaces are exposed in the entity.

By default, the ports are grouped by field/interrupt into records while generics are flattened, but either can be overridden. It is also possible to group multiple fields/interrupts together in a single record.

This structure supports the following configuration keys.

group

Name of the group record used for ports, if any. The ports for any objects that share the same non-null group tag are combined into a single record pair (in and out).

The following values are supported:

  • null (default): port grouping is determined by the global default.

  • no: ports are not grouped in an additional record.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: ports are grouped in a record with the specified name.

This key is optional unless required by context. If not specified, the default value (null) is used.

flatten

Whether the ports for this object should be flattened or combined in a record (pair).

The following values are supported:

  • null (default): port flattening is determined by the global default.

  • no: all ports needed for this object are combined in a record specific to the object. If group is specified in addition, there will be two levels of records. For arrays, an array of records is created.

  • record: The record mentioned above is flattened out. For array objects, std_logic ports become std_logic_arrays (ascending range), and std_logic_vector ports become an array (ascending range) of an appropriately sized std_logic_vector.

  • yes: All port types are flattened to std_logics or std_logic_vectors. std_logic_vector ports for array objects are simply concatenated using the customary descending range, with the lowest-indexed field in the least-significant position.

This key is optional unless required by context. If not specified, the default value (null) is used.

generic-group

Same as group, but for generics.

The following values are supported:

  • null (default): generic grouping is determined by the global default.

  • no: generics are not grouped in an additional record.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: generics are grouped in a record with the specified name.

This key is optional unless required by context. If not specified, the default value (null) is used.

generic-flatten

Same as flatten, but for generics.

The following values are supported:

  • null (default): generic flattening is determined by the global default.

  • record: generics are not grouped in a record, but arrays remain regular arrays (possibly of std_logic_vectors).

  • yes: as above, but all std_logic-based generics are flattened to single std_logics or std_logic_vector`s. Other primitive types still receive their own custom array type for array objects.

  • no: all generics needed for this object are combined in a record specific to the object.

This key is optional unless required by context. If not specified, the default value (null) is used.

Field descriptors

A field descriptor describes either a single field or an array of fields. Each field produced by a field descriptor has exactly the same characteristics, but maps to a different bitrange, and uses a different array index on the register file interface. These bitranges are described by means of a base bitrange (bitrange, optionally offset by address), a repeat count (repeat) and the necessary strides (stride, field-stride and field-repeat). Such repetition is useful when you have an array of similar registers, for instance in a DMA controller with multiple channels, where each channel has its own set of status and control flags.

Note that this means that you can have four kinds of field descriptors:

  • singular scalar fields,
  • singular vector fields,
  • repeated/array scalar fields, and
  • repeated/array vector fields.

In the VHDL world, scalar vs. vector is distinguished by the base type used for interface signals: std_logic for scalar, and std_logic_vector(N-1 downto 0) for vectors. By default, ports that belong to the same field are gathered into a record. This record in turn becomes an array of records for repeated fields, indexed using (0 to N-1). This record and/or the arrays of std_logic_vectors can be flattened away if needed using the interface structure.

The fields themselves as well as the registers they reside in have identifiers and documentation attachted to them (mnemonic, name, brief, doc, register-*). These are obviously used for documentation generation, but also in the generated code in various ways, depending on the language backend used. A zero-indexed integer suffix is automatically added for arrays of fields.

Behavior

The behavior of the field is determined by the behavior key and associated configuration. There are predefined behaviors for a lot of functions commonly and less commonly seen in commercial peripheral register files. On rare occasions where none of the predefined behaviors fit what you need, you can use the custom behavior, which lets you specify the field-specific VHDL code directly.

Access to the field can optionally be denied based on the AXI4L aw_prot and ar_prot fields (read-deny and write-deny). The VHDL code generated for the field can be further customized using the interface key.

Field behaviors can be read-write, read-only, or write-only. Read-only fields can overlap with write-only fields.

Logical registers and blocks

When parsing a register file description, vhdmmio flattens the field descriptors into fields, and then groups them again by address and operation (read/write). Such groups are called logical registers.

It is important to note here that even though each field essentially describes the shape of the logical register that surrounds it using the addressing keys, logical registers cannot overlap. The only exception is that a logical register with only write-only fields can overlap/differ from a logical register with only read-only fields.

A logical register consists of one or more blocks. A block is a single addressable unit, consisting of a base addess and a mask. The mask allows the block to be bigger than a single bus word, by ignoring one or more bits in the comparison. Some field behaviors use these ignored bits for purposes other than address matching; for example, the AXI passthrough behavior uses them to construct the downstream bus addresses.

Multiple blocks are assigned to a logical register when it has fields mapped to it with bit indices beyond the width of the bus; the higher-order bits carry over into a neighboring block until all fields have a place. Either little- or big-endian mode can be specified for this; in little-endian mode the LSB of the logical register resides in the first block, while in big-endian mode the MSB resides in the first block.

The addresses of the blocks are computed by binary-incrementing the non-masked bits address. For example, if the base address for a field is specified to end with binary 10--10--, consecutive blocks will be at addresses 10--11--, 11--00--, 11--01--, and so on.

Atomic access to multi-block registers

vhdmmio ensures that logical registers that span multiple blocks are accessed atomically by means of holding registers. It does so by inferring central read/write holding registers as large as the largest logical register in the register file minus the bus width. For reads, reading from the first block actually performs the read, delivering the low/high word to the bus immediately (little-/big-endian), and saving the rest in the read holding register. Reads to the subsequent blocks simply return whatever is in the holding register. The inverse is done for writes: writing to the last block actually performs the write, while the preceding accesses write the data and strobe signals to the write holding register.

The advantage of sharing holding registers is that it reduces the size of the address decoder and read multiplexer; many addresses taking data from the same source is advantageous for both area and timing. The primary disadvantage is that it only works properly when the blocks are accessed sequentially and completely. It is up to the bus master to enforce this; if it fails to do so, accesses may end up reading or writing garbage. You can therefore generally NOT mix purely AXI4L multi-master systems with multi-block registers.

If you need both multi-block registers and have multiple masters, either use full AXI4 arbiters and use the ar_lock/aw_lock signals appropriately, ensure mutually-exclusive access by means of software solutions, or implement the desired behavior yourself. The necessary write holding registers are essentially just control fields, while the read holding registers are latching fields.

Multi-block registers with shared holding registers also has security implications: a malicious piece of code may intentionally try to violate the aforementioned assumptions to manipulate or eavesdrop accesses made by another program/bus master. This is particularly important when the AXI4L aw_prot or ar_prot signals are used to restrict access to certain fields. More information on this subject can be found here.

Configuration keys

This structure supports the following configuration keys.

behavior

This key describes the behavior of this field or array of fields.

This key can take the following values:

  • primitive: base class for regular field behavior. Normally not used directly; it's easier to use one of its specializations:

    • Constant fields for reading the design-time configuration of the hardware:

      • constant: field which always reads as the same constant value.

      • config: field which always reads as the same value, configured through a generic.

    • Status fields for monitoring hardware:

      • status: field which always reflects the current state of an incoming signal.

      • internal-status: field which always reflects the current state of an internal signal.

      • latching: status field that is only updated by hardware when a write-enable flag is set.

    • Control fields for configuring hardware:

      • control: basic control field, i.e. written by software and read by hardware.

      • internal-control: like control, but drives an internal signal.

    • Flag-like fields for signalling events from hardware to software:

      • flag: one flag per bit, set by hardware and explicitly cleared by an MMIO write.

      • volatile-flag: like flag, but implicitly cleared on read.

      • internal-flag: like flag, but set by an internal signal.

      • volatile-internal-flag: combination of volatile-flag and internal-flag.

    • Flag-like fields for signalling requests from software to hardware:

      • strobe: one flag per bit, strobed by an MMIO write to signal some request to hardware.

      • internal-strobe: one flag per bit, strobed by an MMIO write to signal some request to another vhdmmio construct.

      • request: like strobe, but the request flags stay high until acknowledged by hardware.

      • multi-request: allows multiple software-to-hardware requests to be queued up atomically by counting.

    • Fields for counting events:

    • Fields for interfacing with AXI streams:

  • Fields for interfacing with AXI4-lite busses:

    • axi: connects a field to an AXI4-lite master port for generating hierarchical bus structures.
  • Fields for controlling vhdmmio-managed interrupts:

  • custom: allows you to specify the field-specific VHDL code manually.

Depending on the value, additional configuration keys may be supported or required. These must be specified in the same dictionary that this key resides in. Refer to the documentation for the individual values for more information.

address

This key specifies the base address and block mask for the logical register that the first field described by this descriptor resides in.

The following values are supported:

  • an integer above or equal to 0: specifies the byte address. The address LSBs that index bytes within the bus word are ignored per the AXI4L specification.

  • a hex/bin integer with don't cares: as before, but specified as a string representation of a hexadecimal or binary integer which may contain don't cares (-). The don't care bits mask out address bits in addition to the byte index LSBs. In hexadecimal integers, bit-granular don't-cares can be specified by inserting four-bit binary blocks enclosed in square braces in place of a hex digit.

  • <address>/<size>: as before, but the number of ignored LSBs is explicitly set. This is generally a more convenient notation to use when assigning large blocks of memory to a field.

  • <address>|<ignore>: specifies the byte address and ignored bits using two integers. Both integers can be specified in hexadecimal, binary, or decimal. A bit which is set in the <ignore> value is ignored by the address matcher.

  • <address>&<mask>: specifies the byte address and mask using two integers. Both integers can be specified in hexadecimal, binary, or decimal. A bit which is not set in the <ignore> value is ignored by the address matcher.

This key is required.

conditions

This key specifies additional address match conditions for the logical register surrounding the fields described by this descriptor. These are primarily intended to construct paged or indirect-access register files, which may be useful when not enough address space is allocated to the register file to fit all the registers, or when you want to emulate legacy register files such as a 16550 UART.

The value for this key must match for all fields in the register, so if you use this, it is recommended to use the subfields key to group all fields that belong to the register together so you only have to specify it once. In the future, vhdmmio may be extended to allow this value to be field-specific.

This key must be set to a list of dictionaries, of which the structure is defined here.

This key is optional. Not specifying it is equivalent to specifying an empty list.

endianness

This key specifies the endianness of the logical register surrounding the fields described by this descriptor.

The following values are supported:

  • null (default): the endianness is taken from the global default (little), the register file default specified in the features key, or from other fields within the register that do specify a value.

  • little: the logical register is little endian. That is, when multiple blocks are needed to describe the field(s), bit 0 of the register resides in the first block.

  • big: the logical register is big endian. That is, when multiple blocks are needed to describe the field(s), bit 0 of the register resides in the last block.

This key is optional unless required by context. If not specified, the default value (null) is used.

bitrange

This key specifies the position of the first field described by this descriptor within the surrounding logical register, and specifies its vectorness.

Bit indices cannot go below 0, but they can be greater than or equal to the bus width. In this case, the field "spills over" into the subsequent block. For instance, for a 32-bit bus and little-endian endianness, 8:47..8 maps to:

Address 31..24 23..16 15..8 7..0 Block name
0x08 23..16 15..8 7..0 ...L
0x0C 39..32 31..24 ...H

For big-endian it would be:

Address 31..24 23..16 15..8 7..0 Block name
0x08 39..32 31..24 ...H
0x0C 23..16 15..8 7..0 ...L

Following the usual nomenclature, 0x08 and 0x0C would be two different registers, usually called high and low or some abbreviation thereof. vhdmmio calls 0x08 and 0x0C physical registers (or, more generally, blocks, which can have an arbitrary bitmask for the address), which together form a single logical register.

Some output formats require unique names/mnemonics for blocks. Since names can only be specified for logical registers as a whole, vhdmmio needs to uniquify the identifiers on its own. It does this using the following rules:

  • logical registers with one block do not receive any name/mnemonic suffix.
  • logical registers with two blocks receive _high/H and _low/L suffixes for their name/mnemonic based on endianness.
  • logical registers with more than two blocks receive alphabetical suffixes based on the block index (that is, regardless of endianness). The name suffixes have the form _<lowercase>, while the mnemonic suffixes are simply an uppercase letter.

When the block address bitmask is nontrivial, the "subsequent block" concept requires further elaboration. Consider for instance the address 0b10--10-- in a 32-bit register file. You could argue that the next block is 0b11--10-- or 0b10--11--. vhdmmio opts for the latter. Specifically, the final block addresses for each block and each of the the four subaddresses would become:

Block Mask Sub 0 Sub 1 Sub 2 Sub 3
0 0b10--10-- 0x088 0x098 0x0A8 0x0B8
1 0b10--11-- 0x08C 0x09C 0x0AC 0x0BC
2 0b11--00-- 0x0C0 0x0D0 0x0E0 0x0F0
3 0b11--01-- 0x0C4 0x0D4 0x0E4 0x0F4
4 0b11--10-- 0x0C8 0x0D8 0x0E8 0x0F8
5 0b11--11-- 0x0CC 0x0DC 0x0EC 0x0FC
6 0b100--00-- 0x100 0x110 0x120 0x130
... ... ... ... ... ...

For field descriptors that describe an array of fields through the repeat key, this bitrange specifies the position of the first field in the array. Subsequent field positions are inferred based on field-stride and field-repeat.

The following values are supported:

  • null (default): the field occupies the entire bus word, and is thus a vector of the same size as the bus.

  • an integer above or equal to 0: the field occupies a single bit with the specified index, and is thus a scalar.

  • <high>..<low>: the field occupies the given inclusive bitrange, and is thus a vector of size <high> - <low> + 1.

This key is optional unless required by context. If not specified, the default value (null) is used.

subaddress

This key specifies how the subaddress for this field is generated. This subaddress is used for memory-like fields, that need an address in addition to read/write data.

If you leave this list empty or unspecified, the default is to build the subaddress by concatenating the masked word address bits. This is usually what you want. For instance, putting a 64-bit AXI field into a 32-bit register file yields an address like 0b----0--. The block with the first halfword then resides at that address, while the block with the second halfword is at 0b----1--. The four don't-cares to the left of the block index bit form the subaddress, which the AXI field uses as a 64-bit word address, leading to natural ordering.

For more advanced use cases, you can use this key to specify the structure of the subaddress manually. It must be a list of so-called components, each of which represents one or more subaddress bits taken from some source. The source can be the incoming address, an internal signal, an external input signal, or constant zero. The components are then concatenated in LSB to MSB order, and optionally summed with subaddress_offset to get the final subaddress.

This key must be set to a list of dictionaries, of which the structure is defined here.

This key is optional. Not specifying it is equivalent to specifying an empty list.

subaddress-offset

This key allows you to specify a constant offset for the subaddress. The value is added to the result of the logic specified by the subaddress key using a full adder before it is passed to the field. This behavior can not always be emulated by entries in the subaddress key alone due to the ripple carry logic.

Note that subaddresses are usually word-oriented. Fields can be non-power-of-two-bytes wide, so byte addresses are often meaningless.

The following values are supported:

  • 0 (default): no offset is applied.

  • a different integer: the given (word) offset is applied to the subaddress.

This key is optional unless required by context. If not specified, the default value (0) is used.

repeat

This value specifies whether this field descriptor describes a single field or an array of fields.

By default, the individual fields are placed in the same register, as if they were concatenated in LSB to MSB order. This can be customized using the field-repeat, stride, and field-stride keys.

The following values are supported:

  • null (default): the descriptor describes a single field.

  • an integer above or equal to 1: the descriptor describes an array field of the given size.

This key is optional unless required by context. If not specified, the default value (null) is used.

field-repeat

This value specifies how many times this field is repeated within each logical register before moving on to the next logical register. For example, a field descriptor with a repeat of 7 and a field-repeat of 3 may look like this:

Address Byte 3 Byte 2 Byte 1 Byte 0
Base Field 2 Field 1 Field 0
Base + 4 Field 5 Field 4 Field 3
Base + 8 Field 6

With field-repeat set to null instead, they get grouped in the same logical register, despite becoming wider than the bus (refer to the docs for bitrange for more info):

Address Byte 3 Byte 2 Byte 1 Byte 0
Base Field 3 Field 2 Field 1 Field 0
(cont.) Field 6 Field 5 Field 4

The following values are supported:

  • null (default): all fields are placed in the same logical register.

  • 1: each field gets its own logical register.

  • an integer above or equal to 2: the given amount of fields are placed in each logical register.

This key is optional unless required by context. If not specified, the default value (null) is used.

stride

This value specifies by how many blocks the address should be advanced when moving to the next logical register due to field-repeat < repeat.

The following values are supported:

  • 1 (default): the address is incremented by one block. Note that this default is not correct when the logical register is wider than the bus.

  • a different integer: the address is incremented by this amount of blocks each time. Negative numbers can be used for big-endian indexation.

This key is optional unless required by context. If not specified, the default value (1) is used.

field-stride

This value specifies by how many bits the bitrange low/high indices should be advanced when moving to the next field within a single logical register.

The following values are supported:

  • null (default): the bit index is incremented by the width of the field.

  • an integer: the bit index is incremented by this amount of bits each time. Negative values are allowed, as long as the base bitrange is high enough to prevent the final bit indices from falling below zero.

This key is optional unless required by context. If not specified, the default value (null) is used.

Metadata keys

This configuration structure is used to name and document the field.

More information about this structure may be found here.

The following configuration keys are used to configure this structure.

mnemonic

This key is documented here.

name

This key is documented here.

brief

This key is documented here.

doc

This key is documented here.

register-*

This optional configuration structure can be used to name and document the logical register that this field resides in.

Registers can have the same or different metadata attached to them based on the bus access mode (read/write). In the presence of multiple metadata sources, the first one encountered in the following list is used for the read metadata:

  • the register metadata for the least significant readable field in the logical register that carries it;
  • the register metadata for the least significant writable field in the logical register that carries it;
  • generated from the field metadata for the least significant readable field.
  • generated from the field metadata for the least significant writable field.

The generated metadata copies the mnemonic from the field, and uses the field's name with '_reg' suffix for the name. The generated brief just lists the fields in the register.

The priority list is the same for writes, but with points 1 and 2 flipped around (3 and 4 are NOT flipped). If the metadata for the two access modes resolves to the same object, the register is documented once as being R/W, even if some fields are read- or write-only and/or overlap that way. Otherwise, it is documented twice, once as read-only and once as write-only.

For example, in the 16550 UART, register 0/DLAB 0 is commonly referred to as the receiver buffer register (RBR) in read mode and the transmitter holding register (THR) in write mode, so you might want to document them separately. On the other hand, you could also document them once as a FIFO access register (FAR, for instance). This is mostly a matter of taste.

More information about this structure may be found here.

The following configuration keys are used to configure this structure. This structure is optional, so it is legal to not specify any of them, except when this structure is required by context.

register-mnemonic

This key is documented here.

register-name

This key is documented here.

register-brief

This key is documented here.

register-doc

This key is documented here.

read-allow-*

These keys describe which AXI4L ar_prot values are acceptable for read transactions. By default, the ar_prot field is ignored, so all masters can read from the field(s). These keys have no effect for write-only fields.

More information about this structure may be found here.

The following configuration keys are used to configure this structure.

read-allow-user

This key is documented here.

read-allow-privileged

This key is documented here.

read-allow-secure

This key is documented here.

read-allow-nonsecure

This key is documented here.

read-allow-data

This key is documented here.

read-allow-instruction

This key is documented here.

write-allow-*

These keys describe which AXI4L aw_prot values are acceptable for write transactions. By default, the aw_prot field is ignored, so all masters can write to the field(s). These keys have no effect for read-only fields.

More information about this structure may be found here.

The following configuration keys are used to configure this structure.

write-allow-user

This key is documented here.

write-allow-privileged

This key is documented here.

write-allow-secure

This key is documented here.

write-allow-nonsecure

This key is documented here.

write-allow-data

This key is documented here.

write-allow-instruction

This key is documented here.

Interface keys

These keys specify how the VHDL entity interface is generated.

More information about this structure may be found here.

The following configuration keys are used to configure this structure.

group

This key is documented here.

flatten

This key is documented here.

generic-group

This key is documented here.

generic-flatten

This key is documented here.

primitive behavior

This is the base class for regular field behavior. It can be used for everything from simple status/control fields to stream interfaces and performance counters. Most behaviors simply derive from this by overriding some parameters and changing defaults for others.

A primitive field has up to two internal registers associated with it. One contains data, and is thus as wide as the field is; the other is a single bit representing whether the data register is valid. How these registers are initialized and used (if at all) depends entirely on the configuration.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • disabled (default): read access is disabled.

  • error: reads always return a slave error.

  • enabled: normal read access to field, ignoring valid bit.

  • valid-wait: as above, but blocks until field is valid.

  • valid-only: as above, but fails when field is not valid.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

after-bus-read

Configures what happens after a bus read.

The following values are supported:

  • nothing (default): no extra operation after read.

  • invalidate: field is invalidated and cleared after read.

  • clear: field is cleared after read, valid untouched.

  • increment: register is incremented after read, valid untouched.

  • decrement: register is decremented after read, valid untouched.

This key is optional unless required by context. If not specified, the default value (nothing) is used.

bus-write

Configures what happens when a bus write occurs.

The following values are supported:

  • disabled (default): write access is disabled.

  • error: writes always return a slave error.

  • enabled: normal write access to register. Masked bits are written 0.

  • invalid: as above, but ignores the write when the register is valid.

  • invalid-wait: as above, but blocks until register is invalid.

  • invalid-only: as above, but fails when register is already valid.

  • masked: write access respects strobe bits. Precludes after-bus-write.

  • accumulate: write data is added to the register.

  • subtract: write data is subtracted from the register.

  • bit-set: bits that are written 1 are set in the register.

  • bit-clear: bits that are written 1 are cleared in the register.

  • bit-toggle: bits that are written 1 are toggled in the register.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

after-bus-write

Configures what happens after a bus write.

The following values are supported:

  • nothing (default): no extra operation after write.

  • validate: register is validated after write.

  • invalidate: as above, but invalidated again one cycle later.

This key is optional unless required by context. If not specified, the default value (nothing) is used.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

  • enabled: both a data and a valid output signal are generated.

  • handshake: a stream-to-mmio ready signal is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

hw-write

Configure the existence and behavior of the hardware write port.

The following values are supported:

  • disabled (default): no write port is generated.

  • status: the register is constantly driven by a port and is always valid.

  • enabled: a record consisting of a write enable flag and data is generated.

  • stream: like enabled, but the write only occurs when the register is invalid. Furthermore, the write_data signal is renamed to data, and the write_enable signal is renamed to valid, in order to comply with AXI-stream naming conventions.

  • accumulate: like enabled, but the data is accumulated instead of written.

  • subtract: like enabled, but the data is subtracted instead of written.

  • set: like enabled, but bits that are written 1 are set in the register.

  • reset: like enabled, but bits that are written 1 are cleared in the register.

  • toggle: like enabled, but bits that are written 1 are toggled in the register.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

after-hw-write

Configures what happens after a hardware write.

The following values are supported:

  • nothing (default): no extra operation after write.

  • validate: register is automatically validated after write.

This key is optional unless required by context. If not specified, the default value (nothing) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • null: the internal data register resets to 0, with the valid flag cleared.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-lock

Controls the existence of the ctrl_lock control input signal. When this signal is asserted, writes are ignored.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-validate

Controls the existence of the ctrl_validate control input signal. When this signal is asserted, the internal valid flag is set.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-invalidate

Controls the existence of the ctrl_invalidate control input signal. When this signal is asserted, the internal valid flag is cleared. The data register is also set to 0.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-ready

Controls the existence of the ctrl_ready control input signal. This signal behaves like an AXI stream ready signal for MMIO to stream fields.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-increment

Controls the existence of the ctrl_increment control input signal. When this signal is asserted, the internal data register is incremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-set

Controls the existence of the ctrl_bit_set control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is set.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-clear

Controls the existence of the ctrl_bit_clear control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is cleared.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-toggle

Controls the existence of the ctrl_bit_toggle control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is toggled.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

drive-internal

Configures driving or strobing an internal signal with the internal data register belonging to this field. The signal is strobed when after-bus-write is set to invalidate, otherwise it is driven.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created and driven with the value in the internal data register for this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

full-internal

Configures driving an internal signal high when the internal data register is valid. This essentially serves as a holding register full signal for stream interface fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the internal valid register of this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

empty-internal

Configures driving an internal signal high when the internal data register is invalid. This essentially serves as a holding register empty signal for stream interface fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the one's complement of the internal valid register of this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

overflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from high to low during an increment or accumulate operation. This essentially serves as an overflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when an increment or accumulate operation causes the MSB of the data register to be cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

underflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from low to high during a decrement or subtract operation. This essentially serves as an underflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a decrement or subtract operation causes the MSB of the data register to be set.

This key is optional unless required by context. If not specified, the default value (null) is used.

bit-overflow-internal

Configures strobing an internal signal when a bit-set operation to a bit that was already set occurs. This essentially serves as an overflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-set operation occurs to an already-set bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

bit-underflow-internal

Configures strobing an internal signal when a bit-clear operation to a bit that was already cleared occurs. This essentially serves as an underflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-clear operation occurs to an already-cleared bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

overrun-internal

Configures strobing an internal signal when a bus write occurs while the stored value was already valid. This is equivalent to an overflow condition for MMIO to stream fields. It is intended to be used for overflow interrupts.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bus write occurs while the internal valid signal is set.

This key is optional unless required by context. If not specified, the default value (null) is used.

underrun-internal

Configures strobing an internal signal when a bus read occurs while the stored value is invalid. This is equivalent to an underflow condition for stream to MMIO fields. It is intended to be used for underflow interrupts.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bus read occurs while the internal valid signal is cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

monitor-internal

Configures monitoring an internal signal with this field.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: the field monitors the internal signal with the given name. monitor-mode determines how the signal is used.

This key is optional unless required by context. If not specified, the default value (null) is used.

monitor-mode

Configures how monitor-internal works. If monitor-internal is not specified, this key is no-op.

The following values are supported:

  • status (default): the internal data register is constantly assigned to the vector-sized internal signal named by monitor-internal.

  • bit-set: the internal data register is constantly or'd with the vector-sized internal signal named by monitor-internal.

  • increment: the internal data register is incremented whenever the respective bit in the repeat-sized internal signal named by monitor-internal is asserted.

This key is optional unless required by context. If not specified, the default value (status) is used.

constant behavior

Fields with constant behavior always return the value specified through the value option when read. They cannot be written.

This structure supports the following configuration key.

value

Configures the value using an integer or boolean.

This key is required.

config behavior

Fields with config behavior always return the value specified by a VHDL generic. They cannot be written.

This structure does not support any configuration keys.

status behavior

Fields with status behavior always return the current state of an input port. They cannot be written.

This structure does not support any configuration keys.

internal-status behavior

Fields with internal-status behavior always return the current state if an internal signal.

This structure supports the following configuration key.

internal

Configures the internal signal that is to be monitored. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

latching behavior

The latching behavior is a lot like status, but more advanced. It is used when status information is not always available, but only updated sporadically through a write enable. This means that there is an "invalid" state of some kind, used before the first status value is received. By default fields with this behavior will just read as 0 in this state, but this behavior can be overridden with the options below. For instance, the field can be configured to block the read access until the status is valid. It's also possible to enable a control signal that invalidates the field on demand, or to invalidate on read.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): normal read access to field, ignoring valid bit.

  • valid-wait: as above, but blocks until field is valid.

  • valid-only: as above, but fails when field is not valid.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

after-bus-read

Configures what happens after a bus read.

The following values are supported:

  • nothing (default): no extra operation after read.

  • invalidate: field is invalidated and cleared after read.

  • clear: field is cleared after read, valid untouched.

This key is optional unless required by context. If not specified, the default value (nothing) is used.

after-hw-write

Configures what happens after a hardware write.

The following values are supported:

  • nothing (default): no extra operation after write.

  • validate: register is automatically validated after write.

This key is optional unless required by context. If not specified, the default value (nothing) is used.

reset

Configures the reset value.

The following values are supported:

  • no: the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • null (default): the internal data register resets to 0, with the valid flag cleared.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (null) is used.

ctrl-validate

Controls the existence of the ctrl_validate control input signal. When this signal is asserted, the internal valid flag is set.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-invalidate

Controls the existence of the ctrl_invalidate control input signal. When this signal is asserted, the internal valid flag is cleared. The data register is also set to 0.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-increment

Controls the existence of the ctrl_increment control input signal. When this signal is asserted, the internal data register is incremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-set

Controls the existence of the ctrl_bit_set control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is set.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-clear

Controls the existence of the ctrl_bit_clear control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is cleared.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-toggle

Controls the existence of the ctrl_bit_toggle control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is toggled.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

Control

Fields with control behavior are used to push runtime configuration values from software to hardware. They are normally read-write on the MMIO bus and respect the AXI4L byte strobe bits so they can be easily (though not necessarily atomically) updated partially, but read access can be disabled and write access can be simplified if this is desirable.

The hardware interface by default consists of just an std_logic or std_logic_vector with the current value of the field, but you can also enable a valid bit by setting hw-read to enabled if you so desire. You'll also need to set bus-write to enabled and after-bus-write to validate to make that work as you would expect: the value will be marked invalid from reset to when it's first written. You can also make the field one-time-programmable by selecting invalid or invalid-only for bus-write instead of enabled.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): normal read access to field, ignoring valid bit.

  • error: reads always return a slave error.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

bus-write

Configures what happens when a bus write occurs.

The following values are supported:

  • masked (default): write access respects strobe bits. Precludes after-bus-write.

  • enabled: normal write access to register. Masked bits are written 0.

  • invalid: as above, but ignores the write when the register is valid.

  • invalid-only: as above, but fails when register is already valid.

This key is optional unless required by context. If not specified, the default value (masked) is used.

after-bus-write

Configures what happens after a bus write.

The following values are supported:

  • nothing (default): no extra operation after write.

  • validate: register is validated after write.

This key is optional unless required by context. If not specified, the default value (nothing) is used.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • simple (default): only the data output is generated.

  • enabled: both a data and a valid output signal are generated.

This key is optional unless required by context. If not specified, the default value (simple) is used.

reset

Configures the reset value.

The following values are supported:

  • no: the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • null (default): the internal data register resets to 0, with the valid flag cleared.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (null) is used.

ctrl-lock

Controls the existence of the ctrl_lock control input signal. When this signal is asserted, writes are ignored.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-invalidate

Controls the existence of the ctrl_invalidate control input signal. When this signal is asserted, the internal valid flag is cleared. The data register is also set to 0.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

internal-control behavior

This field behaves like a control register that constrols an internal signal by default. That is, the MMIO bus interface is read/write, and the contents of the internal register drives an internal signal. The name of the internal signal must be set using drive-internal.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): normal read access to field, ignoring valid bit.

  • error: reads always return a slave error.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

bus-write

Configures what happens when a bus write occurs.

The following values are supported:

  • masked (default): write access respects strobe bits. Precludes after-bus-write.

  • enabled: normal write access to register. Masked bits are written 0.

This key is optional unless required by context. If not specified, the default value (masked) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

internal

Configures the internal signal that is to be driven. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

flag behavior

Fields with `flag' behavior behave like most edge/event-sensitive interrupt flags in commercial peripherals work: occurance of the event sets the flag bit, and writing a one to the bit through MMIO clears it again.

Usually many of these flags are combined into a single register. Canonical usage by software is then to read the register to determine which events have occurred, write the read value back to the register, and then handle the events. If a new event occurs between the read and write, its flag will not be cleared, because a zero will be written to it by the write action. This event will then be handled the next time the software reads the flag register.

It normally isn't possible to detect how many events have occurred for a single flag, just that there was at least one occurrance since the last read of the flag. If this information is necessary, the counter behavior can be used instead. If only the knowledge that an overflow occurred is needed, bit-overflow-internal can be used to drive an internal-flag field and/or an internal interrupt.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

bit-overflow-internal

Configures strobing an internal signal when a bit-set operation to a bit that was already set occurs. This essentially serves as an overflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-set operation occurs to an already-set bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

bit-underflow-internal

Configures strobing an internal signal when a bit-clear operation to a bit that was already cleared occurs. This essentially serves as an underflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-clear operation occurs to an already-cleared bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

volatile-flag behavior

This behavior is similar to flag, but the flags are immediately cleared when the field is read. The field is therefore read-only, allowing write-only registers to reside at the same address. The access procedure is also slightly faster, because no write action is required. However, the required read-volatility makes it incompatible with processors/caches that prefetch values; any infrastructure that may perform spurious reads may inadvertantly clear the flags.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

bit-overflow-internal

Configures strobing an internal signal when a bit-set operation to a bit that was already set occurs. This essentially serves as an overflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-set operation occurs to an already-set bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal-flag behavior

internal-flag fields behave like flag fields, but instead of the flags being set by an external signal, it is set by an internal signal. This may for instance be used in conjunction with the overrun output of an MMIO to stream field.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

bit-overflow-internal

Configures strobing an internal signal when a bit-set operation to a bit that was already set occurs. This essentially serves as an overflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-set operation occurs to an already-set bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

bit-underflow-internal

Configures strobing an internal signal when a bit-clear operation to a bit that was already cleared occurs. This essentially serves as an underflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-clear operation occurs to an already-cleared bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal

Configures the internal signal that is to be monitored. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

volatile-internal-flag behavior

volatile-internal-flag fields behave like volatile-flag fields, but instead of the flags being set by an external signal, it is set by an internal signal. This may for instance be used in conjunction with the overrun output of an MMIO to stream field.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

bit-overflow-internal

Configures strobing an internal signal when a bit-set operation to a bit that was already set occurs. This essentially serves as an overflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-set operation occurs to an already-set bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal

Configures the internal signal that is to be monitored. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

strobe behavior

This behavior may be used to signal a request to hardware, for hardware that can always handle the request immediately. When a 1 is written to a bit in this register, the respective output bit is strobed high for one cycle. Zero writes are ignored.

This structure does not support any configuration keys.

internal-strobe behavior

This behavior may be used to signal a request to another vhdmmio entity, such as a counter field. When a 1 is written to a bit in this register, the respective bit in the internal signal is strobed high for one cycle. Zero writes are ignored.

This structure supports the following configuration key.

internal

Configures the internal signal that is to be driven. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

request behavior

This behavior can be seen as both the inverse of a flag and as an extension of strobe: the bits in the field are set by software writing a one to them, and cleared when acknowledged by hardware. They can be used for requests that cannot be handled immediately. By default, software can use an MMIO read to determine whether a command has been acknowledged yet, but this can be disabled to make the field write-only.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): normal read access to field, ignoring valid bit.

  • error: reads always return a slave error.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-bit-clear

Controls the existence of the ctrl_bit_clear control input signal. This signal is as wide as the field is. When a bit in this input is high, the respective data bit is cleared.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

bit-overflow-internal

Configures strobing an internal signal when a bit-set operation to a bit that was already set occurs. This essentially serves as an overflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-set operation occurs to an already-set bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

bit-underflow-internal

Configures strobing an internal signal when a bit-clear operation to a bit that was already cleared occurs. This essentially serves as an underflow signal for flag fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bit-clear operation occurs to an already-cleared bit.

This key is optional unless required by context. If not specified, the default value (null) is used.

multi-request behavior

multi-request fields accumulate anything written to them, and by default allow hardware to decrement them. This may be used to request a certain number of things with a single, atomic MMIO write.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): normal read access to field, ignoring valid bit.

  • error: reads always return a slave error.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

hw-write

Configure the existence and behavior of the hardware write port.

The following values are supported:

  • disabled (default): no write port is generated.

  • subtract: like enabled, but the data is subtracted instead of written.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

overflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from high to low during an increment or accumulate operation. This essentially serves as an overflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when an increment or accumulate operation causes the MSB of the data register to be cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

underflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from low to high during a decrement or subtract operation. This essentially serves as an underflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a decrement or subtract operation causes the MSB of the data register to be set.

This key is optional unless required by context. If not specified, the default value (null) is used.

counter behavior

Similar to flag fields, counters are used to signal events from hardware to software. However, counters allow multiple events occurring between consecutive software read cycles to be registered by counting instead of bit-setting. Like flag, software should use fields of this type by reading the value and then writing the read value to it in order to avoid missing events; the write operation subtracts the written value from the internal register.

When a counter overflows, it simply wraps back to zero. Similarly, if a counter is decremented below zero, it wraps to its maximum value. Optionally, overflow-internal and underflow-internal can be used to detect this condition, in conjuntion with an internal-flag field and/or an internal interrupt.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

hw-write

Configure the existence and behavior of the hardware write port.

The following values are supported:

  • disabled (default): no write port is generated.

  • enabled: a record consisting of a write enable flag and data is generated.

  • accumulate: like enabled, but the data is accumulated instead of written.

  • subtract: like enabled, but the data is subtracted instead of written.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-increment

Controls the existence of the ctrl_increment control input signal. When this signal is asserted, the internal data register is incremented.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

overflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from high to low during an increment or accumulate operation. This essentially serves as an overflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when an increment or accumulate operation causes the MSB of the data register to be cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

underflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from low to high during a decrement or subtract operation. This essentially serves as an underflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a decrement or subtract operation causes the MSB of the data register to be set.

This key is optional unless required by context. If not specified, the default value (null) is used.

volatile-counter behavior

This behavior is similar to counter, but the counter value is immediately cleared when the field is read. The field is therefore read-only, allowing write-only registers to reside at the same address The access procedure is also slightly faster, because no write action is required. However, the required read-volatility makes it incompatible with processors/caches that prefetch values; any infrastructure that may perform spurious reads may inadvertantly clear the counter.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

hw-write

Configure the existence and behavior of the hardware write port.

The following values are supported:

  • disabled (default): no write port is generated.

  • enabled: a record consisting of a write enable flag and data is generated.

  • accumulate: like enabled, but the data is accumulated instead of written.

  • subtract: like enabled, but the data is subtracted instead of written.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-increment

Controls the existence of the ctrl_increment control input signal. When this signal is asserted, the internal data register is incremented.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

overflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from high to low during an increment or accumulate operation. This essentially serves as an overflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when an increment or accumulate operation causes the MSB of the data register to be cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal-counter behavior

This field behaves like counter, but instead of the counter being incremented by an external signal, it is incremented by an internal signal.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

hw-write

Configure the existence and behavior of the hardware write port.

The following values are supported:

  • disabled (default): no write port is generated.

  • enabled: a record consisting of a write enable flag and data is generated.

  • accumulate: like enabled, but the data is accumulated instead of written.

  • subtract: like enabled, but the data is subtracted instead of written.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-increment

Controls the existence of the ctrl_increment control input signal. When this signal is asserted, the internal data register is incremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

overflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from high to low during an increment or accumulate operation. This essentially serves as an overflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when an increment or accumulate operation causes the MSB of the data register to be cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

underflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from low to high during a decrement or subtract operation. This essentially serves as an underflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a decrement or subtract operation causes the MSB of the data register to be set.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal

Configures the internal signal that is to be monitored. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

volatile-internal-counter behavior

This field behaves like volatile-counter, but instead of the counter being incremented by an external signal, it is incremented by an internal signal.

This structure supports the following configuration keys.

hw-read

Configure the existence and behavior of the hardware read port.

The following values are supported:

  • disabled (default): no read port is generated.

  • simple: only the data output is generated.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

hw-write

Configure the existence and behavior of the hardware write port.

The following values are supported:

  • disabled (default): no write port is generated.

  • enabled: a record consisting of a write enable flag and data is generated.

  • accumulate: like enabled, but the data is accumulated instead of written.

  • subtract: like enabled, but the data is subtracted instead of written.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

reset

Configures the reset value.

The following values are supported:

  • no (default): the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-clear

Controls the existence of the ctrl_clear control input signal. When this signal is asserted, the internal data register is cleared. The valid flag is not affected.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-reset

Controls the existence of the ctrl_reset control input signal. When this signal is asserted, the field is reset, as if the register file reset input were asserted.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-increment

Controls the existence of the ctrl_increment control input signal. When this signal is asserted, the internal data register is incremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

ctrl-decrement

Controls the existence of the ctrl_decrement control input signal. When this signal is asserted, the internal data register is decremented.

The value must be a boolean (default no).

This key is optional unless required by context. If not specified, the default value (no) is used.

overflow-internal

Configures strobing an internal signal when the most significant bit of the internal register flips from high to low during an increment or accumulate operation. This essentially serves as an overflow signal for counter fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when an increment or accumulate operation causes the MSB of the data register to be cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal

Configures the internal signal that is to be monitored. The value must be a string matching [a-zA-Z][a-zA-Z0-9_]*.

This key is required.

stream-to-mmio behavior

Fields with stream-to-mmio behavior interface with an incoming AXI4 stream. When the incoming AXI4 stream is valid and the internal register for the field is not, the stream is handshaked and the data is put in the register. The MMIO bus can then read from the field to fetch the data, automatically invalidating the internal register to let the cycle repeat. The field cannot be written by the bus.

By default, the only way for software to know whether data is waiting in the internal holding register is to read and compare with zero, which is always what's returned for an empty holding register. This is of course not ideal at best. vhdmmio provides several options for doing this better, which require a bit more work:

  • Set bus-read to valid-wait. In this case, reads will always return valid data because they are blocked until data is available. This is the simplest method, but reading from a stream that isn't going to send anything will deadlock the whole bus.
  • Set bus-read to valid-only. In this case, a read from an empty holding register yields a slave error. This is very simple from vhdmmio's standpoint, but requires the bus master to actually support AXI4L error conditions in a convenient way.
  • Drive an internal signal with the status of the holding register (full-internal or empty-internal), and monitor it with a status field (internal-status behavior) and/or an internal interrupt.
  • Strobe an internal signal when an invalid bus read occurs using underrun-internal and check whether an underrun occurred after the fact using a status field (internal-flag behavior) and/or an internal interrupt.

Finally, vhdmmio allows you to set the reset value of the internal register to a valid value. This effectively imitates a stream transfer, which may be used to start some loop based on sending stream transfers back and forth between systems.

This structure supports the following configuration keys.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): reads from an empty holding register return 0.

  • valid-only: reads from an empty holding register return a slave error.

  • valid-wait: reads from an empty holding register are blocked until data is received from the stream.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

reset

Configures the reset value.

The following values are supported:

  • null (default): the internal data register resets to 0, with the valid flag cleared.

  • no: the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (null) is used.

full-internal

Configures driving an internal signal high when the internal data register is valid. This essentially serves as a holding register full signal for stream interface fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the internal valid register of this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

empty-internal

Configures driving an internal signal high when the internal data register is invalid. This essentially serves as a holding register empty signal for stream interface fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the one's complement of the internal valid register of this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

underrun-internal

Configures strobing an internal signal when a bus read occurs while the stored value is invalid. This is equivalent to an underflow condition for stream to MMIO fields. It is intended to be used for underflow interrupts.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bus read occurs while the internal valid signal is cleared.

This key is optional unless required by context. If not specified, the default value (null) is used.

mmio-to-stream behavior

Fields with mmio-to-stream behavior interface with an outgoing AXI4 stream. When the field is written, the written data is placed in the field's internal data register and the stream is validated. A completed handshake invalidates the internal data register, allowing the MMIO bus master to write the next value. The field cannot be read by the bus.

By default, there is no way for software to know whether the holding register is ready for the next datum. This is not a problem if flow control is handled by some other means. However, vhdmmio also provides several methods to achieve proper flow control:

  • Set bus-write to invalid-wait. In this case, writes are blocked until the holding register is ready. This is the simplest flow control method, but writing to a stream that isn't going to acknowledge anything will deadlock the whole bus.
  • Set bus-write to invalid-only. In this case, writing to a full holding register yields a slave error. This is very simple from vhdmmio's standpoint, but requires the bus master to actually support AXI4L error conditions in a convenient way.
  • Drive an internal signal with the status of the holding register (full-internal or empty-internal), and monitor it with a status field (internal-status behavior) and/or an internal interrupt.
  • Strobe an internal signal when an invalid bus write occurs using overrun-internal and check whether an overrun occurred after the fact using a status field (internal-flag behavior) and/or an internal interrupt.

Finally, vhdmmio allows you to set the reset value of the internal register to a valid value. This effectively imitates a stream transfer, which may be used to start some loop based on sending stream transfers back and forth between systems.

This structure supports the following configuration keys.

bus-write

Configures what happens when a bus write occurs.

The following values are supported:

  • invalid (default): writes to a full holding register are silently ignored.

  • enabled: writes to a full holding register override the register. NOTE: this is not AXI4-stream compliant behavior, since data must remain stable between validation and the completed handshake.

  • invalid-wait: writes to a full holding register are blocked until the register is popped by the stream.

  • invalid-only: writes to a full holding register return a slave error.

This key is optional unless required by context. If not specified, the default value (invalid) is used.

reset

Configures the reset value.

The following values are supported:

  • null (default): the internal data register resets to 0, with the valid flag cleared.

  • no: the internal data register resets to 0, with the valid flag set.

  • yes: the internal data register resets to 1, with the valid flag set.

  • an integer: the internal data register resets to the given value, with the valid flag set.

  • generic: the reset value is controlled through a VHDL generic.

This key is optional unless required by context. If not specified, the default value (null) is used.

full-internal

Configures driving an internal signal high when the internal data register is valid. This essentially serves as a holding register full signal for stream interface fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the internal valid register of this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

empty-internal

Configures driving an internal signal high when the internal data register is invalid. This essentially serves as a holding register empty signal for stream interface fields.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the one's complement of the internal valid register of this field.

This key is optional unless required by context. If not specified, the default value (null) is used.

overrun-internal

Configures strobing an internal signal when a bus write occurs while the stored value was already valid. This is equivalent to an overflow condition for MMIO to stream fields. It is intended to be used for overflow interrupts.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and strobed when a bus write occurs while the internal valid signal is set.

This key is optional unless required by context. If not specified, the default value (null) is used.

axi behavior

Fields with axi behavior map the bus accesses supported by them to a different AXI4L bus.

The width of the outgoing AXI4L bus is set to the width of the field, which must therefore be 32 or 64 bits. The word address for the outgoing bus is taken from the subaddress; the 2 or 3 LSBs of the address (depending on the bus width) are always zero. For example, a field with address 0x0--- in a 32-bit system has a 10-bit subaddress, therefore allowing access to 4kiB of address space on the child AXI4L port.

Note that going from a 64-bit bus to a 32-bit bus always "stretches" the address space of the 32-bit bus, since only half the bus width can be utilized. While it would technically be possible to avoid this by just doing two transfers on the slave bus for each AXI field access, this adds a bunch of complexity, ambiguity, and may prevent read-volatile fields on the child bus from being accessed without side effects, so this feature was not implemented. Going from a 32-bit bus to a 64-bit bus on the other hand is perfectly fine, since this just makes the logical register for the AXI field wider than the bus, following vhdmmio's normal rules. Just make sure that bit 2 of the field's address is zero.

axi fields support multiple outstanding requests. The amount of outstanding requests supported is controlled centrally in the register file features structure.

This structure supports the following configuration keys.

mode

This key configures the supported bus access modes.

The following values are supported:

  • read-write (default): both read and write accesses are supported.

  • read-only: only read accesses are supported.

  • write-only: only write accesses are supported.

This key is optional unless required by context. If not specified, the default value (read-write) is used.

interrupt-internal

This key configures driving an internal signal high when the vhdmmio-specific interrupt signal associated with the outgoing AXI4L stream is asserted. This internal signal can then be tied to an internal interrupt to propagate the flag.

The following values are supported:

  • null (default): the feature is disabled.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: an internal signal with the given name is created (if necessary) and driven by the incoming interrupt signal.

This key is optional unless required by context. If not specified, the default value (null) is used.

bus-flatten

This key specifies whether records or flattened signals are desired for the bus interface. Note that flatten (defined here) should also be set to yes to make this work.

The following values are supported:

  • no (default): the bus is not flattened; the records from vhdmmio_pkg.vhd are used.

  • yes: the bus is flattened; the standard AXI4-lite signal names are used.

This key is optional unless required by context. If not specified, the default value (no) is used.

interrupt behavior

This is the base class for the behavior of interrupt fields, i.e. fields that operate on vhdmmio's built-in interrupt system. They are associated with an interrupt defined in the interrupts key of the register file description. The arrayness of the interrupt must match the repetition/arrayness of the field descriptor, and the individual fields must be scalar.

This structure supports the following configuration keys.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

mode

The role that this field assumes for the associated interrupt.

The following values are supported:

  • raw (default): this field monitors the raw incoming interrupt request.

  • enable: this field monitors and/or controls the interrupt enable flag.

  • flag: this field monitors and/or controls the interrupt status flag.

  • unmask: this field monitors and/or controls the interrupt unmask flag.

  • masked: this field monitors the masked interrupt status flag.

This key is optional unless required by context. If not specified, the default value (raw) is used.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • disabled (default): read access is disabled.

  • enabled: read access is enabled.

  • clear: read access is enabled, and reading clears the associated flag.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

bus-write

Configures what happens when a bus read occurs.

The following values are supported:

  • disabled (default): write access is disabled.

  • enabled: write access is enabled.

  • clear: write access is enabled, and writing a one clears the associated flag.

  • set: write access is enabled, and writing a one sets the associated flag.

This key is optional unless required by context. If not specified, the default value (disabled) is used.

interrupt-flag behavior

This field behavior works much like a regular flag field, but operates on the interrupt pending flag of the associated interrupt instead of a field-specific register. The read value of the field is one if and only if the interrupt is pending, regardless of mask. Writing a one to the field clears the flag. If only one of these operations is needed, the other can be disabled.

If the write mode of this field is enabled, the associated interrupt implicitly becomes strobe-sensitive.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration keys.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): read access is enabled.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

bus-write

Configures what happens when a bus read occurs.

The following values are supported:

  • clear (default): write access is enabled, and writing a one clears the associated flag.

  • disabled: write access is disabled.

This key is optional unless required by context. If not specified, the default value (clear) is used.

volatile-interrupt-flag behavior

This field behavior works much like a regular volatile-flag field, but operates on the interrupt pending flag of the associated interrupt instead of a field-specific register. The read value of the field is one if and only if the interrupt is pending, and the act of reading the field clears the interrupt pending status. Since the interrupt flag can be cleared, the associated interrupt implicitly becomes strobe-sensitive.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration key.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

interrupt-pend behavior

This field behavior allows software to set pend interrupts manually by writing a one, regardless of the enable flag or the incoming interrupt request. Since the interrupt flag can be set, the associated interrupt implicitly becomes strobe-sensitive, and needs a way to clear the flag as well. This can be done by reading this field when bus-read is set to clear, or through a (volatile-)interrupt-flag field.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration keys.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • disabled: read access is disabled.

  • enabled (default): read access is enabled.

  • clear: read access is enabled, and reading clears the associated flag.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

interrupt-enable behavior

This field behavior allows software to access the enable register for the associated interrupt. Incoming interrupt requests only affect the interrupt flag register when the enable register is set. If there is no way to enable an interrupt, it resets to the enabled state; otherwise it resets to disabled.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration keys.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): read access is enabled.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

bus-write

Configures what happens when a bus read occurs.

The following values are supported:

  • disabled: write access is disabled.

  • enabled (default): write access is enabled.

  • clear: write access is enabled, and writing a one clears the associated flag.

  • set: write access is enabled, and writing a one sets the associated flag.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

interrupt-unmask behavior

This field behavior allows software to access the unmask register for the associated interrupt. A pending interrupt only asserts the outgoing interrupt flag signal when it is unmasked. If there is no way to unmask an interrupt, it resets to the unmasked state; otherwise it resets to masked.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration keys.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

bus-read

Configures what happens when a bus read occurs.

The following values are supported:

  • enabled (default): read access is enabled.

  • disabled: read access is disabled.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

bus-write

Configures what happens when a bus read occurs.

The following values are supported:

  • disabled: write access is disabled.

  • enabled (default): write access is enabled.

  • clear: write access is enabled, and writing a one clears the associated flag.

  • set: write access is enabled, and writing a one sets the associated flag.

This key is optional unless required by context. If not specified, the default value (enabled) is used.

interrupt-status behavior

This read-only field behavior reflects the state of the interrupt flag register masked by the interrupt mask register. It is one if and only if the interrupt is pending and unmasked.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration key.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

interrupt-raw behavior

This read-only field behavior reflects the state of the raw incoming interrupt signal, regardless of whether the interrupt is enabled or whether the flag is set.

The arrayness of the interrupt must match the repetition/arrayness of the field descriptor. The individual fields must be scalar.

This structure supports the following configuration key.

interrupt

The name of the interrupt or interrupt array that this field is associated with.

This key is required.

custom behavior

Custom fields allow you to describe the behavior of the field using VHDL snippits. This is very powerful, but not for the faint-hearted. Also, with great power comes great responsibility: you can easily break vhdmmio's generated entities by writing incorrect code. Furthermore, vhdmmio's internal template engine can execute arbitrary Python code, so building a register file from an untrusted source that contains custom fields is a big security risk. Therefore, vhdmmio requires you to specify --trusted on the command line to be able to use these fields.

vhdmmio implements custom fields in a tightly integrated way; it doesn't just copypaste your code directly into the generated output file. Instead, it lets you write code snippits for various actions, that get executed within the generated VHDL process at the appropriate times. This is exactly how the predefined field behaviors are programmed within vhdmmio - custom fields basically just allow direct access to this API. The big advantage of this is that you still don't need to worry about things like the AXI4L interface or interoperability with any other fields in the logical register or register file, but it does mean that you need to specify quite some metadata to vhdmmio to make things work, and that you need a good understanding of how vhdmmio's generated VHDL code works.

Specifying field behavior

The behavior of a field needs to be specified in two different ways. The first is obvious: (templates for) the VHDL code that gets inserted into the generated entity. The second consists of a more abstract description of the field's capabilities and characteristics, which vhdmmio uses to generate the glue logic between the fields and the AXI4L bus, the header files for accessing the registers, and in some cases the documentation.

vhdmmio allows you to specify the following VHDL code blocks. Note that vhdmmio's generated entity is entirely synchronous and uses variables to maintain state, so the order of the blocks is important; the blocks are listed in the order in which they are executed.

  • pre-access: this code block is executed every clock cycle before the AXI4L bus access is handled.
  • read: this code block is executed when the bus is trying to read the field, and the bus interface logic is ready for the field's response.
  • read-lookahead: like read, but the bus interface logic is not yet ready for the response.
  • read-request: this code block is executed when a read request for the field is available, regardless of whether the bus interface logic is ready for the response.
  • read-response: this code block is executed when one of the above blocks deferred a read, and the bus interface logic is ready for the response.
  • write, write-lookahead, write-request, and write-response: the write analogues for the above.
  • post-access: this code block is executed every clock cycle after the AXI4L bus access is handled.

For more information about each block, refer to the documentation below.

vhdmmio needs the following metadata in addition to the code blocks:

  • whether the read/read-request/write/write-request code blocks can block a bus access (that is, delay the bus response);
  • whether reads/writes are volatile (that is, the result of accessing the field once differs from accessing it twice);
  • how the field can be accessed without affecting its state, if this is possible at all (used when a different field within a single logical register is to be accessed).

This metadata is also used to determine whether two fields can coexist within the same register. The rules are:

  • blocking fields cannot be combined with other blocking fields;
  • blocking fields cannot be combined with volatile fields;
  • fields that support multiple outstanding requests cannot be combined with any other field.

Template syntax

vhdmmio uses a custom template engine to preprocess VHDL code. The code blocks specified in for custom fields pass through this template engine as well.

The template engine is controlled using three characters that are normally not used in VHDL: |, $, and @. Each corresponds to a different phase of the template logic.

Indentation stripping phase (|)

In this phase, all whitespace at the start of a line followed by a | is stripped. This allows you to indent your template however you want, without this indentation appearing in the generated code block. If you need to start a line with an | for some reason, simply prefix a second |; the substitution is only done once per line.

Substitution phase ($)

This is the most important phase, dealing with substitutions and conditionals, similar to the functionality of the C preprocessor.

The template engine supports both inline and single-line directives. Single-line directives start with a $, followed by any amount of whitespace, followed by a command, followed by some arguments depending on the command. There should not be any whitespace before the $ sign; to indent such commands you need to use the | syntax described above. Conversely, inline directives both start and end with a $ and can be anywhere on a line. To insert a $ in the output, use $$.

The following single-line directives are available:

  • $if <python-expression>: opens a conditional block based on an expression evaluated by Python.
  • $else: opens the else block for a previous $if.
  • $endif: terminates an $if or $else block.
  • $block <name>: defines/adds code to a named block. This is like #define in the C preprocessor, but multiline.
  • $end_block: terminates a block definition.
  • $<name>: inserts a previously defined block. If there are no spaces between the $ and the name, no indentation is added; otherwise one space plus the spacing between the $ and the name is added for each line.

Inline directives are always evaluated directly by Python. The result of the Python expression is cast to a string and inserted in place of the directive.

The custom field logic makes some variables available within these Python expressions. These are:

  • i: the field index within the field descriptor, or None if the field descriptor describes only one field (that is, repeat is not specified).
  • s: structure containing the VHDL identifiers for each signal/variable specified through the interfaces configuration key.

Additional variables may be available depending on the block.

Comment and wrapping phase (@)

This phase deals with generating aestetically pleasing, properly line-wrapped code regardless of the current indentation depth, which is impossible (or at least hard) to know when the template is written. The following constructs are available:

  • Lines that start with @ are treated as comments. Subsequent comment lines are treated as markdown, and are rewrapped as such to get to column 80.
  • Lines that start with @@ are also treated as comments, but are not rewrapped.
  • @@@ at the start of a line maps to a single @ in the output.
  • Inline @ are replaced with either a space or a newline followed by appropriate indentation, depending on line wrapping.
  • Inline @@ maps to a single @ in the output.

Configuration keys

This structure supports the following configuration keys.

interfaces

This key specifies the interfaces and state variables that this field uses.

This key must be set to a list of dictionaries, of which the structure is defined here.

This key is optional. Not specifying it is equivalent to specifying an empty list.

pre-access

This key specifies the VHDL template for the code block that is executed each cycle before the bus is accessed. This is usually used for initializing non-state variables and for connecting input signals to the internal state.

The following values are supported:

  • null (default): no pre-access code block is needed.

  • a string: insert the given pre-access code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

read

This key specifies the VHDL template for the code block that is executed when the bus is attempting to read the field while also ready for the response.

The template must perform one of the following actions to respond to the bus.

  • Set the $ack$ boolean variable to true, and the $data$ variable to the read result. $data$ is appropriately sliced to represent the shape of the field; that is, it is sliced to an std_logic for scalar fields and to an appropriately sized std_logic_vector for vector fields.
  • Set the $nack$ boolean variable to true to respond with a slave error.
  • Set the $block$ boolean variable to true to stall. In this case, the block will be executed again the next cycle. The read-can-block key must be set in order to use this variable.
  • Set the $defer$ boolean variable to true to defer. In this case, the request logic will accept the bus request and send subsequent requests to read-lookahead blocks, while the response logic will start calling the read-response block to get the response. Such a read-response block must be specified in order to use this variable.
  • Nothing: the bus behaves as if the field does not exist. If there are no other fields in the addressed register, a decode error is returned.

In addition to the field's interfaces, the template can use the following variables:

  • $prot$: the prot field associated with the request as a 3-bit std_logic_vector.
  • $addr$: the incoming bus address for the request as a 32-bit std_logic_vector.
  • $sub$: the subaddress for the for the request as an std_logic_vector slice, of which the width depends on the field's subaddress configuration.

The following values are supported:

  • null (default): no read code block is needed.

  • a string: insert the given read code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

read-lookahead

This key specifies the VHDL template for the code block that is executed when the bus is attempting to read the field, but the response logic is not yet ready for the response. This can be used to initiate long transactions a few cycles earlier, or can be used in conjunction with multiple outstanding request support.

The template must perform one of the following actions to respond to the bus.

  • Set the $defer$ boolean variable to true to defer. In this case, the request logic will accept the bus request and send subsequent requests to read-lookahead blocks, while the response logic will start calling the read-response block to get the response. Such a read-response block must be specified in order to use this variable.
  • Nothing: the bus interface logic will continue to call this block in subsequent cycles until the response logic is ready, at which point the regular read block is executed instead.

In addition to the field's interfaces, the template can use the following variables:

  • $prot$: the prot field associated with the request as a 3-bit std_logic_vector.
  • $addr$: the incoming bus address for the request as a 32-bit std_logic_vector.
  • $sub$: the subaddress for the for the request as an std_logic_vector slice, of which the width depends on the field's subaddress configuration.

The following values are supported:

  • null (default): no read lookahead code block is needed.

  • a string: insert the given read lookahead code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

read-request

This key specifies the VHDL template for the code block that is executed when the bus is attempting to read the field, regardless of whether the bus is ready for the response. It is up to the code block itself to check this where needed, using the $resp_ready$ boolean variable. Depending on this boolean, the block must respond to the access as described in the documentation for the read and read-lookahead blocks.

While uncommon, both read/read-lookahead and read-request may be specified at the same time. In this case, read/read-lookahead is executed before read-request.

The following values are supported:

  • null (default): no read request code block is needed.

  • a string: insert the given read request code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

read-response

This key specifies the VHDL template for the code block that is executed when the bus is ready for the response of a previously deferred read.

The template must perform one of the following actions to respond to the bus.

  • Set the $ack$ boolean variable to true, and the $data$ variable to the read result. $data$ is appropriately sliced to represent the shape of the field; that is, it is sliced to an std_logic for scalar fields and to an appropriately sized std_logic_vector for vector fields.
  • Set the $nack$ boolean variable to true to respond with a slave error.
  • Set the $block$ boolean variable to true to stall. In this case, the block will be executed again the next cycle. The read-can-block key must be set in order to use this variable.
  • Nothing: the bus behaves as if the field does not exist. If there are no other fields in the addressed register, a decode error is returned.

The following values are supported:

  • null (default): no read response code block is needed; multiple outstandingread requests are not supported for this field.

  • a string: insert the given read response code block; this field supports multiple outstanding requests in read mode.

This key is optional unless required by context. If not specified, the default value (null) is used.

write

This key specifies the VHDL template for the code block that is executed when the bus is attempting to write to the field while also ready for the response.

The template must perform one of the following actions to respond to the bus.

  • Set the $ack$ boolean variable to true to respond with an acknowledgement.
  • Set the $nack$ boolean variable to true to respond with a slave error.
  • Set the $block$ boolean variable to true to stall. In this case, the block will be executed again the next cycle. The write-can-block key must be set in order to use this variable.
  • Set the $defer$ boolean variable to true to defer. In this case, the request logic will accept the bus request and send subsequent requests to write-lookahead blocks, while the response logic will start calling the write-response block to get the response. Such a write-response block must be specified in order to use this variable.
  • Nothing: the bus behaves as if the field does not exist. If there are no other fields in the addressed register, a decode error is returned.

In addition to the field's interfaces, the template can use the following variables:

  • $data$: the write data for the request, appropriately sliced for the shape of the field. That is, $data$ behaves like an std_logic for scalar fields, and like an appropriately sized std_logic_vector for vector fields.
  • $strb$: the write strobe for the request. The variable has the same shape as $data$ and thus behaves as a bit strobe, even though AXI4L's strobe signal is byte-oriented. If a bit in $strb$ is zero, the respective $data$ bit is guaranteed to also be zero, and should not be written.
  • $prot$: the prot field associated with the request as a 3-bit std_logic_vector.
  • $addr$: the incoming bus address for the request as a 32-bit std_logic_vector.
  • $sub$: the subaddress for the for the request as an std_logic_vector slice, of which the width depends on the field's subaddress configuration.

The following values are supported:

  • null (default): no write code block is needed.

  • a string: insert the given write code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

write-lookahead

This key specifies the VHDL template for the code block that is executed when the bus is attempting to write to the field, but the response logic is not yet ready for the response. This can be used to initiate long transactions a few cycles earlier, or can be used in conjunction with multiple outstanding request support.

The template must perform one of the following actions to respond to the bus.

  • Set the $defer$ boolean variable to true to defer. In this case, the request logic will accept the bus request and send subsequent requests to write-lookahead blocks, while the response logic will start calling the write-response block to get the response. Such a write-response block must be specified in order to use this variable.
  • Nothing: the bus interface logic will continue to call this block in subsequent cycles until the response logic is ready, at which point the regular write block is executed instead.

In addition to the field's interfaces, the template can use the following variables:

  • $data$: the write data for the request, appropriately sliced for the shape of the field. That is, $data$ behaves like an std_logic for scalar fields, and like an appropriately sized std_logic_vector for vector fields.
  • $strb$: the write strobe for the request. The variable has the same shape as $data$ and thus behaves as a bit strobe, even though AXI4L's strobe signal is byte-oriented. If a bit in $strb$ is zero, the respective $data$ bit is guaranteed to also be zero, and should not be written.
  • $prot$: the prot field associated with the request as a 3-bit std_logic_vector.
  • $addr$: the incoming bus address for the request as a 32-bit std_logic_vector.
  • $sub$: the subaddress for the for the request as an std_logic_vector slice, of which the width depends on the field's subaddress configuration.

The following values are supported:

  • null (default): no write lookahead code block is needed.

  • a string: insert the given write lookahead code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

write-request

This key specifies the VHDL template for the code block that is executed when the bus is attempting to write to the field, regardless of whether the bus is ready for the response. It is up to the code block itself to check this where needed, using the $resp_ready$ boolean variable. Depending on this boolean, the block must respond to the access as described in the documentation for the write and write-lookahead blocks.

While uncommon, both write/write-lookahead and write-request may be specified at the same time. In this case, write/write-lookahead is executed before write-request.

The following values are supported:

  • null (default): no write request code block is needed.

  • a string: insert the given write request code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

write-response

This key specifies the VHDL template for the code block that is executed when the bus is ready for the response of a previously deferred write.

The template must perform one of the following actions to respond to the bus.

  • Set the $ack$ boolean variable to true to respond with an acknowledgement.
  • Set the $nack$ boolean variable to true to respond with a slave error.
  • Set the $block$ boolean variable to true to stall. In this case, the block will be executed again the next cycle. The write-can-block key must be set in order to use this variable.
  • Nothing: the bus behaves as if the field does not exist. If there are no other fields in the addressed register, a decode error is returned.

The following values are supported:

  • null (default): no write response code block is needed; multiple outstandingwrite requests are not supported for this field.

  • a string: insert the given write response code block; this field supports multiple outstanding requests in write mode.

This key is optional unless required by context. If not specified, the default value (null) is used.

post-access

This key specifies the VHDL template for the code block that is executed each cycle after the bus is accessed. This is usually used for connecting the internal state to output signals.

The following values are supported:

  • null (default): no pre-access code block is needed.

  • a string: insert the given pre-access code block.

This key is optional unless required by context. If not specified, the default value (null) is used.

read-can-block

This key specifies whether the field can block read accesses.

The following values are supported:

  • no (default): this field cannot block reads.

  • yes: this field can block reads.

This key is optional unless required by context. If not specified, the default value (no) is used.

read-volatile

This key specifies whether the field is volatile in read mode. vhdmmio defines volatility as the read result or side effects being different when the field is accessed once versus when it is accessed more than once.

The following values are supported:

  • no (default): this field is not read-volatile.

  • yes: this field is read-volatile.

This key is optional unless required by context. If not specified, the default value (no) is used.

read-has-side-effects

This key specifies whether reads have side effects.

The following values are supported:

  • no (default): reading this field does not have side effects.

  • yes: reading this field may have side effects.

This key is optional unless required by context. If not specified, the default value (no) is used.

read-write-related

This key specifies whether the read data carries the same significance as the write data. If this is not set, vhdmmio will never attempt to read-modify-write this field.

The following values are supported:

  • no (default): the read and write data of this field are not related.

  • yes: the read and write data of this field are related.

This key is optional unless required by context. If not specified, the default value (no) is used.

write-can-block

This key specifies whether the field can block write accesses.

The following values are supported:

  • no (default): this field cannot block writes.

  • yes: this field can block writes.

This key is optional unless required by context. If not specified, the default value (no) is used.

write-volatile

This key specifies whether the field is volatile in write mode. vhdmmio defines volatility as the write result or side effects being different when the field is accessed once versus when it is accessed more than once.

The following values are supported:

  • no (default): this field is not write-volatile.

  • yes: this field is write-volatile.

This key is optional unless required by context. If not specified, the default value (no) is used.

write-no-op

This key specifies what strategies vhdmmio can use to write the logical register that this field resides in without affecting this field, if this is possible at all.

The following values are supported:

  • never (default): it is impossible to write to this field without side effects.

  • zero: writing zero to this field never has any side effects (flags).

  • current: writing the current value never has any side effects. The current value must either be known from context, or, if read-write-related is set, can be read from the field first (read-modify-write).

  • mask: this field can only be masked out using the AXI4L byte strobe signal.

  • current-or-mask: this field can be masked out by writing the current value, or through the AXI4L byte strobe signal.

  • always: anything goes: writing to this field never has any side effects that vhdmmio has to concern itself with.

This key is optional unless required by context. If not specified, the default value (never) is used.

Interfaces for custom field behavior

Custom fields can specify any interfaces and state variables they want to use through this configuration structure. The interface type is determined based on which of the input, output, generic, drive, strobe, monitor, and state keys is present to reduce verbosity in the configuration files; exactly one of these must therefore be specified.

This structure supports the following configuration keys.

input

Use this key to request an input signal to be generated.

The following values are supported:

  • null (default): this interface does not specify an input port.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a scalar input port with the specified name is generated. The VHDL identifier for it is made available to the templates through $s.<name>$.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the port is a vector of the specified width.

This key is optional unless required by context. If not specified, the default value (null) is used.

output

Use this key to request an output signal to be generated.

The following values are supported:

  • null (default): this interface does not specify an output port.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a scalar output port with the specified name is generated. The VHDL identifier for it is made available to the templates through $s.<name>$.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the port is a vector of the specified width.

This key is optional unless required by context. If not specified, the default value (null) is used.

generic

Use this key to request a generic to be generated.

The following values are supported:

  • null (default): this interface does not specify a generic.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a scalar generic with the specified name is generated. The VHDL identifier for it is made available to the templates through $s.<name>$.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the generic is a vector of the specified width.

This key is optional unless required by context. If not specified, the default value (null) is used.

drive

Use this key to request an internal signal driven by this field to be generated.

The following values are supported:

  • null (default): this interface does not specify a driven internal.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: an internal with the specified name is generated and expected to be driven by this field. If the field is not repeated, the signal is scalar, otherwise its width equals the field repetition. The VHDL identifier for it is made available to the templates through $s.<name>$; it always behaves like an std_logic.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the internal signal is a vector of the specified width. This prevents field repetition from being used.

This key is optional unless required by context. If not specified, the default value (null) is used.

strobe

Use this key to request an internal signal strobed by this field to be generated. A strobed internal should only ever be or'd or written high!

The following values are supported:

  • null (default): this interface does not specify a strobed internal.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: an internal with the specified name is generated and expected to be strobed by this field. If the field is not repeated, the signal is scalar, otherwise its width equals the field repetition. The VHDL identifier for it is made available to the templates through $s.<name>$; it always behaves like an std_logic.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the internal signal is a vector of the specified width. This prevents field repetition from being used.

This key is optional unless required by context. If not specified, the default value (null) is used.

monitor

Use this key to request an internal signal monitored by this field to be generated.

The following values are supported:

  • null (default): this interface does not specify a monitored internal.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: an internal with the specified name is generated and expected to only be read by this field. If the field is not repeated, the signal is scalar, otherwise its width equals the field repetition. The VHDL identifier for it is made available to the templates through $s.<name>$; it always behaves like an std_logic.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the internal signal is a vector of the specified width. This prevents field repetition from being used.

This key is optional unless required by context. If not specified, the default value (null) is used.

state

Use this key to request a state variable to be generated.

The following values are supported:

  • null (default): this interface does not specify a state variable.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a scalar state variable with the specified name is generated. The VHDL identifier for it is made available to the templates through $s.<name>$.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: as above, but the state variable is a vector of the specified width.

This key is optional unless required by context. If not specified, the default value (null) is used.

type

This key specifies the type of the signal. Note that only generics support natural and boolean types, and only input and output ports support the axi4l-*-* types.

The following values are supported:

  • std_logic (default): this interface is an std_logic or std_logic_vector.

  • natural: this interface is a VHDL natural.

  • boolean: this interface is a VHDL boolean.

  • axi4l-req-32: this interface is a 32-bit AXI4-lite request structure.

  • axi4l-req-64: this interface is a 64-bit AXI4-lite request structure.

  • axi4l-resp-32: this interface is a 32-bit AXI4-lite response structure.

  • axi4l-resp-64: this interface is a 64-bit AXI4-lite response structure.

This key is optional unless required by context. If not specified, the default value (std_logic) is used.

Additional address match conditions

To support disabling registers at runtime and paged/indirect register files, vhdmmio allows you to specify additional conditions for the address matching logic of each register. This may be useful when not enough address space is allocated to the register file to fit all the registers, or when you want to emulate legacy register files such as a 16550 UART.

This structure supports the following configuration keys.

internal

This key specifies the internal signal to use for the match condition.

The following values are supported:

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a scalar internal with the given name is used for the match condition.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: a vector internal with the given name and width is used for the match condition.

This key is required.

value

This key specifies the value that the signal must have for the logical register to be addressed.

The following values are supported:

  • no (default): the signal value needs to be 0.

  • yes: the signal value needs to be 1.

  • an integer above or equal to 0: the signal needs to have the specified value.

  • a hex/bin integer with don't cares: the signal value is matched against the given number, specified as a string representation of a hexadecimal or binary integer which may contain don't cares (-). In hexadecimal integers, bit-granular don't-cares can be specified by inserting four-bit binary blocks enclosed in square braces in place of a hex digit.

  • <address>/<size>: as before, but the given number of LSBs are ignored in addition.

  • <address>|<ignore>: specifies the required signal value and ignored bits using two integers. Both integers can be specified in hexadecimal, binary, or decimal. A bit which is set in the <ignore> value is ignored in the matching process.

  • <address>&<mask>: specifies the required signal value and bitmask using two integers. Both integers can be specified in hexadecimal, binary, or decimal. A bit which is not set in the <ignore> value is ignored in the matching process.

This key is optional unless required by context. If not specified, the default value (no) is used.

Subaddress components

vhdmmio fields can encompass more than one address. This allows fields such as memories and AXI passthrough to exist. Accessing such a field involves an address in addition to the read and write data. This address is called a subaddress. This configuration structure specifies part of a custom subaddress format.

Note that exactly one of the address, internal, and blank keys must be specified.

This structure supports the following configuration keys.

address

This key specifies that this component of the subaddress is based on bits taken from the incoming address. Normally these bits would be masked out, but this is not required.

The following values are supported:

  • null (default): this subaddress component is not based on the incoming address.

  • an integer between 0 and 31: the specified bit of the incoming address is used.

  • <high>..<low>: the specified bitrange of the incoming address is used. The range is inclusive, so the number of bits in the subaddress component is <high> - <low> + 1.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal

This key specifies that this component of the subaddress is based on the value of an internal signal.

The following values are supported:

  • null (default): this subaddress component is not based on an internal signal.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a scalar internal with the given name is inserted into the subaddress at the current position.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: a vector internal with the given name and width is inserted into the subaddress at the current position.

This key is optional unless required by context. If not specified, the default value (null) is used.

internal-bitrange

For component based on vector internal signals, this key allows you to use only a subset of the signal for this component. In conjunction with other subaddress components based on the same signal, this allows bits to be reordered.

The following values are supported:

  • null (default): the entire vector is used.

  • an integer above or equal to 0: only the specified bit within the vector is used.

  • <high>..<low>: the specified subset of the vector is used. The range is inclusive, so the number of bits in the subaddress component is <high> - <low> + 1.

This key is optional unless required by context. If not specified, the default value (null) is used.

blank

This key specifies that a number of blank bits should be inserted as the next component. The bits are always zero; use the subaddress-offset key in the field descriptor to set a different value.

The following values are supported:

  • null (default): this subaddress component is not a blank.

  • an integer above or equal to 1: the specified number of blank (zero) bits are inserted.

This key is optional unless required by context. If not specified, the default value (null) is used.

Permissions

This configuration structure defines the privilege levels that are allowed to access a field based on the aw_prot and ar_prot AXI4L signals. This is primarily intended to help you identify problems during development (such as a softcore deciding to jump to a register file).

If you're using vhdmmio in an environment where security is in any way meaningful, restrict yourself to using single-word, non-blocking registers. Even then, vhdmmio has not undergone any kind of auditing or certification process and therefore does not make ANY guarantees that your system will be secure.

The following best-effort logic is included based on access privileges:

  • Accessing a field for which the master has insufficient privileges makes the field behave like it does not exist. Depending on whether there are other fields in the surrounding register that can be accessed, a decode error may or may not be generated. Read data is always blanked out, and there will not be any side effects.

  • When a higher-privileged master is in the process of accessing a multi-word register, lower-privileged accesses are rejected. An access is considered less privileged when the ongoing access is privileged (--1) while the interrupting access is unprivileged (--0), OR when the ongoing access is secure (-0-) while the interrupting access is nonsecure (-1-). Such accesses are rejected by means of a slave error. Even though it would normally be ignored, the read data is forced to all zeros during this error to prevent leaks.

  • When a multi-word read completes, the holding register is cleared.

The latter two features may be disabled within the register file features structure to save a small amount of logic.

vhdmmio certainly will NOT protect against:

  • Timing attacks on blocking fields. This is impossible to avoid by vhdmmio, since AXI4L does not support reordering.

  • Denial-of-service and man-in-the-middle style attacks for multi-word accesses on the same privilege level. This is impossible to avoid by vhdmmio, since AXI4L does not support locking.

  • Powerline side-channel attacks, as well as undervolting, overclocking, radiation, etc.. Basically, anything that can be used to circumvent the semantics of VHDL. This is impossible to avoid in a vendor-agnostic way, and would be extremely difficult even for a specific FPGA/ASIC.

To the best of my knowledge, barring the above, a register file with only single-word, non-blocking, non-deferring registers should be fairly secure. But please take this statement with a big grain of salt, as I am not a security expert.

This structure supports the following configuration keys.

user

Whether unprivileged masters (--0) can access the field.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

privileged

Whether privileged masters (--1) can access the field.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

secure

Whether secure transactions (-0-) can be used to can access the field.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

nonsecure

Whether nonsecure transactions (-1-) can be used to can access the field.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

data

Whether data transactions (0--) can access the field.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

instruction

Whether instruction transactions (1--) can access the field.

The value must be a boolean (default yes).

This key is optional unless required by context. If not specified, the default value (yes) is used.

Interrupt descriptors

In addition to MMIO, vhdmmio can handle interrupt routing for you. Each AXI4-lite bus is equiped with an additional signal in the slave-to-master direction that serves as an interrupt request flag. This flag is connected to a (masked) wired-or network of any incoming interrupts you define.

Behavior

The interrupts can be monitored and controlled through fields with the (interrupt)[interrupt.md] behavior.

There are up to three internal registers for each interrupt, named enab (short for enable), flag, and umsk (short for unmask). enab controls whether incoming interrupts are passed on to the flag register. The flag register stores whether the interrupt is pending regardless of whether it is enabled; if an interrupt comes in while the interrupt is enabled, and the interrupt is then disabled, the flag remains asserted until it is explicitly cleared (usually by an interrupt handler). umsk (unmask) has a similar function, but is placed after the flag register. Thus, masking an interrupt immediately stops it from being requested, but once the interrupt is unmasked again, it will be requested again. This logic is shown schematically below.

            .--[raw>
            |         ____                 flag
IRQ --------o--------|    \     _____     .----.   .-[flag>
                     |     )----\    \    |>   |   |         ____
                  .--|____/      )    )---|S  Q|---o--------|    \     to
           enab   |      [pend>-/____/  .-|R   |  umsk      |     )--> wired
          .----.  |      [clear>--------' '----' .----.  .--|____/     OR
          |>   |  |                              |>   |  |
[enable>--|S  Q|--o--[enabled>          [unmask>-|S  Q|--o--[unmasked>
[disable>-|R   |                        [mask>---|R   |
          '----'                                 '----'

Each of the three registers are accessible in read, write, set, and clear modes through fields with (interrupt)[interrupt.md] behavior. The raw incoming interrupt signal and the masked output signal of an interrupt can also be monitored directly.

Interrupts can be made level-sensitive by not specifying a way to clear the interrupt. In this case, the logic is automatically simplified to the following.

            .--[raw>
            |         ____                 .-[flag>
IRQ --------o--------|    \                |         ____
                     |     )---------------o--------|    \     to
                  .--|____/                         |     )--> wired
           enab   |                       umsk   .--|____/     OR
          .----.  |                      .----.  |
          |>   |  |                      |>   |  |
[enable>--|S  Q|--o--[enabled>  [unmask>-|S  Q|--o--[unmasked>
[disable>-|R   |                [mask>---|R   |
          '----'                         '----'

Furthermore, if there is no way to enable/unmask an interrupt, the respective AND gate and the register is effectively optimized away. If there is a way, the reset state is disabled/masked.

Interrupt sources

A vhdmmio interrupt can currently be requested through an internal or synchronous external signal, or by software using the interrupt-pend field behavior. An external synchronizer is needed to accept asynchronous interrupts. These are often vendor-specific, therefore they are not included in vhdmmio.

Configuration keys

This structure supports the following configuration keys.

repeat

This value specifies whether this interrupt descriptor describes a single interrupt or an array of interrupts.

The following values are supported:

  • null (default): the descriptor describes a single interrupt.

  • an integer above or equal to 1: the descriptor describes an array of interrupts of the given size.

This key is optional unless required by context. If not specified, the default value (null) is used.

Metadata keys

This configuration structure is used to name and document the interrupt.

More information about this structure may be found here.

The following configuration keys are used to configure this structure.

mnemonic

This key is documented here.

name

This key is documented here.

brief

This key is documented here.

doc

This key is documented here.

internal

This key specifies whether the interrupt is requested by an internal or external signal.

The following values are supported:

  • null (default): the interrupt request source is an input port.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: the interrupt request source is the internal signal with the given name. The arrayness of the signal must match this interrupt's repetition. Level-sensitive interrupts cannot be associated with strobe signals.

This key is optional unless required by context. If not specified, the default value (null) is used.

active

This key specifies the event that the interrupt is sensitive to.

The following values are supported:

  • high (default): the interrupt is level/strobe-sensitive, active-high.

  • low: the interrupt is level/strobe-sensitive, active-low.

  • rising: the interrupt is rising-edge sensitive.

  • falling: the interrupt is falling-edge sensitive.

  • edge: the interrupt is sensitive to any edge.

This key is optional unless required by context. If not specified, the default value (high) is used.

group

The interrupt request port for the internal signal can optionally be grouped along with other ports in a record. This key specifies the name of the group record.

The following values are supported:

  • null (default): port grouping is determined by the global default.

  • no: the port is not grouped in a record.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: the port is grouped in a record with the specified name.

This key is optional unless required by context. If not specified, the default value (null) is used.

Internal signal I/O

While vhdMMIO's field types and interrupts are already quite powerful on their own, their full power is only truly unlocked when they are used together. For instance, you may want to trigger an interrupt when a bus write occurs to an MMIO-to-stream field while the stream is blocked, to notify the software that it did something wrong. To support this and more without needing some external boilerplate logic (after all, the goal is to reduce such boilerplate logic as much as possible!), vhdMMIO supports specification of custom "internal" signals.

An internal signal is automatically inferred when its name is referenced by an event source or sink. The name acts as a unique identifier, so specifying the same name twice will result in the components being tied together.

Internal signals can be scalars (std_logic) or vectors (std_logic_vector), and can be level-based with a single driver, or strobe/event-based with one or more event sources (sometimes called strobers). The kind of internal signal that's associated with a name is usually implied by context. Of course, all endpoints that refer to an internal must agree to its kind, or vhdMMIO will send an error message your way.

Sometimes, you may want to use or drive an data source or sink outside the register file. For instance, there may be a page register outside the register file that you want to use to select which page of registers is accessible. That's where this configuration structure comes in: it lets you associate a port with an internal signal, essentially making it an external signal.

This structure supports the following configuration keys.

direction

This key specifies what kind of I/O port should be made for the internal signal specified by internal.

The following values are supported:

  • input: an input port is generated for the internal. This must be the internal signal's only driver.

  • strobe: an strobe input port is generated for the internal. The internal can be driven by other strobe sources as well; the result is wired-or.

  • output: an input port is generated for the internal.

This key is required.

internal

This key specifies the name and shape of the internal signal.

The following values are supported:

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: a port is generated for a scalar internal with the given name.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*:[0-9]+: a port is generated for a vector internal with the given name and width.

This key is required.

port

This key specifies the name of the port.

The following values are supported:

  • null (default): the port is named after the internal signal.

  • a string matching [a-zA-Za-z][a-zA-Z0-9_]*: the specified name is used for the port, regardless of the name of the internal signal.

This key is optional unless required by context. If not specified, the default value (null) is used.

group

The I/O port for the internal signal can optionally be grouped along with other ports in a record. This key specifies the name of the group record.

The following values are supported:

  • null (default): port grouping is determined by the global default.

  • no: the port is not grouped in a record.

  • a string matching [a-zA-Z][a-zA-Z0-9_]*: the port is grouped in a record with the specified name.

This key is optional unless required by context. If not specified, the default value (null) is used.