CPU의 명령어 처리

2021. 4. 15. 18:09Layer7/Layer7_Hardware

중앙처리장치의 개요

중앙처리장치(CPU)는 사람에 비유하면 두뇌에 해당하는 역할을 합니다. 주기억장치에서 데이터를 가져와 해석하고, 실행하고 데이터를 돌려주는 작업을 합니다.

 

 

중앙처리장치의 구조

  • 연산장치
  • 제어장치
  • 레지스터

연산장치(ALU)산술 연산논리 연산을 담당하는 장치입니다. 산술 연산이란, 덧셈, 뺄셈, 곱셈, 나눗셈 등이 있으며, 논리 연산으로는 논리합, 논리곱, 부정 등이 있습니다.

데이터를 레지스터에서 가져와 연산을 수행한 뒤 레지스터에 다시 덮어쓰기 합니다.

 

제어장치지휘자의 역할을 합니다. 주기억장치에서 데이터를 인출해(Fetch) 해독(Decode), 실행(Execute) 그리고 다시 데이터를 되돌려주는 (Write-Back)의 과정을 수행합니다. 즉, 명령어를 순서대로 실행할 수 있도록 제어하는 장치입니다.

 

레지스터는 주기억장치와 중앙처리장치 사이의 속도차를 보완하기 위한 적은 용량의 초고속 저장장치이므로, 중앙처리장치 내부에 있습니다. 명령어 코드, 명령어 주소, 연산에 필요한 데이터, 연산 결과를 임시로 저장하는 역할을 합니다. 레지스터는 범용 레지스터와 특수 목적 레지스터로 나뉩니다. 범용 레지스터는 연산에 필요한 데이터 (즉, 1+2할 때 1과 2), 그리고 특수 목적 레지스터는 특수한 용도로 이용되며 용도와 기능에 따라 조금씩 다릅니다.

 

특수 목적 레지스터로는 PC, MAR, MBR, IR, AC 등이 있습니다.

  • PC는 명령어 계수기 (Program Counter)로 다음에 인출될 명령어의 주기억 장치 내의 주소를 포인팅 합니다. 예를 들어 현재 실행되고 있는 명령어의 주소를 10이라고 가정하면 PC의 값은 11 (10+1)이 됩니다.
  • MAR는 명령어 레지스터 (Memory Address Register)로 주기억 장치에 명령이나 데이터가 저장된 주소를 보관하는 주소 레지스터입니다.
  • MBR 기억 레지스터 (Memory Buffer Register)는 PC가 포인팅 하고 있는 주소에 있는 데이터를 임시 보관하는 레지스터입니다.
  • IR는 명령어 레지스터 (Instruction Register)로 가장 최근에 인출된 명령어가 저장되어 있는 레지스터입니다.
  • AC는 누산기 (Accumulator)로 연산 결과를 저장하는 레지스터입니다.

 

 

중앙처리장치의 동작 과정

처음으로 주기억장치에서 명령어를 인출합니다. 인출을 Fetch라고 부릅니다. 인출된 명령어는 제어장치에서 Decoder에 의해 해석되는 Decode 과정을 거칩니다. 해석된 뒤 제어장치(CU)가 연산 장치(ALU)에게 데이터를 넘겨주어 연산을 하게 되는데, 이를 Execute라 합니다. 실행된 결과를 가지고 경우에 따라 Memory에 접근하기도 합니다. 마지막으로 연산 결과를 레지스터에 입력해주는 Write-Back을 합니다. 이러한 과정을 통틀어서 명령어 사이클 (Instruction Cycle)라 합니다.

그러나 이는 5개의 과정 (Fetch - Decode - Execute - Memory - Write-Back)을 거쳐 하나의 명령어 밖에 수행을 하지 못하므로 굉장히 비효율적인 방법입니다. 한 명령어가 Decode 되는 과정에서 한 장치만 일을 하고 나머지는 놀고 있는데, 나머지가 노는 것을 꼴 뵈기 싫어서 고안된 기술이 Pipelining입니다.

 

 

Pipelining 기술

한 명령어를 Decode하는 동안 다음 데이터를 Fetch 하고, 또 명령어가 Decode에서 Execute으로 넘어가는 과정에서 Fetch 하던 데이터가 Decode를 하게 되고, 또 새로운 명령어를 Fetch 할 수 있게 됩니다. 이로써 훨씬 효율적으로 데이터를 처리할 수 있습니다.

 

파이프라이닝 기술

 

그러나 이는 장점만 있는 것은 아닙니다.

 

 

Pipelining 기술의 문제점

1. Data Hazard

Pipelining을 하다보면 여러 가지 논리적인 오류가 발생할 수 있습니다. 예를 들어, 한 명령어가 Decode 되고 있는데 앞 명령어의 결과가 필요하다고 가정합시다. 앞 명령어는 현재 Execute 중이라서 Decode 중인 명령어에 사용될 수 없습니다.

즉, 첫 번째 명령어(이후 A)가 MOV rax, 1이고 두 번째 명령어(이후 B)가 ADD rdx, rax일 시 A가 Execute 되고 있는 중인데 B는 Decode에 rax의 값이 필요해서 아예 실행 자체가 불가합니다. 이는 Data Hazard라고 부르며, Out-of-order Execution 기술로 해결이 가능합니다.

 

2. Control Hazard

또 다른 문제점으로는 Control Hazard가 있습니다. 이는 앞 분기문의 결과를 알지 못하여 지연이 발생하는 경우입니다. 이는 Branch Prediction 기술로 해결할 수 있습니다.

 

 

 

Pipelining 기술의 문제점을 해결하기 위한 기술

Out-of-order Execution (비순차적 명령어 처리)

