RISC

Reduced instruction set computer의 약자.

1 개요

IBM에서 1980년에 발표하고 MIPS를 창시한 데이비드 패터슨 교수등이 정립한 CPU의 명령어셋 아키텍처와 마이크로 아키텍처 설계에 대해 새로 제시한 개념 내지는 그 개념에 의해 설계된 CPU를 의미한다.

기본적인 개념은 트랜지스터 기반의 메인프레임을 개선하는 과정에서 개발된 아키텍처 개념으로, 최대한 단순히 설명하자면 그동안 별 생각 없이 중구난방으로 만들어 온CPU 명령어셋을 CPU를 고속화시키는 데 적절하게 재정립하여 같은 트랜지스터 숫자를 투입하면서도 더 높은 성능의 CPU를 만들자는 것이다.

2 상세

1980년대 당시 CISC 명령어셋에 대해 지적되는 문제점은 다음과 같았다.

  • 명령어 길이가 제각각이다. 따라서 명령어를 인출할때 언제가 명령어 종료시점인지 알 수 없으며 다중 사이클이 소요되는 명령어를 그대로 파이프라인 처리를 할 경우 파이프라인 버블이 발생하여 처리효율을 떨어뜨린다.
  • 명령어 포맷이 중구난방이다. 때문에 명령어 해석기에서 특정 내용을 액세스하려고 할 경우 그 명령어에 대한 인출과 해석이 완전이 끝나야 가능하다.
  • 명령어에 레지스터 대상이 아닌 메모리를 대상으로 한 연산이 섞여있다. 메모리를 대상으로 한 연산의 경우 메모리 액세스 사이클의 손실이 정확히 얼마일지 알 수 없기 때문에 파이프라인의 정확한 운용이 심히 고자스러워진다.
  • 각 명령어들의 실행 사이클이 제각각이다. 어떤 명령어는 1사이클, 어떤 명령어는 3사이클 하는 식으로... 이러한 구조는 파이프라인의 효율성을 심각하게 저하시킨다.
  • 마이크로코드를 통해 구현된 복잡한 기능의 명령어는 처음 도입할 때는 타당성이 있었을지 모르지만 CPU기술이 발전하면서 다른 방식으로 처리하는 게 더 빨라지는 사태가 발생했다.
  • 마이크로코드 방식 자체가 CPU의 명령어해석기 고속화에 발목을 잡게 되었다.
  • 명령어의 구조가 고색창연한 어큐뮬레이터 구조를 유지하고 있다. 명령어가 2개의 레지스터/메모리만을 액세스 가능하므로 a+b의 연산을 c에 따로 저장하지 못하고 b의 내용에 덮어쓰면서 b의 내용을 재활용하지 못하게 된다.
  • 레지스터의 기능이 일정하지 못하고 특수기능이 포함된 경우가 많아 컴파일러의 복잡성을 증대시켰다.
  • 프로그램 코드와 데이터가 단일 캐시메모리 공간에 위치하고 있는 폰노이만 구조는 코드의 메모리 동작특성과 데이터의 메모리 동작특성이 크게 다르다는 사실을 반영하지 못하고 있다.
  • ROM 기반이던 마이크로코드 해석기는 수정이 불가능하고 유연성이 떨어지지만 속도가 상대적으로 빠르다는 장점이 있었는데 RAM 기술이 비약적으로 발달하면서 이런 장점도 퇴색되었다.

이러한 문제점들을 해결하기 위해 RISC가 등장하였고 아래와 같은 방법으로 문제를 해결하였다.

  • 명령어 길이를 16bit 혹은 32bit로 일정하게 정리하였다. 따라서 명령어 인출기는 무슨 명령어인지 별도로 판단할 필요 없이 16bit 혹은 32bit만큼 인출동작을 기계적으로 수행하면 되므로 명령어 인출기가 크게 단순화 되었다. 또한 1사이클에 1명령어가 정확하게 들어오는 것이 보장되면서 파이프라인에 버블이 낄 가능성이 낮아졌다.
  • 명령어 포맷을 일정하게 다듬었다. 예를 들어 소스 레지스터와 타겟 레지스터를 나타내는 플래그가 명령어상에 특정 비트에 위치시킴으로서 명령어 해석기에서 명령 해석이 완전히 끝나기도 전에 소스 레지스터와 타겟 레지스터를 찾아서 선제적으로 동작시키는 것이 가능해졌다. 이로써 명령어 해석기와 내부 컨트롤의 효율이 증가하였다.
  • 메모리를 대상으로 하는 load/store 연산과 레지스터를 대상으로 하는 mov 연산을 분리하면서 메모리 액세스 타이밍의 불확실성을 제거하였다. 즉 필요한 값에 대한 load 동작을 메모리 레이턴시를 고려하여 몇 사이클 앞에서 선제적으로 실행하고 load동작이 완료되자마자 연산을 수행하는 식으로 레이턴시를 감추는 방식을 사용할 수 있게 되었다. 또한 파이프라인의 효율성도 그에 따라 증가하였다.
  • 각 명령어들의 실행 사이클을 1사이클로 조정하였다.
  • 마이크로코드의 복잡한 연산기능은 컴파일러로 그 역할을 이전하였다. 마이크로코드가 제외되면서 명령어 해석기가 hard-wired한 회로로 구성되었고 그에 따라 동작속도가 증가하였다.
  • 어큐뮬레이터 구조를 폐지하였다. 이제 한 개의 명령어는 2개의 소스 레지스터와 1개의 타겟 레지스터를 대상으로 동작하게 되었다. 즉 b=a+b에 종속된 구조에서 탈피하여 c=a+b 동작이 가능해졌다.
  • 레지스터는 기본적으로 일반목적레지스터(GPR)로 설계되었다.
  • 폰노이만 구조를 버리고 하버드 구조가 채용되었다.
  • 명령어 해석기 부분이 단순화 되고 효율적으로 변경되면서 남아도는 트랜지스터는 더 깊은 파이프라인이나 더 많은 캐시메모리 등에 할당되면서 성능이 향상되었다.
  • 가능한 명령어 시퀀스의 경우의 수가 간략해지면서 아키텍처의 정상 동작 검증이 원활해졌다.

