R-type과 I-type은 MEM 스테이지가 필요가 없고, Branch inst는 MEM과 WB 스테이지가 필요가 없다.
하비 머드 렉처노트
Multi-cycle Cpu Implementation
Figure3에 있는 것처럼 다섯 단계를 구현해야한다.
RISC-V의 FSM은 JAL과 JALR 때문에 살짝 다를 수 있다. 이 두 개 빼고는 다른 디테일들은 다 똑같다.
TA는 FSM을 디자인하는 것을 다 끝내면 transition table을 만들기를 권장한다.
transition table의 간단한 형태는 Figure4에 있는거랑 같다.
더해서, RISC-V의 트랜지션 테이블은 Figure4랑 살짝 다르다. 이건 multi-cycle CPU를 만드는데 도움을 줄거다.
Control Unit Implementation
컨트롤 유닛을 만드는데 있어서는 두 개의 옵션이 있다.
하나의 옵션은 FSM base의 컨트롤 유닛 디자인을 따라하는 것이고,
다른 하나는 microprogram + microcoding 방식의 컨트롤러를 기반으로 짜는 것이다.
근데 만약에 첫번째 모델을 사용하기로 했다면 state diagram을 보고서에 적어야한다.
만약 충분히 알겠다면 microprogram-based의 컨트롤 유닛을 작성해도 된다.
여기서 중요한 것은 microprogram counter 인데, 이건 state ID를 나타내준다.
instruction이랑 microprogram counter를 사용해서 컨트롤 시그널을 만들어내야한다.
그럴려면 counter 또는 micro_counter이라는 variable을 추가해야할 거다. stage를 추적하고 control signal을 만들어내기 위해서.
지금 그냥 간단하게 생각하는 거지만
•
Address select logic: 전체 저 Microcode storage 안에서 어떤 주소로 갈건지를 정하는 것
•
Microprogram counter: 어떤 주소로 갈건지를 담고 있는 레지스터
•
1을 더해서 다시 오거나, 값을 적당히 조작해서 적절한 pc로 오게끔 설계해야하지 않을까?
•
그리고 n-bit mPC input : instruction과 현재 스테이지 ID를 받아들여서 n-bit의 microPC 값을 생성해낸다.
•
microPC값에 맞춰서 따라가면 쭉 순서대로 컨트롤 시그널의 결과를 나타내는 signal이 정의되어있어서 그걸 그대로 출력해내면 됨.
다른건 lab3랑 다 똑같고 각 스테이지는 one clock cycle이 걸린다.
integer computational instruction 에 대해서는 각 instruction이 4 cycle이 걸린다.
구현해야할 명령어
•
LUI, AUIPC → U type
◦
AUIPC
▪
pc와 Imm을 더해서(ALU 연산)
▪
rd에 저장한다.
▪
pc = pc +4
◦
LUI
▪
Imm을 (ALU 연산 없이)
▪
rd에 저장하는데, 이 때 하위 12비트는 다 0으로 한다.
▪
pc는 pc+4
•
JAL → J type
◦
pc에 imm을 더하고(ALU 연산)
◦
그 결과를 pc에 반영
◦
pc+4를 rd에 저장
•
JALR → I type
◦
Imm를 Ra1에 더하고(ALU 연산)
◦
그 결과를 pc에 반영
•
BEQ, BNE, BLT, BGE, BLTU, BGEU → B type
◦
Imm 를 pc에 더한다(ALU 연산)
◦
그 결과를 pc에 반영
◦
rd에 저장하지 않는다.
•
LG, LH, LW, LBU, LHU → I type Load
◦
Imm을 Ra1에 더하고(ALU연산)
◦
그걸 주소값으로 데이터를 읽어서
◦
rd에 저장.
◦
pc = pc +4
•
SB, SH, SW → S type
◦
Imm을 Ra1에 더하고(ALU 연산)
◦
그 주소에다가 Ra2 값을 저장함.
◦
WB하는 과정이 없다.
◦
pc = pc +4
•
ADDI (arithmetic), SLTI, SLTIU (conditional), XORI, ORI, ANDI(logical), SLLI, SRLI, SRAI (shift)
◦
Ra1과 Imm을 ALU연산하고
◦
해당 결과를 rd에 저장
◦
pc = pc +4
◦
opcode = 0010011
◦
I-type
◦
•
ADD, SUB{signed,unsigned}, SLL, SRL, SRA, (Shift) SLT, SLTU,(Conditional) XOR, OR, AND(Logical) - Rtype
◦
Ra1과 Ra2를 ALU 연산하고
◦
해당 결과를 rd에 저장
◦
opcode = 0110011
◦
func값에 따라 달라짐
◦
다만 SRA와 SRL은 func7값에 따라 달라짐
AUIPC | LUI | JAL | JALR | BEQ, BNE, BLT, BGE, BLTU, BGEU | LG, LH, LW, LBU, LHU | SB, SH, SW | ADDI (arithmetic), SLTI, SLTIU (conditional), XORI, ORI, ANDI(logical), SLLI, SRLI, SRAI (shift) | ADD, SUB{signed,unsigned}, SLL, SRL, SRA, (Shift) SLT, SLTU,(Conditional) XOR, OR, AND(Logical) - Rtype | |
IF | pc = next_pc (sequential)
IR ← MEM[pc](sequential)
next_pc = pc +4 | pc = next_pc (sequential)
IR ← MEM[pc](sequential) next_pc = pc +4 | IR ← MEM[pc](sequential)
pc = next_pc (sequential) | pc = next_pc (sequential)
IR ← MEM[pc] (sequential) | pc = next_pc (sequential)
IR ← MEM[pc] (sequential)
Imm 생성
next_pc = pc + 4 | pc = next_pc (sequential)
IR ← MEM[pc] (sequential)
next_pc = pc + 4
Imm 생성 | pc = next_pc (sequential)
IR ← MEM[pc] (sequential)
next_pc = pc + 4
Imm 생성 | pc = next_pc (sequential)
IR ← MEM[pc] (sequential)
next_pc = pc + 4
Imm 생성 | pc = next_pc (sequential)
IR ← MEM[pc] (sequential)
next_pc = pc + 4
Imm 생성 |
ID | Ra1 읽기 | Ra1과 Ra2에서 값 읽기
ALUOut ← pc + Imm
next_pc = ALUOut | Ra1 값 가져오기 | Ra1, Ra2 값 가져오기 | Ra1 값 가져오기 | Ra1 값 가져오기 | |||
EX | ALUOut ← pc + Imm | ALUOut ← pc + imm
next_pc = ALUOut | ALUOut ← Ra1 + Imm
next_pc = ALUOut | Ra1과 Ra2로부터 값 비교해서 ControlUnit에 넣기 | ALUOut ← Imm + Ra1 | ALUOut ← Imm + Ra1 | ALUOut ← Imm + Ra1 | ALUOut ← Imm + Ra1 | |
MEM | MDR ← MEM[ALUOut] | MEM[ALUOut] ← Ra2 | |||||||
WB | RF[rd] ← ALUOut | RF[rd] ← Imm | RF[rd] ← ALUResult = pc + 4 | RF[rd] ← ALUResult = pc + 4 | RF[rd] ← MDR | RF[rd] ← ALUOut | RF[rd] ← ALUOut |
Riscv_top
sequential logic
1.
pc ← next_pc로 이동시키는게 목적
적절한 사이클에서 pc를 옮겨붙여야하는데, 이 때 필요한 조건이 I_MEM_DI와 stage
현재 I_MEM_DI값과 stage값을 이용해서 pc를 옮길지 말지를 결정하고
옮긴다면 pc ← next_pc로 하고 stage를 IF로 리셋
안 옮긴다면 현재 stage값을 어디로 이동시킬지를 결정
Control Signal
ASel
•
00: reg_A
•
01: pc
•
10: oldPC
BSel
•
00 : reg_B
•
01 : imm
•
10 : 4
pcSel
•
0: AluResult(즉시 계산값)
•
1: AluOut(저장값)
wbSel
•
00: AluOut
•
01: D_MEM_OUT
•
10: AluResult
•
11: Imm
Instruction | stage | regA_Con | regB_Con | pcWrite | IRWrite | regWrite | oldPc_write | ASel | BSel | AluRegCon | isSign | pcSel | wbSel | memWrite |
ADD, SUB{signed,unsigned}, SLL, SRL, SRA, (Shift) SLT, SLTU,(Conditional) XOR, OR, AND(Logical) - Rtype | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
ID | 1 | 1 | 0 | 0 | 0 | 0 | 00 | 00 | 0 | 0 | 0 | 00 | 0 | |
EX | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 00 | 1 | 명령어 따라 적당히 | 0 | 00 | 0 | |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 00 | 00 | 0 | 0 | 0 | 00 | 0 | |
ADDI (arithmetic), SLTI, SLTIU (conditional), XORI, ORI, ANDI(logical), SLLI, SRLI, SRAI (shift) | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
ID | 1 | 1 | 0 | 0 | 0 | 0 | 00 | 01 | 0 | 0 | 0 | 00 | 0 | |
EX | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 01 | 1 | 명령어 따라 적당히 | 0 | 00 | 0 | |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 00 | 01 | 0 | 0 | 0 | 00 | 0 | |
LG, LH, LW, LBU, LHU | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
ID | 1 | 1 | 0 | 0 | 0 | 0 | 00 | 01 | 0 | 0 | 0 | 01 | 0 | |
EX | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 01 | 1 | 명령어 따라 적당히 | 0 | 01 | 0 | |
MEM | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 01 | 0 | 0 | 0 | 01 | 0 | |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 00 | 01 | 0 | 0 | 0 | 01 | 0 | |
SB, SH, SW | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
ID | 1 | 1 | 0 | 0 | 0 | 0 | 00 | 01 | 0 | 0 | 0 | 00 | 0 | |
EX | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 01 | 1 | 1 | 0 | 00 | 0 | |
MEM | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 01 | 0 | 0 | 0 | 00 | 1 | |
JAL | IF | 0 | 0 | 0 | 1 | 0 | 1 | 01 | 01 | 0 | 0 | 0 | 00 | 0 |
EX | 0 | 0 | 1 | 0 | 0 | 0 | 01 | 01 | 1 | 0 | 1 | 00 | 0 | |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 10 | 10 | 0 | 0 | 1 | 10 | 0 | |
JALR | IF | 0 | 0 | 0 | 1 | 0 | 1 | 00 | 01 | 0 | 0 | 1 | 10 | 0 |
ID | 1 | 0 | 0 | 0 | 0 | 0 | 00 | 01 | 0 | 0 | 1 | 10 | 0 | |
EX | 0 | 0 | 1 | 0 | 0 | 0 | 00 | 01 | 1 | 0 | 1 | 10 | 0 | |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 10 | 10 | 0 | 0 | 1 | 10 | 0 | |
BEQ, BNE, BLT, BGE, BLTU, BGEU | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
ID | 1 | 1 | 0 | 0 | 0 | 0 | 10 | 01 | 1 | 명령어 따라 적당히 | 0 | 00 | 0 | |
EX | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 00 | 0 | 0 | 1 | 00 | 0 | |
AUIPC | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
EX | 0 | 0 | 0 | 0 | 0 | 0 | 01 | 01 | 1 | 0 | 0 | 00 | 0 | |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 01 | 01 | 0 | 0 | 0 | 00 | 0 | |
LUI | IF | 0 | 0 | 1 | 1 | 0 | 1 | 01 | 10 | 0 | 0 | 0 | 00 | 0 |
WB | 0 | 0 | 0 | 0 | 1 | 0 | 01 | 10 | 0 | 0 | 0 | 11 | 0 | |
테스트 벤치 Code Review
TB_RISCV_inst 는 I-type과 R-type integer computational instruction이다. → 4 cycle
TB_RISCV_forloop 와 TB_RISCV_sort는 간단한 for-loop와 sort algorithm을 나타낸다.
TB_RISCV_inst는 각 명령어 실행의 아웃풋 값을 체크한다. 한 번에 한 명령을 실행하고 각 명령의 정확도를 체크한 다음, 그 다음 instruction으로 넘어간다. 따라서 이거 먼저 테스트하셈.
testbench 파일에서
•
riscv_clkrst1 : clock이랑 reset 시그널을 생성한다.
•
riscv_top1: datapath를 생성한다. major sequential logics를 포함하지 않는다.
•
i_mem1 은 instruction memory를 생성한다.
•
d_mem1 은 데이터 메모리를 만든다.
•
reg_file1 은 register file을 만든다.
모든 모듈은 RSTn signal로 초기화된다. 추가로 모든 코어, 메모리, 레지스터파일은 CLK signal과 동기화되어있다.
core module만 작성하면 된다.
Core module
I_MEM_CSN : RSTn이 1일 때 0으로 선언된다, 아니면 1
I_MEM_DI : 코어가 instruction 메모리에서 받는 값을 의미
I_MEM_ADDR : instruction memory에 접근할 때 주소
D_MEM_CSN : RSTn이 1일 때 0으로 선언된다, 아니면 1
D_MEM_DI : 코어가 data 메모리에서 받는 값을 의미
D_MEM_DOUT:
D_MEM_ADDR : data memory에 접근할 때의 주소
D_MEM_WEN
D_MEM_BE
RF_WE : Register FileWrite Enable, 1로 하면 쓰기가 가능하다.
RF_RA1: register1의 주소
RF_RA2: register2의 주소
RF_WA : 목적 레지스터의 주소
RF_WD: 레지스터 파일에 쓰여질 data
RF_RD1, RF_RD2: RF_RA1과 RF_RA2에서 읽을 데이터들
코어 모듈과 레지스터 파일은 wire로 연결되어있다. core module은 register 파일에서 일고 쓸 수 있다.
Instruction Memory
hex파일이 있는 경로를 ROMDATA에다가 넣어줘야한다.
DOUT : instruction 자체
궁금한거
각 명령어 타입별로 몇 사이클인지 어떻게 아냐..? → 사이클 개수 보고 그레이딩한다는데..?
우리가 배울 땐 instruction memory 랑 data memory가 합쳐진걸 배웠는데...?
그냥 새로 디자인하란건가
Branch에서 pcUpdate 값은 무조건 1을 뱉고
is_branch 값과 br_result 값을 이용하도록 하자