Device Library Management
Introduction
The device library provides the means for loading and configuring a simulation model for a particular MCU model or variant. The information is also used for accessing the device internals in a ‘pythonic’ and human-readable way, mainly for testing and debugging purposes. The device library for yasimavr is built around 3 categories of classes/objects :
Descriptors : contains all the information describing a device: pins, interrupts, memory layout, registers, etc.
Builders : factory classes to instantiate and configure a device simulation model based on the information stored in descriptors.
Accessors : allows to access the internals of a device model, in particular the registers in a ‘Pythonic’ way. Designed primarily for automatic testing of simulation models but may also be used in simulation.
The information for configuring device models is stored in configuration files using the YAML format.
yasimavr contains pre-defined models for some device variants. To use these variants, there is no need for a user to dive into the device library package and configuration files, and one can simply use device_library.load_device().
The list of pre-defined models can be obtained in command line by executing python -m yasimavr --list-models
Note
Using the device library to instantiate a simulation model is not compulsory, it only makes it more convenient for commonly used device models. It is possible to build and configure a model from scratch using the C++ API classes if one feels like it…
Device Descriptor
A descriptor is a Python object storing the information required to build a simulated device model. There are two ways to load a Device object : by name or by file.
The information is loaded from device configuration files in YAML format.
Reg Path format
In device configuration files, registers can be referenced to by what is called a ‘reg path’. A reg path is a string representing a path through a device description tree to a register or a field. It can be absolute (from the root) or relative (from a given peripheral instance).
Valid formats for the regpath are:
[P]/[R]/[F] (1)
[R]/[F] (2)
[A]/[F] (3)
[P]/[R] (4)
[R] (5)
where [P] is a peripheral instance name, [R] a register name, [A] a register address, [F] a field or a combination of fields using the character ‘|’.
Register addresses can be decimal or hexadecimal. Fields can be represented by a name, a bit number X or a bit range X-Y. However, if the register is given by an address, named fields are not allowed.
Examples:
SLPCTRL/SMCR/SE : absolute path to the bit SE of the SMCR register belonging to the Sleep Controller
CPU/GPIOR0 : absolute path to the GPIOR0 register
SPCR/SPE : relative path to the SPI Enable bit of the SPI Control Register (valid in the context of a SPI interface controller)
EXTINT/PCICR/2 : absolute path to bit 2 of the PCICR register
EXTINT/PCMSK0/0-3 : absolute path to bits 0 to 3 of the PCMSK0 register
0x49/5|7 : path to the bits 5 and 7 of hexadecimal address 0x49
2/0 : path to bit 0 of decimal address 2
Note
Reference (Descriptor structure)
A descriptor is a Python object storing the information required to build a simulated device model.
There are two ways to load a Device object: * by name, using one of the builtin device models, by using DeviceDescriptor.create_from_model() * by file, using DeviceDescriptor.create_from_file()
- class yasimavr.device_library.descriptors.DeviceDescriptor
Top-level descriptor for a device variant, storing the configuration from a YAML configuration file. It contains information about pins, interrupts, memory space layout, etc.
- Variables:
name (str) – name of the device model.
architecture (str) – one of supported architectures, currently ‘AVR’ or ‘XT’
mem (MemoryDescriptor) – descriptor of the device memory
core_attributes (dict[str,bool]) – dictionary of the attribute values to configure the device model
fuses (dict[str,int]) – default values for the device fuses, usually taken from factory values
access_config (dict[str,bool]) – dictionary of configuration values for Accessor objects
pins (list[str]) – list of the pin names
interrupt_map (InterruptMapDescriptor) – configuration values for interrupts
peripherals (dict[str,PeripheralInstanceDescriptor]) – dictionary of the peripheral instances
- classmethod create_from_file(filename, repositories=())
Instantiate a device descriptor from an arbitrary configuration file.
- Parameters:
filename (str) – Device configuration file path
repositories (list) – list of locations for finding peripheral class configuration files
- classmethod create_from_model(model)
Instantiate a device descriptor from a pre-defined device model configuration.
- Parameters:
model (str) – Model/variant name. the value is case insensitive
To be valid, the model name must be included in the device list file pointed to by the global variable LibraryDatabase.
Note that device descriptor are cached and a previously instantiated descriptor may be returned.
- reg_address(reg_path, default=None)
Utility method that resolves a reg path and returns the address of the register. If the register could not be resolved, with a given default value, the default value is returned otherwise a ValueError exception is raised.
- Parameters:
reg_path (str) – reg path to a register, must be of format [P]/[R] (P: peripheral name, R: register name)
default (any) – if set to any value other than None, sets the default value
- class yasimavr.device_library.descriptors.PeripheralInstanceDescriptor(name, loader, f, device)
Descriptor class for the instantiation of a peripheral class.
For example, a device may have PORTA, PORTB, PORTC, all are instances of a PORT peripheral class.
- Variables:
name (str) – name of the instance
per_class (str) – class name of the peripheral
ctl_id (str) – CTLID used for the peripheral model instance
reg_base (int) – base address of the peripheral (-1 if not relevant)
class_descriptor (PeripheralClassDescriptor) – descriptor of the class of the peripheral
device (DeviceDescriptor) – top-level device descriptor owning the peripheral
config (dict) – YAML section storing the settings for configuring the peripheral model
- reg_address(reg_path, default=None)
Utility method that resolves a reg path and returns the address of the register. If the register could not be resolved, with a given default value, the default value is returned otherwise a ValueError exception is raised.
- Parameters:
reg_path (str) – reg path to a register, must be of format [R] or [P]/[R] (P: peripheral name, R: register name)
default (any) – if set to any value other than None, sets the default value
- class yasimavr.device_library.descriptors.PeripheralClassDescriptor(per_config)
Descriptor class for a peripheral class
- Parameters:
per_config – YAML configuration section for the peripheral class
- Variables:
registers (dict[str,RegisterDescriptor]) – map of the registers owned by the peripheral class
config (dict) – YAML section storing the settings for configuring the peripheral simulation model
- class yasimavr.device_library.descriptors.ProxyRegisterDescriptor(reg, offset)
Descriptor class for a register proxy, used to represent the high and low parts of a 16-bits register
- Variables:
reg (RegisterDescriptor) – full-length register descriptor
offset (int) – offset of the part from the register address
- class yasimavr.device_library.descriptors.RegisterDescriptor(reg_config)
Descriptor class for a I/O register
- Parameters:
reg_config – YAML configuration section for the register
- Variables:
name (str) – name of the register
address (int) – absolute address of the register (or -1 if not relevant)
offset (int) – offset of the register from the peripheral base address (or -1 if not relevant)
size (int) – size in bytes of the register
kind (str) – kind of the register, one of ‘RAW’, ‘INT’ or ‘’
fields (dict[str,RegisterFieldDescriptor]) – dict of fields composing the register
readonly (bool) – indicates if the register is readonly (true) or writable (false) for the CPU
supported (bool) – indicates if the register is supported by the simulation model
- class yasimavr.device_library.descriptors.RegisterFieldDescriptor(field_name, field_config, reg_size)
Descriptor class for a field of a I/O register
- Parameters:
field_name (str) – name of the field
field_config – YAML configuration section for the field
reg_size (int) – size of the register in bits
Note that variables differ depending on the kind of field
- Variables:
name (str) – name of the field
kind (str) – data type of the field: one of ‘RAW’, ‘INT’, ‘BIT’, ‘ENUM’
readonly (bool) – indicates if the field is readonly (true) or writable (false) for the CPU
supported (bool) – indicates if the field is supported by the simulation model
pos (int) – (BIT only) bit position
one (str) – (BIT only) interpretation of the ‘one’ value (by default: 1)
zero (str) – (BIT only) interpretation of the ‘zero’ value (by default: 0)
LSB (int) – (RAW, INT and ENUM) lowest significant bit position
MSB (int) – (RAW, INT and ENUM) most significant bit position
values (dist[int,str]) – (ENUM only) interpretation for the binary values
unit (str) – (INT only) unit of the values
- class yasimavr.device_library.descriptors.InterruptMapDescriptor(int_config)
Descriptor class for an interrupt vector map It includes the list of interrupt vectors with their names ordered by index. It also includes the sleep mask map. This maps the sleep modes supported by the device to the interrupts that can wake up the device.
Each sleep mask is a list of 8-bits flags where each bit enable or disable a vector. Example: with sleep_mask=[0xFF,0x80]: vectors 0 to 7 and 15 are enabled whilst vectors 8 to 14 and above 15 are disabled.
- Parameters:
int_config – YAML configuration section for the interrupt vectors
- Variables:
vector_size (int) – size in bytes of each vector
vectors (list[str]) – list of the vector names
sleep_mask (dict[name:list[int]]) – dict mapping the sleep masks to each sleep mode name
- class yasimavr.device_library.descriptors.MemorySpaceDescriptor(size, page_size)
Named tuple class for a memory space
- Parameters:
size (int) – size of the memory space in bytes
page_size (int) – size of the page for read/write operations (where relevant) in bytes
Reference (Utility functions)
- yasimavr.device_library.descriptors.convert_to_regbit(arg, per=None, dev=None)
Utility method that resolves a reg path and returns a regbit_t object. If the register could not be resolved, or if the result spans several bytes, a ValueError exception is raised.
If
argis an integer, it is interpreted as a register address and a regbit_t object representing the whole register is returned. Ifargis a list, it is interpreted as the elements of a reg path.One of
perordevarguments should be specified to resolve reg path with names.peris required to resolve relative reg paths. Ifperis given,devdoesn’t need to be.- Parameters:
arg (str|int|list) – reg path to convert
per (PeripheralInstanceDescriptor) – used to resolve reg paths
dev (DeviceDescriptor) – used to resolve reg paths
- yasimavr.device_library.descriptors.convert_to_regbit_compound(arg, per=None, dev=None)
Utility method that resolves a reg path and returns a regbit_compound_t object. If the register could not be resolved, a ValueError exception is raised.
If
argis a list, it is interpreted as a list of reg path to merge.One of
perordevarguments should be specified to resolve reg path with names.peris required to resolve relative reg paths. Ifperis given,devdoesn’t need to be.- Parameters:
arg (str|list[str]) – reg path or list of reg paths
per (PeripheralInstanceDescriptor) – used to resolve reg paths
dev (DeviceDescriptor) – used to resolve reg paths
- yasimavr.device_library.descriptors.convert_to_bitmask(arg, per=None, dev=None)
Utility method that resolves a reg path and returns a bitmask_t object. If the register could not be resolved, a ValueError exception is raised.
If
argis a list, it is interpreted as a list of reg path to merge.One of
perordevarguments should be specified to resolve reg path with names.peris required to resolve relative reg paths. Ifperis given,devdoesn’t need to be.- Parameters:
arg (str|list) – reg path to a register or field
per (PeripheralInstanceDescriptor) – used to resolve reg paths
dev (DeviceDescriptor) – used to resolve reg paths
Device Builders
- class yasimavr.device_library.builders._base.DeviceBuilder(dev_descriptor)
Generic device builder object, factory for device simulation models. Users don’t normally have to instantiate directly this class but rather use one of he sub-classes for each of the core architectures. It implements a cache for both peripheral builders and configuration structure.
- classmethod build_device(dev_desc, dev_class)
Builds a device simulator model using the information from a descriptor.
- Parameters:
dev_desc – device descriptor object
dev_class – base class for the device model to build and configure
- build_peripheral(device, per_name)
Build a peripheral from the device descriptor and attach it to a device model.
- Parameters:
device – instance of Device model
per_names – name of the peripheral instance to build
- build_peripherals(device, per_names)
Build a list of peripherals from the device descriptor and attach them to a device model.
- Parameters:
device – instance of Device model
per_names – list of peripheral names to build
- classmethod clear_cache()
Clears the internal class cache for device builders
Accessors
The core library provides a DeviceDebugProbe class that allows to read and write to I/O registers as if the probe was the CPU. However the probe only deals with 8-bits raw byte values.
Accessors provide an upper layer by using the information contained in descriptors, from device configuration files, and provide two features:
A fine-grained access to individual I/O bits and fields,
Pretty printing and human-readable interpretation of values for read/write operations.
For example, the following (using the debug probe object to enable sleep):
value = probe.read_ioreg(0x33) #reading the register SMCR
value |= 1 #setting SE (bit 0) to 1
probe.write_ioreg(0x33, value) #writing back to SMCR
is equivalent, using the accessor system, to :
device_accessor.SLPCTRL.SMCR.SE = 'enabled'
The following (Reading the current sleep mode):
value = probe.read_ioreg(0x33) #reading the register SMCR
mode = (value >> 1) & 0x07 #Extracting the SM field
print('Sleep mode :', mode) #Print the value (raw)
will output: >>> Sleep mode : 0
The equivalent, using the accessor system :
print('Sleep mode :', device_accessor.SLPCTRL.SMCR.SM)
will output: >>> Sleep mode : IDLE
Reference (Accessor structure)
- class yasimavr.device_library.accessors.DeviceAccessor(arg, descriptor=None)
Accessor class for a device.
It is initialised from either a probe or a device.
If the 1st argument is a probe, it must be already attached to a device. If it’s a device, the accessor will create a debug probe and attach it.
- Parameters:
arg (DeviceDebugProbe|Device) –
descriptor (DeviceDescriptor) – optional device descriptor object. If not specified, the descriptor is obtained from the _descriptor_ field of the device model instance.
- Variables:
pins (dict) – dictionary of the device model pins
- property aliases
Aliases of the device model corresponding to the descriptor used
- property descriptor
Getter for the device descriptor
- property name
Name of the device model corresponding to the descriptor used
- class yasimavr.device_library.accessors.CPUAccessor(probeIO, name, per, byteorders)
Accessor class for the core, giving access to the CPU registers (Rxx, PC) along with access to those located in the I/O space (SREG, SP)
- class yasimavr.device_library.accessors.PeripheralAccessor(probeIO, name, per, byteorders)
Accessor class for a peripheral instance
- property base
Getter for the peripheral base address (when relevant)
- property class_descriptor
Getter for the peripheral class descriptor
- property name
Getter for the peripheral name
- signal()
Getter for the peripheral signal (or None if not used)
- class yasimavr.device_library.accessors.RegisterAccessor(probeIO, per, addr, name, reg)
Accessor class for a I/O register.
This class allows to access the whole 8-bits of the register or by using each field composing it.
It supports ordering and comparison to integers.
- property address
Getter for the register address
- property allocated
Returns true is the register is properly allocated in the device model
- property name
Getter for the register name
- read()
Read a value from the I/O register
Return an integer (for INT or RAW kinds) or a bytes object (for ARRAY kind)
The read always succeeds even for unsupported registers.
- property size
Getter for the register size
- write(value)
Write a value to the I/O register
:param value integer (for INT or RAW kinds) or bytes-like object (for ARRAY kind)
Raise an exception if the register is read-only or unsupported
- class yasimavr.device_library.accessors.CPURegisterAccessor(probe, name, index=-1)
Accessor class for a CPU register: R0-R31, X, Y, Z, PC.
- property name
Getter for the register name
- read()
Read a value from the I/O register
- property size
Getter for the register size
- write(value)
Write a value to the I/O register :param value integer (8 or 16-bits depending on the register size)
- class yasimavr.device_library.accessors._FieldAccessor(reg, field)
Generic accessor class for a field of a I/O register. Field accessor can be converted and compared to integers (it uses the raw bit field value)
It uses the information stored in a field descriptor (
RegisterFieldDescriptor) to decode/encode the value.- read_raw()
Read a raw integer value for the field from the I/O register.
- write_raw(raw_value)
Write a raw integer value for the field to the I/O register.
- class yasimavr.device_library.accessors.BitFieldAccessor(reg, field)
Accessor class for a field of a I/O register consisting of one bit.
Bit fields can be written with 0, 1, False, True or any string corresponding to the defined ‘zero’ or ‘one’ parameters in the descriptor.
- read()
Read the value for the field from the I/O register.
:return the ‘one’ or ‘zero’ values defined in the field descriptor.
- write(value)
Write the value for the field to the I/O register.
:param value integer (raw value), boolean (True or False) or the ‘one’ or ‘zero’ values defined in the field descriptor.
- class yasimavr.device_library.accessors.IntFieldAccessor(reg, field)
Accessor class for a field of a I/O register consisting of an integer value.
- read()
Read a value for the field from the I/O register.
- write(value)
Write the value for the field to the I/O register.
- class yasimavr.device_library.accessors.EnumFieldAccessor(reg, field)
Accessor class for a field of a I/O register consisting of an enumeration value.
- read()
Write the value for the field to the I/O register.
Return one of the enumeration values if a enum dictionary is specified or else the raw integer value.
- write(value)
Write the value for the field to the I/O register.
:param value integer (raw value) or a string from one of the enumeration values
- class yasimavr.device_library.accessors.RawFieldAccessor(reg, field)
Accessor class for a field of a I/O register consisting of an raw value. It’s identical to IntFieldAccessor except it’s printed in hexadecimal.