다만 RISC는 다음과 같은 단점을 가지게 되었다.

  • 최대의 단점은 코드밀도가 감소하여 같은 내용을 처리하는 데 더 많은 코드 용량이 필요하게 되었다는 점이다. 그 원인은 또 다음과 같이 분류할 수 있다.
- 항상 16bit 혹은 32bit를 차지하는 고정 길이 명령어는 상황에 따라 8~32bit를 오가는 CISC의 가변 길이 명령어에 비해 코드밀도 면에서 원천적으로 불리하다.
- 메모리를 대상으로 하는 연산 명령어의 경우 CISC에서는 1개 명령어로 표현 가능한데 RISC에서는 load-execute-store로 3개의 명령어가 필요하다.
- 마이크로코드로 한 줄로 구현된 CISC명령어를 몇 개, 혹은 수십개의 RISC명령어로 변환해야 한다.
  • 메모리를 소스 혹은 타겟으로 쓸 수 없게 되면서 그 역할을 대체해야 하는 더 많은 레지스터가 필요하게 되었다.
  • 명령어 길이가 제약되면서 분기명령의 점프 범위가 제약되었다. CISC에서는 분기명령의 점프 범위를 단순히 코드 길이를 늘리는 것으로 해결할 수 있지만 RISC명령어는 그게 불가능하다.
  • 그리고 가장 현실적인 단점은... x86이 아니더라는 것이었다. 당시 x86으로 대세가 흘러가는 시장 상황에서 이것만큼 큰 단점도 달리 없었다. x86이 다소 쇠퇴하고 있는 2010년대의 시점에서 보면 상전벽해가 따로 없을 지경.

3 현황

RISC CPU라고 해서 CISC CPU를 그냥 단순화시켜서 설계하는 것도 아니고 반드시 명령어의 숫자가 CISC에 비해 적은 것도 아니다[1]. 실제로 RISC 명령어 구조가 가져다 준 이득은 명령어의 종류와 구성을 하드웨어 구현에 적합하게 단순화하고 정리한 결과로 인해 CPU의 마이크로아키텍처 설계를 전반적을 향상시킬 수 있게 되었다는 것이다. CISC에서는 여러 clock을 차지하는 복잡한 연산을 하는 명령어들이 종종 있었다. 심지어 for 루프를 실행하는 명령어가 존재했을 정도였다. 이는 과거에 컴파일러의 성능이 부족했기 때문에, 컴파일러를 사용한 후에도 최적화를 하기 위해서 기계어 코드를 수정하는 등 프로그래머가 기계어를 직접 다루는 경우가 많았기 때문이다.

그러나 현대에는 컴파일러의 성능이 향상되었기 때문에 더이상 이런 시시콜콜한 명령어를 CPU에서 직접 제공할 필요가 없다. 또한 이런 복잡한 명령어들이 있으면 clock 스피드를 높이는데 애로사항이 있고 파이프라이닝이나 슈퍼스칼라 등으로 CPU가 한 번에 여러 개의 명령어를 동시에 처리하고 있는 상태를 유지하도록 함으로써 성능을 향상시키는 기법을 적용하기도 대단히 어려워지는 등의 문제가 있다. 이 때문에 RISC에서는 이러한 명령어들을 제거하고 한 clock 혹은 일정한 숫자의 clock (파이프라이닝을 적용하는 경우) 동안 실행할 수 있는 명령어들로 명령어 셋을 정리한 것이다.[2]

