[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC] peripheral/register/bitfield objects - new MCU model
From: |
Liviu Ionescu |
Subject: |
[Qemu-devel] [RFC] peripheral/register/bitfield objects - new MCU model |
Date: |
Wed, 8 Jul 2015 23:14:36 +0300 |
as anyone who did it knows, describing memory mapped peripherals is tedious. as
far as I know, qemu support ends at defining memory regions and implementing
the read/write callbacks for all accesses in this region.
while implementing several Cortex-M devices (currently STM32F103, F107, F407,
F429 are functional for blinky projects), I experimented with some solutions to
automate this.
the model that I stopped at uses a hierarchy of objects that goes down to
register bitfield level (peripheral/register/bitfield).
the central object in this hierarchy is the peripheral register, which holds a
value (up to 64-bits), and its content is automatically retrieved/updated by
read/writes, based on accurate vendor bitmasks.
in addition, each register may have two user actions defined, a pre-read
action, to load the register with an external value, and a post-write action,
to forward the value to an external device, or to implement register
interdependencies.
these actions are obviously user functions, registered as callbacks.
the other objects, the peripheral and bitfield, are more or less helpers.
the bitfield is a simple object, that stores a mask and a shift value, to
retrieve a bitfield value; it is always a register child.
the peripheral is more or less a container of registers; it implements the
logic to forward read/writes to the appropriate register.
registers and bitfields are defined with arrays of Info structures; special
functions traverse these structures and create the objects.
an example of a read only 32-bit word register:
{
.desc = "Port input data register (GPIOx_IDR)",
.name = "idr",
.offset_bytes = 0x08,
.reset_value = 0x00000000,
.reset_mask = 0xFFFF0000,
.access_flags = PERIPHERAL_REGISTER_32BITS_WORD,
.readable_bits = 0x0000FFFF,
.rw_mode = REGISTER_RW_MODE_READ,
},
an example of a register with bitfields defined:
{
.desc = "RCC PLL configuration register (RCC_PLLCFGR)",
.name = "pllcfgr",
.offset_bytes = 0x04,
.reset_value = 0x24003010,
.bitfields = (RegisterBitfieldInfo[] ) {
{
.name = "pllm",
.desc = "PLL division factor",
.first_bit = 0,
.width_bits = 6,
},
{
.name = "plln",
.desc = "PLL multiplication factor",
.first_bit = 6,
.width_bits = 9,
},
{
.name = "pllp",
.desc = "Main PLL (PLL) division factor",
.first_bit = 16,
.width_bits = 2,
},
{
.name = "pllsrc",
.desc = "Main PLL (PLL) clock source",
.first_bit = 22,
},
{
.name = "pllq",
.desc = "Main PLL (PLL) division factor",
.first_bit = 24,
.width_bits = 4,
},
{ },
},
},
accessing registers and reading bitfields is straightforward:
peripheral_register_write_value(odr, new_value);
....
pllm = register_bitfield_read_value(state->f4.fld.pllcfgr.pllm);
this model has several advantages:
- increased emulation accuracy; the functionality is fully and uniformly
implemented for all objects, for example byte and unaligned accesses are
implemented for all registers; read/write masks allow to affect only the
desired bits; etc
- increased readability; the definitions are descriptive, not hidden inside code
- opens the door to automatically generate the MCU definitions
possible disadvantages:
- a small overhead, hopefully not impacting general performances
this model is currently implemented and functional in my branch, and it was
used to implement the needed STM32 peripherals (RCC, GPIO, FLASH, PWR) for the
STM32F1 and STM32F4 families, and will probably be part of the new GNU ARM
Eclipse QEMU release, scheduled in 2-3 weeks.
however I would consider it still experimental, since I already have new ideas
that I would like to experiment in future versions.
regards,
Liviu
- [Qemu-devel] [RFC] peripheral/register/bitfield objects - new MCU model,
Liviu Ionescu <=