명령어 구조 (Instruction Structure)
| 개념 | 설명 |
| Major Opcode | 명령어의 주요 분류 코드 |
| Minor Opcode | 세부 동작 지정 코드 |
| Immediates | 명령어에 포함된 상수값 |
| Types | 명령어 형식 (R, I, S, B, U, J) |
하드웨어 구조 (Hardware Structures)
| 구조 | 설명 |
| Register File | 32개의 범용 레지스터 |
| CSRs | Control and Status Registers (제어/상태 레지스터) |
RISC-V 명령어 세트 배경 및 명명 규칙
| 개념 | 설명 | 예시 |
| ISA | 명령어의 구현-독립적 동작 명세 | RISC-V, x86, ARM |
| Microarchitecture | ISA의 특정 하드웨어 구현 | Intel Core, AMD Zen |
| Computer Architecture | ISA와 구현을 연구하는 학문 | - |
| ABI | 함수 호출 수준의 인터페이스 명세 | 레지스터 사용 규약 |
┌─────────────────────────────────────────────────────────┐
│ ISA (추상적 명세) │
│ ↓ │
│ Microarchitecture (구체적 구현) │
│ ↓ │
│ 실제 칩 (Silicon) │
└─────────────────────────────────────────────────────────┘
ISA vs. 마이크로아키텍처 vs. 컴퓨터 아키텍처 vs. ABI
- ISA (명령어 세트 아키텍처)
- 명령어 동작에 대한 구현 독립적인 명세.
- IS(명령어 세트, 명령어 목록)와 이를 조작하는 레지스터 및 데이터 타입을 정의
- 또한 메모리 접근 및 I/O와 같은 기본 기능도 정의
- RISC-V는 ISA다.
- 마이크로아키텍처 (약어: µarch 또는 uarch)
- ISA의 특정 구현으로, 실제 하드웨어 프로세서 설계
- 주어진 ISA는 여러 다른 마이크로아키텍처로 구현될 수 있다.
- 컴퓨터 아키텍처
- ISA와 그 마이크로아키텍처 구현을 연구하는 학문 분야
- ABI (응용 프로그램 이진 인터페이스)
- ISA와 같은 명세이지만 함수 호출과 일반적인 저수준 소프트웨어 운영체제 기능의 더 높은 추상화 수준에 있다.
- 함수 호출이 어떤 레지스터를 사용하는지, 기본 어셈블리 데이터 타입의 크기가 얼마인지를 정의한다.
- 이 장에서 레지스터의 ABI 이름은 "소프트웨어 측" 이름으로, "ISA" 이름은 "하드웨어 측" 이름으로 참조된다.
- 다양한 RISC-V ABI에 대한 자세한 내용은 RISC-V ABI 명세 문서에 있다.
RISC vs. CISC
- RISC (축소 명령어 세트 컴퓨터)
- 하드웨어 구현을 크게 단순화하기 위해 적은 수의 빠르고 단순한 단일 기능 명령어를 갖는 것을 우선시하는 컴퓨터 설계
- 이는 보통 상대적으로 많은 수(16-32개)의 빠른 레지스터와 함께 사용된다.
- 주요 단점은 어셈블리 코드 크기가 크다는 것
- RISC-V는 변형에 따라 16개에서 32개의 레지스터를 가진 RISC 유형 ISA이다.
- CISC (복합 명령어 세트 컴퓨터)
- 오늘날 위에서 설명한 엄격한 RISC가 아닌 모든 것을 포괄하는 컴퓨터 설계
- CISC 명령어 세트는 보통 더 많은 명령어를 포함하며, 각 명령어는 보통 여러 개의 단순한 연산을 수행할 수 있다.
- 이는 어셈블리 코드 크기와 필요한 레지스터 수를 줄이지만 하드웨어 구현 복잡성을 크게 증가시킨다.
빅 엔디안 vs. 리틀 엔디안 인코딩
- 빅 엔디안 인코딩: 최상위 비트에서 최하위 비트 순으로 비트를 전달한다. 그 결과:
- 명령어 비트를 왼쪽에서 오른쪽으로 번호 매김
- 명령어 인코딩 필드를 왼쪽에서 오른쪽으로 읽음
- 메모리의 바이트가 가장 작은 주소에 최상위 바이트부터 저장됨
- 리틀 엔디안 인코딩:
- 최하위 비트에서 최상위 비트 순으로 비트를 전달한다.
- RISC-V는 리틀 엔디안이다. 그 결과:
- 명령어 비트를 오른쪽에서 왼쪽으로 번호 매김
- 명령어 인코딩 필드를 오른쪽에서 왼쪽으로 읽음
- 메모리의 바이트가 가장 작은 주소에 최하위 바이트부터 저장됨
RISC-V vs. 다른 RISC 유사 ISA
RISC-V는 처음부터 무료이고 오픈 소스이며 모든 유형의 장치에서 실행되도록 설계된 최초의 ISA이다.
| 과거의 실수 | 배운 교훈 | |||
| ARM-32 (1986) | MIPS-32 (1986) | x86-32 (1978) | RV32I (2011) | |
| 비용 | 정수 곱셈 필수 | 정수 곱셈과 나눗셈 필수 | 8비트 및 16비트 연산. 정수 곱셈과 나눗셈 필수 | 8비트 및 16비트 연산 없음. 정수 곱셈과 나눗셈은 선택 사항 (RV32M) |
| 단순성 | 제로 레지스터 없음. 조건부 명령어 실행. 복잡한 데이터 주소 모드. 스택 명령어(push/pop). 산술/논리 명령어에 시프트 옵션 | 제로 확장 및 부호 확장 즉시값. 일부 산술 명령어가 오버플로우 트랩 유발 가능. 다중 로드. 계산된 즉시값. PC가 범용 레지스터 | 제로 레지스터 없음. 복잡한 프로시저 호출/반환 명령어(enter/leave). 스택 명령어(push/pop). 복잡한 데이터 주소 모드. 루프 명령어 | x0 레지스터가 0 전용. 부호 확장 즉시값만 사용. 단일 데이터 주소 모드. 조건부 실행 없음. 복잡한 호출/반환 또는 스택 명령어 없음. 산술 오버플로우 트랩 없음. 별도의 시프트 명령어 |
| 성능 | 분기에 조건 코드 사용. 소스 및 목적지 레지스터가 명령어 형식마다 다름 | 분기에 조건 코드 사용. 소스 및 목적지 레지스터가 명령어 형식마다 다름. 명령어당 최대 2개 레지스터 | 분기에 조건 코드 사용. 명령어당 최대 2개 레지스터 | 비교 및 분기 명령어 (조건 코드 없음). 명령어당 3개 레지스터. 다중 로드 없음. 소스 및 목적지 레지스터가 명령어 형식에 고정. 즉시값 고정. PC는 범용 레지스터 아님 |
| 구현으로부터 아키텍처 분리 | PC를 범용 레지스터로 사용하여 파이프라인 길이 노출 | 지연 분기. 지연 로드. 곱셈과 나눗셈 전용 HI 및 LO 레지스터 | 레지스터가 범용이 아님 (AX, CX, DX, DI, SI가 고유 용도 가짐) | 지연 분기 없음. 지연 로드 없음. 범용 레지스터 |
| 확장 여유 | 가용 opcode 공간 제한적 | 가용 opcode 공간 제한적 | 충분한 opcode 공간 | |
| 프로그램 크기 | 32비트 명령어만 (별도 ISA로 Thumb-2 추가) | 32비트 명령어만 (별도 ISA로 microMIPS 추가) | 바이트 가변 명령어, 그러나 선택지 부적절 | 32비트 명령어 + 16비트 RV32C 확장 |
| 프로그래밍/컴파일/링킹 용이성 | 레지스터 15개만. 메모리 데이터 정렬 필요. 불규칙한 데이터 주소 모드. 일관성 없는 성능 카운터 | 메모리 데이터 정렬 필요. 일관성 없는 성능 카운터 | 레지스터 8개만. PC 상대 데이터 주소 지정 없음. 일관성 없는 성능 카운터 | 레지스터 31개. 데이터 비정렬 가능. PC 상대 데이터 주소 지정. 대칭적 데이터 주소 모드. 성능 카운터가 아키텍처에 정의됨 |
RISC-V 명명 규칙
RISC-V ISA의 세부 사항을 공부하기 전에, 명명 규칙을 명확히 해야 한다. RISC-V의 근본적인 특성 중 하나는 모듈성으로, 최소한의 "코어" 세트 위에 "확장" 명령어 세트로 구조화되는 특성이다. 명명 규칙은 이 구조를 직접 반영한다. 주어진 "변형"은 비특권 명세 문서 27장에 설명되어 있으며 아래와 같이 요약된다.
- RV32I - RISC-V 32비트 정수 (기본) ISA. 최소한이지만 완전한 명령어 세트를 포함
- RV32E - RISC-V 32비트 정수 (축소) ISA. RV32I와 동일한 명령어를 가지지만 16개의 레지스터만 접근 가능. 비특권 명세 문서 4장 참조.
- RV64I - RISC-V 64비트 정수 (기본) ISA. RV32I와 거의 동일한 32비트 폭 명령어를 공유하지만 64비트 연산을 지원하기 위한 약간의 차이가 있다.
- RV128I - RISC-V 128비트 정수 (기본) ISA. RV64I와 거의 동일한 32비트 폭 명령어를 공유하지만 128비트 연산을 지원하기 위한 약간의 차이가 있다.
"RV" 바로 뒤의 숫자(비특권 명세 문서에서 XLEN이라 불림)는 명령어의 폭이 아니라 레지스터의 폭을 나타낸다.
"기본" 명명법 뒤에 확장 목록이 정규 순서로 제공된다. 예를 들어, M, A, C 확장이 있는 RV32I 변형은 RV32IMAC라고 불린다. 또 다른 자주 등장하는 예는 RV64G로, RV64IMAFDZicsr_Zifencei의 약칭이며 표준 범용 RISC-V 변형으로 간주된다. 정규 순서와 표준, 예외 사항, 특수 확장에 대한 더 많은 정보는 비특권 명세 문서 27장에 나와 있다.
RV32I 기본 ISA에 포함된 기본 명령어 세트
RISC-V ISA의 "기본 버전"은 소위 RV32I로, RISC-V 32비트 기본 "정수" ISA로 확장된다. 이것은 최소한의 하드웨어에서 정수 연산을 위한 최소한이지만 완전한 명령어 세트를 포함한다. 비특권 명세 문서 2장에 자세히 설명되어 있다. 이 섹션에서 요약하는 것은 ISA이며, 어셈블리 코드와 레지스터 명명 규칙은 어셈블리 프로그래머 매뉴얼에서 찾을 수 있다. 또한 각 명령어는 이 장의 뒷부분에서 심층적으로 다룰 것이다.
RV32I 구성 요소
- 1개의 32비트 폭 프로그램 카운터 레지스터
- 32개의 32비트 폭 레지스터 (x0부터 x31까지)
- 40개의 고유한 32비트 폭 비특권 명령어 (6가지 형식: R, I, S, B, U, J)이며 일부 반복되는 필드가 있음:
- 명령어의 처음 7비트에 있는 주요 opcode로 명령어를 식별
- 소스 레지스터 (rs1은 항상 비트 15
19, rs2는 비트 2024)와 목적지 레지스터 (rd는 비트 7~11) 필드 - 기능 필드 또는 부차 opcode로, 비트 폭에 따라 funct7 또는 funct3라고 명명됨. Funct7은 R 타입 명령어의 마지막 7비트를 차지하고, funct3는 항상 비트 12~14를 차지
- 즉시값 필드는 항상 명령어의 끝(왼쪽)쪽에 위치하며 명령어 타입에 따라 다르게 인코딩됨
- 24개의 추가 고유 32비트 폭 특권 명령어 (2가지 형식: R과 I).
- 간단히 말해, 명령어가 수행할 수 있는 모든 연산 중 일부만 모든 사용자가 실행할 수 있고, 가장 민감한 연산들(잘못 사용하면 기계 작동을 손상시킬 수 있는 것들)은 운영체제와 같은 "특권" 사용자만 실행할 수 있다.
모든 명령어 타입의 일반 구조 개요

