Skip to content

Commit eb3ea9e

Browse files
committed
stm32: Add support for STM32N6xx MCUs.
This commit adds preliminary support for ST's new STM32N6xx MCUs. Supported features of this MCU so far are: - basic clock tree initialisation, running at 800MHz - fully working USB - XSPI in memory-mapped mode - machine.Pin - machine.UART - RTC and deepsleep support - SD card - filesystem - ROMFS - WiFi and BLE via cyw43-driver (SDIO backend) Note that the N6 does not have internal flash, and has some tricky boot sequence, so using a custom bootloader (mboot) is almost a necessity. Signed-off-by: Damien George <damien@micropython.org>
1 parent 24fd5f7 commit eb3ea9e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1659
-135
lines changed

ports/stm32/Makefile

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,15 @@ CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
123123
CFLAGS += -DMBOOT_VTOR=$(MBOOT_TEXT0_ADDR)
124124
CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR)
125125

126+
ifeq ($(MCU_SERIES),n6)
127+
ifeq ($(USE_MBOOT),1)
128+
CFLAGS += -DMICROPY_HW_RUNS_FROM_EXT_FLASH=1
129+
endif
130+
# as doesn't recognise -mcpu=cortex-m55
131+
AFLAGS += -march=armv8.1-m.main
132+
else
126133
AFLAGS += $(filter -mcpu=%,$(CFLAGS_MCU_$(MCU_SERIES)))
134+
endif
127135

128136
# Configure for nan-boxing object model if requested
129137
ifeq ($(NANBOX),1)
@@ -300,6 +308,7 @@ SRC_C += \
300308
adc.c \
301309
sdio.c \
302310
subghz.c \
311+
xspi.c \
303312
$(wildcard $(BOARD_DIR)/*.c)
304313

305314
SRC_O += \
@@ -316,6 +325,13 @@ CFLAGS += -DUSE_HAL_DRIVER
316325
SRC_O += \
317326
resethandler_m3.o \
318327
shared/runtime/gchelper_thumb2.o
328+
else ifeq ($(MCU_SERIES),n6)
329+
SRC_O += shared/runtime/gchelper_thumb2.o
330+
ifeq ($(USE_MBOOT),1)
331+
SRC_O += resethandler_iram.o
332+
else
333+
SRC_O += resethandler.o
334+
endif
319335
else
320336
SRC_O += \
321337
system_stm32.o \
@@ -329,8 +345,6 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
329345
hal_adc_ex.c \
330346
hal_cortex.c \
331347
hal_dma.c \
332-
hal_flash.c \
333-
hal_flash_ex.c \
334348
hal_gpio.c \
335349
hal_i2c.c \
336350
hal_pwr.c \
@@ -347,15 +361,30 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
347361
ll_utils.c \
348362
)
349363

350-
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 l0 l1 l4 wb))
364+
ifneq ($(MCU_SERIES),n6)
365+
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
366+
hal_flash.c \
367+
hal_flash_ex.c \
368+
)
369+
endif
370+
371+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 l0 l1 l4 n6 wb))
351372
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
352373
hal_pcd.c \
353374
hal_pcd_ex.c \
354375
ll_usb.c \
355376
)
356377
endif
357378

358-
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h5 h7 l4))
379+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
380+
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
381+
hal_bsec.c \
382+
hal_rif.c \
383+
hal_xspi.c \
384+
)
385+
endif
386+
387+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h5 h7 l4 n6))
359388
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
360389
hal_sd.c \
361390
ll_sdmmc.c \
@@ -380,7 +409,7 @@ $(BUILD)/$(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_hal_mmc.o: CFLAGS += -Wno
380409
endif
381410
endif
382411

383-
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7))
412+
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 g0 g4 h5 h7 n6))
384413
HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\
385414
hal_dma_ex.c \
386415
)
@@ -496,6 +525,12 @@ all: $(TOP)/lib/stm32lib/README.md all_main $(BUILD)/firmware.hex
496525

497526
ifeq ($(MBOOT_ENABLE_PACKING),1)
498527
all_main: $(BUILD)/firmware.pack.dfu
528+
else ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
529+
ifeq ($(USE_MBOOT),1)
530+
all_main: $(BUILD)/firmware.dfu
531+
else
532+
all_main: $(BUILD)/firmware-trusted.bin
533+
endif
499534
else
500535
all_main: $(BUILD)/firmware.dfu
501536
endif
@@ -556,7 +591,7 @@ define GENERATE_HEX
556591
$(Q)$(OBJCOPY) -O ihex $(2) $(1)
557592
endef
558593

559-
.PHONY: deploy deploy-stlink deploy-openocd
594+
.PHONY: deploy deploy-stlink deploy-openocd deploy-trusted
560595

561596
ifeq ($(MBOOT_ENABLE_PACKING),1)
562597
deploy: $(BUILD)/firmware.pack.dfu
@@ -566,6 +601,9 @@ deploy: $(BUILD)/firmware.dfu
566601
$(call RUN_DFU,$^)
567602
endif
568603

604+
deploy-trusted: $(BUILD)/firmware-trusted.bin
605+
$(STM32_CUBE_PROGRAMMER)/bin/STM32_Programmer.sh -c port=SWD mode=HOTPLUG ap=1 -el $(DKEL) -w $^ 0x70000000 -hardRst
606+
569607
# A board should specify TEXT0_ADDR if to use a different location than the
570608
# default for the firmware memory location. A board can also optionally define
571609
# TEXT1_ADDR to split the firmware into two sections; see below for details.
@@ -620,6 +658,10 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf
620658
$(BUILD)/firmware.elf: $(OBJ)
621659
$(call GENERATE_ELF,$@,$^)
622660

661+
$(BUILD)/firmware-trusted.bin: $(BUILD)/firmware.bin
662+
/bin/rm -f $@
663+
$(STM32_CUBE_PROGRAMMER)/bin/STM32_SigningTool_CLI -bin $^ -nk -of 0x80000000 -t fsbl -o $@ -hv $(STM32_N6_HEADER_VERSION)
664+
623665
# List of sources for qstr extraction
624666
SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(GEN_PINS_SRC)
625667

ports/stm32/adc.c

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
/// val = adc.read_core_vref() # read MCU VREF
5252

5353
/* ADC definitions */
54-
#if defined(STM32H5)
54+
#if defined(STM32H5) || defined(STM32N6)
5555
// STM32H5 features two ADC instances, ADCx and pin_adc_table are set dynamically
5656
#define PIN_ADC_MASK (PIN_ADC1 | PIN_ADC2)
5757
#else
@@ -107,7 +107,7 @@
107107
#define ADC_CAL2 ((uint16_t *)(ADC_CAL_ADDRESS + 4))
108108
#define ADC_CAL_BITS (12)
109109

110-
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB)
110+
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L1) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
111111

