한 Cycle에 여러 가지 명령어가 수행될 수 있도록 하는 것
장점
→ 여러 가지 Unit들의 사용률을 향상 시킴
→ Performance가 향상됨
단점
→ 하드웨어 구성 및 Control Logic이 복잡해짐
→ Hazard가 발생
ex) Add명령어의 WB 단계에서 Register에 값을 Write하려고 하는데, 어떤 Register에 Write를 해야하는지에
대한 정보를 알아야 하기 때문 or 명령어의 Stage에 따른 Control Signal들을 참고하기 위해 필요
한 Cycle에서 WB Stage가 동시에 두개가 실행됨
하지만 Register의 Write Port는 1개기 때문에, 두 명령어의 WB중 하나는 실행되지 않을 수 있음
ADD의 명령어가 $1에 WB하기 전에 SUB 명령어가 $1을 RF/ID에서 Read한다.
→ ADD 명령어를 통해 최신화되지 않은 $1의 값이 SUB 명령어에서 Read된다.
→ Stall을 삽입해 Do nothing을 시키고 앞선 명령어의 WB Stage가 실행된 후 다음 명령어의 Read가 실행되도록 한다.
→ 3 Clock Cycle을 낭비하는 셈
한 Cycle을 두개의 Half Cycle로 나누는 방법
→ CC5의 앞 Half에서 SUB 명령어의 WB이 실행되도록함
CC5의 뒤 Half에서 AND 명령어의 RF가 실행되도록 함.
→ 하지만 여전히 2 Clock Cycle을 Stall 시켜야 함
필요한 Data를 Data를 필요로 하는 Unit으로 직접 전달해주는 방법
→ EX단계 실행 후, EX/MEM Register에 있는 Data의 계산된 값을 필요로 하는 Unit으로 직접 전달해줌
→ 위의 그림과 같은 Forwarding Unit이 추가적으로 필요함.
→ Forward를 해야한다면 Forwarding Unit이 Mux 값을 Control하는 Logic인 것으로 보임
LW 명령어에 의한 한계
→ LW의 MEM과 AND의 EX가 같은 Cycle에 있어 Forwarding이 될 것이라고 예상하지만
Memory에 접근하는 LW는 수행 시간이 길어 Clock Cycle의 후반부에 수행이 완료됨
하지만 EX는 Clock Cycle의 전반부에 수행되기 때문에 Forwarding 불가능
solution of Fowarding의 Limitation)
→ 어쩔 수 없이 한 Cycle의 Stall을 사용해야 한다.
→ Compiler가 Hazard가 발생할 것 같다고 인지되는 명령어들의 순서를 변경해줌
Branch가 Taken 된다면 뒤따라오던 명령어 3개는 무용지물
→ 3 Clock Cycle의 낭비 초래**
→ Branch에 해당하는 명령어의 결과를 알기 전까지 뒤의 명령어들을 Stall 시킴
→ 결과가 Taken일지 Not-Taken일지 예측하는 것
→ Taken인지 Not-Taken인지에 대한 과거의 결과를 저장해두는 Table을 활용
→ RF/ID Stage에서 Comparator라는 Unit으로 비교
→ Penalty를 1 Clock Cycle로 줄일 수 있음
→ 구현하기가 굉장히 어려움
1bit Branch - Prediction
→ Taken으로 예상하다가 Not-Taken 발생하면 Not-Taken으로 예상, 다시 Taken 발생하면 Taken 예상
2bit Branch - Prediction
연속 두번으로 예상과 다른 결과가 발생해야 예상하는 값이 바뀜.