Cortex-M4(F) Lazy Stacking and Context Switching (1)

이번 포스팅에서는 Interrupt 디버깅이나 RTOS 개발에 필요한 Cortex-M4(F) Lazy Stacking and Context Switching에 대한 Application note를 번역기를 돌린 내용입니다.

Introduction

Cortex-M4 프로세서는 ARMv7E-M 아키텍처를 기반으로 하며 Cortex-M3와 유사합니다. ARM Cortex-M3와 동일한 일반적인 데이터 처리를 위한 정수(integer) 레지스터 뱅크와 스택 기반 예외 모델을 가지고 있습니다.

Cortex-M4 제품은 다음과 같이 제공됩니다.

  • FPU가 없는 Cortex-M4
  • FPU가 있는 Cortex-M4F.

Cortex-M4F를 Cortex-M4 또는 Cortex-M3과 비교하면 Cortex-M4F에는 S0 – S31 범위의 추가 부동 소수점 레지스터 뱅크와 대부분이 메모리 매핑되는 몇 가지 다른 레지스터가 포함됩니다.

Floating-point Status and Control Register (FPSCR)

이것은 FPU의 특수 레지스터이며 메모리 매핑되지 않습니다. 여기에는 부동 소수점 연산을 제어하기 위한 제어 비트 필드와 FPU의 상태를 나타내는 여러 상태 비트 필드가 포함되어 있습니다. VMSR(ARM 코어 레지스터에서 부동 소수점 시스템 레지스터로 이동) 및 VMRS(부동 소수점 시스템 레지스터에서 ARM 코어 레지스터로 이동) 명령어는 FPSCR과 정수 레지스터 뱅크의 범용 레지스터 간에 데이터를 전송하는 데 사용됩니다.

Coprocessor Access Control Register (CPACR)

이 레지스터는 주소 0xE000ED88에 있습니다. FPU를 활성화하려면 CP10 및 CP11 비트 필드인 CPACR의 비트[23:20]을 0xF로 설정해야 합니다. 기본적으로 FPU는 RESET 후에는 비활성화됩니다.

Floating-point Context Control Register (FPCCR)

이 레지스터는 주소 0xE000EF34에 있습니다. 이 레지스터는 컨텍스트 저장 동작을 제어합니다. 기본적으로 lazy stacking 동작을 활성화합니다. 7페이지의 lazy stacking 기능을 참조하십시오.

Floating-point Context Address Register (FPCAR)

이 레지스터는 주소 0xE000EF38에 있습니다. 이 레지스터는 예외(exception) 항목 이후 스택에 아직 저장되지 않은 부동 소수점 레지스터에 대한 예외 스택 프레임에 할당된 예약된 공간의 주소 위치를 보유합니다.

Note : FPCAR 레지스터는 현재 스택 내의 스택 공간 섹션을 가리킵니다. FPCAR의 주소 값은 프로세서의 하드웨어에 의해 자동으로 생성됩니다.

Floating-point Default Status Control Register (FPDSCR)

이 레지스터는 0xE000EF3C에 있습니다. 이 레지스터는 FPSCR의 기본값을 유지합니다.