112112
#define ADC_SCALE_V (((float)VREFINT_CAL_VREF) / 1000.0f)
113113
#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR)
@@ -166,6 +166,9 @@
166166
#define VBAT_DIV (3)
167167
#elif defined(STM32L152xE)
168168
// STM32L152xE does not have vbat.
169+
#elif defined(STM32N6)
170+
// ADC2 VINP 16
171+
#define VBAT_DIV (4)
169172
#else
170173
#error Unsupported processor
171174
#endif
@@ -247,7 +250,7 @@ static bool is_adcx_channel(int channel) {
247250
handle.Instance = ADCx;
248251
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
249252
|| IS_ADC_CHANNEL(&handle, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
250-
#elif defined(STM32H5)
253+
#elif defined(STM32H5) || defined(STM32N6)
251254
// The first argument to the IS_ADC_CHANNEL macro is unused.
252255
return __HAL_ADC_IS_CHANNEL_INTERNAL(channel)
253256
|| IS_ADC_CHANNEL(NULL, __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel));
@@ -260,7 +263,7 @@ static void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t ti
260263
uint32_t tickstart = HAL_GetTick();
261264
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
262265
while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
263-
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
266+
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
264267
while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
265268
#else
266269
#error Unsupported processor
@@ -279,7 +282,7 @@ static void adcx_clock_enable(ADC_HandleTypeDef *adch) {
279282
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
280283
#elif defined(STM32G0)
281284
__HAL_RCC_ADC_CLK_ENABLE();
282-
#elif defined(STM32G4)
285+
#elif defined(STM32G4) || defined(STM32N6)
283286
__HAL_RCC_ADC12_CLK_ENABLE();
284287
#elif defined(STM32H5)
285288
__HAL_RCC_ADC_CLK_ENABLE();
@@ -352,6 +355,15 @@ static void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
352355
adch->Init.OversamplingMode = DISABLE;
353356
adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
354357
adch->Init.DMAContinuousRequests = DISABLE;
358+
#elif defined(STM32N6)
359+
adch->Init.GainCompensation = 0;
360+
adch->Init.ScanConvMode = ADC_SCAN_DISABLE;
361+
adch->Init.LowPowerAutoWait = DISABLE;
362+
adch->Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL;
363+
adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
364+
adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
365+
adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
366+
adch->Init.OversamplingMode = DISABLE;
355367
#else
356368
#error Unsupported processor
357369
#endif
@@ -384,7 +396,7 @@ static void adc_init_single(pyb_obj_adc_t *adc_obj, ADC_TypeDef *adc) {
384396
static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
385397
ADC_ChannelConfTypeDef sConfig;
386398

387-
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
399+
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
388400
sConfig.Rank = ADC_REGULAR_RANK_1;
389401
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel) == 0) {
390402
channel = __HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel);
@@ -433,6 +445,18 @@ static void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
433445
sConfig.SingleDiff = ADC_SINGLE_ENDED;
434446
sConfig.OffsetNumber = ADC_OFFSET_NONE;
435447
sConfig.Offset = 0;
448+
#elif defined(STM32N6)
449+
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
450+
sConfig.SamplingTime = ADC_SAMPLETIME_246CYCLES_5;
451+
} else {
452+
sConfig.SamplingTime = ADC_SAMPLETIME_11CYCLES_5;
453+
}
454+
sConfig.SingleDiff = ADC_SINGLE_ENDED;
455+
sConfig.OffsetNumber = ADC_OFFSET_NONE;
456+
sConfig.Offset = 0;
457+
sConfig.OffsetSignedSaturation = DISABLE;
458+
sConfig.OffsetSaturation = DISABLE;
459+
sConfig.OffsetSign = ADC_OFFSET_SIGN_POSITIVE;
436460
#else
437461
#error Unsupported processor
438462
#endif
@@ -510,7 +534,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
510534
// 1st argument is the pin name
511535
mp_obj_t pin_obj = args[0];
512536

