summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2009-09-21 07:44:28 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2009-09-21 07:44:28 +0000
commit687e34b6194bd4722d5955a8cdb89389d52f89f9 (patch)
treeef465839aab0b641efa100268a851474e21d4f3b
parent2009-09-20 Joel Sherrill <joel.sherrill@oarcorp.com> (diff)
downloadrtems-687e34b6194bd4722d5955a8cdb89389d52f89f9.tar.bz2
Add missing files.
-rw-r--r--c/src/lib/libbsp/arm/lpc24xx/ChangeLog5
-rw-r--r--c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c194
-rw-r--r--c/src/lib/libbsp/arm/lpc24xx/misc/timer.c55
-rw-r--r--c/src/lib/libbsp/arm/lpc24xx/startup/bspstarthooks.c410
4 files changed, 664 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/lpc24xx/ChangeLog b/c/src/lib/libbsp/arm/lpc24xx/ChangeLog
index 4e3d88840f..26bb79511f 100644
--- a/c/src/lib/libbsp/arm/lpc24xx/ChangeLog
+++ b/c/src/lib/libbsp/arm/lpc24xx/ChangeLog
@@ -1,3 +1,8 @@
+2009-09-21 Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>
+
+ * startup/bspstarthooks.c, misc/dma-copy.c, misc/timer.c: Add
+ missing files.
+
2009-09-17 Sebastian Huber <sebastian.huber@embedded-brains.de>
* startup/bspstarthooks.c, misc/dma-copy.c, misc/timer.c: New files.
diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c b/c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c
new file mode 100644
index 0000000000..55c33e451f
--- /dev/null
+++ b/c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c
@@ -0,0 +1,194 @@
+/**
+ * @file
+ *
+ * @ingroup lpc24xx_dma
+ *
+ * @brief Direct memory access (DMA) support.
+ */
+
+/*
+ * Copyright (c) 2008, 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp/lpc24xx.h>
+#include <bsp/dma.h>
+#include <bsp/irq.h>
+
+static rtems_id lpc24xx_dma_sema_table [GPDMA_CH_NUMBER];
+
+static bool lpc24xx_dma_status_table [GPDMA_CH_NUMBER];
+
+static void lpc24xx_dma_copy_handler(rtems_vector_number vector, void *arg)
+{
+ /* Get interrupt status */
+ uint32_t tc = GPDMA_INT_TCSTAT;
+ uint32_t err = GPDMA_INT_ERR_STAT;
+
+ /* Clear interrupt status */
+ GPDMA_INT_TCCLR = tc;
+ GPDMA_INT_ERR_CLR = err;
+
+ /* Check channel 0 */
+ if (IS_FLAG_SET(tc, GPDMA_STATUS_CH_0)) {
+ rtems_semaphore_release(lpc24xx_dma_sema_table [0]);
+ }
+ lpc24xx_dma_status_table [0] = IS_FLAG_CLEARED(err, GPDMA_STATUS_CH_0);
+
+ /* Check channel 1 */
+ if (IS_FLAG_SET(tc, GPDMA_STATUS_CH_1)) {
+ rtems_semaphore_release(lpc24xx_dma_sema_table [1]);
+ }
+ lpc24xx_dma_status_table [1] = IS_FLAG_CLEARED(err, GPDMA_STATUS_CH_1);
+}
+
+rtems_status_code lpc24xx_dma_copy_initialize(void)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_id id0 = RTEMS_ID_NONE;
+ rtems_id id1 = RTEMS_ID_NONE;
+
+ /* Create semaphore for channel 0 */
+ sc = rtems_semaphore_create(
+ rtems_build_name('D', 'M', 'A', '0'),
+ 0,
+ RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &id0
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+
+ /* Create semaphore for channel 1 */
+ sc = rtems_semaphore_create(
+ rtems_build_name('D', 'M', 'A', '1'),
+ 0,
+ RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &id1
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_semaphore_delete(id0);
+
+ return sc;
+ }
+
+ /* Install DMA interrupt handler */
+ sc = rtems_interrupt_handler_install(
+ LPC24XX_IRQ_DMA,
+ "DMA copy",
+ RTEMS_INTERRUPT_UNIQUE,
+ lpc24xx_dma_copy_handler,
+ NULL
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_semaphore_delete(id0);
+ rtems_semaphore_delete(id1);
+
+ return sc;
+ }
+
+ /* Initialize global data */
+ lpc24xx_dma_sema_table [0] = id0;
+ lpc24xx_dma_sema_table [1] = id1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code lpc24xx_dma_copy_release(void)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_status_code rsc = RTEMS_SUCCESSFUL;
+
+ sc = rtems_interrupt_handler_remove(
+ LPC24XX_IRQ_DMA,
+ lpc24xx_dma_copy_handler,
+ NULL
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = sc;
+ }
+
+ sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [0]);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = sc;
+ }
+
+ sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [1]);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rsc = sc;
+ }
+
+ return rsc;
+}
+
+rtems_status_code lpc24xx_dma_copy(
+ unsigned channel,
+ void *dest,
+ const void *src,
+ size_t n,
+ size_t width
+)
+{
+ volatile lpc24xx_dma_channel *e = GPDMA_CH_BASE_ADDR(channel);
+ uint32_t w = GPDMA_CH_CTRL_W_8;
+
+ switch (width) {
+ case 4:
+ w = GPDMA_CH_CTRL_W_32;
+ break;
+ case 2:
+ w = GPDMA_CH_CTRL_W_16;
+ break;
+ }
+
+ n = n >> w;
+
+ if (n > 0U && n < 4096U) {
+ e->desc.src = (uint32_t) src;
+ e->desc.dest = (uint32_t) dest;
+ e->desc.lli = 0;
+ e->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n)
+ | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_1)
+ | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_1)
+ | SET_GPDMA_CH_CTRL_SW(0, w)
+ | SET_GPDMA_CH_CTRL_DW(0, w)
+ | GPDMA_CH_CTRL_ITC
+ | GPDMA_CH_CTRL_SI
+ | GPDMA_CH_CTRL_DI;
+ e->cfg = SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_MEM_DMA)
+ | GPDMA_CH_CFG_IE
+ | GPDMA_CH_CFG_ITC
+ | GPDMA_CH_CFG_EN;
+ } else {
+ return RTEMS_INVALID_SIZE;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code lpc24xx_dma_copy_wait(unsigned channel)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = rtems_semaphore_obtain(
+ lpc24xx_dma_sema_table [channel],
+ RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+
+ return lpc24xx_dma_status_table [channel]
+ ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
+}
diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/timer.c b/c/src/lib/libbsp/arm/lpc24xx/misc/timer.c
new file mode 100644
index 0000000000..e9d44312ab
--- /dev/null
+++ b/c/src/lib/libbsp/arm/lpc24xx/misc/timer.c
@@ -0,0 +1,55 @@
+/**
+ * @file
+ *
+ * @ingroup lpc24xx
+ *
+ * @brief Benchmark timer support.
+ */
+
+/*
+ * Copyright (c) 2008, 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <rtems/timerdrv.h>
+
+#include <bsp/system-clocks.h>
+
+static bool benchmark_timer_find_average_overhead = false;
+
+static uint32_t benchmark_timer_base;
+
+void benchmark_timer_initialize(void)
+{
+ benchmark_timer_base = lpc24xx_timer();
+}
+
+uint32_t benchmark_timer_read(void)
+{
+ uint32_t delta = lpc24xx_timer() - benchmark_timer_base;
+
+ if (benchmark_timer_find_average_overhead) {
+ return delta;
+ } else {
+ /* Value determined by tmck for NCS board */
+ if (delta > 74) {
+ return delta - 74;
+ } else {
+ return 0;
+ }
+ }
+}
+
+void benchmark_timer_disable_subtracting_average_overhead( bool find_average_overhead )
+{
+ benchmark_timer_find_average_overhead = find_average_overhead;
+}
diff --git a/c/src/lib/libbsp/arm/lpc24xx/startup/bspstarthooks.c b/c/src/lib/libbsp/arm/lpc24xx/startup/bspstarthooks.c
new file mode 100644
index 0000000000..c86cd02171
--- /dev/null
+++ b/c/src/lib/libbsp/arm/lpc24xx/startup/bspstarthooks.c
@@ -0,0 +1,410 @@
+/**
+ * @file
+ *
+ * @ingroup lpc24xx
+ *
+ * @brief Startup code.
+ */
+
+/*
+ * Copyright (c) 2008, 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdbool.h>
+
+#include <bspopts.h>
+#include <bsp/start.h>
+#include <bsp/lpc24xx.h>
+#include <bsp/linker-symbols.h>
+
+#ifdef LPC24XX_EMC_MICRON
+ static void __attribute__((section(".bsp_start"))) lpc24xx_ram_test_32(void)
+ {
+ #ifdef LPC24XX_EMC_TEST
+ int *begin = (int *) 0xa0000000;
+ const int *end = (const int *) 0xa0800000;
+ int *out = begin;
+
+ while (out != end) {
+ *out = (int) out;
+ ++out;
+ }
+
+ out = begin;
+ while (out != end) {
+ if (*out != (int) out) {
+ while (true) {
+ /* Do nothing */
+ }
+ }
+ ++out;
+ }
+ #endif
+ }
+
+ static void __attribute__((section(".bsp_start"))) lpc24xx_cpu_delay(
+ unsigned ticks
+ )
+ {
+ unsigned i = 0;
+
+ /* One loop execution needs four instructions */
+ ticks /= 4;
+
+ for (i = 0; i <= ticks; ++i) {
+ asm volatile ("nop");
+ }
+ }
+#endif
+
+/**
+ * @brief EMC initialization hook 0.
+ */
+static void __attribute__((section(".bsp_start"))) lpc24xx_init_emc_0(void)
+{
+ #ifdef LPC24XX_EMC_NUMONYX
+ /*
+ * Static Memory 1: Numonyx M29W160EB
+ *
+ * 1 clock cycle = 1/72MHz = 13.9ns
+ *
+ * We cannot use an initializer since this will result in the usage of the
+ * read-only data section which is not available here.
+ */
+ lpc24xx_emc_static numonyx;
+
+ /*
+ * 16 bit, page mode disabled, active LOW chip select, extended wait
+ * disabled, writes not protected, byte lane state LOW/LOW (!).
+ */
+ numonyx.cfg = 0x81;
+
+ /* 1 clock cycles delay from the chip select 1 to the write enable */
+ numonyx.waitwen = 0;
+
+ /*
+ * 0 clock cycles delay from the chip select 1 or address change
+ * (whichever is later) to the output enable
+ */
+ numonyx.waitoen = 0;
+
+ /* 7 clock cycles delay from the chip select 1 to the read access */
+ numonyx.waitrd = 0x6;
+
+ /*
+ * 32 clock cycles delay for asynchronous page mode sequential accesses
+ */
+ numonyx.waitpage = 0x1f;
+
+ /* 5 clock cycles delay from the chip select 1 to the write access */
+ numonyx.waitwr = 0x3;
+
+ /* 16 bus turnaround cycles */
+ numonyx.waitrun = 0xf;
+ #endif
+
+ /* Set pin functions for EMC */
+ PINSEL5 = (PINSEL5 & 0xf000f000) | 0x05550555;
+ PINSEL6 = 0x55555555;
+ PINSEL8 = 0x55555555;
+ PINSEL9 = (PINSEL9 & 0x0f000000) | 0x50555555;
+
+ #ifdef LPC24XX_EMC_NUMONYX
+ /* Static Memory 1 settings */
+ bsp_start_memcpy_arm(
+ (int *) EMC_STA_BASE_1,
+ (const int *) &numonyx,
+ sizeof(numonyx)
+ );
+ #endif
+}
+
+/**
+ * @brief EMC initialization hook 1.
+ */
+static void __attribute__((section(".bsp_start"))) lpc24xx_init_emc_1(void)
+{
+ /* Use normal memory map */
+ EMC_CTRL = CLEAR_FLAG(EMC_CTRL, 0x2);
+
+ #ifdef LPC24XX_EMC_MICRON
+ /* Check if we need to initialize it */
+ if (IS_FLAG_CLEARED(EMC_DYN_CFG0, 0x00080000)) {
+ /*
+ * The buffer enable bit is not set. Now we assume that the controller
+ * is not properly initialized.
+ */
+
+ /* Global dynamic settings */
+
+ /* FIXME */
+ EMC_DYN_APR = 2;
+
+ /* Data-in to active command period tWR + tRP */
+ EMC_DYN_DAL = 4;
+
+ /* Load mode register to active or refresh command period 2 tCK */
+ EMC_DYN_MRD = 1;
+
+ /* Active to precharge command period 44 ns */
+ EMC_DYN_RAS = 3;
+
+ /* Active to active command period 66 ns */
+ EMC_DYN_RC = 4;
+
+ /* Use command delayed strategy */
+ EMC_DYN_RD_CFG = 1;
+
+ /* Auto refresh period 66 ns */
+ EMC_DYN_RFC = 4;
+
+ /* Precharge command period 20 ns */
+ EMC_DYN_RP = 1;
+
+ /* Active bank a to active bank b command period 15 ns */
+ EMC_DYN_RRD = 1;
+
+ /* FIXME */
+ EMC_DYN_SREX = 5;
+
+ /* Write recovery time 15 ns */
+ EMC_DYN_WR = 1;
+
+ /* Exit self refresh to active command period 75 ns */
+ EMC_DYN_XSR = 5;
+
+ /* Dynamic Memory 0: Micron M T48LC 4M16 A2 P 75 IT */
+
+ /*
+ * Use SDRAM, 0 0 001 01 address mapping, disabled buffer, unprotected writes
+ */
+ EMC_DYN_CFG0 = 0x0280;
+
+ /* CAS and RAS latency */
+ EMC_DYN_RASCAS0 = 0x0202;
+
+ /* Wait 50 micro seconds */
+ lpc24xx_cpu_delay(3600);
+
+ /* Send command: NOP */
+ EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_NOP;
+
+ /* Wait 50 micro seconds */
+ lpc24xx_cpu_delay(3600);
+
+ /* Send command: PRECHARGE ALL */
+ EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_PALL;
+
+ /* Shortest possible refresh period */
+ EMC_DYN_RFSH = 0x01;
+
+ /* Wait at least 128 AHB clock cycles */
+ lpc24xx_cpu_delay(128);
+
+ /* Wait 1 micro second */
+ lpc24xx_cpu_delay(72);
+
+ /* Set refresh period */
+ EMC_DYN_RFSH = 0x46;
+
+ /* Send command: MODE */
+ EMC_DYN_CTRL = EMC_DYN_CTRL_CE | EMC_DYN_CTRL_CS | EMC_DYN_CTRL_CMD_MODE;
+
+ /* Set mode register in SDRAM */
+ *((volatile uint32_t *) (0xa0000000 | (0x23 << (1 + 2 + 8))));
+
+ /* Send command: NORMAL */
+ EMC_DYN_CTRL = 0;
+
+ /* Enable buffer */
+ EMC_DYN_CFG0 |= 0x00080000;
+
+ /* Test RAM */
+ lpc24xx_ram_test_32();
+ }
+ #endif
+}
+
+static void __attribute__((section(".bsp_start"))) lpc24xx_pll_config(
+ uint32_t val
+)
+{
+ PLLCON = val;
+ PLLFEED = 0xaa;
+ PLLFEED = 0x55;
+}
+
+/**
+ * @brief Sets the Phase Locked Loop (PLL).
+ *
+ * All parameter values are the actual register field values.
+ *
+ * @param clksrc Selects the clock source for the PLL.
+ *
+ * @param nsel Selects PLL pre-divider value (sometimes named psel).
+ *
+ * @param msel Selects PLL multiplier value.
+ *
+ * @param cclksel Selects the divide value for creating the CPU clock (CCLK)
+ * from the PLL output.
+ */
+static void __attribute__((section(".bsp_start"))) lpc24xx_set_pll(
+ unsigned clksrc,
+ unsigned nsel,
+ unsigned msel,
+ unsigned cclksel
+)
+{
+ uint32_t pllstat = PLLSTAT;
+ uint32_t pllcfg = SET_PLLCFG_NSEL(0, nsel) | SET_PLLCFG_MSEL(0, msel);
+ uint32_t clksrcsel = SET_CLKSRCSEL_CLKSRC(0, clksrc);
+ uint32_t cclkcfg = SET_CCLKCFG_CCLKSEL(0, cclksel | 1);
+ bool pll_enabled = IS_FLAG_SET(pllstat, PLLSTAT_PLLE);
+
+ /* Disconnect PLL if necessary */
+ if (IS_FLAG_SET(pllstat, PLLSTAT_PLLC)) {
+ if (pll_enabled) {
+ /* Check if we run already with the desired settings */
+ if (PLLCFG == pllcfg && CLKSRCSEL == clksrcsel && CCLKCFG == cclkcfg) {
+ /* Nothing to do */
+ return;
+ }
+ lpc24xx_pll_config(PLLCON_PLLE);
+ } else {
+ lpc24xx_pll_config(0);
+ }
+ }
+
+ /* Set CPU clock divider to a reasonable save value */
+ CCLKCFG = 0;
+
+ /* Disable PLL if necessary */
+ if (pll_enabled) {
+ lpc24xx_pll_config(0);
+ }
+
+ /* Select clock source */
+ CLKSRCSEL = clksrcsel;
+
+ /* Set PLL Configuration Register */
+ PLLCFG = pllcfg;
+
+ /* Enable PLL */
+ lpc24xx_pll_config(PLLCON_PLLE);
+
+ /* Wait for lock */
+ while (IS_FLAG_CLEARED(PLLSTAT, PLLSTAT_PLOCK)) {
+ /* Wait */
+ }
+
+ /* Set CPU clock divider and ensure that we have an odd value */
+ CCLKCFG = cclkcfg;
+
+ /* Connect PLL */
+ lpc24xx_pll_config(PLLCON_PLLE | PLLCON_PLLC);
+}
+
+static void __attribute__((section(".bsp_start"))) lpc24xx_init_pll(void)
+{
+ /* Enable main oscillator */
+ if (IS_FLAG_CLEARED(SCS, 0x40)) {
+ SCS = SET_FLAG(SCS, 0x20);
+ while (IS_FLAG_CLEARED(SCS, 0x40)) {
+ /* Wait */
+ }
+ }
+
+ /* Set PLL */
+ lpc24xx_set_pll(1, 0, 11, 3);
+}
+
+static void __attribute__((section(".bsp_start"))) lpc24xx_clear_bss(void)
+{
+ const int *end = (const int *) bsp_section_bss_end;
+ int *out = (int *) bsp_section_bss_begin;
+
+ /* Clear BSS */
+ while (out != end) {
+ *out = 0;
+ ++out;
+ }
+}
+
+void __attribute__((section(".bsp_start"))) bsp_start_hook_0(void)
+{
+ /* Initialize PLL */
+ lpc24xx_init_pll();
+
+ /* Initialize EMC hook 0 */
+ lpc24xx_init_emc_0();
+}
+
+void __attribute__((section(".bsp_start"))) bsp_start_hook_1(void)
+{
+ /* Re-map interrupt vectors to internal RAM */
+ MEMMAP = SET_MEMMAP_MAP(MEMMAP, 2);
+
+ /* Set memory accelerator module (MAM) */
+ MAMCR = 0;
+ MAMTIM = 4;
+
+ /* Enable fast IO for ports 0 and 1 */
+ SCS = SET_FLAG(SCS, 0x1);
+
+ /* Set fast IO */
+ FIO0DIR = 0;
+ FIO1DIR = 0;
+ FIO2DIR = 0;
+ FIO3DIR = 0;
+ FIO4DIR = 0;
+ FIO0CLR = 0xffffffff;
+ FIO1CLR = 0xffffffff;
+ FIO2CLR = 0xffffffff;
+ FIO3CLR = 0xffffffff;
+ FIO4CLR = 0xffffffff;
+
+ /* Initialize EMC hook 1 */
+ lpc24xx_init_emc_1();
+
+ /* Copy .text section */
+ bsp_start_memcpy_arm(
+ (int *) bsp_section_text_begin,
+ (const int *) bsp_section_text_load_begin,
+ (size_t) bsp_section_text_size
+ );
+
+ /* Copy .rodata section */
+ bsp_start_memcpy_arm(
+ (int *) bsp_section_rodata_begin,
+ (const int *) bsp_section_rodata_load_begin,
+ (size_t) bsp_section_rodata_size
+ );
+
+ /* Copy .data section */
+ bsp_start_memcpy_arm(
+ (int *) bsp_section_data_begin,
+ (const int *) bsp_section_data_load_begin,
+ (size_t) bsp_section_data_size
+ );
+
+ /* Copy .fast section */
+ bsp_start_memcpy_arm(
+ (int *) bsp_section_fast_begin,
+ (const int *) bsp_section_fast_load_begin,
+ (size_t) bsp_section_fast_size
+ );
+
+ /* Clear .bss section */
+ lpc24xx_clear_bss();
+
+ /* At this point we can use objects outside the .start section */
+}