
APU와 제어장치
ALU
ALU는 계산하는 부품입니다. 1+2 라는 계산을 하기 위해선 1, 2 와 같은 피연산자와 + 라는 연산자가 필요합니다. ALU도 계산을 위해선 피연산자와 연산이 필요합니다.
ALU는 레지스터를 통해 피연산자를 받아들이고, 제어장치로 부터 수행할 연산을 알려주는 제어 신호를 받아들입니다. ALU는 레지스터와 제어장치로부터 받아들인 피연산자와 제어 신호로 산술 연산, 논리 연산 등 다양한 연산을 수행합니다.
ALU가 내보내는 정보는 메모리에 바로 저장되지 않고 일시적으로 레지스터에 저장됩니다. CPU가 메모리에 접근하는 속도는 레지스터에 접근하는 속도보다 훨씬 느립니다. 매번 메모리에 접근하게 되면 프로그램 속도가 느려지기 때문에 레지스터에 우선 저장하도록 동작합니다.
ALU는 계산 결과와 더불어 플래그를 내보냅니다. 대표적인 플래그는 다음과 같습니다.
플래그는 CPU가 프로그램을 실행하는 도중 반드시 기억해야 하는 일종의 참고 정보입니다. 그리고 플래그들은 플래그 레지스터에 저장됩니다.
제어장치
제어장치는 제어 신호를 내보내고, 명령어를 해석하는 부품입니다. 그리고 제어 신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호입니다. 제어장치는 제조사마다 구현 방식이나 명령어를 해석하는 방식이 다르기 때문에 여기서는 제어장치가 받아들이고 내보내는 대표적인 정보에만 초점을 맞춰서 정리해보겠습니다.
제어장치는 클럭 신호를 받아들입니다.
클럭이란 컴퓨터의 모든 부품을 움직이게 하는 시간 단위입니다. 컴퓨터 부품들은 클럭이라는 박자에 맞춰 동작하게 됩니다. 다만 한 클럭마다 동작하는것은 아니고 여러 클럭에 걸쳐서 실행되기도 합니다.
제어장치는 '해석해야 할 명령어'를 받아들입니다.
CPU가 해석해야 할 명령어는 명령어 레지스터라는 특별한 레지스터에 저장됩니다. 제어장치는 이 명령어 레지스터로부터 해석할 명령어를 받아들이고 해석한 뒤, 제어 신호를 발생시켜 컴퓨터 부품들에 수행해야 할 내용을 알려줍니다.
제어장치는 플래그 레지스터 속 플래그 값을 받아들입니다.
플래그는 ALU 연산에 대한 추가적인 상태 정보입니다. 제어장치는 플래그 값을 참고해서 제어 신호를 발생시킵니다.
제어장치는 시스템 버스, 그중에서 제어 버스로 전달된 제어 신호를 받아들입니다.
제어 신호는 CPU에서만 발생되는게 아닙니다. 제어장치는 외부 장치들에서 발생한 제어 신호를 받을 수 있습니다.
이제 제어장치가 내보내는 정보를 알아보겠습니다. 제어장치가 내보내는 정보는 크게 CPU 외부에 전달하는 제어 신호와 CPU 내부에 전달하는 제어 신호가 있습니다.
CPU 외부에 제어 신호를 전달하는 경우 제어 버스로 신호를 내보냅니다. 이러한 제어 신호에는 크게 메모리에 전달하는 제어 신호와 입출력장치에 전달하는 제어 신호가 있습니다.
제어장치가 메모리에 저장된 값을 읽거나 메모리에 새로운 값을 쓰고 싶다면 메모리로 제어 신호를 내보냅니다. 그리고 입출력장치에 새로운 값을 쓰고 싶을 때는 입출력장치로 제어 신호를 내보냅니다.
CPU 내부에 전달하는 제어 신호에는 크게 ALU에 전달하는 제어 신호와 레지스터에 전달하는 제어 신호가 있습니다. ALU에는 수행할 연산을 지시하기 위해, 레지스터에는 레지스터 간에 데이터를 이동시키거나 레지스터에 저장된 명령어를 해석하기 위해 제어 신호를 내보냅니다.
레지스터
프로그램 속 명령어와 데이터는 실행 전후로 반드시 레지스터에 저장됩니다. 따라서 레지스터에 저장된 값만 잘 관찰해도 프로그램의 실행 흐름을 파악할 수 있습니다.
CPU 안에는 다양한 레지스터들이 있고, 각기 다른 역할을 가지고 있습니다. 이번 절에서는 각 레지스터의 이름과 역할을 알아보겠습니다.
반드시 알아야 할 레지스터
제조사마다 레지스터의 종류가 다양합니다. 그래서 여러 레지스터들 중에서 중요하게 다루는 8개의 레지스터를 중심으로 정리해보겠습니다. 8개의 레지스터는 다음과 같습니다.
프로그램 카운터
프로그램 카운터는 메모리에서 가져올 명령어의 주소, 즉 메모리에서 읽어 들일 명령어의 주소를 저장합니다. 프로그램 카운터를 명령어 포인터라고 부르기도 합니다.
명령어 레지스터
명령어 레지스터는 해석할 명령어, 즉 방금 메모리에서 읽어 들인 명령어를 저장하는 레지스터입니다. 제어장치는 명령어 레지스터 속 명령어를 받아들이고 이를 해석한 뒤 제어 신호를 내보냅니다.
메모리 주소 레지스터
메모리 주소 레지스터는 메모리 주소를 저장하는 레지스터 입니다. CPU가 읽어 들이고자 하는 주소 값을 주소 버스로 보낼 때 메모리 주소 레지스터를 거치게 됩니다.
메모리 버퍼 레지스터
메모리 버퍼 레지스터는 메모리와 주고받을 값을 저장하는 레지스터입니다. 즉, 메모리에 쓰고 싶은 값이나 메모리로부터 전달받은 값은 메모리 버퍼 레지스터를 거칩니다. CPU가 주소 버스로 내보낼 값이 메모리 주소 레지스터를 거친다면, 데이터 버스로 주고 받을 값은 메모리 버퍼 레지스터를 거칩니다.
위의 레지스터가 동작하는 방식과 순서를 간단히 표현 해보면
프로그램 카운터 -> 메모리 주소 레지스터 -> 메모리 버퍼 레지스터 -> 명령어 레지스터
순서로 실행되며 그 이후 제어장치가 명령어 레지스터를 해석하고 제어 신호를 발생시킵니다. 하나의 사이클이 끝나면 프로그램 카운터가 증가하며 그 다음 사이클이 돌게 됩니다. CPU가 메모리 속 프로그램을 순차적으로 읽어 들이고 실행해 나갈 수 있는 이유는 CPU 속 프로그램 카운터가 꾸준히 증가하기 때문입니다.
범용 레지스터
범용 레지스터는 이름 그래도 다양하고 일반적인 상황에서 자유롭게 사용할 수 있는 레지스터 입니다. 메모리 버퍼 레지스터는 데이터 버스로 주고받을 값만 저장하고, 메모리 주소 레지스터는 주소 버스로 내보낼 주소값만 저장하지만, 범용 레지스터는 데이터와 주소를 모두 저장할 수 있습니다.
플래그 레지스터
플래그 레지스터는 ALU 연산 결과에 따른 플래그를 저장합니다. 또한 CPU 상태에 대한 부가적인 정보를 저장하는 레지스터입니다.
특정 레지스터를 이용한 주소 지정방식: 스택 주소 지정 방식
프로그램 카운터, 스택 포인터, 베이스 레지스터는 주소 지정에 사용될 수 있는 특별한 레지스터입니다. 스택 포인터는 스택 주소 지정 방식에 사용되고, 프로그램 카운터와 베이스 레지스터는 변위 주소 지정 방식에 사용됩니다.
스택 주소 지정 방식은 스택과 스택 포인터를 이용한 주소 지정 방식입니다. 스택은 가장 최근에 저장하는 값부터 꺼낼 수 있습니다. 여기서 스택 포인터란 스택의 꼭대기를 가리키는 레지스터 입니다. 즉, 스택 포인터는 스택에 마지막으로 저장한 값의 위치를 저장하는 레지스터입니다.
스택은 어디에 있는걸까요? 스택은 메모리 안에 있습니다. 정확히는 메모리 안에 스택처럼 사용할 영역이 정해져 있습니다. 이를 스택 영역이라고 합니다. 이 영역은 다른 주소 공간과는 다르게 스택처럼 사용하기로 암묵적으로 약속된 영역입니다.
특정 레지스터를 이용한 주소 지정 방식: 변위 주소 지정 방식
명령어는 연산 코드와 오퍼랜드로 이루어져 있다고 배웠습니다. 그리고 오퍼랜드 필드에는 메모리의 주소를 담을수도 있습니다. 변위 주소 지정 방식이란 오퍼랜드 필드의 값과 특정 레지스터의 값을 더하여 유효 주소를 얻어내는 주소 지정 방식입니다.
변위 주소 지정 방식을 사용하는 명령어는 연산 코드 필드, 어떤 레지스터의 값과 더할지를 나타내는 레지스터 필드, 그리고 주소를 담고 있는 오퍼랜드 필드가 있습니다. 이때, 변위 주소 지정 방식은 오퍼랜드 필드의 주소와 어떤 레지스터를 더하는지에 따라 상대 주소 지정 방식, 베이스 레지스터 주소 지정 방식 등으로 나뉩니다.
상대 주소 지정 방식
상대 주소 지정 방식은 오퍼랜드와 프로그램 카운터의 값을 더하여 유효 주소를 얻는 방식입니다.
프로그램 카운터에는 읽어 들일 명령어의 주소가 저장되어 있습니다. 만약 오퍼랜드가 음수, 가령 -3이었다면 CPU는 읽어 들이기로 한 명령어로부터 '세 번째 이전' 번지로 접근합니다. 한마디로 실행하려는 명령어의 세 칸 이전 번지 명령어를 실행하는 것입니다.
상대 주소 지정방식은 모든 코드를 실행하는 것이 아닌, 특정 주소의 코드를 실행할 때 사용됩니다.
베이스 레지스터 주소 지정 방식
베이스 레지스터 주소 지정 방식은 오퍼랜드와 베이스 레지스터의 값을 더하여 유효 주소를 얻는 방식입니다. 여기서 베이스 레지스터는 '기준 주소', 오퍼랜드는 '기준 주소로부터 떨어진 거리'로서의 역할을 합니다. 즉, 베이스 레지스터 주소 지정 방식은 베이스 레지스터 속 기준 주소로부터 얼마나 떨어져 있는 주소에 접근할 것인지를 연산하여 유효 주소를 얻어내는 방식입니다.
명령어 사이클과 인터럽트
CPU가 하나의 명령어를 처리하는 과정에는 정해진 흐름이 있습니다. 이를 명령어 사이클이라고 합니다. 정해진 흐름에 따라 명령어를 처리하던 도중 간혹 흐름이 끊어지는 상황이 발생하는데 이를 인터럽트라고 합니다. 이번 절에서는 명령어 사이클과 인터럽트에 대해 알아보겠습니다.
명령어 사이클
메모리에 저장된 명령어 하나를 실행한다고 가정해 봅시다. 우선 명령어를 처리하기 위해선 메모리에서 CPU로 명령어를 가져와야 합니다. 이게 명령어 사이클의 첫 과정이고 이를 인출 사이클이라고 합니다. 그 후 가져온 명령어를 실행하게 되는데 이를 실행 사이클이라고 합니다. 제어장치가 명령어 레지스터에 담긴 값을 해석하고, 제어 신호를 발생시키는 단계를 말합니다.
모든 명령어가 인출 사이클, 실행 사이클의 단계만 거치는건 아닙니다. 예를 들어 명령어가 간접 주소 지정 방식을 사용한다면, 명령어를 인출하여 CPU로 가져왔어도 바로 실행 사이클에 돌입할 수 없습니다. 명령어를 실행하기 위해선 실제 데이터가 있는 메모리에 한번 더 접근해야 하기 때문입니다. 이 단계를 간접 사이클이라고 합니다.
명령어 사이클은 이게 끝이 아닙니다. 아직 고려해야할 것이 남아 있는데, 바로 인터럽트 입니다.
인터럽트
인터럽트는 영어로 '방해하다, 중단시키다' 의 의미를 가집니다. 즉 CPU가 수행 중인 작업은 방해를 받아 잠시 중단될 수 있는데, 이렇게 CPU의 작업을 방해하는 신호를 인터럽트라고 합니다.
인터럽트는 CPU가 작업을 중단해야 할 정도의 중요한 작업이 생겼을 때 발생하는데, 구체적으로 어떤 상황에서 인터럽트가 발생하는지를 인터럽트의 종류를 통해 알아보겠습니다.
인터럽트는 크게 동기 인터럽트와 비동기 인터럽트가 있습니다.
동기 인터럽트는 CPU에 의해 발생하는 인터럽트입니다. CPU가 명령어를 수행하다가 예상치 못한 상황에 마주쳤을 때, 가령 프로그래밍상의 오류같은 상황에 발생하는게 동기 인터럽트 입니다. 이런 점에서 동기 인터럽트는 예외라고 부릅니다.
비동기 인터럽트는 주로 입출력장치에 의해 발생하는 인터럽트입니다. 예를 들자면 CPU가 프린터와 같은 입출력장치에 입출력을 부탁하면 작업을 끝낸 입출력장치가 CPU에 완료 알림(인터럽트)를 보냅니다. 비동기 인터럽트를 하드웨어 인터럽트라고도 부릅니다.
하드웨어 인터럽트
하드웨어 인터럽트는 알림과 같은 인터럽트 입니다. CPU는 입출력 작업 도중에도 효율적으로 명령어를 처리하기 위해 이런 알림과 같은 하드웨어 인터럽트를 사용합니다.
입출력장치는 CPU보다 속도가 현저히 느리기 때문에 CPU는 입출력장치에 명령을 맡기고 다른 작업을 처리하다가 완료 인터럽트를 받으면 그 때 처리하게 됩니다.
하드웨어 인터럽트 처리 순서
