나무모에 미러 (일반/어두운 화면)
최근 수정 시각 : 2024-10-17 21:00:52

CISC


명령어 집합
CISC AMD64x86 · M68K · 68xx · Z80 · 8080 · MOS 65xx · VAX
RISC AArch64 ARM · RISC-V · MIPS · DEC Alpha · POWER PowerPC · CELL-BE
LoongArch · OpenRISC · PA-RISC · SPARC · Blackfin · SuperH · AVR32 AVR
VLIW
EPIC
E2K · IA-64 · Crusoe

1. 개요2. 특징
2.1. 장점2.2. 단점
3. CISC 방식을 사용한 CPU들4. 관련 문서

1. 개요

Complex Instruction Set Computer, CISC

종류가 다양하고 하는 일이 복잡한 명령어로 이루어진 CPU, 또는 마이크로프로세서.

2. 특징

명령어의 길이가 가변적이기 때문에 명령어 밀도에서 유리한 편이다. 만약 데이터나 주소값이 필요하다면 명령어 길이를 늘려 해결한다. 하지만 RISC 구조에서는 길이를 늘릴 수도 없고 정해진 명령어 워드 길이 안에서 해결해야 한다. 그래서 복잡하다는 편견과 달리 CISC 구조는 명령어 세트 설계가 바이트 단위로 깔끔한 편이다.

흔히 비파이프라이닝 방식을 사용하는데, 이 방식은 명령어를 하나씩 처리하는 방식으로 한 명령어가 끝나야 다음 명령어를 처리하므로 명령어를 쪼개서 한번에 여러개를 동시에 처리하는 파이프라이닝 방식에 비해서 비효율적이다. 파이프라이닝 방식을 적용하기 위해서는 명령어 사이의 데이터 흐름을 실시간으로 분석해야 하는데 명령어가 복잡하면 이 분석에 사용되는 하드웨어가 너무 복잡해져서 설계 비용이 증가하고 회로의 속도가 떨어지기 때문에 CISC에서는 폭넓게 적용하기가 매우 어렵다. 이 때문에 성능 향상이 나중에 나온 RISC에 따라잡히게 되면서 현재는 도태되었고 결국 100% 온전한 의미의 CISC 프로세서는 현재 시장에서 찾아볼 수 없다

x86 및 그 확장판 x86-64가 CISC를 채택하고 있는 대표적인 아키텍처이다. 하지만, 그것은 옛날 기술의 기준이지 현재의 x86 CPU는 내부적으로 RISC로 동작하면서 CISC 명령을 에뮬레이션하는 형태를 취하고 있기 때문에 CISC 아키텍처가 아직까지 살아남아 있다고 주장하기는 어렵다. 즉 CISC는 RISC와 섞여 혼종처럼 남아있는 상태라, 순수한 CISC는 현재 찾아볼 수 없다.

2.1. 장점

하나의 마이크로코드에 많은 명령어들을 담아내므로 코드의 밀도가 높다. 특히 이는 지금의 컴퓨터가 왜 RISC가 아닌 CISC로 시작을 했는지 보여주는데, CISC를 사용하면 프로그램의 용량을 줄일 수 있고 메모리 접근 횟수를 크게 줄일 수 있다. CISC의 장점은 바로 적은 지시로 많은 작업을 처리할 수 있단 점이다. 특히 컴퓨터 발전 초기에는 경악할만한 비용의 메모리를 사용하던 시절인데다 사용할 수 있는 메모리 용량도 매우 한정적이라, 메모리 관련 비용을 절감하고 안그래도 부족했던 메모리 용량을 아끼면서 사용할 수 있는 CISC가 매우 유리하다 보니 CISC가 제일 먼저 탄생해 현장에서 이용됐다.
코드 단위당 작업량이 매우 많다. CISC는 가변 길이 마이크로코드를 사용하므로, 16 = 4 x 4와 같이 CISC로 단 하나의 코드로 해결할 수 있는 작업을, RISC로는 2+2+2+2+2+2+2+2의 코드를 입력해야 해 마이크로코드 작성자 입장에선 CISC가 매우 편리하다. 즉 CISC는 생산성이 높다. [1]
RISC는 CPU 구조가 바뀌어 처리 비트 단위에 변화가 생기면 기존의 명령어를 사용할 수 없어 호환성의 문제를 일으킨다. CISC는 구조상 프로세싱 단계에 꼭 들어맞아야 할 최적 명령어의 개념이 없어, 하드웨어 단계에서 지원하는 명령어를 후속 프로세서에서도 지원해준다면 명령어의 호환성을 크게 신경쓰지 않아도 된다. 호환 명령어의 사용이 가능하다 보니 프로그래머가 거의 쓰이지 않는 CPU 명령어로만 프로그래밍을 하지 않는 이상 호환성이 확보된다. 그리고 프로세서 구조를 바꾸어도 호환 명령어를 통해 호환성이 확보되므로, 프로세서 설계자들은 급진적인 설계 변화와 혁신적인 구조의 아키텍처 개발을 지속할 수 있다.
[2]
이 덕분에 사실상 반쯤 추상화된 인스트럭션을 어떻게 해석하고 재 배치하는지에 따라 성능의 차이를 보여줘 오래된 코드들 또한 새로운 프로세서에서 성능상 이점을 주게 되는것에 비해 RISC와 같이 프로세서 파이프라인을 감안해 코드를 만들어 줘야 하는 RISC계열 프로세서의 경우 프로그래머와 컴파일러의 중요성이 높아지게 된다. 이 문제가 극대화된 프로세서가 VLIW.