각 형식 내 명령어에 대한 간략한 개요는 다음과 같다.
| 형식 | 설명 |
| R "레지스터" 타입 | ADD, SUB, 부울 연산, 시프트와 같은 산술 레지스터-레지스터 연산에 사용 |
| I "즉시값" 타입 | 즉시값을 사용하는 산술, 논리, 시프트 연산, 점프 앤 링크 레지스터, 환경 호출, LOAD 명령어에 사용 |
| S "저장" 타입 | STORE 명령어에 사용 |
| B "분기" 타입 | BRANCH 명령어에 사용 |
| U "상위 즉시값" 타입 | 상위 즉시값을 사용하는 명령어(LUI와 AUIPC)에 사용 |
| J "점프" 타입 | JAL(점프 앤 링크) 명령어에 사용 |
RV32I와 RV64I의 차이점
RISC-V ISA의 RV64I 변형은 RV32I의 거의 동일한 32비트 폭 명령어를 공유하지만, 64비트 폭 레지스터 파일에서 작동하므로 고유한 사용 사례를 위한 전용 명령어가 있다. RV32I와 RV64I 간의 완전한 차이점은 비특권 명세 문서 5장에 포함되어 있다.
RV64I에서는 64비트 연산을 지원하기 위해 RV32I에 12개의 새로운 명령어가 추가된다.
- "Load Doubleword" (LD) 와 "Store Doubleword" (SD) 명령어: 64비트 폭 더블워드를 로드하고 저장할 수 있다. "Load Word Unsigned" (LWU) 는 RV64I에서 메모리의 32비트 값을 제로 확장한다.
- 일부 명령어는 32비트 값에서만 작동하고 32비트 결과를 64비트로 부호 확장한다. 이들은 RV32I 대응 명령어와 동일한 이름을 가지지만(RV32I 대응 명령어는 이제 64비트 값으로 작동하고 64비트 결과를 생성), W 접미사가 붙으며, 이는 "word"를 의미한다. 아래 표에 설명되어 있다.
| 명령어 | 설명 |
| ADDW | Add Word (워드 덧셈) |
| ADDIW | Add Immediate to Word (워드에 즉시값 덧셈) |
| SUBW | Subtract Word (워드 뺄셈) |
| SLLW | Shift Left Logical Word (워드 논리 좌측 시프트) |
| SLLIW | Shift Left Logical Immediate Word (워드 즉시값 논리 좌측 시프트) |
| SRLW | Shift Right Logical Word (워드 논리 우측 시프트) |
| SRLIW | Shift Right Logical Immediate Word (워드 즉시값 논리 우측 시프트) |
| SRAW | Shift Right Arithmetic Word (워드 산술 우측 시프트) |
| SRAIW | Shift Right Arithmetic Immediate Word (워드 즉시값 산술 우측 시프트) |
위의 명령어들은 RV32I 변형과 다음과 같이 구별된다.
- 주요 opcode만 변경하여 구별: ADDIW, ADDW, SUBW, SLLIW, SRLIW, SRAIW, SLLW, SRLW, SRAW
- 부차 opcode만 변경하여 구별 (이 경우 funct3): LD, SD, LWU
Quadrants, Major Opcode, Minor Opcode
실제 명령어 타입과 개별 명령어 인코딩을 심층적으로 다루기 전에, 주요 opcode를 알아보자.
- 인코딩 "쿼드런트" 개념
- 쿼드런트는 인코딩 공간의 (보통 주요한) 부분
- 예를 들어, 32비트 인코딩 공간이 주어졌을 때, 처음 2비트는 2^32개의 가능한 명령어를 4개(2^2)의 30비트 폭 쿼드런트로 나누며, 각각 2^30개의 명령어를 포함한다.
- 같은 방식으로, 동일한 32비트 인코딩 공간의 처음 7비트가 쿼드런트를 인덱싱하는 데 사용되면, 128개(2^7)의 25비트 폭 쿼드런트로 나눈다.
- 공식 문서에서 명령어의 특정 필드를 참조하는 방법
- Python을 아는 사람들은 결과가 익숙할 것이다.
- inst[1:0]은 명령어의 처음 두 개(가장 오른쪽) 비트를 참조하고, inst[4]는 다섯 번째 비트를, inst[31:27]은 가장 왼쪽 5비트를 참조한다.
- 차이점은 양 끝이 항상 포함된다는 것이다.
위의 예시 숫자들은 무작위가 아니며, RISC-V 인코딩 공간의 실제 특성을 반영한다. 실제로 모든 RISC-V 명령어의 처음 비트들은 인코딩을 더 잘 조직하고 구현을 단순화하기 위해 명령어 길이에 대한 정보를 포함한다. 이는 주소 공간을 쿼드런트로 나눔으로써 수행된다.
디코더는 다른 명령어 필드를 읽기 전에 비트를 오른쪽에서 왼쪽으로 순서대로 읽어 명령어가 얼마나 넓은지 "읽는다". 재미있는 사실로, 이 특성이 Olof Kindgren의 비트 직렬 RISC-V CPU와 같은 특이한 구현을 더 쉽게 만드는 것이다.
Opcode 인코딩
RV32I/RV64I 명령어와 처음 4개의 쿼드런트(처음 두 개의 가장 오른쪽 비트로 인덱싱되는 4개의 쿼드런트)를 고려할 때, 문서에서는 해당 쿼드런트 중 하나만 32비트(또는 그 이상) 명령어에 사용되며, 그것은 인덱스 11의 쿼드런트라고 설명한다. 다른 세 개의 쿼드런트(00, 01, 10)는 16비트 압축 명령어에 사용된다.
다양한 명령어 길이 크기의 인코딩 목록

