Search

Lab4

Lab4(1).pdf
1677.7KB
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 값을 이용하도록 하자