2.2. 단점

RISC를 탄생시킨 결정적인 이유이다. 마이크로코드를 받으면 이를 해독해야 하는데, 해독 자체도 어려워 디코더 설계가 까다로우며 해독한 뒤에는 버퍼를 거쳐 명령어를 재정렬 해야하는 등 시퀀싱도 복잡하다. 프로세서 설계가 전체적으로 어렵기 때문에, 1970년대에 IBM에서 CISC를 대체할 RISC 프로세서를 개발하였고, 현재 CISC 진영의 대표 주자인 인텔에서는 80년대 나온 VLIW를 90년대 채택하는 등 아이태니엄의 실패 이전까지 꾸준히 x86을 포기하려고 시도하였다.
일정한 길이로 작게 쪼개진 마이크로코드를 사용하는 RISC는 코드를 바로 파이프라인에 투입하면 되므로 파이프라이닝 구현이 쉽다. 하지만 CISC는 어떤 길이의 마이크로코드가 입력될지 알 수 없기 때문에 이를 적절하게 쪼개 파이프라인으로 전달해줘야 해, 파이프라이닝 구현이 RISC에 비해 난해하다. 이 때문에 고성능 상용 RISC CPU에 들어가있던 파이프라이닝이, CISC에서는 슈퍼컴퓨터에서나 찾아볼 수 있는 기술이었다. 나중에 인텔이 슈퍼스칼라를 뜯어고치면서 이 문제를 해결할 방법을 찾고 나서야 CISC 프로세서의 파이프라이닝 구현 난도가 확 낮아졌지만, 파이프라이닝의 효율은 그래도 RISC가 CISC보다 높으며 파이프라이닝의 확장도 RISC가 쉽고 CISC는 확장이 어려운 편이다. 지금의 x86 계통 CPU들이 CISC로 작동하는데 내부는 RISC로 명령어를 처리하는 괴상한 혼종이 된 이유가 파이프라이닝을 제대로 구현해내기 위해 RISC의 구조를 일부 수용했기 때문이다.
마이크로코드를 해독해야 하는 디코더가 굉장히 비대해진다. x86계 CPU들이 가진 대표적인 문제점이기도 한데, 이는 CISC 구조가 (특히 가변 길이 명령어 인코딩이) 야기한 선천적인 부작용이라 그렇다. 지금은 반도체 공정의 발전으로 트랜지스터를 늘리기 쉽지만, 예전에는 프로세서의 가용 트랜지스터 수가 굉장히 제한적이었다. 그런데 CISC는 디코딩이 복잡해 CISC 프로세서의 디코더가 커질 수 밖에 없어 많은 트랜지스터를 디코더가 혼자 독식하는 일이 비일비재했다. 다른 유닛도 트랜지스터를 할당 받아 성능 확장을 해야 했지만, 디코더가 트랜지스터를 거의 다 가져가 성능향상에 발목 잡히는 일이 흔했다. 그리고 디코더의 중요성이 매우 커, 디코더를 못 만들면 아키텍처 전체의 성능이 눈에 띄게 떨어지는 문제가 있었다.(이건 반대로 디코더를 잘 만들면, 프로세서 아키텍처의 성능을 크게 끌어올릴 수 있단 이야기가 된다.) 이 디코더에 많은 트랜지스터가 집적되기 때문에 큰 전력소모와 높은 발열 문제를 야기한다. RISC는 이런 문제를 피할 수 있어, 프로세서의 전력소모량과 발열 줄이는게 쉽다. 반대로 CISC 같은 경우는 프로세서의 거의 50퍼센트에 가까운 전력을 디코더가 소모하는 등 순수 CISC 프로세서는 디코더가 전력문제와 발열의 주범이다.