추가사항

  • Cortex-M3에서도 사용할 수 있는 특수 레지스터인 CONTROL 레지스터에는 FPU 기능을 지원하는 추가 비트 필드가 있습니다. CONTROL 레지스터의 비트[2]는 FPCA(Floating-Point Context Active)로 정의됩니다. 이 비트는 FPU가 사용될 때 자동으로 설정되고 새 컨텍스트가 시작될 때(예: ISR(Interrupt Service Routine) 시작 시) 지워집니다. FPCA 비트는 Cortex-M4F에서만 사용할 수 있습니다. CONTROL 레지스터는 메모리 매핑되지 않습니다. MSR 및 MRS 명령어를 사용하여 이 레지스터에 액세스할 수 있습니다.
  • 예외(exception) 메커니즘에서 사용되는 EXC_RETURN 코드 값에는 부동 소수점 스택 상태를 정의하는 추가 비트 필드가 있습니다. EXC_RETURN[4]의 값이 0이면 예외 반환을 위한 예외 스택 프레임에 부동 소수점 레지스터가 포함되어 있음을 나타냅니다. 이 비트가 1이면 예외 스택 프레임에 부동 소수점 레지스터가 포함되어 있지 않음을 의미합니다.
  • Note : EXC_RETURN(예외 반환)은 예외 처리기에 진입할 때 Cortex-M 프로세서에 의해 자동으로 생성되는 코드 값입니다. 이 값은 링크 레지스터(LR)에 저장되며 예외 반환 시 사용됩니다. 이 코드의 여러 비트는 예를 들어 사용 중인 스택 포인터와 같이 예외 이전의 프로세서 상태에 대한 정보를 저장하는 데 사용됩니다.
  • 예외(exception) 스택 프레임에는 FPU에서 S0-S15 및 FPSCR 레지스터의 자동 저장을 허용하는 5페이지의 그림 1에 표시된 추가 형식 유형이 있습니다. 이것은 R0-R3, R12, LR, PC, 스페이서로 구성된 Cortex-M3 스택 프레임에 저장되는 레지스터에 추가됩니다. Cortex-M3의 원래 스택 프레임 형식 유형은 부동 소수점 레지스터의 스택이 필요하지 않은 경우에도 사용됩니다.

ARM 아키텍처용 프로시저 호출 표준(AAPCS)에 명시된 요구 사항에 따라 C 함수는 함수 실행 중에 사용될 때만 S16-S31에서 해당 레지스터를 보존해야 합니다. FPU의 다른 레지스터, 즉 S0-S15 및 FPSCR은 항상 자동으로 저장됩니다. 이러한 레지스터는 C 함수로 수정할 수도 있습니다.

인터럽트 핸들러가 일반 C 함수로 작성되도록 하려면 부동 소수점 레지스터의 현재 내용이 나중에 필요할 수 있을 때 프로세서가 S0-S15 레지스터와 FPSCR을 스택에 자동으로 저장해야 합니다.

  • FPU가 사용된 경우(CONTROL 레지스터의 FPCA 비트에 1로 표시됨) 프로세서는 R0-R3, R12, LR, PC 및 스페이서 외에도 S0-S15 및 FPSCR을 스택에 자동으로 저장해야 합니다. 기존 Cortex-M 스택 프레임에 이미 저장된 레지스터. 자세한 내용은 5페이지의 그림 1 오른쪽에 있는 스택 프레임을 참조하십시오.
  • FPU가 사용되지 않은 경우(CONTROL 레지스터의 FPCA 비트에서 0으로 표시됨) R0-R3, R12, LR, PC 및 스페이서 레지스터만 저장해야 합니다. 자세한 내용은 5페이지의 그림 1 왼쪽에 있는 스택 프레임을 참조하십시오.

그림1

 

사용 중인 스택 프레임 유형은 CONTROL 특수 레지스터의 FPCA 비트에 표시된 대로 FPCCR의 설정과 FPU가 현재 컨텍스트에서 이미 사용되었는지 여부에 따라 하드웨어에 의해 자동으로 결정됩니다. FPCA가 설정되고 자동 상태 저장 기능이 활성화된 경우 부동 소수점 저장소가 있는 예외 스택 프레임이 사용됩니다. 인터럽트 처리가 완료된 후 나중에 현재 컨텍스트에서 FPU의 레지스터 값이 필요할 수 있기 때문입니다.

부동 소수점 레지스터를 쌓으면 다음과 같은 영향이 있습니다.

• 스택 프레임 크기 증가

• 잠재적으로 인터럽트 처리에서 인터럽트 대기 시간을 증가시킵니다.

• 임베디드 운영 체제(OS)에서 컨텍스트 전환 시간을 늘립니다.

두 가지 가능한 스택 프레임 형식이 있기 때문에 스택에 인수가 전달된 C 함수는 스택에서 인수를 추출할 때 EXC_RETURN 값을 고려해야 합니다.

OS가 없는 애플리케이션의 인터럽트 처리를 위해 자동 하드웨어 상태 보존으로 충분하고 사용하기 쉽습니다. 일반 C 함수로 인터럽트 핸들러를 작성할 수 있으며 자동 스태킹 메커니즘은 필요한 부동 소수점 레지스터 스태킹 및 잠금 해제를 처리합니다.

