4장 CPU의 작동 원리
04-1 ALU와 제어장치
CPU의 구성
- ALU: 계산을 담당
- 제어장치: 명령어를 읽어 들이고 해석
- 레지스터: 작은 임시 저장 장치
ALU
Input
- 피연산자: 레지스터를 통해 받는 연산의 대상
- 제어 신호: 수행할 연산에 대한 정보
Output
- 계산 결괏값, 플래그
- 연산 수행의 결과는 특정 데이터일 수도, 메모리 주소가 될 수 있다.
- 결괏값은 바로 메모리에 저장되지 않고 일시적으로 레지스터에 저장
- CPU가 메모리에 접근하는 속도 < CPU가 레지스터에 접근하는 속도
- 플래그(flag)
- 연산 결과에 대한 추가적인 정보
- 부호 플래그, 제로 플래그, 캐리 플래그 등
- 플래그 레지스터에 저장
- 오버플로우(overflow): 연산결과가 연산을 담을 레지스터보다 큰 상황
제어장치
- 제어 신호를 내보내고, 명령어를 해석하는 부품
- 제어신호: 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호
Input
- 클럭 신호
- 클럭(clock): 컴퓨터의 모든 부품을 움직이는 시간 단위
- 컴퓨터의 모든 부품은 클럭 신호에 맞춰 작동
- 하지만 모든 부품이 한 클럭마다 작동하는 것은 아님
- 해석해야 할 명령어
- 명령어 레지스터에 저장된 명령어
- 명령어를 받아 해석한 뒤, 제어 신호를 발생시켜 컴퓨터 부품들에 수행해야할 내용을 전달
- 플래그 레지스터 속 플래그 값
- ALU 연산에 대한 추가적인 상태 정보
- 제어버스로 전달된 제어 신호
- 입출력장치를 비롯한 CPU 외부 장치가 발생시킨 제어 신호도 포함
Output
- CPU 외부에 전달하는 제어 신호
- 입출력장치: 입출력장치의 값을 읽거나 새로운 값을 쓸 때
- 메모리: 메모리에 저장된 값을 읽거나 새로운 값을 쓸 때
- CPU 내부에 전달하는 제어 신호
- ALU: 수행할 연산을 지시하기 위해
- 레지스터: 레지스터 간에 데이터롤 이동시키거나 저장된 명령어를 해석하기 위해
04-2 레지스터
반드시 알아야 할 레지스터
많은 CPU가 공통으로 포함하는 레지스터들
프로그램 카운터
PC(Program Counter) 혹은 IP**(Instruction Pointer)**: 메모리에서 가져올 명령어의 주소를 저장
명령어 레지스터
IR(Instruction Register): 읽어들인 명령어를 저장하는 레지스터
메모리 주소 레지스터
MAR(Memory Address Register): 메모리의 주소를 저장하는 레지스터
CPU가 주소 버스로 내보낼 값이 거치는 곳
메모리 버퍼 레지스터
MBR(Memory Buffer Register) 혹은 MDR**(Memory Data Register)**: 메모리와 주고받을 값(데이터와 명령어)을 저장하는 레지스터
CPU가 데이터 버스로 주고 받을 값이 거치는 곳
범용 레지스터
GPR(General Purpose Register): 데이터와 주소를 모두 저장할 수 있는 레지스터
플래그 레지스터
FR(Flag Register): ALU 연산 결과, CPU 상태에 대한 부가적인 정보 저장
스택 포인터
SP(Stack Pointer): 스택에 마지막으로 저장된 값의 위치(꼭대기)를 가리키는 레지스터. 스택 주소 지정 방식에 사용
베이스 레지스터
BR(Base Register): 변위 주소 지정 방식에 사용
메모리에 저장된 프로그램을 실행하는 과정
- 프로그램이 저장된 처음 메모리 주소(ex. 1000)이 프로그램 카운터에 저장됨
- 해당 메모리 주소가 메모리 주소 레지스터에 저장됨
- 해당 메모리 주소(1000)가 주소 버스, 제어 신호(메모리 읽기)가 제어 버스를 통하여 메모리에 전달
- 1000에 저장된 값이 데이터 버스를 통해 메모리 버퍼 레지스터에 전달되어 저장됨
- 1000이 저장된 프로그램 카운터가 1001로 증가함
- 메모리 버퍼 레지스터에 저장된 값이 명령어 레지스터로 저장됨
CPU 속 프로그램 카운터는 꾸쭌히 증가하며, 특정 명령어로 인해 순차적인 실행흐름이 끊어질 수 있음
ex) 점프, 특정 주소로 이동 등
특정 레지스터를 이용한 주소 지정 방식(1): 스택 주소 지정 방식
스택: 메모리 안에 존재하는 스택 영역에 존재
스택 포인터는 스택의 꼭대기를 가리킨다. 즉 스택에서 어느 주소까지 데이터가 채워져 있는지를 나타냄
스택 주소 지정 방식은 명령어의 오퍼랜드 필드에 스택 주소를 담는 방식
특정 레지스터를 이용한 주소 지정 방식(2): 변위 주소 지정 방식
변위 주소 지정 방식(displacement addressing mode): 명령어의 오퍼랜드 필드의 값(변위)과 특정 레지스터의 값을 더하여 유효 주소를 얻어내는 주소 지정 방식
오퍼랜드 필드의 주소와 어떤 레지스터를 더하는지에 따라 나뉘어짐
명령어의 값(PC)의 값과 멀면 오퍼랜드에 저장되어야 할 값이 커짐
상대 주소 지정 방식
상대 주소 지정 방식(relative addressing mode): 오퍼랜드 + 프로그램 카운터의 값(읽어들일 명령어의 주소) ⇒ 유효주소
따라서 지금 실행 중인 명령어의 주소를 기준으로 한 거리
베이스 레지스터 주소 지정 방식
베이스 레지스터 주소 지정 방식(base-register addressing mode): 오퍼랜드 + 베이스 레지스터의 값(기준 주소) ⇒ 유효주소
04-3 명령어 사이클과 인터럽트
명령어 사이클: 하나의 명령어를 처리하는 정형화된 흐름
인터럽트: 명령어를 처리해 나가는 흐름이 끊어지는 상황
명령어 사이클
명령어 사이클(instruction cycle): 프로그램 속 각각의 명령어들이 반복되며 실행되는 주기
인출 사이클(fetch cycle): 메모리에 있는 명령어를 CPU로 가지고 오는 단계
실행 사이클(execution cycle): CPU로 가져온 명령어를 실행하는 단계
간접 사이클(indirect cycle): 메모리 접근이 더 필요한 경우의 단계(간접 주소 지정 방식이라 주소를 가져온 경우 등)
인출 사이클과 실행 사이클의 반복 사이에서 경우에 따라 간접 사이클과 인터럽트 사이클이 실행된다.
인터럽트
인터럽트(Interrupt): CPU의 작업을 방해하고 중단시키는 신호
동기 인터럽트(synchronous interrupts)
- **예외(exception)**라고도 함
- CPU에 의해 발생하는 인터럽트
- ex) CPU가 실행하는 프로그래밍상의 오류
비동기 인터럽트(asynchronous interrupts)
- 하드웨어 인터럽트라고도 함
- 주로 입출력장치에 의해 발생하는 인터럽트
- ex) 작업을 끝낸 입출력장치가 CPU에 완료 알람을 보내는 경우
하드웨어 인터럽트
CPU의 명령을 수행하는 입출력장치가 작업의 완료를 알림
인터럽트가 발생하기 전까지 CPU는 다른 작업을 진행할 수 있음
하드웨어 인터럽트 처리 순서
- 입출력장치 → CPU 인터럽트 요청 신호 송신
- CPU는 실행 사이클이 끝나고 명령어를 인출하기 전 항상 인터럽트 여부를 확인
- CPU는 인터럽트 요청을 확인하고 인터럽트 플래그를 통해 현재 인터럽트를 수신할 수 있는 상태인지 확인
- CPU는 수신할 수 있으면 지금까지의 작업을 백업
- CPU는 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴을 실행
- 인터럽트 서비스 루틴 실행이 끝나면 4의 백업을 복구하여 실행 재개
인터럽트 요청 신호: 인터럽트를 발생시켜도 되는지 CPU에게 묻는 신호
인터럽트 플래그(interrupt flag): CPU가 하드웨어 인터럽트를 받아들일지, 무시할지를 결정하는 플래그 레지스터의 플래그
- 막을 수 있는 인터럽트(maskable interrupt)
- 막을 수 없는 인터럽트(non maskable interrupt): 일부 중요한 하드웨어 인터럽트(하드웨어 고장, 정전 등)는 플래그를 무시
인터럽트 서비스 루틴(Interrupt Service Routine): 인터럽트를 처리하기 위한 동작들로 이루어진 프로그램
- **인터럽트 핸들러(Interrupt handler)**라고도 함
인터럽트 벡터(interrupt vector): 인터럽트 서비스 루틴을 식별하기 위한 정보
CPU는 하드웨어 인터럽트 요청을 보낸 대상으로부터 데이터 버스를 통해 인터럽트 벡터를 전달받음
CPU는 인터럽트 벡터를 통해 특정 인터럽트 서비스 루틴의 시작 주소를 알 수 있음
CPU가 인터럽트를 처리한다: 인터럽트 서비스 루티능ㄹ 실행하고, 본래 수행하던 작업으로 다시 되돌아온다.
CPU가 인터럽트를 처리하기 전, 프로그램 카운터 값 등 인터럽트 처리 이후 작업을 재개하기 위해 필요한 모든 내용을 스택에 백업함
예외의 종류
- 인터럽트
- 동기 인터럽트(예외)
- 폴트(fault)
- 예외를 처리한 직후 예외가 발생한 명령어부터 실행을 재개
- ex) 명령어를 처리하기 전 보조기억장치에서 필요한 데이터를 불러옴
- 트랩(trap)
- 예외를 처리한 직후 예외가 발생한 명령어의 다음 명령어부터 실행을 재개
- ex) 디버깅
- 중단(abort)
- CPU가 실행중인 프로그램을 강제로 중단시킬 수밖에 없는 심각한 오류 발견
- 소프트웨어 인터럽트(software interrupt)
- 시스템 호출 발생
- 폴트(fault)
- 동기 인터럽트(예외)
- 비동기 인터럽트(하드웨어 인터럽트)
의문
제로플래그는 왜 필요할까?
- 연산 결과가 0인지 아주 빠르게 알기 위해..?
- 비교할 때 편하다.
- CPU가 두 값을 비교할 때, 뺄셈을 한다.
- 5와 5를 비교했을 때 연산 결과로 제로플래그가 나오면 “아 둘은 같군”이라고 판단함
IR은 있는데, 데이터 레지스터는 없나?
- GPR이 그 역할을 함
명령어 데이터를 MBR→ IR 순서를 거치지 않고 바로 IR로 저장하면 안되나?
- 확장성, 타이밍, 예외처리를 위해 완충 역할(버퍼/캐시)로서 MBR이 필요
- 메모리에서 값이 딱 한 사이클에 깨끗하게 오지 않는다.
- 그럼 메모리에서 값이 여러 사이클에 온다고 하면 MBR이 다 받아서 한번에 IR로 넘겨줌
상대 주소 지정 방식과 베이스 레지스터 주소 지정 방식의 차이는 뭐지?
- 상대 주소 = 코드 기준(PC) 이동, 베이스 주소 = 데이터 기준(베이스 레지스터) 이동.
- 여기서 코드는 메모리에 저장된 프로그램의 명령어들
스택 주소 지정방식은 스택에 데이터가 스택에 저장되어 있을 때 사용하나? 그럼 스택에 저장된 데이터는 뭐지?
- 로컬/리턴주소/레지스터 백업 등 호출 프레임을 다룰 때 사용
레지스터 별로 크기 차이가 다를까?
대부분의 레지스터는 CPU의 “비트 크기”와 같음. 플래그 레지스터는 상태 표시만 하므로 더 작을 수 있음
베이스 레지스터 주소 지정방식과 레지스터 간접 주소 지정 방식의 차이. 왜 굳이 더하게 만들었을까?
- 연속된 데이터 접근에 최적화. 순서대로 1000, 1004, 10008에 접근해야 한다면
- 레지스터 간접 주소 지정 방식은 1000, 1004, 1008을 오퍼랜드 필드에 넣어야함
- 베이스 레지스터 주소 지정 방식은 BR에 1000을 넣어두고 오퍼랜드만 +0, +4, +8로 바꿔주면 됨.
- 훨씬 짧고 빨라지며 명령어 크기도 줄어든다.
- 프로그램의 메모리 주소가 500, 504, 508로 바뀐다면?
- 레지스터 간접 주소 지정 방식이면 3개를 다 바꾸어야 함.
- 베이스 레지스터 주소 지정 방식이면 베이스 레지스터를 ‘현재 프로그램이 올라간 시작 주소’로 해두면 어느 위치에서든 같은 동작을 하게 됨 ⇒ 위치 독립 코드(Position Independent Code)
- 연속된 데이터 접근에 최적화. 순서대로 1000, 1004, 10008에 접근해야 한다면