사전 레지스터
개념

레지스터

gabury1고친 사람 github-actions[bot]

레지스터는 프로세서가 지금 계산하는 값을 손에 쥐고 있게 해 줍니다. 프로세서 안에 있는 아주 작은 저장 칸입니다. 메모리보다 훨씬 빠르지만 몇십 칸밖에 없습니다. 주변 장치를 조작하는 칸도 레지스터라고 부릅니다. 이 편은 프로세서 안의 칸을 중심으로 다룹니다.

쉽고 빠른 이해

레지스터는 프로세서가 계산하는 동안 값을 올려 두는 칸입니다. 두 수를 더하면 두 수와 그 합이 모두 이 칸에 잠깐 들어갑니다.

프로세서는 계산할 값을 대개 자기 안의 칸으로 먼저 가져옵니다. 메모리는 프로세서 바깥에 있어 오가는 데 시간이 듭니다. 그래서 지금 쓸 값만 칸에 올려 두고 계산합니다.

어떻게 도나:

  1. 메모리에서 계산할 값을 레지스터로 가져옵니다
  2. 레지스터끼리 더하거나 비교합니다
  3. 결과를 다시 메모리에 적거나 다음 계산에 씁니다

대가가 있습니다. 칸이 몇십 개뿐이라 함수를 부르거나 스레드를 바꿀 때마다 칸의 값을 어딘가에 옮겨 둬야 합니다. 일이 끝나면 그 값을 되돌립니다. 전원이 꺼지면 값도 사라집니다.

상세

프로세서는 프로그램의 명령어를 하나씩 실행하는 장치입니다. 흔히 CPU(Central Processing Unit, 중앙 처리 장치)라고 부릅니다. 레지스터는 그 CPU 안에 들어 있는 저장 칸입니다. 명령어가 계산에 쓸 값과 계산 결과를 여기에 둡니다.

요리사로 비유하면 냉장고가 메모리이고 도마가 레지스터입니다. 요리사는 재료를 냉장고에 넣어 둡니다. 썰 때는 지금 다룰 재료 몇 개만 도마 위에 꺼내 놓습니다. 도마는 좁지만 손이 바로 닿습니다.

메모리가 있는데 칸을 따로 두는 까닭

프로그램의 값은 대부분 메모리에 있습니다. 메모리는 CPU 바깥에 놓인 칩이라 값을 읽고 쓰려면 신호가 오가야 합니다. CPU 가 계산하는 속도에 비하면 이 왕복은 느립니다.

CPU 안에서 덧셈이나 비교를 실제로 해내는 회로를 연산 회로라고 합니다. CPU 는 이 회로 바로 옆에 칸 몇 개를 둡니다. 지금 계산하는 값만 그 칸에 가져와 다룹니다. 그래서 연산은 대개 레지스터에 든 값을 대상으로 합니다.

레지스터와 메모리 사이에는 CPU 캐시가 하나 더 있습니다. 자주 쓰는 메모리 값을 CPU 가까이 복사해 두는 작은 저장소입니다. 값을 두는 곳을 읽고 쓰는 시간이 짧은 순서로 늘어놓으면 레지스터가 맨 위에 옵니다.

저장소 속도 크기 전원이 꺼지면
레지스터 가장 빠릅니다 몇십 칸 사라집니다
CPU 캐시 빠릅니다 작습니다 사라집니다
메모리 중간입니다 큽니다 사라집니다
디스크 느립니다 아주 큽니다 남습니다

아래로 갈수록 느리지만 더 많이 담습니다. 메모리 계층은 이 층층의 구조를 가리키는 말입니다.

덧셈 한 번에서 레지스터가 하는 일

a = b + c 한 줄을 CPU 가 어떻게 처리하는지 따라가 봅니다. 아래는 특정 CPU 의 문법이 아니라 흐름만 적은 의사 코드입니다. b 에는 3, c 에는 4 가 들어 있다고 둡니다.

