본문 바로가기
Computer Science/컴퓨터구조(Computer Architecture)

명령어 사이클과 인터럽트

by 컴돈AI 2024. 3. 28.

목차

    명령어 사이클과 인터럽트

    • 명령어 사이클
      • CPU가 하나의 명령어를 처리하는 과정에는 어떤 정해진 흐름이 있고, CPU는 그 흐름을 반복하며 명령어들을 처리해 나감.이렇게 하나의 명령어를 처리하는 정형화된 흐름을 명령어 사이클이라고 함.
    • 인터럽트
      • CPU는 정해진 흐름에 따라 명령어를 처리해 나가지만, 간혹 이 흐름이 끊어지는 상황이 발생하는데 이러한 상황을 인터럽트라고 함.

    명령어 사이클

    • 우리가 실행하는 프로그램은 수많은 명령어로 이루어져 있고, CPU는 이 명령어들을 하나씩 실행함.
      • 이때 프로그램 속 각각의 명령어들은 일정한 주기가 반복되며 실행되는데, 이 주기를 명령어 사이클이라고 함.
      • 즉, 프로그램 속 각각의 명령어들은 명령어 사이클이 반복되며 실행됨.
    • 명령어 사이클 예시
      • 인출 사이클 -> 실행 사이클
        • 인출 사이클 : 메모리에 있는 명령어를 CPU로 가지고 오는 단계
        • 실행 사이클 : CPU로 가져온 명령어를 실행하는 단계
      • 인출 사이클 -> 간접 사이클 -> 실행 사이클
        • 간접 주소 지정 방식처럼 오퍼랜드 필드에 유효 주소의 주소를 명시할 경우, 명령어를 인출하여 CPU로 가져왔다 하더라도 바로 실행 사이클에 돌입할 수는 없음. 
        • 명령어를 실행하기 위해서는 메모리 접근을 한 번 더 해야하는데 이 단계를 간접 사이클이라고 함.

    인터럽트

    • CPU가 수행 중인 작업을 방해하는 신호를 인터럽트라고 함
    • 인터럽트 종류
      • 동기 인터럽트(synchronous interrupts) (= 예외)
        • 동기 인터럽트는 CPU에 의해 발생하는 인터럽트
        • CPU가 명령어들을 수행하다가 예상치 못한 상황에 마주쳤을 때(가령 CPU가 실행하는 프로그래밍상의 오류와 같은 예외적인 상황에 마주쳤을때) 발생하는 인터럽트가 동기 인터럽트
        • 이런 점에서 동기 인터럽트는 예외(exception)라고 부름
        • 예외의 종류
          • 폴트(fault)
            • 예외를 처리한 직후 예외가 발생한 명령어부터 실행을 재개하는 예외
            • 예를 들어 CPU가 한 명령어를 실행하려 하는데, 이 명령어를 실행하기 위해 꼭 필요한 데이터가 메모리가 아닌 보조기억장치에 있다고 가정할 경우, 프로그램이 실행되려면 반드시 메모리에 저자오디어 있어야 하기에 CPU는 폴트를 발생시키고 보조기억장치로부터 필요한 데이터를 메모리로 가져와 저장함. 보조기억장치로부터 필요한 데이터를 메모리로 가지고 왔으면 CPU는 다시 실행을 재개함. (폴트가 발생한 그 명령어부터 실행함.)
          • 트랩(trap)
            • 트랩은 예외를 처리한 직후 예외가 발생한 명령어의 다음 명령어부터 실행을 재개하는 예외 
            • 주로 디버깅할 때 사용
            • 예를 들어 디버깅 할때 특정 코드가 실행되는 순간 프로그램의 실행을 멈추게 할 수 있음.
            • 쉽게 말해 CPU에 이 코드가 실행된 그 순간의 프로그램 상태를 보고 싶어. 그러니까 이 코드가 실행되는 순간 잠깐 실행을 멈춰! 라고 명령하는 것
            • 디버깅이 끝나면 프로그램은 다음 명령어부터 실행을 이어 나가면 됨.
          • 중단(abort)
            • CPU가 실행 중인 프로그램을 강제로 중단시킬 수 밖에 없는 심각한 오류를 발견했을때 발생하는 예외
          • 소프트웨어 인터럽트
            • 시스템 호출이 발생했을때 나타나는 예외
      • 비동기 인터럽트(asynchronous interrupts) (=하드웨어 인터럽트)
        • 비동기 인터럽트는 주로 입출력장치에 의해 발생하는 인터럽트
        • 비동기 인터럽트 예시
          • CPU가 프린터와 같은 입출력장치에 입출력 작업을 부탁하면 작업을 끝낸 입출력장치가 CPU에 완료 알림(인터럽트)을 보냄
          • 키보드, 마우스와 같은 입출력장치가 어떠한 입력을 받아들였을 때 이를 처리하기 위해 CPU에 입력 알림(인터럽트)을 보냄
        • 일반적으로 비동기 인터럽트를 인터럽트라고 이야기 함. (혼동을 방지하기 위해 하드웨어 인터럽트라고함)
    • 하드웨어 인터럽트 처리 순서(CPU가 인터럽트를 처리하는 방식)
      • 입출력장치가 CPU에 인터럽트 요청 신호를 보냄
        • 인터럽트는 CPU의 정상적인 실행 흐름을 끊는 것이기에 다른 누군가가 인터럽트하기 전에는 "지금 끼어들어도 되나요? 하고 CPU에 물어봐야함. 이를 인터럽트 요청 신호라고 함
      • CPU는 실행 사이클이 끝나고 명령어를 인출하기 전 항상 인터럽트 여부를 확인함
      • CPU는 인터럽트 요청을 확인하고 인터럽트 플래그를 통해 현재 인터럽트를 받아들일 수 있는지 여부 확인
        • CPU가 인터럽트 요청을 수용하기 위해서는 플래그 레지스터의 인터럽트 플래그가 활성화되어 있어야 함.
        • 인터럽트 플래그는 말 그대로 하드웨어 인터럽트를 받아들일지, 무시할지를 결정하는 플래그
        • CPU가 중요한 작업을 처리해야 하거나 어떤 방해도 받지 않아야 할 때 인터럽트 플래그는 "불가능"으로 설정됨.
          • 만약 인터럽트 플래그가 "불가능"으로 설정되어 있다면 CPU는 인터럽트 요청이 오더라도 해당 요청을 무시함. 
          • 하지만 "불가능" 이더라도 모든 하드웨어 인터럽트를 막을 수 있는 것은 아님. 무시할수 없는 인터럽트 요청도 있음. 가장 우선순위가 높은, 정전이나 하드웨어 고장으로 인터럽트는 불가능이더라도 인터럽트 처리를 해야함.
        • 인터럽트 플래그가 "가능"으로 설정되어 있다면 CPU는 인터럽트 요청 신호를 받아들이고 인터럽트를 처리함.
      • 인터럽트를 받아들일 수 있다면 CPU는 지금까지의 작업을 백업
      • CPU는 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴을 실행함
        • CPU가 인터럽트 요청을 받아들이기로 했다면 CPU는 인터럽트 서비스 루틴 (ISR : Interrupt Service Routine)이라는 프로그램을 실행함.
          • 인터럽트 서비스 루틴은 인터럽트를 처리하기 위한 프로그램. 
          • 인터럽트 핸들러(interrupt handler)라고도 부름
        • 인터럽트 서비스 루틴은 "키보드가 어떤 인터럽트 요청을 보냈을 때는 어떻게 작동한다.", "마우스가 어떤 인터럽트 요청을 보냈을 때는 어떻게 작동한다.", "프로그램에 어떤 문제가 생겼을 때는 어떻게 작동한다."와 같이 어떤 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하고 작동해야할지에 대한 정보로 이루어진 프로그램.
        • "CPU가 인터럽트를 처리한다" 라는 말은 "인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다"라는 말과 같음.
        • 메모리에는 여러 개의 인터럽트 서비스 루틴이 저장되어 있음.(인터럽트 서비스 루틴 하나하나가 인터럽트가 발생하면 어떻게 행동해야 할지를 알려주는 프로그램임)
        • CPU는 이런 각기 다른 인터럽트 서비스 루틴을 구분하기 위해 인터럽트 벡터를 사용함
          • 인터럽트 벡터는 인터럽트 서비스 루틴을 식별하기 위한 정보
          • 인터럽트 벡터를 알면 인터럽트 서비스 루틴의 시작 주소를 알 수 있기 때문에 CPU는 인터럽트 벡터를 통해 특정 인터럽트 서비스 루틴을 처음부터 실행할 수 있음.
          • CPU는 하드웨어 인터럽트 요청을 보낸 대상으로부터 데이터버스를 통해 인터럽트 벡터를 전달받음.
        • 인터럽트 서비스 루틴은 여느 프로그램과 마찬가지로 명령어와 데이터로 이루어져 있음. 따라서 인터럽트 서비스 루틴도 프로그램 카운터를 비롯한 레지스터들을 사용하며 실행됨.
        • 그럼 인터럽트가 발생하기 전까지의 레지스터에 저장된 값들은 어떻게 할까?
          • 인터럽트 요청을 받기 전까지 CPU가 수행하고 있었던 일은 인터럽트 서비스 루틴이 끝나면 되돌아와서 마저 수행을 해야 하기 때문에 지금까지의 작업 내역들은 어딘가에 백업을 해둬야함. 
          • 그렇기에 CPU는 인터럽트 서비스 루틴을 실행하기 전에 프로그램 카운터 값 등 현재 프로그램을 재개하기 위해 필요한 모든 내용을 스택에 백업함. 
          • 그러고 나서 인터럽트 서비스 루틴의 시작 주소가 위치한 곳으로 프로그램 카운터가 값을 갱신하고 인터럽트 서비스 루틴을 실행함.
          • 인터럽트 서비스 루틴을 모두 실행하면, 다시 말해 인터럽트를 처리하고 나면 스택에 저장해 둔 값을 다시 불러온 뒤 이전까지 수행하던 작업을 재개
      • 인터럽트 서비스 루틴 실행이 끝나면 백업해둔 작업을 복구하여 실행을 재개
    • 결국 명령어 사이클은 인출 사이클, 실행 사이클, 간접 사이클, 인터럽트 사이클 과정을 반복해나가며 프로그램을 실행함.