컴퓨터구조와 운영체제

9. 명령어 사이클과 인터럽트

waterclean101 2023. 11. 9. 09:26

명령어 사이클과 인터럽트

 

컴퓨터의 내부 동작 원리를 이해함에 있어서 명령어 사이클과 인터럽트는 아주 중요한 개념이다.

명령어 사이클과 인터럽트

 

  • 명령어 사이클: CPU는 메모리로부터 명령어나 데이터들을 갖고 와서 실행하고, 필요하다면 값을 저장할 수도 있다고 했는데 이 과정에서 CPU가 메모리에 저장되어 있는 프로그램을 실행하는 데 일정한 패턴이 있다. 일정한 주기가 있다. 다시 말해서 일정한 어떤 정해진 흐름이 있다. CPU는 메모리 안에 있는 프로그램을 어떤 정해진 흐름대로 처리하게 되는데 그 정해진 흐름 주기를 명령어 사이클이라고 한다.
  • 인터럽트: CPU는 메모리에 있는 프로그램을 정해진 흐름대로 처리를 하는데 간혹 정해진 흐름을 방해하는 신호가 CPU한테 올 수 있다. 그렇게 정해진 흐름을 끊는 신호를 인터럽트라고 한다.

 

명령어 사이클

  • 인출 사이클: 어떤 프로그램을 실행하기 위해서는 메모리에 있는 값을 CPU의 레지스터 혹은 CPU 내부로 가져와야 한다. 이렇게 CPU가 메모리 안에 있는 어떤 프로그램을 실행하기 위해서 메모리에 저장된 값을 CPU 내부로 갖고 오는 작업을 인출이라고 하고 인출하는 주기를 인출 사이클이라고 부른다.
  • 실행 사이클: 갖고 왔으면 실행해야 한다. 실행 사이클.

일반적으로 CPU는 인출-실행-인출-실행 이렇게 인출 사이클과 실행 사이클이 반복되면서 실행된다. 이 과정이 반복되어 이게 명령어 사이클의 일부가 된다.

그런데 간접 주소 지정 방식 등 인출을 하더라도 바로 실행이 불가능한 경우 즉, 추가적으로 메모리에 접근해야 하는 경우가 있을 수가 있다. 이렇게 인출을 했다고 해서 바로 실행이 가능하지 않고 몇 번 더 메모리 접근을 해야 되는 경우를 위해서 간접 사이클이 추가될 수 있다.

일반적으로는 인터럽트라고 하는 개념이 없다면 CPU는 이 주기를 바탕으로 실행된다.

 

인터럽트

CPU가 꼭 주목해야 할 때, CPU가 얼른 처리해야 되는 작업이 생겼을 때 보통 이럴 때 인터럽트가 발생한다. 인터럽트에는 동기 인터럽트(예외)와 비동기 인터럽트(하드웨어 인터럽트)가 있다.

 

동기 인터럽트

CPU가 예기치 못한 상황을 접했을 때 발생한다. CPU가 주기대로 실행을 하고 있었는데 잠깐 멈추고 이 예외적인 상황을 먼저 처리해야 한다고 인지하는 것이다. 동기 인터럽트에 대해서는 운영 체제에서 조금 더 자세하게 다룰 것.

 

비동기 인터럽트(하드웨어 인터럽트)

  • 입출력 장치에 의해서 발생하는, 다른 하드웨어가 보내주는 인터럽트
  • 동기 인터럽트가 CPU가 예기치 못한 상황을 접했을 때 발생한다면 비동기 인터럽트는 어떤 문제라기보다는 알림과 같은 역할을 한다. 예를 들어 인쇄물을 프린트 하는 상황에서 CPU가 프린트에게 다른 일을 처리하고 있을테니 출력 작업 완료되면 불러달라고 하고, 프린터는 출력 작업이 완료되면 CPU한테 알림과 같은 하드웨어 인터럽트를 보낸다. 키보드, 마우스 등도 마찬가지.
  • CPU가 입출력 작업 도중에도 효율적으로 명령어를 처리하기 위해서 사용한다. 입출력 장치의 입출력 작업은 일반적으로 CPU에 비해서 느리다. 하드웨어 인터럽트가 없다면 CPU가 프린터기에 입출력 명령 프린트를 하라는 명령을 내렸을 때 CPU는 프린트 완료 여부를 확인하기 위해서 주기적으로 완료 여부를 확인해줘야 한다.
  • 인터럽트가 있어서 CPU가 입출력 잡업 동안 다른 일을 할 수 있다.

 

 

하드웨어 인터럽트의 처리 순서

