- IF (Instruction Fetch to Program Counter from memory)
- ID (Instruction Decode)
- EX (Execution) (일반적으로 ALU에서 동작하는 부분)
- MEM (Memory)
- WB (Write Back)
- 다음은 PC(Program Counter)에서 다음 실행할 명령어를 fetch하고, decode를 위해 내보내는 과정이다.
- Register -> ALU -> Register
- PC에 적혀있는 메모리 주소를 받아오면, 해당 주소의 메모리로 접근해 Instruction을 가져오고 decode를 위해 Instruction을 내보낸다.
- 명령어의 길이는 32bit(4byte)이므로 메모리 상 4칸 씩 띄워져있다. (한 메모리 주소 당 1byte 값을 저장하므로) 따라서 PC = PC+4 만큼 다음에 계산해 실행할 명령어(다음 줄의 명령어)를 PC에 저장할 수 있도록 Input에 넣고 대기한다.
- write enable 신호가 있는 상태에서, Clock Rising Edge를 만나면 PC의 state가 Input 값으로 바뀐다.
- 다음은 R-format Instruction이 작동하는 과정이다.
- Register -> (ImmGen) -> ALU -> DataMemory -> Register
- Instruction의 rs1 (5-bit), rs2, rd를 각각 받는다.
- rs1: Read Register 1 (5-bit)
- rs2: Read Register 2 (5-bit)
- rd: Write Register (5-bit)
- (General Purpose Integer Register는 32개가 있으므로 5-bit이다.)
- rs1과 rs2의 값을 ALU의 Input으로 넣어 계산한다.
- ALU가 할 계산은 ALU Operation에 따라 정해지며, ALU Operation은 Instruction의 opcode, function bits을 보고 판단한다.
- Input이 들어오면 바로 Output이 나온다. 왜냐하면 Combinational Logic 이기 때문에 edge rising을 기다릴 필요가 없다.
- 연산된 값은 rd에 적을 값의 input값으로 대기하고 있으며, RegWrite 신호가 활성화된 후 Clock Rising Edge를 만나면 rd의 state가 변경된다.
- 다음은 Load or Store Instruction이 작동하는 과정이다.
- Register -> (ImmGen) -> ALU -> DataMemory -> Register
- Instruction의 rs1과 rd, 그리고 Immediate 값을 가져온다.
- rs1: Read Register 1 (메모리 주소가 저장된 레지스터)
- rd: Write Register (값을 저장할 레지스터 주소)
- Imm12: (Offset 값)
- Imm12값은 Immediate Generator를 통해 64bit 명령어로 확장한다.
- rs1의 값(64bit)과 Immgen으로 만들어진 값(64bit)을 ALU를 통해 더한다.
- 더한 값을 메모리 주소로 하여금 접근해 MemRead 신호가 있을 경우 읽는다.
- 메모리에서 가져온 값을 rd 값의 input으로 대기하고, RegWrite 신호가 들어온 후 Clock Rising Edge를 만나면 rd의 state가 변경된다.
- 다음은 Branch Instruction이 작동하는 과정이다.
- Register -> ALU -> ImmGen -> PC
- Instruction의 rs1과 rs2 값을 가져온다.
- rs1: Read Register 1
- rs2: Read Register 2
- ALU에서는 rs1과 rs2를 뺀 값이 0인지 확인하고 zero flag를 띄울지 판단한다.
- 조건에 만족할 경우 branch Immediate 값을 ImmGen을 거쳐 sign-extended 64-bit으로 바꾸고, shift left 1만큼 하여 PC를 변경한다
- shift left 1을 하는 이유는 RISC-V는 16-bit Instruction도 지원하기 위해서이다.
- 다음은 R-type과 Load/Store를 합친 것이다.
- R-type은 rs1, rs2가 있으며, Load/Store은 rs1만 있고, rs2 대신 Immediate 값이 온다. 따라 Mux로 값을 선택한다.
- rd에 값을 적을 때, R-type은 ALU로 연산한 값이, Load/Store은 Memory로부터 읽은 값을 저장한다. 따라서 Memory 뒷 단에 Mux를 둔다. (앞 단이 아닌 뒷단인 것이 핵심이다.)
- 각각의 Mux가 실행해야할 것들을 정하는 것은 Instruction Decode 단계에서 opcode를 기반으로 정해준다.
- 핵심: rs2 vs Imm (ALUSrc), MEM vs ALURes (MemToReg)
- 위 사진을 정확히 이해하자.
- Control signal은 opcode와 function bit으로 만든다. (PCSrc 제외)
- 모든 Controler signal은 Instruction을 보고 만들 수 있다 (X)
- 대부분 Controler signal은 Instruction을 보고 만들 수 있다 (O)
- PCSrc는 Branch Signal + ALU의 Zero Signal을 AND 연산하여 만든다.
- ALU Control은 ALUOp(Opcode) + function bit으로 만든다.
- Signal of R-Type (Register -> ALU -> Register)
RegWrite: 1 (rd에 쓰는 작업이 있기 때문)
ALUSrc: 0 (rs2 사용하기 때문)
ALUOp: function bits에 따라 달라짐
MemWrite: 0 (Memory 접근 X)
MemRead: 0 (Memory 접근 X)
MemtoReg: 0 (Memory에서 Reg로 가는 것이 아닌, ALU 값이 바로 Reg로 감)
Branch: 0 (Branch 명령어 아님)
- Signal of Load (Register -> ImmGen -> ALU -> Mem -> Register)
RegWrite: 1 (rd에 쓰는 작업이 있기 때문)
ALUSrc: 1 (rs2가 아닌 Imm값을 사용)
ALUOp: ADD (offset 값을 항상 더함)
MemWrite: 0 (메모리 쓰기 작업 사용X, Store가 아님)
MemRead: 1 (Load이므로 Memory 읽기 작업)
MemtoReg: 1 (Memory에서 Reg로 바로 감)
Branch: 0 (Branch 명령어 아님)
- Signal of Store (Register -> ImmGen -> ALU -> Mem)
RegWrite: 0 (rd에 쓰는 작업 없음)
ALUSrc: 1 (rs2가 아닌 Imm값을 사용)
ALUOp: ADD (offset 값을 항상 더함)
MemWrite: 1 (Store이므로 Memory 쓰기 작업)
MemRead: 0 (메모리 읽기 작업 사용X, Load가 아님)
MemtoReg: X (메모리 쓴 후 명령어 종료)
Branch: 0 (Branch 명령어 아님)
- Signal of Branch (Register -> ImmGen -> ALU -> PC)
RegWrite: 0 (rd에 쓰는 작업 없음)
ALUSrc: 0 (rs2값 사용)
ALUOp: SUB (항상 빼기 연산을 통해 zero signal 여부를 판단)
MemWrite: 0 (Store이므로 Memory 쓰기 작업)
MemRead: 0 (메모리 읽기 작업 사용X, Load가 아님)
MemtoReg: X (메모리 쓴 후 명령어 종료)
Branch: 1 (Branch 명령어 아님)
(+) PCSrc: Branch AND Zero