 Okay, so hello everyone, I'm Fabien Chouteau, this is Quentin. So first I'm going to celebrate the 20 years of first time by showing off my 10 years old vintage t-shirts. And so yes, I am actually that old. So BSP generator for more than 3,000 arm microcontrollers. Actually, when I wrote the title, I didn't check, but it's more than 4,000 now. So what is this about? First we're going to start with some context, and then Quentin will explain what actually the project is. So the context is that we work for an open source software company called AdaCorp. We do open source software development tools. So we contribute to GCC, GDB. We have IDs, code coverage analysis, formal verification, so on and so forth. And so in particular for the Ada and Spark programming languages. And one of the targets and the context that we support for our customer and user is the really bare metal embedded platforms. And so we are independent from any hardware vendors, and you will see why this can be a problem sometimes. So very quickly, the Ada and Spark programming languages. So Ada is a language that is really designed for functional safety, and that's why it's heavily used in the safety critical domain. So we have the Unix, Space, Railway, and Automotive now as well. And so some of the useful key features are strong typing. So Ada is a strong type language, but what's most important is that you have the capability to define very precisely your own types. So that ranges, for instance, is one example. We also now have contract-based programming. And one interesting feature that we will talk about later is the representation clauses, which let you really precisely control the representation of your data at the hardware level. And Spark, so Spark is a subset of the Ada language with tools for formal verification. So you can have mathematical proof that your software is correct. And so another piece of the context is the market of ARM microcontrollers. And so that's only ARM. You can also consider other architecture. So there is dozens of vendors, eight different architecture variants. I think that's only eight so far, but maybe there are more. So of course you have thousands and thousands of different parts. And so, for instance, can anyone tell me how many RAM there is in an HT32F22366 or MB9AF155M? And so that's the kind of problem that we have when users come to us and say, how do you support the S6E2CC8HOA? Well, okay, that's kind of difficult. So if we dive a little bit deeper, if we look just at one of those microcontrollers, so HT32F446RET6, it's a beast. You have 46 peripherals in there. To control those 46 peripherals, you have more than 800 memory map registers. And in those registers, you have more than 6,000 fields that you have to program. And so the question for us, since we are providing tools for, let's say, an alternative programming language, so alternative means everything that is not C and C++, how can we actually provide drivers for this kind of architecture and for all the complexity of the ecosystem and the market? And so in particular, what we are looking at is the basic blocks to get started. And so for us, that means the linker script and the startup code that will be different for every microcontroller, mostly because of the different architecture and also the memory layer. So depending on how much RAM or flash do you have, for instance, the linker script will be different. And also drivers if possible. And so lucky for us, we have ARM to the rescue. So I don't know exactly when, but some years ago, ARM started, it's a bit difficult to describe what this is actually. Let's say it's an initiative, it's a program called Cortex Microcontroller Software Interface Standard, so CMCs for the happy few. And so there's many, many things under this name. So for instance, there's the DAP, so it's more or less some kind of standardized hardware debugging probe interface. That's what you get, for instance, if you plug a, I think, microbit development board, you see a USB flash drive, and you can just drag and drop program to it. I think that's some of the stuff that is defined with the DAP. The driver is a C driver API in a way, so that hardware vendors are supposed to implement and provide for their microcontrollers, but they don't always do that. There is also more or less the same concept, but for real-time operating system. So again, an API to basically provide, try to provide some kind of portability. And then you have interesting libraries, actually. So there's a neural network library, specifically for Cortex-M. There's also a DSP library, and I forgot to put it, but they also have some kind of file system dedicated for microcontrollers as well. So this is very interesting, but that's actually not the most interesting for us, because the other, the remaining part of CMCS are the CMCS packs. So in the general sense, it's just a way to distribute software packages, but what's interesting is the data inside. And so in particular, we will look at two kind of files, the PDSC and DSVD. And so I have to explain that actually the CMCS pack are provided by the hardware vendors. So ARM is defining more or less the structure and the data format, but it's provided by the vendors. And so in the PDSC, what we will be interested in is detailed specification for each microcontroller for all the more than 3,000 or 4,000 microcontrollers, you have detailed specification available in the PDSC. And the SVD is a description of the peripherals, the registers and the field that I mentioned earlier. And so now I will let Quentin tell you how we can use those data to provide the BSPs. So now the question is, how can we use all that data? So first, we can use a tool that we developed at ADECore called SVD2ADER. So what it does is it takes an SVD file, so in that case a plain XML file that describes down to each field of every register what its purpose and what the different values of the registers are. So SVD2ADER will take that file and generate some data bindings for it. Now, how could you interact with the register in C? So in C you would probably do something like that. So you define your macros, you have your register that you set at an address, and then with the binary operation, you set the mask that you want on your register. So if it works, it's fine, but it can be kind of unwieldy, and the C-type system is not helping you with it here, not at all. So in ADA, we have what we call, in ADA is park entry, actually, we have what we call representation closes. So here, for example, I describe a type called Pinsense, which is an NM, and I can specify its size, so its size has bit, so in our case it has two-bit size. For that NM, I set specific values for every value of the NM. And after that, what I can do is I described a type record, so it's actually like a structure in C, and I used the type previously described in the middle of the register to represent a specific register. After that, in my record, I can set the specific bits range for every field of my structure. And at the end, all I have to do is instantiate my type, I register with a variable register, and I can set its address like that, and afterward, if I want to disable or enable the sensor, all I have to do is call register.thing, and then the value that you want to put in there. So what's the advantage? The advantage is that the ADA type system is quite strong, and for example, if you want in C to write, let's say I have a field that is two bits, and I write by mistake an integer on that, well, you will write the integer, and there are some problems that will occur. If you try to do something like that in ADA, the compiler will warn you and will tell you it will not work. So that's the advantage here. So now we have some bindings to the peripherals and the registers, but now we still need to solve the problem of the CRT0 and the linker script, how to boot. Here comes my internship project at ADA Core that I started a year and a half ago. It's called Startup Gen, and what it does is it generates all that info for you, so the CRT0 and the linker script from the content in the CMC SPACs. So in the CMC SPACs, we have a lot of XML files actually, but we also have another one called a PDSC, which describes, it's really big, and it describes all the different devices and their memories. For example, if there are bootloaders where they are located, what else? Path to the documentation. So really a ton of stuff, but what interests us here is only really the memory part. So here we have a ROM, so it's marked as Startup, so the device will boot on the ROM, and then we have a ROM, so we start address and a size, and at the start it's not initialized. So we have to take care of initializing it ourselves. So from that XML file, we can write a GPR file. GPR is our, not internal representation at ELECO, but it's a file format that we use to compile our projects with our build system called GPR build. So here we can see that basically I transcribed the content of the XML in GPR form. So as you can see, it's a bit more readable for a human now. And from that GPR file, we can generate, what else is good with a GPR file is that you can take care of the advantages of that language, the GPR language. And for example, if you have a development board and a production board, you can set different values depending on the variable that board that you pass as parameter when generating the code. And the code will change depending on if you have a development or production board. So in that case, the linker script will be different. So now startup gen, okay, thank you. So startup gen will generate a CRT-0 and a linker script. So here is the CRT-0 and we can see that it's a part where we copy all that is supposed to be in data and when we call the main, we copy the parts of the data sections from the ROM to the ROM. So it's an assembly loop and all of that is generated based on the info we have in the CMC specs. Afterwards, so this is part of the linker script that is generated. And you can see we have a ROM, so the flash and the ROM actually, and we put the text sections in the flash. In our case, every ROM has different data sections, BSS sections, all of that. It's because we really want a way to boot rapidly on a board and if the user wants to customize a linker script, it's easier to tell the user to customize his linker script rather to come up with weird heuristics and weird behaviors to try and infer what the user would want. So as I told you, there's a missing link between the XML file and the GPR file. I told you I had to write it. So that's not true actually. Currently, it's handled by a database, but it's in the reverence in the repo because it's not finished currently. We want to integrate it in an ID. So Fabien told you before that we have an ID called Gnat Studio. And really the point of that in terms of subject was to integrate, was to make startup gen, so the tool to generate the code, and then to integrate it in an ID so that you would be able to, I want to start developing on Ada on a given board. I click New Project. I click a BSP project and then I select the board that I want to develop on. I click the button and then I can start developing on Ada and everything is taken care of for me. So this is the result that we have. We can basically generate an Ada Spark hardware bindings, let's say, so BSP for any Cortex-M controller that we have in our CMC Spark data banks. And it also includes how to boot the file, sorry, how to boot the board. So the chart is underlinked script. So thank you for your attention. Do you have any questions? Yes. Yeah. Okay, so the question is about the Rust embedded community that is doing also some things with SVD. And so you said they're also patching the SVD to fix them. And so the question is, do we talk with them or are we aware of this effort, I guess? So yes, we have seen this effort. I talk with some of them saying that hey, we do the same stuff. Actually, I think we started a little bit before them. And so far, we don't reuse the SVD patching stuff. But yeah, I've talked with some of the people from the embedded Rust. And there's really a common interest here. And I think in particular with Rust, like us, is an alternative programming language. And the stuff we deal with here, they will have to deal with it. And so potentially what's interesting is to be able to talk to the hardware vendor and make sure they provide good SVD files. Yeah, and also what's important is that actually SVD is not actually designed to generate code. It's supposed to be a format for Debugger so you can inspect the peripherals. And so it's not the intended usage for SVD. And so sometimes they are not very good. And also one of the problem I see is that, so this is for ARM, it's very nice. But for instance, we do a lot of programming on RISC-5 as well. And also I'm trying to push the RISC-5 vendors to provide SVD files for their devices. It's not always easy to explain why this is important. So the question is that we didn't show the implementation for interrupt vectors. Yeah, so actually that's a part that we didn't show. But in the GPR file you can specify. So from the PDSC, or from the SVD actually, you have the list of interrupts. And we also generate the interrupt vectors and we generate the vector table in the CRT0 as well. So we didn't show it but it's available. So the question is if the interrupts are handled by the operating system. So it depends on how you handle it. So for Cortex-M you always need to have a vector of an interrupt. So what you can do is you can specify the same handler name for every interrupt and that would be the symbol that your ERTOS is using. You would have to change the GPR file to specify that. Also what's important is that I guess the main point of this effort is to make it easy to start. But it will not cover all the possible use case because it's very complex. And something that I want to mention as well. So SVD to Ada of course is really focused on Ada. But the startup gen project can actually be used for C or probably for Rust as well. It's just a CRT0 and a linker script that's not related to any specific language. Okay, any more questions? Okay, thank you.