임베디드 OS 개발자의 경우 상황은 더 복잡합니다. 멀티태스킹 시스템이 여러 작업에서 FPU를 사용하도록 허용하려면 FPU에 포함된 추가 레지스터, S0-S31 및 FPSCR의 컨텍스트 저장을 처리하도록 OS 또는 실시간 운영 체제(RTOS)를 업데이트해야 합니다.

컨텍스트 전환 중에 OS는 다음을 수행해야 합니다 :

  1. EXC_RETURN의 비트[4]를 사용하여 애플리케이션 작업이 FPU를 사용했는지 확인합니다.
  2. 필요한 경우 부동 소수점 컨텍스트를 저장합니다.
  3. 필요한 경우 다음 작업을 위해 부동 소수점 컨텍스트를 복원합니다.
  4. EXC_RETURN 코드 값이 스택 프레임 유형과 일치하는 예외 반환을 사용하여 다음 작업으로 전환합니다.

자동 스태킹 메커니즘은 S0-S15 레지스터와 FPSCR만 처리합니다. OS는 S16에서 S31 레지스터의 저장 및 복원을 수동으로 처리해야 합니다.

Lazy stacking feature

Cortex-M4F는 lazy stacking이라는 추가기능을 가지고 있습니다. 이 기능은 다음과 같이 필요하지 않은 경우 부동 소수점 레지스터의 스택을 건너뛰어 인터럽트 대기 시간 증가를 방지합니다.

  • 인터럽트 처리기가 FPU를 사용하지 않는 경우 또는
  • 중단된 프로그램이 FPU를 사용하지 않는 경우

인터럽트 핸들러가 FPU를 사용해야 하고 인터럽트된 컨텍스트도 이전에 FPU에서 사용한 경우 부동 소수점 레지스터의 스택은 인터럽트 핸들러가 FPU를 처음 사용하는 프로그램의 지점에서 발생합니다.

lazy stacking 기능은 프로그래밍이 가능하며 기본적으로 켜져 있습니다. lazy stacking 제어는 FPCCR에서 처리합니다. OS 개발자는 컨텍스트 전환 코드를 개발할 때 lazy stacking의 영향을 고려해야 합니다.

lazy stacking을 활성화하려면 always save enable를 나타내는 ASPEN이라는 FPCCR의 비트[31]과 lazy save enable를 나타내는 LSPEN이라는 비트[30]이 둘 다 1로 설정되어야 합니다. 이것이 기본값입니다. LSPEN을 0으로 설정하여 lazy stacking을 비활성화할 수 있습니다.

애플리케이션이 이전에 CONTROL 레지스터의 비트[2]로 표시된 FPU를 사용한 경우 FPCA는 자동으로 1로 설정됩니다. 인터럽트가 발생하고 lazy stacking 기능이 켜져 있으면 프로세서는 S0-S15 레지스터 및 FPSCR용 프레임을 위해 스택에 추가 공간을 예약합니다. 그러나 이러한 레지스터의 실제 stacking은 일어나지 않으며 이를 나타내기 위해 FPCCR, LSPACT(Lazy State Preservation Active)의 비트[0]이 1로 설정됩니다. 예외 항목에서 생성된 EXC_RETURN 값의 비트[4]는 0으로 설정되어 실제 레지스터 내용은 없지만 예외 스택 프레임에 부동 소수점 레지스터에 대한 스택 공간이 있음을 나타냅니다.

  • 인터럽트 핸들러가 FPU를 사용하지 않으면 LSPACT는 인터럽트가 끝날 때까지 HIGH로 유지됩니다. 인터럽트에서 복귀할 때 프로세서 하드웨어는 EXC_RETURN의 비트[4]가 0이고 LSPACT가 1임을 감지하여 스택 프레임에 부동 소수점 레지스터를 위한 공간이 포함되어 있지만 스택에 푸시되지 않았음을 나타냅니다. 부동 소수점 레지스터는 무시됩니다.
  • 인터럽트 처리기가 어느 단계에서 FPU를 사용하는 경우 첫 번째 부동 소수점 명령이 발생할 때 프로세서가 정지되고 부동 소수점 레지스터, 즉 S0-S15 레지스터와 FPSCR이 스택으로 푸시되고 LSPACT가 지워집니다. 그런 다음 프로그램 실행이 계속됩니다. 인터럽트 처리기의 끝에서 프로세서 하드웨어는 EXC_RETURN[4]가 0이고 LSPACT가 0임을 감지하여 스택 프레임에 푸시된 부동 소수점 레지스터가 포함되어 있음을 나타내며 그에 따라 스택을 해제합니다.