| 인코딩 패턴 | 명령어 길이 |
| xxxxxxxxxxxxxxaa | 16비트 (aa ≠ 11) |
| xxxxxxxxxxxxxxxxx | xxxxxxxxxxxbbb11 | 32비트 (bbb ≠ 111) |
| ···xxxx | xxxxxxxxxxxxxxxxx | xxxxxxxxxx011111 | 48비트 |
| ···xxxx | xxxxxxxxxxxxxxxxx | xxxxxxxxx0111111 | 64비트 |
| ···xxxx | xxxxxxxxxxxxxxxxx | xnnnxxxxx1111111 | (80+16*nnn)비트, nnn≠111 |
| ···xxxx | xxxxxxxxxxxxxxxxx | x111xxxxx1111111 | 192비트 이상용 예약 |
RISC-V ISA는 처음 몇 비트에서 명령어 길이를 인식하는 방법을 정의한다.
위 체계에서 관심을 가질 것은 처음 두 줄뿐이다
- 첫 번째는 00, 01, 또는 10으로 시작하는 모든 명령어가 16비트 폭이라고 주장하고,
- 모든 32비트 폭 명령어는 11로 시작하며
- 다음 세 비트가 111과 다르다.
이것은 우리의 목적상 각 opcode의 처음 두 비트에 대한 인코딩 공간을 완전히 다룬다. 주요 opcode의 나머지 부분(비트 위치 2부터 5비트 길이)은 부차 opcode와 함께 정확한 명령어를 정의한다.
RISC-V 기본 명령어 세트의 주요 Opcode 맵