r1 ← 메모리[b]    // r1 = 3
r2 ← 메모리[c]    // r2 = 4
r1 ← r1 + r2      // r1 = 7
메모리[a] ← r1    // a = 7

r1·r2 가 레지스터입니다. 두 값을 메모리에서 칸으로 가져와 칸끼리 더했습니다. 결과는 마지막 줄에서 메모리로 돌려보냈습니다. 덧셈 자체는 메모리에 손대지 않고 칸 안에서 끝났습니다.

CPU 가 곧바로 실행하는 명령어는 0 과 1 의 비트로 적혀 있습니다. 이것이 기계어입니다. 기계어 명령어에는 할 일과 함께 계산할 값이 어디 있는지도 적힙니다.

메모리에 든 값은 주소로 가리킵니다. 주소를 적으려면 비트가 많이 듭니다. 레지스터는 몇십 개뿐이라 번호 몇 비트면 가리킬 수 있습니다. 그만큼 명령어가 짧아져 같은 프로그램이 메모리를 덜 차지합니다.

맡은 일로 나눈 종류

레지스터는 칸마다 맡은 일이 다릅니다. 어떤 칸은 아무 값이나 담습니다. 어떤 칸은 CPU 가 정한 한 가지 값만 담습니다.

어떤 칸이 몇 개 있고 이름이 무엇인지는 명령어 집합이 정합니다. 명령어 집합은 한 CPU 계열이 알아듣는 명령어와 레지스터를 모은 목록입니다. CPU 계열이 다르면 레지스터의 개수와 이름도 달라집니다.

종류 담는 것 없으면 곤란한 일
범용 레지스터 계산에 쓰는 아무 값 계산할 값을 둘 곳이 없습니다
프로그램 카운터 다음에 실행할 명령어의 주소 CPU 가 어디를 실행할지 모릅니다
스택 포인터 스택 꼭대기의 주소 함수 호출이 돌아갈 곳을 못 찾습니다
플래그 레지스터 직전 계산의 결과가 0 인지, 음수인지, 넘쳤는지 「같으면 건너뛰어라」 같은 분기를 못 합니다

표에서 볼 것은 뒤의 셋입니다. 이 셋은 계산 값이 아니라 프로그램이 지금 어디까지 왔는지를 담습니다. 범용 레지스터와 함께 이 칸들의 값을 모으면 실행 중인 프로그램의 순간 상태가 됩니다.

CPU 안에서 이 칸들과 메모리가 어떻게 이어지는지 그리면 이렇습니다.

flowchart TD
    subgraph CPU["CPU"]
        GR["범용 레지스터 · r1 r2 …"]
        ALU["연산 회로"]
        FL["플래그 레지스터"]
        PC["프로그램 카운터"]
        SP["스택 포인터"]
        GR <--> ALU
        ALU -->|"계산 결과의 성질"| FL
    end
    MEM["메모리 · 명령어와 데이터"]
    PC -->|"다음 명령어의 주소"| MEM
    SP -->|"스택 꼭대기의 주소"| MEM
    MEM <-->|"값을 가져오고 돌려보낸다"| GR

플래그는 연산 회로가 계산할 때마다 새로 적힙니다. 프로그램 카운터와 스택 포인터는 계산할 값을 담지 않습니다. 두 칸은 메모리 안의 한 위치를 가리키는 데 쓰입니다.

칸 하나의 폭

레지스터 한 칸에 들어가는 비트 수는 CPU 마다 정해져 있습니다. 흔히 말하는 「64비트 CPU」의 64 는 대개 범용 레지스터 한 칸의 폭입니다.

CPU 가 한 번에 다루는 값의 크기를 워드라고 합니다. 레지스터의 폭이 곧 워드 크기인 경우가 많습니다.

칸의 폭은 가리킬 수 있는 주소 범위도 정합니다. 프로그램 카운터와 스택 포인터처럼 주소를 담는 칸이 있기 때문입니다. 64비트 칸은 32비트 칸보다 훨씬 넓은 주소 범위를 가리킬 수 있습니다.

