-
Notifications
You must be signed in to change notification settings - Fork 46
5. Standard Templates
This chapter describes the standard templates included the
Device Modeling Language (DML)
library. The templates can be used for both registers and fields. The
templates can be accessed after importing utility.dml
.
The most common device register functionality is included in the standard templates.
Note that many standard templates has the same functionality and only differ by name or log-messages printed when writing or reading them. The name of the template help developers to get a quick overview of the device functionality. An example are the undocumented and reserved templates. Both have the same functionality. However, the undocumented template hints that something in the device documentation is unclear or missing, and the reserved template that the register or field should not be used by software.
The sub-sections use object as a combined name for registers
and fields. The sub-sections refers to software and hardware reads and
writes. Software reads and writes are defined as accesses using the
io_memory
interface (write/reads to memory/io mapped
device). Software reads and writes use the DML built-in read and write
methods. Hardware read writes are defined as accesses using Simics
configuration attributes, using the DML built-in set and get
methods. Device code can still modify a register or device even if
hardware modification is prohibited.
Reset behavior can vary quite a bit between different devices. DML
has no built-in support for handling reset, but there are standard
templates in utility.dml
to cover some common reset
mechanisms.
There are three standard reset types:
-
Power-on reset
-
The reset that happens when power is first supplied to a device.
-
Hard reset
-
Typically triggered by a physical hard reset line that can be controlled from various sources, such as a watchdog timer or a physical button. Often the same as a power-on reset.
-
Soft reset
-
This usually refers to a reset induced by software, e.g. by a register write. Not all devices have a soft reset, and some systems may support more than one type of soft reset.
Usually, the effect of a reset is that all registers are restored to some pre-defined value.
In DML, the reset types can be enabled by instantiating the templates
poreset
, hreset
and sreset
, respectively. These will define
a port with the corresponding upper-case name (POWER
, HRESET
, SRESET
),
which implements the signal
interface, triggering the corresponding reset
type on raising edge. This happens by invoking a corresponding method
(power_on_reset
, hard_reset
and soft_reset
, respectively), in all
objects implementing a given template (power_on_reset
, hard_reset
and
soft_reset
, respectively). The default is that all
registers and fields implement these templates, with the default behavior
being to restore to the value of the init_val
parameter.
The methods signal_raise
and signal_lower
can be overridden to add additional
side effects upon device reset. One example would be to track if the reset
signal is asserted to prevent interaction with the device during reset.
The default implementation of all reset methods recursively calls
the corresponding reset method in all sub-objects. Thus, if a reset
method is overridden in an object without
calling default()
, then reset is effectively suppressed in
all sub-objects.
The two most common overrides of reset behavior are:
-
to reset to a different value. In the general case, this can be done with an explicit method override. In the case of soft reset, you can also use the standard template
soft_reset_val
which allows you to configure the reset value with a parametersoft_reset_val
. -
to suppress reset. This can be done with a standard template:
sticky
suppresses soft reset only, whileno_reset
suppresses all resets.It is quite common that hard reset and power-on reset behave identically. In this case, we recommend that only a
HRESET
port is created; this way, the presence of aPOWER
port is an indication that the device actually provides a distinct behavior on power cycling.There are some less common reset use cases:
-
In some devices, the standard reset types may not map well to the hardware, typically because there may be more than one reset type that could be viewed as a soft reset. In this case, we recommend that
SRESET
is replaced with device-specific port names that map better to the hardware, but that thePOWER
andHRESET
port names are preserved if they are unambiguous. -
In some cases, it is desirable to accurately simulate how a device acts in a powered-off state. This would typically mean that the device does not react to other stimuli until power is turned on again.
The recommended way to simulate a powered-off state, is to let the high signal level of the
POWER
port represent that the device has power, and react as if power is down while the signal is low. Furthermore, the device is reset when thePOWER
signal is lowered.If this scheme is used by a device, then a device will be considered turned off after instantiation, so the
POWER
signal must be raised explicitly before the device can function normally.Thus, there are two rather different ways to handle devices that have a
POWER
port:-
POWER
can be treated as a pure reset port, which stays low for most of the time and is rapidly raised and lowered to mark a power-on reset. This is the most convenient way to provide a power signal, but it only works if the device only usesPOWER
for power-on reset. If the device models power supply accurately, then it will not function as expected, because it will consider power to be off. -
POWER
can be accurately treated as a power supply, meaning that the signal is raised before simulation starts, and lowered when power goes down. A reset is triggered by a lower followed by a raise. This approach is less convenient to implement, but more correct: The device will function correctly both if the device does an accurate power supply simulation, and if it only usesPOWER
for power-on reset.
-
Implemented on any object to get a callback on the corresponding reset event. Automatically implemented by registers and fields.
Implemented on the top level to get standard reset behaviour, for power-on reset, hard reset and soft reset, respectively.
power_on_reset
, hard_reset
, soft_reset
The following templates can be applied to both registers and fields. Most of
them affect either the write or read operation; if applied on a register it
will disregard fields. For instance, when applying the
read_unimpl
template on a register with fields, then the read
will ignore any implementations of read
or read_field
in fields, and return
the current register value (through get
), ignoring any read
overrides in
fields. However, writes will still propagate to the fields.
Implemented on a register or field. Upon soft reset, the reset value is
defined by the required soft_reset_val
parameter,
instead of the default init_val
.
Writes are ignored. This template might also be useful for read-only
fields inside an otherwise writable register. See the documentation for the
read_only
template for more information.
Reads return 0, regardless of register/field value. Writes are unaffected by this template.
The object value is read-only for software, the object value can be modified by hardware.
First software write results in a spec_violation log-message on log-level 1, remaining writes on log-level 2. Fields will only log if the written value is different from the old value.
If the register containing the read-only field also contains writable fields,
it may be better to use the ignore_write
template instead, since software
often do not care about what gets written to a read-only field, causing
unnecessary logging.
The register value can be modified by software but can't be read back, reads
return 0. Only for use on registers; use read_zero
for write-only
fields.
The first time the object is read there is a spec_violation log-message on log-level 1, remaining reads on log-level 2.
Software can only clear bits. This feature is often used when hardware sets bits and software clears them to acknowledge. Software write 1's to clear bits. The new object value is a bitwise AND of the old object value and the bitwise complement of the value written by software.
Software reads return the object value. The object value is then reset to 0 as a side-effect of the read.
Software can only set bits to 1. The new object value is the bitwise OR of the old object value and the value written by software.
Software can only set bits to 0. The new object value is the bitwise AND of the old object value and the value written by software.
Reads return a constant value.
Writes are unaffected by this template. The read value is unaffected by the value of the register or field.
The template is intended for registers or fields that have a stored value that
is affected by writes, but where reads disregard the stored value and return a
constant value. The attribute for the register will reflect the stored value,
not the value that is returned by read operations. For constant registers or
fields that do not store a value, use the constant
template instead.
read_val
: the constant value
constant
, silent_constant
,
read_zero
Writes are forbidden and have no effect.
The object still has backing storage, which affects the value being read. Thus, an end-user can modify the constant value by writing to the register's attribute. Such tweaks will survive a reset.
Using the constant
template marks that the object is intended to
stay constant, so the model should not update the register value, and not
override the read
method. Use the template
read_only
if that is desired.
First write to register or field (if field value is not equal to write value) results in a spec_violation log-message on log-level 1, remaining writes on log-level 2.
init_val: the constant value
read_constant
, silent_constant
,
read_only
The object value will remain constant. Writes are ignored and do not update the object value.
The end-user can tweak the constant value; any tweaks will survive a reset.
By convention, the object value should not be modified by the model; if that
behaviour is wanted, use the ignore_write
template instead.
init_val: the constant value
The object value is constant 0. Software writes are forbidden and do not update the object value.
First software write to register or field (if field value is not equal to write value) results in a spec_violation log-message on log-level 1, remaining writes on log-level 2.
The object is constant all 1's. Software writes do not update the object value. The object value is all 1's.
First software write to register or field (if field value is not equal to write value) results in a spec_violation log-message on log-level 1, remaining writes on log-level 2.
The object's functionality is unimportant. Reads return 0. Writes are ignored.
The object is marked reserved and should not be used by software. Writes update the object value. Reads return the object value.
First software write to register or field (if field value is not
equal to write value) results in a spec-viol
log-message on
log-level 2. No logs on subsequent writes.
The object functionality is unimplemented. Warn when software is using the object. Writes and reads are implemented as default writes and reads.
First read from a register results in an unimplemented log-message on log-level 1, remaining reads on log-level 3. Reads from a field does not result in a log-message. First write to a register results in an unimplemented log-message on log-level 1, remaining writes on log-level 3. First write to a field (if field value is not equal to write value) results in an unimplemented log-message on log-level 1, remaining writes on log-level 3.
read_unimpl
, write_unimpl
,
silent_unimpl
, design_limitation
The object functionality associated to a read access is unimplemented. Write
access is using default implementation and can be overridden (for instance
by the read_only
template).
First software read to a register results in an unimplemented log-message on log-level 1, remaining reads on log-level 3. Software reads to fields does not result in a log-message.
unimpl
, write_unimpl
,
silent_unimpl
, design_limitation
The object functionality associated to a write access is unimplemented. Read
access is using default implementation and can be overridden (for instance
by the write_only
template).
First software write to registers results in an unimplemented log-message on log-level 1, remaining writes on log-level 3. First write to a field (if field value is not equal to write value) results in an unimplemented log-message on log-level 1, remaining writes on log-level 3.
unimpl
, read_unimpl
,
silent_unimpl
, design_limitation
The object functionality is unimplemented, but do not print a lot of log-messages when reading or writing. Writes and reads are implemented as default writes and reads.
First software read to a register results in an unimplemented log-message on log-level 2, remaining reads on log-level 3. Software reads to fields does not result in a log-message. First software write to a register results in an unimplemented log-message on log-level 2, remaining writes on log-level 3. First write to a field (if field value is not equal to write value) results in an unimplemented log-message on log-level 2, remaining writes on log-level 3.
The object functionality is undocumented or poorly documented. Writes and reads are implemented as default writes and reads.
First software write and read result in a spec_violation log-message on log-level 1, remaining on log-level 2.
The register is excluded from the address space of the containing bank.
Do not reset object value on soft-reset, keep current value.
The object's functionality is not in the model's scope and has been left unimplemented as a design decision. Software and hardware writes and reads are implemented as default writes and reads. Debug registers are a prime example of when to use this template. This is different from unimplemented which is intended to be implement (if required) but is a limitation in the current model.
The register's or field's value will not be changed on a hard or soft reset.
Only valid in bank
objects. The bank is recognized as a function mapped bank
by the function_io_memory
template, and is mapped to a
specified function by whoever instantiates that template.
function: the function number, an integer
Only valid in implement
objects named io_memory
. Implements the io_memory
interface by function mapping: An incoming memory transaction is handled by
finding a bank that instantiates the
function_mapped_bank
template inside
the same (sub)device as implement
, and has a function
number that matches the memory transaction's. If such a bank exists, the
transaction is handled by that bank. If no such bank exists, an error message
is logged and a miss is reported for the access.
Mapping banks by function number is a deprecated practice, still used by PCI devices for legacy reasons. It is usually easier to map a bank directly into a memory space, than using a function number as an indirection.
Note also that function numbers as defined by the PCI standard are unrelated to the function numbers of banks. They can sometimes coincide, though.
function: the function number, an integer
Only valid in bank
objects. Handles unmapped accesses by ignoring write
accesses, and returning a given value for each unmapped byte. If you want to
customize this behaviour, overriding unmapped_get
is sufficient to also
customize unmapped_read
.
miss_pattern: each missed byte in a miss read is set to this value
A connect
object can instantiate the template map_target
. The template
provides an easy way to send memory transactions to objects that can be
mapped into Simics memory maps. It defines a default implementation of set
which assigns the session variable map_target
of type map_target_t *
,
which can be used to issue transactions to the connected object. It also
defines a default implementation of validate
which verifies that the
object can be used to create a map target, i.e. the Simics API
SIM_new_map_target
returns a valid pointer.
The template defines the following methods:
-
read(uint64 addr, uint64 size) -> (uint64) throws
Reads
size
bytes starting ataddr
in the connected object. Size must be 8 or less. Byte order is little-endian. Throws an exception if the read fails. -
read_bytes(uint64 addr, uint64 size, uint8 *bytes) throws
Reads
size
bytes intobytes
, starting ataddr
in the connected object. Throws an exception if the read fails. -
write(uint64 addr, uint64 size, uint64 value) throws
Writes
value
ofsize
bytes, starting ataddr
in the connected object. Size must be 8 or less. Byte order is little-endian. Throws an exception if the write fails. -
write_bytes(uint64 addr, uint64 size, const uint8 *bytes) throws
Writes
size
bytes frombytes
, starting ataddr
in the connected object. Throws an exception if the write fails. -
issue(transaction_t *t, uint64 addr) -> (exception_type_t)
Provides a shorthand to the API function
SIM_issue_transaction
. This method is called by the read/write methods in this template. It can be overridden, e.g. to add additional atoms to the transactions, while still allowing the ease-of-use from the simpler methods.
Implements a signal interface with saved state. The current state of the signal
is stored in the saved boolean high
, and a spec-violation message is logged
on level 2 if the signal is raised or lowered when already high or low. The
methods signal_raise
and signal_lower
can be overridden to add additional
side effects.
Implements a connect with a signal interface, with saved state. The current
state of the signal is stored in the saved boolean signal.high
. If the
connect is changed while signal.high
is true
and the device is configured,
the signal_lower
method will be called on the old object, and the
signal_raise
method will be called on the new object. Similarly, if the
device is created with signal.high
set to true
, the signal_raise
method
will be called on the connected object in the finalize phase. This behaviour
can be changed by overriding the set
method and/or the post_init
method. The template defines the following method:
-
set_level(uint1 high)
: Sets the level of the signal, by callingsignal_raise
orsignal_lower
, as required. Also setssignal.high
tohigh
.