하드웨어 인터럽트라고 쓰기는 했지만 인터럽트의 종류를 막론하고 대부분의 인터럽트를 처리하는 순서는 여기 아래에서 크게 벗어나지 않는다.

  1. 입출력 장치는 CPU한테 인터럽트 요청 신호를 보낸다.
  2. CPU는 실행 사이클이 끝나고 명령어를 인출하기 전에 항상 인터럽트가 인터럽트 여부를 확인한다.
  3. CPU가 인터럽트 요청을 확인하면 레지스터에 있는 인터럽트 플래그를 통해서 현재 이 인터럽트를 지금 처리할 수 있는지 여부를 확인한다.
  4. 인터럽트를 처리할 수 있다면 CPU는 지금까지 했던 작업을 잠시 백업을 한다.
  5. 그 후 인터럽트 백터를 참조하여 인터럽트 서비스 루틴이라는 프로그램을 실행한다.
  6. 인터럽트 서비스 루틴 실행이 끝나면 백업해 둔 작업을 복구해서 다시 하던 일을 실행을 재개한다.

 

인터럽트 요청 신호: 하드웨어 인터럽트를 보내는 입출력 장치 같은 주체들이 CPU에게 지금 끼어들어도 되는지 요청을 보내는 신호. 인터럽트는 CPU의 정상적인 실행 흐름을 끊는 것이기 때문에 항상 인터럽트를 보내는 주체는 CPU에게 인터럽트 요청 신호를 보낸다.

인터럽트 플래그: CPU와 인터럽트 요청 신호를 받아들였으면 실행 사이클이 끝나고 항상 플래그 레지스터 속에 인터럽트 플래그를 확인한다. 인터럽트 플래그에는 현재 인터럽트를 받아들일 수 있다 현재 인터럽트를 받아들일 수 없다가 0과 1로 표기된다. 단, 모든 인터럽트를 인터럽트 플래그으로 막을 수 있는 것은 아니다. 일부 인터럽트 중에서는 하드웨어 고장이나 정전 같은 너무 중요하고 긴급한 인터럽트도 있다. 막을 수 없는 인터럽트를 non maskable interrupt라고 부른다. 다만 대부분의 입출력 장치가 CPU에 보내는 하드웨어 인터럽트는 인터럽트 플래그를 통해서 막을 수 있다.

인터럽트 서비스 루틴: CPU가 인터럽트를 받아들이기로 했다면 인터럽트 서비스 루틴이라는 프로그램을 실행한다. 인터럽트 서비스 루틴은 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하면 되는지가 적혀 있는 프로그램. 인터럽트 서비스 루틴 또한 프로그램이기 때문에 일반적으로 메모리에 저장되어 있다.

CPU는 실행 중인 프로그램을 쭉 실행하다 인터럽트가 발생하면 해당 명령어까지는 실행을 끝내고 그 인터럽트로 되돌아가서 그 인터럽트를 실행한 다음 다시 되돌아와서 수행을 재개하게 된다. 여기서 인터럽트를 보낼 수 있는 주체에 따라서 인터럽트 서비스 루틴의 시작 주소가 달라지는데 즉, 프린트, 키보드, 마우스의 인터럽트 서비스 루틴의 시작 주소가 다른데, CPU가 해당 인터럽트 서비스 루틴의 시작 주소는 무엇인지 각각의 인터럽트를 구분하기 위한 정보를 인터럽트 백터라 부른다. 그리고 이 인터럽트 백터를 표의 형태로 모아놓은 것을 인터럽트 백터 테이블이라 한다.

 

요컨데 CPU가 인터럽트를 처리한다라고 하는 말은 달리 말하면 인터럽트 서비스 루팅을 실행하고 원래 수행하던 작업으로 되돌아온다라고도 표현할 수 있다. 인터럽트 시작 주소는 인터럽트 백터를 통해 알 수 있다. 이렇게 알게 된 시작 주소에 있는 프로그램을 실행하고 즉 인터럽트 서비스 루틴을 실행하고 원래 작업으로 되돌아온다

여기서 문제가 있다. CPU가 실행 중인 프로그램을 실행하다가 인터럽트가 발생하면 해당 인터럽트 서비스 루틴으로 점프해서 마저 실행하고 되돌아온다고 했는데 이 전 프로그램을 실행하는 과정에서 프로그램 카운터 등 레지스터 값들이 이미 CPU 안에 저장되어 있다. 그래서 지금까지 했던 작업을 백업을 한 후 인터럽트 서비스를 실행해야 한다. 이 때 스택 영역에 백업을 한다.