컴퓨터구조(4) - 프로세서(2)
‘컴퓨터 구조 및 설계’를 공부하여 정리한 내용입니다.
5. 파이프라이닝에 대한 개관
파이프라이닝에 대한 간단한 소개
- 여러 명령어가 중첩되어 실행되는 구현 기술이다.
- 데이터패스의 관점에서 생각하면, 스테이지가 실행되고 있을 때, 다른 스테이지도 다른 것을 처리하도록 하는 것이다.
- 컴퓨터의 모든 최적화 개념은 우선 쓸데없는 일을 줄인다와, 놀고 있는 자원을 최대한 없애는 것에서 시작한다는 것을 생각하면 매우 자연스러운 접근 방법이다.
6, 7, 8 파이프라인 해저드
파이프라인 해저드
-
구조적 해저드
- 명령어와 데이터가 같은 메모리 공간에 있다고 생각하자 (
폰노이만 구조
) - 이 경우 데이터 패스에서 Instruction Fetch와 Data Access(mem)를 동시에 실행하는 과정에서 같은 부분을 건들일 수도 있게 된다.
- 이 경우는 경쟁 상태(race condition)와 비슷한 상황이 발생하는데, 실제로 하나의 구조에서 하나라도 쓰는 작업이 있는 경우는 이 상황이 일어나는 것은 바람직하지 않다.
- 사실 해결방법은 간단한데, 명령어가 있는 메모리 공간과, 데이터가 있는 메모리 공간을 물리적으로 분리하는 것이다. (
하버드 구조
) - 이는 구역을 나누는 방식으로도 손쉽게 구현이 가능한데, 가장 많이 사용되는 방법이다.
- 명령어와 데이터가 같은 메모리 공간에 있다고 생각하자 (
-
데이터 해저드
- 어떤 단계가 끝나야 다음 단계를 실행시킬 수 있는 경우를 의미한다.
-
예를 들어 다음과 같은 경우를 생각해보자
$ add $s0, $t0, $t1 # 이 명령어의 작업이 끝나야 $s0의 값을 알 수 있다. $ sub $t2, $s0, $t3 # 바로 다음 명령어가 $s0의 값을 쓰는데 파이프라인으로 붙어서 거의 동시에 가고 있다.
- 이 경우는 앞선 명령어의 결과를 기다려야하는 경우이기에 add의 결과값이 $s0 레지스터로 저장될 때까지 sub가 기다려야 하는 상황이 발생한다.
- 평범하게 파이프라이닝을 하면 이상한 값으로 sub가 연산되게 된다.
-
간단한 방법은 ALU의 결과를 바로 뒤 따라오는 sub의 ALU를 실행할 때 사용하는 것이다. 이를 우리는 전방전달(forwarding) 이라고 한다.
$ lw $s0, 100($t1) # 이건 적재 명령어라 ALU에서 값이 나오는 것이 아니라 Data Access를 마쳐야 한다. $ sub $t2, $s0, $t3 # 바로 다음 명령어가 $s0의 값을 쓰는데 파이프라인으로 붙어서 거의 동시에 가고 있다.
- 이 경우는 Data Access(MEM) 단계를 기다려야 하기 때문에 어쩔 수 없이 한번은 기다려야 한다. 이렇게 기다려야 할 때는 파이프라이닝을 한번 멈추기도 한다. 그리고 멈추는 단계는 주로 거품(bubble)이라는 별명으로 불리고, 표현된다. (파이프라인 지연)
-
제어 해저드
- if 문을 사용하는 경우다 (beq, bne 등)
- 왜 발생하는지는 명확하다.
- 이 경우는 기다리고 결과를 알면 브랜치하는 방식도 있지만, 실제로는 예상하는 방식을 더 많이 사용한다. (true나 false를 프로세서가 찍는 것)
- 왜냐하면 for문 같은 것을 생각해도 알 수 있듯이(true면 loop를 돌고, false면 loop를 빠져나오는 문법), true나 false는 연속적으로 나타나는 경우가 많기 때문이다.
- 틀리면 예상하고 진행하던 작업을 취소하고 다시 되돌아간다.
- 1bit 예측 방법은 오히려 많이 틀릴 수도 있다. 2bit 예측 방법은 유명한 방식이다. 이건 검색을 하면 많이 나오니까 패스..
해저드를 해결하기 위한 장치들
- Forwarding unit
- Harzard detection unit
- 데이터 해저드에서 lw 명령어를 사용하면 어쩔 수 없이 지연이 필요하다고 언급한바 있다.
- 이 경우는 이 유닛에서 그 해저드를 검출하고, 퍼져있는 EX, MEM, WB 단계들의 제어신호를 0으로 만들어서 아무런 작업을 하지 않도록 한다.
- 이는 nop으로 바뀌는 효과를 보이며, 위에서 말했듯이 Bubble로 불린다.
- 제어 해저드를 해결하기 위한 특수한 방식
- ID에서 분기가 일어난다고 판단하면 IF.Flush를 사용하여 그 직전에 인출되고 있던 주소를 0으로 만든다(nop)
- ID에서 분기가 일어난 것을 파악하기 위해서, sign-extend와 shift left 2를 사용해서 새로운 주소를 만드는 파트가 Register의 앞으로 옮겨진 것을 볼 수 있다. (해저드를 해결하기 위한 데이터패스에서) 이전에 해저드를 신경쓰지 않던 데이터패스에서는 이 부분이 Register 뒤에서 진행되었었다.
- 이는 사실 굉장히 어려운 작업이고 ID에서 분기를 파악하게 하는 것이기에 그 클럭 시간 자체를 증가시키게 되는 등 비효율 적인 부분이 있다.
- 하지만 이 작업을 통해서 분기가 발생할 때 바로 다음에 인출되고 있는 명령어 하나만 희생해서 분기의 손실을 막을 수 있다. 이전의 방식은 두개의 명령어를 희생시켜야 했다.
더 나아가서
- 이런 해저드의 해결은 하드웨어에서 담당하지만, 그 밖에 명령어의 조합으로 이런 하자드가 최대한 적게 발생시키는 방식은 컴파일러에서 고려하는 것이 가능하다.
- 이렇듯 컴퓨터의 프로그램을 올리기 위해서는 전방위에서 서로의 능력을 고려하면서 돌아갈 수 있어야 한다.
Leave a Comment