Data Hazard을 해결하기 위해 고안된 기술로, 앞에 아직 실행할 수 없는 명령어가 오고 뒤에는 실행할 수 있는 명령어가 오는 경우에 뒤에 있는 명령어가 먼저 실행되므로써 새치기를 하는 기술입니다. 단, 이는 원래 비순차적 명령어 처리가 수행되지 않았을 때의 결과와 똑같을 때만 실행됩니다. 이런 별거 아닌 것 같은 기술을 통해 속도가 엄청나게 증가하는 현상을 살펴볼 수 있습니다. 그러나 이때 Meltdown이라는 보안 취약점이 발생할 수 있습니다.

 

 

Branch prediction (분기 예측)

Control Hazard를 해결하기 위해 고안되었습니다. 명령어들 중에서 조건문이 나왔을 때 조건이 참인지 아닌지 검사해야 합니다. 그러나 참 거짓을 검사하기에는 시간이 많이 걸립니다. 검사하는 시간까지도 줄이기 위해 (우리의 시간은 소중하니까^^) 분기 예측이라는 기술을 사용합니다. 이는 분기문을 검사하는 시간 동안 미리 참일때의 명령문을 실행하고, 나중에 분기문의 결과를 확인하여 참이었을 경우 그냥 바로 넘길 수 있어 성능이 향상됩니다. 분기문이 거짓이 되었다 하더라도 완료(Commit) 단계 전까지는 분기문의 실행을 취소할 수 있어 원본 상태로 되돌릴 수 있습니다. 다소 귀찮은 작업이라는 생각이 들 수 있지만, 원래대로 조건을 검사한 뒤 실행하는 것보다 속도가 훨씬 빠르기 때문에 분기 예측을 사용하는 것이 무조건 유리합니다. 그러나 이때는 Spectre라는 보안 취약점이 발생할 수 있습니다.

 

Speculation execution(추측 실행)

명령어를 실행하다가 필요한 데이터가 아직 없어서 진행이 중단될 때 그 데이터를 예측하는 기술입니다. 데이터를 예측하는 것은 어려운 일이고 시스템 자원을 많이 요구하나, 맞추었을 때의 이득이 틀렸을 때의 손해보다 훨씬 크기 때문에 이러한 과정을 거치는 것이 좋습니다.

예를 들어 반복문이 실행된다고 가정합시다.

for(int i = 0; i < 100; i++){
	printf("%d\n", i);
}

위와 같은 반복문이 실행되는데 매 번 검사하고 검사 결과를 기다린 후 실행하기에는 너무 시간이 많이 소요됩니다. 이때 추측 실행이 사용됩니다. 이 반복문에서는 100번은 무조건 실행될 것이고 마지막 검사(i가 100이 될 때)만 거짓이 되기 때문에(100번은 맞을 것이고, 101번째 실행 때만 거짓이 됨) 차라리 모든 명령문을 먼저 실행하고 그 시간 동안 조건을 검사하는 편이 훨씬 효율적입니다. 1번째부터 100번까지 쭉~ 가다가 101번째 실행을 합니다. 이미 명령문을 실행했는데 조건이 거짓이 되어 반복문에서 빠져나와야 하므로 이때 이미 실행했던 101번째 실행을 Commit 단계에서 취소하고, 뒤에서 처리되기를 기다리고 있는 명령어들 (Fetch과 Decode 되고 있는 명령어들)을 모두 파이프라인에서 지우게 됨으로써 다음에 실행되지 않도록 합니다.

 

 

 

결론

결론적으로, 중앙처리장치는 데이터를 주기억장치로부터 가져와 제어장치 내의 Decoder가 해석하고, 해석된 명령어를 제어장치가 연산장치에 넘겨주어 실행한 다음, 결과를 다시 제어장치에게 넘겨주어 메모리에 접근이 필요할 시 메모리에 접근하며, 마지막으로 결과를 레지스터에 입력합니다. 이러한 명령어 처리의 과정을 명령어 사이클이라 하며, 명령어 사이클의 성능 향상을 위해 파이프라이닝 기술이 발명되었습니다. 파이프라이닝은 한 명령어를 실행하는 동안 다음 명령어를 해석하고 그다음 명령어를 주기억장치에서 가져오며, 이를 통해 한번에 더 많은 명령어를 처리할 수 있도록 해줍니다. 이때 크게 두 가지의 논리적인 문제점이 발생할 수 있는데, 데이터에 접근할 수 없는 Data Hazard와 분기의 결과를 몰라 지연이 생기는 Control Hazard가 발생할 수 있습니다. 비순차적으로 실행하여 명령어들이 새치기할 수 있게 하는 기술이 Out-of-order-execution이며, Data Hazard를 해결하기 위해 탄생했습니다. 그리고 분기를 예측하여 지연을 줄이는 기술인 Branch prediction이 Control Hazard를 해결하기 위해 만들어졌습니다.

 

생각보다 간단할 것 같았던 중앙처리장치, 무식하게 명령어만 연속적으로 실행하는 것 같았던 이 장치가 내부적으로 훨씬 복잡하고 빠른 속도를 내기 위하여 데이터 예측 등의 고급 기술을 이용하는 것도 새롭게 알게 되었습니다. 우리는 키보드를 누른 것 뿐이고 마우스만 움직였을 뿐, 컴퓨터 내부에서 대단히 복잡한 일들이 이 세상 가장 빠르게 수행되고 작동되고 있습니다.

 

 

중앙처리장치(CPU)의 모습

 

메인 사진 출처: Unsplash

 

© 남찬우, 2021

'Layer7 > Layer7_Hardware' 카테고리의 다른 글

임베디드 구조  (0) 2021.04.20
컴퓨터의 부팅 과정  (0) 2021.04.06
Flash, ROM, RAM에 대하여  (0) 2021.04.05