AdaCore / bb-runtimes

Source repository for the GNAT Bare Metal BSPs
Other
63 stars 50 forks source link

Add support for runtime sources generated from template files. #16

Closed damaki closed 3 years ago

damaki commented 5 years ago

This pull request is a proposal to add simple "code generation" capability to build_rts.py to solve the problem identified in #12 of customizing system.ads interrupt priorities for different ARM targets that support varying numbers of interrupt priorities.

Currently, when build_rts.py generates the source tree it simply copies (or symlinks) files from bb-runtimes and GCC/GNAT sources into the target source tree. This pull request adds a mechanism to perform simple string substitutions while copying certain files. This allows a common "template" file to be customised for each specific runtime where required. For example, a common system.ads template file for Cortex-M4 devices may be specialised with the correct number of interrupt priorities for the specific device.

When copying these "template" files, the script will search for instances matching the pattern ${var}, and will replace all instances with a value matching the key called var from a dictionary. For example, ${Max_Interrupt_Priority} in the template file may be replaced with 255 in the generated source.

Example

The default behaviour is to retain the existing behaviour, i.e. simply copy (or symlink) files without modifying their content. "Template" files that require this new functionality to modify files during generation must be explicitly configured as such, along with what values to substitute. Here is an example (using the nRF51 target as an example):

        self.add_sources('crt0', [
            'src/s-bbarat.ads',
            'src/s-bbarat.adb',
            'arm/nordic/nrf51/svd/i-nrf51.ads',
            'arm/nordic/nrf51/svd/i-nrf51-clock.ads',
            'arm/nordic/nrf51/svd/i-nrf51-rtc.ads',
            'arm/nordic/nrf51/svd/i-nrf51-uart.ads',
            'arm/nordic/nrf51/svd/handler.S',
            'arm/nordic/nrf51/start-rom.S',
            'arm/nordic/nrf51/s-bbmcpa.ads'],
            installer=TemplateFileInstaller({
                'key1': 10,
                'key2':'hello'
            })

In the above example, all of the source files mentioned in the list will be copied, and all instances in those files of ${key1} will be replaced with 10 and all instances of ${key2} will be replaced with hello in the destination file. These substitutions only affect the files in the list. Other files will be copied or symlinked as usual, unless they also specify their own installer.

Since system.ads files have their own system_ads property in the Target class, I added a new property system_ads_installer which returns the installer object that should be used to install the system.ads files in the source tree for each runtime. This property may be overridden to define alternative behaviours during generation of the source tree for system.ads. For example, I have updated ArmV7MTarget to make use of this to customise the interrupt priorities for Cortex-M4 targets.

Cortex-M4 Interrupt Priorities

I have used this new mechanism to customise Any_Priority, Priority, and Interrupt_Priority in system.ads based on the actual number of hardware interrupt priorities available on the specific Cortex-M4 device. The files src/system/system-xi-cortexm4-full.ads and src/system/system-xi-cortexm4-sfp.ads have been updated to act as template files. They define ${Max_Priority} and ${Max_Interrupt_Priority} in places where those values are required. The appropriate values are determined in system_ads_installer in cortexm.py based on the number of interrupt priorities available on the target.

The specific target classes can simply override the interrupt_priorities property to return the actual number of interrupt priorities available on the specific target.

Here's an example of the generated system.ads file for the stm32f4 target:

   Max_Interrupt_Priority   : constant Positive := 255;
   Max_Priority             : constant Positive := 240;

   subtype Any_Priority       is Integer range         0 .. 255;
   subtype Priority           is Any_Priority range    0 .. 240;
   subtype Interrupt_Priority is Any_Priority range  240 + 1 .. 255;

   Default_Priority : constant Priority := Max_Priority / 2;

Implementation

The main change to the build scripts is to associate an "installer" object with each source/destination pair managed by the existing FilesHolder class. This "installer" object is responsible for actually implementing the desired behaviour to generate the destination file from the source file.

The default installer is the new CopyFileInstaller class which just implements the behaviour from FilesHolder._copy and FilesHolder._copy_pair, i.e. to simply copy or symlink the file with no modifications.

The alternative installer is the new TemplateFileInstaller which performs the string substitutions during the file copy.

Extensibility

Fabien mentioned in #12 that we may need more code generation in bb-runtimes going forward. Keeping this in mind, I designed this new mechanism to support different installers that may implement different ways of generating files.

To implement a new custom installer, it is just necessary to 1) create a new installer class derived from CopyFileInstaller, then 2) override the install method with the desired behaviour. Then 3) this new class can then be set as the installer when calling add_sources, like in the example above where I used TemplateFileInstaller.

Fabien-Chouteau commented 3 years ago

Hello @damaki

I implemented a template system inspired by your PR. See: