⚠️ 공부한 내용을 정리하는 공간입니다. 설명이 부족하거나 옳바르지 못한 부분이 있을 수 있습니다. 옳바르지 못한 내용을 발견하셨다면 댓글로 알려주시길 부탁드립니다. 수정하도록 하겠습니다.
오늘의 사족
비밀은 아니지만 저는 1일 1포스트를 수행하기 위해 시간적으로 여유로운 날에 2~3개의 글을 작성하여 비축해두고 있습니다.
여유분의 글을 작성할 때 곤란한 점을 꼽자면 바로 '오늘의 사족' 입니다. 왜냐면 하루에 3개의 글을 작성하는 경우에는 오늘의 사족을 3번 작성해야 하는데 그러기엔 저의 하루는 상당히 소소합니다. 그래서 간혹 오늘의 사족이 없는 글이 있습니다. 저의 소소한 하루를 3번에 걸쳐 새로운 이야기를 하기엔 앞서 말했듯 하루하루가 소소하기 때문이죠.
그래도 짜내서 말해보자면 이건 정말 비밀인데 저는 블로그 방문자 수의 제일 앞자리가 바뀔 때마다 기분이 좋아서 포효합니다. 방문자 수와 상관없이 꾸준히 하기로 마음을 다잡았지만 그래도 방문해주시는 분이 많으면 기분은 좋더군요 저의 기분을 좋게 만들어주시는 방문자분들 항상 감사드립니다!
1. Instruction Cycle (명령 주기)
“[1] CPU는 데이터를 인출하고 해석하고 실행한 다음 저장하는 과정을 거치면서 프로그램을 실행한다.” 즉 CPU의 명령주기(Instruction Cycle)는 데이터를 Fetch(인출)하고 명령을 Decode(해석)하고 Execute(실행)을 반복하는 과정으로 이뤄진다.
자세히 CPU가 어떻게 메모리에서 명령어를 읽어오고 해석하여 실행하는지에 대한 과정은 이전에 작성했던 글에서 확인할 수 있다.
CPU는 메모리에서 한 줄씩 명령을 읽어와 해석하여 실행하는 일은 반복적으로 수행하여 프로그램을 실행한다. 그런데 이때 CPU의 Instruction Cycle을 방해하는 경우가 생길 수 있다. 그 경우를 Interrupt라고 한다.
2. Interrupt
Interrupt는 CPU가 명령을 수행하는 흐름을 중단시키는 신호이다. 이때 명령을 중단시키도록 하는 주체가 CPU면 이를 Synchronous Interrupt(동기 인터럽트)라 하고 입출력 장치이면 Asynchronous Interrupt(비동기 인터럽트)라 한다.
2-1. Synchronous Interrupts (동기 인터럽트)
동기 인터럽트는 CPU에 의해 명령 주기 흐름이 중단된 경우이다. 주로 언제 동기 인터럽트가 발생하냐면 CPU가 명령어를 수행하다가 예상치 못한 상황 즉, 예외(exception)를 맞닥뜨릴 때 명령이 중단된다.
예외는 프로그램상의 문제로 프로그램을 멈추게 한다. 즉 명령어 자체에 오류가 있어 CPU가 명령을 수행하는 도중에 명령에 오류가 있음을 감지하고 명령 주기를 중단하는 것이다.
다음 코드 예시를 보자(Java를 사용했다)
public class ExceptionExample {
public static void main(String[] args) {
String[] animals = { "🐐Goat", "🐈Cat", "🐕Dog" };
System.out.println(animals[10]);
System.out.println("I Love Goat");
}
}
이처럼 예외는 명령 자체에 문제가 발생하여 CPU가 명령 수행을 중단한다.
2-2. Asynchronous Interrupts (비동기 인터럽트)
비동기 인터럽트는 입출력 장치에 의해 발생하는 인터럽트이다.
입출력 장치가 어떻게 CPU의 명령 주기를 방해할까?
에어프라이어로 군고구마🍠를 굽는다고 생각해보자. 우리는 고구마를 에어프라이어에 넣어 1시간을 굽는다. 고구마를 굽는 동안에 우리는 에어프라이어가 고구마를 다 구울 때까지 곁에서 지켜보진 않는다. 구워지는 동안에 책을 읽는다거나 TV를 시청한다거나 다른 일을 수행할 것이다.
CPU도 마찬가지이다. 입출력 장치가 일을 수행하는 동안에 다른 중요한 일을 수행하다가 입출력 장치가 일을 다 완료했을 때 입출력 장치로 부터 신호를 받는다. 신호를 받으면 그때 CPU가 수행하던 명령을 멈추고 입출력 장치의 요청을 들어준다.
그렇다면 어떻게 입출력 장치가 CPU에게 일을 완료했다고 신호를 보내는지 비동기 인터럽트가 발생하는 과정을 알아보자!
전에 CPU의 구성요소를 설명하는 글에서 Flag Register가 하는 일에 대해 설명했었다. Flag Register가 기억하는 다양한 부가정보 중에서 이번 주제와 관련하여 주의깊게 봐야할 Flag가 있다. 바로 Interrupt Flag이다. Interrupt Flag가 저장하는 정보로는 CPU가 명령을 수행하는 도중에 Interrupt를 가능하게 할 것인지 아닌지이다.
즉, 입출력장치가 인터럽트를 발생시키는 전제 조건이 Interrupt Flag가 활성화되어야 한다는 것이다.
CPU가 Interrupt Flag를 활성화시켰다면 CPU는 Interrupt Service Routine 프로그램을 실행하여 인터럽트를 처리한다. Interrupt Service Routine은 입출력 장치가 어떤 인터럽트 요청을 보낸 경우에 어떻게 처리할 것인지에 대한 정보로 이루어진 프로그램이다.
이때 입출력 장치는 다양하기 때문에 각 장치별로 Interrupt Service Routine 시작점이 다 다르다. 그래서 CPU가 프로그램을 실행하는 도중에 특정 입출력 장치로부터 인터럽트 요청을 받으면 특정 입출력 장치의 Interrupt Service Routine 시작점으로 안내할 필요가 있다. 그 안내자 역할을 하는 것이 바로 Interrupt Vector이다. Interrupt Vector는 Interrupt Service Routine을 식별하기 위한 정보로서 CPU는 어떤 입출력 장치에 의해 인터럽트 요청을 받으면 Interrupt Vector를 통해 특정 Interrupt Service Routine을 시작한다.
CPU는 Interrupt Service Routine을 마치고 수행했던 명령으로 돌아와 다시 시작한다. 이때 어떻게 다시 실행했던 명령어의 주소를 찾아가냐면 CPU는 Interrupt Service Routine을 수행하기 전에 지금까지 실행하던 명령에 대한 정보를 메모리에 있는 스택 영역(Stack Segment)에 백업해두고 Interrupt Service Routine을 수행한다.
< 참조 >
[1] bRd 3D. (2021.07.31) CPU는 어떻게 작동할까?-[Video file].(17분 55초~) 검색경로 https://www.youtube.com/watch?v=Fg00LN30Ezg