본문 바로가기

RISC-V/레지스터

[RISC-V] 레지스터: 범용 레지스터

RISC-V 아키텍처에서 레지스터를 배우려면 어떤 내용을 알아야 할까요? RISC-V 아키텍처에서는 다음과 같은 레지스터를 제공합니다.

  • 범용 레지스터
  • CSRs(Control and Status) 레지스터

범용 레지스터

먼저 범용 레지스터에 대해 알아 봅시다. 범용 레지스터는 어셈블리 명령어의 입력과 출력을 저장하는 용도로 사용됩니다. 개념 상 C 언어의 변수와 비슷한 개념입니다. 어셈블리 명령어를 분석하실 때 반드시 레지스터를 알아야 합니다.

RISC-V 아키텍처에서 정의된 범용 레지스터의 목록은 다음과 같습니다. 

 

Armv8 아키텍처와 비슷하게 레지스터의 갯수는 X0에서 X31까지 있습니다. 레지스터의 갯수가 많은 편입니다. 대부분 어셈블리 명령어의 인풋과 출력 결과를 저장하기 위해 사용되는데, 함수가 호출될 때 특별히 사용되는 레지스터가 있습니다. 예를 들면:

  • X1(ra): 링크 레지스터, jal 명령어를 실행하면 돌아올 주소를 Hart(RISC-V의 CPU core)가 업데이트
  • X2(sp): 스택 포인터, 프로세스가 가장 마지막에 실행된 스택 주소를 가리킴
  • X10~X17(a0~a7): 함수에 전달되는 아규먼트


리눅스 커널이나 RTOS에서 컨텍스트 스위칭라는 용어를 아마 들으신 적이 있을 것입니다. 여기서 말하는 컨텍스트는 실행 흐름을 뜻하며, 컨텍스트 스위칭은 실행 흐름을 바꾼다라고 볼 수 있습니다. 구체적으로는 컨텍스는 범용 레지스터를 뜻하며, 컨텍스트 스위칭은 범용 레지스터를 바꾼다라고 볼 수 있습니다.

다음은 리눅스 커널에서 컨텍스트를 저장하는 자료구조입니다.  

https://elixir.bootlin.com/linux/v6.9/source/include/linux/sched.h#L748
struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK
	/*
	 * For reasons of header soup (see current_thread_info()), this
	 * must be the first element of task_struct.
	 */
	struct thread_info		thread_info;
#endif
	unsigned int			__state;
...
	/* CPU-specific state of this task: */
	struct thread_struct		thread;  //<<--

 

task_struct 구조체의 가장 마지막 필드는 thead입니다. 

https://elixir.bootlin.com/linux/v6.9/source/arch/riscv/include/asm/processor.h#L113
/* CPU-specific state of a task */
struct thread_struct {
	/* Callee-saved registers */
	unsigned long ra;
	unsigned long sp;	/* Kernel mode stack */
	unsigned long s[12];	/* s[0]: frame pointer */
	struct __riscv_d_ext_state fstate;
	unsigned long bad_cause;
	u32 riscv_v_flags;
	u32 vstate_ctrl;
	struct __riscv_v_ext_state vstate;
	unsigned long align_ctl;
	struct __riscv_v_ext_state kernel_vstate;
};


보시는 바와 같이 thread 필드에 레지스터를 나타내는 필드가 확인됩니다. 이처럼 범용 레지스터는 운영체제 커널이나 RTOS에서 컨텍스트로 표현됩니다.

 

< 관련 강의 >

 

'RISC-V > 레지스터' 카테고리의 다른 글

[RISC-V] CSR (Control and Status) 레지스터 소개  (0) 2024.08.03