CPU: 예외(Exception)
MIPS 아키텍처에서의 예외(Exception) 이해
MIPS 프로세서에서 예외(Exception)란, 프로그램의 정상적인 실행 흐름을 방해하고 특별한 처리를 요구하는 예상치 못한 이벤트를 의미합니다. 이는 프로세서의 내부적인 원인(예: 잘못된 명령어 실행) 또는 외부적인 원인(예: I/O 장치 요청)에 의해 발생할 수 있습니다. 예외는 시스템의 안정성과 신뢰성을 보장하기 위해 프로세서가 반드시 인식하고 적절히 처리해야 하는 중요한 메커니즘입니다.
1. 예외의 종류 및 분류
MIPS에서 다양한 이벤트를 예외 또는 인터럽트로 분류하는 방식을 명확히 보여줍니다.
이벤트 유형 | 발생 위치 | MIPS 용어 | 예시 |
---|---|---|---|
I/O 장치 요청 | 외부 (External) | 인터럽트 (Interrupt) | 키보드 입력, 마우스 클릭, 네트워크 패킷 수신, 디스크 읽기/쓰기 완료, 타이머 만료 등. 프로세서 외부 장치에서 발생하며 비동기적입니다. |
사용자 프로그램의 OS 요청 | 내부 (Internal) | 예외 (Exception) | syscall 명령어와 같이 사용자 프로그램이 운영체제 서비스(파일 입출력, 메모리 할당 등)를 명시적으로 요청할 때 발생합니다. |
산술 오버플로우 | 내부 (Internal) | 예외 (Exception) | add 명령어와 같이 부호 있는 정수 연산 결과가 레지스터의 표현 범위를 초과할 때 발생합니다. (예: 32비트 레지스터에 2^31-1을 초과하는 값 저장 시) |
정의되지 않은 명령어 사용 | 내부 (Internal) | 예외 (Exception) | 프로세서가 인식할 수 없는 비표준 명령어 코드를 실행하려고 할 때 발생합니다. |
하드웨어 오작동 | 내부/외부 (Either) | 예외 또는 인터럽트 | 메모리 오류(버스 오류 등)나 기타 하드웨어 결함으로 인해 발생할 수 있습니다. 상황에 따라 내부 예외로 처리되거나 외부 신호에 의한 인터럽트로 처리될 수 있습니다. |
핵심 구분:
인터럽트는 프로세서 외부에서 오는 예외의 한 종류로, 주로 I/O 장치와 관련이 있습니다.
나머지 대부분의 예외는 프로세서 내부에서 발생하며, 프로그램 실행 중 발생한 오류나 운영체제 요청과 관련이 깊습니다.
2. MIPS에서의 예외 처리 절차 (General)
예외가 발생했을 때 MIPS 프로세서는 CP0(Coprocessor 0, 시스템 제어 코프로세서)의 특수 레지스터들을 활용하여 정해진 절차에 따라 예외를 처리합니다.
문제 발생 명령어의 주소 저장 (Save EPC):
프로세서는 예외가 발생한 명령어의 주소(또는 파이프라인에서 지연 슬롯에 있었을 경우 지연 슬롯의 명령어 주소)의 다음 줄(PC+4)을 EPC (Exception Program Counter) 레지스터 (CP0, Reg 14)에 저장합니다. 이는 예외 처리 후 원래 프로그램으로 복귀할 지점을 알려주는 역할을 합니다.
예외 원인 저장 (Save Cause Register):
발생한 예외의 유형(원인, 32비트)을 Cause 레지스터에 기록합니다. Cause 레지스터 내의 ExcCode(Exception Code) 필드는 각 예외 유형에 대한 고유한 코드를 가집니다 (예: 정의되지 않은 명령어는
10
, 산술 오버플로우는12
).
예외 핸들러로 점프 (Jump to Handler):
CP0 레지스터(특히 Cause 레지스터의 ExcCode, Status 레지스터의 BEV 비트 등)의 정보를 기반으로, 프로세서는 미리 정해진 예외 벡터 주소로 점프합니다. 이 주소에는 해당 예외를 처리하기 위한 특별한 코드인 **예외 핸들러(Exception Handler)**가 위치합니다.
정의되지 않은 명령어의 경우
8000 0000_hex
로, 산술 오버플로우의 경우8000 0180_hex
로 점프합니다.
예외 핸들러는 발생한 예외의 종류를 식별하고, 적절한 처리(예: 에러 메시지 출력, 리소스 할당, 프로그램 재시작 등)를 수행합니다. 처리 완료 후에는
eret
(Exception Return) 명령어 등을 사용하여EPC
에 저장된 주소로 돌아가 프로그램 실행을 재개합니다.
3. 파이프라인에서의 예외 처리
add $1, $2, $1
명령어에서 EX(Execute) 스테이지에서 오버플로우가 발생했다고 가정할 경우, 파이프라인은 다음 절차를 따릅니다.
오버플로우 값 저장 방지:
ALU에서 오버플로우가 감지되면, 잘못된 결과 값($1 레지스터)이 레지스터 파일에 쓰이는 것을 즉시 중단해야 합니다. 이는 해당 명령어의 Write Back (WB) 스테이지를 취소(stall 또는 flush)함으로써 이루어집니다.
이전 명령어들 완료:
오버플로우가 발생한
add
명령어보다 먼저 파이프라인에 들어와 있었던 모든 명령어들은 정상적으로 실행을 완료하도록 허용합니다. 파이프라인은 명령어들의 원래 프로그램 순서를 보장해야 하므로, 이미 시작된 이전 작업들은 완료되어야 합니다.
이후 명령어들 플러시 (Flush):
오버플로우가 발생한
add
명령어 뒤에 파이프라인에 들어온 모든 명령어들은 즉시 파이프라인에서 제거되고 버려집니다 (Flush, 비우다). 이 명령어들은 예외 처리 루틴으로의 점프 이후에는 더 이상 유효하지 않기 때문입니다. 이미지에서 "EX.Flush"는 EX 스테이지에서 예외가 감지되었을 때 플러시가 시작됨을 나타냅니다.
EPC 및 Cause 레지스터 값 설정:
예외 발생 시점의 정확한 프로그램 상태를 기록합니다. 예외가 발생한
add
명령어의 주소를 EPC에, 오버플로우를 나타내는 코드(12
)와 기타 정보를 Cause 레지스터에 저장합니다.
오버플로우 핸들러로 점프:
마지막으로, 파이프라인의 다음 인출될 명령어 주소를 오버플로우 예외 핸들러의 시작 주소(
8000 0180_hex
)로 변경하여 제어권을 넘깁니다. 이로써 예외 처리 루틴이 시작됩니다.
파이프라인에서의 예외 처리의 중요성: 파이프라인 환경에서의 예외 처리는 정확한 예외(Precise Exception) 개념과 밀접하게 관련됩니다. 이는 예외 발생 시, 예외를 일으킨 명령어까지는 모든 동작이 완료되고, 그 이후의 명령어는 아무런 영향을 미치지 않도록 해야 한다는 원칙입니다. 이를 위해 파이프라인은 복잡한 플러싱 및 상태 저장 메커니즘을 동원하게 됩니다.