RISC의 기본 설계 개념 주에서 가장 중요한 사항은 명령어들이 한 클럭 사이클(clock cycle)에 한 개씩 실행되도록 하는 것이다. 그러나 명령어 실행은 오퍼랜드 인출, 연산, 및 결과의 저장을 모두 포함하기 때문에 사실상 한 클럭 사이클내에 실행한다는 것은 불가능하다. 따라서 이것이 가능하도록 하기 위하여 명령어 실행 과정을 파이프라이닝(pipelining)하고, 특정 명령어들 외에는 실행 과정에서 주기억장치를 액세스하지 않도록 하며, 필요한 데이터를 가능한한 프로세서 내부에서 액세스할수 있도록 레지스터의 수를 증가시키는 것과 같은 특별한 고려가 필요하다. RISC 설계에서 공통적으로 사용되고 있는 이와 같은 몇 가지 기본 원리들을 좀더 자세히 살펴보면 다음과 같다.
1) 복잡한 명령어의 제거
한 사이클 내에 명령어가 실행되도록 하기 위하여 실행 과정을 파이프라이닝 하였을 때, 파이프라인의 어느 한 단계가 특별히 긴 시간이 걸린다면 전체 클럭 사이클의 주기가 길어질 수 밖에 없을 것이다. 이러한 문제를 피하기 위하여 복잡하고 긴 시간이 걸리는 연산을 포함하는 명령어는 제거하였다. 예를 들면, 대부분의 RISC 프로세서들의 명령어 세트에는 곱셈 명령어와 나눈셈 명령어가 없다. 이들은 쉬프트(shift)와 덧셈 또는 뺄셈 명령어들을 반복 사용함으로써 대체될 수 있다. 또한 부동-소수점 연산으 산술 보조프로세서(arthmetic coprocessor)를 이용하여 처리할 수 있다.
2) 주기억장치 액세스 명령어의 제한
명령어 실행의 속도를 높이기 위하여 파이프라인 구조가 사용되었더라도 연산을 위한 데이터가 필요한 시점에서 사용 가능하지 않다면, 파이프라인의 효율이 급격히 떨어질 것이다. 그러나 기억장치를 액세스하는 동작은 다른 동작들에 비하여 시간이 오래 걸리기 때문에, 명령어 실행 도중에 데이터를 기억장치로부터 액세스하게 되면 파이프라인 동작의 흐름이 깨어질 것이다. 이러한 문제를 방지하기 위하여 RISC 프로세서에서는 데이터에 대한 연산을 수행하는 명령어의 실행에 필요한 데이터는 항상 (외부 기억장치가 아닌) 내부 레지스터에 저장되어 있도록 하고 있다. 즉, 이러한 명령어들에게는 기억 장치 액세스를 허용하지 않는 것이다.
그렇게 되는 경우에는 데이터에 대한 연산을 수행하는 명령어들은 레지스터 주소지정 방식(register addressing mode)만을 가지면 되며, CISC 프로세서의 명령어에서와 같은 여러 가지 복잡한 주소지정 방식들은 사용할 필요가 없어진다. 이에 따른 이점들은 다음과 같다.
명령어 코드가 기억장치 주소 비트들은 포함하지 않고 레지스터 번호를 나타내는 적은 수의 비트들만 가지면 되므로, 명려어 코드의 비트 수가 줄어든다. 예를 들어, 레지스터의 수가 32개라면 주소필드는 5비트이면 된다.
유효 주소(effective address)를 계산하는 데 걸리는 시간이 절약된다.
연산에 필요한 데이터가 항상 레지스터 내에 있도록 하기 위해서는 데이터가 사용되기 이전에 미리 다른 명령어에 의하여 기억장치로부터 인출되어 있어야 한다. 또한 연산이 완료된 후에 결과값도 일단 레지스터에 저장되며, 기억장치에 저장되어야 하는 시점에서 다른 명령어에 의하여 저장된다. RISC 프로세서에서는 이와 같은 기억장치 액세스 동작은 LOAD와 STORE 명령어에 의해서만 이루어지도록 하고 있다. 또한 이 명령어들은 사용되는 주소지정 방식도 간단한 것들만 사용된다.
일반적인 RISC 프로세서에서 정의된 LOAD 및 STORE 명령어의 종류를 보면 표 6과 같다. 여기서 LOAD 명령어가 부호화 여부(signed 또는 unsigned)에 따라 두 가지로 구분되어 있는 이유는 다음과 같다: 기억장치로부터 읽어오는 데이터가 프로세서의 한 단어(word) 길이인 32비트보다 짧은 byte 또는 halfword라면, 32비트 레지스터로 적재될 때 부호(+,-)를 가진 수의 경우에는 상위 비트들이 모두 부호 비트(sign bit)와 같은 값을 가지도록 한다. 즉, 부호 비트가 확장된다. 부호가 없는 수(unsigned byte 또는 halfword)의 경우에는 부호 비트의 확장이 필요하지 않다. STORE 명령어의 경우에는 명령어 실행 과정에서 부호 비트 확장 동작이 필요하지 않으므로, 명령어도 구분될 필요가 없다.
[표 6] LOAD 및 STORE 명령어의 종류 | |
LOAD 명령어 |
STORE 명령어 |
LOAD signed byte LOAD unsigned byte |
STORE byte |
LOAD signed halfword LOAD unsigned halfword |
STORE halfword |
LOAD word |
STORE word |
이와 같이 기억장치 액세스는 LOAD 및 STORE 명령어만에 의하여 이루어지기 때문에, 다른 명령어들은 기억장치 주소를 포함할 필요가 없다. 예를 들어, ADD, MOVE, AND와 같은 명령어들에는 레지스터 번호를 나타내는 적은 수의 비트들만 포함되어 있다.
3) 주소지정 방식의 단순화
명령어의 종류가 많아지면 연산 코드를 해독하는 회로가 복잡해지는 것과 마찬가지로, 주소지정 방식(addressign mode)의 종류가 많으면 유효 주소(effective address)를 계산하는 시간이 그만큼 더 걸리게 되고 회로도 복잡해진다. 이를 방지하기 위해서는 주소지정 방식의 종류도 최소화시킬 필요가 있다. 실제로 RISC 프로세서들은 매우 적은 수의 간단한 주소지정 방식들만 사용하고 있는데, 그 설명을 위한 예로서 다음과 같은 RISC I의 명령어 형식을 분석해 보자.
7 |
1 |
5 |
5 |
1 |
13 |
OP code |
C |
DEST |
SRC |
I |
OFFSET |
이 형식에서 위의 숫자들은 각 필드의 비트 수를 나타내며, OP code 필드는 명령어의 연산코드이고, C 비트는 이 명령어의 실행 결과에 조건 코드(condition code)를 세트 할 것인지의 여부를 나타낸다. 즉, C=1이면, 연산 결과에 따라 조건 코드를 세트하라는 의미이고, C=0이면 명령어 실행 결과가 조건 코드에 영향을 주지 않는다는 것이다. DEST 필드는 이 연산의 결과가 저장될 목적지 레지스터(destination register)를 지정하고, SRC 필드는 연산에 사용될 데이터의 근원지 레지스터(source register)를 지정한다. 이 필드들은 각각 5비트씩이므로, 32개의 레지스터들이 지정될 수 있다.
I 비트는 OFFSET 필드의 내용을 지정해준다. 즉, I=1이면 OFFSET 필드의 내용이 연산에 사용될 실제 데이터라는 것을 가리키고, I=0이면 OFFSET 필드의 하위 5비트가 연산의 두 번째 오퍼랜드를 가지고 있는 레지스터의 번호라는 것을 의미한다. 이에 따라 주소지정 방식은 다음과 같은 종류로 구분될 수 있다.
I=1의 경우: 즉치 주소지정방식(immediate addressing mode)
R(DEST) = R(SRC) op OFFSET
I=0의 경우: 레지스터 주소지정방식(register addressing mode)
R(DEST) = R(SRC) op R(lower 5 bit of OFFSET)
단, R(n)은 n값이 지정하는 번호의 레지스터를 나타내고, op는 OP code에 의하여 지정되는 연산(ADD, SUB, AND 등)을 의미한다. I=1일 때, OFFSET 필드가 13비트이므로 데이터가 2의 보수로 표현되는 경우에 -212 과 (212-1) 사이의 정수값을 가질 수 있다.
여기서 흥미로운 것은 레지스터 0의 내용을 하드웨어적으로 0값에 고정시키는 것이다. 따라서, 연산 오퍼랜드의 근원지가 레지스터 0인 경우에는 읽혀오는 값이 항상 0이 된다. 이것을 이용한 연산의 몇 가지 예를 보면 다음과 같다.
I = 1, SRC = 0, op = ADD : R(DEST)OFFSET
I = 0, SRC = 0, op = AND : R(DEST)0
I = 0, OFFSET = 0, op = ADD : R(DEST)R(SRC)
일반적인 명령어들에세는 위에서 설명한 두 가지 주소지정 방식들만 사용되며, 주기억장치를 액세스하는 LOAD 와 STORE 명령어에서는 이들과는 다른 주소지정 방식들이 사용된다. 먼저 LOAD 와 STORE 명령어에서 유효 주소 effective address : EA)가 계산되는 방법을 보면 다음과 같다.
EA = (RSRC) + OFFSET
여기서 만약 OFFSET = 0 이라면 EA = (RSRC)가 되어 레지스터 간접 주소지정(register indirect addressing) 방식이 되며, OFFSET 0 이면 인덱스 주소지정(index addressing)방식이 된다. 또한 만약 RSRC = R0 라면, EA = OFFSET이 되므로 직접 주소지정(direct addressing) 방식이 된다. 그런데 OFFSET 필드는 13비트이므로, 이 방식을 사용하는 명령어는 전체 주소 공간의 최하위 213 = 8192개의 기억 장소들만 주소 지정할 수 있다.
그 외에도 RISC II에서는 조건분기 명령어를 위하여 PC-relative 주소지정 방식이 추가되어 있다. 이 방식에서는 RISC I의 명령어 형식에서 DEST 필드의 비트들이 분기의 조건을 지정하는데 사용되고, SRC 필드를 포함한 하위 19비트들이 부호를 가진 변위(signed offset) 값으로 사용되어 PC 값에 더해져서 분기의 목적지 주소가 된다.
대부분의 RISC 프로세서들은 지금까지 살펴본 몇 가지 주소지정 방식들만 사용하기 때문에 명령어 형식이 고정되고, 명령어의 비트 수가 줄어들며, 유효 주소를 결정하는데 있어서 복잡한 계산이 필요하지 않도록 하고 있다.
4) 파이프 라이닝
RISC 프로세서에서 명령어들이 비록 간략화 되기는 하였으나, 사실상 명령어를 한 클럭 사이클 내에 실행하는 것은 불가능하다. 그러나 n 사이클 이내에 n 개의 명령어 실행을 완료할 수만 있다면, 평균적으로 한 사이클 당 한 개의 명령어를 실행한다고 말할 수 있을 것이다. 이를 위하여 모든 RISC들은 명령어 실행 과정을 파이프라이닝(pipelining)하고 있는데, 일반적으로 다음과 같은 파이프라인 단계(pipeling stages)들로 나누어진다: 명령어 인출 단계, 명령어 해독 단계, 실행 단계 및 기억장치 액세스 단계. 이들 중에서 명령어 인출 단계는 명령어 캐쉬가 적중(hit)된 경우에 한 사이클 내에 완료될 수 있고, 명령어의 해독과 실행도 각각 한 사이클 내에 처리될 수 있다. 그러나 기억장치를 액세스하는 LOAD와 STORE 명령어에 있어서는 실행 단계(execution stage)가 적어도 두 사이클은 소요된다. 그에 따른 문제점을 분석하기 위하여 다음과 같은 어셈블리 프로그램을 고려해보자.
LOAD R0, X ; 기억장치 X번지의 내용을 레지스터 R0로 적재하라.
ADD R1, R0 ; 레지스터 R0와 R1의 내용을 더하고, 결과를 R1에 저장하라.
이 프로그램의 처리 과정에서 두 명령어들이 순서대로 파이프라인을 통과하기 때문에 LOAD 명령어가 실행된 지 한 사이클 후에는 ADD 명령어의 실행이 시작될 것이다. 그러나 LOAD 명령어는 아직 실행이 완료되지 않았으므로 레지스터 R0에는 X의 내용이 적재되지 않았다. 따라서 ADD 명령어는 X번지의 내용이 아닌 원래 R0의 내용을 R1에 더하게 될 것이므로 잘못된 계산 결과를 산출하게 된다. 이를 방지하기 위하여 RISC 프로세서에서느 다음과 같은 두 가지 방법들이 사용된다.
하드웨어 인터라킹(H/W interlocking): LOAD/STORE 명령어가 실행된 후에 해당 레지스터에 데이터가 적재될 때까지 자동적으로 NO-OP 명령어 코드에 해당하는 지연 슬롯(delay slot)을 삽입하는 방법이다. 프로세서 속도와 기억장치 속도의 차이가 큰 경우에는 여러 개의 지연 슬롯들이 삽입될 수도 있다. 이 방법은 하드웨어로 구현된다.
프로그램 실행 순서의 재조정: 컴파일러가 어셈블리 프로그램 코드들을 조사하여 LOAD/STORE 명령어의 실행 완료 여부와 무관하게 실행될 수 있는 명령어를 LOAD/STORE 명령어의 다음에 위치시키는 방법이다. 만약 그러한 명령어를 찾지 못했을 때는 NO-OP 명령어 코드를 삽입한다.
이와 같은 파이프란인의 실제 처리 과정을 설명하기 위하여 [그림 1]과 같은 3단계 파이프라인을 고려해보자. [그림 1]에서는 10개의 명령어들이 순서대로 처리되고 있는데, 유의할 부분은 세 번째와 일곱 번째에 각각 위치하고 있는 LOAD와 STORE 명령어의 실행이다. 먼저 첫 번째 사이클에서 명령어 1이 인출된다. 두 번째 사이클에서는 명령어 2가 인출된다. 동시에 명령어 1은 실행된다. 세 번째 사이클에서는 명령어 3(LOAD임을 나타내기 위하여 L로 표시)이 인출되고, 동시에 명령어 2가 실행된다. 네 번째 사이클에서 LOAD 명령어의 실행이 시작되는데, 한 사이클 내에 완료되지 못한다. 따라서 다섯 번째 사이클에서 특별한 상황이 일어난다. 즉, LOAD 명령어 실행은 완료되지 못한 상태에서 명령어 4(<4>로 표시)가 실행된다. 만약 명령어 4가 앞의 LOAD 명령어의 목적지 레지스터를 사용하지만 않는다면 아무런 문제가 발생하지 않으며, 명령어 실행은 지연 없이 진행된다.
|
[그림 1] 파이프라인된 RISC에서의 명령어 실행 과정 |
|
| |||||||
사이클 파이프라인 단계 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
명령어 인출 |
1 |
2 |
L |
4 |
5 |
6 |
S |
8 |
9 |
10 |
명령어 실행 |
|
1 |
2 |
L |
<4> |
5 |
6 |
S |
<8> |
9 |
기억장치 액세스 |
|
|
|
|
L |
|
|
|
S |
|
그것이 가능해지도록 하기 위하여 위에서 설명한 방법들 중에서 두 번째 방법을 사용한다면, 컴파일러가 LOAD 명령어의 다음 위치에 LOAD 명령어에 의하여 기억장치로부터 인출되는 데이터를 사용하는 명령어가 오지 않도록 순서를 조정해주면 된다. 만약 컴파일러가 그러한 명령어를 찾을 수 없을 때는 LOAD 명령어 다음에 NO-OP 명령어를 삽입해주어서 아무런 동작이 처리되지 않으면서 한 사이클을 기다리게 한다. STORE 명령어의 경우에도 비슷한 일이 발생하는데, 이때도 명령어 8이 STORE 명령어의 실행과 무관하다면 아무런 문제가 없다.
이와 같이 기억장치를 액세스하는 명령어의 다음 위치에 그와 무관한 명령어를 위치시키는 재구성 방법을 사용하면 H/W 인터라킹 방법보다 프로세서의 내부 하드웨어가 더 간단해진다. 그러나 컴퓨터시스템에 따라 프로세서의 속도와 기억장치 속도간의 차이가 더 커져서 기억장치 액세스에 여러 사이클들이 걸리는 경우에는 컴파일러가 그만큼 더 많은 명령어들을 찾아서 삽입해야 하고, 만약 그러한 명령어들을 찾을 수 없다면 그 수만큼의 NO-OP 명령어들을 삽입해야 한다. 이러한 동작은 컴파일러에게 큰 부담이 될 수 있기 때문에 MIPS에서는 이와 같은 명령어 실행 순서의 재조정을 담당하는 별도의 프로그램인 재구성기(reorganizer)를 사용한다. 재구성기는 어셈블리 프로그램을 조사하여 기억장치의 액세스의 지연에 따른 영향을 최소화시키기 위하여 명령어들의 실행 순서를 전체적으로 재조정해주는 역할을 한다.
5) 마이크로프로그램의 제거
독자들은 CISC 프로세서에서 제어 유니트가 명령어 해석과 제어 신호 발생을 위하여 마이크로프로그램을 사용하였다는 것을 기억할 것이다. 그 주요 이유는 제어 유니트 내부 회로의 복잡성을 줄이기 위한 것이었다. 그에 따라 제어 유니트의 내부에는 마이크로로그램을 저장하기 위한 제어 기억장치(control memory)가 필요하게 되었고, 그것으로부터 마이크로 코드(micro-code)를 인출해야 하기 때문에 실행 과정에 많은 시간이 걸리게 되었다. 즉, 명령어 실행 속도가 저하되는 주요 원인이 된 것이다.
RISC 프로세서에서는 모든 명령어 실행 과정이 하드웨어만에 의하여 이루어진다. 다시 표현하면, 명령어를 해석하고 제어 신호를 발생하는 과정에서 마이크로프로그램이 개입되지 않는다는 것이다. 명령어 인출 유니트(instruction fetch unit)에 의해 인출된 명령어 코드의 비트들이 그 명령어 실행에 필요한 제어 신호들을 발생시키는 데 직접 사용된다. 이것은 실제 RISC 프로세서의 고속화에 큰 기여를 하였다.
'Algorithm' 카테고리의 다른 글
병행프로세스와 상호배제 (0) | 2008.08.19 |
---|---|
주소지정방식 (0) | 2008.08.19 |
deadlock 4가지 (0) | 2008.08.01 |
B-, B+ Tree (0) | 2008.08.01 |
CPU scheduling (0) | 2008.08.01 |