강민철님의 "혼자 공부하는 컴퓨터 구조+운영체제"을 기반으로 학습한 게시물입니다.
📕 목차
1. ALU와 제어장치
2. Register
3. 명령어 사이클과 인터럽트
1. ALU와 제어장치
📌 ALU
- ALU는 연산한 결괏값과 플래그(flag)를 내보낸다. (플래그 레지스터에 저장)
- Register를 통해 피연산자를 받고, 제어장치로부터 제어 신호를 받아 수행할 연산을 판단
- 결괏값은 바로 Memory에 저장되지 않고 일시적으로 Register에 저장 (CPU가 Memory에 접근하는 게 느려서)
- 가산기, 보수기, 시프터, 오버플로우 검출기 등의 회로가 내부에 구성
✒️ 플래그(flag)
종류 의미 예시 sign flag 연산 결과의 부호 • 음수 : 1
• 양수 : 0zero flag 연산 결과 0 여부 • 0인 경우 : 1
• 0이 아닌 경우 : 0carry flag 연산 결과 올림수나 빌림수 발생 여부 • 발생 : 1
• 미발생 : 0overflow flag 오버 플로우 발생 여부 • 발생 : 1
• 미발생 : 0interrupt flag 인터럽트 가능 여부 • 가능 : 1
• 불가능 : 0supervisor flag 커널 모드 / 사용자 모드 • 커널 모드 : 1
• 사용자 모드 : 0
📌 제어장치
- CPU 구성 요소 중 가장 정교하게 설계된 부분
- 4가지 수신 정보
- 클럭(clock) 신호 수신
- 명령어 Register로부터 해석해야 할 명령어 수신
- Flag register의 flag 수신
- 제어 버에서 제어 장치로 전달된 제어 신호 수신
- 2가지 출력 정보
- 내부 제어 신호 출력 (Register, ALU)
- Register : 레지스터 간 데이터 이동, 저장된 명령어 해석
- ALU : 수행할 연산 지시
- 외부 제어 신호 출력
- Memory : 메모리 값 읽기/쓰기
- IO Device(보조 기억 장치) : IO 장치 값 읽기/쓰기
- 내부 제어 신호 출력 (Register, ALU)
2. Register
- 프로세서(CPU)에 위치한 고속의 메모리
- 특수한 값 하나를 저장하는 기억공간
- 프로그램 속 명령어와 데이터는 실행 전후로 반드시 레지스터에 저장
📌 Register 종류
- 프로그램 카운터 (Program Counter)
- 메모리에서 가져올 명령어 주소 저장
- 명령어 포인터(IP; Instruction Pointer)라고도 함
- 명령어 레지스터 (Instruction Register)
- 메모리에서 읽어 들인 명령어를 저장
- 제어장치에서 명령어 레지스터의 명령어를 수신하여 해석한 뒤 제어신호 출력
- 메모리 주소 레지스터 (MAR; Memory Address Register)
- 메모리의 주소를 저장
- CPU가 주소 버스로 내보낼 값
- 메모리 버퍼 레지스터 (MBR; Memory Buffer Register)
- 메모리와 주고받을 값(데이터, 명령어) 저장
- CPU가 데이터 버스로 주고받을 값
- 메모리 데이터 레지스터(MDR; Memory Data Register)와 동일
- 플래그 레지스터 (Flag Register)
- ALU 연산 결과 또는 CPU 상태에 대한 부가적인 정보 저장
- 범용 레지스터 (General Purpose Register)
- 다양하고 일반적인 상황에서 자유롭게 사용
- 데이터와 주소를 모두 저장 가능
- CPU 내에 여러 개의 범용 레지스터들이 존재
- 스택 포인터 (Stack Pointer)
- 스택의 꼭대기를 가리키는 레지스터
- 스택 주소 지정 방식 사용
- 베이스 레지스터 (Base Register)
- 기준 주소를 의미
- 오퍼랜드(기준 주소로부터 떨어진 거리)와 함께 사용하여 베이스 레지스터 주소 지정 방식 사용
더보기
✒️ 1~4번 레지스터 동작 과정
1️⃣ CPU로 실행할 프로그램이 1000~1500번지까지 저장되어 있음
2️⃣ 프로그램 실행을 위해 프로그램 카운터에 1000번지 저장
3️⃣ 주소 버스로 1000번지를 보내기 위해 메모리 주소 레지스터에 1000번지 저장
4️⃣ '메모리 읽기' 제어신호화 메모리 주소 레지스터 값이 각각 제어 버스와 주소 버스를 통해 메모리로 전달
5️⃣ 메모리 1000번지 주소의 값이 데이터 버스를 통해 메모리 버퍼 레지스터에 저장
- 이 때, 프로그램 카운터가 증가하여 다음 명령어를 읽을 준비를 한다.
6️⃣ 메모리 버퍼 레지스터에 저장된 값이 명령어 레지스터로 이동
7️⃣ 제어장치가 명령어 레지스터의 명령어를 해석하고 제어 신호 발생
✒️ 순차적 실행 흐름이 끊기는 경우
명령어 중 JUMP, CONDITIONAL JUMP, CALL, RET처럼 특정 Memory 주소로 실행 흐름을 이동하는 명령어 실행 시, 프로그램이 순차적으로 실행되지 않는다.
또한 Interrupt가 발생해도 순차적인 흐름은 끊어진다.
📌 스택 주소 지정 방식(Stack addressing mode)
- Stack point register가 Stack 꼭대기 주소 정보를 가리킨다
- Stack 영역 : 메모리 안에서 Stack처럼 사용할 영역 (다른 주소 공간과 다르게 사용하기로 암묵적 약속)
📌 변위 주소 지정 방식(Displacement addressing mode)
- 프로그램 카운터와 베이스 레지스터 사용
- 명령어(연산 코드 + 오퍼랜드)에서 오퍼랜드 필드 값(변위)과 특정 Register 값을 더하여 유효 주소 판단
- (레지스터 값 + 오퍼랜드)가 가리키는 주소의 값으로 (연산 코드) 수행
1️⃣ 상대 주소 지정 방식(relative addressing mode)
- 오퍼랜드와 프로그램 카운터 값을 더하여 유효주소 판단
- 읽어 들일 명령어 주소(프로그램 카운터)에서 이동 값(변위)을 더한 메모리 주소 값에 접근
2️⃣ 베이스 레지스터 주소 지정 방식(base-register addressing mode)
- 오퍼랜드와 베이스 레지스터 값을 더하여 유효주소 판단
3. 명령어 사이클과 인터럽트
- CPU가 하나의 명령어를 처리하는 과정에는 정해진 흐름이 있다.
- 명령어 사이클 : 하나의 명령어를 처리하는 정형화된 흐름
- 인터럽트 : 정해진 흐름이 끊어지는 상황
📌 명령어 사이클(instruction cycle)
- 프로그램 속 각각의 명령어들이 반복되며 실행되는 일정한 주기
- 인출 사이클(fetch cycle)
- 메모리에 있는 명령어를 CPU로 가지고 오는 단계
- 실행 사이클(execution cycle)
- CPU로 가져온 명령어를 실행하는 단계
- 제어장치가 명령어 레지스터에 담긴 값을 해석, 제어 신호 발생
- 간접 사이클(indirect cycle)
- 명령어 실행을 위해 메모리 접근을 한 번 더 해야 하는 경우
- 간접 주소 지정 방식의 경우 오퍼랜드 필드에 유효 주소의 주소를 명시해둠
- 즉, 명령어를 인출하여 CPU를 가져와도 바로 실행 사이클 돌입 불가능
📌 인터럽트(interrupt)
- CPU가 수행 중인 작업을 잠시 방해하고, 다른 일을 처리시킨다.
- 동기 인터럽트(synchronous interrupts)
- CPU에 의해 발생
- 명령어 수행 도중 예상치 못한 상황
- 예외(exception)과 동일
- 비동기 인터럽트(asynchronous interrupts)
- 입출력 장치에 의해 발생
- ex. CPU가 프린터같은 IO 장치에 작업을 요청하고, 작업이 끝낸 IO 장치가 CPU에 완료 알림(인터럽트) 송신
- ex. 키보드, 마우스 같은 IO 장치가 어떤 입력을 받으면 이를 처리하기 위해 CPU에 입력 알림(인터럽트) 송신
- 하드웨어 인터럽트와 동일
📌 하드웨어 인터럽트
💡 CPU가 Interrupt를 처리하는 것은 ISR을 실행하고, 본래 작업으로 돌아오는 것이다.
- CPU 입출력 작업 도중에도 효율적 명령어 처리를 위한 알림과 같은 인터럽트
- IO 장치는 일반적으로 cpu보다 속도가 현저히 느림
- HW가 인터럽트를 사용하지 않으면, CPU가 주기적으로 작업 완료 여부 확인 과정 필요 (오버헤드)
- 일반적인 처리 순서
- IO 장치는 CPU에 인터럽트 요청 신호 송신
- CPU가 실행 사이클이 끝나고 명령어 인출하기 전 항상 인터럽트 여부 확인
- CPU가 인터럽트 요청 확인 → 인터럽트 플래그를 통해 현재 인터럽트 수신 가능 여부 확인
- 가능하다면 CPU는 지금까지 작업을 백업
- 프로그램 카운터 값 등 현재 프로그램 재개를 위한 모든 내용을 Stack에 백업
- CPU는 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴 실행
- 루틴이 종료되면 백업해둔 작업을 복구하여 재실행
- 용어 정리
- 인터럽트 요청 신호
- CPU에 작업 중단 가능 여부 확인
- 인터럽트 플래그
- Flag Register의 Interrupt flag 활성화되어 있다면 인터럽트 가능 (비활성화면 인터럽트 무시)
- 막을 수 있는 인터럽트(maskable interrupt) : 일반적인 IO 장치 요청
- 막을 수 없는 인터럽트(non maskable interrupt) : 정전이나 하드웨어 고장으로 인한 인터럽트
- 인터럽트 서비스 루틴 (ISR; Interrupt Service Routine)
- 인터럽트 핸들러(Interrupt Handler)와 동일
- 해당 Interrupt를 어떻게 처리하고 작동해야 할지에 대한 정보로 이루어진 Program
- Memory에는 여러 개의 Interrupt Service Routine이 저장되어 있고, 하나하나가 Interrupt에 대한 대처 방식을 정의해둠 (명령어 + 데이터)
- 인터럽트 벡터(Interrupt Vecotr)
- CPU가 수많은 ISR을 구분하기 위한 정보
- ISR의 시작 주소를 통해, Interrupt가 발생하면 해당 주소로 jump한다.
- 인터럽트 요청 신호
📌 예외 종류
Exception이 발생하면 CPU는 하던 일을 중단하고 예외를 처리한다.
예외를 처리하면 cpu는 본래 작업으로 되돌아 오는데, 어디로 돌아가느냐로 나뉘어질 수 있다.
Synchronous Interrupts는 4가지로 더 나누어 볼 수 있다.
- 폴트(fault)
- 예외를 처리한 직후 예외가 발생한 명령어부터 실행 재개
- ex. 프로그램 실행에 필요한 데이터가 Memory에는 없고 보조 기억 장치에만 있는 경우, CPU는 fault를 발생시키고 보조 기억 장치에서 데이터를 Memory로 옮긴 후, fault가 발생한 명령어부터 실행
- 트랩(trap)
- 예외를 처리한 직후 예외가 발생한 명령어의 다음 명령어부터 실행 재개
- 주로 디버깅할 때 사용
- 중단(abort)
- CPU가 프로세스를 강제로 중단시킬 정도로 심각한 오류가 검출된 경우
- 소프트웨어 인터럽트(software interrupt)
- 시스템 호출이 발생했을 때 발생