Pipeline의 Hazards는 세 가지 종류가 있었다.
1) Structure hazard
2) Data hazard
3) Control hazard
이 중에서 Data hazard는 언제 생길지에 대해 살펴보자.
Data hazard는 data 간의 dependency가 있을 때 발생한다.
예를 들어 앞에 있는 명령어가 끝나서 이를 받아 이후에 명령어가 실행되어야 하는데 파이프라이닝에서는 동시적으로 일어나기에 문제가 발생한다.
즉, 이렇게 되면 레지스터에 데이터가 업데이트 되기 전에 그 데이터를 읽으려는 현상이 발생하고 만다!
따라서 이 hazard를 없애기 위해서는 뒤에 따라오는 명령어를 늦추는 방법밖에 없다.
다시 말하면 뒤 따라 오는 명령어가 실행되지 않게 잠시 freeze를 시키는 것이다.
이를 stall이라고 부르며, PC와 IF/ID단을 계속 지연시키는 것이다.
아래의 그림을 살펴보면, EX MEM가 이루어질 때 stall로 지연시킨 후 WB에 도달했을 때 비로소 ID를 실행시키어 data를 저장함과 동시에 읽는 작업이 일어나게 된다.
두 clock이 손해보기는 하지만 Data hazard를 피하는 Pipelining을 위해서 감수해야 하는 부분이다.
하지만 만약 명령어의 50%가 data dependency가 있고, 이들이 인접해 있다면?!
이러한 경우도 있기에 잘 고려해야 한다.
이번에는 Data hazard의 두 번째 해결 방안으로 Forwarding 방법이다.
사실 WB에서 data를 write하기 전에 이미 EX단에서 어떤 것이 write될 지 알고 있다. 따라서 나중에 무엇이 저장될 지 알기에 이를 미리 가로채서 다음 명령에서 수행하는 것이다.
즉, WB로 보내어 write하기도 하고, 다음 명령어를 위해 WB로 보내기 전 EX부분에서 데이터를 가로채 ID에서 EX로 넘어갈 때 계산도 바로 수행할 수 있게 하고!
이와 같이 datapath를 조금 수정하여 사용할 소스를 미리 가져오는 것이다.
하지만 LW의 경우는 데이터가 EX단에서 나오는 것이 아니라, MEM단까지 와야 한다. 따라서 이 때는 어쩔 수 없이 한 clock을 낭비하게 된다.
이번에는 세 번째 방법을 살펴보자. Compiler scheduling 방법으로 미리 실행하기 전에 data hazard가 일어나지 않게 정리를 하는 것이다!
사람은 막 작성을 하고, 어떤 프로그램이 알아서 정리를 해준 후 넣는 방법이다.
예를 들어 뒤에 data dependency가 일어날 경우 NOP를 삽입하거나, 재배열을 통해 이를 막게 된다.
이는 하드웨어를 건드리지 않고, 소프트웨어만으로 data hazard를 해결한다.