513-
#if defined(STM32H5)
537+
#if defined(STM32H5) || defined(STM32N6)
514538
// STM32H5 has two ADC instances where some pins are only available on ADC1 or ADC2 (but not both).
515539
// Assume we're using a channel of ADC1. Can be overridden for ADC2 later in this function.
516540
ADC_TypeDef *adc = ADC1;
@@ -527,7 +551,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
527551
// No ADC function on the given pin.
528552
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin(%q) doesn't have ADC capabilities"), pin->name);
529553
}
530-
#if defined(STM32H5)
554+
#if defined(STM32H5) || defined(STM32N6)
531555
if ((pin->adc_num & PIN_ADC2) == PIN_ADC2) {
532556
adc = ADC2;
533557
pin_adc_table = pin_adc2;
@@ -542,7 +566,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
542566
}
543567

544568
// If this channel corresponds to a pin then configure the pin in ADC mode.
545-
#if defined(STM32H5)
569+
#if defined(STM32H5) || defined(STM32N6)
546570
if (channel < num_adc_pins) {
547571
const machine_pin_obj_t *pin = pin_adc_table[channel];
548572
if (pin != NULL) {
@@ -563,7 +587,7 @@ static mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
563587
o->base.type = &pyb_adc_type;
564588
o->pin_name = pin_obj;
565589
o->channel = channel;
566-
#if defined(STM32H5)
590+
#if defined(STM32H5) || defined(STM32N6)
567591
adc_init_single(o, adc);
568592
#else
569593
adc_init_single(o, ADCx);
@@ -654,7 +678,7 @@ static mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
654678
// for subsequent samples we can just set the "start sample" bit
655679
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
656680
self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
657-
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
681+
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
658682
SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART);
659683
#else
660684
#error Unsupported processor
@@ -764,7 +788,7 @@ static mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
764788
// ADC is started: set the "start sample" bit
765789
#if defined(STM32F4) || defined(STM32F7) || defined(STM32L1)
766790
adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
767-
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
791+
#elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L4) || defined(STM32N6) || defined(STM32WB)
768792
SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART);
769793
#else
770794
#error Unsupported processor
@@ -898,6 +922,8 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
898922
} else {
899923
return 0;
900924
}
925+
#elif defined(STM32N6)
926+
int32_t raw_value = 0; // TODO
901927
#else
902928
int32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_TEMPSENSOR);
903929
#endif
@@ -909,6 +935,10 @@ int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) {
909935
static volatile float adc_refcor = 1.0f;
910936

911937
float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
938+
#if defined(STM32N6)
939+
return 0.0f; // TODO
940+
#else
941+
912942
#if defined(STM32G4) || defined(STM32L1) || defined(STM32L4)
913943
// Update the reference correction factor before reading tempsensor
914944
// because TS_CAL1 and TS_CAL2 of STM32G4,L1/L4 are at VDDA=3.0V
@@ -931,6 +961,8 @@ float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) {
931961
float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0f;
932962
#endif
933963
return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f;
964+
965+
#endif
934966
}
935967

