diff options
author | Jörg Hohensohn <hohensoh@rockbox.org> | 2003-11-30 11:37:43 +0000 |
---|---|---|
committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2003-11-30 11:37:43 +0000 |
commit | 6a4e4c87c24455e18bbd77565cb3e993ee350618 (patch) | |
tree | 6f2ceac4da97aa63ff8deef939bd3cc2d56d3466 /flash/bootloader | |
parent | 014c4fa1f8d56850cfd504a90221c293e4a158f6 (diff) |
source code for all my flash stuff, now finally in cvs
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4083 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'flash/bootloader')
-rw-r--r-- | flash/bootloader/Makefile | 78 | ||||
-rw-r--r-- | flash/bootloader/README | 4 | ||||
-rw-r--r-- | flash/bootloader/bootloader.c | 480 | ||||
-rw-r--r-- | flash/bootloader/bootloader.h | 111 | ||||
-rw-r--r-- | flash/bootloader/bootloader.lds | 34 | ||||
-rw-r--r-- | flash/bootloader/no_rom.lds | 62 |
6 files changed, 769 insertions, 0 deletions
diff --git a/flash/bootloader/Makefile b/flash/bootloader/Makefile new file mode 100644 index 0000000000..ae56cf9425 --- /dev/null +++ b/flash/bootloader/Makefile @@ -0,0 +1,78 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +CC = sh-elf-gcc +LD = sh-elf-ld +AR = sh-elf-ar +AS = sh-elf-as +OC = sh-elf-objcopy + +FIRMWARE := ../../firmware +TOOLSDIR=../../tools + +TARGET = bootloader +LDS := $(TARGET).lds + + +ifndef PLATFORM +not_configured: + @echo "No platform given." + @echo "Use make PLATFORM=PLAYER|RECORDER|RECORDER|FM {NO_ROM=1}" +##else +##configured: +## @echo "Building bootloader for platform "$(PLATFORM) +endif + + +INCLUDES= -I$(FIRMWARE)/export -I. -I$(OBJDIR) +DEFINES= -DPLATFORM_$(PLATFORM) + +OBJDIR := . + +CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(DEFINES) +AFLAGS += -small -relax + + +ifdef DEBUG + DEFINES := -DDEBUG + CFLAGS += -g +endif + +SRC := $(wildcard *.c) + +OBJS := $(SRC:%.c=$(OBJDIR)/%.o) + +ifdef NO_ROM +LINKFILE = $(OBJDIR)/no_rom.lds +ORIGIN = 0 +DEFINES += -DNO_ROM +else +LINKFILE = $(OBJDIR)/$(TARGET).lds +ORIGIN = FFFF500 +endif + +$(OBJDIR)/$(TARGET).bin : $(OBJDIR)/$(TARGET).elf + $(OC) -O binary $(OBJDIR)/$(TARGET).elf $(OBJDIR)/$(TARGET).bin + $(TOOLSDIR)/sh2d $(OBJDIR)/$(TARGET).bin -o $(ORIGIN) > $(OBJDIR)/$(TARGET).asm +ifndef NO_ROM + $(TOOLSDIR)/scramble $(OBJDIR)/$(TARGET).bin $(OBJDIR)/$(TARGET).ajz +endif + +$(OBJDIR)/$(TARGET).elf : $(OBJS) + $(CC) -Os -nostdlib -o $(OBJDIR)/$(TARGET).elf -L$(OBJDIR) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/$(TARGET).map + + +clean: + -rm -f \ + $(OBJS) \ + $(OBJDIR)/$(TARGET).asm \ + $(OBJDIR)/$(TARGET).bin \ + $(OBJDIR)/$(TARGET).ajz \ + $(OBJDIR)/$(TARGET).elf \ + $(OBJDIR)/$(TARGET).map diff --git a/flash/bootloader/README b/flash/bootloader/README new file mode 100644 index 0000000000..16c27d9876 --- /dev/null +++ b/flash/bootloader/README @@ -0,0 +1,4 @@ +(c) 2003 by Jörg Hohensohn + +This is the source code for the flash bootloader. +It give the dual boot feature, decompresses one of two software images. diff --git a/flash/bootloader/bootloader.c b/flash/bootloader/bootloader.c new file mode 100644 index 0000000000..7179bbef95 --- /dev/null +++ b/flash/bootloader/bootloader.c @@ -0,0 +1,480 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2003 by Jörg Hohensohn + * + * Second-level bootloader, with dual-boot feature by holding F1/Menu + * This is the image being descrambled and executed by the boot ROM. + * It's task is to copy Rockbox from Flash to DRAM. + * The image(s) in flash may optionally be compressed with UCL 2e + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "sh7034.h" +#include "bootloader.h" + + +#ifdef NO_ROM +// start with the vector table +UINT32 vectors[] __attribute__ ((section (".vectors"))) = +{ + (UINT32)_main, // entry point, the copy routine + (UINT32)(end_stack - 1), // initial stack pointer + FLASH_BASE + 0x200, // source of image in flash + (UINT32)total_size, // size of image + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x03020080 // mask and version (just as a suggestion) +}; +#else +// our binary has to start with a vector to the entry point +tpMain start_vector[] __attribute__ ((section (".startvector"))) = {main}; +#endif + +#ifdef NO_ROM // some code which is only needed for the romless variant +void _main(void) +{ + UINT32* pSrc; + UINT32* pDest; + UINT32* pEnd; +/* + asm volatile ("ldc %0,sr" : : "r"(0xF0)); // disable interrupts + asm volatile ("mov.l @%0,r15" : : "r"(4)); // load stack + asm volatile ("ldc %0,vbr" : : "r"(0)); // load vector base +*/ + // copy everything to IRAM and continue there + pSrc = begin_iramcopy; + pDest = begin_text; + pEnd = pDest + (begin_stack - begin_text); + + do + { + *pDest++ = *pSrc++; + } + while (pDest < pEnd); + + main(); // jump to the real main() +} + + +void BootInit(void) +{ + // inits from the boot ROM, whether they make sense or not + PBDR &= 0xFFBF; // LED off (0x131E) + PBCR2 = 0; // all GPIO + PBIOR |= 0x40; // LED output + PBIOR &= 0xFFF1; // LCD lines input + + // init DRAM like the boot ROM does + PACR2 &= 0xFFFB; + PACR2 |= 0x0008; + CASCR = 0xAF; + BCR |= 0x8000; + WCR1 &= 0xFDFD; + DCR = 0x0E00; + RCR = 0x5AB0; + RTCOR = 0x9605; + RTCSR = 0xA518; +} +#endif // #ifdef NO_ROM + + +int main(void) +{ + int nButton; + + PlatformInit(); // model-specific inits + + nButton = ButtonPressed(); + + if (nButton == 3) + { // F3 means start monitor + MiniMon(); + } + else + { + tImage* pImage; + pImage = GetStartImage(nButton); // which image + DecompressStart(pImage); // move into place and start it + } + + return 0; // I guess we won't return ;-) +} + + +// init code that is specific to certain platform +void PlatformInit(void) +{ +#ifdef NO_ROM + BootInit(); // if not started by boot ROM, we need to init what it did +#endif + +#if defined PLATFORM_PLAYER + BRR1 = 0x0019; // 14400 Baud for monitor + if (FW_VERSION > 451) // "new" Player? + { + PBDR &= ~0x10; // set PB4 to 0 to power-up the harddisk early + PBIOR |= 0x10; // make PB4 an output + } +#elif defined PLATFORM_RECORDER + BRR1 = 0x0002; // 115200 Baud for monitor + if (ReadADC(7) > 0x100) // charger plugged? + { // switch off the HD, else a flat battery may not start + PACR2 &= 0xFBFF; // GPIO for PA5 + PAIOR |= 0x20; // make PA5 an output (low by default) + } +#elif defined PLATFORM_FM + BRR1 = 0x0002; // 115200 Baud for monitor + PBDR |= 0x20; // set PB5 to keep power (fixes the ON-holding problem) + PBIOR |= 0x20; // make PB5 an output + if (ReadADC(0) < 0x1FF) // charger plugged? + { + // how do we switch this off? + } +#endif + + // platform-independent inits + DCR |= 0x1000; // enable burst mode on DRAM + BCR |= 0x2000; // activate Warp mode (simultaneous internal and external mem access) +} + + +// Thinned out version of the UCL 2e decompression sourcecode +// Original (C) Markus F.X.J Oberhumer under GNU GPL license +#define GETBIT(bb, src, ilen) \ + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1) + +int ucl_nrv2e_decompress_8( + const UINT8 *src, UINT8 *dst, UINT32* dst_len) +{ + UINT32 bb = 0; + unsigned ilen = 0, olen = 0, last_m_off = 1; + + for (;;) + { + unsigned m_off, m_len; + + while (GETBIT(bb,src,ilen)) + { + dst[olen++] = src[ilen++]; + } + m_off = 1; + for (;;) + { + m_off = m_off*2 + GETBIT(bb,src,ilen); + if (GETBIT(bb,src,ilen)) break; + m_off = (m_off-1)*2 + GETBIT(bb,src,ilen); + } + if (m_off == 2) + { + m_off = last_m_off; + m_len = GETBIT(bb,src,ilen); + } + else + { + m_off = (m_off-3)*256 + src[ilen++]; + if (m_off == 0xffffffff) + break; + m_len = (m_off ^ 0xffffffff) & 1; + m_off >>= 1; + last_m_off = ++m_off; + } + if (m_len) + m_len = 1 + GETBIT(bb,src,ilen); + else if (GETBIT(bb,src,ilen)) + m_len = 3 + GETBIT(bb,src,ilen); + else + { + m_len++; + do { + m_len = m_len*2 + GETBIT(bb,src,ilen); + } while (!GETBIT(bb,src,ilen)); + m_len += 3; + } + m_len += (m_off > 0x500); + { + const UINT8 *m_pos; + m_pos = dst + olen - m_off; + dst[olen++] = *m_pos++; + do dst[olen++] = *m_pos++; while (--m_len > 0); + } + } + *dst_len = olen; + + return ilen; +} + + +// move the image into place and start it +void DecompressStart(tImage* pImage) +{ + UINT32* pSrc; + UINT32* pDest; + + pSrc = pImage->image; + pDest = pImage->pDestination; + + if (pSrc != pDest) // if not linked to that flash address + { + if (pImage->flags & IF_UCL_2E) + { // UCL compressed, algorithm 2e + UINT32 dst_len; // dummy + ucl_nrv2e_decompress_8((UINT8*)pSrc, (UINT8*)pDest, &dst_len); + } + else + { // uncompressed, copy it + UINT32 size = pImage->size; + UINT32* pEnd; + size = (size + 3) / 4; // round up to 32bit-words + pEnd = pDest + size; + + do + { + *pDest++ = *pSrc++; + } + while (pDest < pEnd); + } + } + + pImage->pExecute(); +} + + +int ReadADC(int channel) +{ + // after channel 3, the ports wrap and get re-used + volatile UINT16* pResult = (UINT16*)(ADDRAH_ADDR + 2 * (channel & 0x03)); + int timeout = 266; // conversion takes 266 clock cycles + + ADCSR = 0x20 | channel; // start single conversion + while (((ADCSR & 0x80) == 0) && (--timeout)); // 6 instructions per round + + return (timeout == 0) ? -1 : *pResult>>6; +} + + +// This function is platform-dependent, +// until I figure out how to distinguish at runtime. +int ButtonPressed(void) // return 1,2,3 for F1,F2,F3, 0 if none pressed +{ + int value = ReadADC(CHANNEL); + + if (value >= F1_LOWER && value <= F1_UPPER) // in range + return 1; + else if (value >= F2_LOWER && value <= F2_UPPER) // in range + return 2; + else if (value >= F3_LOWER && value <= F3_UPPER) // in range + return 3; + + return 0; +} + + +// Determine the image to be started +tImage* GetStartImage(int nPreferred) +{ + tImage* pImage1; + tImage* pImage2 = NULL; // default to not present + UINT32 pos; + UINT32* pFlash = (UINT32*)FLASH_BASE; + + // determine the first image position + pos = pFlash[2] + pFlash[3]; // position + size of the bootloader = after it + pos = (pos + 3) & ~3; // be shure it's 32 bit aligned + + pImage1 = (tImage*)pos; + + if (pImage1->size != 0) + { // check for second image + pos = (UINT32)(&pImage1->image) + pImage1->size; + pImage2 = (tImage*)pos; + + // does it make sense? (not in FF or 00 erazed space) + if (pImage2->pDestination == (void*)0xFFFFFFFF + || pImage2->size == 0xFFFFFFFF + || pImage2->pExecute == (void*)0xFFFFFFFF + || pImage2->flags == 0xFFFFFFFF + || pImage2->pDestination == NULL) // size, execute and flags can legally be 0 + { + pImage2 = NULL; // invalidate + } + } + + if (pImage2 == NULL || nPreferred == 1) + { // no second image or overridden: return the first + return pImage1; + } + + return pImage2; // return second image +} + +// diagnostic functions + +void SetLed(BOOL bOn) +{ + if (bOn) + PBDR |= 0x40; + else + PBDR &= ~0x40; +} + + +void UartInit(void) +{ + PBIOR &= 0xFBFF; // input: RXD1 remote pin + PBCR1 |= 0x00A0; // set PB3+PB2 to UART + PBCR1 &= 0xFFAF; // clear bits 6, 4 -> UART + SMR1 = 0x0000; // async format 8N1, baud generator input is CPU clock + SCR1 = 0x0030; // transmit+receive enable + PBCR1 &= 0x00FF; // set bit 12...15 as GPIO + SSR1 &= 0x00BF; // clear bit 6 (RDRF, receive data register full) +} + + +UINT8 UartRead(void) +{ + UINT8 byte; + while (!(SSR1 & SCI_RDRF)); // wait for char to be available + byte = RDR1; + SSR1 &= ~SCI_RDRF; + return byte; +} + + +void UartWrite(UINT8 byte) +{ + while (!(SSR1 & SCI_TDRE)); // wait for transmit buffer empty + TDR1 = byte; + SSR1 &= ~SCI_TDRE; +} + + +// include the mini monitor as a rescue feature, started with F3 +void MiniMon(void) +{ + UINT8 cmd; + UINT32 addr; + UINT32 size; + UINT32 content; + volatile UINT8* paddr = NULL; + volatile UINT8* pflash = NULL; // flash base address + + UartInit(); + + while (1) + { + cmd = UartRead(); + switch (cmd) + { + case BAUDRATE: + content = UartRead(); + UartWrite(cmd); // acknowledge by returning the command value + while (!(SSR1 & SCI_TEND)); // wait for empty shift register, before changing baudrate + BRR1 = content; + break; + + case ADDRESS: + addr = (UartRead() << 24) | (UartRead() << 16) | (UartRead() << 8) | UartRead(); + paddr = (UINT8*)addr; + pflash = (UINT8*)(addr & 0xFFF80000); // round down to 512k align + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_READ: + content = *paddr++; + UartWrite(content); // the content is the ack + break; + + case BYTE_WRITE: + content = UartRead(); + *paddr++ = content; + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_READ16: + size = 16; + while (size--) + { + content = *paddr++; + UartWrite(content); // the content is the ack + } + break; + + case BYTE_WRITE16: + size = 16; + while (size--) + { + content = UartRead(); + *paddr++ = content; + } + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_FLASH: + content = UartRead(); + pflash[0x5555] = 0xAA; // set flash to command mode + pflash[0x2AAA] = 0x55; + pflash[0x5555] = 0xA0; // byte program command + *paddr++ = content; + UartWrite(cmd); // acknowledge by returning the command value + break; + + case BYTE_FLASH16: + size = 16; + while (size--) + { + content = UartRead(); + pflash[0x5555] = 0xAA; // set flash to command mode + pflash[0x2AAA] = 0x55; + pflash[0x5555] = 0xA0; // byte program command + *paddr++ = content; + } + UartWrite(cmd); // acknowledge by returning the command value + break; + + case HALFWORD_READ: + content = *(UINT16*)paddr; + paddr += 2; + UartWrite(content >> 8); // highbyte + UartWrite(content & 0xFF); // lowbyte + break; + + case HALFWORD_WRITE: + content = UartRead() << 8 | UartRead(); + *(UINT16*)paddr = content; + paddr += 2; + UartWrite(cmd); // acknowledge by returning the command value + break; + + case EXECUTE: + { + tpFunc pFunc = (tpFunc)paddr; + pFunc(); + UartWrite(cmd); // acknowledge by returning the command value + } + break; + + case VERSION: + UartWrite(1); // return our version number + break; + + default: + { + SetLed(TRUE); + UartWrite(~cmd); // error acknowledge + } + + } // case + } // while (1) +} diff --git a/flash/bootloader/bootloader.h b/flash/bootloader/bootloader.h new file mode 100644 index 0000000000..eee61c4809 --- /dev/null +++ b/flash/bootloader/bootloader.h @@ -0,0 +1,111 @@ +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +// scalar types +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; +typedef int BOOL; + +typedef void(*tpFunc)(void); // type for execute +typedef int(*tpMain)(void); // type for start vector to main() + + +// structure of an image in the flash +typedef struct +{ + UINT32* pDestination; // address to copy it to + UINT32 size; // how many bytes of payload (to the next header) + tpFunc pExecute; // entry point + UINT32 flags; // uncompressed or compressed + // end of header, now comes the payload + UINT32 image[]; // the binary image starts here + // after the payload, the next header may follow, all 0xFF if none +} tImage; + +// flags valid for image header +#define IF_NONE 0x00000000 +#define IF_UCL_2E 0x00000001 // image is compressed with UCL, algorithm 2e + + +// resolve platform dependency of F1 button check +#if defined PLATFORM_PLAYER +#define CHANNEL 1 +#define F1_LOWER 0 // this is the "Menu" key +#define F1_UPPER 384 +#define F2_LOWER 1024 // not present +#define F2_UPPER 1024 +#define F3_LOWER 1024 +#define F3_UPPER 1024 +#elif defined PLATFORM_RECORDER +#define CHANNEL 4 +#define F1_LOWER 250 +#define F1_UPPER 499 +#define F2_LOWER 500 +#define F2_UPPER 699 +#define F3_LOWER 900 +#define F3_UPPER 1023 +#elif defined PLATFORM_FM +#define CHANNEL 4 +#define F1_LOWER 150 +#define F1_UPPER 384 +#define F2_LOWER 385 +#define F2_UPPER 544 +#define F3_LOWER 700 +#define F3_UPPER 1023 +#else +#error ("No platform given!") +#endif + +#define FLASH_BASE 0x02000000 // start of the flash memory +#define FW_VERSION *(unsigned short*)(FLASH_BASE + 0xFE) // firmware version + + +// prototypes +void _main(void) __attribute__ ((section (".startup"))); +int main(void); +void PlatformInit(void); +void DramInit(void); +int ucl_nrv2e_decompress_8(const UINT8 *src, UINT8 *dst, UINT32* dst_len); +void DecompressStart(tImage* pImage); +int ReadADC(int channel); +int ButtonPressed(void); +tImage* GetStartImage(int nPreferred); +// test functions +void SetLed(BOOL bOn); +void UartInit(void); +UINT8 UartRead(void); +void UartWrite(UINT8 byte); +void MiniMon(void); + + +// minimon commands +#define BAUDRATE 0x00 // followed by BRR value; response: command byte +#define ADDRESS 0x01 // followed by 4 bytes address; response: command byte +#define BYTE_READ 0x02 // response: 1 byte content +#define BYTE_WRITE 0x03 // followed by 1 byte content; response: command byte +#define BYTE_READ16 0x04 // response: 16 bytes content +#define BYTE_WRITE16 0x05 // followed by 16 bytes; response: command byte +#define BYTE_FLASH 0x06 // followed by 1 byte content; response: command byte +#define BYTE_FLASH16 0x07 // followed by 16 bytes; response: command byte +#define HALFWORD_READ 0x08 // response: 2 byte content +#define HALFWORD_WRITE 0x09 // followed by 2 byte content; response: command byte +#define EXECUTE 0x0A // response: command byte if call returns +#define VERSION 0x0B // response: version + + +// linker symbols +extern UINT32 begin_text[]; +extern UINT32 end_text[]; +extern UINT32 begin_data[]; +extern UINT32 end_data[]; +extern UINT32 begin_bss[]; +extern UINT32 end_bss[]; +extern UINT32 begin_stack[]; +extern UINT32 end_stack[]; +extern UINT32 begin_iramcopy[]; +extern UINT32 total_size[]; diff --git a/flash/bootloader/bootloader.lds b/flash/bootloader/bootloader.lds new file mode 100644 index 0000000000..143d83bdc7 --- /dev/null +++ b/flash/bootloader/bootloader.lds @@ -0,0 +1,34 @@ +OUTPUT_FORMAT(elf32-sh) +INPUT(bootloader.o) + +MEMORY +{ + /* the boot ROM uses IRAM at 400-430, stay away and start at 500 */ + IRAM : ORIGIN = 0x0FFFF500, LENGTH = 0xA00 + /* and leave some room for stack at the end */ +} + +SECTIONS +{ + .startvector : + { + *(.startvector) + . = ALIGN(0x4); + } > IRAM + + .text : + { + *(.text) + . = ALIGN(0x4); + } > IRAM + + .data : + { + *(.data) + } > IRAM + + .bss : + { + *(.bss) + } > IRAM +} diff --git a/flash/bootloader/no_rom.lds b/flash/bootloader/no_rom.lds new file mode 100644 index 0000000000..e65e7fdd3c --- /dev/null +++ b/flash/bootloader/no_rom.lds @@ -0,0 +1,62 @@ +/* This is for the variant without boot ROM, + where the flash ROM is mirrored to address zero */ + +OUTPUT_FORMAT(elf32-sh) +INPUT(bootloader.o) + +MEMORY +{ + IRAM : ORIGIN = 0x0FFFF000, LENGTH = 0x1000 + FLASH : ORIGIN = 0x00000000, LENGTH = 0x40000 +} + +SECTIONS +{ + .vectors : + { + *(.vectors) + . = ALIGN(0x200); + } > FLASH + + .startup : + { + *(.startup) + . = ALIGN(0x4); + _begin_iramcopy = .; + } > FLASH + + .text : AT ( _begin_iramcopy ) + { + _begin_text = .; + *(.text) + . = ALIGN(0x4); + _end_text = .; + } > IRAM + + .data : AT ( _end_text ) + { + _begin_data = .; + *(.data) + . = ALIGN(0x4); + _end_data = .; + } > IRAM + + .bss : AT ( _end_data ) + { + _begin_bss = .; + *(.bss) + . = ALIGN(0x4); + _end_bss = .; + } > IRAM + + .stack : + { + _begin_stack = .; + *(.stack) + . = ALIGN(0x1000); + _end_stack = .; + } > IRAM + + /* size of the program (without vectors) */ + _total_size = SIZEOF(.startup) + SIZEOF(.text) + SIZEOF(.data); +} |