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
- Metadata
- Register file options
- VHDL entity configuration
- VHDL interface configuration
- Field descriptors
primitive
behaviorconstant
behaviorconfig
behaviorstatus
behaviorinternal-status
behaviorlatching
behaviorControl
internal-control
behaviorflag
behaviorvolatile-flag
behaviorinternal-flag
behaviorvolatile-internal-flag
behaviorstrobe
behaviorinternal-strobe
behaviorrequest
behaviormulti-request
behaviorcounter
behaviorvolatile-counter
behaviorinternal-counter
behaviorvolatile-internal-counter
behaviorstream-to-mmio
behaviormmio-to-stream
behavioraxi
behaviorinterrupt
behaviorinterrupt-flag
behaviorvolatile-interrupt-flag
behaviorinterrupt-pend
behaviorinterrupt-enable
behaviorinterrupt-unmask
behaviorinterrupt-status
behaviorinterrupt-raw
behaviorcustom
behavior- Additional address match conditions
- Subaddress components
- Permissions
- Interrupt descriptors
- Internal signal I/O
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 defaultreset
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
andawprot
; - Write data channel:
wvalid
,wready
,wdata
, andwstrb
; - Write response channel:
bvalid
,bready
, andbresp
; - Read address channel:
arvalid
,arready
,araddr
, andarprot
; - Read data channel:
rvalid
,rready
,rdata
, andrresp
.
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 fromvhdmmio_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. Ifgroup
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 becomestd_logic_array
s (ascending range), andstd_logic_vector
ports become an array (ascending range) of an appropriately sizedstd_logic_vector
. -
yes
: All port types are flattened tostd_logic
s orstd_logic_vector
s.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 ofstd_logic_vector
s). -
yes
: as above, but allstd_logic
-based generics are flattened to singlestd_logic
s 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_vector
s 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:
-
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
: likecontrol
, 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
: likeflag
, but implicitly cleared on read. -
internal-flag
: likeflag
, but set by an internal signal. -
volatile-internal-flag
: combination ofvolatile-flag
andinternal-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 anothervhdmmio
construct. -
request
: likestrobe
, 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:
-
counter
: external event counter, reset explicitly by a write. -
volatile-counter
: external event counter, reset implicitly by the read. -
internal-counter
: internal event counter, reset explicitly by a write. -
volatile-internal-counter
: internal event counter, reset implicitly by the read.
-
-
Fields for interfacing with AXI streams:
-
stream-to-mmio
: field which pops data from an incoming stream. -
mmio-to-stream
: field which pushes data into an outgoing stream.
-
-
-
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:-
interrupt
: base class for interrupt field behaviors. Normally not used directly; it's easier to use one of its specializations: -
interrupt-flag
: interrupt pending flag, cleared by writing ones. -
volatile-interrupt-flag
: interrupt pending flag, cleared by reading. -
interrupt-pend
: software-pend field. -
interrupt-enable
: interrupt enable control field. -
interrupt-unmask
: interrupt unmask control field. -
interrupt-status
: reflects the masked interrupt flag. -
interrupt-raw
: reflects the raw interrupt request.
-
-
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 thefeatures
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, thewrite_data
signal is renamed todata
, and thewrite_enable
signal is renamed tovalid
, 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 bymonitor-internal
. -
bit-set
: the internal data register is constantly or'd with the vector-sized internal signal named bymonitor-internal
. -
increment
: the internal data register is incremented whenever the respective bit in the repeat-sized internal signal named bymonitor-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, counter
s 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
tovalid-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
tovalid-only
. In this case, a read from an empty holding register yields a slave error. This is very simple fromvhdmmio
'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
orempty-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
toinvalid-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
toinvalid-only
. In this case, writing to a full holding register yields a slave error. This is very simple fromvhdmmio
'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
orempty-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, sincedata
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 fromvhdmmio_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
: likeread
, 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
, andwrite-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 theelse
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, orNone
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 theinterfaces
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 totrue
, 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 anstd_logic
for scalar fields and to an appropriately sizedstd_logic_vector
for vector fields. - Set the
$nack$
boolean variable totrue
to respond with a slave error. - Set the
$block$
boolean variable totrue
to stall. In this case, the block will be executed again the next cycle. Theread-can-block
key must be set in order to use this variable. - Set the
$defer$
boolean variable totrue
to defer. In this case, the request logic will accept the bus request and send subsequent requests toread-lookahead
blocks, while the response logic will start calling theread-response
block to get the response. Such aread-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$
: theprot
field associated with the request as a 3-bitstd_logic_vector
.$addr$
: the incoming bus address for the request as a 32-bitstd_logic_vector
.$sub$
: the subaddress for the for the request as anstd_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 totrue
to defer. In this case, the request logic will accept the bus request and send subsequent requests toread-lookahead
blocks, while the response logic will start calling theread-response
block to get the response. Such aread-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$
: theprot
field associated with the request as a 3-bitstd_logic_vector
.$addr$
: the incoming bus address for the request as a 32-bitstd_logic_vector
.$sub$
: the subaddress for the for the request as anstd_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 totrue
, 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 anstd_logic
for scalar fields and to an appropriately sizedstd_logic_vector
for vector fields. - Set the
$nack$
boolean variable totrue
to respond with a slave error. - Set the
$block$
boolean variable totrue
to stall. In this case, the block will be executed again the next cycle. Theread-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 totrue
to respond with an acknowledgement. - Set the
$nack$
boolean variable totrue
to respond with a slave error. - Set the
$block$
boolean variable totrue
to stall. In this case, the block will be executed again the next cycle. Thewrite-can-block
key must be set in order to use this variable. - Set the
$defer$
boolean variable totrue
to defer. In this case, the request logic will accept the bus request and send subsequent requests towrite-lookahead
blocks, while the response logic will start calling thewrite-response
block to get the response. Such awrite-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 anstd_logic
for scalar fields, and like an appropriately sizedstd_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$
: theprot
field associated with the request as a 3-bitstd_logic_vector
.$addr$
: the incoming bus address for the request as a 32-bitstd_logic_vector
.$sub$
: the subaddress for the for the request as anstd_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 totrue
to defer. In this case, the request logic will accept the bus request and send subsequent requests towrite-lookahead
blocks, while the response logic will start calling thewrite-response
block to get the response. Such awrite-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 anstd_logic
for scalar fields, and like an appropriately sizedstd_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$
: theprot
field associated with the request as a 3-bitstd_logic_vector
.$addr$
: the incoming bus address for the request as a 32-bitstd_logic_vector
.$sub$
: the subaddress for the for the request as anstd_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 totrue
to respond with an acknowledgement. - Set the
$nack$
boolean variable totrue
to respond with a slave error. - Set the
$block$
boolean variable totrue
to stall. In this case, the block will be executed again the next cycle. Thewrite-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, ifread-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 thatvhdmmio
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 anstd_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 anstd_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 anstd_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 anstd_logic
orstd_logic_vector
. -
natural
: this interface is a VHDLnatural
. -
boolean
: this interface is a VHDLboolean
. -
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.