├── .gitignore ├── CONTRIBUTING.md ├── COPYING3 ├── README.md ├── doc ├── Makefile └── source │ ├── adacore-logo-white.png │ ├── conf.py │ ├── favicon.ico │ ├── index.rst │ └── theme │ ├── static │ └── adacore.css_t │ └── theme.conf ├── share ├── examples │ └── startup-gen │ │ └── startup-gen-stm32f4 │ │ ├── README.txt │ │ ├── hello.gpr │ │ └── src │ │ └── hello.adb └── startup-gen │ └── resources │ ├── armvX-m.S.tmplt │ ├── armvX-m.ld.tmplt │ ├── riscv.S.tmplt │ └── riscv.ld.tmplt ├── src ├── device.adb ├── device.ads ├── main.adb ├── number_input.adb ├── number_input.ads ├── setup.adb ├── setup.ads ├── utils.adb └── utils.ads ├── startup_gen.gpr └── testsuite ├── tests ├── basic_symbol_matching │ ├── cortex-m │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── risc-v32 │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ └── risc-v64 │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml ├── boards │ ├── hifive1 │ │ ├── prj.gpr │ │ ├── src │ │ │ ├── main.adb │ │ │ ├── test-flash.adb │ │ │ ├── test-flash.ads │ │ │ ├── test-ram.adb │ │ │ └── test-ram.ads │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── polarfiresoc │ │ ├── prj.gpr │ │ ├── src │ │ │ ├── main.adb │ │ │ ├── test.adb │ │ │ └── test.ads │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── stm32f407_disco │ │ ├── prj.gpr │ │ ├── src │ │ │ ├── main.adb │ │ │ ├── test-ccm.adb │ │ │ ├── test-flash.adb │ │ │ ├── test-ram.ads │ │ │ ├── test-rom.ads │ │ │ └── test-sram.adb │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ └── stm32f407_disco_C │ │ ├── prj.gpr │ │ ├── src │ │ └── main.c │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml ├── gpr_tool │ ├── spec.gpr │ ├── test.py │ ├── test.ref │ └── test.yaml ├── invalid_gpr │ ├── invalid_addr │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_arch │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_boot_mem │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_mem_kind │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_size │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_stack_mem │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_stack_mem_kind │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── invalid_user_tags │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── memory_overlap │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── missing_addr │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── missing_kind │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── missing_size │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── no_boot_mem │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ └── project_not_found │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml ├── no_project_file │ ├── test.py │ ├── test.ref │ └── test.yaml ├── templates │ ├── boot_from_rom │ │ ├── boot_from_rom.tmplt │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── interrupts │ │ ├── interrupt_list.tmplt │ │ ├── spec.gpr │ │ ├── spec_no_int.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── memory │ │ ├── memory_list.tmplt │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ ├── print_tags │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml │ └── user_tags │ │ ├── spec.gpr │ │ ├── test.py │ │ ├── test.ref │ │ └── test.yaml └── z999-999 │ ├── test.py │ └── test.yaml ├── testsuite.py └── testsuite_support ├── __init__.py ├── python_driver.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | gpr2ld 3 | gnatinspect.db 4 | spec-loc.xml 5 | *.pyc 6 | testsuite/out 7 | testsuite/**/crt0.S 8 | testsuite/**/linker.ld 9 | doc/_build 10 | startup-gen 11 | database 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to statup-gen 2 | ========================== 3 | 4 | Thank you for taking the time to contribute! 5 | 6 | If this is your first contribution, we invite you to read our [list of 7 | guidelines](https://github.com/AdaCore/contributing-howto), common to all 8 | AdaCore repositories. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # startup-gen 2 | 3 | `startup-gen` generates startup files (crt0 and linker script) based on 4 | properties of the target device such as: architecture, memory layout, number of 5 | interrupts. 6 | 7 | One of the goals of this tool is to make it easier to start developing on 8 | micro-controllers by providing the basic elements of a Board Support Package 9 | (BSP). 10 | 11 | # Build 12 | 13 | `startup-gen` depends on the 14 | [template-parser](https://github.com/AdaCore/templates-parser) library. Clone 15 | or download the repository and follow the build instructions. 16 | 17 | Once built, set the `GPR_PROJECT_PATH` path using: 18 | ``` 19 | $ export GPR_PROJECT_PATH=/path/to/built-templates-parser/share/gpr 20 | ``` 21 | 22 | Download and install a native GNAT Community compiler at 23 | [adacore.com/download](https://www.adacore.com/download). 24 | 25 | Build with this command: 26 | ``` 27 | $ gprbuild -P startup_gen.gpr 28 | ``` 29 | 30 | # Usage 31 | 32 | See [documentation](doc/source/index.rst). 33 | 34 | # Work-in-progress 35 | 36 | The `dev` branch of this repository also contains work-in-progress tools to 37 | build a database of target properties for more than 3000 ARM micro-controllers 38 | from CMSIS-Pack files. 39 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = startup-gen 8 | SOURCEDIR = source 9 | BUILDDIR = . 10 | 11 | # Internal variables. 12 | PAPEROPT_a4 = -D latex_paper_size=a4 13 | PAPEROPT_letter = -D latex_paper_size=letter 14 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 15 | 16 | .PHONY: help Makefile 17 | 18 | html: 19 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 20 | 21 | pdf: 22 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/pdf 23 | make -C $(BUILDDIR)/pdf all-pdf LATEXOPTS="-interaction=nonstopmode" 24 | 25 | -------------------------------------------------------------------------------- /doc/source/adacore-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaCore/startup-gen/07391cc41a6c06a688e069878943a716b0226fbb/doc/source/adacore-logo-white.png -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'startup-gen' 23 | copyright = '2019, AdaCore' 24 | author = 'AdaCore' 25 | 26 | # The short X.Y version 27 | version = '' 28 | # The full version, including alpha/beta/rc tags 29 | release = '' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx_rtd_theme', 43 | ] 44 | 45 | # Add any paths that contain templates here, relative to this directory. 46 | templates_path = ['_templates'] 47 | 48 | # The suffix(es) of source filenames. 49 | # You can specify multiple suffix as a list of string: 50 | # 51 | # source_suffix = ['.rst', '.md'] 52 | source_suffix = '.rst' 53 | 54 | # The master toctree document. 55 | master_doc = 'index' 56 | 57 | # The language for content autogenerated by Sphinx. Refer to documentation 58 | # for a list of supported languages. 59 | # 60 | # This is also used if you do content translation via gettext catalogs. 61 | # Usually you set "language" from the command line for these cases. 62 | language = None 63 | 64 | # List of patterns, relative to source directory, that match files and 65 | # directories to ignore when looking for source files. 66 | # This pattern also affects html_static_path and html_extra_path . 67 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 68 | 69 | # The name of the Pygments (syntax highlighting) style to use. 70 | pygments_style = 'sphinx' 71 | 72 | 73 | # -- Options for HTML output ------------------------------------------------- 74 | 75 | # The theme to use for HTML and HTML Help pages. See the documentation for 76 | # a list of builtin themes. 77 | # 78 | html_theme = 'sphinx_rtd_theme' 79 | 80 | # Theme options are theme-specific and customize the look and feel of a theme 81 | # further. For a list of options available for each theme, see the 82 | # documentation. 83 | # https://sphinx-rtd-theme.readthedocs.io/en/stable/configuring.html#theme-options 84 | html_theme_options = { 85 | # Use AdaCore blue in the Table Of Content 86 | "style_nav_header_background": "#12284c", 87 | } 88 | 89 | # The name of an image file (relative to this directory) to place at the top 90 | # of the sidebar. 91 | html_logo = "adacore-logo-white.png" 92 | 93 | # The name of an image file (within the static path) to use as favicon of the 94 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 95 | # pixels large. 96 | html_favicon = "favicon.ico" 97 | 98 | # Add any paths that contain custom static files (such as style sheets) here, 99 | # relative to this directory. They are copied after the builtin static files, 100 | # so a file named "default.css" will overwrite the builtin "default.css". 101 | html_theme_path = ['.'] 102 | html_static_path = ['_static'] 103 | 104 | # Custom sidebar templates, must be a dictionary that maps document names 105 | # to template names. 106 | # 107 | # The default sidebars (for documents that don't match any pattern) are 108 | # defined by theme itself. Builtin themes are using these templates by 109 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 110 | # 'searchbox.html']``. 111 | # 112 | # html_sidebars = {} 113 | 114 | 115 | # -- Options for HTMLHelp output --------------------------------------------- 116 | 117 | # Output file base name for HTML help builder. 118 | htmlhelp_basename = 'startup-gendoc' 119 | 120 | 121 | # -- Options for LaTeX output ------------------------------------------------ 122 | 123 | latex_elements = { 124 | # The paper size ('letterpaper' or 'a4paper'). 125 | # 126 | # 'papersize': 'letterpaper', 127 | 128 | # The font size ('10pt', '11pt' or '12pt'). 129 | # 130 | # 'pointsize': '10pt', 131 | 132 | # Additional stuff for the LaTeX preamble. 133 | # 134 | # 'preamble': '', 135 | 136 | # Latex figure (float) alignment 137 | # 138 | # 'figure_align': 'htbp', 139 | } 140 | 141 | # Grouping the document tree into LaTeX files. List of tuples 142 | # (source start file, target name, title, 143 | # author, documentclass [howto, manual, or own class]). 144 | latex_documents = [ 145 | (master_doc, 'startup-gen.tex', 'Startup-gen User\'s Guide', 146 | 'AdaCore', 'manual'), 147 | ] 148 | 149 | 150 | # -- Options for manual page output ------------------------------------------ 151 | 152 | # One entry per manual page. List of tuples 153 | # (source start file, name, description, authors, manual section). 154 | man_pages = [ 155 | (master_doc, 'startup-gen', 'startup-gen Documentation', 156 | [author], 1) 157 | ] 158 | 159 | 160 | # -- Options for Texinfo output ---------------------------------------------- 161 | 162 | # Grouping the document tree into Texinfo files. List of tuples 163 | # (source start file, target name, title, author, 164 | # dir menu entry, description, category) 165 | texinfo_documents = [ 166 | (master_doc, 'startup-gen', 'startup-gen Documentation', 167 | author, 'startup-gen', 'One line description of project.', 168 | 'Miscellaneous'), 169 | ] 170 | -------------------------------------------------------------------------------- /doc/source/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaCore/startup-gen/07391cc41a6c06a688e069878943a716b0226fbb/doc/source/favicon.ico -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Startup-gen User's Guide 3 | ======================== 4 | 5 | .. |startup-gen| replace:: ``startup-gen`` 6 | 7 | .. toctree:: 8 | 9 | 10 | About startup-gen 11 | ================= 12 | 13 | |startup-gen| generates startup files (crt0 and linker script) based on 14 | properties of the target device such as: architecture, memory layout, number of 15 | interrupts. 16 | 17 | One of the goals of this tool is to make it easier to start developing on 18 | micro-controllers by providing the basic elements of a Board Support Package 19 | (BSP). 20 | 21 | The target device properties are provided inside a GNAT Project file (see 22 | `Input format`_) and the output files are generated from templates in the 23 | `template-parser `_ format (see 24 | `Custom templates`_). 25 | 26 | Usage 27 | ===== 28 | 29 | To use |startup-gen| you need a GNAT Project file that contains the target 30 | device properties (see `Input format`_). 31 | 32 | Here is an example of project file: 33 | 34 | .. code-block:: ada 35 | 36 | project Spec is 37 | 38 | package Device_Configuration is 39 | 40 | for CPU_Name use "cortex-m4f"; 41 | for Number_Of_Interrupts use "25"; 42 | 43 | for Main_Stack_Size use ("4K"); 44 | 45 | for Memories use ("flash", "sram"); 46 | 47 | for Boot_Memory use "flash"; 48 | 49 | for Main_Stack_Memory use "sram"; 50 | for Main_Stack_Size use "8K"; 51 | 52 | -- flash 53 | for Mem_Kind ("flash") use "ROM"; 54 | for Address ("flash") use "16#08000000#"; 55 | for Size ("flash") use "1024K"; 56 | 57 | -- sram 58 | for Mem_Kind ("sram") use "RAM"; 59 | for Address ("sram") use "16#20000000#"; 60 | for Size ("sram") use "128K"; 61 | 62 | end Device_Configuration; 63 | 64 | end Spec; 65 | 66 | 67 | The following command line switches are available: 68 | 69 | * -l ARG Name of the generated linker script. 70 | * -s ARG Name of the generated startup code. 71 | * -X ARG Specify an external reference for Project Files. 72 | * -P ARG Name of the project file with the device configuration. 73 | * --print-tags Print the tags available in templates. 74 | 75 | Here is an example of |startup-gen| command: 76 | 77 | .. code-block:: bash 78 | 79 | $ startup-gen -P spec.gpr -l link.ld -s crt0.S 80 | 81 | This command will generate a linker script in the file ``link.ld`` and a crt0 82 | in the file ``crt0.S`` based on the target properties provided in ``spec.gpr``. 83 | 84 | 85 | The ``-P`` switch is required. The linker script and/or crt0 will be generated 86 | only if respectively the ``-l`` and/or ``-s`` switches are provided. 87 | 88 | Input format 89 | ============ 90 | 91 | The properties of the target device must be provided in a 92 | ``Device_Configuration`` package inside a GNAT Project file. 93 | 94 | Here are the attributes supported by |startup-gen|: 95 | 96 | Architecture and CPU 97 | -------------------- 98 | 99 | * ``for CPU_Name use ("");`` This attribute (optional if a supported 100 | run-time is defined) specifies the name of the target CPU. It is used, for 101 | instance, to determine the default templates that will be used for output 102 | generation. 103 | 104 | * ``for Float_Handling use "";`` This attribute is optional and 105 | specifies whether the floating point support is provided by the CPU/hardware 106 | (``hard``) or by the compiler/software (``soft``). It is used, for instance, 107 | to determine whether the Floating Point Unit (FPU) is initialized in the 108 | ``crt0``. Note that you can decide to not use hardware floating point even 109 | if the target device has an FPU. 110 | 111 | Memory 112 | ------ 113 | 114 | * ``for Memories use ();`` This attribute specifies the list 115 | of memory banks of the device, e.g. ``("flash", "sram", "dtcm")``. For each 116 | bank of this list, the ``Kind``, ``Address`` and ``Size`` attributes are 117 | **required**. 118 | 119 | * ``for Boot_Memory use "";`` This attribute specifies the memory 120 | bank from which the program will start. It can be a ROM bank if the program 121 | is written to a non-volatile memory such as flash, or a RAM bank if the 122 | program is loaded by a debugger or a bootloader. 123 | 124 | * ``for Mem_Kind () use "";`` This attribute specifies the 125 | kind of memory ````, either ``ROM`` (read-only) or ``RAM``. This 126 | attribute is used to determine what linker sections will be allocated to the 127 | bank. For instance a ``.data`` or ``.bss`` cannot be allocated in read-only 128 | memory. 129 | 130 | * ``for Address () use "";`` This attribute specifies the 131 | base address of the memory bank. ```` is a string containing an Ada or 132 | C numeric literal, e.g. ``16#08000000#`` or ``0x08000000``. 133 | 134 | * ``for Size () use "";`` This attribute specifies the size 135 | of the memory bank. ```` is a string containing a numeric literal. 136 | Multiplier suffix ``K`` and ``M`` are supported, e.g. ``16K``. 137 | 138 | * ``for Main_Stack_Size use "";`` This attribute specifies the size of 139 | the main program stack statically allocated in the linker script. The value 140 | is a string containing a numeric literal. Multiplier suffix ``K`` and ``M`` 141 | are supported, e.g. ``16K`` 142 | 143 | * ``for Main_Stack_Memory use "";`` This attribute specifies the 144 | memory bank where the the main program stack is statically allocated in the 145 | linker script. The bank must be a RAM bank. 146 | 147 | Interrupts 148 | ---------- 149 | 150 | * ``for Number_Of_Interrupts use "";`` This attribute specifies the 151 | number of interrupt lines on the device. The value is a string containing a 152 | numeric literal. Depending on the architecture, this value can be used to 153 | create a trap vector in the ``crt0``. 154 | 155 | * ``for Interrupt("") use "";`` This attribute specifies a name for 156 | an interrupt. ```` is a numeric literal representing the interrupt id 157 | (starts at zero). ```` is a string that will be used to declare 158 | assembly symbols for instance. Therefore the name must be a valid assembly 159 | symbol name. 160 | 161 | Templates 162 | --------- 163 | 164 | * ``for Startup_Template use "";`` This attribute specifies a path to a 165 | custom template file used to control startup (``crt0``) generation (see 166 | `Custom Templates`_). 167 | 168 | * ``for Linker_Template use "";`` This attribute specifies a path to a 169 | custom template file used to control linker script generation (see `Custom 170 | Templates`_). 171 | 172 | * ``for User_Tag ("") use "";`` This attribute specifies 173 | a user defined tag to be used in templates. It can be used control optional 174 | features in templates or provide extra values that are not generated by 175 | startup-gen. 176 | 177 | Advanced Topics 178 | =============== 179 | 180 | Scenario Variables 181 | ------------------ 182 | 183 | |startup-gen| supports the use of `scenario variables 184 | `_ 185 | in the input project file. 186 | 187 | These can be used in multiple ways, here are some examples: 188 | 189 | Select boot memory 190 | ^^^^^^^^^^^^^^^^^^ 191 | 192 | .. code-block:: ada 193 | 194 | project Prj is 195 | 196 | type Boot_Mem is ("flash", "sram"); 197 | Boot : Boot_Mem := external ("BOOT_MEM", "flash"); 198 | 199 | package Device_Configuration is 200 | 201 | for Memories use ("flash", "sram"); 202 | 203 | for Boot_Memory use Boot; 204 | 205 | -- [...] 206 | end Device_Configuration; 207 | end Prj; 208 | 209 | .. code-block:: bash 210 | 211 | $ startup-gen -P prj.gpr -l link.ld -s crt0.S -XBOOT_MEM=flash 212 | $ startup-gen -P prj.gpr -l link.ld -s crt0.S -XBOOT_MEM=sram 213 | 214 | Select boards with different device configuration 215 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 216 | .. code-block:: ada 217 | 218 | project Prj is 219 | 220 | type Board_Kind is ("dev_board", "production_board"); 221 | Board : Board_Kind := external ("BOARD", "dev_board"); 222 | 223 | package Device_Configuration is 224 | 225 | for Memories use ("flash", "sram"); 226 | 227 | case Board is 228 | when "dev_board" => 229 | for Size ("sram") use "256K"; 230 | when "production_board" => 231 | for Size ("sram") use "128K"; 232 | end case; 233 | 234 | -- [...] 235 | end Device_Configuration; 236 | end Prj; 237 | 238 | .. code-block:: bash 239 | 240 | $ startup-gen -P prj.gpr -l link.ld -s crt0.S -XBOARD=dev_board 241 | $ startup-gen -P prj.gpr -l link.ld -s crt0.S -XBOARD=production_board 242 | 243 | Custom Templates 244 | ---------------- 245 | 246 | You can provide your own templates for startup and linker script files using 247 | the ``Startup_Template`` and ``Linker_Template`` attributes (see `Templates`_). 248 | 249 | The output files are generated using the `template-parser 250 | `_ library, you can therefore 251 | refer to this `documentation 252 | `_ to 253 | write your templates. 254 | 255 | To see the list of predefined tags available for your templates, use the 256 | ``--print-tags`` command line switch. 257 | 258 | For instance: 259 | 260 | .. code-block:: bash 261 | 262 | $ startup-gen -P spec.gpr --print-tags 263 | --- Template tags --- 264 | BOOT_FROM_ROM => TRUE 265 | BOOT_MEM => ("flash") 266 | BOOT_MEM_ADDR => ("0x8000000") 267 | BOOT_MEM_SIZE => ("0x100000") 268 | MAIN_RAM => ("sram") 269 | MAIN_RAM_ADDR => ("0x20000000") 270 | MAIN_RAM_SIZE => ("0x20000") 271 | RAM_REGION => ("ccm") 272 | RAM_ADDR => ("0x10000000") 273 | RAM_SIZE => ("0x10000") 274 | ROM_REGION => () 275 | ROM_ADDR => () 276 | ROM_SIZE => () 277 | MAIN_STACK_SIZE => ("0x1000") 278 | MAIN_STACK_REGION => ("ccm") 279 | INTERRUPT_NAME => () 280 | INTERRUPT_ID => () 281 | --------------------- 282 | [...] 283 | 284 | Example of project using a generic Light Ada run-time and startup-gen 285 | =================================================================== 286 | 287 | For this example we will use STM32F4-Discovery development board from 288 | STmicroelectronics. The board is equipped with an ARM Cortex-M4F 289 | microcontroller. 290 | 291 | The sources of this example can be found in: 292 | `/share/examples/startup-gen/startup-gen-stm32f4` 293 | 294 | Board specifications 295 | ---------------------- 296 | 297 | To begin with we need to know the specification of the board and 298 | microcontroller. We will need: 299 | 300 | * The name of the CPU core architecture (ARM Cortex-M4F in our case) 301 | * Base address and size of memory banks (flash, RAM, etc.) 302 | * The number of interrupts 303 | 304 | You can get the information from the vendor documentation or product page. 305 | 306 | The project file 307 | ---------------- 308 | 309 | The project file will require some specific fields: 310 | 311 | * The list of languages must contain `ASM_CPP`, because we will compile the 312 | startup code (crt0) written in assembly language. 313 | * The run-time should be set to `light-cortex-m4f` because we are using an ARM 314 | Cortex-M4F microcontroller 315 | * The linker script must be specified as a linker option 316 | * The board specifications in a `Device_Configuration` 317 | 318 | Here is what the project file looks like: 319 | 320 | .. code-block:: ada 321 | 322 | project Hello is 323 | 324 | for Languages use ("Ada", "ASM_CPP"); -- ASM_CPP to compile the startup code 325 | for Source_Dirs use ("src"); 326 | for Object_Dir use "obj"; 327 | for Main use ("hello.adb"); 328 | 329 | for Target use "arm-eabi"; 330 | 331 | -- generic Light run-time compatible with our MCU 332 | for Runtime ("Ada") use "light-cortex-m4f"; 333 | 334 | package Linker is 335 | -- Linker script generated by startup-gen 336 | for Switches ("Ada") use ("-T", Project'Project_Dir & "/src/link.ld"); 337 | end Linker; 338 | 339 | package Device_Configuration is 340 | 341 | -- Name of the CPU core on the STM32F407 342 | for CPU_Name use "ARM Cortex-M4F"; 343 | 344 | for Float_Handling use "hard"; 345 | 346 | -- Number of interrupt lines on the STM32F407 347 | for Number_Of_Interrupts use "82"; 348 | 349 | -- List of memory banks on the STM32F407 350 | for Memories use ("SRAM", "FLASH", "CCM"); 351 | 352 | -- Specify from which memory bank the program will load 353 | for Boot_Memory use "FLASH"; 354 | 355 | -- Allocate the main stack in CCM with 8K size 356 | for Main_Stack_Memory use "CCM"; 357 | for Main_Stack_Size use "8K"; 358 | 359 | -- Specification of the SRAM 360 | for Mem_Kind ("SRAM") use "ram"; 361 | for Address ("SRAM") use "0x20000000"; 362 | for Size ("SRAM") use "128K"; 363 | 364 | -- Specification of the FLASH 365 | for Mem_Kind ("FLASH") use "rom"; 366 | for Address ("FLASH") use "0x08000000"; 367 | for Size ("FLASH") use "1024K"; 368 | 369 | -- Specification of the CCM RAM 370 | for Mem_Kind ("CCM") use "ram"; 371 | for Address ("CCM") use "0x10000000"; 372 | for Size ("CCM") use "64K"; 373 | 374 | end Device_Configuration; 375 | end Hello; 376 | 377 | Generate the linker script and startup-code with startup-gen 378 | ------------------------------------------------------------ 379 | 380 | Once the project file is ready we can use startup-gen to generate the linker 381 | script and startup code. 382 | 383 | To do this use the following command line: 384 | 385 | .. code-block:: bash 386 | 387 | $ startup-gen -P hello.gpr -l src/link.ld -s src/crt0.S 388 | 389 | This means that startup-gen will create a linker script in src/link.ld and a 390 | startup code in src/crt0.S 391 | 392 | Build 393 | ------- 394 | We can now build our project: 395 | 396 | .. code-block:: bash 397 | 398 | $ gprbuild -P hello.gpr 399 | 400 | You can also open this project in GNATstudio and build it from there. 401 | 402 | Running on the GNATemulator 403 | --------------------------- 404 | 405 | You can now run the example on GNATemulator: 406 | 407 | .. code-block:: bash 408 | 409 | $ arm-eabi-gnatemu --board=STM32F4 obj/hello 410 | -------------------------------------------------------------------------------- /doc/source/theme/static/adacore.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * nature.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- nature theme. 6 | * 7 | * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: Arial, sans-serif; 18 | font-size: 100%; 19 | background-color: #111; 20 | color: #555; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.documentwrapper { 26 | float: left; 27 | width: 100%; 28 | } 29 | 30 | div.bodywrapper { 31 | margin: 0 0 0 230px; 32 | } 33 | 34 | hr { 35 | border: 1px solid #B1B4B6; 36 | } 37 | 38 | div.document { 39 | background-color: #eee; 40 | } 41 | 42 | div.body { 43 | background-color: #ffffff; 44 | color: #3E4349; 45 | padding: 0 30px 30px 30px; 46 | font-size: 0.9em; 47 | } 48 | 49 | div.footer { 50 | color: #555; 51 | width: 100%; 52 | padding: 13px 0; 53 | text-align: center; 54 | font-size: 75%; 55 | } 56 | 57 | div.footer a { 58 | color: #444; 59 | text-decoration: underline; 60 | } 61 | 62 | div.related { 63 | background-color: #4A7697; 64 | line-height: 32px; 65 | color: #fff; 66 | font-size: 0.9em; 67 | } 68 | 69 | div.related a { 70 | color: #E2F3CC; 71 | } 72 | 73 | div.sphinxsidebar { 74 | font-size: 0.75em; 75 | line-height: 1.5em; 76 | } 77 | 78 | div.sphinxsidebarwrapper{ 79 | padding: 20px 0; 80 | } 81 | 82 | div.sphinxsidebar h3, 83 | div.sphinxsidebar h4 { 84 | font-family: Arial, sans-serif; 85 | color: #222; 86 | font-size: 1.2em; 87 | font-weight: normal; 88 | margin: 0; 89 | padding: 5px 10px; 90 | background-color: #ccc; 91 | text-shadow: 1px 1px 0 white 92 | } 93 | 94 | div.sphinxsidebar h4{ 95 | font-size: 1.1em; 96 | } 97 | 98 | div.sphinxsidebar h3 a { 99 | color: #444; 100 | } 101 | 102 | 103 | div.sphinxsidebar p { 104 | color: #888; 105 | padding: 5px 20px; 106 | } 107 | 108 | div.sphinxsidebar p.topless { 109 | } 110 | 111 | div.sphinxsidebar ul { 112 | margin: 10px 20px; 113 | padding: 0; 114 | color: #000; 115 | } 116 | 117 | div.sphinxsidebar a { 118 | color: #444; 119 | } 120 | 121 | div.sphinxsidebar input { 122 | border: 1px solid #ccc; 123 | font-family: sans-serif; 124 | font-size: 1em; 125 | } 126 | 127 | div.sphinxsidebar input[type=text]{ 128 | margin-left: 20px; 129 | } 130 | 131 | /* -- body styles ----------------------------------------------------------- */ 132 | 133 | a { 134 | color: #005B81; 135 | text-decoration: none; 136 | } 137 | 138 | a:hover { 139 | color: #E32E00; 140 | text-decoration: underline; 141 | } 142 | 143 | div.body h1, 144 | div.body h2, 145 | div.body h3, 146 | div.body h4, 147 | div.body h5, 148 | div.body h6 { 149 | font-family: Arial, sans-serif; 150 | background-color: #6A96B7; 151 | font-weight: normal; 152 | color: #212224; 153 | margin: 30px 0px 10px 0px; 154 | padding: 5px 0 5px 10px; 155 | } 156 | 157 | div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } 158 | div.body h2 { font-size: 150%; background-color: #C8D5E3; } 159 | div.body h3 { font-size: 120%; background-color: #D8DEE3; } 160 | div.body h4 { font-size: 110%; background-color: #D8DEE3; } 161 | div.body h5 { font-size: 100%; background-color: #D8DEE3; } 162 | div.body h6 { font-size: 100%; background-color: #D8DEE3; } 163 | 164 | a.headerlink { 165 | color: #c60f0f; 166 | font-size: 0.8em; 167 | padding: 0 4px 0 4px; 168 | text-decoration: none; 169 | } 170 | 171 | a.headerlink:hover { 172 | background-color: #c60f0f; 173 | color: white; 174 | } 175 | 176 | div.body p, div.body dd, div.body li { 177 | line-height: 1.5em; 178 | } 179 | 180 | div.admonition p.admonition-title + p { 181 | display: inline; 182 | } 183 | 184 | div.highlight{ 185 | background-color: white; 186 | } 187 | 188 | div.note { 189 | background-color: #eee; 190 | border: 1px solid #ccc; 191 | } 192 | 193 | div.seealso { 194 | background-color: #ffc; 195 | border: 1px solid #ff6; 196 | } 197 | 198 | div.topic { 199 | background-color: #eee; 200 | } 201 | 202 | div.warning { 203 | background-color: #ffe4e4; 204 | border: 1px solid #f66; 205 | } 206 | 207 | p.admonition-title { 208 | display: inline; 209 | } 210 | 211 | p.admonition-title:after { 212 | content: ":"; 213 | } 214 | 215 | pre { 216 | padding: 10px; 217 | background-color: #E4FFCB; 218 | color: #222; 219 | border: 1px solid #C6C9CB; 220 | font-size: 1.1em; 221 | } 222 | 223 | tt { 224 | background-color: #ecf0f3; 225 | color: #222; 226 | /* padding: 1px 2px; */ 227 | font-size: 1.1em; 228 | font-family: monospace; 229 | } 230 | 231 | .viewcode-back { 232 | font-family: Arial, sans-serif; 233 | } 234 | 235 | div.viewcode-block:target { 236 | background-color: #f4debf; 237 | border-top: 1px solid #ac9; 238 | border-bottom: 1px solid #ac9; 239 | } 240 | -------------------------------------------------------------------------------- /doc/source/theme/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = adacore.css 4 | pygments_style = sphinx 5 | -------------------------------------------------------------------------------- /share/examples/startup-gen/startup-gen-stm32f4/README.txt: -------------------------------------------------------------------------------- 1 | S T A R T U P - G E N - S T M 3 2 F 4 2 | ===================================== 3 | 4 | This simple example demonstrates the use of startup-gen and generic ZFP 5 | run-times for bare-board Ada applications. 6 | 7 | The example targets the SMT32F4-Discovery board and prints "Hello world!" using 8 | ARM semihosting. 9 | 10 | While targeting a specific developer board, the concept of generic ZFP 11 | run-times can be used on any ARM Cortex-M microcontroller. See the Startup-gen 12 | User's Guide Supplement for more information. 13 | 14 | Startup code 15 | ------------ 16 | 17 | Before building the example we have to generate the linker script and startup 18 | code base on the device configuration using the startup-gen tool: 19 | 20 | $ startup-gen -P hello.gpr -l src/link.ld -s src/crt0.S 21 | 22 | Build 23 | ----- 24 | 25 | We can then build the example: 26 | 27 | $ gprbuild -P hello.gpr 28 | 29 | Run 30 | --- 31 | 32 | And run it on GNATemulator for instance: 33 | 34 | $ arm-eabi-gnatemu --board=STM32F4 obj/hello 35 | 36 | Adaptation 37 | ---------- 38 | 39 | You can modify this example to work on your ARM Cortex-M target by changing the 40 | Device_Configuration and run-time in the project file. 41 | -------------------------------------------------------------------------------- /share/examples/startup-gen/startup-gen-stm32f4/hello.gpr: -------------------------------------------------------------------------------- 1 | project Hello is 2 | 3 | for Languages use ("Ada", "ASM_CPP"); -- ASM_CPP to compile the startup code 4 | for Source_Dirs use ("src"); 5 | for Object_Dir use "obj"; 6 | for Main use ("hello.adb"); 7 | 8 | for Target use "arm-eabi"; 9 | 10 | -- generic Light run-time compatible with our MCU 11 | for Runtime ("Ada") use "light-cortex-m4f"; 12 | 13 | package Linker is 14 | -- Linker script generated by startup-gen 15 | for Switches ("Ada") use ("-T", Project'Project_Dir & "/src/link.ld"); 16 | end Linker; 17 | 18 | package Device_Configuration is 19 | 20 | -- Name of the CPU core on the STM32F407 21 | for CPU_Name use "ARM Cortex-M4F"; 22 | 23 | for Float_Handling use "hard"; 24 | 25 | -- Number of interrupt lines on the STM32F407 26 | for Number_Of_Interrupts use "82"; 27 | 28 | -- List of memory banks on the STM32F407 29 | for Memories use ("SRAM", "FLASH", "CCM"); 30 | 31 | -- Specify from which memory bank the program will load 32 | for Boot_Memory use "FLASH"; 33 | 34 | -- Allocate the main stack in CCM with 8K size 35 | for Main_Stack_Memory use "CCM"; 36 | for Main_Stack_Size use "8K"; 37 | 38 | -- Specification of the SRAM 39 | for Mem_Kind ("SRAM") use "ram"; 40 | for Address ("SRAM") use "0x20000000"; 41 | for Size ("SRAM") use "128K"; 42 | 43 | -- Specification of the FLASH 44 | for Mem_Kind ("FLASH") use "rom"; 45 | for Address ("FLASH") use "0x08000000"; 46 | for Size ("FLASH") use "1024K"; 47 | 48 | -- Specification of the CCM RAM 49 | for Mem_Kind ("CCM") use "ram"; 50 | for Address ("CCM") use "0x10000000"; 51 | for Size ("CCM") use "64K"; 52 | 53 | end Device_Configuration; 54 | 55 | end Hello; 56 | -------------------------------------------------------------------------------- /share/examples/startup-gen/startup-gen-stm32f4/src/hello.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; 2 | 3 | procedure Hello is 4 | begin 5 | Ada.Text_IO.Put_Line ("Hello world!"); 6 | end Hello; 7 | -------------------------------------------------------------------------------- /share/startup-gen/resources/armvX-m.S.tmplt: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * * 3 | * Copyright (C) 2023 AdaCore * 4 | * * 5 | * GNAT is free software; you can redistribute it and/or modify it under * 6 | * terms of the GNU General Public License as published by the Free Soft- * 7 | * ware Foundation; either version 3, or (at your option) any later ver- * 8 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * 9 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * 10 | * or FITNESS FOR A PARTICULAR PURPOSE. * 11 | * * 12 | * As a special exception under Section 7 of GPL version 3, you are granted * 13 | * additional permissions described in the GCC Runtime Library Exception, * 14 | * version 3.1, as published by the Free Software Foundation. * 15 | * * 16 | * You should have received a copy of the GNU General Public License and * 17 | * a copy of the GCC Runtime Library Exception along with this program; * 18 | * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see * 19 | * . * 20 | * * 21 | *****************************************************************************/ 22 | 23 | .syntax unified 24 | 25 | #if defined(__SOFTFP__) 26 | .cpu cortex-m0 27 | #else 28 | /* FPU support means at least cortex-m4 compatibility */ 29 | .cpu cortex-m4 30 | #endif 31 | 32 | .thumb 33 | 34 | .text 35 | .globl __vectors 36 | .p2align 9 37 | .section .vectors,"a" 38 | __vectors: 39 | /* Cortex-M core interrupts */ 40 | .word __stack_end /* stack top address */ 41 | .word Reset_Handler /* 1 Reset */ 42 | .word NMI_Handler /* 2 NMI. */ 43 | .word HardFault_Handler /* 3 Hard fault. */ 44 | .word MemoryManagement_Handler /* 4 Mem manage. */ 45 | .word BusFault_Handler /* 5 Bus fault. */ 46 | .word UsageFault_Handler /* 6 Usage fault. */ 47 | .word Reserved_Handler /* 7 reserved. */ 48 | .word Reserved_Handler /* 8 reserved. */ 49 | .word Reserved_Handler /* 9 reserved. */ 50 | .word Reserved_Handler /* 10 reserved. */ 51 | .word SVC_Handler /* 11 SVCall. */ 52 | .word DebugMon_Handler /* 12 Breakpoint. */ 53 | .word Reserved_Handler /* 13 reserved. */ 54 | .word PendSV_Handler /* 14 PendSV. */ 55 | .word SysTick_Handler /* 15 Systick. */ 56 | /* MCU interrupts */ 57 | @@TABLE@@ 58 | .word __@_INTERRUPT_NAME_@_handler /* @_INTERRUPT_ID_@ */ 59 | @@END_TABLE@@ 60 | 61 | @@TABLE@@ 62 | @@IF@@ @_INTERRUPT_NAME_@ /= unknown_interrupt 63 | .weak __@_INTERRUPT_NAME_@_handler 64 | .thumb_set __@_INTERRUPT_NAME_@_handler,__common_int_handler 65 | @@END_IF@@ 66 | @@END_TABLE@@ 67 | 68 | .text 69 | 70 | .weak __unknown_interrupt_handler 71 | .thumb_set __unknown_interrupt_handler,__common_int_handler 72 | 73 | .macro weak_handler name 74 | .thumb_func 75 | .weak \name 76 | .type \name, %function 77 | \name: 78 | 0: b 0b 79 | .size \name, . - \name 80 | .endm 81 | 82 | weak_handler NMI_Handler 83 | weak_handler HardFault_Handler 84 | weak_handler MemoryManagement_Handler 85 | weak_handler BusFault_Handler 86 | weak_handler UsageFault_Handler 87 | weak_handler Reserved_Handler 88 | weak_handler SVC_Handler 89 | weak_handler DebugMon_Handler 90 | weak_handler PendSV_Handler 91 | weak_handler SysTick_Handler 92 | weak_handler __common_int_handler 93 | 94 | /*********/ 95 | /* .data */ 96 | /*********/ 97 | .section .data.argv 98 | argv_str: 99 | .ascii "main\0" 100 | 101 | .align 4 102 | argv: 103 | .word argv_str 104 | .word 0 105 | 106 | /*****************/ 107 | /* Reset_Handler */ 108 | /*****************/ 109 | 110 | .text 111 | .thumb_func 112 | .globl Reset_Handler 113 | 114 | Reset_Handler: 115 | 116 | /* Set the stack pointer */ 117 | ldr r1,=__stack_end 118 | mov sp, r1 119 | 120 | @@IF@@ @_BOOT_FROM_ROM_@ 121 | /* Copy .data */ 122 | .thumb_func 123 | _startup_copy_data: 124 | ldr r0,=__data_start 125 | ldr r1,=__data_words 126 | ldr r2,=__data_load 127 | cmp r1,#0 128 | beq 1f 129 | 0: ldr r4,[r2] 130 | str r4,[r0] 131 | adds r2,#4 132 | adds r0,#4 133 | subs r1,r1,#1 134 | bne 0b 135 | 1: 136 | .size _startup_copy_data, . - _startup_copy_data 137 | @@TABLE@@ 138 | 139 | /* Copy .@_RAM_REGION_@_data */ 140 | .thumb_func 141 | _startup_copy_@_RAM_REGION_@_data: 142 | ldr r0,=__@_RAM_REGION_@_data_start 143 | ldr r1,=__@_RAM_REGION_@_data_words 144 | ldr r2,=__@_RAM_REGION_@_data_load 145 | cmp r1,#0 146 | beq 1f 147 | 0: ldr r4,[r2] 148 | str r4,[r0] 149 | adds r2,#4 150 | adds r0,#4 151 | subs r1,r1,#1 152 | bne 0b 153 | 1: 154 | .size _startup_copy_@_RAM_REGION_@_data, . - _startup_copy_@_RAM_REGION_@_data 155 | @@END_TABLE@@ 156 | @@END_IF@@ 157 | 158 | /* Clear .bss */ 159 | .thumb_func 160 | _startup_clear_bss: 161 | ldr r0,=__bss_start 162 | ldr r1,=__bss_words 163 | movs r2,#0 164 | cmp r1,#0 165 | beq 1f 166 | 0: str r2,[r0] 167 | adds r0,#4 168 | subs r1,r1,#1 169 | bne 0b 170 | 1: 171 | .size _startup_clear_bss, . - _startup_clear_bss 172 | @@TABLE@@ 173 | 174 | /* Clear .@_RAM_REGION_@_bss */ 175 | .thumb_func 176 | _startup_clear_@_RAM_REGION_@_bss: 177 | ldr r0,=__@_RAM_REGION_@_bss_start 178 | ldr r1,=__@_RAM_REGION_@_bss_words 179 | movs r2,#0 180 | cmp r1,#0 181 | beq 1f 182 | 0: str r2,[r0] 183 | adds r0,#4 184 | subs r1,r1,#1 185 | bne 0b 186 | 1: 187 | .size _startup_clear_@_RAM_REGION_@_bss, . - _startup_clear_@_RAM_REGION_@_bss 188 | 189 | @@END_TABLE@@ 190 | 191 | #if !defined(__SOFTFP__) 192 | /**************/ 193 | /* Enable FPU */ 194 | /**************/ 195 | 196 | movw r0,#0xED88 197 | movt r0,#0xE000 198 | ldr r1,[r0] 199 | orr r1,r1,#(0xF << 20) 200 | str r1,[r0] 201 | 202 | dsb 203 | isb 204 | #endif 205 | 206 | /* Call static constructors */ 207 | .weak __libc_init_array 208 | ldr r5,=__libc_init_array 209 | cmp r5,#0 210 | beq .skip_libc_init 211 | blx r5 212 | .skip_libc_init: 213 | 214 | /* Call main, with argc, argv */ 215 | movs r0,#1 216 | ldr r1,=argv 217 | bl main 218 | 219 | /* Save main's return value */ 220 | mov r4, r0 221 | 222 | /* static destructors */ 223 | .weak __libc_fini_array 224 | ldr r5,=__libc_fini_array 225 | cmp r5,#0 226 | beq .skip_libc_fini 227 | blx r5 228 | .skip_libc_fini: 229 | 230 | /* Restore main's return value */ 231 | mov r0, r4 232 | 233 | bl _exit 234 | bl Reset_Handler 235 | .size Reserved_Handler, . - Reset_Handler 236 | -------------------------------------------------------------------------------- /share/startup-gen/resources/armvX-m.ld.tmplt: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * * 3 | * Copyright (C) 2023 AdaCore * 4 | * * 5 | * GNAT is free software; you can redistribute it and/or modify it under * 6 | * terms of the GNU General Public License as published by the Free Soft- * 7 | * ware Foundation; either version 3, or (at your option) any later ver- * 8 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * 9 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * 10 | * or FITNESS FOR A PARTICULAR PURPOSE. * 11 | * * 12 | * As a special exception under Section 7 of GPL version 3, you are granted * 13 | * additional permissions described in the GCC Runtime Library Exception, * 14 | * version 3.1, as published by the Free Software Foundation. * 15 | * * 16 | * You should have received a copy of the GNU General Public License and * 17 | * a copy of the GCC Runtime Library Exception along with this program; * 18 | * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see * 19 | * . * 20 | * * 21 | *****************************************************************************/ 22 | @@----------------------------------------------------------------------------- 23 | @@-- MACROS 24 | @@-- 25 | @@-- 26 | @@-- ALLOCATE_MAIN_STACK 27 | @@-- 28 | @@MACRO(ALLOCATE_MAIN_STACK)@@ 29 | __interrupt_stack_start = .; 30 | *(.interrupt_stacks) 31 | . = ALIGN(0x8); 32 | __interrupt_stack_end = .; 33 | 34 | __stack_start = .; 35 | . += DEFINED (__stack_size) ? __stack_size : _DEFAULT_STACK_SIZE; 36 | . = ALIGN(0x8); 37 | __stack_end = .; 38 | @@END_MACRO@@ 39 | @@-- 40 | @@-- 41 | @@-- CREATE_RAM_SECTIONS 42 | @@-- 43 | @@MACRO(CREATE_RAM_SECTIONS)@@ 44 | __@_$1_@_data_load = LOADADDR(.@_$1_@_data); 45 | .@_$1_@_data : 46 | { 47 | __@_$1_@_data_start = .; 48 | *(.@_$1_@_data .@_$1_@_data.*) 49 | 50 | /* Ensure that the end of the data section is always word aligned. 51 | Initial values are stored in 4-bytes blocks so we must guarantee 52 | that these blocks do not fall out the section (otherwise they are 53 | truncated and the initial data for the last block are lost). */ 54 | 55 | . = ALIGN(0x4); 56 | __@_$1_@_data_end = .; 57 | } > @_$1_@ AT> @_BOOT_MEM_@ 58 | __@_$1_@_data_words = (__@_$1_@_data_end - __@_$1_@_data_start) >> 2; 59 | 60 | .@_$1_@_bss (NOLOAD): { 61 | . = ALIGN(0x8); 62 | __@_$1_@_bss_start = .; 63 | 64 | *(.@_$1_@_bss .@_$1_@_bss.*) 65 | 66 | @@IF@@ @_MAIN_STACK_REGION_@ = @_$1_@ 67 | @_ALLOCATE_MAIN_STACK()_@ 68 | @@END_IF@@ 69 | 70 | __@_$1_@_bss_end = .; 71 | __@_$1_@_heap_start = .; 72 | __@_$1_@_heap_end = ORIGIN(@_$1_@) + LENGTH(@_$1_@); 73 | } > @_$1_@ 74 | __@_$1_@_bss_words = (__@_$1_@_bss_end - __@_$1_@_bss_start) >> 2; 75 | @@END_MACRO@@ 76 | @@-- 77 | @@-- 78 | @@-- CREATE_ROM_SECTIONS 79 | @@-- 80 | @@MACRO(CREATE_ROM_SECTIONS)@@ 81 | .@_$1_@_rodata : 82 | { 83 | __@_$1_@_rom_start = .; 84 | 85 | *(.@_$1_@_rodata .@_$1_@_rodata.*) 86 | . = ALIGN(0x4); 87 | __@_$1_@_rom_end = .; 88 | } > @_$1_@ 89 | @@END_MACRO@@ 90 | @@----------------------------------------------------------------------------- 91 | /* This is a ARM specific version of this file */ 92 | 93 | /* This script replaces ld's default linker script, providing the 94 | appropriate memory map and output format. */ 95 | 96 | SEARCH_DIR(.) 97 | __DYNAMIC = 0; 98 | 99 | _DEFAULT_STACK_SIZE = @_MAIN_STACK_SIZE_@; 100 | 101 | ENTRY(Reset_Handler); 102 | 103 | MEMORY 104 | { 105 | @@IF@@ @_BOOT_FROM_ROM_@ 106 | @_BOOT_MEM_@ (rx) : ORIGIN = @_BOOT_MEM_ADDR_@, LENGTH = @_BOOT_MEM_SIZE_@ 107 | @_MAIN_RAM_@ (rwx) : ORIGIN = @_MAIN_RAM_ADDR_@, LENGTH = @_MAIN_RAM_SIZE_@ 108 | @@ELSE@@ 109 | @_BOOT_MEM_@ (rwx) : ORIGIN = @_BOOT_MEM_ADDR_@, LENGTH = @_BOOT_MEM_SIZE_@ 110 | @@END_IF@@ 111 | @@TABLE@@ 112 | @_ROM_REGION_@ (rx) : ORIGIN = @_ROM_ADDR_@, LENGTH = @_ROM_SIZE_@ 113 | @@END_TABLE@@ 114 | @@TABLE@@ 115 | @_RAM_REGION_@ (rwx) : ORIGIN = @_RAM_ADDR_@, LENGTH = @_RAM_SIZE_@ 116 | @@END_TABLE@@ 117 | } 118 | 119 | /* 120 | * Boot memory (.text, .ro_data, interrupt vector): @_BOOT_MEM_@ 121 | * Main RAM memory (.data, .bss, stacks, interrupt stacks): @_BOOT_MEM_@ 122 | */ 123 | 124 | SECTIONS 125 | { 126 | 127 | @_C_COMMENT_BOX(2):BOOT_MEM_@ 128 | .text : 129 | { 130 | KEEP (*(.vectors)) 131 | *(.text .text.* .gnu.linkonce.t*) 132 | *(.gnu.warning) 133 | KEEP (*(.init)) 134 | KEEP (*(.fini)) 135 | } > @_BOOT_MEM_@ 136 | 137 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > @_BOOT_MEM_@ 138 | /* .ARM.exidx is 4-bytes aligned, so __exidx_start needs to be 139 | aligned too. Note that assigning the location counter also makes 140 | ld attach the following symbols to the next section (instead of the 141 | previous section which is the default), so will properly 142 | consider the location counter of .ARM.exidx for __exidx_start and 143 | __exidx_end and not the previous section's one. */ 144 | . = ALIGN(0x4); 145 | PROVIDE_HIDDEN (__exidx_start = .); 146 | .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > @_BOOT_MEM_@ 147 | PROVIDE_HIDDEN (__exidx_end = .); 148 | 149 | .preinit_array : 150 | { 151 | PROVIDE_HIDDEN (__preinit_array_start = .); 152 | KEEP (*(.preinit_array*)) 153 | PROVIDE_HIDDEN (__preinit_array_end = .); 154 | } > @_BOOT_MEM_@ 155 | 156 | .init_array : 157 | { 158 | PROVIDE_HIDDEN (__init_array_start = .); 159 | KEEP (*(SORT(.init_array.*))) 160 | KEEP (*(.init_array*)) 161 | PROVIDE_HIDDEN (__init_array_end = .); 162 | } > @_BOOT_MEM_@ 163 | 164 | .fini_array : 165 | { 166 | PROVIDE_HIDDEN (__fini_array_start = .); 167 | KEEP (*(SORT(.fini_array.*))) 168 | KEEP (*(.fini_array*)) 169 | PROVIDE_HIDDEN (__fini_array_end = .); 170 | } > @_BOOT_MEM_@ 171 | 172 | .rodata : 173 | { 174 | *(.lit) 175 | *(.rodata .rodata.* .gnu.linkonce.r*) 176 | . = ALIGN(0x4); 177 | __rom_end = .; 178 | } > @_BOOT_MEM_@ 179 | @_C_COMMENT_BOX(2/End of ):BOOT_MEM_@ 180 | 181 | @_C_COMMENT_BOX(2):MAIN_RAM_@ 182 | __data_load = LOADADDR(.data); 183 | .data : 184 | { 185 | __data_start = .; 186 | *(.data .data.* .gnu.linkonce.d*) 187 | 188 | /* Ensure that the end of the data section is always word aligned. 189 | Initial values are stored in 4-bytes blocks so we must guarantee 190 | that these blocks do not fall out the section (otherwise they are 191 | truncated and the initial data for the last block are lost). */ 192 | 193 | . = ALIGN(0x4); 194 | __data_end = .; 195 | } > @_MAIN_RAM_@ AT> @_BOOT_MEM_@ 196 | __data_words = (__data_end - __data_start) >> 2; 197 | 198 | .bss (NOLOAD): { 199 | . = ALIGN(0x8); 200 | __bss_start = .; 201 | 202 | *(.bss .bss.*) 203 | *(COMMON) 204 | 205 | . = ALIGN(0x8); /* Align the stack to 64 bits */ 206 | __bss_end = .; 207 | 208 | @@IF@@ @_MAIN_STACK_REGION_@ = @_MAIN_RAM_@ 209 | @_ALLOCATE_MAIN_STACK()_@ 210 | @@END_IF@@ 211 | 212 | _end = .; 213 | __heap_start = .; 214 | __heap_end = ORIGIN(@_MAIN_RAM_@) + LENGTH(@_MAIN_RAM_@); 215 | } > @_MAIN_RAM_@ 216 | __bss_words = (__bss_end - __bss_start) >> 2; 217 | @_C_COMMENT_BOX(2/End of ):MAIN_RAM_@ 218 | 219 | @@-- 220 | @@-- 221 | @@-- For all ROM regions besides BOOT_MEM 222 | @@-- 223 | @@IF@@ @_SIZE:ROM_REGION_@ > 0 224 | @@TABLE@@ 225 | @_C_COMMENT_BOX(2):ROM_REGION_@ 226 | @_CREATE_ROM_SECTIONS(@_ROM_REGION_@)_@ 227 | @_C_COMMENT_BOX(2/End of ):ROM_REGION_@ 228 | 229 | @@END_TABLE@@ 230 | @@END_IF@@ 231 | @@-- 232 | @@-- 233 | @@-- For all RAM regions besides main RAM 234 | @@-- 235 | @@IF@@ @_SIZE:RAM_REGION_@ > 0 236 | @@TABLE@@ 237 | @_C_COMMENT_BOX(2):RAM_REGION_@ 238 | @_CREATE_RAM_SECTIONS(@_RAM_REGION_@)_@ 239 | @_C_COMMENT_BOX(2/End of ):RAM_REGION_@ 240 | 241 | @@END_TABLE@@ 242 | @@END_IF@@ 243 | /* DWARF debug sections. 244 | Symbols in the DWARF debugging sections are relative to the beginning 245 | of the section so we begin them at 0. */ 246 | /* DWARF 1 */ 247 | .debug 0 : { *(.debug) } 248 | .line 0 : { *(.line) } 249 | /* GNU DWARF 1 extensions */ 250 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 251 | .debug_sfnames 0 : { *(.debug_sfnames) } 252 | /* DWARF 1.1 and DWARF 2 */ 253 | .debug_aranges 0 : { *(.debug_aranges) } 254 | .debug_pubnames 0 : { *(.debug_pubnames) } 255 | /* DWARF 2 */ 256 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 257 | .debug_abbrev 0 : { *(.debug_abbrev) } 258 | .debug_line 0 : { *(.debug_line) } 259 | .debug_frame 0 : { *(.debug_frame) } 260 | .debug_str 0 : { *(.debug_str) } 261 | .debug_loc 0 : { *(.debug_loc) } 262 | .debug_macinfo 0 : { *(.debug_macinfo) } 263 | /* DWARF 3 */ 264 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 265 | .debug_ranges 0 : { *(.debug_ranges) } 266 | .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } 267 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 268 | } 269 | -------------------------------------------------------------------------------- /share/startup-gen/resources/riscv.S.tmplt: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * * 3 | * Copyright (C) 2023 AdaCore * 4 | * * 5 | * GNAT is free software; you can redistribute it and/or modify it under * 6 | * terms of the GNU General Public License as published by the Free Soft- * 7 | * ware Foundation; either version 3, or (at your option) any later ver- * 8 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * 9 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * 10 | * or FITNESS FOR A PARTICULAR PURPOSE. * 11 | * * 12 | * As a special exception under Section 7 of GPL version 3, you are granted * 13 | * additional permissions described in the GCC Runtime Library Exception, * 14 | * version 3.1, as published by the Free Software Foundation. * 15 | * * 16 | * You should have received a copy of the GNU General Public License and * 17 | * a copy of the GCC Runtime Library Exception along with this program; * 18 | * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see * 19 | * . * 20 | * * 21 | *****************************************************************************/ 22 | 23 | /*********/ 24 | /* .data */ 25 | /*********/ 26 | .section .data.argv 27 | argv_str: 28 | .ascii "main\0" 29 | 30 | .align 4 31 | argv: 32 | .word argv_str 33 | .word 0 34 | 35 | /**********/ 36 | /* _start */ 37 | /**********/ 38 | 39 | .section .start 40 | .globl _start 41 | .type _start,@function 42 | 43 | _start: 44 | .option push 45 | .option norelax 46 | la gp, __global_pointer$ 47 | .option pop 48 | la sp, __stack_end 49 | 50 | @@-- 51 | @@-- This part of the template implements an infinite loop for all core with 52 | @@-- an ID different than the one provided. 53 | @@-- 54 | @@IF@@ @_EXIST:only_allow_hart_id_@ 55 | #ifdef __riscv_zicsr /* if CSR instructions are available */ 56 | li t0, @_only_allow_hart_id_@ /* hart id that will be allowed to run */ 57 | csrr t1, mhartid 58 | 1: bne t0, t1, 1b 59 | #endif 60 | @@END_IF@@ 61 | 62 | @@IF@@ @_BOOT_FROM_ROM_@ 63 | /* Load data section */ 64 | .type _startup_copy_data,@function 65 | _startup_copy_data: 66 | la a0, __data_load 67 | la a1, __data_start 68 | la a2, __data_end 69 | bgeu a1, a2, 2f 70 | 1: 71 | lw t0, (a0) 72 | sw t0, (a1) 73 | addi a0, a0, 4 74 | addi a1, a1, 4 75 | bltu a1, a2, 1b 76 | 2: 77 | .size _startup_copy_data, . - _startup_copy_data 78 | 79 | @@TABLE@@ 80 | 81 | /* Load .@_RAM_REGION_@_data section */ 82 | .type _startup_copy_@_RAM_REGION_@_data,@function 83 | _startup_copy_@_RAM_REGION_@_data: 84 | la a0, __@_RAM_REGION_@_data_load 85 | la a1, __@_RAM_REGION_@_data_start 86 | la a2, __@_RAM_REGION_@_data_end 87 | bgeu a1, a2, 2f 88 | 1: 89 | lw t0, (a0) 90 | sw t0, (a1) 91 | addi a0, a0, 4 92 | addi a1, a1, 4 93 | bltu a1, a2, 1b 94 | 2: 95 | .size _startup_copy_@_RAM_REGION_@_data, . - _startup_copy_@_RAM_REGION_@_data 96 | @@END_TABLE@@ 97 | @@END_IF@@ 98 | 99 | /* Clear bss section */ 100 | .type _startup_clear_bss,@function 101 | _startup_clear_bss: 102 | la a0, __bss_start 103 | la a1, __bss_end 104 | bgeu a0, a1, 2f 105 | 1: 106 | sw zero, (a0) 107 | addi a0, a0, 4 108 | bltu a0, a1, 1b 109 | 2: 110 | .size _startup_clear_bss, . - _startup_clear_bss 111 | @@TABLE@@ 112 | 113 | /* Clear .@_RAM_REGION_@_bss */ 114 | .type _startup_clear_@_RAM_REGION_@_bss,@function 115 | _startup_clear_@_RAM_REGION_@_bss: 116 | la a0, __@_RAM_REGION_@_bss_start 117 | la a1, __@_RAM_REGION_@_bss_end 118 | bgeu a0, a1, 2f 119 | 1: 120 | sw zero, (a0) 121 | addi a0, a0, 4 122 | bltu a0, a1, 1b 123 | 2: 124 | .size _startup_clear_@_RAM_REGION_@_bss, . - _startup_clear_@_RAM_REGION_@_bss 125 | 126 | @@END_TABLE@@ 127 | 128 | @@IF@@ @_FLOAT_HANDLING_@ = "HARD" 129 | #ifndef __riscv_f 130 | #error "floating-point instruction-set extension not enabled" 131 | #else 132 | /* Enable the FPU */ 133 | li t0, 0x00006000 134 | csrs mstatus, t0 135 | #endif 136 | @@END_IF@@ 137 | 138 | /* Call static constructors */ 139 | .weak __libc_init_array 140 | la t0, __libc_init_array 141 | beq t0, zero, .skip_libc_init 142 | jalr t0 143 | .skip_libc_init: 144 | 145 | /* Call main, with argc, argv */ 146 | la a0, 1 147 | la a1, argv 148 | call main 149 | 150 | /* Save main's return value */ 151 | mv t0, a0 152 | 153 | /* static destructors */ 154 | .weak __libc_fini_array 155 | la t0, __libc_fini_array 156 | beq t0, zero, .skip_libc_fini 157 | jalr t0 158 | .skip_libc_fini: 159 | 160 | /* Restore main's return value */ 161 | mv a0, t0 162 | 163 | call __gnat_exit 164 | 2: j 2b 165 | 166 | 167 | 168 | @@-- 169 | @@-- This part of the template implements an optional exit function for 170 | @@-- the HiFive1 emulation on QEMU. This is included for testing purposes. 171 | @@-- 172 | @@IF@@ @_EXIST:qemu_sifive_test_exit_@ 173 | 174 | .globl __gnat_exit 175 | .type __gnat_exit,@function 176 | .globl _abort 177 | .type abort,@function 178 | abort: 179 | __gnat_exit: 180 | /* Write to the SiFive Test device on QEMU to shutdown */ 181 | li t0, 0x5555 182 | li t1, 0x100000 183 | sw t0, (t1) 184 | 185 | j __gnat_exit 186 | 187 | /* Weak alias _exit to __gnat_exit */ 188 | .weak _exit 189 | .set _exit,__gnat_exit 190 | @@END_IF@@ 191 | 192 | @@-- 193 | @@-- This part of the template implements an optional exit function for 194 | @@-- the polarfire SOC emulation on QEMU. This is included for testing 195 | @@-- purposes. 196 | @@-- 197 | @@IF@@ @_EXIST:qemu_polarfire_test_exit_@ 198 | 199 | .globl __gnat_exit 200 | .type __gnat_exit,@function 201 | .globl _abort 202 | .type abort,@function 203 | abort: 204 | __gnat_exit: 205 | /* Write 0xDEAD to MSS_RESET_CR. */ 206 | li t0, 0x20002018 207 | li t1, 0xDEAD 208 | sw t1, (t0) 209 | 210 | j __gnat_exit 211 | 212 | /* Weak alias _exit to __gnat_exit */ 213 | .weak _exit 214 | .set _exit,__gnat_exit 215 | @@END_IF@@ 216 | 217 | @@-- 218 | @@-- This part of the template implements an optional putchar function for 219 | @@-- the polarfire SOC board on QEMU. This is included for testing purposes. 220 | @@-- 221 | @@IF@@ @_EXIST:polarfire_lsr_root_@ 222 | .globl putchar 223 | .type putchar,@function 224 | putchar: 225 | li t1, @_polarfire_lsr_root_@ 226 | 227 | .loop: 228 | lw t3, 0x14(t1) 229 | and t3, t3, 0b00100000 230 | beqz t3, .loop 231 | 232 | sb a0, 0(t1) 233 | ret 234 | @@END_IF@@ 235 | 236 | @@-- 237 | @@-- This part of the template implements an optional putchar function for 238 | @@-- the Hifive1 board on QEMU. This is included for testing purposes. 239 | @@-- 240 | @@IF@@ @_EXIST:hifive1_uart_root_@ 241 | .globl putchar 242 | .type putchar,@function 243 | putchar: 244 | li t1, @_hifive1_uart_root_@ 245 | li t1, 0x10013000 246 | li t2, 0x80000000 247 | .loop: 248 | lw t3, 0(t1) 249 | and t3, t3, t2 250 | bnez t3, .loop 251 | 252 | sb a0, 0(t1) 253 | ret 254 | @@END_IF@@ 255 | -------------------------------------------------------------------------------- /share/startup-gen/resources/riscv.ld.tmplt: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * * 3 | * Copyright (C) 2023 AdaCore * 4 | * * 5 | * GNAT is free software; you can redistribute it and/or modify it under * 6 | * terms of the GNU General Public License as published by the Free Soft- * 7 | * ware Foundation; either version 3, or (at your option) any later ver- * 8 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * 9 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * 10 | * or FITNESS FOR A PARTICULAR PURPOSE. * 11 | * * 12 | * As a special exception under Section 7 of GPL version 3, you are granted * 13 | * additional permissions described in the GCC Runtime Library Exception, * 14 | * version 3.1, as published by the Free Software Foundation. * 15 | * * 16 | * You should have received a copy of the GNU General Public License and * 17 | * a copy of the GCC Runtime Library Exception along with this program; * 18 | * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see * 19 | * . * 20 | * * 21 | *****************************************************************************/ 22 | 23 | @@----------------------------------------------------------------------------- 24 | @@-- MACROS 25 | @@-- 26 | @@-- 27 | @@-- ALLOCATE_MAIN_STACK 28 | @@-- 29 | @@MACRO(ALLOCATE_MAIN_STACK)@@ 30 | /* Interrupt stacks. Statically allocated in System.BB.Interrupts */ 31 | __interrupt_stack_start = .; 32 | *(.interrupt_stacks) 33 | . = ALIGN(0x10); /* Align stack to 128 bits as required in the ABI */ 34 | __interrupt_stack_end = .; 35 | 36 | __stack_start = .; 37 | . += DEFINED (__stack_size) ? __stack_size : _DEFAULT_STACK_SIZE; 38 | . = ALIGN(0x10); /* Align stack to 128 bits as required in the ABI */ 39 | __stack_end = .; 40 | @@END_MACRO@@ 41 | @@-- 42 | @@-- 43 | @@-- CREATE_RAM_SECTIONS 44 | @@-- 45 | @@MACRO(CREATE_RAM_SECTIONS)@@ 46 | __@_$1_@_data_load = LOADADDR(.@_$1_@_data); 47 | .@_$1_@_data : 48 | { 49 | __@_$1_@_data_start = .; 50 | *(.@_$1_@_data .@_$1_@_data.*) 51 | 52 | /* Ensure that the end of the data section is always word aligned. 53 | Initial values are stored in 4-bytes blocks so we must guarantee 54 | that these blocks do not fall out the section (otherwise they are 55 | truncated and the initial data for the last block are lost). */ 56 | 57 | . = ALIGN(0x4); 58 | __@_$1_@_data_end = .; 59 | } > @_$1_@ AT> @_BOOT_MEM_@ 60 | __@_$1_@_data_words = (__@_$1_@_data_end - __@_$1_@_data_start) >> 2; 61 | 62 | .@_$1_@_bss (NOLOAD): { 63 | . = ALIGN(0x8); 64 | __@_$1_@_bss_start = .; 65 | 66 | *(.@_$1_@_bss .@_$1_@_bss.*) 67 | @@IF@@ @_MAIN_STACK_REGION_@ = @_$1_@ 68 | @_ALLOCATE_MAIN_STACK()_@ 69 | @@END_IF@@ 70 | 71 | __@_$1_@_bss_end = .; 72 | __@_$1_@_heap_start = .; 73 | __@_$1_@_heap_end = ORIGIN(@_$1_@) + LENGTH(@_$1_@); 74 | } > @_$1_@ 75 | __@_$1_@_bss_words = (__@_$1_@_bss_end - __@_$1_@_bss_start) >> 2; 76 | @@END_MACRO@@ 77 | @@-- 78 | @@-- 79 | @@-- CREATE_ROM_SECTIONS 80 | @@-- 81 | @@MACRO(CREATE_ROM_SECTIONS)@@ 82 | .@_$1_@_rodata : 83 | { 84 | __@_$1_@_rom_start = .; 85 | 86 | *(.@_$1_@rdata) 87 | *(.@_$1_@_rodata .@_$1_@_rodata.*) 88 | . = ALIGN(0x4); 89 | __@_$1_@_rom_end = .; 90 | } > @_$1_@ 91 | @@END_MACRO@@ 92 | @@----------------------------------------------------------------------------- 93 | 94 | /* This is a RISC-V specific version of this file */ 95 | 96 | _DEFAULT_STACK_SIZE = @_MAIN_STACK_SIZE_@; 97 | 98 | OUTPUT_ARCH("riscv") 99 | 100 | ENTRY(_start); 101 | 102 | MEMORY 103 | { 104 | @@IF@@ @_BOOT_FROM_ROM_@ 105 | @_BOOT_MEM_@ (rx) : ORIGIN = @_BOOT_MEM_ADDR_@, LENGTH = @_BOOT_MEM_SIZE_@ 106 | @_MAIN_RAM_@ (rwx) : ORIGIN = @_MAIN_RAM_ADDR_@, LENGTH = @_MAIN_RAM_SIZE_@ 107 | @@ELSE@@ 108 | @_BOOT_MEM_@ (rwx) : ORIGIN = @_BOOT_MEM_ADDR_@, LENGTH = @_BOOT_MEM_SIZE_@ 109 | @@END_IF@@ 110 | @@TABLE@@ 111 | @_ROM_REGION_@ (rx) : ORIGIN = @_ROM_ADDR_@, LENGTH = @_ROM_SIZE_@ 112 | @@END_TABLE@@ 113 | @@TABLE@@ 114 | @_RAM_REGION_@ (rwx) : ORIGIN = @_RAM_ADDR_@, LENGTH = @_RAM_SIZE_@ 115 | @@END_TABLE@@ 116 | } 117 | 118 | SECTIONS 119 | { 120 | @_C_COMMENT_BOX(2):BOOT_MEM_@ 121 | .text : 122 | { 123 | KEEP (*(SORT_NONE(.start))) 124 | *(.text .text.* .gnu.linkonce.t*) 125 | *(.gnu.warning) 126 | KEEP (*(.init)) 127 | KEEP (*(.fini)) 128 | } > @_BOOT_MEM_@ 129 | 130 | .eh_frame_hdr : 131 | { 132 | *(.eh_frame_hdr) 133 | } > @_BOOT_MEM_@ 134 | 135 | .eh_frame : 136 | { 137 | __EH_FRAME__ = .; 138 | KEEP(*(.eh_frame)) 139 | LONG(0); 140 | } > @_BOOT_MEM_@ 141 | 142 | .gcc_except_table : 143 | { 144 | *(.gcc_except_table .gcc_except_table.*) 145 | } > @_BOOT_MEM_@ 146 | 147 | .init_array : 148 | { 149 | PROVIDE_HIDDEN (__init_array_start = .); 150 | KEEP (*(SORT(.init_array.*))) 151 | KEEP (*(.init_array*)) 152 | PROVIDE_HIDDEN (__init_array_end = .); 153 | } > @_BOOT_MEM_@ 154 | 155 | .fini_array : 156 | { 157 | PROVIDE_HIDDEN (__fini_array_start = .); 158 | KEEP (*(SORT(.fini_array.*))) 159 | KEEP (*(.fini_array*)) 160 | PROVIDE_HIDDEN (__fini_array_end = .); 161 | } > @_BOOT_MEM_@ 162 | 163 | .rodata : 164 | { 165 | *(.rdata) 166 | *(.rodata .rodata.* .gnu.linkonce.r*) 167 | . = ALIGN(0x4); 168 | __rom_end = .; 169 | } > @_BOOT_MEM_@ 170 | @_C_COMMENT_BOX(2/End of ):BOOT_MEM_@ 171 | 172 | @_C_COMMENT_BOX(2):MAIN_RAM_@ 173 | .data : 174 | { 175 | __data_start = .; 176 | *(.data .data.* .gnu.linkonce.d*) 177 | } > @_MAIN_RAM_@ AT > @_BOOT_MEM_@ 178 | 179 | .srodata ALIGN(4) : ALIGN(4) /* Align both virtual and load addresses */ 180 | { 181 | PROVIDE( __global_pointer$ = . + 0x800 ); 182 | *(.srodata.cst16) 183 | *(.srodata.cst8) 184 | *(.srodata.cst4) 185 | *(.srodata.cst2) 186 | *(.srodata .srodata.*) 187 | } > @_MAIN_RAM_@ AT > @_BOOT_MEM_@ 188 | 189 | .sdata ALIGN(4) : ALIGN(4) /* Align both virtual and load addresses */ 190 | { 191 | *(.sdata .sdata.*) 192 | *(.gnu.linkonce.s.*) 193 | } > @_MAIN_RAM_@ AT > @_BOOT_MEM_@ 194 | 195 | __data_end = .; 196 | 197 | /* Size of all data sections (.data, .srodata, .sdata) in number of 32bit 198 | * words. 199 | */ 200 | __data_words = (__data_end - __data_start) >> 2; 201 | 202 | /* Base address of all data sections in ROM. The startup code copies these 203 | * sections from __data_load (in ROM) to __data_start (in RAM). 204 | */ 205 | __data_load = LOADADDR(.data); 206 | 207 | .bss (NOLOAD): { 208 | . = ALIGN(0x8); 209 | __bss_start = .; 210 | 211 | *(.sbss*) 212 | *(.gnu.linkonce.sb.*) 213 | *(.bss .bss.*) 214 | *(.gnu.linkonce.b.*) 215 | *(COMMON) 216 | 217 | @@IF@@ @_MAIN_STACK_REGION_@ = @_MAIN_RAM_@ 218 | @_ALLOCATE_MAIN_STACK()_@ 219 | @@END_IF@@ 220 | 221 | _end = .; 222 | __heap_start = .; 223 | __heap_end = ORIGIN(@_MAIN_RAM_@) + LENGTH(@_MAIN_RAM_@); 224 | __bss_end = .; 225 | } > @_MAIN_RAM_@ 226 | __bss_words = (__bss_end - __bss_start) >> 2; 227 | @_C_COMMENT_BOX(2/End of ):MAIN_RAM_@ 228 | 229 | @@-- 230 | @@-- 231 | @@-- For all ROM regions besides BOOT_MEM 232 | @@-- 233 | @@IF@@ @_SIZE:ROM_REGION_@ > 0 234 | @@TABLE@@ 235 | @_C_COMMENT_BOX(2):ROM_REGION_@ 236 | @_CREATE_ROM_SECTIONS(@_ROM_REGION_@)_@ 237 | @_C_COMMENT_BOX(2/End of ):ROM_REGION_@ 238 | 239 | @@END_TABLE@@ 240 | @@END_IF@@ 241 | @@-- 242 | @@-- 243 | @@-- For all RAM regions besides main RAM 244 | @@-- 245 | @@IF@@ @_SIZE:RAM_REGION_@ > 0 246 | @@TABLE@@ 247 | @_C_COMMENT_BOX(2):RAM_REGION_@ 248 | @_CREATE_RAM_SECTIONS(@_RAM_REGION_@)_@ 249 | @_C_COMMENT_BOX(2/End of ):RAM_REGION_@ 250 | 251 | @@END_TABLE@@ 252 | @@END_IF@@ 253 | /* DWARF debug sections. 254 | Symbols in the DWARF debugging sections are relative to the beginning 255 | of the section so we begin them at 0. */ 256 | /* DWARF 1 */ 257 | .debug 0 : { *(.debug) } 258 | .line 0 : { *(.line) } 259 | /* GNU DWARF 1 extensions */ 260 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 261 | .debug_sfnames 0 : { *(.debug_sfnames) } 262 | /* DWARF 1.1 and DWARF 2 */ 263 | .debug_aranges 0 : { *(.debug_aranges) } 264 | .debug_pubnames 0 : { *(.debug_pubnames) } 265 | /* DWARF 2 */ 266 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 267 | .debug_abbrev 0 : { *(.debug_abbrev) } 268 | .debug_line 0 : { *(.debug_line) } 269 | .debug_frame 0 : { *(.debug_frame) } 270 | .debug_str 0 : { *(.debug_str) } 271 | .debug_loc 0 : { *(.debug_loc) } 272 | .debug_macinfo 0 : { *(.debug_macinfo) } 273 | /* DWARF 3 */ 274 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 275 | .debug_ranges 0 : { *(.debug_ranges) } 276 | .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } 277 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 278 | } 279 | -------------------------------------------------------------------------------- /src/device.adb: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019-2021, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with Ada.Text_IO; use Ada.Text_IO; 20 | with Ada.Strings.Fixed; 21 | with Interfaces; use Interfaces; 22 | 23 | with GNAT.Regpat; 24 | with GNAT.Strings; 25 | 26 | with GNATCOLL.Utils; 27 | with GNATCOLL.VFS; use GNATCOLL.VFS; 28 | 29 | with Templates_Parser.Query; 30 | with Templates_Parser.Utils; 31 | 32 | with Utils; use Utils; 33 | with Number_Input; use Number_Input; 34 | 35 | package body Device is 36 | 37 | use type GNAT.Strings.String_List_Access; 38 | 39 | package Tmplt renames Templates_Parser; 40 | 41 | function To_Number_Of_Interrupt (Str : String) return Natural; 42 | function Resources_Base_Directory return String; 43 | function Arch_From_CPU (CPU_Name : String) return String; 44 | function Arch_From_Runtime (Runtime_Name : String) return String; 45 | function C_Comment_Box_Filter 46 | (Value : String; 47 | Parameters : String; 48 | Context : Templates_Parser.Filter_Context) 49 | return String; 50 | 51 | ------------- 52 | -- Convert -- 53 | ------------- 54 | 55 | function Convert (Str : String) return Float_Type is 56 | begin 57 | return Float_Type'Value (Str); 58 | exception 59 | when Constraint_Error => return Soft; 60 | end Convert; 61 | 62 | ---------------------------- 63 | -- To_Number_Of_Interrupt -- 64 | ---------------------------- 65 | 66 | function To_Number_Of_Interrupt (Str : String) return Natural is 67 | begin 68 | return Natural'Value (Str); 69 | exception 70 | when Constraint_Error => return 0; 71 | end To_Number_Of_Interrupt; 72 | 73 | ------------------------------ 74 | -- Resources_Base_Directory -- 75 | ------------------------------ 76 | 77 | function Resources_Base_Directory return String is 78 | Exec_Loc : constant String := GNATCOLL.Utils.Executable_Location; 79 | begin 80 | return GNATCOLL.Utils.Join_Path 81 | (Exec_Loc, "share", "startup-gen", "resources"); 82 | end Resources_Base_Directory; 83 | 84 | ------------------- 85 | -- Arch_From_CPU -- 86 | ------------------- 87 | 88 | function Arch_From_CPU (CPU_Name : String) return String is 89 | 90 | function Match (Pattern : String) return Boolean 91 | is (GNAT.Regpat.Match (GNAT.Regpat.Compile 92 | (Pattern, 93 | GNAT.Regpat.Case_Insensitive), 94 | CPU_Name)); 95 | 96 | begin 97 | if CPU_Name = "" then 98 | return ""; 99 | end if; 100 | 101 | if Match ("^(arm)?\s*cortex-m(0(\+|plus|p)?|1)$") then 102 | return "armv6-m"; 103 | elsif Match ("^(arm)?\s*cortex-m3$") then 104 | return "armv7-m"; 105 | elsif Match ("^(arm)?\s*cortex-m(4|7)(f|d|fd)?$") then 106 | return "armv7e-m"; 107 | elsif Match ("^(arm)?\s*cortex-m(23|33)(f|d|fd)?$") then 108 | return "armv8-m"; 109 | elsif Match ("^(riscv|risc-v|rv)(32|64|128)?$") then 110 | return "risc-v"; 111 | end if; 112 | 113 | Fatal_Error ("Unknown CPU name: '" & CPU_Name & "'"); 114 | end Arch_From_CPU; 115 | 116 | function Arch_From_Runtime (Runtime_Name : String) return String is 117 | 118 | function Match (Pattern : String) return Boolean 119 | is (GNAT.Regpat.Match (GNAT.Regpat.Compile 120 | (Pattern, 121 | GNAT.Regpat.Case_Insensitive), 122 | Runtime_Name)); 123 | 124 | begin 125 | if Runtime_Name = "" then 126 | return ""; 127 | end if; 128 | 129 | if Match ("^(light|zfp)-cortex-m(0(\+|plus|p)?|1)$") then 130 | return "armv6-m"; 131 | elsif Match ("^(light|zfp)-cortex-m3$") then 132 | return "armv7-m"; 133 | elsif Match ("^(light|zfp)-cortex-m(4|7)(f|d|fd)?$") then 134 | return "armv7e-m"; 135 | elsif Match ("^(light|zfp)-cortex-m(23|33)(f|d|fd)?$") then 136 | return "armv8-m"; 137 | elsif Match ("^(light|zfp)-(riscv|risc-v|rv)(32|64|128)?[imafdgqlcjtpvnh]*$") then 138 | return "risc-v"; 139 | end if; 140 | 141 | Warning ("Unknown run-time name: '" & Runtime_Name & "'"); 142 | return ""; 143 | end Arch_From_Runtime; 144 | 145 | ---------------------------------- 146 | -- Get_Memory_List_From_Project -- 147 | ---------------------------------- 148 | 149 | procedure Get_Memory_List_From_Project 150 | (Self : in out Spec; 151 | Spec_Project : Project_Type) 152 | is 153 | use Memory_Region_Vectors; 154 | 155 | Memory_List : constant Attribute_Pkg_List := 156 | Build (Prj_Package_Name, "memories"); 157 | Size_Table : constant Attribute_Pkg_String := 158 | Build (Prj_Package_Name, "Size"); 159 | Address_Table : constant Attribute_Pkg_String := 160 | Build (Prj_Package_Name, "Address"); 161 | Kind_Table : constant Attribute_Pkg_String := 162 | Build (Prj_Package_Name, "mem_kind"); 163 | 164 | Memories : constant GNAT.Strings.String_List_Access := 165 | Spec_Project.Attribute_Value (Memory_List); 166 | begin 167 | if Memories = null then 168 | Put_Line ("No memory delcared"); 169 | else 170 | for Memory of Memories.all loop 171 | declare 172 | Size : constant String := 173 | Spec_Project.Attribute_Value 174 | (Size_Table, Index => Memory.all); 175 | 176 | Address : constant String := 177 | Spec_Project.Attribute_Value 178 | (Address_Table, Index => Memory.all); 179 | 180 | Kind_Str : constant String := 181 | Spec_Project.Attribute_Value 182 | (Kind_Table, Index => Memory.all); 183 | 184 | begin 185 | 186 | if Size = "" then 187 | Fatal_Error 188 | ("Missing Size for memory: '" & Memory.all & "'"); 189 | elsif Address = "" then 190 | Fatal_Error 191 | ("Missing Address for memory: '" & Memory.all & "'"); 192 | elsif Kind_Str = "" then 193 | Fatal_Error 194 | ("Missing Kind for memory: '" & Memory.all & "'"); 195 | end if; 196 | 197 | begin 198 | declare 199 | Kind : constant Memory_Kind := 200 | Memory_Kind'Value (Kind_Str); 201 | begin 202 | Self.Memory := Self.Memory & 203 | (Name => To_Unbounded_String (Memory.all), 204 | Address => To_Unbounded_String (Address), 205 | Size => To_Unbounded_String (Size), 206 | Kind => Kind); 207 | end; 208 | exception 209 | when Constraint_Error => 210 | Fatal_Error ("Invalid memory kind: '" & Kind_Str & "'"); 211 | end; 212 | end; 213 | end loop; 214 | end if; 215 | end Get_Memory_List_From_Project; 216 | 217 | --------------------------------------- 218 | -- Get_Interrupt_Vector_From_Project -- 219 | --------------------------------------- 220 | 221 | procedure Get_Interrupt_Vector_From_Project 222 | (Self : in out Spec; 223 | Spec_Project : Project_Type) 224 | is 225 | Interrupts : constant Attribute_Pkg_String := 226 | Build 227 | (Package_Name => Prj_Package_Name, 228 | Attribute_Name => "Interrupt"); 229 | 230 | Interrupt_List : GNAT.Strings.String_List := 231 | Spec_Project.Attribute_Indexes (Interrupts); 232 | begin 233 | for Interrupt of Interrupt_List loop 234 | declare 235 | Name : constant String := 236 | Spec_Project.Attribute_Value 237 | (Attribute => Interrupts, 238 | Index => Interrupt.all); 239 | 240 | Interrupt_Index : constant Integer := 241 | Integer'Value (Interrupt.all); 242 | begin 243 | if Self.Interrupts.Is_Index_Used (Interrupt_Index) then 244 | -- Key already present, there is a problem in the 245 | -- project file describing the interrupt vector. 246 | raise Name_Error 247 | with "Interrupt nb " & Interrupt.all & 248 | " is already present in the interrupt vector."; 249 | else 250 | Self.Interrupts.Add_Interrupt 251 | (Interrupt_Index, To_Unbounded_String (Name)); 252 | end if; 253 | end; 254 | end loop; 255 | GNATCOLL.Utils.Free (Interrupt_List); 256 | end Get_Interrupt_Vector_From_Project; 257 | 258 | ---------------------------------- 259 | -- Get_Boot_Memory_From_Project -- 260 | ---------------------------------- 261 | 262 | procedure Get_Boot_Memory_From_Project 263 | (Self : in out Spec; 264 | Spec_Project : Project_Type) 265 | is 266 | Boot_Mem : constant String := Spec_Project.Attribute_Value 267 | (Build (Prj_Package_Name, "Boot_Memory")); 268 | begin 269 | Self.Boot_Memory := To_Unbounded_String (Boot_Mem); 270 | 271 | if Self.Boot_Memory = "" then 272 | Fatal_Error ("No boot memory specified"); 273 | end if; 274 | end Get_Boot_Memory_From_Project; 275 | 276 | -------------------------- 277 | -- Get_CPU_From_Project -- 278 | -------------------------- 279 | 280 | procedure Get_CPU_From_Project 281 | (Self : in out Spec; 282 | Spec_Project : Project_Type) 283 | is 284 | Name : constant Unbounded_String := 285 | To_Unbounded_String 286 | (Spec_Project.Attribute_Value (Build (Prj_Package_Name, 287 | "cpu_name"))); 288 | 289 | CPU_Arch : constant String := Arch_From_CPU (To_String (Name)); 290 | 291 | RTS_Arch : constant String := Arch_From_Runtime 292 | (Spec_Project.Get_Runtime); 293 | 294 | Arch : Unbounded_String; 295 | 296 | Float_Handling : constant String := 297 | Spec_Project.Attribute_Value (Build (Prj_Package_Name, 298 | "float_handling")); 299 | 300 | Number_Of_Interrupts : constant String := 301 | Spec_Project.Attribute_Value (Build (Prj_Package_Name, 302 | "number_of_interrupts")); 303 | 304 | Main_Stack_Size : constant String := 305 | Spec_Project.Attribute_Value (Build (Prj_Package_Name, 306 | "main_stack_size")); 307 | 308 | Main_Stack_Memory : constant String := 309 | Spec_Project.Attribute_Value (Build (Prj_Package_Name, 310 | "main_stack_memory")); 311 | 312 | Linker_Template : constant String := 313 | Spec_Project.Attribute_Value (Build (Prj_Package_Name, 314 | "linker_template")); 315 | Startup_Template : constant String := 316 | Spec_Project.Attribute_Value (Build (Prj_Package_Name, 317 | "startup_template")); 318 | begin 319 | 320 | if RTS_Arch = "" then 321 | if CPU_Arch /= "" then 322 | Arch := To_Unbounded_String (CPU_Arch); 323 | else 324 | Fatal_Error 325 | ("Unknown CPU, please specify CPU_Name or Rumtime attribute"); 326 | end if; 327 | else 328 | if CPU_Arch = "" or else CPU_Arch = RTS_Arch then 329 | Arch := To_Unbounded_String (RTS_Arch); 330 | else 331 | Fatal_Error 332 | ("Mismatch between CPU_Name (" & To_String (Name) & 333 | ") and run-time (" & Spec_Project.Get_Runtime & 334 | ") attributes"); 335 | end if; 336 | end if; 337 | 338 | Self.CPU := 339 | (Name => Name, 340 | Float_Handling => Convert (Float_Handling), 341 | Number_Of_Interrupts => To_Number_Of_Interrupt (Number_Of_Interrupts), 342 | Arch => Arch); 343 | 344 | if Main_Stack_Size /= "" then 345 | Self.Main_Stack_Size := To_Unbounded_String (Main_Stack_Size); 346 | else 347 | Self.Main_Stack_Size := To_Unbounded_String ("0x1000"); 348 | end if; 349 | 350 | if Main_Stack_Memory /= "" then 351 | Self.Main_Stack_Memory := To_Unbounded_String (Main_Stack_Memory); 352 | end if; 353 | 354 | if Linker_Template /= "" then 355 | Self.Linker_Template := To_Unbounded_String (Linker_Template); 356 | else 357 | Self.Linker_Template := 358 | To_Unbounded_String (Self.Default_Linker_Template); 359 | end if; 360 | 361 | if Startup_Template /= "" then 362 | Self.Startup_Template := To_Unbounded_String (Startup_Template); 363 | else 364 | Self.Startup_Template 365 | := To_Unbounded_String (Self.Default_Startup_Template); 366 | end if; 367 | 368 | end Get_CPU_From_Project; 369 | 370 | -------------------------------- 371 | -- Get_User_Tags_From_Project -- 372 | -------------------------------- 373 | 374 | procedure Get_User_Tags_From_Project 375 | (Self : in out Spec; 376 | Spec_Project : Project_Type) 377 | is 378 | User_Tags : constant Attribute_Pkg_String := 379 | Build (Package_Name => Prj_Package_Name, 380 | Attribute_Name => "user_tag"); 381 | 382 | User_Tag_List : GNAT.Strings.String_List := 383 | Spec_Project.Attribute_Indexes (User_Tags); 384 | begin 385 | 386 | for Tag of User_Tag_List loop 387 | declare 388 | Name : constant String := 389 | Spec_Project.Attribute_Value 390 | (Attribute => User_Tags, 391 | Index => Tag.all); 392 | begin 393 | if Self.User_Tags.Contains (To_Unbounded_String (Tag.all)) then 394 | Fatal_Error ("User tag '" & Tag.all & "' already defined"); 395 | else 396 | Self.User_Tags.Insert (To_Unbounded_String (Tag.all), 397 | To_Unbounded_String (Name)); 398 | end if; 399 | end; 400 | end loop; 401 | GNATCOLL.Utils.Free (User_Tag_List); 402 | end Get_User_Tags_From_Project; 403 | 404 | ----------- 405 | -- Valid -- 406 | ----------- 407 | 408 | function Valid (Self : in out Spec) return Boolean is 409 | begin 410 | -- NOTE: In the case where we have 2 interrupts with the same 411 | -- attribute number, we will see only the last one due to how 412 | -- GNATCOLL handles indexed values. 413 | return Self.Valid_Input and then Self.Valid_Memory_Regions; 414 | end Valid; 415 | 416 | ------------- 417 | -- Display -- 418 | ------------- 419 | 420 | procedure Display (Self : in out Spec) is 421 | begin 422 | Put_Line ("CPU: " & To_String (Self.CPU.Name)); 423 | Put_Line 424 | ("Float_Handling: " & Float_Type'Image (Self.CPU.Float_Handling)); 425 | for Memory of Self.Memory loop 426 | Put_Line ("Name : " & To_String (Memory.Name)); 427 | Put_Line ("Address : " & To_String (Memory.Address)); 428 | Put_Line ("Size : " & To_String (Memory.Size)); 429 | Put_Line ("Kind : " & Memory_Kind'Image (Memory.Kind)); 430 | end loop; 431 | end Display; 432 | 433 | ------------------------ 434 | -- Dump_Linker_Script -- 435 | ------------------------ 436 | 437 | procedure Dump_Linker_Script (Self : in out Spec; Filename : String) 438 | is 439 | Translations : constant Tmplt.Translate_Table := Self.To_Translate_Table; 440 | Template : constant String := To_String (Self.Linker_Template); 441 | Output : constant String := Tmplt.Parse (Template, Translations); 442 | File : Writable_File := 443 | Write_File (Create (Filesystem_String (Filename))); 444 | begin 445 | GNATCOLL.VFS.Write (File, Output); 446 | GNATCOLL.VFS.Close (File); 447 | end Dump_Linker_Script; 448 | 449 | ----------------------- 450 | -- Dump_Startup_Code -- 451 | ----------------------- 452 | 453 | procedure Dump_Startup_Code (Self : in out Spec; Filename : String) 454 | is 455 | Translations : constant Tmplt.Translate_Table := Self.To_Translate_Table; 456 | Template : constant String := To_String (Self.Startup_Template); 457 | Output : constant String := Tmplt.Parse (Template, Translations); 458 | File : Writable_File := 459 | Write_File (Create (Filesystem_String (Filename))); 460 | begin 461 | GNATCOLL.VFS.Write (File, Output); 462 | GNATCOLL.VFS.Close (File); 463 | end Dump_Startup_Code; 464 | 465 | -------------------------- 466 | -- Dump_Translate_Table -- 467 | -------------------------- 468 | 469 | procedure Dump_Translate_Table (Self : in out Spec) is 470 | begin 471 | Put_Line ("--- Template tags ---"); 472 | 473 | for Assoc of Self.To_Translate_Table loop 474 | 475 | case Tmplt.Query.Kind (Assoc) is 476 | 477 | when Tmplt.Std => 478 | Put_Line (Tmplt.Query.Variable (Assoc) & " => " & 479 | Tmplt.Get (Assoc)); 480 | 481 | when Tmplt.Composite => 482 | declare 483 | Tag : constant Tmplt.Tag := Tmplt.Get (Assoc); 484 | begin 485 | Put_Line (Tmplt.Query.Variable (Assoc) & " => " & 486 | Tmplt.Utils.Image (Tag)); 487 | end; 488 | end case; 489 | end loop; 490 | 491 | Put_Line ("---------------------"); 492 | end Dump_Translate_Table; 493 | 494 | ------------------------ 495 | -- To_Translate_Table -- 496 | ------------------------ 497 | 498 | function To_Translate_Table 499 | (Self : Spec) 500 | return Tmplt.Translate_Table 501 | is 502 | use type Tmplt.Vector_Tag; 503 | use type Tmplt.Translate_Table; 504 | function "+" (Str : String) return Unbounded_String 505 | renames To_Unbounded_String; 506 | 507 | Boot_Mem : Unbounded_String; 508 | Boot_Mem_Addr : Unbounded_String; 509 | Boot_Mem_Size : Unbounded_String; 510 | 511 | Main_RAM : Unbounded_String; 512 | Main_RAM_Addr : Unbounded_String; 513 | Main_RAM_Size : Unbounded_String; 514 | 515 | RAM_Regions : Tmplt.Vector_Tag; 516 | RAM_Addr : Tmplt.Vector_Tag; 517 | RAM_Size : Tmplt.Vector_Tag; 518 | 519 | ROM_Regions : Tmplt.Vector_Tag; 520 | ROM_Addr : Tmplt.Vector_Tag; 521 | ROM_Size : Tmplt.Vector_Tag; 522 | 523 | Stack_Size : constant Unbounded_String := 524 | +To_C_Hexadecimal (Convert (Self.Main_Stack_Size)); 525 | Stack_Region : Unbounded_String; 526 | 527 | Interrupt_Names : Tmplt.Vector_Tag; 528 | Interrupt_Ids : Tmplt.Vector_Tag; 529 | 530 | Addr, Size : Unsigned_64; 531 | 532 | User_Assocs : Tmplt.Translate_Table 533 | (1 .. Integer (Self.User_Tags.Length)); 534 | User_Tags : User_Tags_Maps.Map := Self.User_Tags.Copy; 535 | 536 | begin 537 | 538 | -- First search for the boot memory 539 | for Mem of Self.Memory loop 540 | if Mem.Name = Self.Boot_Memory then 541 | Boot_Mem := Mem.Name; 542 | 543 | Addr := Convert (Mem.Address); 544 | Size := Convert (Mem.Size); 545 | Boot_Mem_Addr := +To_C_Hexadecimal (Addr); 546 | Boot_Mem_Size := +To_C_Hexadecimal (Size); 547 | 548 | if Mem.Kind = RAM then 549 | -- Set the main RAM as the boot memory 550 | Main_RAM := Mem.Name; 551 | Main_RAM_Addr := +To_C_Hexadecimal (Addr); 552 | Main_RAM_Size := +To_C_Hexadecimal (Size); 553 | end if; 554 | end if; 555 | end loop; 556 | 557 | -- Then set the other memories 558 | for Mem of Self.Memory loop 559 | if Mem.Name /= Self.Boot_Memory then 560 | 561 | Addr := Convert (Mem.Address); 562 | Size := Convert (Mem.Size); 563 | 564 | case Mem.Kind is 565 | 566 | when RAM => 567 | if Main_RAM = "" then 568 | -- If not already set, use the RAM in the list as Main RAM 569 | Main_RAM := Mem.Name; 570 | Main_RAM_Addr := +To_C_Hexadecimal (Addr); 571 | Main_RAM_Size := +To_C_Hexadecimal (Size); 572 | elsif Mem.Name /= Main_RAM then 573 | RAM_Regions := RAM_Regions & Mem.Name; 574 | RAM_Addr := RAM_Addr & To_C_Hexadecimal (Addr); 575 | RAM_Size := RAM_Size & To_C_Hexadecimal (Size); 576 | end if; 577 | 578 | when ROM => 579 | ROM_Regions := ROM_Regions & Mem.Name; 580 | ROM_Addr := ROM_Addr & To_C_Hexadecimal (Addr); 581 | ROM_Size := ROM_Size & To_C_Hexadecimal (Size); 582 | 583 | end case; 584 | end if; 585 | end loop; 586 | 587 | -- Select stack region 588 | if Self.Main_Stack_Memory /= "" then 589 | if not (for some Mem of Self.Memory 590 | => Mem.Name = Self.Main_Stack_Memory) 591 | then 592 | Fatal_Error ("Undefined memory used for main stack: '" & 593 | To_String (Self.Main_Stack_Memory) & "'"); 594 | end if; 595 | 596 | if (for some Mem of Self.Memory 597 | => Mem.Name = Self.Main_Stack_Memory and then Mem.Kind = ROM) 598 | then 599 | Fatal_Error ("Main stack memory cannot be ROM: '" & 600 | To_String (Self.Main_Stack_Memory) & "'"); 601 | end if; 602 | 603 | Stack_Region := Self.Main_Stack_Memory; 604 | else 605 | Stack_Region := Main_RAM; 606 | end if; 607 | 608 | -- Interrupts 609 | for Int_Id in 0 .. Integer'Max (Self.Interrupts.Last_Index, 610 | Self.CPU.Number_Of_Interrupts - 1) 611 | loop 612 | Interrupt_Ids := Interrupt_Ids & Int_Id; 613 | if Self.Interrupts.Is_Index_Used (Int_Id) then 614 | Interrupt_Names := Interrupt_Names & 615 | Self.Interrupts.Get_Name (Int_Id); 616 | else 617 | Interrupt_Names := Interrupt_Names & "unknown_interrupt"; 618 | end if; 619 | end loop; 620 | 621 | -- User defined tags 622 | for Assoc of User_Assocs loop 623 | declare 624 | Cur : constant User_Tags_Maps.Cursor := User_Tags.First; 625 | Key : constant Unbounded_String := User_Tags_Maps.Key (Cur); 626 | Val : constant Unbounded_String := User_Tags_Maps.Element (Cur); 627 | begin 628 | Assoc := Templates_Parser.Assoc (To_String (Key), 629 | To_String (Val)); 630 | User_Tags.Delete (Key); 631 | end; 632 | end loop; 633 | 634 | return User_Assocs & 635 | (Templates_Parser.Assoc ("FLOAT_HANDLING", 636 | Self.CPU.Float_Handling'Img), 637 | Templates_Parser.Assoc ("BOOT_FROM_ROM", Self.Boot_From_ROM), 638 | Templates_Parser.Assoc ("BOOT_MEM", Boot_Mem), 639 | Templates_Parser.Assoc ("BOOT_MEM_ADDR", Boot_Mem_Addr), 640 | Templates_Parser.Assoc ("BOOT_MEM_SIZE", Boot_Mem_Size), 641 | Templates_Parser.Assoc ("MAIN_RAM", Main_RAM), 642 | Templates_Parser.Assoc ("MAIN_RAM_ADDR", Main_RAM_Addr), 643 | Templates_Parser.Assoc ("MAIN_RAM_SIZE", Main_RAM_Size), 644 | Templates_Parser.Assoc ("RAM_REGION", RAM_Regions), 645 | Templates_Parser.Assoc ("RAM_ADDR", RAM_Addr), 646 | Templates_Parser.Assoc ("RAM_SIZE", RAM_Size), 647 | Templates_Parser.Assoc ("ROM_REGION", ROM_Regions), 648 | Templates_Parser.Assoc ("ROM_ADDR", ROM_Addr), 649 | Templates_Parser.Assoc ("ROM_SIZE", ROM_Size), 650 | Templates_Parser.Assoc ("MAIN_STACK_SIZE", Stack_Size), 651 | Templates_Parser.Assoc ("MAIN_STACK_REGION", Stack_Region), 652 | Templates_Parser.Assoc ("INTERRUPT_NAME", Interrupt_Names), 653 | Templates_Parser.Assoc ("INTERRUPT_ID", Interrupt_Ids)); 654 | end To_Translate_Table; 655 | 656 | ------------------- 657 | -- Add_Interrupt -- 658 | ------------------- 659 | 660 | procedure Add_Interrupt 661 | (Self : in out Interrupt_Vector; 662 | Index : Integer; 663 | Name : Unbounded_String) 664 | is 665 | begin 666 | Interrupt_Hashed_Maps.Include 667 | (Container => Self.Interrupts, 668 | Key => Index, 669 | New_Item => Name); 670 | 671 | if Index > Self.Last_Index then 672 | Self.Last_Index := Index; 673 | end if; 674 | 675 | end Add_Interrupt; 676 | 677 | ------------------- 678 | -- Is_Index_Used -- 679 | ------------------- 680 | 681 | function Is_Index_Used 682 | (Self : Interrupt_Vector; 683 | Index : Integer) return Boolean 684 | is 685 | use Interrupt_Hashed_Maps; 686 | Is_Used : constant Boolean := 687 | Find 688 | (Container => Self.Interrupts, 689 | Key => Index) /= No_Element; 690 | begin 691 | return Is_Used; 692 | end Is_Index_Used; 693 | 694 | -------------- 695 | -- Get_Name -- 696 | -------------- 697 | 698 | function Get_Name 699 | (Self : Interrupt_Vector; 700 | Index : Integer) return String 701 | is 702 | begin 703 | return To_String 704 | (Interrupt_Hashed_Maps.Element 705 | (Container => Self.Interrupts, 706 | Key => Index)); 707 | end Get_Name; 708 | 709 | ----------------- 710 | -- Valid_Input -- 711 | ----------------- 712 | 713 | function Valid_Input (Self : in out Spec) return Boolean is 714 | Boot_Mem_Is_Valid : Boolean := False; 715 | 716 | Result : Boolean := True; 717 | begin 718 | for Memory_Region of Self.Memory loop 719 | if Memory_Region.Name = Self.Boot_Memory then 720 | -- We found the boot memory. 721 | Boot_Mem_Is_Valid := True; 722 | 723 | Self.Boot_From_ROM := Memory_Region.Kind = ROM; 724 | end if; 725 | 726 | -- If the size or the memory are not matching, we raise an exception. 727 | if not Number_Input.Valid (To_String (Memory_Region.Size)) then 728 | Error ("Invalid memory size expression for '" & 729 | To_String (Memory_Region.Name) & "' : '" & 730 | To_String (Memory_Region.Size) & "'"); 731 | Result := False; 732 | end if; 733 | 734 | if not Number_Input.Valid (To_String (Memory_Region.Address)) then 735 | Error ("Invalid memory address expression for '" & 736 | To_String (Memory_Region.Name) & "' : '" & 737 | To_String (Memory_Region.Address) & "'"); 738 | Result := False; 739 | end if; 740 | end loop; 741 | 742 | if not Boot_Mem_Is_Valid then 743 | Error ("Invalid boot memory : " & To_String (Self.Boot_Memory)); 744 | Result := False; 745 | end if; 746 | 747 | if not Number_Input.Valid (To_String (Self.Main_Stack_Size)) then 748 | Error ("Invalid main stack size : " & 749 | To_String (Self.Main_Stack_Size)); 750 | Result := False; 751 | end if; 752 | 753 | return Result; 754 | end Valid_Input; 755 | 756 | -------------------------- 757 | -- Valid_Memory_Regions -- 758 | -------------------------- 759 | 760 | function Valid_Memory_Regions (Self : in out Spec) return Boolean is 761 | Result : Boolean := True; 762 | begin 763 | for Region of Self.Memory loop 764 | for Memory_Region_To_Check_Against of Self.Memory loop 765 | -- We dont check the memory region against itself. 766 | if Memory_Region_To_Check_Against.Name /= Region.Name then 767 | if Memory_Regions_Overlap 768 | (Region, 769 | Memory_Region_To_Check_Against) 770 | then 771 | Error 772 | ("Memory overlap : " & 773 | ASCII.LF & Get_Info_String (Region) & 774 | ASCII.LF & 775 | Get_Info_String (Memory_Region_To_Check_Against)); 776 | Result := False; 777 | end if; 778 | end if; 779 | end loop; 780 | end loop; 781 | return Result; 782 | end Valid_Memory_Regions; 783 | 784 | ---------------------------- 785 | -- Memory_Regions_Overlap -- 786 | ---------------------------- 787 | 788 | function Memory_Regions_Overlap (Memory_1 : Memory_Region; 789 | Memory_2 : Memory_Region) 790 | return Boolean 791 | is 792 | Memory_1_Address : constant Unsigned_64 := Convert (Memory_1.Address); 793 | Memory_1_Size : constant Unsigned_64 := Convert (Memory_1.Size); 794 | Memory_2_Address : constant Unsigned_64 := Convert (Memory_2.Address); 795 | Memory_2_Size : constant Unsigned_64 := Convert (Memory_2.Size); 796 | 797 | begin 798 | -- Memory size cannot be zero. 799 | if Memory_2_Size = 0 or else Memory_1_Size = 0 then 800 | return True; 801 | end if; 802 | if Memory_2_Address > Memory_1_Address then 803 | return not (Memory_1_Address + Memory_1_Size <= Memory_2_Address); 804 | elsif Memory_2_Address < Memory_1_Address then 805 | return not (Memory_2_Address + Memory_2_Size <= Memory_1_Address); 806 | else -- Memory addresses are the same. 807 | return True; 808 | end if; 809 | end Memory_Regions_Overlap; 810 | 811 | --------------------- 812 | -- Get_Info_String -- 813 | --------------------- 814 | 815 | function Get_Info_String (Region : Memory_Region) return String is 816 | begin 817 | return To_String (Region.Name) & " : Size = " & To_String (Region.Size) & 818 | " and Address = " & To_String (Region.Address); 819 | end Get_Info_String; 820 | 821 | ----------------------------- 822 | -- Default_Linker_Template -- 823 | ----------------------------- 824 | 825 | function Default_Linker_Template (Self : Spec) return String is 826 | use GNATCOLL.Utils; 827 | 828 | Arch : constant String := To_String (Self.CPU.Arch); 829 | begin 830 | if Arch = "armv6-m" or else Arch = "armv7-m" or else 831 | Arch = "armv7e-m" or else Arch = "armv8-m" 832 | then 833 | return Join_Path (Resources_Base_Directory, "armvX-m.ld.tmplt"); 834 | elsif Arch = "risc-v" then 835 | return Join_Path (Resources_Base_Directory, "riscv.ld.tmplt"); 836 | end if; 837 | 838 | Fatal_Error ("No default linker template for this configuration, " & 839 | "please specify a custom template."); 840 | end Default_Linker_Template; 841 | 842 | ------------------------------ 843 | -- Default_Startup_Template -- 844 | ------------------------------ 845 | 846 | function Default_Startup_Template (Self : Spec) return String is 847 | use GNATCOLL.Utils; 848 | 849 | Arch : constant String := To_String (Self.CPU.Arch); 850 | begin 851 | if Arch = "armv6-m" or else Arch = "armv7-m" or else 852 | Arch = "armv7e-m" or else Arch = "armv8-m" 853 | then 854 | return Join_Path (Resources_Base_Directory, "armvX-m.S.tmplt"); 855 | elsif Arch = "risc-v" then 856 | return Join_Path (Resources_Base_Directory, "riscv.S.tmplt"); 857 | end if; 858 | 859 | Fatal_Error ("No default startup template for this configuration, " & 860 | "please specify a custom template."); 861 | end Default_Startup_Template; 862 | 863 | -------------------------- 864 | -- C_Comment_Box_Filter -- 865 | -------------------------- 866 | 867 | function C_Comment_Box_Filter 868 | (Value : String; 869 | Parameters : String; 870 | Context : Templates_Parser.Filter_Context) 871 | return String 872 | is 873 | pragma Unreferenced (Context); 874 | use Ada.Strings.Fixed; 875 | 876 | Separator_Index : constant Natural := Index (Parameters, "/"); 877 | 878 | Indent_Cnt : constant Natural := Natural'Value 879 | ((if Parameters'Length = 0 880 | then "0" 881 | elsif Separator_Index /= 0 882 | then Head (Parameters, Separator_Index - 1) 883 | else Parameters)); 884 | 885 | Prefix : constant String := 886 | (if Separator_Index /= 0 887 | then Tail (Parameters, Parameters'Length - Separator_Index) 888 | else ""); 889 | 890 | Text : constant String := Prefix & Value; 891 | Indent : constant String := Indent_Cnt * ' '; 892 | Bar : constant String := "/**" & (Text'Length * '*') & "**/"; 893 | begin 894 | return Indent & Bar & ASCII.LF & 895 | Indent & "/* " & Text & " */" & ASCII.LF & 896 | Indent & Bar; 897 | end C_Comment_Box_Filter; 898 | 899 | begin 900 | Templates_Parser.Register_Filter 901 | ("C_COMMENT_BOX", C_Comment_Box_Filter'Access); 902 | end Device; 903 | -------------------------------------------------------------------------------- /src/device.ads: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019-2021, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; 20 | with Ada.Strings.Unbounded.Hash; 21 | with Ada.Strings.Hash; 22 | with Ada.Containers.Vectors; 23 | with Ada.Containers.Hashed_Maps; 24 | 25 | with GNATCOLL.Projects; use GNATCOLL.Projects; 26 | 27 | with Templates_Parser; 28 | 29 | package Device is 30 | 31 | type Spec is tagged private; 32 | 33 | procedure Get_Memory_List_From_Project 34 | (Self : in out Spec; 35 | Spec_Project : Project_Type); 36 | 37 | procedure Get_Interrupt_Vector_From_Project 38 | (Self : in out Spec; 39 | Spec_Project : Project_Type); 40 | 41 | procedure Get_Boot_Memory_From_Project 42 | (Self : in out Spec; 43 | Spec_Project : Project_Type); 44 | 45 | procedure Get_CPU_From_Project 46 | (Self : in out Spec; 47 | Spec_Project : Project_Type); 48 | 49 | procedure Get_User_Tags_From_Project 50 | (Self : in out Spec; 51 | Spec_Project : Project_Type); 52 | 53 | procedure Display (Self : in out Spec); 54 | 55 | -- Checks that the specs are valid, IE: 56 | -- Validate Inputs (address, sizes, etc...) 57 | -- No overlapping memory_regions 58 | -- Boot memory exists 59 | -- No overlapping interrupts in the interrupt vector. 60 | -- return False if there is an error 61 | function Valid (Self : in out Spec) return Boolean; 62 | 63 | procedure Dump_Linker_Script (Self : in out Spec; Filename : String); 64 | 65 | procedure Dump_Startup_Code (Self : in out Spec; Filename : String); 66 | 67 | procedure Dump_Translate_Table (Self : in out Spec); 68 | 69 | function To_Translate_Table 70 | (Self : Spec) 71 | return Templates_Parser.Translate_Table; 72 | 73 | private 74 | 75 | type Float_Type is (Hard, Soft); 76 | 77 | function Convert (Str : String) return Float_Type; 78 | 79 | type CPU_Type is record 80 | Name : Unbounded_String; 81 | Float_Handling : Float_Type; 82 | Number_Of_Interrupts : Natural := 0; 83 | Arch : Unbounded_String; 84 | end record; 85 | 86 | type Memory_Kind is (RAM, ROM); 87 | 88 | type Memory_Region is record 89 | Name : Unbounded_String; 90 | Address : Unbounded_String; 91 | Size : Unbounded_String; 92 | Kind : Memory_Kind; 93 | end record; 94 | 95 | package Memory_Region_Vectors is new Ada.Containers.Vectors 96 | (Positive, Memory_Region); 97 | 98 | use Ada.Containers; 99 | function Identity_Integer (Key : Integer) return Hash_Type 100 | is (Hash_Type (Key)); 101 | 102 | function Identity_Unbounded_String (Key : Unbounded_String) return Hash_Type 103 | is (Ada.Strings.Hash (To_String (Key))); 104 | 105 | package Interrupt_Hashed_Maps is new Ada.Containers.Hashed_Maps 106 | (Key_Type => Integer, 107 | Element_Type => Unbounded_String, 108 | Hash => Identity_Integer, 109 | Equivalent_Keys => "="); 110 | 111 | type Interrupt_Vector is tagged record 112 | Interrupts : Interrupt_Hashed_Maps.Map; 113 | Last_Index : Integer := -1; 114 | end record; 115 | 116 | package User_Tags_Maps is new Ada.Containers.Hashed_Maps 117 | (Key_Type => Unbounded_String, 118 | Element_Type => Unbounded_String, 119 | Hash => Ada.Strings.Unbounded.Hash, 120 | Equivalent_Keys => "="); 121 | 122 | type Spec is tagged record 123 | Memory : Memory_Region_Vectors.Vector; 124 | Boot_Memory : Unbounded_String; 125 | Boot_From_ROM : Boolean; 126 | CPU : CPU_Type; 127 | Interrupts : Interrupt_Vector; 128 | Linker_Template : Unbounded_String; 129 | Startup_Template : Unbounded_String; 130 | Main_Stack_Size : Unbounded_String; 131 | Main_Stack_Memory : Unbounded_String; 132 | User_Tags : User_Tags_Maps.Map; 133 | end record; 134 | 135 | -- Private procedures -- 136 | 137 | procedure Add_Interrupt 138 | (Self : in out Interrupt_Vector; 139 | Index : Integer; 140 | Name : Unbounded_String); 141 | 142 | -- Used to check if an interrupt has been defined for a given Index. 143 | function Is_Index_Used 144 | (Self : Interrupt_Vector; 145 | Index : Integer) return Boolean; 146 | 147 | function Get_Name 148 | (Self : Interrupt_Vector; 149 | Index : Integer) return String; 150 | 151 | -- Checks that the input is coherent IE: 152 | -- Boot memory is a valid memory region. 153 | -- All memory regions have an address and a size in a relevant format. 154 | function Valid_Input (Self : in out Spec) return Boolean; 155 | 156 | -- Checks that there are no overlapping memory regions. 157 | function Valid_Memory_Regions (Self : in out Spec) return Boolean; 158 | 159 | -- Verify that two memory regions are not overlapping each other. 160 | function Memory_Regions_Overlap (Memory_1 : Memory_Region; 161 | Memory_2 : Memory_Region) 162 | return Boolean; 163 | 164 | -- Return a string of the following form 165 | -- with Size = and Address = ; 166 | function Get_Info_String (Region : Memory_Region) return String; 167 | 168 | -- Return the default linker template based on the device information 169 | function Default_Linker_Template (Self : Spec) return String; 170 | 171 | -- Return the default startup template based on the device information 172 | function Default_Startup_Template (Self : Spec) return String; 173 | 174 | end Device; 175 | -------------------------------------------------------------------------------- /src/main.adb: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019-2021, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with GNAT.Command_Line; 20 | with GNAT.Strings; 21 | 22 | with Ada.Text_IO; use Ada.Text_IO; 23 | 24 | with GNATCOLL.Projects; use GNATCOLL.Projects; 25 | with GNATCOLL.VFS; use GNATCOLL.VFS; 26 | 27 | with Setup; 28 | with Utils; 29 | with Device; use Device; 30 | 31 | procedure Main is 32 | 33 | use GNAT.Strings; 34 | 35 | -- Spec representing the target device 36 | Spec : Device.Spec; 37 | 38 | use Setup; 39 | Input : aliased Command_Line_Values; 40 | 41 | begin 42 | Input.Get_Arguments; 43 | 44 | Utils.Register_Memory_Map_Attributes; 45 | 46 | declare 47 | Env : Project_Environment_Access; 48 | Tree : Project_Tree; 49 | 50 | Project_File : constant Virtual_File := 51 | Create_From_Base (Filesystem_String (Input.Project_File.all)); 52 | 53 | begin 54 | Initialize (Env); 55 | 56 | Apply_Scenario_Variables (Env); 57 | 58 | Tree.Load 59 | (Root_Project_Path => Project_File, 60 | Env => Env, 61 | Packages_To_Check => All_Packs); 62 | 63 | -- TODO: Put all that in a function that prepares the spec. 64 | Spec.Get_Memory_List_From_Project (Tree.Root_Project); 65 | 66 | Spec.Get_Boot_Memory_From_Project (Tree.Root_Project); 67 | 68 | Spec.Get_Interrupt_Vector_From_Project (Tree.Root_Project); 69 | 70 | Spec.Get_CPU_From_Project (Tree.Root_Project); 71 | 72 | Spec.Get_User_Tags_From_Project (Tree.Root_Project); 73 | 74 | if not Spec.Valid then 75 | -- At least one error message should have been displayed. 76 | return; 77 | end if; 78 | 79 | if Input.Print_Tags then 80 | Spec.Dump_Translate_Table; 81 | end if; 82 | 83 | if Input.Linker_File /= null 84 | and then 85 | Input.Linker_File.all /= "" 86 | then 87 | Spec.Dump_Linker_Script (Input.Linker_File.all); 88 | end if; 89 | 90 | if Input.Startup_Code_File /= null 91 | and then 92 | Input.Startup_Code_File.all /= "" 93 | then 94 | Spec.Dump_Startup_Code (Input.Startup_Code_File.all); 95 | end if; 96 | 97 | Spec.Display; 98 | end; 99 | exception 100 | -- We catch the exception from the command line when 101 | -- the user called the executable with "-h" or "--help" 102 | when GNAT.Command_Line.Exit_From_Command_Line => 103 | New_Line; 104 | 105 | when GNATCOLL.Projects.Invalid_Project => 106 | Utils.Error 107 | ("Project file """ & Input.Project_File.all & """ not found."); 108 | when Utils.Exit_Exc => null; 109 | 110 | end Main; 111 | -------------------------------------------------------------------------------- /src/number_input.adb: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with Ada.Text_IO; 20 | 21 | with Interfaces; use Interfaces; 22 | with GNAT.Regpat; use GNAT.Regpat; 23 | with GNATCOLL.Utils; use GNATCOLL.Utils; 24 | with Utils; use Utils; 25 | 26 | package body Number_Input is 27 | 28 | package U64_IO is new Ada.Text_IO.Modular_IO (Unsigned_64); 29 | 30 | Dec_Number_And_Unit : constant String := 31 | "(^[0-9]+(k|K|m|M)$)"; 32 | 33 | Hex_Number : constant String := 34 | "(^0x([0-9]|[A-F]|[a-f])+$)"; 35 | 36 | Pattern : constant String := 37 | Hex_Number & "|" & Dec_Number_And_Unit; 38 | 39 | Matcher : constant Pattern_Matcher := Compile (Pattern); 40 | 41 | ----------- 42 | -- Valid -- 43 | ----------- 44 | 45 | function Valid (Str : String) return Boolean is 46 | begin 47 | if Match (Matcher, Str) then 48 | return True; 49 | else 50 | 51 | -- Check if Str is a valid Ada literal by trying to do a conversion 52 | declare 53 | U : Unsigned_64; 54 | pragma Unreferenced (U); 55 | begin 56 | U := Unsigned_64'Value (Str); 57 | exception 58 | when others => return False; 59 | end; 60 | return True; 61 | end if; 62 | end Valid; 63 | 64 | ------------- 65 | -- Convert -- 66 | ------------- 67 | 68 | function Convert (Str : String) return Unsigned_64 is 69 | Multiplier : Unsigned_64 := 1; 70 | begin 71 | if Match (Matcher, Str) then 72 | if Starts_With (Str, "0x") then 73 | return Unsigned_64'Value 74 | ("16#" & Str (Str'First + 2 .. Str'Last) & "#"); 75 | else 76 | case Str (Str'Last) is 77 | when 'k' | 'K' => 78 | Multiplier := 1024; 79 | when 'm' | 'M' => 80 | Multiplier := 1024 * 1024; 81 | when others => 82 | Fatal_Error 83 | ("Invalid input to number conversion: '" & Str & "'"); 84 | end case; 85 | end if; 86 | return Unsigned_64'Value 87 | (Str (Str'First .. Str'Last - 1)) * Multiplier; 88 | else 89 | return Unsigned_64'Value (Str); 90 | end if; 91 | end Convert; 92 | 93 | ---------------------- 94 | -- To_C_Hexadecimal -- 95 | ---------------------- 96 | 97 | function To_C_Hexadecimal (Val : Interfaces.Unsigned_64) return String is 98 | Temp_String : String (1 .. 256); 99 | Result : Unbounded_String; 100 | begin 101 | U64_IO.Put (To => Temp_String, 102 | Item => Val, 103 | Base => 16); 104 | 105 | Result := To_Unbounded_String (Temp_String); 106 | Trim (Result, Ada.Strings.Left); 107 | return ("0x" & Slice (Result, 4, Length (Result) - 1)); 108 | end To_C_Hexadecimal; 109 | 110 | end Number_Input; 111 | -------------------------------------------------------------------------------- /src/number_input.ads: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with Interfaces; 20 | with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; 21 | 22 | package Number_Input is 23 | 24 | function Valid (Str : String) return Boolean; 25 | 26 | function Valid (Str : Unbounded_String) return Boolean 27 | is (Valid (To_String (Str))); 28 | 29 | function Convert (Str : String) return Interfaces.Unsigned_64 30 | with Pre => Valid (Str); 31 | 32 | function Convert (Str : Unbounded_String) return Interfaces.Unsigned_64 33 | is (Convert (To_String (Str))) 34 | with Pre => Valid (Str); 35 | 36 | function To_C_Hexadecimal (Val : Interfaces.Unsigned_64) return String; 37 | -- Convert to a string representation in C literal format 38 | 39 | end Number_Input; 40 | -------------------------------------------------------------------------------- /src/setup.adb: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with Ada.Text_IO; use Ada.Text_IO; 20 | with Ada.Containers.Indefinite_Ordered_Maps; 21 | with GNAT.Command_Line; use GNAT.Command_Line; 22 | with GNAT.OS_Lib; 23 | with Utils; 24 | 25 | package body Setup is 26 | 27 | package Scv_Maps is 28 | new Ada.Containers.Indefinite_Ordered_Maps 29 | (Key_Type => String, 30 | Element_Type => String); 31 | Scv_Map : Scv_Maps.Map; 32 | -- All defined scenario variables 33 | 34 | procedure Add_Scenario_Var (Key, Value : String); 35 | procedure Handle_Scenerio_Arg (Switch, Value : String); 36 | 37 | ---------------------- 38 | -- Add_Scenario_Var -- 39 | ---------------------- 40 | 41 | procedure Add_Scenario_Var (Key, Value : String) is 42 | begin 43 | Scv_Map.Include (Key, Value); 44 | end Add_Scenario_Var; 45 | 46 | ------------------------- 47 | -- Handle_Scenerio_Arg -- 48 | ------------------------- 49 | 50 | procedure Handle_Scenerio_Arg (Switch, Value : String) is 51 | pragma Unreferenced (Switch); 52 | Name_First, Name_Last, Value_First : Natural; 53 | begin 54 | Name_First := Value'First; 55 | Name_Last := Name_First - 1; 56 | while Name_Last < Value'Last 57 | and then Value (Name_Last + 1) /= '=' 58 | loop 59 | Name_Last := Name_Last + 1; 60 | end loop; 61 | 62 | Value_First := Name_Last + 2; 63 | 64 | Add_Scenario_Var 65 | (Key => Value (Name_First .. Name_Last), 66 | Value => Value (Value_First .. Value'Last)); 67 | end Handle_Scenerio_Arg; 68 | 69 | ------------------- 70 | -- Get_Arguments -- 71 | ------------------- 72 | 73 | procedure Get_Arguments (Values : aliased out Command_Line_Values) 74 | 75 | is 76 | Config : Command_Line_Configuration; 77 | 78 | begin 79 | Define_Switch 80 | (Config, 81 | Values.Linker_File'Access, 82 | "-l:", 83 | Help => "Name of the generated linker script."); 84 | 85 | Define_Switch 86 | (Config, 87 | Values.Startup_Code_File'Access, 88 | "-s:", 89 | Help => "Name of the generated startup code."); 90 | 91 | Define_Switch 92 | (Config, 93 | Handle_Scenerio_Arg'Access, 94 | "-X:", 95 | Help => "Specify an external reference for Project Files."); 96 | 97 | Define_Switch 98 | (Config, 99 | Values.Project_File'Access, 100 | "-P:", 101 | Help => "Name of the project file with the device configuration."); 102 | 103 | Define_Switch 104 | (Config, 105 | Values.Print_Tags'Access, 106 | Switch => "", 107 | Long_Switch => "--print-tags", 108 | Help => "Print the tags available in templates."); 109 | 110 | Getopt (Config); 111 | 112 | if Values.Project_File = null or else Values.Project_File.all = "" then 113 | Utils.Fatal_Error ("Project file required (-P)"); 114 | end if; 115 | end Get_Arguments; 116 | 117 | ------------------------------ 118 | -- Apply_Scenario_Variables -- 119 | ------------------------------ 120 | 121 | procedure Apply_Scenario_Variables (Env : Project_Environment_Access) is 122 | use Scv_Maps; 123 | begin 124 | for Scv_C in Scv_Map.Iterate loop 125 | Change_Environment (Env.all, Key (Scv_C), Element (Scv_C)); 126 | end loop; 127 | 128 | -- Make sure GPR_TOOL is initalized. There are several ways to 129 | -- initialize it: by decreasing order of precedence: 130 | -- 131 | -- * explicitly set through a -X option; 132 | -- * set through an environment variable; 133 | -- * implicitly initialized by startup-gen. 134 | 135 | if Scv_Map.Contains ("GPR_TOOL") then 136 | null; 137 | 138 | else 139 | declare 140 | GPR_Tool_Env_Var : GNAT.Strings.String_Access := 141 | GNAT.OS_Lib.Getenv ("GPR_TOOL"); 142 | GPR_Tool_Value : constant String := 143 | (if GPR_Tool_Env_Var.all = "" 144 | then "startup-gen" 145 | else GPR_Tool_Env_Var.all); 146 | begin 147 | Change_Environment (Env.all, "GPR_TOOL", GPR_Tool_Value); 148 | Free (GPR_Tool_Env_Var); 149 | end; 150 | end if; 151 | end Apply_Scenario_Variables; 152 | 153 | ------------- 154 | -- Display -- 155 | ------------- 156 | 157 | procedure Display (Values : in out Command_Line_Values) 158 | is 159 | begin 160 | Put_Line ("Spec " & Values.Project_File.all); 161 | Put_Line ("Linker Script " & Values.Linker_File.all); 162 | Put_Line ("Startup Code " & Values.Startup_Code_File.all); 163 | end Display; 164 | 165 | end Setup; 166 | -------------------------------------------------------------------------------- /src/setup.ads: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with GNAT.Strings; use GNAT.Strings; 20 | with Ada.IO_Exceptions; use Ada.IO_Exceptions; 21 | with GNATCOLL.Projects; use GNATCOLL.Projects; 22 | 23 | package Setup is 24 | 25 | type Command_Line_Values is tagged record 26 | Project_File : aliased String_Access := null; 27 | Linker_File : aliased String_Access := null; 28 | Startup_Code_File : aliased String_Access := null; 29 | Print_Tags : aliased Boolean := False; 30 | end record; 31 | 32 | -- We verify that the mandatory arguments are correct. 33 | procedure Get_Arguments (Values : aliased out Command_Line_Values) 34 | with Post => (Values.Project_File.all /= "") 35 | or else raise Name_Error 36 | with "You must pass a file on the command line."; 37 | 38 | procedure Apply_Scenario_Variables (Env : Project_Environment_Access); 39 | 40 | procedure Display (Values : in out Command_Line_Values); 41 | 42 | end Setup; 43 | -------------------------------------------------------------------------------- /src/utils.adb: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019-2021, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | with Ada.Text_IO; use Ada.Text_IO; 20 | with Ada.Command_Line; use Ada.Command_Line; 21 | with GNATCOLL.Projects; use GNATCOLL.Projects; 22 | 23 | package body Utils is 24 | 25 | ------------------------------------ 26 | -- Register_Memory_Map_Attributes -- 27 | ------------------------------------ 28 | 29 | procedure Register_Memory_Map_Attributes is 30 | 31 | type Err_Str_Access is access constant String; 32 | type Strings is array (Integer range <>) of Err_Str_Access; 33 | 34 | -- Register attributes and save the potential errors in an array 35 | Errors : constant Strings := 36 | ( 37 | 38 | -- Memory_Map -- 39 | new String'(Register_New_Attribute 40 | ("Mem_Kind", 41 | Prj_Package_Name, 42 | Indexed => True)), 43 | new String'(Register_New_Attribute 44 | ("Size", 45 | Prj_Package_Name, 46 | Indexed => True)), 47 | new String'(Register_New_Attribute 48 | ("Address", 49 | Prj_Package_Name, 50 | Indexed => True)), 51 | new String'(Register_New_Attribute 52 | ("Memories", 53 | Prj_Package_Name, 54 | Is_List => True)), 55 | new String'(Register_New_Attribute 56 | ("Boot_Memory", 57 | Prj_Package_Name)), 58 | 59 | -- CPU -- 60 | new String'(Register_New_Attribute 61 | ("CPU_Name", 62 | Prj_Package_Name)), 63 | new String'(Register_New_Attribute 64 | ("Float_Handling", 65 | Prj_Package_Name)), 66 | new String'(Register_New_Attribute 67 | ("Number_Of_Interrupts", 68 | Prj_Package_Name)), 69 | new String'(Register_New_Attribute 70 | ("Main_Stack_Size", 71 | Prj_Package_Name)), 72 | new String'(Register_New_Attribute 73 | ("Main_Stack_Memory", 74 | Prj_Package_Name)), 75 | new String'(Register_New_Attribute 76 | ("Linker_Template", 77 | Prj_Package_Name)), 78 | new String'(Register_New_Attribute 79 | ("Startup_Template", 80 | Prj_Package_Name)), 81 | 82 | -- Interrupt_Vector -- 83 | new String'(Register_New_Attribute 84 | ("Interrupt", 85 | Prj_Package_Name, 86 | Indexed => True)), 87 | 88 | -- User_Tag -- 89 | new String'(Register_New_Attribute 90 | ("User_Tag", 91 | Prj_Package_Name, 92 | Indexed => True)) 93 | ); 94 | begin 95 | for Str of Errors loop 96 | if Str.all /= "" then 97 | raise Program_Error with "Could not register new attribute " & 98 | Str.all; 99 | end if; 100 | end loop; 101 | end Register_Memory_Map_Attributes; 102 | 103 | ------------- 104 | -- Warning -- 105 | ------------- 106 | 107 | procedure Warning (Msg : String) is 108 | begin 109 | Put_Line (Standard_Error, "Warning: " & Msg); 110 | end Warning; 111 | 112 | ----------- 113 | -- Error -- 114 | ----------- 115 | 116 | procedure Error (Msg : String) is 117 | begin 118 | Put_Line (Standard_Error, "Error: " & Msg); 119 | Set_Exit_Status (Failure); 120 | end Error; 121 | 122 | ----------------- 123 | -- Fatal_Error -- 124 | ----------------- 125 | 126 | procedure Fatal_Error (Msg : String) is 127 | begin 128 | Error (Msg); 129 | raise Exit_Exc; 130 | end Fatal_Error; 131 | 132 | end Utils; 133 | -------------------------------------------------------------------------------- /src/utils.ads: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | -- -- 3 | -- startup-gen -- 4 | -- -- 5 | -- Copyright (C) 2019, AdaCore -- 6 | -- -- 7 | -- This is free software; you can redistribute it and/or modify it under -- 8 | -- terms of the GNU General Public License as published by the Free Soft- -- 9 | -- ware Foundation; either version 3, or (at your option) any later ver- -- 10 | -- sion. This software is distributed in the hope that it will be useful, -- 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 12 | -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- 13 | -- License for more details. You should have received a copy of the GNU -- 14 | -- General Public License distributed with GNAT; see file COPYING. If not, -- 15 | -- see . -- 16 | -- -- 17 | ------------------------------------------------------------------------------ 18 | 19 | package Utils is 20 | 21 | Prj_Package_Name : constant String := "Device_Configuration"; 22 | 23 | procedure Register_Memory_Map_Attributes; 24 | 25 | Exit_Exc : exception; 26 | 27 | procedure Warning (Msg : String); 28 | procedure Error (Msg : String); 29 | procedure Fatal_Error (Msg : String) 30 | with No_Return; 31 | 32 | end Utils; 33 | -------------------------------------------------------------------------------- /startup_gen.gpr: -------------------------------------------------------------------------------- 1 | with "templates_parser.gpr"; 2 | with "gnatcoll"; 3 | with "gpr"; 4 | 5 | project Startup_Gen is 6 | 7 | for Languages use ("Ada"); 8 | for Source_Dirs use ("src"); 9 | for Main use ("main.adb"); 10 | for Object_Dir use "obj/"; 11 | for Exec_Dir use "."; 12 | for Create_Missing_Dirs use "True"; 13 | 14 | 15 | type Enabled_Kind is ("enabled", "disabled"); 16 | Compile_Checks : Enabled_Kind := External ("STARTUP_GEN_COMPILE_CHECKS", "disabled"); 17 | Runtime_Checks : Enabled_Kind := External ("STARTUP_GEN_RUNTIME_CHECKS", "enabled"); 18 | Style_Checks : Enabled_Kind := External ("STARTUP_GEN_STYLE_CHECKS", "disabled"); 19 | Contracts_Checks : Enabled_Kind := External ("STARTUP_GEN_CONTRACTS", "enabled"); 20 | 21 | type Build_Kind is ("debug", "optimize"); 22 | Build_Mode : Build_Kind := External ("STARTUP_GEN_BUILD_MODE", "optimize"); 23 | 24 | Compile_Checks_Switches := (); 25 | case Compile_Checks is 26 | when "enabled" => 27 | Compile_Checks_Switches := 28 | ("-gnatwa", -- All warnings 29 | "-gnatVa", -- All validity checks 30 | "-gnatwe"); -- Warnings as errors 31 | when others => null; 32 | end case; 33 | 34 | Runtime_Checks_Switches := (); 35 | case Runtime_Checks is 36 | when "enabled" => null; 37 | when others => 38 | Runtime_Checks_Switches := 39 | ("-gnatp"); -- Supress checks 40 | end case; 41 | 42 | Style_Checks_Switches := (); 43 | case Style_Checks is 44 | when "enabled" => null; 45 | Style_Checks_Switches := 46 | ("-gnatyg", -- Style checks 47 | "-gnatyM80", -- Maximum line length 48 | "-gnatyO"); -- Overriding subprograms explicitly marked as such 49 | when others => null; 50 | end case; 51 | 52 | Contracts_Switches := (); 53 | case Contracts_Checks is 54 | when "enabled" => null; 55 | Contracts_Switches := 56 | ("-gnata"); -- Enable assertions and contracts 57 | when others => 58 | end case; 59 | 60 | Build_Switches := (); 61 | case Build_Mode is 62 | when "optimize" => 63 | Build_Switches := ("-O3", -- Optimization 64 | "-gnatn"); -- Enable inlining 65 | when "debug" => 66 | Build_Switches := ("-g", -- Debug info 67 | "-O0"); -- No optimization 68 | end case; 69 | 70 | package Compiler is 71 | for Default_Switches ("Ada") use 72 | Compile_Checks_Switches & 73 | Build_Switches & 74 | Runtime_Checks_Switches & 75 | Style_Checks_Switches & 76 | Contracts_Switches & 77 | ("-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities 78 | end Compiler; 79 | 80 | package Builder is 81 | for Executable ("main.adb") use "startup-gen"; 82 | end Builder; 83 | 84 | package Install is 85 | for Artifacts (".") use ("share"); 86 | end Install; 87 | 88 | end Startup_Gen; 89 | -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/cortex-m/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import make_simple_project, nm_symbols, \ 2 | check_symbols, MemoryMap 3 | 4 | memmap = MemoryMap() 5 | memmap.add('flash1', 'ROM', 0x0000000, 32 * 1024) 6 | memmap.add('flash2', 'ROM', 0x1000000, 32 * 1024) 7 | memmap.add('flash3', 'ROM', 0x2000000, 32 * 1024) 8 | memmap.add('ram1', 'RAM', 0x3000000, 32 * 1024) 9 | memmap.add('ram2', 'RAM', 0x4000000, 32 * 1024) 10 | memmap.add('ram3', 'RAM', 0x5000000, 32 * 1024) 11 | 12 | for CPU, runtime in [('Cortex-M0', 'light-cortex-m0'), 13 | ('Cortex-M0+', 'light-cortex-m0p'), 14 | ('Cortex-M1', 'light-cortex-m1'), 15 | ('Cortex-M3', 'light-cortex-m3'), 16 | ('Cortex-M4', 'light-cortex-m4'), 17 | ('Cortex-M4F', 'light-cortex-m4f')]: 18 | for boot_mem in ['flash1', 'ram1']: 19 | for stack_mem in ['ram1', 'ram2']: 20 | bin = make_simple_project('test_simple_project_%s_%s_%s' % (boot_mem, 21 | stack_mem, 22 | runtime), 23 | runtime, 24 | 'arm-eabi', 25 | CPU, 26 | memmap, 27 | boot_mem, 28 | stack_mem) 29 | syms = nm_symbols(bin) 30 | if check_symbols(syms, memmap, [('Reset_Handler', boot_mem), 31 | ('__heap_start', 'ram1'), 32 | ('__heap_end', 'ram1'), 33 | ('__stack_start', stack_mem), 34 | ('__stack_end', stack_mem)]): 35 | print("With boot_mem = %s stack_mem = %s:" % (boot_mem, stack_mem)) 36 | print("CPU: %s run-time: %s" % (CPU, runtime)) 37 | print("------") 38 | -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/cortex-m/test.ref: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaCore/startup-gen/07391cc41a6c06a688e069878943a716b0226fbb/testsuite/tests/basic_symbol_matching/cortex-m/test.ref -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/cortex-m/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'arm-eabi'", "Test for arm-eabi"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/risc-v32/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import make_simple_project, nm_symbols,\ 2 | check_symbols, MemoryMap 3 | 4 | memmap = MemoryMap() 5 | memmap.add('flash1', 'ROM', 0x0000000, 32 * 1024) 6 | memmap.add('flash2', 'ROM', 0x1000000, 32 * 1024) 7 | memmap.add('flash3', 'ROM', 0x2000000, 32 * 1024) 8 | memmap.add('ram1', 'RAM', 0x3000000, 32 * 1024) 9 | memmap.add('ram2', 'RAM', 0x4000000, 32 * 1024) 10 | memmap.add('ram3', 'RAM', 0x5000000, 32 * 1024) 11 | 12 | for runtime in ['light-rv32i', 13 | 'light-rv32iac', 14 | 'light-rv32im', 15 | 'light-rv32imac', 16 | 'light-rv32imafc', 17 | 'light-rv32imafdc']: 18 | for boot_mem in ['flash1', 'ram1']: 19 | for stack_mem in ['ram1', 'ram2']: 20 | bin = make_simple_project('test_simple_project_%s_%s_%s' % (boot_mem, 21 | stack_mem, 22 | runtime), 23 | runtime, 24 | 'riscv32-elf', 25 | 'RISC-V32', 26 | memmap, 27 | boot_mem, 28 | stack_mem) 29 | syms = nm_symbols(bin) 30 | if check_symbols(syms, memmap, [('_start', boot_mem), 31 | ('__global_pointer$', 'ram1'), 32 | ('__stack_start', stack_mem), 33 | ('__stack_end', stack_mem), 34 | ('__heap_start', 'ram1'), 35 | ('__heap_end', 'ram1')]): 36 | print("With boot_mem = %s stack_mem = %s:" % (boot_mem, stack_mem)) 37 | print("Testing run-time: %s" % runtime) 38 | print("------") 39 | -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/risc-v32/test.ref: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaCore/startup-gen/07391cc41a6c06a688e069878943a716b0226fbb/testsuite/tests/basic_symbol_matching/risc-v32/test.ref -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/risc-v32/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'riscv32-elf'", "Test for riscv32-elf"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/risc-v64/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import make_simple_project, nm_symbols, \ 2 | check_symbols, MemoryMap 3 | 4 | memmap = MemoryMap() 5 | memmap.add('flash1', 'ROM', 0x0000000, 32 * 1024) 6 | memmap.add('flash2', 'ROM', 0x1000000, 32 * 1024) 7 | memmap.add('flash3', 'ROM', 0x2000000, 32 * 1024) 8 | memmap.add('ram1', 'RAM', 0x3000000, 32 * 1024) 9 | memmap.add('ram2', 'RAM', 0x4000000, 32 * 1024) 10 | memmap.add('ram3', 'RAM', 0x5000000, 32 * 1024) 11 | 12 | for runtime in ['light-rv64imac', 13 | 'light-rv64imafc', 14 | 'light-rv64imafdc']: 15 | for boot_mem in ['flash1', 'ram1']: 16 | for stack_mem in ['ram1', 'ram2']: 17 | bin = make_simple_project('test_simple_project_%s_%s_%s' % (boot_mem, 18 | stack_mem, 19 | runtime), 20 | runtime, 21 | 'riscv64-elf', 22 | 'RISC-V64', 23 | memmap, 24 | boot_mem, 25 | stack_mem) 26 | syms = nm_symbols(bin) 27 | if check_symbols(syms, memmap, [('_start', boot_mem), 28 | ('__global_pointer$', 'ram1'), 29 | ('__stack_start', stack_mem), 30 | ('__stack_end', stack_mem), 31 | ('__heap_start', 'ram1'), 32 | ('__heap_end', 'ram1')]): 33 | print("With boot_mem = %s stack_mem = %s:" % (boot_mem, stack_mem)) 34 | print("Testing run-time: %s" % runtime) 35 | print("------") 36 | -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/risc-v64/test.ref: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaCore/startup-gen/07391cc41a6c06a688e069878943a716b0226fbb/testsuite/tests/basic_symbol_matching/risc-v64/test.ref -------------------------------------------------------------------------------- /testsuite/tests/basic_symbol_matching/risc-v64/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'riscv64-elf'", "Test for riscv64-elf"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/prj.gpr: -------------------------------------------------------------------------------- 1 | project Prj is 2 | 3 | for Target use "riscv32-elf"; 4 | for Runtime ("Ada") use "light-rv32imac"; 5 | 6 | for Languages use ("Ada", "Asm_CPP"); 7 | for Source_Dirs use ("src"); 8 | for Object_Dir use "obj"; 9 | for Main use ("main.adb"); 10 | for Create_Missing_Dirs use "True"; 11 | 12 | package Linker is 13 | for Switches ("Ada") use ("-T", "src/linker.ld"); 14 | end Linker; 15 | 16 | type Boot_Mem is ("flash", "ram"); 17 | Boot : Boot_Mem := external ("BOOT_MEM", "flash"); 18 | 19 | package Naming is 20 | for Spec ("Test") use "test-" & Boot & ".ads"; 21 | for Body ("Test") use "test-" & Boot & ".adb"; 22 | end Naming; 23 | 24 | package Device_Configuration is 25 | 26 | for Float_Handling use "soft"; 27 | 28 | -- MEMORY MAP 29 | for Memories use ("flash", "ram"); 30 | 31 | for Boot_Memory use Boot; 32 | 33 | -- flash 34 | for Mem_Kind ("flash") use "ROM"; 35 | for Address ("flash") use "0x20400000"; 36 | for Size ("flash") use "512M"; 37 | 38 | -- ram 39 | for Mem_Kind ("ram") use "RAM"; 40 | for Address ("ram") use "0x80000000"; 41 | for Size ("ram") use "16K"; 42 | 43 | for User_Tag ("hifive1_uart_root") use "0x10013000"; 44 | for User_Tag ("qemu_sifive_test_exit") use "True"; 45 | 46 | end Device_Configuration; 47 | 48 | end Prj; 49 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/src/main.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | 3 | with Test; 4 | 5 | procedure Main is 6 | begin 7 | Put_Line ("=== Test for RISC-V32 HiFive1 ==="); 8 | Test.Check_Memories; 9 | end Main; 10 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/src/test-flash.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | with Interfaces; use Interfaces; 3 | 4 | package body Test is 5 | 6 | RAM_Data : array (1 .. 10) of Unsigned_8 := (others => 42); 7 | RAM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0); 8 | 9 | Heap_Start : Unsigned_32; 10 | pragma Import (C, Heap_Start, "__heap_start"); 11 | 12 | Heap_End : Unsigned_32; 13 | pragma Import (C, Heap_End, "__heap_end"); 14 | 15 | -------------------- 16 | -- Check_Memories -- 17 | -------------------- 18 | 19 | procedure Check_Memories is 20 | Result : Boolean := True; 21 | begin 22 | Put_Line ("Boot memory: FLASH"); 23 | 24 | if not In_RAM (RAM_Data'Address) then 25 | Put_Line ("Wrong address for RAM_Data"); 26 | Result := False; 27 | end if; 28 | 29 | if not In_RAM (RAM_BSS'Address) then 30 | Put_Line ("Wrong address for RAM_Data"); 31 | Result := False; 32 | end if; 33 | 34 | if not In_RAM (Heap_Start'Address) then 35 | Put_Line ("Wrong address for Heap_Start"); 36 | Result := False; 37 | end if; 38 | 39 | if not In_RAM (Heap_End'Address) then 40 | Put_Line ("Wrong address for Heap_End"); 41 | Result := False; 42 | end if; 43 | 44 | -- Check that the data was copied from flash 45 | for Elt of RAM_Data loop 46 | if Elt /= 42 then 47 | Put_Line ("Wrong value for RAM_Data"); 48 | Result := False; 49 | end if; 50 | end loop; 51 | 52 | -- Check that the bss was cleared 53 | for Elt of RAM_BSS loop 54 | if Elt /= 0 then 55 | Put_Line ("Wrong value for RAM_BSS"); 56 | Result := False; 57 | end if; 58 | end loop; 59 | 60 | if Result then 61 | Put_Line ("PASS: Memories checks"); 62 | else 63 | Put_Line ("FAIL: Memories checks"); 64 | end if; 65 | end Check_Memories; 66 | 67 | end Test; 68 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/src/test-flash.ads: -------------------------------------------------------------------------------- 1 | with System; use System; 2 | with System.Storage_Elements; use System.Storage_Elements; 3 | 4 | package Test is 5 | 6 | procedure Check_Memories; 7 | 8 | function In_RAM (Addr : System.Address) return Boolean 9 | is (To_Integer (Addr) in 16#80000000# .. 16#80000000# + 16 * 1024); 10 | 11 | function In_FLASH (Addr : System.Address) return Boolean 12 | is (To_Integer (Addr) in 16#20400000# .. 16#20400000# + 512 * 1024 * 1024); 13 | 14 | end Test; 15 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/src/test-ram.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | with Interfaces; use Interfaces; 3 | 4 | package body Test is 5 | 6 | RAM_Data : array (1 .. 10) of Unsigned_8 := (others => 42); 7 | 8 | RAM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0); 9 | 10 | Heap_Start : Unsigned_32; 11 | pragma Import (C, Heap_Start, "__heap_start"); 12 | 13 | Heap_End : Unsigned_32; 14 | pragma Import (C, Heap_End, "__heap_end"); 15 | 16 | -------------------- 17 | -- Check_Memories -- 18 | -------------------- 19 | 20 | procedure Check_Memories is 21 | Result : Boolean := True; 22 | begin 23 | Put_Line ("Boot memory: RAM"); 24 | 25 | if not In_RAM (RAM_Data'Address) then 26 | Put_Line ("Wrong address for RAM_Data"); 27 | Result := False; 28 | end if; 29 | 30 | if not In_RAM (RAM_BSS'Address) then 31 | Put_Line ("Wrong address for Heap_End"); 32 | Result := False; 33 | end if; 34 | 35 | if not In_RAM (Heap_Start'Address) then 36 | Put_Line ("Wrong address for Heap_Start"); 37 | Result := False; 38 | end if; 39 | 40 | if not In_RAM (Heap_End'Address) then 41 | Put_Line ("Wrong address for Heap_End"); 42 | Result := False; 43 | end if; 44 | 45 | -- Check that the bss was cleared 46 | for Elt of RAM_BSS loop 47 | if Elt /= 0 then 48 | Put_Line ("Wrong value for RAM_BSS"); 49 | Result := False; 50 | end if; 51 | end loop; 52 | 53 | if Result then 54 | Put_Line ("PASS: Memories checks"); 55 | else 56 | Put_Line ("FAIL: Memories checks"); 57 | end if; 58 | end Check_Memories; 59 | 60 | end Test; 61 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/src/test-ram.ads: -------------------------------------------------------------------------------- 1 | with Interfaces; use Interfaces; 2 | with System; use System; 3 | with System.Storage_Elements; use System.Storage_Elements; 4 | 5 | package Test is 6 | 7 | Start : constant Unsigned_32; 8 | pragma Import (C, Start, "_start"); 9 | 10 | -- These few instructions inserted in the flash_rodata sectioareis supposed 11 | -- to be allocated at the start of flash memory, and will jump to the _start 12 | -- symbol. 13 | Boot_Vect : constant array (1 .. 4) of Address := 14 | (System'To_Address (2#00000000000000000000_00001_0010111#), -- auipc ra,0x0 15 | System'To_Address (2#000000001100_00001_010_00001_0000011#), -- lw ra,12(ra) 16 | System'To_Address (2#000000000000_00001_000_00001_1100111#), -- jalr ra 17 | Start'Address) 18 | with Linker_Section => ".flash_rodata"; 19 | 20 | procedure Check_Memories; 21 | 22 | function In_RAM (Addr : System.Address) return Boolean 23 | is (To_Integer (Addr) in 16#80000000# .. 16#80000000# + 16 * 1024); 24 | 25 | function In_FLASH (Addr : System.Address) return Boolean 26 | is (To_Integer (Addr) in 16#20400000# .. 16#20400000# + 512 * 1024 * 1024); 27 | 28 | end Test; 29 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, gprbuild, runcross, contents_of 2 | 3 | 4 | for boot_mem in ['flash', 'ram']: 5 | 6 | run_tool(['-P', 'prj.gpr', '-XBOOT_MEM=%s' % boot_mem, 7 | '-s', 'src/crt0.S', '-l', 'src/linker.ld']) 8 | 9 | gprbuild(['-f', '-P', 'prj.gpr', '-XBOOT_MEM=%s' % boot_mem]) 10 | 11 | runcross('riscv32-elf', 'qemu-hifive1', 'obj/main', output='runcross.out') 12 | 13 | print(contents_of('runcross.out')) 14 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/test.ref: -------------------------------------------------------------------------------- 1 | === Test for RISC-V32 HiFive1 === 2 | Boot memory: FLASH 3 | PASS: Memories checks 4 | === Test for RISC-V32 HiFive1 === 5 | Boot memory: RAM 6 | PASS: Memories checks 7 | -------------------------------------------------------------------------------- /testsuite/tests/boards/hifive1/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'riscv32-elf'", "Test for riscv32-elf"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/prj.gpr: -------------------------------------------------------------------------------- 1 | project Prj is 2 | 3 | for Target use "riscv64-elf"; 4 | for Runtime ("Ada") use "light-rv64imafc"; 5 | 6 | for Languages use ("Ada", "Asm_CPP"); 7 | for Source_Dirs use ("src"); 8 | for Object_Dir use "obj"; 9 | for Main use ("main.adb"); 10 | for Create_Missing_Dirs use "True"; 11 | 12 | package Linker is 13 | for Switches ("Ada") use ("-T", "src/linker.ld"); 14 | end Linker; 15 | 16 | package Device_Configuration is 17 | 18 | for Float_Handling use "hard"; 19 | 20 | -- MEMORY MAP 21 | for Memories use ("ram"); 22 | 23 | for Boot_Memory use "ram"; 24 | 25 | -- ram 26 | for Mem_Kind ("ram") use "RAM"; 27 | for Address ("ram") use "0x80000000"; 28 | for Size ("ram") use "128M"; 29 | 30 | for User_Tag ("polarfire_lsr_root") use "0x20000000"; 31 | for User_Tag ("qemu_polarfire_test_exit") use "True"; 32 | for User_Tag ("only_allow_hart_id") use "1"; 33 | end Device_Configuration; 34 | 35 | end Prj; 36 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/src/main.adb: -------------------------------------------------------------------------------- 1 | with Interfaces; use Interfaces; 2 | with System; 3 | with System.Machine_Code; use System.Machine_Code; 4 | 5 | with Ada.Text_IO; use Ada.Text_IO; 6 | 7 | with Test; 8 | 9 | procedure Main is 10 | begin 11 | Put_Line ("=== Test for RISC-V64 PolarFire SOC ==="); 12 | 13 | -- The FPU should be enabled here, do a simple float operation here to 14 | -- check. 15 | Asm ("fadd.s f0, f1, f0", 16 | Volatile => True); 17 | 18 | Test.Check_Memories; 19 | end Main; 20 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/src/test.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | with Interfaces; use Interfaces; 3 | 4 | package body Test is 5 | 6 | RAM_Data : array (1 .. 10) of Unsigned_8 := (others => 42); 7 | 8 | RAM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0); 9 | 10 | Heap_Start : Unsigned_32; 11 | pragma Import (C, Heap_Start, "__heap_start"); 12 | 13 | Heap_End : Unsigned_32; 14 | pragma Import (C, Heap_End, "__heap_end"); 15 | 16 | -------------------- 17 | -- Check_Memories -- 18 | -------------------- 19 | 20 | procedure Check_Memories is 21 | Result : Boolean := True; 22 | begin 23 | Put_Line ("Boot memory: RAM"); 24 | 25 | if not In_RAM (RAM_Data'Address) then 26 | Put_Line ("Wrong address for RAM_Data"); 27 | Result := False; 28 | end if; 29 | 30 | if not In_RAM (RAM_BSS'Address) then 31 | Put_Line ("Wrong address for Heap_End"); 32 | Result := False; 33 | end if; 34 | 35 | if not In_RAM (Heap_Start'Address) then 36 | Put_Line ("Wrong address for Heap_Start"); 37 | Result := False; 38 | end if; 39 | 40 | if not In_RAM (Heap_End'Address) then 41 | Put_Line ("Wrong address for Heap_End"); 42 | Result := False; 43 | end if; 44 | 45 | -- Check that the bss was cleared 46 | for Elt of RAM_BSS loop 47 | if Elt /= 0 then 48 | Put_Line ("Wrong value for RAM_BSS"); 49 | Result := False; 50 | end if; 51 | end loop; 52 | 53 | if Result then 54 | Put_Line ("PASS: Memories checks"); 55 | else 56 | Put_Line ("FAIL: Memories checks"); 57 | end if; 58 | end Check_Memories; 59 | 60 | end Test; 61 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/src/test.ads: -------------------------------------------------------------------------------- 1 | with Interfaces; use Interfaces; 2 | with System; use System; 3 | with System.Storage_Elements; use System.Storage_Elements; 4 | 5 | package Test is 6 | 7 | procedure Check_Memories; 8 | 9 | function In_RAM (Addr : System.Address) return Boolean 10 | is (To_Integer (Addr) in 16#80000000# .. 16#80000000# + 128 * 1024 * 1024); 11 | 12 | end Test; 13 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, gprbuild, runcross, contents_of 2 | 3 | run_tool(['-P', 'prj.gpr', '-s', 'src/crt0.S', '-l', 'src/linker.ld']) 4 | 5 | gprbuild(['-f', '-P', 'prj.gpr']) 6 | 7 | runcross('riscv64-elf', 'qemu-polarfiresoc', 'obj/main', output='runcross.out') 8 | 9 | print(contents_of('runcross.out')) 10 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/test.ref: -------------------------------------------------------------------------------- 1 | === Test for RISC-V64 PolarFire SOC === 2 | Boot memory: RAM 3 | PASS: Memories checks 4 | -------------------------------------------------------------------------------- /testsuite/tests/boards/polarfiresoc/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'riscv64-elf'", "Test for riscv64-elf"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/prj.gpr: -------------------------------------------------------------------------------- 1 | project Prj is 2 | 3 | for Target use "arm-eabi"; 4 | for Runtime ("Ada") use "light-cortex-m4f"; 5 | 6 | for Languages use ("Ada", "Asm_CPP"); 7 | for Source_Dirs use ("src"); 8 | for Object_Dir use "obj"; 9 | for Main use ("main.adb"); 10 | for Create_Missing_Dirs use "True"; 11 | 12 | package Linker is 13 | for Switches ("Ada") use ("-T", "src/linker.ld"); 14 | end Linker; 15 | 16 | type Boot_Mem is ("flash", "sram", "ccm"); 17 | Boot : Boot_Mem := external ("BOOT_MEM", "flash"); 18 | 19 | type Stack_Mem is ("sram", "ccm"); 20 | Stack: Stack_Mem := external ("STACK_MEM", "sram"); 21 | 22 | package Naming is 23 | case Boot is 24 | when "sram" | "ccm" => 25 | for Spec ("Test") use "test-ram.ads"; 26 | when others => 27 | for Spec ("Test") use "test-rom.ads"; 28 | end case; 29 | 30 | for Body ("Test") use "test-" & Boot & ".adb"; 31 | end Naming; 32 | 33 | package Device_Configuration is 34 | for Float_Handling use "hard"; 35 | for Number_Of_Interrupts use "82"; 36 | 37 | -- MEMORY MAP 38 | for Memories use ("flash", "sram", "ccm"); 39 | 40 | for Boot_Memory use Boot; 41 | 42 | for Main_Stack_Memory use Stack; 43 | 44 | -- flash 45 | for Mem_Kind ("flash") use "ROM"; 46 | for Address ("flash") use "16#08000000#"; 47 | for Size ("flash") use "1024K"; 48 | 49 | -- sram 50 | for Mem_Kind ("sram") use "RAM"; 51 | for Address ("sram") use "16#20000000#"; 52 | for Size ("sram") use "128K"; 53 | 54 | -- ccm 55 | for Mem_Kind ("ccm") use "RAM"; 56 | for Address ("ccm") use "16#10000000#"; 57 | for Size ("ccm") use "64K"; 58 | 59 | end Device_Configuration; 60 | 61 | end Prj; 62 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/src/main.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | 3 | with Test; 4 | 5 | procedure Main is 6 | begin 7 | Put_Line ("=== Test for STM32F407 disco ==="); 8 | Test.Check_Memories; 9 | end Main; 10 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/src/test-ccm.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | with Interfaces; use Interfaces; 3 | 4 | package body Test is 5 | 6 | SRAM_Data : array (1 .. 10) of Unsigned_8 := (others => 42) 7 | with Linker_Section => ".sram_data"; 8 | 9 | SRAM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0) 10 | with Linker_Section => ".sram_bss"; 11 | 12 | SRAM_Heap_Start : Unsigned_32; 13 | pragma Import (C, SRAM_Heap_Start, "__sram_heap_start"); 14 | 15 | SRAM_Heap_End : Unsigned_32; 16 | pragma Import (C, SRAM_Heap_End, "__sram_heap_end"); 17 | 18 | CCM_Data : array (1 .. 10) of Unsigned_8 := (others => 42); 19 | CCM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0); 20 | 21 | Heap_Start : Unsigned_32; 22 | pragma Import (C, Heap_Start, "__heap_start"); 23 | 24 | Heap_End : Unsigned_32; 25 | pragma Import (C, Heap_End, "__heap_end"); 26 | 27 | -------------------- 28 | -- Check_Memories -- 29 | -------------------- 30 | 31 | procedure Check_Memories is 32 | Result : Boolean := True; 33 | begin 34 | Put_Line ("Boot memory: CCM"); 35 | 36 | if not In_CCM (CCM_Data'Address) then 37 | Put_Line ("Wrong address for CCM_Data"); 38 | Result := False; 39 | end if; 40 | 41 | if not In_CCM (CCM_BSS'Address) then 42 | Put_Line ("Wrong address for CCM_Data"); 43 | Result := False; 44 | end if; 45 | 46 | if not In_SRAM (SRAM_Heap_Start'Address) then 47 | Put_Line ("Wrong address for CCM_Heap_Start"); 48 | Result := False; 49 | end if; 50 | 51 | if not In_SRAM (SRAM_Heap_End'Address) then 52 | Put_Line ("Wrong address for CCM_Heap_End"); 53 | Result := False; 54 | end if; 55 | 56 | if not In_SRAM (SRAM_Data'Address) then 57 | Put_Line ("Wrong address for SRAM_Data"); 58 | Result := False; 59 | end if; 60 | 61 | if not In_SRAM (SRAM_BSS'Address) then 62 | Put_Line ("Wrong address for SRAM_Data"); 63 | Result := False; 64 | end if; 65 | 66 | if not In_CCM (Heap_Start'Address) then 67 | Put_Line ("Wrong address for Heap_Start"); 68 | Result := False; 69 | end if; 70 | 71 | if not In_CCM (Heap_End'Address) then 72 | Put_Line ("Wrong address for Heap_End"); 73 | Result := False; 74 | end if; 75 | 76 | -- Check that the bss was cleared 77 | for Elt of SRAM_BSS loop 78 | if Elt /= 0 then 79 | Put_Line ("Wrong value for SRAM_BSS"); 80 | Result := False; 81 | end if; 82 | end loop; 83 | for Elt of CCM_BSS loop 84 | if Elt /= 0 then 85 | Put_Line ("Wrong value for CCM_BSS"); 86 | Result := False; 87 | end if; 88 | end loop; 89 | 90 | if Result then 91 | Put_Line ("PASS: Memories checks"); 92 | else 93 | Put_Line ("FAIL: Memories checks"); 94 | end if; 95 | end Check_Memories; 96 | 97 | end Test; 98 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/src/test-flash.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | with Interfaces; use Interfaces; 3 | 4 | package body Test is 5 | 6 | CCM_Data : array (1 .. 10) of Unsigned_8 := (others => 42) 7 | with Linker_Section => ".ccm_data"; 8 | CCM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0) 9 | with Linker_Section => ".ccm_bss"; 10 | 11 | CCM_Heap_Start : Unsigned_32; 12 | pragma Import (C, CCM_Heap_Start, "__ccm_heap_start"); 13 | 14 | CCM_Heap_End : Unsigned_32; 15 | pragma Import (C, CCM_Heap_End, "__ccm_heap_end"); 16 | 17 | SRAM_Data : array (1 .. 10) of Unsigned_8 := (others => 42); 18 | SRAM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0); 19 | 20 | Heap_Start : Unsigned_32; 21 | pragma Import (C, Heap_Start, "__heap_start"); 22 | 23 | Heap_End : Unsigned_32; 24 | pragma Import (C, Heap_End, "__heap_end"); 25 | 26 | -------------------- 27 | -- Check_Memories -- 28 | -------------------- 29 | 30 | procedure Check_Memories is 31 | Result : Boolean := True; 32 | begin 33 | Put_Line ("Boot memory: FLASH"); 34 | 35 | if not In_CCM (CCM_Data'Address) then 36 | Put_Line ("Wrong address for CCM_Data"); 37 | Result := False; 38 | end if; 39 | 40 | if not In_CCM (CCM_BSS'Address) then 41 | Put_Line ("Wrong address for CCM_Data"); 42 | Result := False; 43 | end if; 44 | 45 | if not In_CCM (CCM_Heap_Start'Address) then 46 | Put_Line ("Wrong address for CCM_Heap_Start"); 47 | Result := False; 48 | end if; 49 | 50 | if not In_CCM (CCM_Heap_End'Address) then 51 | Put_Line ("Wrong address for CCM_Heap_End"); 52 | Result := False; 53 | end if; 54 | 55 | if not In_SRAM (SRAM_Data'Address) then 56 | Put_Line ("Wrong address for SRAM_Data"); 57 | Result := False; 58 | end if; 59 | 60 | if not In_SRAM (SRAM_BSS'Address) then 61 | Put_Line ("Wrong address for SRAM_Data"); 62 | Result := False; 63 | end if; 64 | 65 | if not In_SRAM (Heap_Start'Address) then 66 | Put_Line ("Wrong address for Heap_Start"); 67 | Result := False; 68 | end if; 69 | 70 | if not In_SRAM (Heap_End'Address) then 71 | Put_Line ("Wrong address for Heap_End"); 72 | Result := False; 73 | end if; 74 | 75 | -- Check that the data was copied from flash 76 | for Elt of SRAM_Data loop 77 | if Elt /= 42 then 78 | Put_Line ("Wrong value for SRAM_Data"); 79 | Result := False; 80 | end if; 81 | end loop; 82 | for Elt of CCM_Data loop 83 | if Elt /= 42 then 84 | Put_Line ("Wrong value for CCM_Data"); 85 | Result := False; 86 | end if; 87 | end loop; 88 | 89 | -- Check that the bss was cleared 90 | for Elt of SRAM_BSS loop 91 | if Elt /= 0 then 92 | Put_Line ("Wrong value for SRAM_BSS"); 93 | Result := False; 94 | end if; 95 | end loop; 96 | for Elt of CCM_BSS loop 97 | if Elt /= 0 then 98 | Put_Line ("Wrong value for CCM_BSS"); 99 | Result := False; 100 | end if; 101 | end loop; 102 | 103 | if Result then 104 | Put_Line ("PASS: Memories checks"); 105 | else 106 | Put_Line ("FAIL: Memories checks"); 107 | end if; 108 | end Check_Memories; 109 | 110 | end Test; 111 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/src/test-ram.ads: -------------------------------------------------------------------------------- 1 | with Interfaces; use Interfaces; 2 | with System; use System; 3 | with System.Storage_Elements; use System.Storage_Elements; 4 | 5 | package Test is 6 | 7 | Start : constant Unsigned_32; 8 | pragma Import (C, Start, "Reset_Handler"); 9 | 10 | -- This vector inserted in the flash_rodata section is supposed to be 11 | -- allocated at the address zero, and will be used by QEMU to find the 12 | -- reset PC address and stack pointer. 13 | Boot_Vect : constant array (1 .. 2) of Address := 14 | (Null_Address, -- Stack pointer 15 | Start'Address) -- Reset address 16 | with Linker_Section => ".flash_rodata"; 17 | 18 | procedure Check_Memories; 19 | 20 | function In_CCM (Addr : System.Address) return Boolean 21 | is (To_Integer (Addr) in 16#10000000# .. 16#10000000# + 64 * 1024); 22 | 23 | function In_SRAM (Addr : System.Address) return Boolean 24 | is (To_Integer (Addr) in 16#20000000# .. 16#20000000# + 128 * 1024); 25 | 26 | function In_FLASH (Addr : System.Address) return Boolean 27 | is (To_Integer (Addr) in 16#08000000# .. 16#08000000# + 1024 * 1024); 28 | 29 | end Test; 30 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/src/test-rom.ads: -------------------------------------------------------------------------------- 1 | with System; use System; 2 | with System.Storage_Elements; use System.Storage_Elements; 3 | 4 | package Test is 5 | 6 | procedure Check_Memories; 7 | 8 | function In_CCM (Addr : System.Address) return Boolean 9 | is (To_Integer (Addr) in 16#10000000# .. 16#10000000# + 64 * 1024); 10 | 11 | function In_SRAM (Addr : System.Address) return Boolean 12 | is (To_Integer (Addr) in 16#20000000# .. 16#20000000# + 128 * 1024); 13 | 14 | function In_FLASH (Addr : System.Address) return Boolean 15 | is (To_Integer (Addr) in 16#08000000# .. 16#08000000# + 1024 * 1024); 16 | 17 | end Test; 18 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/src/test-sram.adb: -------------------------------------------------------------------------------- 1 | with Ada.Text_IO; use Ada.Text_IO; 2 | with Interfaces; use Interfaces; 3 | 4 | package body Test is 5 | 6 | CCM_Data : array (1 .. 10) of Unsigned_8 := (others => 42) 7 | with Linker_Section => ".ccm_data"; 8 | 9 | CCM_BSS: array (1 .. 10) of Unsigned_8 := (others => 0) 10 | with Linker_Section => ".ccm_bss"; 11 | 12 | CCM_Heap_Start : Unsigned_32; 13 | pragma Import (C, CCM_Heap_Start, "__ccm_heap_start"); 14 | 15 | CCM_Heap_End : Unsigned_32; 16 | pragma Import (C, CCM_Heap_End, "__ccm_heap_end"); 17 | 18 | SRAM_Data : array (1 .. 10) of Unsigned_8 := (others => 42); 19 | 20 | SRAM_BSS : array (1 .. 10) of Unsigned_8 := (others => 0); 21 | 22 | Heap_Start : Unsigned_32; 23 | pragma Import (C, Heap_Start, "__heap_start"); 24 | 25 | Heap_End : Unsigned_32; 26 | pragma Import (C, Heap_End, "__heap_end"); 27 | 28 | -------------------- 29 | -- Check_Memories -- 30 | -------------------- 31 | 32 | procedure Check_Memories is 33 | Result : Boolean := True; 34 | begin 35 | Put_Line ("Boot memory: SRAM"); 36 | 37 | if not In_CCM (CCM_Data'Address) then 38 | Put_Line ("Wrong address for CCM_Data"); 39 | Result := False; 40 | end if; 41 | 42 | if not In_CCM (CCM_BSS'Address) then 43 | Put_Line ("Wrong address for CCM_BSS"); 44 | Result := False; 45 | end if; 46 | 47 | if not In_CCM (CCM_Heap_Start'Address) then 48 | Put_Line ("Wrong address for CCM_Heap_Start"); 49 | Result := False; 50 | end if; 51 | 52 | if not In_CCM (CCM_Heap_End'Address) then 53 | Put_Line ("Wrong address for CCM_Heap_End"); 54 | Result := False; 55 | end if; 56 | 57 | if not In_SRAM (SRAM_Data'Address) then 58 | Put_Line ("Wrong address for SRAM_Data"); 59 | Result := False; 60 | end if; 61 | 62 | if not In_SRAM (SRAM_BSS'Address) then 63 | Put_Line ("Wrong address for Heap_End"); 64 | Result := False; 65 | end if; 66 | 67 | if not In_SRAM (Heap_Start'Address) then 68 | Put_Line ("Wrong address for Heap_Start"); 69 | Result := False; 70 | end if; 71 | 72 | if not In_SRAM (Heap_End'Address) then 73 | Put_Line ("Wrong address for Heap_End"); 74 | Result := False; 75 | end if; 76 | 77 | -- Check that the bss was cleared 78 | for Elt of SRAM_BSS loop 79 | if Elt /= 0 then 80 | Put_Line ("Wrong value for SRAM_BSS"); 81 | Result := False; 82 | end if; 83 | end loop; 84 | for Elt of CCM_BSS loop 85 | if Elt /= 0 then 86 | Put_Line ("Wrong value for CCM_BSS"); 87 | Result := False; 88 | end if; 89 | end loop; 90 | 91 | if Result then 92 | Put_Line ("PASS: Memories checks"); 93 | else 94 | Put_Line ("FAIL: Memories checks"); 95 | end if; 96 | end Check_Memories; 97 | 98 | end Test; 99 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, gprbuild, runcross, contents_of 2 | 3 | 4 | for boot_mem in ['flash', 'sram', 'ccm']: 5 | for stack_mem in ['sram', 'ccm']: 6 | print("testing -> boot:%s stack:%s" % (boot_mem, stack_mem)) 7 | 8 | run_tool(['-P', 'prj.gpr', '-XBOOT_MEM=%s' % boot_mem, 9 | '-XSTACK_MEM=%s' % stack_mem, 10 | '-s', 'src/crt0.S', '-l', 'src/linker.ld']) 11 | 12 | gprbuild(['-f', '-P', 'prj.gpr', '-XBOOT_MEM=%s' % boot_mem]) 13 | 14 | runcross('arm-elf', 'qemu-stm32', 'obj/main', output='runcross.out') 15 | 16 | print(contents_of('runcross.out')) 17 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/test.ref: -------------------------------------------------------------------------------- 1 | testing -> boot:flash stack:sram 2 | === Test for STM32F407 disco === 3 | Boot memory: FLASH 4 | PASS: Memories checks 5 | testing -> boot:flash stack:ccm 6 | === Test for STM32F407 disco === 7 | Boot memory: FLASH 8 | PASS: Memories checks 9 | testing -> boot:sram stack:sram 10 | === Test for STM32F407 disco === 11 | Boot memory: SRAM 12 | PASS: Memories checks 13 | testing -> boot:sram stack:ccm 14 | === Test for STM32F407 disco === 15 | Boot memory: SRAM 16 | PASS: Memories checks 17 | testing -> boot:ccm stack:sram 18 | === Test for STM32F407 disco === 19 | Boot memory: CCM 20 | PASS: Memories checks 21 | testing -> boot:ccm stack:ccm 22 | === Test for STM32F407 disco === 23 | Boot memory: CCM 24 | PASS: Memories checks 25 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'arm-eabi'", "Test for arm-eabi"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco_C/prj.gpr: -------------------------------------------------------------------------------- 1 | project Prj is 2 | 3 | for Target use "arm-eabi"; 4 | for Languages use ("C", "Asm_CPP"); 5 | for Source_Dirs use ("src"); 6 | for Object_Dir use "obj"; 7 | for Main use ("main.c"); 8 | for Create_Missing_Dirs use "True"; 9 | 10 | Common_Required_Switches := ("-mlittle-endian", "-mthumb", "-mfloat-abi=hard", "-mcpu=cortex-m4", "-mfpu=fpv4-sp-d16"); 11 | package Compiler is 12 | 13 | for Leading_Required_Switches ("C") use Common_Required_Switches; 14 | for Leading_Required_Switches ("Asm_CPP") use Common_Required_Switches; 15 | end Compiler; 16 | 17 | package Linker is 18 | for Required_Switches use Common_Required_Switches; 19 | for Switches ("C") use ("-T", "src/linker.ld", 20 | "-u__libc_init_array", 21 | "-u__libc_fini_array", 22 | "-Wl,--gc-sections"); 23 | end Linker; 24 | 25 | package Device_Configuration is 26 | for CPU_Name use "cortex-m4f"; 27 | for Float_Handling use "hard"; 28 | for Number_Of_Interrupts use "82"; 29 | 30 | -- MEMORY MAP 31 | for Memories use ("flash", "sram", "ccm"); 32 | for Boot_Memory use "flash"; 33 | for Main_Stack_Memory use "sram"; 34 | 35 | -- flash 36 | for Mem_Kind ("flash") use "ROM"; 37 | for Address ("flash") use "16#08000000#"; 38 | for Size ("flash") use "1024K"; 39 | 40 | -- sram 41 | for Mem_Kind ("sram") use "RAM"; 42 | for Address ("sram") use "16#20000000#"; 43 | for Size ("sram") use "128K"; 44 | 45 | -- ccm 46 | for Mem_Kind ("ccm") use "RAM"; 47 | for Address ("ccm") use "16#10000000#"; 48 | for Size ("ccm") use "64K"; 49 | 50 | end Device_Configuration; 51 | 52 | end Prj; 53 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco_C/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define AIRCR (*(volatile uint32_t*)0xe000ed0cUL) 4 | #define SYSRESETREQ (1<<2) 5 | #define VECTKEY (0x05fa0000UL) 6 | #define VECTKEY_MASK (0x0000ffffUL) 7 | 8 | void print(const char* str) 9 | { 10 | int len = 0; 11 | asm volatile ( 12 | " mov r0, %[reason] \n" 13 | " mov r1, %[arg] \n" 14 | " bkpt %[swi] \n" 15 | : 16 | : [reason] "r" (0x04), [arg] "r" (str), [swi] "i" (0xAB) 17 | : "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" 18 | ); 19 | } 20 | 21 | void _exit(int val) { 22 | while (1) { 23 | AIRCR = (AIRCR & VECTKEY_MASK) | VECTKEY | SYSRESETREQ; 24 | } 25 | } 26 | 27 | void before_main(void) __attribute__((constructor)); 28 | void after_main(void) __attribute__((destructor)); 29 | 30 | void before_main(void) 31 | { 32 | print("before_main()\n"); 33 | } 34 | 35 | void after_main(void) 36 | { 37 | print("after_main()\n"); 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | print("main()\n"); 42 | return -1; 43 | } 44 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco_C/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, gprbuild, runcross, contents_of 2 | 3 | 4 | run_tool(['-P', 'prj.gpr', '-s', 'src/crt0.S', '-l', 'src/linker.ld']) 5 | 6 | gprbuild(['-f', '-P', 'prj.gpr']) 7 | 8 | runcross('arm-elf', 'qemu-stm32', 'obj/main', output='runcross.out') 9 | 10 | print(contents_of('runcross.out')) 11 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco_C/test.ref: -------------------------------------------------------------------------------- 1 | before_main() 2 | main() 3 | after_main() 4 | -------------------------------------------------------------------------------- /testsuite/tests/boards/stm32f407_disco_C/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [SKIP, "env.target.triplet != 'arm-eabi'", "Test for arm-eabi"] 4 | -------------------------------------------------------------------------------- /testsuite/tests/gpr_tool/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | Tool := External ("GPR_TOOL", "undefined"); 4 | 5 | package Device_Configuration is 6 | 7 | for CPU_Name use Tool; 8 | 9 | for Memories use ("rom"); 10 | 11 | for Boot_Memory use "rom"; 12 | 13 | for Mem_Kind ("rom") use "ROM"; 14 | for Address ("rom") use "0"; 15 | for Size ("rom") use "0x100"; 16 | 17 | end Device_Configuration; 18 | 19 | end Spec; 20 | -------------------------------------------------------------------------------- /testsuite/tests/gpr_tool/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | from testsuite_support.utils import run_tool 3 | 4 | # If GPR_TOOL is not defined, we should get the default value: startup-gen 5 | run_tool(['-P', 'spec.gpr']) 6 | 7 | # Define GPR_TOOL in the environment variables 8 | os.environ["GPR_TOOL"] = "defined_in_env" 9 | 10 | # If GPR_TOOL is defined on the command line it should have priority over 11 | # environment variable and default value. 12 | run_tool(['-P', 'spec.gpr', '-XGPR_TOOL=defined_on_cmd_line']) 13 | 14 | # If GPR_TOOL is defined in environment variable, but not on the command line 15 | # it should have priority over default value. 16 | run_tool(['-P', 'spec.gpr']) 17 | -------------------------------------------------------------------------------- /testsuite/tests/gpr_tool/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Unknown CPU name: 'startup-gen' 3 | command failed: 4 | Error: Unknown CPU name: 'defined_on_cmd_line' 5 | command failed: 6 | Error: Unknown CPU name: 'defined_in_env' 7 | -------------------------------------------------------------------------------- /testsuite/tests/gpr_tool/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_addr/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1", "rom2", "rom3", "rom4"); 8 | 9 | for Boot_Memory use "rom1"; 10 | 11 | for Mem_Kind ("rom1") use "ROM"; 12 | for Address ("rom1") use "-1"; 13 | for Size ("rom1") use "0x100"; 14 | 15 | for Mem_Kind ("rom2") use "ROM"; 16 | for Address ("rom2") use "0x0bad!"; 17 | for Size ("rom2") use "0x100"; 18 | 19 | for Mem_Kind ("rom3") use "ROM"; 20 | for Address ("rom3") use "19bad!87"; 21 | for Size ("rom3") use "0x100"; 22 | 23 | for Mem_Kind ("rom4") use "ROM"; 24 | for Address ("rom4") use "bad!0"; 25 | for Size ("rom4") use "0x100"; 26 | 27 | end Device_Configuration; 28 | 29 | end Spec; 30 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_addr/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_addr/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Invalid memory address expression for 'rom1' : '-1' 3 | Error: Invalid memory address expression for 'rom2' : '0x0bad!' 4 | Error: Invalid memory address expression for 'rom3' : '19bad!87' 5 | Error: Invalid memory address expression for 'rom4' : 'bad!0' 6 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_addr/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_arch/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | for Runtime ("Ada") use "light-cortex-m0"; 4 | 5 | package Device_Configuration is 6 | for CPU_Name use "cortex-m4f"; 7 | 8 | for Memories use ("rom1"); 9 | for Boot_Memory use "rom1"; 10 | for Mem_Kind ("rom1") use "RAM"; 11 | for Address ("rom1") use "0x10"; 12 | for Size ("rom1") use "0x100"; 13 | end Device_Configuration; 14 | 15 | end Spec; 16 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_arch/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_arch/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Mismatch between CPU_Name (cortex-m4f) and run-time (light-cortex-m0) attributes 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_arch/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_boot_mem/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1"); 8 | 9 | for Boot_Memory use "bad!"; 10 | 11 | for Mem_Kind ("rom1") use "ROM"; 12 | for Address ("rom1") use "0x10"; 13 | for Size ("rom1") use "0x100"; 14 | 15 | end Device_Configuration; 16 | 17 | end Spec; 18 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_boot_mem/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_boot_mem/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Invalid boot memory : bad! 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_boot_mem/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_mem_kind/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1"); 8 | for Boot_Memory use "rom1"; 9 | 10 | for Mem_Kind ("rom1") use "PLOP"; 11 | for Address ("rom1") use "0x10"; 12 | for Size ("rom1") use "0x100"; 13 | 14 | end Device_Configuration; 15 | 16 | end Spec; 17 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_mem_kind/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_mem_kind/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Invalid memory kind: 'PLOP' 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_mem_kind/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_size/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1", "rom2", "rom3", "rom4"); 8 | 9 | for Main_Stack_Size use "-1"; 10 | 11 | for Boot_Memory use "rom1"; 12 | 13 | for Mem_Kind ("rom1") use "ROM"; 14 | for Size ("rom1") use "-1"; 15 | for Address ("rom1") use "0x100"; 16 | 17 | for Mem_Kind ("rom2") use "ROM"; 18 | for Size ("rom2") use "0x0bad!"; 19 | for Address ("rom2") use "0x100"; 20 | 21 | for Mem_Kind ("rom3") use "ROM"; 22 | for Size ("rom3") use "19bad!87"; 23 | for Address ("rom3") use "0x100"; 24 | 25 | for Mem_Kind ("rom4") use "ROM"; 26 | for Size ("rom4") use "bad!0"; 27 | for Address ("rom4") use "0x100"; 28 | 29 | end Device_Configuration; 30 | 31 | end Spec; 32 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_size/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_size/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Invalid memory size expression for 'rom1' : '-1' 3 | Error: Invalid memory size expression for 'rom2' : '0x0bad!' 4 | Error: Invalid memory size expression for 'rom3' : '19bad!87' 5 | Error: Invalid memory size expression for 'rom4' : 'bad!0' 6 | Error: Invalid main stack size : -1 7 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_size/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1", "ram1"); 8 | 9 | for Boot_Memory use "rom1"; 10 | 11 | for Main_Stack_Memory use "plop"; 12 | 13 | for Mem_Kind ("rom1") use "ROM"; 14 | for Address ("rom1") use "0x10"; 15 | for Size ("rom1") use "0x100"; 16 | 17 | for Mem_Kind ("ram1") use "RAM"; 18 | for Address ("ram1") use "0x1000"; 19 | for Size ("ram1") use "0x100"; 20 | 21 | end Device_Configuration; 22 | 23 | end Spec; 24 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr', '-l', 'link.ld']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Undefined memory used for main stack: 'plop' 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem_kind/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1", "ram1"); 8 | 9 | for Boot_Memory use "rom1"; 10 | 11 | for Main_Stack_Memory use "rom1"; 12 | 13 | for Mem_Kind ("rom1") use "ROM"; 14 | for Address ("rom1") use "0x10"; 15 | for Size ("rom1") use "0x100"; 16 | 17 | for Mem_Kind ("ram1") use "RAM"; 18 | for Address ("ram1") use "0x1000"; 19 | for Size ("ram1") use "0x100"; 20 | 21 | end Device_Configuration; 22 | 23 | end Spec; 24 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem_kind/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr', '-l', 'link.ld']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem_kind/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Main stack memory cannot be ROM: 'rom1' 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_stack_mem_kind/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_user_tags/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1"); 8 | 9 | for Boot_Memory use "rom1"; 10 | 11 | for Mem_Kind ("rom1") use "ROM"; 12 | for Address ("rom1") use "0"; 13 | for Size ("rom1") use "0x100"; 14 | 15 | 16 | for User_Tag ("TEST") use ("42", "21"); 17 | end Device_Configuration; 18 | 19 | end Spec; 20 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_user_tags/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_user_tags/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | spec.gpr:16:33: wrong expression kind for attribute "user_tag" 3 | Error: Project file "spec.gpr" not found. 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/invalid_user_tags/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/memory_overlap/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1", "rom2"); 8 | 9 | for Boot_Memory use "rom1"; 10 | 11 | for Mem_Kind ("rom1") use "ROM"; 12 | for Address ("rom1") use "0x10"; 13 | for Size ("rom1") use "0x100"; 14 | 15 | for Mem_Kind ("rom2") use "ROM"; 16 | for Address ("rom2") use "0x10"; 17 | for Size ("rom2") use "0x100"; 18 | 19 | end Device_Configuration; 20 | 21 | end Spec; 22 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/memory_overlap/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/memory_overlap/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Memory overlap : 3 | rom1 : Size = 0x100 and Address = 0x10 4 | rom2 : Size = 0x100 and Address = 0x10 5 | Error: Memory overlap : 6 | rom2 : Size = 0x100 and Address = 0x10 7 | rom1 : Size = 0x100 and Address = 0x10 8 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/memory_overlap/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_addr/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | for Memories use ("rom1"); 7 | for Boot_Memory use "rom1"; 8 | 9 | for Mem_Kind ("rom1") use "ROM"; 10 | -- for Address ("rom1") use "0x10"; 11 | for Size ("rom1") use "0x100"; 12 | 13 | end Device_Configuration; 14 | 15 | end Spec; 16 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_addr/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_addr/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Missing Address for memory: 'rom1' 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_addr/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_kind/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | for Memories use ("rom1"); 7 | for Boot_Memory use "rom1"; 8 | 9 | -- for Mem_Kind ("rom1") use "ROM"; 10 | for Address ("rom1") use "0x10"; 11 | for Size ("rom1") use "0x100"; 12 | 13 | end Device_Configuration; 14 | 15 | end Spec; 16 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_kind/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_kind/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Missing Kind for memory: 'rom1' 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_kind/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_size/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | for Memories use ("rom1"); 7 | for Boot_Memory use "rom1"; 8 | 9 | for Mem_Kind ("rom1") use "ROM"; 10 | for Address ("rom1") use "0x10"; 11 | -- for Size ("rom1") use "0x100"; 12 | 13 | end Device_Configuration; 14 | 15 | end Spec; 16 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_size/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_size/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Missing Size for memory: 'rom1' 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/missing_size/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/no_boot_mem/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1"); 8 | 9 | for Mem_Kind ("rom1") use "ROM"; 10 | for Address ("rom1") use "0x10"; 11 | for Size ("rom1") use "0x100"; 12 | 13 | end Device_Configuration; 14 | 15 | end Spec; 16 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/no_boot_mem/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'spec.gpr']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/no_boot_mem/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: No boot memory specified 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/no_boot_mem/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/project_not_found/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool(['-P', 'invalid.gpr', '-s', 'crt0.S', '-l', 'linker.ld']) 4 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/project_not_found/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Project file "invalid.gpr" not found. 3 | -------------------------------------------------------------------------------- /testsuite/tests/invalid_gpr/project_not_found/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/no_project_file/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | run_tool([]) 4 | -------------------------------------------------------------------------------- /testsuite/tests/no_project_file/test.ref: -------------------------------------------------------------------------------- 1 | command failed: 2 | Error: Project file required (-P) 3 | -------------------------------------------------------------------------------- /testsuite/tests/no_project_file/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/templates/boot_from_rom/boot_from_rom.tmplt: -------------------------------------------------------------------------------- 1 | Boot from ROM: @_BOOT_FROM_ROM_@ 2 | -------------------------------------------------------------------------------- /testsuite/tests/templates/boot_from_rom/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | type Boot_Mem is ("ram", "rom"); 4 | Boot : Boot_Mem := external ("BOOT_MEM", "ram"); 5 | package Device_Configuration is 6 | 7 | for CPU_Name use "cortex-m4f"; 8 | 9 | for Memories use ("rom", "ram"); 10 | 11 | for Boot_Memory use Boot; 12 | 13 | for Mem_Kind ("rom") use "ROM"; 14 | for Address ("rom") use "0x10"; 15 | for Size ("rom") use "0x1"; 16 | 17 | for Mem_Kind ("ram") use "RAM"; 18 | for Address ("ram") use "0x30"; 19 | for Size ("ram") use "0x3"; 20 | 21 | for Startup_Template use "./boot_from_rom.tmplt"; 22 | 23 | end Device_Configuration; 24 | 25 | end Spec; 26 | -------------------------------------------------------------------------------- /testsuite/tests/templates/boot_from_rom/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, contents_of 2 | 3 | run_tool(['-s', 'test.out', '-P', 'spec.gpr', '-XBOOT_MEM=rom']) 4 | print(contents_of('test.out')) 5 | 6 | run_tool(['-s', 'test.out', '-P', 'spec.gpr', '-XBOOT_MEM=ram']) 7 | print(contents_of('test.out')) 8 | -------------------------------------------------------------------------------- /testsuite/tests/templates/boot_from_rom/test.ref: -------------------------------------------------------------------------------- 1 | Boot from ROM: TRUE 2 | Boot from ROM: FALSE 3 | -------------------------------------------------------------------------------- /testsuite/tests/templates/boot_from_rom/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/templates/interrupts/interrupt_list.tmplt: -------------------------------------------------------------------------------- 1 | @@TABLE@@ 2 | ID: @_INTERRUPT_ID_@ Name: @_INTERRUPT_NAME_@ 3 | @@END_TABLE@@ 4 | 5 | -------------------------------------------------------------------------------- /testsuite/tests/templates/interrupts/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Interrupt ("2") use "int_2_name"; 8 | for Interrupt ("6") use "int_6_name"; 9 | for Interrupt ("10") use "int_10_name"; 10 | 11 | -- If the interrupt name is not specified in the project file, the tool 12 | -- should provide default interrupt names for all interrupts from 0 to 13 | -- Number_Of_Interrupts - 1. 14 | for Number_Of_Interrupts use "25"; 15 | 16 | for Startup_Template use "./interrupt_list.tmplt"; 17 | 18 | 19 | 20 | for Memories use ("flash"); 21 | for Boot_Memory use "flash"; 22 | for Mem_Kind ("flash") use "ROM"; 23 | for Address ("flash") use "0x0"; 24 | for Size ("flash") use "0x1"; 25 | 26 | end Device_Configuration; 27 | 28 | end Spec; 29 | -------------------------------------------------------------------------------- /testsuite/tests/templates/interrupts/spec_no_int.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Startup_Template use "./interrupt_list.tmplt"; 8 | 9 | 10 | 11 | for Memories use ("flash"); 12 | for Boot_Memory use "flash"; 13 | for Mem_Kind ("flash") use "ROM"; 14 | for Address ("flash") use "0x0"; 15 | for Size ("flash") use "0x1"; 16 | 17 | end Device_Configuration; 18 | 19 | end Spec; 20 | -------------------------------------------------------------------------------- /testsuite/tests/templates/interrupts/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, contents_of 2 | 3 | run_tool(['-s', 'test.out', '-P', 'spec.gpr']) 4 | run_tool(['-s', 'test_no_int.out', '-P', 'spec_no_int.gpr']) 5 | 6 | print("with interrupts:") 7 | print(contents_of('test.out')) 8 | print("without interrupts:") 9 | print(contents_of('test_no_int.out')) 10 | -------------------------------------------------------------------------------- /testsuite/tests/templates/interrupts/test.ref: -------------------------------------------------------------------------------- 1 | with interrupts: 2 | ID: 0 Name: unknown_interrupt 3 | ID: 1 Name: unknown_interrupt 4 | ID: 2 Name: int_2_name 5 | ID: 3 Name: unknown_interrupt 6 | ID: 4 Name: unknown_interrupt 7 | ID: 5 Name: unknown_interrupt 8 | ID: 6 Name: int_6_name 9 | ID: 7 Name: unknown_interrupt 10 | ID: 8 Name: unknown_interrupt 11 | ID: 9 Name: unknown_interrupt 12 | ID: 10 Name: int_10_name 13 | ID: 11 Name: unknown_interrupt 14 | ID: 12 Name: unknown_interrupt 15 | ID: 13 Name: unknown_interrupt 16 | ID: 14 Name: unknown_interrupt 17 | ID: 15 Name: unknown_interrupt 18 | ID: 16 Name: unknown_interrupt 19 | ID: 17 Name: unknown_interrupt 20 | ID: 18 Name: unknown_interrupt 21 | ID: 19 Name: unknown_interrupt 22 | ID: 20 Name: unknown_interrupt 23 | ID: 21 Name: unknown_interrupt 24 | ID: 22 Name: unknown_interrupt 25 | ID: 23 Name: unknown_interrupt 26 | ID: 24 Name: unknown_interrupt 27 | without interrupts: 28 | -------------------------------------------------------------------------------- /testsuite/tests/templates/interrupts/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/templates/memory/memory_list.tmplt: -------------------------------------------------------------------------------- 1 | Boot Mmmory: @_BOOT_MEM_@ Addr: @_BOOT_MEM_ADDR_@ Size: @_BOOT_MEM_SIZE_@ 2 | ROMs: 3 | @@TABLE@@ 4 | - @_ROM_REGION_@ Addr: @_ROM_ADDR_@ Size: @_ROM_SIZE_@ 5 | @@END_TABLE@@ 6 | 7 | Main RAM: @_MAIN_RAM_@ Addr: @_MAIN_RAM_ADDR_@ Size: @_MAIN_RAM_SIZE_@ 8 | Other RAMs: 9 | @@TABLE@@ 10 | - @_RAM_REGION_@ Addr: @_RAM_ADDR_@ Size: @_RAM_SIZE_@ 11 | @@END_TABLE@@ 12 | -------------------------------------------------------------------------------- /testsuite/tests/templates/memory/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1", "ram1", "rom2", "ram2"); 8 | 9 | for Boot_Memory use "rom2"; 10 | 11 | for Mem_Kind ("rom1") use "ROM"; 12 | for Address ("rom1") use "0x10"; 13 | for Size ("rom1") use "0x1"; 14 | 15 | for Mem_Kind ("rom2") use "ROM"; 16 | for Address ("rom2") use "0x20"; 17 | for Size ("rom2") use "0x2"; 18 | 19 | for Mem_Kind ("ram1") use "RAM"; 20 | for Address ("ram1") use "0x30"; 21 | for Size ("ram1") use "0x3"; 22 | 23 | for Mem_Kind ("ram2") use "RAM"; 24 | for Address ("ram2") use "0x40"; 25 | for Size ("ram2") use "0x3"; 26 | 27 | for Startup_Template use "./memory_list.tmplt"; 28 | 29 | end Device_Configuration; 30 | 31 | end Spec; 32 | -------------------------------------------------------------------------------- /testsuite/tests/templates/memory/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool, contents_of 2 | 3 | run_tool(['-s', 'test.out', '-P', 'spec.gpr']) 4 | 5 | print(contents_of('test.out')) 6 | -------------------------------------------------------------------------------- /testsuite/tests/templates/memory/test.ref: -------------------------------------------------------------------------------- 1 | Boot Mmmory: rom2 Addr: 0x20 Size: 0x2 2 | ROMs: 3 | - rom1 Addr: 0x10 Size: 0x1 4 | 5 | Main RAM: ram1 Addr: 0x30 Size: 0x3 6 | Other RAMs: 7 | - ram2 Addr: 0x40 Size: 0x3 8 | -------------------------------------------------------------------------------- /testsuite/tests/templates/memory/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/templates/print_tags/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Main_Stack_Size use "16K"; 8 | 9 | for Memories use ("rom1", "ram1", "rom2", "ram2"); 10 | 11 | for Boot_Memory use "rom2"; 12 | 13 | for Main_Stack_Size use "8K"; 14 | for Main_Stack_Memory use "ram2"; 15 | 16 | for Mem_Kind ("rom1") use "ROM"; 17 | for Address ("rom1") use "0x10"; 18 | for Size ("rom1") use "0x1"; 19 | 20 | for Mem_Kind ("rom2") use "ROM"; 21 | for Address ("rom2") use "0x20"; 22 | for Size ("rom2") use "0x2"; 23 | 24 | for Mem_Kind ("ram1") use "RAM"; 25 | for Address ("ram1") use "0x30"; 26 | for Size ("ram1") use "0x3"; 27 | 28 | for Mem_Kind ("ram2") use "RAM"; 29 | for Address ("ram2") use "0x40"; 30 | for Size ("ram2") use "0x3"; 31 | 32 | end Device_Configuration; 33 | 34 | end Spec; 35 | -------------------------------------------------------------------------------- /testsuite/tests/templates/print_tags/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | print(run_tool(['-P', 'spec.gpr', '--print-tags'])) 4 | -------------------------------------------------------------------------------- /testsuite/tests/templates/print_tags/test.ref: -------------------------------------------------------------------------------- 1 | --- Template tags --- 2 | FLOAT_HANDLING => SOFT 3 | BOOT_FROM_ROM => TRUE 4 | BOOT_MEM => rom2 5 | BOOT_MEM_ADDR => 0x20 6 | BOOT_MEM_SIZE => 0x2 7 | MAIN_RAM => ram1 8 | MAIN_RAM_ADDR => 0x30 9 | MAIN_RAM_SIZE => 0x3 10 | RAM_REGION => ("ram2") 11 | RAM_ADDR => ("0x40") 12 | RAM_SIZE => ("0x3") 13 | ROM_REGION => ("rom1") 14 | ROM_ADDR => ("0x10") 15 | ROM_SIZE => ("0x1") 16 | MAIN_STACK_SIZE => 0x2000 17 | MAIN_STACK_REGION => ram2 18 | INTERRUPT_NAME => () 19 | INTERRUPT_ID => () 20 | --------------------- 21 | CPU: cortex-m4f 22 | Float_Handling: SOFT 23 | Name : rom1 24 | Address : 0x10 25 | Size : 0x1 26 | Kind : ROM 27 | Name : ram1 28 | Address : 0x30 29 | Size : 0x3 30 | Kind : RAM 31 | Name : rom2 32 | Address : 0x20 33 | Size : 0x2 34 | Kind : ROM 35 | Name : ram2 36 | Address : 0x40 37 | Size : 0x3 38 | Kind : RAM 39 | -------------------------------------------------------------------------------- /testsuite/tests/templates/print_tags/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/templates/user_tags/spec.gpr: -------------------------------------------------------------------------------- 1 | project Spec is 2 | 3 | package Device_Configuration is 4 | 5 | for CPU_Name use "cortex-m4f"; 6 | 7 | for Memories use ("rom1"); 8 | 9 | for Boot_Memory use "rom1"; 10 | 11 | for Mem_Kind ("rom1") use "ROM"; 12 | for Address ("rom1") use "0x10"; 13 | for Size ("rom1") use "0x1"; 14 | 15 | for User_Tag ("TEST_USER_TAG_1") use "42"; 16 | 17 | 18 | -- Redefining an entry is not an error for gpr files. We do it here to 19 | -- check that this behavior will remain in the future. 20 | for User_Tag ("TEST_USER_TAG_2") use "21"; 21 | for User_Tag ("TEST_USER_TAG_2") use "42"; 22 | 23 | end Device_Configuration; 24 | 25 | end Spec; 26 | -------------------------------------------------------------------------------- /testsuite/tests/templates/user_tags/test.py: -------------------------------------------------------------------------------- 1 | from testsuite_support.utils import run_tool 2 | 3 | print(run_tool(['-P', 'spec.gpr', '--print-tags'])) 4 | -------------------------------------------------------------------------------- /testsuite/tests/templates/user_tags/test.ref: -------------------------------------------------------------------------------- 1 | --- Template tags --- 2 | test_user_tag_1 => 42 3 | test_user_tag_2 => 42 4 | FLOAT_HANDLING => SOFT 5 | BOOT_FROM_ROM => TRUE 6 | BOOT_MEM => rom1 7 | BOOT_MEM_ADDR => 0x10 8 | BOOT_MEM_SIZE => 0x1 9 | MAIN_RAM => 10 | MAIN_RAM_ADDR => 11 | MAIN_RAM_SIZE => 12 | RAM_REGION => () 13 | RAM_ADDR => () 14 | RAM_SIZE => () 15 | ROM_REGION => () 16 | ROM_ADDR => () 17 | ROM_SIZE => () 18 | MAIN_STACK_SIZE => 0x1000 19 | MAIN_STACK_REGION => 20 | INTERRUPT_NAME => () 21 | INTERRUPT_ID => () 22 | --------------------- 23 | CPU: cortex-m4f 24 | Float_Handling: SOFT 25 | Name : rom1 26 | Address : 0x10 27 | Size : 0x1 28 | Kind : ROM 29 | -------------------------------------------------------------------------------- /testsuite/tests/templates/user_tags/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | -------------------------------------------------------------------------------- /testsuite/tests/z999-999/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.exit(1) 4 | -------------------------------------------------------------------------------- /testsuite/tests/z999-999/test.yaml: -------------------------------------------------------------------------------- 1 | driver: python 2 | control: 3 | - [XFAIL, "True", "Sanity check"] 4 | -------------------------------------------------------------------------------- /testsuite/testsuite.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | """ 4 | e3.testsuite-based testsuite for startup-gen. 5 | """ 6 | 7 | import sys 8 | from e3.testsuite import Testsuite 9 | from testsuite_support.python_driver import PythonDriver 10 | 11 | 12 | class StartupgenTestsuite(Testsuite): 13 | tests_subdir = 'tests' 14 | test_driver_map = {'python': PythonDriver} 15 | 16 | enable_cross_support = True 17 | 18 | 19 | if __name__ == '__main__': 20 | sys.exit(StartupgenTestsuite().testsuite_main()) 21 | -------------------------------------------------------------------------------- /testsuite/testsuite_support/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdaCore/startup-gen/07391cc41a6c06a688e069878943a716b0226fbb/testsuite/testsuite_support/__init__.py -------------------------------------------------------------------------------- /testsuite/testsuite_support/python_driver.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | import sys 4 | 5 | from e3.testsuite.driver.diff import DiffTestDriver 6 | 7 | 8 | class PythonDriver(DiffTestDriver): 9 | 10 | @property 11 | def baseline_file(self): 12 | return ('test.ref', False) 13 | 14 | @property 15 | def diff_ignore_white_chars(self): 16 | return True 17 | 18 | def run(self): 19 | env = dict(os.environ) 20 | env['target-triplet'] = str(self.env.target.triplet) 21 | 22 | # give it access to our Python helpers 23 | python_path = env.get('PYTHONPATH', '') 24 | path_for_drivers = os.path.abspath( 25 | os.path.dirname(os.path.dirname(__file__))) 26 | env['PYTHONPATH'] = '{}{}{}'.format( 27 | path_for_drivers, os.path.pathsep, python_path 28 | ) if python_path else path_for_drivers 29 | 30 | self.shell([sys.executable, 'test.py'], env=env) 31 | -------------------------------------------------------------------------------- /testsuite/testsuite_support/utils.py: -------------------------------------------------------------------------------- 1 | from e3.os.process import Run 2 | from e3.fs import mkdir 3 | from e3.env import Env 4 | 5 | import os 6 | 7 | try: 8 | from pycross.runcross.main import run_cross 9 | except ImportError: 10 | # Make pycross an optional dependency 11 | 12 | def run_cross(*args, **kwargs): 13 | raise ImportError("Could not import pycross.runcross.main") 14 | 15 | 16 | def contents_of(filename): 17 | """Return contents of file FILENAME""" 18 | with open(filename) as f: 19 | contents = f.read() 20 | 21 | return contents 22 | 23 | 24 | def run_tool(args, output='startup-gen.out', error='startup-gen.err'): 25 | p = Run(['startup-gen'] + args, output=output, error=error) 26 | 27 | if p.status != 0: 28 | print("command failed:") 29 | print(contents_of(output)) 30 | print(contents_of(error)) 31 | 32 | return contents_of(output) 33 | 34 | 35 | def gprbuild(args, output='gprbuild.out', error='gprbuild.err'): 36 | p = Run(['gprbuild'] + args, output=output, error=error) 37 | 38 | if p.status != 0: 39 | print("Build failed:") 40 | print(contents_of(output)) 41 | print(contents_of(error)) 42 | 43 | 44 | def runcross(target, board, bin, output='runcross.out'): 45 | Env().set_target(target, '', board) 46 | 47 | p = run_cross([bin], output=output, timeout=5) 48 | 49 | if p.status != 0: 50 | print("runcross failed:") 51 | print(contents_of(output)) 52 | 53 | 54 | class MemoryDescription: 55 | def __init__(self, name, kind, addr, size): 56 | self.name = name 57 | self.kind = kind 58 | self.addr = addr 59 | self.size = size 60 | 61 | 62 | class MemoryMap(dict): 63 | def add(self, name, kind, addr, size): 64 | self[name] = MemoryDescription(name, kind, addr, size) 65 | 66 | 67 | class SymbolList: 68 | def __init__(self): 69 | self.list = [] 70 | 71 | def append(self, name, addr): 72 | self.list.append((name, addr)) 73 | 74 | def defined(self, symbol): 75 | return symbol in (x[0] for x in self.list) 76 | 77 | def in_range(self, symbol, start, end): 78 | for name, addr in self.list: 79 | if name == symbol: 80 | return addr >= start and addr <= end 81 | return False 82 | 83 | def in_memory(self, symbol, mem): 84 | return self.in_range(symbol, mem.addr, mem.addr + mem.size) 85 | 86 | def in_memmap(self, symbol, memmap, mem): 87 | return self.in_range(symbol, 88 | memmap[mem].addr, 89 | memmap[mem].addr + memmap[mem].size) 90 | 91 | 92 | def check_symbols(symbols, memmap, to_check): 93 | """ 94 | With a list of tuple (symbol_name, memory_name), check that the symbol are 95 | define in the expected memory region. 96 | 97 | Return True on error 98 | """ 99 | err = False 100 | for name, mem in to_check: 101 | if not symbols.defined(name): 102 | print("Symbol '%s' is not defined" % name) 103 | err = True 104 | elif not symbols.in_memmap(name, memmap, mem): 105 | print("Symbol '%s' is not defined in '%s'" % (name, mem)) 106 | err = True 107 | return err 108 | 109 | def nm_symbols(binary): 110 | """Return a SymbolList from a binary file""" 111 | 112 | output = 'nm.out' 113 | error = 'nm.err' 114 | 115 | triplet = os.environ['target-triplet'] 116 | args = [triplet + '-nm', binary] 117 | p = Run(args, output=output, error=error) 118 | 119 | if p.status != 0: 120 | print("nm failed:") 121 | print(contents_of(output)) 122 | print(contents_of(error)) 123 | 124 | result = SymbolList() 125 | for line in contents_of(output).splitlines(): 126 | addr, typ, symbol = line.split(' ') 127 | 128 | if typ in ['A', 'B', 'C', 'D', 'd', 'G', 'g', 129 | 'R', 'r', 'S', 's', 'T', 't']: 130 | result.append(symbol, int('0x' + addr, base=16)) 131 | 132 | return result 133 | 134 | 135 | def generate_gpr(filename, runtime, target, CPU, memmap, boot_mem, stack_mem): 136 | """ Generate a simple project file from the provided memory layout""" 137 | 138 | with open(filename, "w") as f: 139 | f.write('project Prj is\n') 140 | f.write(' for Target use "%s";\n' % target) 141 | f.write(' for Runtime ("Ada") use "%s";\n' % runtime) 142 | f.write(' for Languages use ("Ada", "Asm_CPP");\n') 143 | f.write(' for Source_Dirs use (Project\'Project_Dir & "src");\n') 144 | f.write(' for Object_Dir use Project\'Project_Dir & "obj";\n') 145 | f.write(' for Main use ("main.adb");\n') 146 | f.write(' for Create_Missing_Dirs use "True";\n') 147 | f.write(' package Linker is\n') 148 | f.write(' for Switches ("Ada") use ("-T", "src/linker.ld");\n') 149 | f.write(' end Linker;\n') 150 | f.write(' package Device_Configuration is\n') 151 | f.write(' for CPU_Name use "%s";\n' % CPU) 152 | f.write(' for Memories use ("%s");\n' % '", "'.join(memmap)) 153 | f.write(' for Boot_Memory use \"%s\";\n' % boot_mem) 154 | f.write(' for Main_Stack_Memory use \"%s\";\n' % stack_mem) 155 | for mem in memmap: 156 | f.write(' for Mem_Kind ("%s") use "%s";\n' % 157 | (memmap[mem].name, memmap[mem].kind)) 158 | f.write(' for Address ("%s") use "%d";\n' % 159 | (memmap[mem].name, memmap[mem].addr)) 160 | f.write(' for Size ("%s") use "%d";\n' % 161 | (memmap[mem].name, memmap[mem].size)) 162 | 163 | if runtime.startswith('light-rv'): 164 | f.write(' for User_Tag ("qemu_sifive_test_exit") use "True";') 165 | f.write(' end Device_Configuration;\n') 166 | f.write('end Prj;\n') 167 | 168 | 169 | def make_simple_project(dir, runtime, target, CPU, mems, boot_mem, stack_mem): 170 | """ 171 | Create and build a simple project with empty main procedure, and return the 172 | path to the output binary. 173 | """ 174 | mkdir(dir) 175 | mkdir(os.path.join(dir, 'src')) 176 | 177 | # Create an empty main procedure 178 | with open(os.path.join(dir, 'src', 'main.adb'), 'w') as f: 179 | f.write("procedure Main is begin null; end Main;\n") 180 | 181 | # Generate the project file from memory layout 182 | generate_gpr(os.path.join(dir, 'prj.gpr'), runtime, 183 | target, CPU, mems, boot_mem, stack_mem) 184 | 185 | # Generate crt0 and linker script 186 | run_tool(['-P', os.path.join(dir, 'prj.gpr'), 187 | '-s', os.path.join(dir, 'src', 'crt0.S'), 188 | '-l', os.path.join(dir, 'src', 'linker.ld')]) 189 | 190 | # Build 191 | gprbuild(['-f', '-P', os.path.join(dir, 'prj.gpr')]) 192 | 193 | # Return path to the binary file 194 | return os.path.join(dir, 'obj', 'main') 195 | --------------------------------------------------------------------------------