90년대 중반이 지나서는 PowerPC, POWER, UltraSparc, Alpha 등 대부분의 고성능 CPU와 ARM과 같은 저전력 CPU, 그리고 일부 MCU들까지도 RISC이거나 RISC 구조를 기반으로 한다. 바꿔 말하면 RISC의 개념이 정착된 이후 더 이상 CISC 방식의 CPU를 새로 설계하는 일은 없게 되었다. CISC의 대표 주자인 인텔의 x86조차도 CISC명령어를 실행시킨다는 점만 제외하고는 인텔 펜티엄 프로에서부터는 이미 내부적으로는 CISC 명령어를 RISC 구조의 코드로 변환해서 실행하는 P6 아키텍처로 개편하였다. 또한 좀 더 앞선 시기에 AMD는 K6에 동일한 설계를 구현하였다. 그래도 완전한 RISC 구조와 비교하면 한계가 있어서, 펜티엄 프로만 해도 파이프라인이 무려 10단계에 이르렀다. 반면 당시 대부분의 RISC CPU는 5단계 혹은 7단계, 많아야 9단계 정도.

참고로, 흔히 파이프라인 단계가 많으면 많을수록 좋다고 오해하는 경향이 있는데, 파이프라인 단계가 늘어나는 것은 clock 스피드를 높일 수 있는 것 이외에는 단점밖에 없다. 그런데 x86 CPU에서 파이프라인 단계 수가 RISC CPU들보다 많은 것은 x86 명령어들을 변환하기 위한 단계가 대거 추가되었기 때문이었으며 따라서 펜티엄 프로 시절에는 오히려 clock 스피드가 RISC CPU들보다 느렸다. 인텔 코어 i 시리즈가 나온 요즘은 인텔에서도 클럭 당 효율을 높여 오히려 불필요한 파이프라인 단계를 줄이려는 노력을 기울이고 있다.

명령어들을 하나씩 차례대로 실행하는 게 당연했던 CISC 시절과는 달리 RISC 구조에서는 어셈블리어 레벨의 프로그래밍에 편의를 제공해주는 명령어들이 부재하기 때문에 일반 프로그래머 레벨에서 기계어 코드를 손으로 최적화하는 것은 어렵고 그만큼 컴파일러의 중요성이 크다. 물론 하나씩 차례대로 실행하는 것도 가능하지만 동시에 처리하는 것 보다는 효율이 떨어지게 된다.

2000년대 후반 들어 스마트폰을 비롯한 다양한 멀티미디어 기기에 ARM 아키텍처가 적용된 CPU가 많이 탑재되고 있는데, 이것도 RISC 명령어셋을 택하고 있다.[3]

흔히 CISC와 RISC를 서로 대립되는 포지션으로 취급하는 경우가 많은데 이는 RISC이 등장하게 된 이유나 최근의 CPU설계 경향등에 비추어 봤을 경우 적절한 취급이라고 할 수 없다. 우선 상기한 바와 같이 RISC는 CISC에서의 단점을 분석하고 극복하는 연구 과정에서 탄생한 명령어셋으로 명백하게 CISC보다 더 발전된 개념을 포함한 우월한차세대 기술이다. 그렇기 때문에 RISC가 출현한 이후 CISC기술에 기반한 신규 명령어셋은 실질적으로 도태되는 수순을 밟게 되었고 CISC의 흔적은 RISC계열 CPU에 포함된 일부 마이코로코드 기반 명령어셋[4] 정도에 남아있을 뿐이다. 또한 마이크로아키텍처 관점에서는 CISC를 수행하는 마이크로아키텍처 조차도 내부의 프론트엔드 파트에서 명령어셋을 RISC로 변환하여 실행하게끔 발전하면서 사실상 CISC명령어를 실행할 수 있는 RISC가 되고 말았다. 결국 시장 상황은 CISC가 우위를 가지되 실질적인 기술은 RISC가 지배하고 있는 것이 현실이라고 할 수 있다.
  1. 혹자는 이 언급을 읽고 CISC와 RISC의 차이점에 대해서 혼란을 일으킬 수도 있겠지만 RISC 명령어가 단순히 명령어 수를 줄인 것이 아니라 명령어 해석기에서의 마이크로코드의 의존도를 제거하고 관련 로직을 단순화하여 성능을 올리는 방향으로 발전했다는 것을 상기하라. 이것을 다른 관점으로 해석하면 명령어해석기 로직의 복잡화를 감당할 여유가 되는(가용 트랜지스터의 꾸준한 증가에 의해 실제로 그러한 여유가 증가해 왔다.) 상황에서는 RISC 역시 명령어의 종류를 증가시키는 게 이득이라는 것이다. 대표적인 분야가 바로 SIMD계열의 명령어셋.
  2. 부동소수점 연산 등의 예외도 좀 있지만. 그러나 부동소수점 연산도 FPU유닛의 파이프라인 단계를 증가시켜서 점차 한 clock에 실행 가능하도록 하는 것(다만 이 경우에는 한 클록 실행은 가능하지만 레이턴시는 증가된 파이프라인 갯수만큼 지연된다.)이 대세가 되고 있다.
  3. ARM이라는 이름 자체가 Advanced RISC Machine의 이니셜이다. 또한 ARM 명령어셋이 처음 등장한 시기는 1985년으로 RISC명령어셋 중에서는 MIPS와 함께 가장 이른 시기에 도입된 명령어셋 중 하나이다.
  4. 예를 들면 ARM의 LDM/STM 명령어가 대표적인 마이크로코드를 이용한 명령어이다.