오른쪽에서 읽을 때 세 번째부터 일곱 번째까지의 각 명령어의 5비트는 주요 opcode를 구성하며 명령어의 의미적 영역을 대략적으로 식별한다.
명령어 구조 예시
각 명령어 구조의 체계(아래 예시)는 이러한 것들을 이름으로 참조한다. (오른쪽 하단 참조)

위에서 하나의 주요 opcode인 OP-IMM이 표시된 최소 5개의 다른 명령어를 포함하는 것을 볼 수 있다. 이들은 funct3 부차 opcode에 의해서만 구별되며, 정확한 매핑은 비특권 명세 문서 19장에서 볼 수 있다.
레지스터
이전에 언급했듯이, RISC-V는 32개의 "정수" 레지스터를 정의하며, CSR이나 부동 소수점 확장에서 정의된 것과 같은 별도의 레지스터 파일과 구분하기 위해 이렇게 부른다.
하드웨어 측면에서 참조할 때, 이들은 x0-x31로 명명되며, x0은 0으로 하드와이어되어 있고, x1-x31은 범용 레지스터로서 정확한 용도는 더 높은 추상화 수준의 명세(ABI)에서 정의된다. 이러한 레지스터의 폭은 명세 문서에서 종종 XLEN으로 약칭되며, RV32의 경우 32비트이고 RV64를 사용할 때는 64비트이다(그 이상도 마찬가지).
따라서 RV32와 RV64 명령어는 5비트 폭 인코딩으로 정수 레지스터를 참조하며, 주어진 명령어는 최대 세 개의 레지스터(두 개의 소스 레지스터 rs1과 rs2, 그리고 하나의 목적지 레지스터 rd)를 참조한다.
아래는 wikichip에서 가져온 정수 레지스터의 완전한 주석이 달린 표이다.
RISC-V ISA에서 정의된 레지스터 목록
| 5비트 인코딩 (rx) | 3비트 압축 인코딩 (rx') | 레지스터 | ABI 이름 | 설명 | 저장 주체 |
| 0 | - | x0 | zero | 하드와이어된 제로 | - |
| 1 | - | x1 | ra | 반환 주소 | Caller |
| 2 | - | x2 | sp | 스택 포인터 | Callee |
| 3 | - | x3 | gp | 전역 포인터 | - |
| 4 | - | x4 | tp | 스레드 포인터 | - |
| 5 | - | x5 | t0 | 임시 레지스터 0 | Caller |
| 6 | - | x6 | t1 | 임시 레지스터 1 | Caller |
| 7 | - | x7 | t2 | 임시 레지스터 2 | Caller |
| 8 | 0 | x8 | s0 / fp | 저장 레지스터 0 / 프레임 포인터 | Callee |
| 9 | 1 | x9 | s1 | 저장 레지스터 1 | Callee |
| 10 | 2 | x10 | a0 | 함수 인자 0 / 반환 값 0 | Caller |
| 11 | 3 | x11 | a1 | 함수 인자 1 / 반환 값 1 | Caller |
| 12 | 4 | x12 | a2 | 함수 인자 2 | Caller |
| 13 | 5 | x13 | a3 | 함수 인자 3 | Caller |
| 14 | 6 | x14 | a4 | 함수 인자 4 | Caller |
| 15 | 7 | x15 | a5 | 함수 인자 5 | Caller |
| 16 | - | x16 | a6 | 함수 인자 6 | Caller |
| 17 | - | x17 | a7 | 함수 인자 7 | Caller |
| 18 | - | x18 | s2 | 저장 레지스터 2 | Callee |
| 19 | - | x19 | s3 | 저장 레지스터 3 | Callee |
| 20 | - | x20 | s4 | 저장 레지스터 4 | Callee |
| 21 | - | x21 | s5 | 저장 레지스터 5 | Callee |
| 22 | - | x22 | s6 | 저장 레지스터 6 | Callee |
| 23 | - | x23 | s7 | 저장 레지스터 7 | Callee |
| 24 | - | x24 | s8 | 저장 레지스터 8 | Callee |
| 25 | - | x25 | s9 | 저장 레지스터 9 | Callee |
| 26 | - | x26 | s10 | 저장 레지스터 10 | Callee |
| 27 | - | x27 | s11 | 저장 레지스터 11 | Callee |
| 28 | - | x28 | t3 | 임시 레지스터 3 | Caller |
| 29 | - | x29 | t4 | 임시 레지스터 4 | Caller |
| 30 | - | x30 | t5 | 임시 레지스터 5 | Caller |
| 31 | - | x31 | t6 | 임시 레지스터 6 | Caller |
마지막 세 열은 ABI의 소프트웨어 측면 기능을 설명하고, 두 번째 열은 압축 인덱싱이 어떻게 작동하는지 보여준다(이 장 뒷부분에서 다룰 C 확장과 부동 소수점 확장 및 해당 확장이 정의하는 추가 레지스터와 함께).
마지막으로, 처음 16개의 레지스터만 사용하는 자원 제약 구현을 위해 RV32I의 변형이 정의되었다는 점을 반드시 알아야 한다. 이것은 RV32E라고 불리며 비특권 명세 문서 3장에서 자세히 다룬다.
Immediates and Addresses
Opcode(주요, 부차, 단일 비트 플래그)와 레지스터 외에도, 주어진 명령어 인코딩에는 즉시값이 포함될 수 있다.
즉시값은 메모리나 레지스터가 아닌 명령어에 직접 인코딩된 데이터 조각이다. 이 데이터는 예를 들어 산술 연산에 사용되는 상수나 메모리 주소/오프셋을 나타낼 수 있다.
인코딩 관점에서 명령어의 레지스터 필드조차도 기술적으로는 레지스터 파일 주소를 포함하는 즉시값이다. 이 장에서 "주소"를 참조할 때, 우리는 일반적으로 레지스터 파일, PC, 또는 다음 섹션에서 다룰 별도의 CSR 주소 공간이 아닌 실제 메모리 주소 공간을 지칭할 것이다.
즉시값의 다른 처리 방식이 명령어 타입을 정의하는 정확한 특성이지만, 모든 즉시값은 하드웨어 즉시값 디코더의 구현을 단순화하기 위해 유사한 위치에 인코딩되는 경향이 있다. 모든 즉시값은 32비트 폭 값으로 디코딩되지만, 인코딩은 명령어에 따라 다르며 비특권 명세 문서 2.3장에서 가져온 아래 이미지에 표시되어 있다.
RISC-V 즉시값 디코딩 요약

| 비트 위치 | 31-12 | 11-5 | 4-1 | 0 | 타입 |
| I-immediate | inst[31] 부호 확장 | inst[30:25] | inst[24:21] | inst[20] | I-즉시값 |
| S-immediate | inst[31] 부호 확장 | inst[30:25] | inst[11:8] | inst[7] | S-즉시값 |
| B-immediate | inst[31] 부호 확장 | inst[7] | inst[30:25] | inst[11:8] | 0 |
| U-immediate | inst[31] | inst[30:20] | inst[19:12] | 0 | U-즉시값 |
| J-immediate | inst[31] 부호 확장 | inst[19:12] | inst[20] | inst[30:25] | inst[24:21] |
다음은 각 명령어 타입의 즉시값이 무엇에 사용되는지에 대한 간략한 개요이다.
I 즉시값 (12비트)
- 산술, 논리, 또는 시프트 연산의 두 번째 피연산자로 사용됨 (시프트 연산의 경우 다르게 인코딩되며, 이는 나중에 다룰 예정)
- PC라고도 불리는 프로그램 카운터 레지스터(JALR 명령어) 또는 메모리 주소(LOAD 명령어)를 계산하기 위해 레지스터 내용에 대한 오프셋으로 사용됨
- 환경 호출에서는 사용되지 않음. 단, CALL과 BREAK 명령어를 구분하는 플래그로 사용되는 첫 번째 비트는 예외
S 즉시값 (12비트)
- STORE 메모리 주소를 계산하기 위해 레지스터 내용에 대한 오프셋으로 사용됨
B (12비트) 및 J 즉시값 (20비트)
- 분기 연산을 위한 PC 오프셋으로 사용됨. 이러한 이유로, PC 점프 값은 항상 최소 16비트(2바이트)의 배수이므로 첫 번째 비트가 0으로 강제됨
U 즉시값 (20비트)
- 큰 PC 오프셋이나 레지스터 값으로 사용될 큰("상위") 숫자를 생성하기 위해 12자리 시프트되는 유일한 즉시값
명세에 따르면, RISC-V는 위치 독립적 코드를 지원하며, 이는 모든 조건부 및 무조건부 점프가 항상 PC에 상대적인 오프셋으로 설명됨을 의미한다.
- 조건부 분기(B 타입 명령어)의 오프셋은 13비트 폭(명령어에 인코딩된 12비트가 1비트 왼쪽으로 시프트됨)이며, 더 큰 조건부 분기는 불가능하다.
- RV32와 RV64 모두에서 LOAD, STORE, I 타입 점프의 오프셋은 12비트 즉시값을 20비트 길이의 U 또는 J 즉시값과 짝지어 32비트 주소 공간을 커버할 수 있다.
CSR (제어 및 상태 레지스터)
제어 및 상태 레지스터(줄여서 CSR)는 별도의 레지스터 뱅크로, 일반적으로 64비트 폭이며 별도의 12비트 주소 공간을 가져 그 수가 4096개로 제한된다. 이들은 보통 타이머, 카운터, 플래그, 제조업체 정보 및 기타 데이터와 같은 다양한 CPU 정보를 포함한다.
CSR을 32비트 청크 단위로 읽기, 쓰기, 기타 유형의 연산을 수행하기 위해 6개의 I-타입 CSR 명령어가 정의되어 있지만, 기본 비특권 ISA에서는 일부 CSR 카운터를 읽는 것만 허용된다.
해당 Zicsr 확장의 나머지 기능은 특권 수준을 다룰 때 더 잘 설명될 것이며, CSR 명령어의 세부 사항은 비특권 명세 문서 2.8장에서 다룬다.
References
Books
- The RISC-V Reader: An Open Architecture Atlas (Patterson & Waterman, 2017)
Links
'Architecture > RISC-V' 카테고리의 다른 글
| RISC-V #1 Overview (0) | 2025.12.22 |
|---|