/* =============================================================================
 * STM32F407VGTx_FLASH.ld - GNU ld 링커 스크립트 (ST 스타일)
 *
 * 대상: STM32F407VGT6 (Cortex-M4F)
 *   FLASH   1024K @ 0x08000000  (코드/상수/초기화 데이터 원본)
 *   RAM      128K @ 0x20000000  (SRAM1+SRAM2, .data/.bss/heap/stack)
 *   CCMRAM    64K @ 0x10000000  (Core-Coupled Memory; DMA 접근 불가)
 *
 * CCMRAM 활용(중요):
 *   CCMRAM 은 코어 전용 64K 버스로 데이터 접근 지연이 적다(코드 페치 불가,
 *   DMA/이더넷 DMA 디스크립터/버퍼 사용 불가). 핫한 비-DMA 데이터를 두기에 좋다.
 *   - FreeRTOS heap_4 의 ucHeap 을 CCMRAM 에 두려면 heap_4.c 가 참조하는
 *     배열에 __attribute__((section(".ccmram"))) 를 부여하거나, configAPPLICATION_
 *     ALLOCATED_HEAP=1 로 두고 사용자 정의 ucHeap[] 를 .ccmram 에 배치한다.
 *   - 특정 태스크 스택을 CCMRAM 에 두려면 static StackType_t 배열에
 *     section(".ccmram") 를 지정하고 xTaskCreateStatic() 으로 생성한다.
 *   주의: LwIP/ETH DMA 버퍼는 절대 CCMRAM 에 두지 말 것(이더넷 DMA 비접근).
 * ===========================================================================*/

/* 진입점(startup_stm32f407xx.s 의 리셋 핸들러). */
ENTRY(Reset_Handler)

/* ── 스택/힙 최소 크기 (startup 어셈블리/sbrk 가 참조) ───────────────────── */
/* _estack: 메인 스택 포인터 초기값(RAM 최상단). 인터럽트/스케줄러 시작 전 사용. */
_Min_Heap_Size  = 0x400;   /* newlib malloc/sbrk 최소 힙 (FreeRTOS 는 자체 힙 사용) */
_Min_Stack_Size = 0x800;   /* 메인/인터럽트 스택 최소 (2K) */

/* ── 메모리 영역 ─────────────────────────────────────────────────────────── */
MEMORY
{
  FLASH  (rx)  : ORIGIN = 0x08000000, LENGTH = 1024K
  RAM    (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
  CCMRAM (rw)  : ORIGIN = 0x10000000, LENGTH = 64K
}

/* RAM 최상단을 메인 스택 초기 포인터로 사용. */
_estack = ORIGIN(RAM) + LENGTH(RAM);

/* ── 섹션 배치 ───────────────────────────────────────────────────────────── */
SECTIONS
{
  /* 1) 인터럽트 벡터 테이블 — 플래시 선두(0x08000000). */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))   /* startup 의 벡터 테이블 (가비지 컬렉션 금지) */
    . = ALIGN(4);
  } >FLASH

  /* 2) 코드 (.text). */
  .text :
  {
    . = ALIGN(4);
    *(.text)
    *(.text*)
    *(.glue_7)             /* ARM/Thumb 인터워킹 glue */
    *(.glue_7t)
    *(.eh_frame)
    KEEP(*(.init))
    KEEP(*(.fini))
    . = ALIGN(4);
    _etext = .;            /* 코드 끝 */
  } >FLASH

  /* 3) 읽기 전용 데이터 (.rodata: const, 문자열, CA PEM 등). */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
    . = ALIGN(4);
  } >FLASH

  /* ARM 예외 처리 인덱스(EHABI). nano/nosys 에서도 링크 정합성을 위해 유지. */
  .ARM.extab :
  {
    . = ALIGN(4);
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    . = ALIGN(4);
  } >FLASH

  .ARM :
  {
    . = ALIGN(4);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(4);
  } >FLASH

  /* C++ / libc 초기화 배열(preinit/init/fini). startup 이 호출. */
  .preinit_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN(__preinit_array_start = .);
    KEEP(*(.preinit_array*))
    PROVIDE_HIDDEN(__preinit_array_end = .);
    . = ALIGN(4);
  } >FLASH

  .init_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN(__init_array_start = .);
    KEEP(*(SORT(.init_array.*)))
    KEEP(*(.init_array*))
    PROVIDE_HIDDEN(__init_array_end = .);
    . = ALIGN(4);
  } >FLASH

  .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN(__fini_array_start = .);
    KEEP(*(SORT(.fini_array.*)))
    KEEP(*(.fini_array*))
    PROVIDE_HIDDEN(__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH

  /* _sidata: 초기화 데이터(.data)의 "원본" 위치(플래시). startup 이
   * _sdata.._edata 로 복사한다. */
  _sidata = LOADADDR(.data);

  /* 4) 초기화된 데이터 (.data) — 실행 주소는 RAM, 로드 주소는 FLASH. */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;            /* .data 시작 (RAM) — startup 이 참조 */
    *(.data)
    *(.data*)
    *(.RamFunc)            /* RAM 에서 실행해야 하는 함수(예: 플래시 프로그래밍) */
    *(.RamFunc*)
    . = ALIGN(4);
    _edata = .;            /* .data 끝 (RAM) */
  } >RAM AT> FLASH

  /* 5) 초기화되지 않은 데이터 (.bss) — 0 으로 초기화(startup). */
  .bss :
  {
    . = ALIGN(4);
    _sbss = .;             /* .bss 시작 — startup 이 참조 */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    _ebss = .;             /* .bss 끝 */
    __bss_end__ = _ebss;
  } >RAM

  /* 6) 힙/스택 가드 — 최소 크기 확보(부족 시 링크 에러). */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE(end = .);       /* newlib _sbrk 의 힙 시작(end / _end) */
    PROVIDE(_end = .);
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM

  /* 7) CCMRAM(.ccmram) — 코어 전용 64K. 비-DMA 데이터/스택 전용.
   *    배치 예: __attribute__((section(".ccmram"))) static uint8_t ucHeap[...];
   *    초기화 필요한 .ccmram 데이터를 쓰려면 .data 처럼 별도 복사 루프가 필요하나,
   *    기본은 무초기화(NOLOAD) 영역으로 둔다(런타임에 명시 초기화 권장). */
  .ccmram (NOLOAD) :
  {
    . = ALIGN(4);
    _sccmram = .;
    *(.ccmram)
    *(.ccmram*)
    . = ALIGN(4);
    _eccmram = .;
  } >CCMRAM

  /* 디버그/주석 섹션 제거(산출물 슬림화). */
  /DISCARD/ :
  {
    *(.ARM.attributes)
  }
}
