MIPS CPU의 Execute 단계가 어떻게 실행되는지 명령어의 기능에 따라 구분하여 정리하였다.
산술/논리 연산자 실행
add, sub, addi, or, and 와 같은 명령어를 실행하는 과정을 먼저 생각해보자.
우선 위 연산을 실질적으로 실행하는 유닛은 ALU 라는 유닛이 수행한다.
산술 연산과 직접적으로 관련된 명령어 포맷은 R 포맷과 I 포맷 밖에 없다.
R 포맷은 모든 피연산자가 레지스터고, 연산 결과가 레지스터로 들어간다.
I 포맷은 피연산자가 하나는 레지스터, 하나는 상수고, 연산 결과가 레지스터로 들어간다.
우선 피연산자 하나는 반드시 레지스터에서 오고, 연산 결과는 레지스터로 들어가는 것이 동일하므로 아래와 같이 그릴 수 있다.
이제 결정해야 하는 것은 R 포맷이면 레지스터로부터 ALU의 두번째 소스가 오고,
I 포맷이면 32bit로 확장했던 상수값으로부터 ALU의 두번째 소스가 온다.
명령어의 포맷에 따라 필요한 데이터가 달라지므로 이걸 결정하는 것은 Control Unit 의 역할이 될 것이다.
명령어의 포맷에 따라 ALU 의 소스로 레지스터를 사용할지 상수필드를 사용할지 결정하는 것을 ALU Src 라고 하자.
그리고 데이터를 선택하는 것과 관련된 회로 유닛은 Multiplexer 가 있다.
ALU Src 값에 따라 어떤 데이터를 고를지 mux를 이용하여 선택하도록 아래와 같이 회로를 구성하면 된다.
Data Transfer 명령어 실행
이번에는 메모리에 접근해서 데이터를 주고 받는 명령어를 실행해보자.
대표적으로 lw, sw 와 같은 명령어들이 있었다.
이 명령어는 I 포맷으로, rs 레지스터에 저장되어있는 base 주소에다가 immediate 필드에 있는 값을 그대로 더해서 접근할 새로운 메모리 주소를 계산한 다음, 메모리 데이터를 rt 레지스터에 저장하든가, rt 레지스터에 있는 값을 메모리에 저장하는 명령어였다.
이 명령어의 실행 과정을 살펴보면
1. rs 레지스터의 값와 imm 값을 가져와서 더한다. (메모리 주소 계산)
2. 메모리에 접근해서 레지스터에서 읽어온 데이터를 쓰거나, 메모리에서 읽은 데이터를 레지스터에 쓴다.
로 나눌 수 있다.
1번 과정은 이미 위에서 모두 구현해두었으니 2번 과정만 구현하면 된다.
우선 지금 그려둔 메모리는 '명령어' 가 들어있는 메모리이기 때문에, 데이터를 읽고 쓰는 메모리를 따로 분리해서 그린다.
일단 지금은 값을 쓰는 것만 한번 생각해보자.
아래와 같이 그릴 수 있다.
ALU로 들어오는 rd1 과 immediate 필드로 주소값을 계산하여 메모리에 접근한다.
ALU의 소스가 되지 않은 rd2는 메모리에 쓸 데이터이므로 메모리의 write data 로 그대로 들어간다.
그런데 값을 쓰는 행위는 매우 민감한 행위다.
따라서 메모리에 값을 쓸 때도 레지스터와 마찬가지로 write control 신호가 있을 때만 써야한다.
그리고 이 신호는 당연히 control unit 이 보내준다.
따라서 메모리에 값을 쓰는 최종 회로도는 아래와 같다.
이제 메모리에서 값을 읽어오는 경우를 생각해보자.
메모리에서 읽은 값은 레지스터에 저장해야하므로 레지스터 파일의 wd 포트로 들어가야 한다.
그런데 현재 wd 포트에는 이미 ALU의 연산결과가 들어가도록 연결되어있다.
따라서 메모리의 출력포트와 wd 포트를 바로 연결할 수 없다.
여기에서도 바로 mux 가 쓰인다.
ALU 의 연산결과 데이터와 메모리에서 읽은 데이터 중 하나를 선택해서 wd 데이터에 들어가도록 해야한다.
이 선택은 명령어 종류에 따라 달라지므로 control unit 이 결정할 일이다.
이를 결정하는 속성을 MemToReg 라고 하자.
이 속성값에 따라 다른 결과를 저장하도록 mux를 배치하면 아래와 같이 나온다.
ALU 바로 아래에 mux 를 추가 했다.
이것으로 lw 명령어도 처리할 수 있게 되었다.
이쯤에서 RegWrite 와 MemWrite 의 사용 이유에 대해 정리해보려고 한다.
왜 RegWrite, MemWrite 을 사용하는 걸까?
레지스터에 값을 쓸 때, 메모리에는 값을 쓰면 안된다.
그리고 반대로 메모리에 값을 쓸 때는, 레지스터에서 값을 읽어와서 쓰는 건데,
레지스터의 값이 변경되면 안되기 때문에 레지스터는 값을 수정할 수 없어야 한다.
그래서 메모리에 값을 쓸 때는 RegWrite 가 0 이고, 레지스터에 값을 쓸 때는 MemWrite 가 0이 된다.
둘 중 하나가 1이면 나머지 하나는 0이 되어야 한다고 이해하면 된다.
Branch 명령어 실행
이제는 PC가 순차적으로 증가하는 것이 아니라 경우에 따라 PC의 값이 변하는 분기 명령어의 실행 과정을 정리해보려고 한다.
분기명령어는 크게 조건 분기와 무조건 분기로 나뉜다.
먼저 조건 분기부터 정리해보자.
조건 분기 명령어 실행
간단하게 만들어보기 위해, 조건 분기 명령어는 beq만 있다고 가정하고, beq의 동작에 맞추어 회로를 설계해보자.
먼저 beq 명령어의 구체적인 실행과정을 이해해보자.
beq 명령어는 rs, rt 위치에 있는 레지스터 값을 비교해서 값이 같다면 label 위치로 분기한다.
정리하면 아래와 같은 과정으로 실행된다.
1. rs, rt 가 같은지 확인한다.
두 값이 같은지 확인하는 방법으로 제일 간단한 방법은 두 수를 같은 bit 선상에 두고
bit 값을 하나하나 비교해서 같은지 판단할 수 있다.
(이 방식이 제일 간단하기도 하고, 내 생각에도 그냥 xor 연산으로 모두 0이 나오는지만 보면 되니 단순할 것 같다.)
두번째 방법은 rs - rt가 0 인지 확인한다.
뺄셈이 사실은 2의 보수도 취해야되고 하다보니 더 복잡한 과정이다.
하지만 어떻게 구현하든 산술/논리 연산을 하는 것은 맞으니 ALU로 들어가서 연산한 결과를 토대로 판단을 해야한다.
2. 같다면 ( = 0이라면) 다음 실행할 명령어의 주소를 새로 계산해서 적용한다.
다음 실행할 명령어의 주소는 PC + 4 에 immediate << 2 를 더한 값으로 설정한다.
우선 두 수가 같은지 다른지 확인하는 과정은 ALU를 사용하면 되니 회로도로 충분히 실행할 수 있다.
그렇다면 추가적으로 해야할 작업은 그 연산 결과가 0인지 확인해서 분기하기로 결정하는 것이다.
이 과정을 하려면 크게 2가지 판단을 해야 한다.
1. 조건 분기인가 무조건 분기인가 판단
2. 조건분기라면 조건에 맞는지 판단
그래서 1번 2번이 모두 만족하면 그 때 새로운 PC 주소를 세팅하도록 한다.
우선 1번은 Control Unit 이 명령어를 보고 판단해야 한다.
이 세팅을 Bracch 라고 하자.
그리고 2번은 beq 기준으로 값을 빼든 xor 연산으로 비교하든 결과가 0이어야 하므로 zero 라고 세팅이름을 짓자.
이 두 값이 모두 참이여야 프로그램 카운터의 값을 바꾸도록 허용한다.
프로그램 카운터의 값을 바꾸도록 허용하는 세팅을 프로그램 카운터의 새로운 입력 src 를 결정한다는 의미에서 PC Src 라고 하자.
그러면 아래와 같이 그릴 수 있다.
AND 게이트를 사용하여 zero 속성과 branch 속성이 모두 참인지 확인한다.
여기에서 한가지 의문이 들었는데, zero 라는 패스가 ALU의 연산결과와 별도 패스로 빠지는 이유가 궁금했다.
그런데 생각해보니 필요한게 0인지 아닌지 확인하는 1 bit 정보만 필요한거라면 별도 패스로 빼는게 맞다고 이해했다.
이제 PC Src를 통해 분기 여부가 결정되었으니 이를 활용해서 다음 PC 의 값을 결정해보자.
우선 만약 분기를 하기로 결정했을 때 새로 분기할 주소를 미리 계산해두어야한다.
이 값은 기존 PC + 4 에 imm 필드에 << 2 를 한 값을 더해야한다.
따라서 imm 필드에 << 2 를 연산한 값과 PC + 4 를 더하는 연산을 아래와 같이 추가한다.
그리다보니 공간이 모자라서 아래로 조금 빠져나갔지만.. 이렇게 나왔다.
여기에 다음 PC 값으로 PC + 4 를 사용할 것인지, PC + 4 + (imm << 2) 를 사용할 것인지 결정하면 된다.
이는 PC Src 를 이용한 mux를 이용하면 되니 위와 같이 mux를 추가해주었다.
공간이 모자라서 기존 fetch 회로도를 조금 수정하였다.
무조건 분기 명령어 실행
이제 J 포맷 명령어를 다룰 차례다.
J 포맷은 imm 필드가 26비트가 들어온다.
pc + 4 의 상위 4비트에 26 비트를 imm 값을 << 2 연산한 결과를 or 로 합친 것으로 다음 분기 주소를 결정하므로
우선 이 연산을 통해 jump 를 하는 것으로 결정되었을 경우 건너갈 주소를 계산하자.
J포맷의 imm 필드는 애초에 다른 사이즈로 들어오기 때문에 아예 새로운 데이터패스를 그려줘야 한다.
새로운 데이터패스로 받은 26bit immediate필드를 2bit 시프트해서 28bit로 만들고, pc+4의 상위 4개 비트와 합쳐준다.
이제 이 결과물과 만약 이전 mux에서 조건분기가 선택되지 않아 pc+4를 하게 되었을 때 pc + 4 중에서 어떤 것을 선택할 지 결정하면 된다.
이것도 Control Unit 이 선택해주면 된다.
선택과 관련된 것이니 mux 를 사용하면 되고, 선택의 기준이 되는 속성의 이름은 jump 라고 하자.
그러면 아래와 같이 회로도를 완성할 수 있다.
최종 완성된 Single Cycle 회로도
내가 그린 싱글 사이클 MIPS CPU 회로도이다.
아래는 강의록에 있는 최종 완성 회로도이다.
'CS > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] 15. Single Cycle MIPS - Control Unit (0) | 2024.05.29 |
---|---|
[컴퓨터 구조] 14. Single Cycle MIPS - 회로 정리 & ALU (0) | 2024.04.21 |
[컴퓨터 구조] 12. Single Cycle MIPS - Decode (0) | 2024.04.19 |
[컴퓨터 구조] 11. Single Cycle MIPS - Fetch (0) | 2024.04.19 |
[컴퓨터 구조] 10. Single Cycle MIPS - 개요 (0) | 2024.04.18 |