lazy stacking이 비활성화된 경우 프로세서는 항상 부동 소수점 레지스터를 예외 항목에서 스택으로 푸시하고 인터럽트 반환에서 스택을 해제합니다. 이렇게 하면 인터럽트 대기 시간이 늘어나게 됩니다.

애플리케이션에 따라 표 2에 표시된 다음 설정을 사용할 수 있습니다.

Example lazy stacking scenarios

다음 다이어그램은 lazy stacking이 활성화된 Cortex-M4F 예외 항목 및 예외 반환에 대한 몇 가지 시나리오를 보여줍니다.

그림 2는 리셋 이후 중단된 메인 프로그램에서 부동 소수점 연산이 없는 경우와 ISR에서 부동 소수점 연산이 없는 경우를 보여줍니다.

중단된 메인 프로그램에 이전 부동 소수점 연산이 없으면 FPCA는 LOW 상태를 유지합니다. 이 상황에서 예외 스택 프레임은 FPU가 없는 Cortex-M3 프로세서 또는 Cortex-M4 프로세서와 동일합니다. EXC_RETURN[4]는 스택 프레임에 부동 소수점 내용이 없음을 나타내기 위해 그림 2에서 1입니다.

그림 3에서 리셋 이후 중단된 메인 프로그램에 부동 소수점 연산이 있었고 ISR에는 부동 소수점 연산이 없습니다.

이 경우 부동 소수점 레지스터를 위한 공간이 스택 프레임에 예약됩니다. lazy stacking이 기본적으로 활성화되어 있기 때문에 이러한 레지스터는 스택으로 푸시되지 않습니다.

그림 4는 중단된 메인 프로그램의 부동 소수점 연산과 ISR의 부동 소수점 연산을 보여줍니다.

ISR 실행 중에 부동소수점 연산을 수행하면 부동소수점 레지스터는 FPCAR로 표시되는 Lazy stacking을 사용하여 예약된 공간에 저장됩니다. 이를 위해 프로세서는 레이지 스태킹이 발생할 수 있도록 지연되고 레이지 스태킹이 완료된 후 부동 소수점 연산을 계속 실행합니다(그림 4 참조).

Note : 예약된 공간에는 레지스터 S16 ~ S31이 포함되지 않습니다. 이러한 레지스터는 하드웨어에 의해 저장되지 않습니다. AAPCS 준수 C 컴파일러는 서브루틴 호출에서 이를 보존해야 합니다.

12페이지의 그림 5는 인터럽트된 기본 프로그램과 더 높은 우선 순위의 인터럽트 처리기에서 부동 소수점 연산을 사용하는 중첩된 인터럽트를 보여줍니다.

우선 순위가 낮은 첫 번째 인터럽트 핸들러에 부동 소수점 연산이 없으면 우선 순위가 높은 인터럽트에 들어갈 때 부동 소수점 레지스터에 대한 스택 공간을 예약할 필요가 없습니다. 결과적으로 FPCAR는 여전히 첫 번째 예외 스택 프레임의 예약된 공간을 가리키고 있습니다(그림 5 참조).

그림 6은 인터럽트된 메인 프로그램의 부동 소수점 연산과 낮은 우선 순위 및 높은 우선 순위 인터럽트가 있는 중첩 인터럽트를 보여줍니다.

우선 순위가 낮거나 높은 인터럽트 핸들러와 인터럽트된 메인 프로그램이 모두 부동 소수점 명령을 사용하는 경우 두 인터럽트의 스택 프레임에는 부동 소수점 레지스터용으로 예약된 공간이 필요합니다(13페이지의 그림 6 참조).

FPCAR는 두 예외 모두 진입시 업데이트됩니다.