#!/usr/bin/python # This file is part of Espruino, a JavaScript interpreter for Microcontrollers # # Copyright (C) 2013 Gordon Williams # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # # ---------------------------------------------------------------------------------------- # Reads board information from boards/BOARDNAME.py and uses it to generate # a linker file # ---------------------------------------------------------------------------------------- import subprocess; import re; import json; import sys; import os; import importlib; import common; scriptdir = os.path.dirname(os.path.realpath(__file__)) basedir = scriptdir+"/../" sys.path.append(basedir+"scripts"); sys.path.append(basedir+"boards"); import pinutils; # ----------------------------------------------------------------------------------------- def die(err): sys.stderr.write("ERROR: "+err+"\n") sys.exit(1) # ----------------------------------------------------------------------------------------- # Now scan AF file print "Script location "+scriptdir if len(sys.argv)<3: print "ERROR, USAGE: build_linker.py BOARD_NAME LINKER_FILE [--bootloader_leave_space] [--bootloader]" print " --using_bootloader -> step forwards in flash to leave room for bootloader" print " --bootloader -> is a bootloader - place it in the correct position" exit(1) boardname = sys.argv[1] linkerFilename = sys.argv[2] IS_BOOTLOADER = False IS_USING_BOOTLOADER = False for i in range(3,len(sys.argv)): arg = sys.argv[i]; if arg=="--using_bootloader": IS_USING_BOOTLOADER=True elif arg=="--bootloader": IS_BOOTLOADER=True else: die("Unknown option '"+arg+"'"); print "LINKER_FILENAME "+linkerFilename print "BOARD "+boardname print "IS_BOOTLOADER "+str(IS_BOOTLOADER) print "IS_USING_BOOTLOADER "+str(IS_USING_BOOTLOADER) # import the board def board = importlib.import_module(boardname) # Check what board py says BOARD_BOOTLOADER = "bootloader" in board.info and board.info["bootloader"]!=0 if BOARD_BOOTLOADER != (IS_BOOTLOADER or IS_USING_BOOTLOADER): die("Makefile ("+str(IS_BOOTLOADER or IS_USING_BOOTLOADER)+") and BOARD.py ("+str(BOARD_BOOTLOADER)+") do not agree over bootloaderiness") # ----------------------------------------------------------------------------------------- linkerFile = open(linkerFilename, 'w') def codeOut(s): linkerFile.write(s+"\n"); # ----------------------------------------------------------------------------------------- BOOTLOADER_SIZE = common.get_bootloader_size(board); RAM_BASE = 0x20000000; FLASH_BASE = 0x00000000; RAM_SIZE = board.chip["ram"]*1024; FLASH_SIZE = board.chip["flash"]*1024; # Beware - on some devices (the STM32F4) the memory is divided into two non-continuous blocks if board.chip["family"]=="STM32F4" and RAM_SIZE > 128*1204: RAM_SIZE = 128*1024 if IS_BOOTLOADER: FLASH_SIZE = BOOTLOADER_SIZE elif IS_USING_BOOTLOADER: FLASH_BASE = common.get_espruino_binary_address(board) FLASH_SIZE -= BOOTLOADER_SIZE STACK_START = RAM_BASE + RAM_SIZE if board.chip["family"] != "NRF52": codeOut(""" /* Automatically generated linker file for """+boardname+""" Generated by scripts/build_linker.py ENTRY(Reset_Handler) /* Highest stack address */ _estack = """+hex(STACK_START)+"""; MEMORY { FLASH (rx) : ORIGIN = """+hex(FLASH_BASE)+""", LENGTH = """+str(FLASH_SIZE/1024)+"""K RAM (xrw) : ORIGIN = """+hex(RAM_BASE)+""", LENGTH = """+str(RAM_SIZE/1024)+"""K } SECTIONS { /* FLASH --------------------------------------------- */ /* Interrupt Vector table goes first */ .isr_vector : { . = ALIGN(0x200); /* STM32 requires this alignment */ _VECTOR_TABLE = .; /* We'll need this for relocating our table */ KEEP(*(.isr_vector)) . = ALIGN(4); } >FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } >FLASH /* Then code, then constants */ .text : { """) if not IS_USING_BOOTLOADER and not IS_BOOTLOADER and "place_text_section" in board.chip: codeOut(""" /* In the .py file we were told to place text here (to skip out what was before) */ . = ALIGN("""+hex(board.chip["place_text_section"] & 0x00FFFFFF)+"""); /* hacky! really want it absolute */ """); codeOut(""" . = ALIGN(4); *(.text) *(.text*) *(.rodata) *(.rodata*) . = ALIGN(4); _etext = .; } >FLASH /* used by the startup to initialize data */ _sidata = .; /* Initialized data sections goes into RAM, load LMA copy after code */ .data : AT ( _sidata ) { . = ALIGN(4); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(4); _edata = .; /* define a global symbol at data end */ } >RAM /* Uninitialized data section */ . = ALIGN(4); .bss : { /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; /* define a global symbol at bss end */ } >RAM PROVIDE ( _end = _ebss ); /* Remove stuff we don't want */ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } } """); elif: board.chip["family"] == "NRF52": # NRF52 requires its own Linker Script. # This is very similar to Linkerscipt provdied with the uart example in NRF52 SDK. Just add some variables that Espruino defines in their linkerscript.. codeOut(""" /* Linker script to configure memory regions. */ SEARCH_DIR(.) GROUP(-lgcc -lc -lnosys) MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x80000 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x08000 } /* Linker script for Nordic Semiconductor nRF5 devices * * Version: Sourcery G++ 4.5-1 * Support: https://support.codesourcery.com/GNUToolchain/ * * Copyright (c) 2007, 2008, 2009, 2010 CodeSourcery, Inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice is included verbatim in any distributions. No written agreement, * license, or royalty fee is required for any of the authorized uses. * Modifications to this software may be copyrighted by their authors * and need not follow the licensing terms described here, provided that * the new terms are clearly indicated on the first page of each file where * they apply. */ OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") /* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. * It references following symbols, which must be defined in code: * Reset_Handler : Entry of reset handler * * It defines following symbols, which code can use without definition: * __exidx_start * __exidx_end * __etext * __data_start__ * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __data_end__ * __bss_start__ * __bss_end__ * __end__ * end * __HeapLimit * __StackLimit * __StackTop * __stack */ ENTRY(Reset_Handler) SECTIONS { .text : { KEEP(*(.Vectors)) *(.text*) KEEP(*(.init)) KEEP(*(.fini)) /* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors) /* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors) *(.rodata*) *(.eh_frame*) . = ALIGN(4); } > FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } > FLASH __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) . = ALIGN(4); } > FLASH __exidx_end = .; __etext = .; _etext = .; _sidata = .; .data : AT (__etext) { __data_start__ = .; _sdata = .; *(vtable) *(.data*) . = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN (__preinit_array_start = .); *(.preinit_array) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(4); /* init data */ PROVIDE_HIDDEN (__init_array_start = .); *(SORT(.init_array.*)) *(.init_array) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(4); /* finit data */ PROVIDE_HIDDEN (__fini_array_start = .); *(SORT(.fini_array.*)) *(.fini_array) PROVIDE_HIDDEN (__fini_array_end = .); *(.jcr) . = ALIGN(4); /* All data end */ __data_end__ = .; _edata = .; } > RAM .bss : { . = ALIGN(4); __bss_start__ = .; _sbss = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; _ebss = .; } > RAM .heap (COPY): { __end__ = .; end = __end__; *(.heap*) __HeapLimit = .; } > RAM PROVIDE ( _end = end ); /* .stack_dummy section doesn't contains any symbols. It is only * used for linker to calculate size of stack sections, and assign * values to stack symbols later */ .stack_dummy (COPY): { *(.stack*) } > RAM /* Set stack top to end of RAM, and stack limit move down by * size of stack_dummy section */ __StackTop = ORIGIN(RAM) + LENGTH(RAM); _estack = __StackTop; __StackLimit = __StackTop - SIZEOF(.stack_dummy); PROVIDE(__stack = __StackTop); /* Check if data + heap + stack exceeds RAM limit */ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") } """);