Open-CMSIS-Pack / devtools

Open-CMSIS-Pack development tools - C++
Apache License 2.0
73 stars 54 forks source link

Difficulties using component-defined linker script with regions file or non-preprocessor linker script include #1712

Open KarolSaja-AlifSemi opened 3 weeks ago

KarolSaja-AlifSemi commented 3 weeks ago

Background

We are a vendor implementing a DFP for a family of devices. There are 8 distinct parts, each with the same 2 cores (and these 2 are different from one another). In other words, we have:

as available targets.

Some features are defined by the core (clock, local TCM, first part of the vector table), while others are defined by the device (bulk/external memory, peripherals, second part of the vector table). We had no problems specifying these in the startup component of the CMSIS pack: it selects some files based on the core and some based on the device. This approach is much easier and more logical than maintaining all 16 distinct combinations (especially if we add more cores and devices going forward).

Describe The Problem To Be Solved

[problem A] The first problem we ran into is with using two part-linker script. Because of unusual layout of the device, our startup component provides linker script in two files (both with config attribute). Device part specifies regions: their base addresses and sizes, and is then included in the core part that serves as an actual script used for linking. This is using standard INCLUDE directive in LD and doesn't rely on C preprocessor. This unfortunately doesn't work because link stage (with GCC at least) is not given any include paths (library lookup paths serve as include paths for LD) and the included script path needs to be referenced from the build folder, e.g.: INCLUDE ..\..\..\RTE\Device\DEVICE1_CORE1\mem_regions.ld Since the core linker script is generic for a given core on all devices, it won't know this path and hence this approach is impossible implement (at least without additional directives in the cdefault/cproject file).

[problem B] Seeing as csolution already generates a convenient (and configurable) regions header automatically, we attempted to use this approach, especially given its clearly defined in the spec. However this also proved difficult to implement, because preprocessing of the linker script is only enabled if both, the filename suffix is .src AND cdefault/cproject specifically lists the regions file. Given the name of our auto-generated regions header will be different for every device:core combination, we can't make it work out of the box with a generic project configuration.

[problem C] Defining our own generic regions.h file included in our startup component doesn't prevent csolution from auto-generating one, even if no memory regions are specified in the .pdsc.

Suggest A Solution

Ideally A & B or A & C could be implemented to allow for easier regions management.

ReinhardKeil commented 3 weeks ago

@KarolSaja-AlifSemi thanks for this input that comes very timely. Is your DFP accessible somewhere? Having an example make things easier.

KarolSaja-AlifSemi commented 3 weeks ago

@ReinhardKeil thank you for picking this up so quickly. This issue relates to an experimental pack file we're building internally (.pdsc attached), where we're trying different layouts to determine which one is the most logical and simplifies our maintenance going forward as more device variants (with different memories, peripherals & etc.) are introduced. Right now we're just focusing on startup code. AlifSemiconductorDEV.Ensemble.pdsc.txt

For reference, our official "DFP" is already submitted to the Keil database here: https://www.keil.arm.com/packs/ensemble-alifsemiconductor/devices/ so you can see what kind of device/core combinations there are.

In the PDSC attached above you can see that the startup component includes two linker scripts: one based on the processor (core) name and one based on the device name. Device linker script has its category set to "other" to avoid confusing csolution/cbuild with multiple linker scripts, as its sole purpose is to be included in the processor linker script.

Our intention is to make this work without passing any special settings to the project configuration (especially if they're device/processor specific, it will make our basic project template a nightmare to maintain), by simply including our startup component. We also want to avoid having to create (and maintain) a unique linker script for each device/processor combination, as some of our devices have up to 4 cores, all of which we'd like to support with our DFP.

ReinhardKeil commented 2 weeks ago

@KarolSaja-AlifSemi

When a project specifies the linker: node with regions: and script: there should be no automatic generation of any script or regions files.

When My_M55_HP.cproject.yml contains the below nodes it should work.

  device: :M55_HP    # select core
  :
  linker:
    regions: .\RTE\Device\AE101F4071542\mem_config.h
    script: .\RTE\Device\AE101F4071542\linker_gnu.ld.src

mem_config.h could include another header file. Is this how you have composed it?

KarolSaja-AlifSemi commented 2 weeks ago

@ReinhardKeil thanks for pointing this out, could be useful. For now mem_config.h/mem_regions.h will be a single header, without making things too complicated. However with this solution, there is still a problem of having to explicitly specify the name of the device/processor, as it makes up part of the path to where "config" attribute files are copied (like linker script, regions & etc.). This prevents us from having one generic cproject/cdefault template that suits all of our devices.

That path is already automatically included for the compilation step, can we also include it by default when linker script is preprocessed? Even better if we could add all the include paths that are defined in the project: scope (e.g. with components). Looks like a simple change to the .cmake templates included in the /etc. With this change we could simply write:

  device: :M55_HP    # select core
  :
  linker:
    regions: mem_config.h
    script: linker_gnu.ld.src
ReinhardKeil commented 2 weeks ago

Thanks for the feedback. I created this ticket #1719 and we will discuss the options today in the Open-CMSIS-Pack technical meeting (I will post the recording). Feel free to join this meeting.

We should also take a look to your proposal regarding project templates. There are already provisions to bring in templates in the IDE. Could we work together on this? Can you provide an example template that reflects your project structure?

KarolSaja-AlifSemi commented 2 weeks ago

@ReinhardKeil I pushed a draft of the template to my repo: https://github.com/KarolSaja-AlifSemi/alif_vscode-minimal. Right now this project uses the old pack file with the single linker script.

The proposal in the #1719 is fine, as long as we have a way to either know the path to the configs, or have a variable for the name of the selected device and processor.

We'd like to make this a generic starting point, where the only selection needed is the device/processor. Currently I hardcoded this for our top-end device. The goal is to eventually include these in the section of the PDSC.

For the IDE we're using VS Code with Arm csolution plugin and Arm Environment manager, but currently there's no ability to change the selected device once the project is created (without modifying the .yaml directly).

KarolSaja-AlifSemi commented 2 weeks ago

Small update, regarding the following comment:

or have a variable for the name of the selected device and processor.

I forgot that these already exist (https://github.com/ReinhardKeil/cmsis-toolbox/blob/main/docs/YML-Input-Format.md#access-sequences), giving us a generic way to include device/processor specific regions header (or anything else in the config folder, for that matter):

  linker:
    - regions: "RTE/Device/$Dname$_$Pname$/regions_$Dname$_$Pname$.h"