936968
float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {

ports/stm32/adc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) {
4848
adc_common = ADC_COMMON_REGISTER(0);
4949
#elif defined(STM32F7)
5050
adc_common = ADC123_COMMON;
51-
#elif defined(STM32G4) || defined(STM32H5)
51+
#elif defined(STM32G4) || defined(STM32H5) || defined(STM32N6)
5252
adc_common = ADC12_COMMON;
5353
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
5454
adc_common = ADC12_COMMON;

ports/stm32/boardctrl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,6 @@ int boardctrl_run_boot_py(boardctrl_state_t *state);
122122
int boardctrl_run_main_py(boardctrl_state_t *state);
123123
void boardctrl_start_soft_reset(boardctrl_state_t *state);
124124
void boardctrl_end_soft_reset(boardctrl_state_t *state);
125+
void boardctrl_enter_standby(void);
125126

126127
#endif // MICROPY_INCLUDED_STM32_BOARDCTRL_H

ports/stm32/boards/common_n6_flash.ld

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* Memory layout for N6 when the application runs from external flash in XIP mode.
2+
3+
FLASH_APP .isr_vector
4+
FLASH_APP .text
5+
FLASH_APP .data
6+
7+
RAM .data
8+
RAM .bss
9+
RAM .heap
10+
RAM .stack
11+
*/
12+
13+
ENTRY(Reset_Handler)
14+
15+
REGION_ALIAS("FLASH_COMMON", FLASH_APP);
16+
17+
/* define output sections */
18+
SECTIONS
19+
{
20+
.isr_vector :
21+
{
22+
_siram = .;
23+
24+
/* This ISR is used for normal application mode. */
25+
. = ALIGN(1024);
26+
KEEP(*(.isr_vector));
27+
28+
/* This ISR is used when waking from STANDBY. */
29+
. = ALIGN(1024);
30+
KEEP(*(.rodata.iram_bootloader_isr_vector));
31+
32+
/* Need to place in RAM all the code necessary to write to
33+
* flash, and to resume from STANDBY. */
34+
*(.*.iram_bootloader_reset);
35+
*(.*.memcpy);
36+
*(.*.mp_hal_gpio_clock_enable);
37+
*(.*.mp_hal_pin_config);
38+
*(.*.mp_hal_pin_config_speed);
39+
*drivers/memory/spiflash.o(.text.* .rodata.*)
40+
*xspi.o(.text.* .rodata.*);
41+
*boards*(.rodata.spiflash_config*)
42+
*boards*(.*.board_leave_standby);
43+
*(*.rodata.pin_N*_obj);
44+
*(.text.LL_AHB4_GRP1_EnableClock);
45+
*(.text.LL_APB4_GRP2_EnableClock);
46+
47+
. = ALIGN(4);
48+
_eiram = .;
49+
} >IRAM AT> FLASH_COMMON
50+
51+
INCLUDE common_text.ld
52+
INCLUDE common_extratext_data_in_flash.ld
53+
INCLUDE common_bss_heap_stack.ld
54+
}
55+
56+
/* Used by the start-up code to initialise data */
57+
_siiram = LOADADDR(.isr_vector);

ports/stm32/boards/common_text.ld

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@
1212
. = ALIGN(4);
1313
_etext = .; /* define a global symbol at end of code */
1414
} >FLASH_COMMON
15+
16+
/* Secure Gateway stubs */
17+
.gnu.sgstubs :
18+
{
19+
. = ALIGN(4);
20+
*(.gnu.sgstubs*)
21+
. = ALIGN(4);
22+
} >FLASH_COMMON

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy