본문 바로가기
CS

[CS] 하드웨어 인터럽트

by seonggu 2023. 2. 9.

이전 글 -  https://seonggu.tistory.com/19 

위 글에서 비동기 인터럽트에 대해 간략하게 작성을 했었다. 

저번 글에서 언급했듯 비동기 인터럽트는 하드웨어 인터럽트라고도 부를 수 있다. 

이번 글은 하드웨어 인터럽트에 관한 설명을 추가하고 처리 순서에 대해 작성할 예정이다.

 

1️⃣ 하드웨어 인터럽트

하드웨어 인터럽트는 알림과 같은 인터럽트이다. CPU는 입출력 작업 도중에도 효율적으로 명령어를 처리하기 위해 이런 알림과 같은 하드웨어 인터럽트를 사용한다. 명령어를 효율적으로 처리하는 것과 하드웨어 인터럽트가 무슨 상관이 있는지 알아보자.

 

예를 들면 CPU가 프린터에 출력을 명령한 상황이다. 입출력장치는 CPU보다 속도가 현저히 느리기 때문에 CPU는 입출력 작업의 결과를 바로 받아볼 수 없다. 이때 만약 하드웨어 인터럽트를 사용하지 않는다면 CPU는 프린터가 언제 프린트를 끝낼지 모르기 때문에 주기적으로 프린터의 완료 여부를 확인해야 한다. 이로 인해 CPU는 다른 생산적인 일을 할 수 없으니 CPU 사이클이 낭비된다. 마치 알림이 없는 전자레인지가 언제 조리를 끝낼지 몰라서 전자레인지 앞에서 서성이는 것과 같다.

 

하지만 하드웨어 인터럽트를 사용하면 CPU는 주기적으로 프린트 완료 여부를 확인할 필요가 없다. CPU는 프린터로부터 프린트 완료 인터럽트를 받을 때까지 다른 작업을 처리할 수 있다.

이렇게 하드웨어 인터럽트는 입출력 작업 중에도 CPU로 하여금 효율적으로 명령어를 처리할 수 있게 한다.

 

2️⃣ 하드웨어 인터럽트 처리 순서

그럼 CPU가 하드웨어 인터럽트를 어떻게 처리하는지 구체적으로 알아보자. CPU가 인터럽트를 처리하는 방식은 종류와 상관없이 대동소이하다.

 

CPU가 하드웨어 인터럽트를 처리하는 순서는 다음과 같다.

1) 입출력장치는 CPU에 인터럽트 요청 신호를 보낸다.
2) CPU는 실행 사이클이 끝나고 명령어를 인출하기 전 항상 인터럽트 여부를 확인한다.
3) CPU는 인터럽트 요청을 확인하고 인터럽트 플래그를 통해 현재 인터럽트를 받아들일 수 있는지 여부를 확인한다.
4) 인터럽트를 받아들일 수 있다면 CPU는 지금까지의 작업을 백업한다.
5) CPU는 인터럽트 벡터를 참고하여 인터럽트 서비스 루틴을 실행한다.
6) 인터럽트 서비스 루틴 실행이 끝나면 4번에서 백업해 둔 작업을 복구하여 실행을 재개한다.

 

용어 정리 

인터럽트 요청 신호 : CPU의 작업을 방해하는 인터럽트에 대한 요청

 

인터럽트 플래그 : 하드웨어 인터럽트를 받아들일지, 무시할지를 결정하는 플래그이다. CPU가 인터럽트 요청을 수용하기 위해서는 플래그 레지스터의 인터럽트 플래그(interrupt flag)가 활성화되어있어야 한다. CPU가 중요한 작업을 처리해야 하거나 어떤 방해도 받지 않아야 할 때 인터럽트 플래그는 불가능으로 설정된다. 만약 인터럽트 플래그가 '불가능'으로 설정되어 있다면 CPU는 인터럽트 요청이 오더라도 해당요청을 무시한다. '가능'으로 설정이 되어 있으면 인터럽트 요청 신호를 받아들이고 인터럽트를 처리한다.

 

하지만 모든 하드웨어 인터럽트를 인터럽트 플래그로 막을 수 있는 것은 아니다. 인터럽트 플래그가 불가능으로 설정되어이 있을지라도 무시할 수 없는 인터럽트 요청도 있다. 무시할 수 없는 하드웨어 인터럽트는 가장 우선순위가 높거나 가장 먼저 처리해야 하는 인터럽트이다. 정전이나 하드웨어 고장으로 인한 인터럽트가 이에 해당한다.

CPU가 인터럽트 요청을 받아들이기로 했다면 CPU는 인터럽트 서비스 루틴이라는 프로그램을 실행한다.

 

인터럽트 서비스 루틴(ISR; Interrupt Service Routine) : 인터럽트를 처리하기 위한 프로그램. 인터럽트 핸들러(Interrupt handler)라고 부른다. 

인터럽트 서비스 루틴은 '키보드가 어떤 인터럽트 요청을 보냈을 때는 어떻게 작동한다', '마우스가 어떤 인터럽트 요청을 보냈을 때는 어떻게 작동한다', '프로그램에 어떤 문제가 생겼을 때는 어떻게 작동한다'와 같이 어떤 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하고 작동해야 할지에 대한 정보로 이루어진 프로그램이다.

'CPU가 인터럽트를 처리한다.'라는 말은 '인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다.' 라는 말과 같다.

 

2) 수행 도중 인터럽트가 발생한 경우

① 정상적으로 작업 진행

② 인터럽트 발생

③ 인터럽트 서비스 루틴으로 점프

④ 인터럽트 서비스 루틴 실행

⑤ 기존 작업으로 점프

⑥ 기존 작업 수행 재개

 

인터럽트를 처리하는 방법은 입출력장치마다 다르므로 각기 다른 인터럽트 서비스 루틴을 가지고 있다. 메모리에서는 위 그림과 같이 여러 개의 인터럽트 서비스 루틴이 저장되어 있다. 이들 하나하나가 '인터럽트가 발생하면 어떻게 행동해야 할지를 알려주는 프로그램'이다.

 

그럼 CPU는 각기 다른 인터럽트 서비스 루틴을 구분 해야한다. 이를 위해서 인터럽트 벡터를 이용한다.

 

인터럽트 벡터(interrupt vector) : 인터럽스 서비스 루틴을 식별하기 위한 정보.

인터럽트 벡터를 알면 인터럽트 서비스 루틴의 시작 주소를 알 수 있기 때문에 CPU는 인터럽트 벡터를 통해 특정 인터럽트 서비스 루틴을 처음부터 실행할 수 있다.

 

예를 들어 CPU가 작업을 수행하는 도중 키보드 인터럽트가 발생한 경우라면 CPU는 인터럽트 벡터를 참조하여 키보드 인터럽트 서비스 루틴의 시작 주소를 알아내고, 이 시작 주소로부터 실행해 나가며 키보드 인터럽트 서비스 루틴을 실행한다.

 

✅ 정리

'CPU가 인터럽트를 처리한다'라는 말은 '인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다.'라는 말과 같다. 그리고 CPU가 인터럽트 서비스 루틴을 실행하려면 인터럽트 서비스 루틴의 시작 주소를 알아야 하는데, 이는 인터럽트 벡터를 통해 알 수 있다.

인터럽트 서비스 루틴은 다른 프로그램과 같이 명령어와 데이터로 이루어져 있다. 그렇기에 인터럽트 서비스 루틴도 프로그램 카운터를 비롯한 레지스터들을 사용하며 실행된다.

 

그럼 인터럽트가 발생하기 전까지 레지스터에 저장되어 있던 값은?

CPU의 프로그램 카운터에는 1500이 저장되어 있다. 이 CPU에 하드웨어 인터럽트가 발생하여 10번지에 있는 인터럽트 서비스 루틴을 실행해야 한다고 가정하면, 기존에 프로그램 카운터에 저장되어 있던 1500은 그냥 10으로 덮으면 될까?

 

그렇지 않다. 인터럽트 요청을 받기 전까지 CPU가 수행하고 있던 일은 인터럽트 서비스 루틴이 끝나면 되돌아와서 마저 수행을 해야 하기 때문에 지금까지의 작업 내역들은 어딘가에 백업을 해둬야 한다.

그렇기에 CPU는 인터럽트 서비스 루틴을 실행하기 전에 프로그램 카운터 값 등 현재 프로그램을 재개하기 위해 필요한 모든 내용을 스택에 백업한다. 그러고 나서 인터럽트 서비스 루틴의 시작 주소가 위치한 곳으로 프로그램 카운터 값을 경신하고 인터럽트 서비스 루틴을 실행한다. 

인터럽트 서비스 루틴을 모두 실행하면, 다시 말해 인터럽트를 처리하고 나면 스택에 저장해 둔 값을 다시 불러온 뒤 이전까지 수행하던 작업을 재개한다.

 

 

 

참고자료 -

'CS' 카테고리의 다른 글

[CS] 명령어 병렬 처리 기법  (0) 2023.02.16
[CS] 클럭과 코어, 스레드  (0) 2023.02.14
[CS] 명령어 사이클과 인터럽트  (0) 2023.02.07
[CS] 레지스터  (0) 2023.02.02
[CS] ALU와 제어장치  (0) 2023.01.31