앞에서 Fetch - Decode - Execute 순으로 회로를 점차 개선하는 과정을 보였었다.
이번에는 이를 한번에 정리해서 명령어별로 어떤 데이터 패스를 통해 실행되는지 정리하려고 한다.
그리고 ALU 가 연산자별로 연산을 택하는 그 구체적인 과정도 함께 정리한다.
lw 명령어 실행하기
fetch
lw 명령어를 실행하는 과정을 하나씩 그려보자.
먼저 명령어를 가져올 메모리와, PC 레지스터가 필요하다.
다음과 같이 그렸다.
이제 메모리에서 읽어온 명령어를 decode 해야한다.
decode
읽어온 명령어의 31:26 비트를 보고 opcode를 파악해서 lw 명령어임을 파악한다.
25:21 비트를 reg file 의 ra에 전달해서 base address 주소를 가져온다.
다음으로는 15:0 비트를 상수필드로 보고, 그 값을 32bit 로 sign-extend 한다.
sign-extend 하기 위해 sign_ext 신호를 control unit 에게 받는다.
Execute
ALU로 base address 와 상수필드 값을 더해서 최종 메모리 주소를 계산해 메모리에 접근한다.
메모리에서 읽은 값을 레지스터의 wd 포트로 보낸다.
읽을 레지스터번호는 명령어의 20:16 비트 (rt필드)로부터 알아낸다.
reg_write 신호를 control unit 에게 받아서 레지스터에 값을 쓸 수 있도록 한다.
명령어가 다 실행되면 PC 값은 PC + 4 로 업데이트 된다.
sw 명령어 실행하기
기존 회로에서 rt 필드의 값을 메모리의 쓰기 데이터로 보내는 패스만 추가해주면 된다.
메모리에 값을 쓰는 동작을 제어하는 mem_write 신호를 control unit으로부터 받는다.
add, sub, or, and 명령어 실행하기
이 명령어들은 모두 R 타입의 명령어들이다.
우선 ALU 의 연산 결과와 메모리의 연산 결과중 하나가 레지스터 파일의 wd 포트로 들어가야 한다.
이를 선택하는 mux 를 두고, mem to reg 제어 신호를 받아서 결정하도록 한다.
그리고 R 포맷과 I 포맷은 서로 wa 주소로 쓰는 필드가 다르기 때문에 이를 결정하는 회로도 추가해주었다.
이를 결정하는 것은 reg_dst 제어 신호를 통해 결정하도록 하였다.
마지막으로 R 포맷과 I 포맷은 ALU의 소스로 들어가는 값이 상수인지 레지스터인지 다르므로 이를 결정하는 회로도 추가하였다.
이를 제어하는 신호는 ALU SRC 신호이다.
beq 명령어 실행하기
레지스터 2개로 들어온 입력이 서로 같은지 확인한다.
그리고 조건 분기인지도 확인하는 branch 제어 신호를 받는다.
PC + 4 와 상수필드에 << 2 를 적용한 결과를 더하는 회로를 추가한다.
다음으로 업데이트할 PC 값을 결정하는 로직을 추가하면 beq 명령어의 실행도 완료된다.
최종 회로
레지스터파일과 메모리에도 clock 입력을 넣어주고, control unit 을 추가했다.
ALU 설계하기
마지막으로 ALU를 설계해보자.
ALU는 덧셈, 뺄셈, and, or 같은 다양한 연산을 수행한다.
ALU는 심지어 sltu 와 같은 분기를 위한 명령도 수행한다.
ALU의 연산은 3bit 제어신호에 의해 결정된다.
다음과 같은 구조로 되어있다.
우선 F의 1, 0 번 비트를 통해서 &, |, + 연산이 결정된다는 걸 아래와 같이 작성했다.
미리 덧셈, OR, AND 연산을 해두고, F1:0 비트를 통해 어떤 걸 내보낼 지 결정한다.
다음으로 이 표를 보면 F 의 2번째 비트가 0 이면 B를 그대로 사용하고, 1이면 B에 not 연산을 취했음을 알 수 있다.
A - B 에는 B에 2의 보수를 취하기 위해 not 연산이 들어간다.
sltu 는 지금은 생각하지 말고 해보자.
이렇게 그려진다.
F2 비트의 값에 의해 not 연산 취한 B와 그냥 B 중 어떤 걸 쓸지 고른다.
이제 이 값은 and, or 연산시에 그대로 활용하면 될 것 같다.
하지만 add 연산 같은 경우, 2의 보수가 필요하므로 not B 에 +1 까지 해주어야 한다.
그런데 +1 이 F2에 존재하고 있다!
이 값을 그대로 활용해서 아래와 같이 작성한다.
이제 sltu 를 제외한 모든 연산이 구현되었다.
sltu를 이제 구현해보자.
두 unsigned 수를 비교해서 A < B 이면 1 을 세팅하고, 아니면 0을 세팅한다.
이는 수학적으로 A - B < 0 인지 확인하면 되는데, 이미 뺄셈은 회로상 구현이 되어 있으니 이걸 그대로 활용하면 될 것 같다.
이제 0보다 작은지를 확인하면 된다.
0보다 작은지 확인할 때는 덧셈기의 연산 결과 Carry out 비트가 존재하는지를 보면 된다.
어셈블리에서 정리한 이 글을 참고하면 된다.
우선 결론만 말하면 A - B 를 한 결과 Carry Out 비트가 존재하면, A < B 이므로, 이 1bit 값을 32bit로 zero extension 해서 ALU 결과로 내보내면된다. (수정 : 1bit 값을 '반전' 해서 ALU 결과로 내보내야 한다.)
한번 3 - 3 을 한다고 해보자.
이해하기 쉽게 bit는 4bit만 쓴다고 하면 아래와 같이 계산할 수 있다.
만약 3 - 4 를 한다면
이때부터는 carry out 이 없다.
따라서 이 개념을 회로도에 적용하면 아래와 같이 나온다.
이것이 7가지 연산을 수행하는 ALU의 회로도이다.
실제로는 더 많은 연산을 할 수 있으니 이보다 복잡할 것이다.
(이 회로도에서 zero extend 하기 전에 비트 반전을 시켜야 한다.)
'CS > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] 16. Single Cycle MIPS - 성능 (0) | 2024.05.29 |
---|---|
[컴퓨터 구조] 15. Single Cycle MIPS - Control Unit (0) | 2024.05.29 |
[컴퓨터 구조] 13. Single Cycle MIPS - Execute (0) | 2024.04.19 |
[컴퓨터 구조] 12. Single Cycle MIPS - Decode (0) | 2024.04.19 |
[컴퓨터 구조] 11. Single Cycle MIPS - Fetch (0) | 2024.04.19 |