칸이 모자라서 생기는 약속

레지스터는 CPU 에 한 벌뿐입니다. 함수 A 가 r1 에 값을 넣어 둔 채 함수 B 를 부른다고 해 봅니다. B 도 같은 r1 을 씁니다. B 가 그 값을 덮어쓰면 A 가 돌아와서 엉뚱한 값을 읽습니다.

그래서 칸마다 누가 값을 지킬지 미리 정해 둡니다. 지킨다는 것은 칸을 쓰기 전에 원래 값을 스택에 옮겨 두는 일입니다. 돌아가기 전에는 그 값을 칸에 되돌려 놓습니다. 어떤 칸은 부르는 쪽이 지키고 어떤 칸은 불리는 쪽이 지킵니다.

인자와 반환값을 둘 칸도 미리 정합니다. 부르는 쪽은 정해진 칸에 인자를 넣습니다. 불린 함수는 정해진 칸에 반환값을 남깁니다.

호출 규약은 이런 약속을 모은 것입니다. 다른 사람이 만든 라이브러리를 부를 수 있는 것도 양쪽이 같은 호출 규약을 따르기 때문입니다.

운영체제가 실행할 스레드를 바꿀 때도 같은 문제가 생깁니다. 다음 스레드가 어느 칸을 덮어쓸지 모르니 지금 스레드의 레지스터 값을 전부 메모리에 옮겨 둡니다. 그다음 다음 스레드의 값을 칸에 채워 넣습니다. 이것이 문맥 교환입니다. 옮기는 값이 많을수록 교체 한 번이 무거워집니다.

같은 이름을 쓰는 다른 칸

타이머나 네트워크 카드 같은 주변 장치도 안에 칸을 둡니다. 이 칸이 장치 레지스터입니다. CPU 는 칸마다 정해진 주소에 값을 쓰거나 그 주소를 읽어 장치를 다룹니다.

타이머를 예로 듭니다. 타이머의 제어 레지스터에 켜라는 값을 쓰면 타이머가 돌기 시작합니다. 같은 타이머의 상태 레지스터를 읽으면 시간이 다 됐는지가 나옵니다.

메모리 맵 입출력은 장치 레지스터를 메모리 주소처럼 읽고 쓰게 하는 방식입니다. 임베디드 프로그램이 하드웨어를 다룰 때 주로 만나는 레지스터가 이쪽입니다.

가상 머신 설계에서도 이 이름을 빌려 씁니다. 계산 값을 번호 붙은 칸에 두는 가상 머신을 레지스터 방식이라고 부릅니다.

그 짝은 스택 방식입니다. 칸 대신 스택에 값을 쌓았다 꺼내며 계산합니다. JVM(Java Virtual Machine, 자바 가상 머신)이 스택 방식입니다.

관련 항목

레지스터를 품고 있는 장치

CPU · 프로세서 · 마이크로컨트롤러 · 연산 회로 · ALU · 플립플롭

맡은 일이 정해진 레지스터

프로그램 카운터 · 스택 포인터 · 플래그 레지스터 · 범용 레지스터 · 제어 레지스터 · 명령어 레지스터

속도와 크기로 레지스터와 층을 이루는 저장소

CPU 캐시 · 메모리 · 디스크 · 메모리 계층 · SSD

레지스터 사용법을 정하는 약속

명령어 집합 · 호출 규약 · ABI · 워드 · 기계어 · 어셈블리어

레지스터 값을 옮기고 되살리는 동작

문맥 교환 · 인터럽트 · 시스템 콜 · 스택 프레임 · 레지스터 할당

레지스터라는 이름을 빌려 쓰는 개념

장치 레지스터 · 메모리 맵 입출력 · 임베디드 · 가상 머신 · 스택 기반 가상 머신 · JVM

다른 이름: register · 프로세서 레지스터 · CPU 레지스터