Memory sections
Each data object of an embedded project lives in a memory with a character of its own - RAM,
flash, calibratable ROM behind an emulation overlay, NVM - and the linker places it there by
section. A sections file declares the sections a project uses, and a definition names
one of them; DDD checks the placement and carries it into the generated c.
{
"$schema": "../../schemas/ddd_sections.schema.json",
"sections": [
{ "section": ".fast_ram", "access": "read-write", "alignment": 4 },
{ "section": ".calib", "access": "read-only", "alignment": 4,
"description": "calibration flash, tool writable through the emulation overlay" }
]
}
section is the name as the linker script spells it - a linker name rather than a c
identifier, so .calib is a normal spelling. access is read-write or
read-only from the running software’s point of view; whether a calibration tool can
write a read-only section - an emulation overlay, a calibratable flash - is the target’s
business and deliberately not modelled, because the object’s volatile already states
what the software has to assume. alignment is what the section guarantees, in bytes, a
power of two. The file is listed in the includes of a project like any other
description, and ddd schema sections prints its published contract.
examples/vocabulary is a ready to run project placing measurements and a parameter
into exactly these two sections, next to the unit vocabulary and the
constants of the same project; it checks clean.
A definition then states its section - a storage key like init: the producer states
it, a consumer stating one is refused as consumer-storage, and a structured variable is
placed whole, its members having no placement of their own. An object without a section
goes wherever the toolchain’s defaults put it, which is what makes placement adoptable
gradually.
{
"scope": "output",
"definition": {
"name": "Speed",
"kind": "measurement",
"datatype": "uint16",
"conversion": {},
"volatile": true,
"section": ".fast_ram"
}
}
Unlike a unit, a section is a reference rather than a spelling: naming one that no file declares is refused whether or not any sections file exists, because a section without declared properties is a name the checks below can say nothing about:
$ ddd check p.ddd.json
a.ddd.json#component.interface[2].definition.section: error[unknown-section]: 'Bad' is placed in '.calibb', which is not a section any file of this project declares - did you mean '.calib'?
1 error
Two checks tie placement to what the description already says. A measurement is written by
the software, so placing one in a read-only section is an error; a calibration object may
live in either - const data in RAM is a mirrored calibration:
$ ddd check p.ddd.json
a.ddd.json#component.interface[2].definition.section: error[section-access]: 'Bad' is a measurement, which the software writes, but '.calib' is read-only
1 error
And an object whose datatype needs stricter alignment than its section guarantees is reported - as a warning, because for a structure the need is estimated as the strictest of its members’ datatypes and the compiler’s word on the real layout is final:
$ ddd check p.ddd.json
a.ddd.json#component.interface[1].definition.section: warning[section-alignment]: 'Gain' needs an alignment of 4, but '.calib' guarantees 2
1 warning
The generated c carries the placement in whatever spelling the toolchain wants, which is the templates’ business like the rest of the house style; the shipped example templates spell the GCC attribute, with the attribute between the declarator and the initialiser:
uint16_t Speed __attribute__((section(".fast_ram")));
const uint32_t Gain __attribute__((section(".calib"))) = 3U;
Templates also receive the placed objects grouped per section under model.sections,
ordered strictest alignment first with names breaking ties, so that a project wanting
padding-minimal layout can emit each section’s data in that order. Describing the layout in
the a2l with MEMORY_SEGMENT is planned: a segment’s address and size exist only after
linking, so they will arrive with the address information rather than being restated in the
vocabulary - the linker script already owns them, and a copy would drift. The MOD_PAR
block that will carry them already exists for the
constant vocabulary.