Getting started using a YAML file¶
Using a text editor you can define the YAML structure of your register map relatively easily. It gets a little easier if you use an editor that understands YAML, such as Notepad++ or an IDE such as PyCharm.
The example below shows a register map skeleton that defines some properties of the memory space, along with a summary and description of the register map. The modules section is left blank for now.
In any register map you must have at least one module.
registerMap: {
# A memorySpace is not optional
memorySpace: {
# but all the parameters are optional.
# Default: 0x0
baseAddress: 0x1000
# Default: None
pageSize: None
# Default: 32
addressBits: 48
# Default: 8
memoryUnitBits: 16
}
summary: 'A short summary of the register map'
description: 'A longer description of the register map'
modules: [
]
}
When you are done and have saved your YAML data to a file, your YAML register map can be loaded into Python.
import register_map
myMap = registerMap.load( 'registermap.yml' )
Let’s test that the register map properties are loaded as expected.
assert myMap.memory.addressBits == 48
assert myMap.memory.memoryUnitBits == 16
assert myMap.memory.baseAddress == 0x1000
Another way to quickly get started is to use the Python API to create a register map, export it to YAML and then copy-paste the YAML structures you find to create your data.
import register_map
myMap = registerMap.RegisterMap()
myMap.addModule( 'mymodule' )
myRegister = myMap['modules'][ 'mymodule' ].addRegister( 'myregister' )
myField = myRegister.addField( 'my-field', [2, 4] )
registerMap.save('myMap.yml', myMap)
When you initially create a map this way, or whenever you save register map YAML from Python you will notice a number of properties with an underscore (‘_’) prefix. These are included for reference for a human reader but the values themselves are automatically calculated; you should not modify them, but if you do, don’t expect your modifications to persist as changes will be overwritten the next time you same YAML from Python and they will never have any effect when loaded into Python.
Creating a module¶
modules:
- module:
constraints: {}
description: ''
instances: 1
name: mymodule
registers: []
summary: ''
The instances
properties is used when you are creating a series module.
Creating a register¶
registers:
- register:
bitFields:[]
bitmap:
- destination: '[0:2]'
destinationId: mymodule.myregister.my-field,
source: '[2:4]'
constraints: {}
description: ''
global: false
mode: rw
name: myregister
public: true
summary: ''
The particularly complicated bit here is defining the bitmap; when using Python this is taken care
of to varying degrees by the Python API, depending on the complexity of your bit mapping. The bit
map maps the bits of a member field to the bits of the register. The destination
bit range is
the bit indices of the field. The destinationId
is the canonical ID of the field you are
mapping and the source
is the bit range of the register.
In the example above, bits [0:2] of the bit field are mapped to bits [2:4] of the register.
The definition of the bit field itself is described in the next section.
The global
property is always false for now. It is a placeholder for a
global register feature.
Creating a local field¶
bitFields:
- field:
description: ''
name: my-field
parent: mymodule.myregister
resetValue: 0x0
size: 3
summary: ''
The parent
property is required to identify the bit field as local to the register and not
global (see below).
Creating a global field¶
A global field means that you intend to take the bits of that field and distribute them across multiple registers and modules. As a general rule a global field is not recommended at all for various reasons, not the least of which is that it greatly complicates software required to read, write and manage such “distributed” fields. It is supported here because hardware designers sometimes find it necessary to jam field bits into obscure locations and so a register map description should be able to accommodate this.
In YAML, a global field must have one and only one instantiation that defines the reset value and
size of the field. Subsequent declarations of the global field must only define which bits of the
register are being attached to. A global field must not define a parent
property.
In the example below we have two modules each with a register associating with a global field. To try and reduce the noise a bit, properties that don’t relate to the global field configuration have been dropped.
Notes:
- The register
m1.myregister
has a local fieldmy-field
. The destination bit mapping uses a “third level” canonical id to address the field;m1.myregister.my-field
- The register
m1.myregister
contains the definition of the global fieldmy-global-field
in it’sbitFields
section, including the reset value and size.- The register
m2.other_register
bitFields
section is empty because it has no local fields and is associating with the global field that has already been defined inm1.myregister
.m2.other_register
contain a bit mapping to the global fieldmy-global-field
- The global field
my-global-field
is always referenced using a “first level” canonical ID (just it’s name).
registerMap:
modules:
- module:
name: m1
registers:
- register:
bitFields:
- field: {description: '', name: my-field, parent: mymodule.myregister,
resetValue: 0x0, size: 3, summary: ''}
- field: {description: '', name: my-global-field, resetValue: 0x0, size: 6,
summary: ''}
bitmap:
- {destination: '[0:2]', destinationId: m1.myregister.my-field, source: '[2:4]'}
- {destination: '[3:5]', destinationId: my-global-field, source: '[5:7]'}
name: myregister
- module:
name: m2
registers:
- register:
bitFields: []
bitmap:
- {destination: '[0:2]', destinationId: my-global-field, source: '[1:3]'}
name: other_register