2023. 5. 26. 17:48ㆍ컴퓨터구조
명령어 실행 순서
1. pc에서 명령어 메모리로 접근 , 명령어 가져옴
2. 레지스터 번호를 통해 레지스터 파일 접근-> 읽어옴
3. 명령어에 따라 달라짐
<계산 위한 ALU 사용 >
- 산술 연산
- load/store 위한 메모리 주소 연산 -> load/store 위한 메모리 접근
- Branch target 주소 연산 -> target 주소로 가거나 다음 명령어 실행 위해 PC+4
* Combinational element
예) AND-gate, adder, Multiplexer 등
*Sequential element
- 레지스터: 회로에서 계산 중간에 데이터를 저장하는 용도
Edge-triggered: 클럭이 0에서 1로 바뀔 때 값을 업데이트
-> 클럭 신호가 바뀔 때 레지스터에 보관하던 값으로 업데이트

레지스터에 쓸 때
-> write control 신호가 1일 때 clock edge에 의해 업데이트

The Main Control


Top 4 bit: 원래 PC
나머진 00
26 bit: 점프할 주소
Pipelining에 필요성
가장 오래 걸리는 작업은 load instruction
-> 이로 인해 나머지는 놀고 있게 됨.
MIPS Pipeline
1. IF: 명령어 메모리로부터 명령어 fetch
2. ID: 명령어 해석 & 레지스터 읽기
3. EX: 명령에 의한 operation 실행 또는 주소 계산
4. MEM: 메모리 접근
5. WB: 결과값 레지스터에 기록
파이프라인 속도
-> 단계가 모두 같은 시간 걸린다면
-> 파이프라인 아닐때 명령어 사이 시간/단계 수
*단계가 모두 같은 시간이 아니면 속도가 좀 느려지게 됨
Hazards
- Structure hazards
-> 한번에 하나의 데이터를 접근 가능
-> Load/store 상태에서 데이터를 접근하고 있다면
명령어 fetch는 이번 사이클에서 할 수 없다. --> stall
-> 해결 위해 명령어 캐쉬와 데이터 캐쉬로 분리
- Data hazard

해결책
*Forwarding: 계산이 다 되면 결과값을 레지스터에 저장할 때까지 기다릴 필요 없이
다음 명령에서 바로 사용할 수 있게 해주는 것.
-> stall을 피할 수 있다.

그러나 항상 가능하진 않다.
예) load

* Forwarding으로 안되면 코드의 순서를 재배치하여 stall을 피한다.
-> load 명령과 두 사이클 이상은 차이 나야함.
- Control hazard
분기 흐름의 위험
다음 명령어를 fetch하기 전에 branch 결과가 결정되야 한다.
*MIPS 파이프라인에서는 레지스터 비교와 target 계산을 일찍 하려고
위에 일을 할 하드웨어를 ID stage에 추가한다.

해결책: 분기예측
branch의 결과를 예측하는 것
-> 예측이 잘못됐다면 stall

* Static branch prediction: 소프트웨어적 예측
-> loop와 if문에서의 branch 예측
Dynamic branch prediction: 하드웨어적 예측
-> 최근 히스토리 기록을 가져옴
Pipelined Datapath
흐름이 오른쪽에서 왼쪽으로 가면 hazard가 발생
-> 해결 위해 각 단계마다 레지스터를 하나씩 둬서
이전 사이클에서 생성된 값을 붙잡고 있어야 한다.
forward 해야 할 때를 어떻게 탐지할까?
*Data hazard는 언제 일어나나?
1. EX/MEM stage에서 Rd레지스터 번호와 ID/EX stage에서 Rs 또는 Rt레지스터 번호가 같을 때
-> EX/MEM 레지스터에서 forward 해야함
2. MEM/WB stage에서 Rd레지스터 번호와 ID/EX stage에서 Rs 또는 Rt레지스터 번호가 같을 때
-> MEM/WB 레지스터에서 forward 해야함
그러나 레지스터에 값을 write 할 때만 포워딩을 해야함. write 안하면 굳이 포워딩 안해줘도 됨.
그리고 Rd레지스터 값이 0일 때는 해줄 필요없음
* Double Data Hazard
-> 가장 최근 값을 포워딩 해줘야 한다

* Load-Use Hazard는 언제 일어나나?
ID/EX 단계에서 MemRead를 할때 ID/EX 단계의 레지스터 Rt 번호와 IF/ID 단계의 레지스터 Rs 또는 Rt번호가 같을 떄
-> 이때는 포워딩이 안되므로 stall 하고 bubble 추가해야 함.
*어떻게 stall을 하나?
ID/EX 레지스터에 강제로 0을 대입한다
-> EX, MEM, WB가 아무일도 하지 않도록 nop 명령 추가
PC값이 업데이트 되지 않도록 막는다
-> 명령이 다시 decoded 되도록
Branch Hazrds가 일어났을 때
브랜치된 명령어 전 명령들은 다 실행하면 안됨.
*브랜치 딜레이를 감소시키려면?
ID 단계로부터의 결과를 결정하기 위해 하드웨어를 이동
-> 타겟 주소 adder, 레지스터 comparator
*branch 명령어 2번쨰나 3번쨰 앞에 ALU 명령이 있는 경우
-> forwarding을 이용하여 해결

