8.1 중앙처리장치의 개요
- 컴퓨터에서 데이터 처리 동작을 수행하는 부분을 중앙 처리 장치라고 하며 줄여서 CPU라고 부른다.
- CPU는 위 사진과 같이 세 부분으로 구성되어 있는데, 레지스터 집합은 명령어를 실행하는데 필요한 중간 데이터를 보관하고, 산술 논리 장치(ALU)는 명령어를 실행하기 위한 마이크로 연산을 수행한다. 그리고 제어장치는 레지스터 사이의 정보 전송을 감시하거나 ALU에서 수행할 동작을 지시한다.
- CPU는 컴퓨터에서 정의된 명령어를 통해 다양한 일을 수행한다.
8.2 범용 레지스터 구조
- 포인터, 카운터, 리턴 주소, 일시적인 계산 결과를 저장하기 위해 곱셈에서 부분곱을 저장하기 위해서 기억 장소가 필요하다는 것을 알 수 있다. 이때 메모리를 호출하는 것은 시간이 많이 걸리게 된다. 왜냐하면 메모리 액세스는 마이크로 연산에서 대부분의 시간을 소요하게 되기 때문이다. 따라서 이들 중간값을 프로세서 레지스터에 저장하는 것이 편리하고 효율적이다. 많은 수의 레지스터가 처리 장치에 있다면 그것들을 버스를 통해 연결하고 매우 빠른 접근 시간을 지닌 로컬 메모리로 사용하는 것이 가장 효율적이다.
- 위 그림은 일곱 개의 CPU 레지스터를 가진 버스의 구조이다. 각 레지스터의 출력은 두 개의 멀티플렉서에 연결되어 입력 버스 A와 B를 구성한다. 각 멀티플렉서의 선택 라인은 7개 중 1개의 레지스터나 입력 데이터를 고르게 되고 A와 B의 버스는 ALU의 입력이 된다. 그리고 ALU에서 선택된 동작은 수행되어야 할 산술 또는 논리 마이크로 연산을 결정한다.
- 마이크로 연산의 결과는 출력 데이터로 쓰이기도 하며, 또한 목적지 버스를 통하여 레지스터의 입력으로도 사용된다. 목적지 레지스터는 디코더에 의해 선택되어 D버스로부터 정보를 받는다. 디코더는 레지스터의 로드를 가능하게 하여 D버스와 선택된 목적지간의 정보 전달로를 만들어주게 된다.
- CPU 버스 시스템을 동작하게 하는 제어 장치는 시스템 내의 여러가지 부분들을 선택함으로써 ALU를 통한 정보의 흐름을 지시하게 된다.
-
- 예제) R1 ← R2+R3
- MUX A selector : R2의 내용을 A버스에 놓는다.
- MUX B selector : R3의 내용을 B버스에 놓는다.
- ALU function selector : A+B를 위한 연산 동작을 하게 한다.
- Decoder destination selector : 출력 버스의 내용을 R1에 전달한다.
- 네 개의 제어 선택 변수가 동시에 얻어져야 하고 한 클럭 펄스 간격 동안 사용될 수 있어야 한다. 한 클럭 펄스 동안에 두 개의 소스 레지스터로부터의 정보가 멀티플렉서, ALU, 출력 버스를 거쳐 목적지 레지스터의 입력으로 전해진다. 그리고 다음 클럭 펄스에서 출력 버스의 정보가 R1으로 전달된다. 수행 속도를 빠르게 하기 위해 ALU는 고속의 회로로 구성된다.
제어 워드
- 위 그림에는 14개의 이진 선택 입력으로 이루어진 14비트 제어 워드가 정의되어 있다. 이는 네 개의 필드로 이루어져 있는데, 3비트인 SELA와 SELB는 각각 ALU의 A와 B 입력에 대한 근원지 레지스터를 선택하고, SELD도 3비트로 디코더와 로드 입력을 이용하여 목적지 레지스터를 선택한다. 그리고 5비트의 OPR은 ALU 동작을 선택한다. 따라서 14비트 제어 워드가 선택 입력에 적용되면 특정한 마이크로 연산이 수행된다.
레지스터 선택을 인코딩 하는 방법
- 첫 번째 열은 세 개의 필드에서 가질 수 있는 이진 코드 값을 나타내고, 다음의 세 열에는 각 이진수에 해당하는 번호의 레지스터가 선택됨을 보여주고 있다. 이 중에서 SELA나 SELB가 000일 때는 외부 입력 데이터를 선택하고, SELD=000일 때에는 목적지 레지스터가 선택되지 않으나 버스의 내용이 외부 출력에는 연결됨을 나타낸다.
ALU 연산의 인코딩
- 여기서 OPR은 다섯 비트를 가지고 있고 각 연산들은 기호로 표시된 이름으로 지정되어 있다.
마이크로 연산의 예
- CPU에서 사용되는 14비트의 제어 워드는 선택 변수로 디코딩되어 마이크로 연산을 지정한다.
- 예를 들어 다음의 뺄셈 마이크로 연산은 ALU의 A, B 입력에 R2와 R3를, 목적지 레지스터로는 R1을 지정하고 있으며, ALU 연산은 뺄셈 (A-B)임을 나타낸다.
- 인크리멘트나 전송 마이크로 명령어와 같이 ALU의 B입력을 사용하지 않는 경우에는 제어 워드에 해당 필드를 000으로 한다. 그리고 레지스터의 내용을 외부 단말기로 출력하는 경우에는 목적지 레지스터를 선택하지 않는다. 특히 입력에서 출력으로 데이터를 직접 전송하는 마이크로 명령어는 제어 워드의 모든 비트가 0으로 이루어져 있다. 마지막에 있는 레지스터 클리어 동작은 x+x=0이라는성질을 이용하여 ALU연산으로 XOR를 선택한다.
CPU를 위한 마이크로 연산의 예
- 많은 비트를 가진 제어 워드를 생성해내는 가장 효과적인 방법은 제어 워드를 메모리 장치에 저장하는 것이다. 이러한 메모리 장치를 앞장에서 살펴본 바와 같이 제어 메모리라고 하는데, 제어 메모리에 연속적으로 저장되어 있는 제어 워드를 읽어냄으로써 CPU가 원하는 마이크로 연산을 수행할 수 있었다.
8.3 스택 구조
- 대다수의 컴퓨터의 CPU가 가지고 있는 매우 활동도가 높은 기법으로 스택 또는 last-in, first-out(LIFO) 라는것이 있다. 이는 가장 나중에 메모리에 저장되는 내용이 가장 먼저 꺼내지도록 하는 저장 장치이다.
- 스택은 근본적으로는 단지 수를 세는 역할만 하는 주소 레지스터를 가진 메모리이다. 이러한 주소 레지스터를 스택 포인터(SP) 라고 하는데, 왜냐하면 이 것의 값은 항상 스택의 꼭대기주소를 가리키고 있기 때문이다. 스택에서는 읽고 쓰기만 할 수 있다. 즉, 이때 삽입되고 삭제되는 것은 메모리 워드의 내용이다.
- 스택에서의 두가지 동작은 넣고 빼내는 것이다. 메모리에 항목을 넣는것을 push라고 하고 빼내는 동작을 pop이라고 한다.
레지스터 스택
- 스택은 대규모 메모리의 일부분에 놓일 수도 있고, 제한된 수의 메모리 워드나 레지스터들로 구성될 수도 있다.
메모리 스택의 블럭도
- 위 그림은 64워드의 메모리 스택을 보여준다.
- 스택 포인터 레지스터 SP는 현재 스택의 top이 있는 워드의 주소이다. 세 개의 항목이 A, B, C 순서대로 놓여 있다. C가 스택의 top이라면 SP는 3의 값을 가지고 있다. top에 있는 항목을 꺼내려면(pop) 주소 3에 있는 값을 읽고 SP의 값을 하나 줄이면 된다. 이렇게 하면 B가 스택의 top이 되고 SP의 값은 2가 된다. 새로운 항목을 집어넣으려면 SP를 하나 증가시키고 그 주소에 새로운 항목을 write하면 된다. 이전의 C는 pop했을 때 지워지지 않았지만 문제가 되지 않는 것은 다시 새로운 항목이 push된다면 그 위치에 write되기 때문이다.
- 64개의 워드를 가진 메모리 스택에서의 스택 포인터는 6비트를 가져야 2^6 = 64 개의 주소를 다룰 수 있다. 1비트의 레지스터 FULL과 EMTY는 스택이 full로 되었거나 empty가 되었을 때 세트되게 된다. DR은 읽혀지거나 쓰여질 정보를 저장한다.
- 초기상태로 SP는 0이고 EMTY는 1이며 FULL은 0이다. 만약 스택이 full이 아니라면 (FULL = 0 이라면) , 새로운 항목이 push 동작에 의해 스택에 집어넣을 수 있다.
메모리 스택
- 스택은 독립적으로 존재할 수 있지만, CPU에 부착시킨 RAM 메모리를 이요하여 구현할 수있다. 즉, 메모리의 일부분을 스택 동작을 위해 할당하고 프로세서 레지스터 중에서 하나를 스택 포인터로 사용한다.
프로그램, 데이터, 스택 세그먼트를 가진 컴퓨터 메모리
- 위 사진의 메모리는 프로그램, 데이터, 스택 등 세 개의 세그먼트로 나뉘어 있다. 세 레지스터 PC, AR, SP는 각각의 세그먼트에서 다음 명령어의 주소, 참조할 데이터의 주소, 스택의 꼭대기를 가리킨다. 이들 레지스터는 모두 공통 주소 버스에 연결되어 있어서 접근할 메모리의 주소를 제공한다.
- 위 그림에서 SP이 초기값이 4001일 때 스택이 주소를 감소시키면서 커가는 모양을 보여주고 있다. 즉 첫번째 항목은 스택의 주소 4000에, 두번째 항목은 주소 3999에 저장되어 있는 상태이고, 스택의 마지막 주소는 3000임을 알 수 있다.
- 스택의 항목이 데이터 레지스터와 데이터를 주고 받는 다면, 스택에 새로운 항목을 삽입하는 push 동작은 위 사진의 왼쪽과 같이 나타낼 수 있다.
- 대부분의 컴퓨터는 스택의 오버블로와 언더플로를 검사하는 하드웨어를 갖추고 있지는 않지만, 스택의 상한과 하한을 저장하는 두 개의 레지스터를 이용하여 스택의 한계를 검사할 수 있다. 즉 push 동작 후에는 SP와 상한 레지스터를 비교하고, pop 동작 후에는 SP와 하한 레지스터를 비교하는 것이다.
역 Polish 표기
- 스택의 구조는 어떤 수식의 값을 구하는 데 있어 매우 효율적이다.
-
- A+B : infix 개념
- +AB : prefix 또는 polish 개념
- AB+ : postfix 도는 역 polish 개념
- 역 polish 개념은 스택으로 처리하기에 적합한 형태이다.
- 수식을 왼쪽에서 오른쪽으로 하나씩 읽어나가면서 그것이 연산자이면 왼쪾에 있는 두 개의 피연산자에 대하여 연산을 한다. 그러고나서 두 개의 피연산자와 연산자를 제거하고 그 위치에 연산의 결과를 놓는다. 이러한 과정을 더이상의 연산자가 없을 때까지 모든 연산자에 대해 수행한다.
AB * CD * + 예시
위의 수식에서 A와 B다음에 연산자 *가 있다. A * B의 계산을 하고, 그 결과를 A, B, * 자리에 놓는다.
- (A * B)CD * +
단, 이때 (A * B)는 곱셈으로부터 얻어진 하나의 값이다. 그 다음의 연산자는 *이고 그 앞의 피연산자는 C와 D이므로, C * D계싼을 수행하여 두 개의 피연산자와 하나의 연산자를 가진
- (A * B)(C * D)+
와 같은 형태가 된다.
마지막으로 (A * B)와 (C * D)를 더해 마지막 결과를 얻게 된다.
infix로 표현된 수식을 역 polish 형태로 고치자면 infix 개념에서의 연산 순위를 고려해야 한다. 이 순위는 괄호 안의 연산을 과로 밖보다 먼저하고, 덧셈이나 뺄셈보다 곱셈이나 나눗셈을 먼저 해야 함을 의미한다.
(A + B) * [C * (D + E) + F]
수식의 값을 구하려면 괄호 안에 있는 D+E와 A+B의 계산을 제일 먼저 해야 한다. 그 다음에 중괄호 속의 값을 구한다.
C * (D+E)의 곱셈은 F와의 덧셈보다 연산 순위가 높기 때문에 먼저 행해져야 한다. 마지막은 계산의 괄호속의 값과 중괄호 속의 값을 곱하는 것이다. 이 수식은 연산 순위를 고려해 넣음으로써 괄호의 사용없이 역 polish 형태로 바꿀 수가 있다.
AB + DE + C * F + *
산술식의 계산
- 스택은 연속 계산을 포함하는 길고 복잡한 문제를 취급하는 데 특히 유용하다.
- 이 방법은 우선 어떤 수식을 역 polish의 형태로 바꾸어야 한다. 피연산자는 그들이 나타나는 순서대로 스택에 push된다. 연산자가 나타나면 다음과 같은 마이크로 연산을 한다.
-
- 스택의 top에 있는 두 개의 값이 연산에 사용된다.
- 스택의 값이 pop되고 연산의 결과가 top의 아래에 있는 피연산자의 자리를 차지한다.
8.4 명령어 형식
- 컴퓨터는 흔히 다양한 명령어 코드 형식을 가지고 있다. 각 명령어 코드가 명령어를 수행할 수 있게 필요한 제어 함수를 제공해주는 것이 CPU에 있는 제어 장치의 역할이다.
- 명령어 코드의 비트는 필드라고 불리는 몇 개의 그룹으로 나뉜다. 가장 흔한 필드는 다음과 같다.
-
- 수행해야 할 연산을 명시한 연산 코드 필드
- 메모리의 주소나 레지스터를 지정하는 주소 필드
- 피연산자나 유효 주소가 결정되는 방법을 나타내는 모드 필드
-
- 다른 특별한 필드가 가끔씩 특수한 상황하에서 사용될 수가 있다. ( 시프트의 명령에서 몇 비트나 시프트할 것인가 하는 것을 나타내는 경우)
- 연산 코드 필드(operation code field)는 프로세서가 덧셈, 뺄셈이나 보수를 취하거나 시프트 한다든가 하는 연산을 결정하는 비트의 모임이지만 가장 일반적으로 컴퓨터에서 쓰이는 명령어는 8-6에서 설명한다.
- 모드 필드를 구성하는 비트들은 주어진 주소로부터 피연산자를 선택하는 여러 가지 방법 중 하나를 선택한다.
- 어드레싱 모드 : 메모리 주소 또는 프로세서 레지스터를 지정한다.
- 명령어의 형식에서 주소 필드의 숫자는 컴퓨터 내부의 레지스터의 구성에 의해 좌우된다. 대부분 컴퓨터는 다음의 세 가지 형식 중 하나의 CPU 구조를 가지고 있다.
-
- 단일 누산기 구조 : 기본 컴퓨터와 같은 것이며, 모든 명령어의 수행은 내장되어 있는 누산기 레지스터에서 이루어진다.
- 범용 레지스터 구조 : 세 개의 레지스터 주소 필드를 필요로 한다. 어셈 블리 언어로 쓰면 다음과 같다. ADD, R1, R2, R3 - 이는 R1 ← R2+R3의 동작을 한다. 만약 목적지 레지스터가 소스 레지스터 중의 하나와 같은 것으로 하면 주소 필드 하나를 줄일 수 있다. 즉 ADD, R1, R2 = R1 ← R1+R2
- 스택 구조
- 범용 레지스터형의 컴퓨터는 명령어 형식에 두 개나 세개의 주소필드를 사용한다. 각 주소필드는 레지스터를 지정할 수도 ,메모리에서의 주소를 지정할 수도 있다.
- 스택 구조로된 CPU는 주소필드가 필요한 push와 pop의 명령어가 있어야한다.
-
- PUSH X
- X의 주소에 있는 값을 스택의 top의 push하라는 것이다. 그러나 여기에서는 연산에 관계된 명령어는 주소 필득 ㅏ필요없다. 왜냐하면 스택의 top에 있는 두 개의 값들이 연산에 사용되기 때문이다.
- 대부분의 컴퓨터가 위의 세가지 형식 중 하나이다. 몇몇 컴퓨터는 여러 가지 형태를 섞어 사용하기도 한다. 예를 들어 인텔 8080은 일곱 개의 레지스터를 가지고 있고, 그 중의 하나가 누산기 이다. 따라서 이 프로세서는 범용 레지스터 형식과 누산기 형식의 두가지 특성을 겸해서 가지고 있다. 산술 연산과 논리 연산, 또 store나 load 등의 명령어는 누산기 레지스터를 사용하므로 단 하나의 필드가 필요하다. 그러나 일곱 개의 레지스터 사이의 정보 전송 명령어는 두 개의 레지스터 주소 필드를 가지게 된다.
3-주소의 명령어
- 각 주소 필드가 레지스터를 지정할 수도 있고 메모리의 주소를 지정할 수도 있다.
- 어셈블리로 X=(A + B) * (C + D)를 계산하는 프로그램이 다음과 같다.
- 3주소 명령어 혀식의 장점은 수식 계산을 할 때 프로그램의 길이를 짧게 할 수 있다는 것이다.
- 단점은 이진 코드로 명령어를 나타낼 때 너무 많은 비트가 필요하다는 사실이다.
2-주소의 명령어
-
실제 사용되는 컴퓨터에서 가장 흔히 사용되는 것이 2-주소 필드 방식이다.
-
MOV 명령어는 피연산자를 메모리로부터 레지스터로 가져오거나, 레지스터에서 메모리로 전송하는 역할을 한다.
1-주소의 명령어
- 여기에서는 모든 데이터의 처리가 내장되어 있는 누산기(AC)에 의해 이루어진다. 곱셈이나 나눗셈에서는 또 다른 레지스터가 필요하다. 그러나 여기에서는 또 다른 레지스터를 무시하고, AC가 모든 동작의 결과를 갖는다고 하자.
- AC 레지스터와 메모리의 피연산자 사이에서 모든 동작이 이루어진다. T는 중간값을 일시적으로 저장하기 위한 메모리의 주소이다.
무주소 명령어
- 스택 구조의 컴퓨터는 ADD나 MUL 등의 명령어에서 주소 필드를 사용하지 않는다. 그러나 PUSH와 POP의 명령에서 스택과 피연산자 사이의 정보 전달을 위해 하나의 주소 필드가 필요하다.
- 스택을 사용한 컴퓨터에서 수식을 계산하기 위해서는 우선 수식을 역 polish 형태로 바꾸어야 한다. 무주소 라는 이름은 연산 명령어에서 주소 필드가 없기 때문에 붙여진 것
RISC 명령
- 전형적인 RISC 프로세서의 명령어 집합은 메모리와 CPU 사이의 통신을할 때 load와 store명령어만 사용하도록 제한된다. 그리고 다른 모든 명령어들은 메모리 참조 없이 CPU의 레지스터 안에서 실행된다. 따라서 RISC CPU를 위한 프로그램은 하나의 메모리와 레지스터를 지정하는 주소를 가진 LOAD 및 STORE 명령어와 세 개의 프로세서 레지스터를 지정하는 계산형 명령어로 구성된다.
- 다음은 X = (A + B) * (C + D)의 예제이다.
-
- LOAD R1, A —– R1 ← M[A]
- LOAD R2, B —– R2 ← M[B]
- LOAD R3, C —– R3 ← M[C]
- LOAD R4, D —- R4←M[d]
- ADD R1, R1, R2 —- R1 ← R1 + R2
- ADD R3, R3, R4 —- R3 ← R3+R4
- MUL R1, R1, R3 —- R1 ← R1 * R3
- STORE X, R1 —- M[X] ← R1
- 이 프로그램은 load 명령어를 이용하여 메모리부터 피연산자 CPU 레지스터로 읽어오고, 다음에는 메모리에 대한 접근 없이 레지스터의 데이터에 대해 덧셈과 곱셈 연산을 수행한 후, 계산 결과를 store 명령어로 메모리에 저장하는 절차를 나타내고 있다.