Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PORT] Add GD32VF103 support and Sipeed Longan Nano Board support #959

Merged
merged 27 commits into from
Aug 15, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2657560
Add hacky GD32VF103 support
KarlK90 Jul 9, 2021
19b971c
Add board support for gd32vf103 longan nano
KarlK90 Jul 10, 2021
ddb8378
Disable -Werror for now
KarlK90 Jul 10, 2021
771bbe8
Use https github as submodule
KarlK90 Jul 10, 2021
3db2089
Minor clean ups
KarlK90 Jul 10, 2021
23e3b16
Use JTAG for jlink flashing
KarlK90 Jul 10, 2021
790d90b
Set FreeRTOS to RISC-V (doesn't compile)
KarlK90 Jul 11, 2021
e5bd6bd
Update nuclei-sdk with __riscv_flen fix
KarlK90 Jul 12, 2021
ab1979e
Revert "Disable -Werror for now"
KarlK90 Jul 12, 2021
3eb54d8
Add stm32 license header
KarlK90 Aug 3, 2021
c6d495d
Remove dependencies to external libraries for the dcd driver
KarlK90 Aug 7, 2021
7682829
Add correct endpoint count for GD32VF103
KarlK90 Aug 7, 2021
b473923
Remove redundant linker files
KarlK90 Aug 7, 2021
6e287a7
Cleanup include paths and use linker files from nuclei-sdk
KarlK90 Aug 7, 2021
733a362
Use nuclei-sdk functions for init code
KarlK90 Aug 7, 2021
1d2a57a
Remove unsuitable clock configurations from init code
KarlK90 Aug 7, 2021
60d0311
Correctly initialize and handle the system tick
KarlK90 Aug 7, 2021
66d566f
Use functions provided by the nuclei-sdk hal
KarlK90 Aug 7, 2021
0399996
Code style changes
KarlK90 Aug 7, 2021
4cebde6
Remove unnecessary define guard
KarlK90 Aug 7, 2021
8b78067
Use linear buffer for GD32VF103
KarlK90 Aug 7, 2021
27f147f
Minor style changes
KarlK90 Aug 7, 2021
1b6540a
Update systick reload value
KarlK90 Aug 9, 2021
09e4348
move gd32vf103 to its own family
hathach Aug 15, 2021
37d9f94
add gd32vf103 to riscv ci
hathach Aug 15, 2021
73f8fae
change toolchain to riscv-none-embed-gcc-xpack for ci
hathach Aug 15, 2021
c4a6a5c
skip freertos example for gd32vf103
hathach Aug 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,6 @@
[submodule "hw/mcu/mindmotion/mm32sdk"]
path = hw/mcu/mindmotion/mm32sdk
url = https://github.com/zhangslice/mm32sdk.git
[submodule "hw/mcu/gd/nuclei-sdk"]
path = hw/mcu/gd/nuclei-sdk
url = https://github.com/Nuclei-Software/nuclei-sdk.git
Comment on lines +127 to +129
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nuclei-sdk is too overkill as submodule for just low level mcu driver. Furthermore, TinyUSB shouldn't reply on other project to provide hal layer. It is best to just use the mcu driver from the vendor, I think https://github.com/GigaDevice-Semiconductor/GD32VF103_Firmware_Library would be a much better sub-module, since we only need a basic one.

Copy link
Contributor Author

@KarlK90 KarlK90 Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely agree that the nuclei-sdk is overkill for this port, but I had chosen it over the multiple other repositories of the GD32VF firmware on github because their repository is the most up to date one and actively maintained by nucleisys which provided the RV32 core IP. Furthermore there is a bug in the GD32VF startup code in all libaries that throws an compilation error if -Wundef and -Werror is used with GCC, for which I had opened a PR. Therefore I would vote to keep this despite being more then necessary, what do you think?

The other repositories:

https://github.com/riscv-mcu/GD32VF103_Firmware_Library (Semi-official, contains a note to use nuclei-sdk, last activity in October 2020)

https://github.com/GigaDevice-Semiconductor/GD32VF103_Firmware_Library (Is this official?, last real activity in November 2020)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pull the nuclei and did a quick check, the https://github.com/GigaDevice-Semiconductor/GD32VF103_Firmware_Library is more updated in term of the mcu driver. The last activities you said in 2020 is update the mcu lib to v1.1. while nuclei still uses the v1.0 version. nuclei is more maintained by it is mostly for their platform, tinyusb is only interested in low level mcu driver (clock, register def). Therefore I think it make more sense to move to the said repo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused the latest firmware library from GigaDevice is 1.1.2 from June 2021 but can only be found on http://www.gd32mcu.com/en/download/0?kw=GD32VF1 so all the repos are outdated. Judging from the activity in repositories all but nuclei-sdk seem to be unmaintained, as no pull request are merged or answered.

I hope that I don't bother you with this discussion, but I think that nuclei-sdk is the better choice from a maintenance perspective and I would happily open a PR to update the supplied firmware in nuclei-sdk. If that is not an option at all, I'll switch to the suggested https://github.com/GigaDevice-Semiconductor/GD32VF103_Firmware_Library repository.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not bothered at all, I have looked a bit more closer. To be honest, at first I thought Nuclei is a 3rd party, but look like they are IP creator similar to ARM. And Giga put Nuclei's N200 risc-v core into their silicon. Furthermore, Nuclei seems to spend much more effort on the software/firmware side than Giga does. And I could see why you prefer to go with their sdk. Feel free to correct me if I get it wrong.

https://github.com/Nuclei-Software/NMSIS is indeed a really great repo which is set to do what CMSIS does for ARM. I think we could actually depend on this nmsis. However, I still don't want to force any other users to use nuclei sdk just to run the usb stack. They may already be on another platform/framework, that could cause an conflict. Unless there is something that we would really need from sdk that we couldn't write it ourself.

To sum up, do you think it is good enough to just add 2 submodules

This is actually very similar to stm32 with an cmisis and driver combo, https://github.com/hathach/tinyusb/blob/master/hw/bsp/stm32f103bluepill/board.mk#L2

Note: when integrating tinyusb to an application, you can freely use nuclei, and have your own board setup, just changes the include path to the corresponding. The idea is if we use an smaller set of files (mcu lib), it would be more portable.

Copy link
Contributor Author

@KarlK90 KarlK90 Aug 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not bothered at all, I have looked a bit more closer.

That is good to hear!

You are totally right about Nuclei, they provided the N200/BumbleBee Core for the GD32VF103 to GigaDevice and kind of co-developed the firmware library. I'm not sure why GigaDevice doesn't show a bit more effort with their firmware, it is a bit frustrating.

I still don't want to force any other users to use nuclei sdk just to run the usb stack. They may already be on another platform/framework, that could cause an conflict. Unless there is something that we would really need from sdk that we couldn't write it ourself.

I'm totally with you that we don't want conflicts in other projects. I think you are referring to namespace conflicts, like multiple definitions of the same symbol, but correct me here? My point is that the parts that we include and actively use in the compilation of tinyusb from nuclei-sdk is really just the NMSIS library and the gd32vf103 firmware library with modifications from nuclei to play along nicely with NMSIS (see below). The other header and source files related to different socs are not included in the build, it is just the bare minimum. So the conflicts should not increase by using nuclei-sdk and should be the same as using the separate NMSIS and GD32VF103 firmware repositories.

On the other hand I had started to change the current port to use the two independent repositories as suggested and ran into trouble. The NMSIS library wants specific defines that describe the capabilities of the GD32VF103. Unfortunately we can't just use this file because the GD32VF103 doesn't have a FPU and has other IRQs defined. So we would have to provide this block ourselfs in a separate header file before including nmsis_core.h in the dcd driver.

But by doing so we have a board specific header-file in a rather generic driver, which is not good. The nuclei-sdk provides these defines in gd32vf103.h which is different from the gd32vf103.h that is supplied with the firmware library. And they actually modified the firmware library in other parts to play a long nicely with NMSIS framework. The GD32VF103 firmware library is really just meant to be used on its own. There maybe even more conflicts that but I haven't explored that way further.

Given the above reasons and addressing your concerns about the conflicts could a dependency on just nuclei-sdk be the better option? What do you think?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is good to hear!

You know this much better than me, there is obvious reason why you prefer the nuclei sdk

You are totally right about Nuclei, they provided the N200/BumbleBee Core for the GD32VF103 to GigaDevice and kind of co-developed the firmware library. I'm not sure why GigaDevice doesn't show a bit more effort with their firmware, it is a bit frustrating.

Yeah, I figured it out, Giga doesn't spend much effort like ST do with their stm32

But by doing so we have a board specific header-file in a rather generic driver, which is not good. The nuclei-sdk provides these defines in gd32vf103.h which is different from the gd32vf103.h that is supplied with the firmware library. And they actually modified the firmware library in other parts to play a long nicely with NMSIS framework. The GD32VF103 firmware library is really just meant to be used on its own. There maybe even more conflicts that but I haven't explored that way further.

Given the above reasons and addressing your concerns about the conflicts could a dependency on just nuclei-sdk be the better option? What do you think?

My ultimate goal is not having usb stack to depend on nuclei-sdk to run. User should just compile it with any GD32VF103_Firmware_Library variant, especially one downloaded from the Giga site since that is what user will do. With that in mind, in the fact the nuclei has to modify the library to get it work with nmsis, I think we actually have to change the approach a bit.

  1. We can keep using nuclei-sdk, and use it for running example only ie. bsp folder.
  2. However we shouldn't use any of nuclei-sdk and/or nmsis within the src folder, i.e the dcd_synopsys.c. The reason is it will force user to use the modified firmware lib from nuclei and not be able to use official lib downloaded from Giga website. Even it is not well maintained, it is still what most user would use (unfortunately).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me! I'll change the implementation to meet these constraints, maybe the core code in src can even be implemented without any reliance on any gd32vf103 firmawre library or nmsis/nuclei-sdk.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for patiently following my suggestion, yeah, the example bsp is mostly for demonstrating/testing and maintaining. If nuclei-sdk make it easier for us, no problem at all, I wasn't sure before and kind of worry it will become an dependency due to the nmsis. If we could get it dcd_synopsys neutral then that would be no problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect! I have cleaned up and fixed a bug with the systick timer not beeing reloaded. I decided to go with nuclei-sdk inside bsp for obvious reasons ;-). Let me know what you think!

3 changes: 3 additions & 0 deletions hw/bsp/board_mcu.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
#elif CFG_TUSB_MCU == OPT_MCU_RX63X || CFG_TUSB_MCU == OPT_MCU_RX65X
// no header needed

#elif CFG_TUSB_MCU == OPT_MCU_GD32VF103
#include "gd32vf103.h"

#else
#error "Missing MCU header"
#endif
Expand Down
60 changes: 60 additions & 0 deletions hw/bsp/gd32vf103_longan_nano/board.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
CROSS_COMPILE = riscv32-unknown-elf-

DEPS_SUBMODULES += hw/mcu/gd/nuclei-sdk

NUCLEI_SDK = hw/mcu/gd/nuclei-sdk
GD32VF103_SDK_SOC_COMMON = $(NUCLEI_SDK)/SoC/gd32vf103/Common
GD32VF103_SDK_DRIVER = $(GD32VF103_SDK_SOC_COMMON)/Source/Drivers
SKIP_NANOLIB = 1

CFLAGS += \
-march=rv32imac \
-mabi=ilp32 \
-mcmodel=medlow \
-mstrict-align \
-nostdlib -nostartfiles \
-DCFG_TUSB_MCU=OPT_MCU_GD32VF103 \
-DDOWNLOAD_MODE=DOWNLOAD_MODE_FLASHXIP \
-DGD32VF103

# mcu driver cause following warnings
#CFLAGS += -Wno-error=unused-parameter

# All source paths should be relative to the top level.
LD_FILE = hw/bsp/$(BOARD)/gcc_gd32vf103xb_flashxip.ld # Longan Nano 128k ROM 32k RAM
# LD_FILE = hw/bsp/$(BOARD)/gcc_gd32vf103x8_flashxip.ld # Longan Nano Lite 64k ROM 20k RAM

SRC_C += \
src/portable/st/synopsys/dcd_synopsys.c \
$(GD32VF103_SDK_DRIVER)/gd32vf103_rcu.c \
$(GD32VF103_SDK_DRIVER)/gd32vf103_gpio.c \
$(GD32VF103_SDK_DRIVER)/Usb/gd32vf103_usb_hw.c \
$(GD32VF103_SDK_DRIVER)/gd32vf103_usart.c \
$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/sbrk.c \
$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/close.c \
$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/isatty.c \
$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/fstat.c \
$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/lseek.c \
$(GD32VF103_SDK_SOC_COMMON)/Source/Stubs/read.c

SRC_S += \
$(GD32VF103_SDK_SOC_COMMON)/Source/GCC/startup_gd32vf103.S \
$(GD32VF103_SDK_SOC_COMMON)/Source/GCC/intexc_gd32vf103.S

INC += \
$(TOP)/hw/bsp/$(BOARD) \
$(TOP)/$(NUCLEI_SDK)/NMSIS/Core/Include \
$(TOP)/$(GD32VF103_SDK_SOC_COMMON)/Include \
$(TOP)/$(GD32VF103_SDK_SOC_COMMON)/Include/Usb \

# For freeRTOS port source
FREERTOS_PORT = RISC-V

# For flash-jlink target
JLINK_IF = jtag
JLINK_DEVICE = gd32vf103cbt6 # Longan Nano 128k ROM 32k RAM
#JLINK_DEVICE = gd32vf103c8t6 # Longan Nano Lite 64k ROM 20k RAM

# flash target ROM bootloader
flash: $(BUILD)/$(PROJECT).bin
dfu-util -R -a 0 --dfuse-address 0x08000000 -D $<
284 changes: 284 additions & 0 deletions hw/bsp/gd32vf103_longan_nano/gcc_gd32vf103x8_flashxip.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
/*
* Copyright (c) 2019 - 2020 Nuclei Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************************************************
* @file gcc_gd32vf103x8_flashxip.ld
* @brief GNU Linker Script for gd32vf103x8 based device
* @version V1.0.0
* @date 1. Dec 2020
******************************************************************************/

/*********** Use Configuration Wizard in Context Menu *************************/

OUTPUT_ARCH( "riscv" )
/********************* Flash Configuration ************************************
* <h> Flash Configuration
* <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
* <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
* </h>
*/
__ROM_BASE = 0x08000000;
__ROM_SIZE = 0x00010000;

/*--------------------- ILM RAM Configuration ---------------------------
* <h> ILM RAM Configuration
* <o0> ILM RAM Base Address <0x0-0xFFFFFFFF:8>
* <o1> ILM RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
* </h>
*/
__ILM_RAM_BASE = 0x80000000;
__ILM_RAM_SIZE = 0x00010000;

/*--------------------- Embedded RAM Configuration ---------------------------
* <h> RAM Configuration
* <o0> RAM Base Address <0x0-0xFFFFFFFF:8>
* <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
* </h>
*/
__RAM_BASE = 0x20000000;
__RAM_SIZE = 0x00005000;

/********************* Stack / Heap Configuration ****************************
* <h> Stack / Heap Configuration
* <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
* <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
* </h>
*/
__STACK_SIZE = 0x00000800;
__HEAP_SIZE = 0x00000800;

/**************************** end of configuration section ********************/

/* Define base address and length of flash and ram */
MEMORY
{
flash (rxai!w) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
ram (wxa!ri) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
}
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH,ILM and RAM.
* It references following symbols, which must be defined in code:
* _Start : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* _ilm_lma
* _ilm
* __etext
* _etext
* etext
* _eilm
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* _data_lma
* _edata
* edata
* __data_end__
* __bss_start
* __fbss
* _end
* end
* __heap_end
* __StackLimit
* __StackTop
* __STACK_SIZE
*/
/* Define entry label of program */
ENTRY(_start)
SECTIONS
{
__STACK_SIZE = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2K;

.init :
{
/* vector table locate at flash */
*(.vtable)
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash

.ilalign :
{
. = ALIGN(4);
/* Create a section label as _ilm_lma which located at flash */
PROVIDE( _ilm_lma = . );
} >flash AT>flash

.ialign :
{
/* Create a section label as _ilm which located at flash */
PROVIDE( _ilm = . );
} >flash AT>flash

/* Code section located at flash */
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash

.rodata : ALIGN(4)
{
. = ALIGN(4);
*(.rdata)
*(.rodata .rodata.*)
/* section information for initial. */
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
*(.gnu.linkonce.r.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >flash AT>flash

.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash

. = ALIGN(4);

PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
PROVIDE( _eilm = . );


.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash

.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash

.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash

.ctors :
{
/* gcc uses crtbegin.o to find the start of
* the constructors, so we make sure it is
* first. Because this is a wildcard, it
* doesn't matter if the user does not
* actually link against crtbegin.o; the
* linker won't look for a file to match a
* wildcard. The wildcard also means that it
* doesn't matter which directory crtbegin.o
* is in.
*/
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
* the crtend.o file until after the sorted ctors.
* The .ctor section from the crtend file contains the
* end of ctors marker and it must be last
*/
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash

.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash

.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash

.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash

/* Define data section virtual address is ram and physical address is flash */
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.* .sdata*)
*(.gnu.linkonce.s.*)
} >ram AT>flash

. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );

PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram

. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
/* Define stack and head location at ram */
.stack ORIGIN(ram) + LENGTH(ram) - __STACK_SIZE :
{
PROVIDE( _heap_end = . );
. = __STACK_SIZE;
PROVIDE( _sp = . );
} >ram AT>ram
}
Loading