*branch 명령어 바로 앞에 ALU 명령이 존재하거나
load 명령이 2번째 앞에 있는 경우
-> 한 사이클은 stall 해야 forwarding이 가능함

* branc 명령 바로 앞에 load 명령이 있는 경우
-> 두 사이클은 stall 해야 forwarding 가능

*분기 predictor
1-bit predictor: 과거에 taken이 맞다면 그대로 taken으로
taken이 아니였다면 not taken으로 바로 바꿈
-> 예측이 1번 틀리면 바로 바꿈.
2-bit predictor: 예측이 2번 틀려야 바꾼다.

* 예측을 하더라도 target 주소 계산값은 1사이클 뒤에 알게 됨
-> 이를 brach target 버퍼를 통해 해결
-> 즉시 계산값을 가져올수 있다.
예외와 인터럽트
1. 종류
- Unexpected : 순차적으로 flow가 진행되다가 갑자기 변화가 발생했을 때
- Exception: CPU안에서 발생
- Interrupt: I/O 컨트롤러의 작동에 의해
2. MIPS에서 Exceptions Handling
(1) 원래 pc값을 EPC(Exception Program Counter)에 저장해서 돌아올 곳 저장.
(2) 어떤 문제인지 Cause register에 저장.
-> 0은 정의되지 않은 opcode일때, 1은 overflow가 났을 때
(3) 문제 원인 확인 후 해결 위한 handler로 점프
-> handler 주소는 문제에 따라 달라진다
Undefined opcode일때 : C000 0000
Overflow일때 : C000 0020
(4) 재시작해야한다면?
저장된 PC값으로 이동
그렇지않다면?
프로그램 종료 등.
*파이프라인에서 예외가 발생했을 때
add $1, $2, $1 이 명령이 EX 단계에서 overflow가 났다고 가정
-> 1. $1 값 보호
2. 이전 명령들은 정상 진행
3. add 명령과 그 다음 명령들 flush
4. Cause register, EPC 값 설정
5. handler로 이동
(1) 재시작가능한 예외: 핸들러 실행하고 다시 원래 명령으로 이동
-> refetch하고 실행
**실제로 EPC 값으로 PC+4가 저장됨
-> 예외가 발생한 다음 명령이 실행되는 것
Instruction-Level Parallelism (ILP)
ILP를 증가시키기 위해
1. Deeper pipleline( 스테이지 개수가 많은 파이프라인)
-> 스테이지 당 작업속도가 줄어듦
-> 짧은 clock cycle
2. Multiple issue
-> 파이프라인 stage 복사 -> 여러개의 파이프라인
-> 한 clock cycle 당 여러 명령 시작 가능
-> 더 빨리 많은 명령 가능
-> 그러나 속도가 계속 빨라지지는 않음
* Static multiple issue
- 컴파일러가 여러 명령어들을 그룹화한다
- 컴파일러가 위험을 감지하고 회피한다
* Dynamic multiple issue
- CPU가 동시에 실행 가능한 명령어들을 선발해서 내보냄
- CPU가 위험 해결
- 컴파일러는 명령어를 재배치하여 돕는다.
MIPS with Static Dual Issue
two-issue packets
- ALU/branch와 load/store을 동시에

Dual Issue에서의 위험
파이프라인을 병렬적으로 실행하므로 더 많은 위험 발생 가능
- EX data 위험
single-issue에서는 forwarding을 사용하여 해결하지만
동시에 진행하는 거라 forwarding이 불가능
- Load-use 위험
여전히 한 사이클 stall 해야함.
-> 대신 명령어 2개가 stall
위험피하기 위해 코드 재배치

사실상 동시에 실행할 수 있는 경우가 몇번 안되서 엄청 빨라지지 못함.
Loop unrolling
loop를 재구성
-> 루프 본체를 복사
복사된 루프당 서로 다른 레지스터 사용
동일한 레지스터의 load 뒤에 store

IPC가 2에 가깝지만 레지스터의 비용이 늘고, 코드 size가 커짐
'컴퓨터구조' 카테고리의 다른 글
| chap 5- Memory(2) (0) | 2023.06.01 |
|---|---|
| Chap 5- Memory(1) (0) | 2023.05.31 |
| chap3 - Arithmetic for Computers (0) | 2023.04.12 |
| 컴퓨터구조 전공수업 ch02 (1) | 2023.03.26 |
| 컴퓨터구조 전공수업 ch01. (0) | 2023.03.26 |