다만 현대적인 CISC 프로세서들은 디코더에 가해지는 부하를 줄이는 uOP 캐시가 도입되고 성능에 있어 분기 예측, 비순차적 실행과 같은 설계들이 도입되고 있어 무작정 디코더가 CISC의 발목을 잡는다는 표현은 과거와 달리 항상 유효하다고 보기는 어렵다. 실제로 디코더가 작은 RISC나 RISC보다도 디코더가 더 작은 VLIW 계열이 90년대 한창 유행했으나 RISC는 아직도 CISC를 완전히 밀어내지 못했고 인텔은 2010년대 말 VLIW 계열 CPU인 인텔 아이태니엄 시리즈를 단종시킨다. 이런식으로 현대 x86프로세서와 같은 RISC화 된 CISC의 경우 인스트럭션 디코더가 사용하는 전력은 전체의 5%도 되지 않으며[3] OpCache의 Hitrate 가 떨어져 디코더가 다시 동작하는 상황에서도 3% 에서 10%로 증가하는것에 불과하며 나머지는 L1, L2 와 같은 인스트럭션 캐시와 순수 연산부분이 프로세서 소비전력의 90%이상을 차지한다. [4]
코드의 과대포장의 문제이다. RISC로 절제해 입력할 수 있는 마이크로코드를, 그것도 CISC에서는 이상적으로만 작성한다면 더 간단하게 입력할 수 있는 코드를 인적인 문제 때문에 과도하게 크게 만들어 성능을 저하시키는 문제이다. CISC는 코드 길이를 가변적으로 입력할 수 있기에, 프로그래머의 실력이 떨어지면 코드를 필요 이상으로 길게 작성하는 일이 발생해 큰 퍼포먼스 저하를 유발할 수 있다. [5]
코드 밀도가 높아 메모리 사용량을 줄일 수 있는 장점은 메모리가 보급되면서 큰 의미는 아니게 되었다. GUI 환경에서 가장 큰 용량을 차지하는 부분은 데이터이기 때문이기도 하다. 또한 일부 RISC 구조 CPU에서 가변 길이 명령어를 도입하기도 했으며, 이는 가변 길이 명령어가 더 이상 CISC만의 전유물이 아니게 되었음을 나타낸다. 대표적으로 ARM의 Thumb-2 명령어 세트와 RISC-V가 있다. 하지만 일부 제품군을 제외한 ARM 아키텍처 제품군의 경우 이는 완벽한 가변 길이 명령어 체계가 아니며 중간에 모드 변환 명령어를 실행해야 한다. 그렇지 않다면 프로세서가 오작동하게 된다. x86은 완벽한 가변 길이 명령어 체계를 가지므로 RISC CPU들과는 동작이 다르다.

3. CISC 방식을 사용한 CPU들

4. 관련 문서


[1] 그 예시로 어떤 두 값을 비교 후 비교 결과에 따라 다른 값을 저장해야 할 때 CISC인 x86은 CMPXCHG 명령어 하나로 Lock, Load, Compare, Store 작업이 한번에 끝나고 Register operends 에 따라 비교 대상의 크기를 지정할 필요가 없지만 RISC 프로세서들의 경우 최소 4단계의 오퍼레이션이 필요하고 비교 대상의 레지스터에 따라 모든 구현을 직접 해야한다. Linux arm/include/asm/cmpxchg.h[2] 예를 들어 CISC계열인 x86의 명령어를 예로 들면 {{0x8c6131}} 명령은 16비트, 32비트, 64비트 모두 "mov word ptr [(bx+di), (ecx), (rcx) + 0x31], fs"로 레지스터 크기만 달라지고 동작이 동일하다.[3] uOP 캐시는 CISC 명령어의 주소에 디코드된 uOP들을 대응시키는 구조의 캐시인데, 특수 목적용 프로그램이 아닌 이상 대부분의 프로그램은 SIMD 벡터를 제외하면 mov, lea, push, pop 같은 Load/Store I/O, sub, add, mul, div 와 같은 정수/실수연산과 shr, shl과 같은 시프트연산과 and, or, xor, cmp, jz, jnz, je, jne 같은 비교/분기 명령어 등 1-2개의 RISC식 uOp에 대응되는 명령어가 대부분을 차지하고, 대부분의 시간동안 특정한 루프를 반복하므로 (=자주 쓰이는 코드는 한정적) uOP 캐시의 적중률이 높은 편이다. 레이턴시가 길고 3개 이상의 동작을 해 uOP 캐시를 이용하기 어려운 복잡한 명령어는 AMD64로 넘어오면서 대부분 제거되어 SHLD/SHRD, BSF/BSR 4개 명령어와 일부 특수 명령어 정도밖에 남지 않았다.[4] Empirical Study of Power Consumption of x86-64 Instruction Decoder[5] (xor eax, eax), (mov eax, 0), (sub eax, eax), (and eax, 0) 등등 모두 같은 역할을 하지만 모두 기계어의 길이가 다르다. (xor eax, eax)는 (0x31 0xC0)로 2바이트 명령어지만 (and eax, 0)는 (0x83, 0xE0, 0x00)으로 3바이트, (mov eax, 0)은 (0xbb, 0x00, 0x00, 0x00, 0x00)으로 4바이트 명령어다.[6] IBM의 메인프레임 컴퓨터에 사용되는 아키텍처로, 최신 하드웨어는 2021년에 발표된 Telum이다.