RISC-V Register File, Instruction
RISC-V CPU 기본 모듈
- ALU : 연산 기능을 수행한다.
- Register File : 고속으로 데이터를 임시 저장하고 접근하는 작은 메모리 블록이다.
- PC Register : Instruction이 실행할 위치를 가지고 있는 Register이다. → Program Counter
- Instruction Memory : 프로그램 명령어를 저장하고 CPU가 실행할 명령어를 읽어오는 메모리이다.
- Data Memory : 실행 중인 프로그램이 사용하는 데이터를 저장하고 읽기/쓰기를 수행하는 메모리이다.
RISC-V Instruction Type
R - type
I-Type
IL - Type
S-Type
B-Type
U-Type
UA-Type
J-Type
JA-Type
Single Cycle vs Multi Cycle vs Pipeline
Single Cycle
: 모든 명령어가 하나의 클럭 사이클 내에서 완료되는 프로세서이다.
- 모든 명령어가 동일한 사이클 시간 내에 실행 : 가장 복잡한 명령어를 기준으로 사이클 시간이 결정된다. Propagation delay가 발생할 수 있다.
- 단순한 설계 : 설계가 상대적으로 단순하고 이해하기 쉽다.
- 낮은 효율성 : 간단한 명령어들도 불필요하게 긴 시간을 소모할 수 있다.
전파 지연 [ Propagation Delay ]
: 신호가 회로의 한 부분에서 다른 부분으로 전달되는 데 걸리는 시간이다. 모든 명령어가 하나의 클럭 사이클 내에서 완료되어야 하므로, 클럭 주기는 모든 명령어 중 가장 긴 지연 경로에 맞춰진다. 또한, 클럭 주기가 길어지면 프로세서의 최대 클럭 속도가 낮아지게 되어, 전반적인 성능이 제한될 수 있다.
Multi Cycle
: 각 명령어가 여러 개의 클럭 사이클에 걸쳐 실행되는 프로세서이다. 각 사이클은 명령어의 한 부분을 처리한다. 한 명령어가 끝나면 다음 명령어가 처리된다.
- 명령어가 여러 단계로 분할 : 각 단계는 하나의 클럭 사이클 동안 실행된다.
- 단계적 처리 : 명령어 인출[Fetch], 해독[Decoder], 실행[Execute], 메모리 접근[MemAccess], 쓰기[WriteBack] 단계로 나눠 처리된다.
- 동적인 사이클 시간 : 명령어 복잡도에 따라 필요한 사이클 수가 다르기 때문에 성능 향상이 가능하다.
- 명령어 시간 지연 : 다음 명령어 실행이 느려질 수 있다.
Pipeline
: 여러 명령어를 동시에 서로 다른 단계에서 처리한다. 명령어의 한 부분이 다음 클럭으로 넘어가게 되면, 다음 명령어의 한 부분이 실행된다.
- 병렬 처리 : 각 명령어가 서로 다른 단계에서 병렬로 처리된다. 하나의 명령어가 Decoder에 있을 때, 다른 명령어가 Fetch에 있을 수 있다.
- 파이프라인 해저드 : 데이터, 제어, 주조적 해저드가 발생할 수 있다. 한 명령어의 정보 처리가 끝나지 않아 Register File에 정보가 저장되지 않았음에도 불구하고, 다음 명령어에서 Register File의 정보를 필요로 할 수 있다.
defines.sv
`define OP_TYPE_R 7'b0110011
`define OP_TYPE_IL 7'b0000011
`define OP_TYPE_I 7'b0010011
`define OP_TYPE_S 7'b0100011
`define OP_TYPE_B 7'b1100011
`define OP_TYPE_J 7'b1101111
`define OP_TYPE_JI 7'b1100111
`define OP_TYPE_U 7'b0110111
`define OP_TYPE_UA 7'b0010111
`define ADD 4'b0000
`define SUB 4'b1000
`define SLL 4'b0001
`define SRL 4'b0101
`define SRA 4'b1101
`define SLT 4'b0010
`define SLTU 4'b0011
`define XOR 4'b0100
`define OR 4'b0110
`define AND 4'b0111
`define BEQ 4'b0000
`define BNE 4'b0001
`define BLT 4'b0100
`define BGE 4'b0101
`define BLTU 4'b0110
`define BGEU 4'b0111
DataMemory.sv
`timescale 1ns / 1ps
module DataMemory ( // RAM
input logic clk,
input logic we,
input logic [31:0] addr,
input logic [31:0] wdata,
output logic [31:0] rdata
);
logic [31:0] ram [0:63];
initial begin
int i;
for (i=0 ; i<64 ; i++ ) begin
ram[i] = 100 + i;
end
end
assign rdata = ram[addr[31:2]];
always_ff @(posedge clk) begin
if (we) ram[addr[31:2]] <= wdata;
end
endmodule
DataPath.sv
`timescale 1ns / 1ps
`include "defines.sv"
module DataPath (
input logic clk,
input logic reset,
input logic [31:0] machineCode,
input logic regFileWe,
input logic [ 3:0] aluControl,
output logic [31:0] instrMemRAddr,
output logic [31:0] dataMemRAddr,
output logic [31:0] dataMemWData,
input logic [31:0] dataMemRData,
input logic AluSrcMuxSel,
input logic [ 2:0] extType,
input logic [ 2:0] RFWriteDataSrcMuxSel,
input logic branch,
input logic [ 1:0] PCMuxSel
);
logic [31:0] w_ALUResult, w_RegFileRData1, w_RegFileRData2, w_PC_Data, w_PC_IMM_Data;
logic [31:0] w_extendOut, w_AluSrcMuxOut, w_RFWriteDataSrcMuxOut;
logic [31:0] w_PCAdderSrcMuxOut, w_PC_out, w_PC_Adder;
logic w_btaken, w_PCAdderSrcMuxSel;
assign dataMemRAddr = w_ALUResult;
assign dataMemWData = w_RegFileRData2;
Register U_PC (
.clk (clk),
.reset(reset),
.d (w_PC_out),
.q (instrMemRAddr)
);
assign w_PCAdderSrcMuxSel = branch & w_btaken;
mux_2x1 U_PCAdderSrcMux (
.sel(w_PCAdderSrcMuxSel),
.a (32'd4),
.b (w_extendOut),
.y (w_PCAdderSrcMuxOut)
);
adder U_Adder_PC (
.a(instrMemRAddr),
.b(w_PCAdderSrcMuxOut),
.y(w_PC_Data)
);
RegisterFile U_RegisterFile (
.clk (clk),
.we (regFileWe),
.RAddr1(machineCode[19:15]),
.RAddr2(machineCode[24:20]),
.WAddr (machineCode[11:7]),
.WData (w_RFWriteDataSrcMuxOut),
.RData1(w_RegFileRData1),
.RData2(w_RegFileRData2)
);
mux_2x1 U_ALUSrcMux (
.sel(AluSrcMuxSel),
.a (w_RegFileRData2),
.b (w_extendOut),
.y (w_AluSrcMuxOut)
);
alu U_ALU (
.a (w_RegFileRData1),
.b (w_AluSrcMuxOut),
.aluControl(aluControl),
.result (dataMemRAddr),
.btaken (w_btaken)
);
mux_5x1 U_RFWriteDataSrcMux (
.sel(RFWriteDataSrcMuxSel),
.a (dataMemRAddr),
.b (dataMemRData),
.c (w_extendOut), // u-type
.d (w_PC_IMM_Data), // ua-type
.e (w_PC_Adder), // j-type, i-type
.y (w_RFWriteDataSrcMuxOut)
);
extend U_Extend (
.extType(extType),
.instr (machineCode[31:7]), // except opcode
.immext (w_extendOut)
);
adder U_Adder_PC_IMM (
.a(w_extendOut),
.b(instrMemRAddr),
.y(w_PC_IMM_Data)
);
mux_3x1 U_PC_Mux (
.sel(PCMuxSel),
.a(w_PC_Data),
.b(w_PC_IMM_Data),
.c(dataMemRAddr),
.y(w_PC_out)
);
adder U_PC_Adder_4 (
.a(32'd4),
.b(instrMemRAddr),
.y(w_PC_Adder)
);
endmodule
module RegisterFile (
input logic clk,
input logic we,
input logic [ 4:0] RAddr1,
input logic [ 4:0] RAddr2,
input logic [ 4:0] WAddr,
input logic [31:0] WData,
output logic [31:0] RData1,
output logic [31:0] RData2
);
logic [31:0] RegFile[0:31];
initial begin
RegFile[0] = 32'd0;
RegFile[1] = 32'd1;
RegFile[2] = 32'd2;
RegFile[3] = 32'd3;
RegFile[4] = 32'd4;
RegFile[5] = 32'd5;
end
always_ff @(posedge clk) begin
if (we) RegFile[WAddr] <= WData;
end
assign RData1 = (RAddr1 != 0) ? RegFile[RAddr1] : 0;
assign RData2 = (RAddr2 != 0) ? RegFile[RAddr2] : 0;
endmodule
module Register (
input logic clk,
input logic reset,
input logic [31:0] d,
output logic [31:0] q
);
always_ff @(posedge clk, posedge reset) begin
if (reset) q <= 0;
else q <= d;
end
endmodule
module alu (
input logic [31:0] a,
input logic [31:0] b,
input logic [3:0] aluControl,
output logic btaken,
output logic [31:0] result
);
always_comb begin
case (aluControl)
`ADD: result = a + b;
`SUB: result = a - b;
`SLL: result = a << b;
`SRL: result = a >> b;
`SRA: result = a >>> b;
`SLT: result = (a < b) ? 1 : 0;
`SLTU: result = (a < b) ? 1 : 0;
`XOR: result = a ^ b;
`OR: result = a | b;
`AND: result = a & b;
default: result = 32'bx;
endcase
end
always_comb begin : comparator // B-Type
case (aluControl[2:0])
3'b000: btaken = (a == b); // BEQ: if (rs1 == rs2) PC += imm
3'b001: btaken = (a != b);
3'b100: btaken = (a < b);
3'b101: btaken = (a >= b);
3'b110: btaken = (a < b);
3'b111: btaken = (a >= b);
default: btaken = 1'bx;
endcase
end
endmodule
module adder (
input logic [31:0] a,
input logic [31:0] b,
output logic [31:0] y
);
assign y = a + b;
endmodule
module extend ( // immext
input logic [ 2:0] extType,
input logic [31:7] instr, // except opcode
output logic [31:0] immext
);
always_comb begin
case (extType)
3'b000: immext = {{21{instr[31]}}, instr[31:20]}; // I-Type
3'b001:
immext = {{21{instr[31]}}, instr[30:25], instr[11:7]}; // S-Type
3'b010:
immext = {
{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0
}; // B-Type
3'b011: immext = {instr[31:12], {12{1'b0}}}; // U-Type
3'b100:
immext = {
{12{instr[31]}},
instr[19:12],
instr[20],
instr[30:25],
instr[24:21],
1'b0
}; // J-Type
3'b111:
immext = {
{27{instr[31]}}, instr[24:20]
};
endcase
end
endmodule
module mux_2x1 (
input logic sel,
input logic [31:0] a,
input logic [31:0] b,
output logic [31:0] y
);
always_comb begin
case (sel)
1'b0: y = a;
1'b1: y = b;
default: y = 32'bx;
endcase
end
endmodule
module mux_3x1 (
input logic [ 1:0] sel,
input logic [31:0] a,
input logic [31:0] b,
input logic [31:0] c,
output logic [31:0] y
);
always_comb begin
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
default: y = 32'bx;
endcase
end
endmodule
module mux_5x1 (
input logic [ 2:0] sel,
input logic [31:0] a,
input logic [31:0] b,
input logic [31:0] c,
input logic [31:0] d,
input logic [31:0] e,
output logic [31:0] y
);
always_comb begin
case (sel)
3'b000: y = a;
3'b001: y = b;
3'b010: y = c;
3'b011: y = d;
3'b100: y = e;
default: y = 32'bx;
endcase
end
endmodule
ControlUnit.sv
`timescale 1ns / 1ps
`include "defines.sv"
module ControlUnit (
input logic [6:0] op,
input logic [2:0] funct3,
input logic [6:0] funct7,
output logic regFileWe,
output logic AluSrcMuxSel,
output logic [2:0] RFWriteDataSrcMuxSel,
output logic dataMemWe,
output logic [2:0] extType,
output logic [3:0] aluControl,
output logic branch,
output logic [1:0] PCMuxSel
);
logic [11:0] controls;
// logic [1:0] w_AluOp;
assign {regFileWe, AluSrcMuxSel, RFWriteDataSrcMuxSel, dataMemWe, extType, branch, PCMuxSel} = controls;
always_comb begin : main_decoder
case (op) // Opcode
// regFisleWe, AluSrcMuxSel, RFWriteDataSrcMuxSel, dataMemWe, extType, branch, PCMuxSel
`OP_TYPE_R: controls = 12'b1_0_000_0_xxx_0_00;
`OP_TYPE_IL: controls = 12'b1_1_001_0_000_0_00;
`OP_TYPE_I:
if (funct3 == 3'b001 || funct3 == 3'b101) begin
controls = 12'b1_1_000_0_111_0_00;
end
else begin
controls = 12'b1_1_000_0_000_0_00;
end
`OP_TYPE_S: controls = 12'b0_1_xxx_1_001_0_00;
`OP_TYPE_B: controls = 12'b0_0_xxx_0_010_1_00;
`OP_TYPE_J: controls = 12'b1_x_100_0_100_0_01;
`OP_TYPE_JI: controls = 12'b1_1_100_0_000_0_10;
`OP_TYPE_U: controls = 12'b1_x_010_0_011_0_00;
`OP_TYPE_UA: controls = 12'b1_x_011_0_011_0_00;
default: controls = 12'bx;
endcase
end
always_comb begin : alu_control_signal
case (op)
`OP_TYPE_R: aluControl = {funct7[5], funct3};
`OP_TYPE_IL: aluControl = {1'b0, 3'b000}; // only Add
`OP_TYPE_I:
if (funct3 == 3'b001 || funct3 == 3'b101) begin
aluControl = {funct7[5], funct3};
end
else begin
aluControl = {1'b0, 3'b000};
end
`OP_TYPE_S: aluControl = {1'b0, 3'b000}; // only Add
`OP_TYPE_B: aluControl = {1'b0, funct3};
`OP_TYPE_J: aluControl = {1'b0, 3'b000};
`OP_TYPE_JI: aluControl = {1'b0, 3'b000};
default: aluControl = 4'bx;
endcase
end
endmodule
CPU_Core.sv
`timescale 1ns / 1ps
module CPU_Core (
input logic clk,
input logic reset,
input logic [31:0] machineCode,
output logic [31:0] instrMemRAddr,
output logic dataMemWe,
output logic [31:0] dataMemRAddr,
output logic [31:0] dataMemWData,
input logic [31:0] dataMemRData
);
logic w_regFileWe, w_AluSrcMuxSel, w_branch;
logic [3:0] w_aluControl;
logic [2:0] w_extType, w_RFWriteDataSrcMuxSel;
logic [1:0] w_PCMuxSel;
ControlUnit U_ControlUnit (
.op (machineCode[6:0]),
.funct3 (machineCode[14:12]),
.funct7 (machineCode[31:25]),
.regFileWe (w_regFileWe),
.AluSrcMuxSel (w_AluSrcMuxSel),
.RFWriteDataSrcMuxSel(w_RFWriteDataSrcMuxSel),
.dataMemWe (dataMemWe),
.aluControl (w_aluControl),
.extType (w_extType),
.branch (w_branch),
.PCMuxSel (w_PCMuxSel)
);
DataPath U_DataPath (
.clk (clk),
.reset (reset),
.machineCode (machineCode),
.regFileWe (w_regFileWe),
.aluControl (w_aluControl),
.instrMemRAddr (instrMemRAddr),
.AluSrcMuxSel (w_AluSrcMuxSel),
.RFWriteDataSrcMuxSel(w_RFWriteDataSrcMuxSel),
.dataMemRAddr (dataMemRAddr),
.dataMemRData (dataMemRData),
.extType (w_extType),
.dataMemWData (dataMemWData),
.branch (w_branch),
.PCMuxSel (w_PCMuxSel)
);
endmodule
InstructionMemory.sv
`timescale 1ns / 1ps
module InstructionMemory (
input logic [31:0] addr, // 1 byte standard
output logic [31:0] data
);
logic [31:0] rom[0:63];
initial begin
rom[0] = 32'h00520333; // add x6, x4, x5
rom[1] = 32'h401183b3; // sub x7, x3, x1
rom[2] = 32'h0020F433; // and x8, x1, x2
rom[3] = 32'h0020E4B3; // or x9, x1, x2
rom[4] = 32'h00A02503; // lw x10, x0, 10
rom[5] = 32'h00A08193; // addi x3, x1, 10
rom[6] = 32'h00412223; // sw x2 4 x4 -> sw rs1, imm, rs2 -> R[rs1 + imm %] = rs2
rom[7] = 32'h00108463; // beq x1 x1 8 -> if (x1 == X1), pc + imm => pc
rom[9] = 32'h000015b7; // lui x11 1 -> 4096
rom[10] = 32'h00001617; // auipc x12 1 -> 4096 + PC
rom[11] = 32'h008006EF; // jal x13 8 -> x13 : PC+4, after PC+8
//rom[13] = 32'h00820767; // jalr x14 x4 8 -> x14 : PC+4, after PC+(x4 + 8) -> PC = 12, when PC = 12, rom[3] machineCode run
rom[13] = 32'h00C68767; // jalr x14 x13 12 -> x14 = PC+4=52, x13+12=60
rom[15] = 32'h00269793; // slli x15 x13 2 -> x13<<2 = 48<<2=192, x15=192
rom[16] = 32'h00275813; // srli x16 x14 2 -> x14>>2 = 56>>2=14, x16=14
rom[17] = 32'h40A6D09; // srai x17 x13 2 -> x13>>>2 = 48>>>2=12, x17=12 4026D893
/*
// x0 = 0, x1 = 1, x2 = 2, x3 = 3, x4 = 4, x5 = 5
//R-type
rom[0] = 32'h00520333; // add x6, x4, x5 -> 9
rom[1] = 32'h401183b3; // sub x7, x3, x1 -> 2
rom[2] = 32'h00121433; //sll x8, x4, x1 -> 8
rom[3] = 32'h001254b3; //srl x9, x4, x1 -> 2
rom[4] = 32'h40125533; //sra x10, x4, x1 -> 2
rom[5] = 32'h0030a5b3; //slt x11, x1, x3 -> 1
rom[6] = 32'h0030b633; //sltu x12, x1, x3 -> 1
rom[7] = 32'h0020c6b3; //xor x13, x1, x2 -> 3
rom[8] = 32'h0020e733; //or x14, x1, x2 -> 3
rom[9] = 32'h0020f7b3; //and x15, x1, x2 -> 0
//I-type
rom[10] = 32'h0040a803; //lw x16 x1 4 -> 101
rom[11] = 32'h00908893; //addi x17 x1 9 -> 10
rom[12] = 32'h0040a913; //slti x18 x1 4 -> 1
rom[13] = 32'h0040b993; //sltiu x19 x1 4 -> 1
rom[14] = 32'h0020ca13; //xori x20 x1 2 -> 3
rom[15] = 32'h0020ea93; //ori x21 x1 2 -> 3
rom[16] = 32'h0020fb13; //andi x22 x1 2 -> 0
rom[17] = 32'h00221b93; //slli x23 x4 2 -> 16
rom[18] = 32'h00225c13; //srli x24 x4 2 -> 1
rom[19] = 32'h40225c93; //srai x25 x4 2 -> 1
//S-type
rom[20] = 32'h00502423; //sw x0, 8 x5 -> Ram[2] = 5
//B-type
rom[21] = 32'h00108463; //beq x1 x1 8 -> pc = pc + 8
rom[23] = 32'h00209463; //bne x1 x2 8 -> pc = pc + 8
rom[25] = 32'h0020c463; //blt x1 x2 8 -> pc = pc + 8
rom[27] = 32'h00125463; //bge x4 x1 8 -> pc = pc + 8
rom[29] = 32'h0020e463; //bltu x1 x2 8 -> pc = pc + 8
rom[31] = 32'h00127463; //bgeu x4 x1 8 -> pc = pc + 8
//U-type
rom[33] = 32'h00001d37; //lui x26 1 -> 4096
//UA-type
rom[34] = 32'h00001d97; //auipc x27 1 -> pc = pc + 4096
//J-type
rom[35] = 32'h00800e6f; //jal x28 8 -> rd = pc + 4 / pc = pc + imm
//I-type
rom[37] = 32'h00810ee7; //jalr x2 x29 8 -> rd = rd = pc + 4 / pc = rs1(2) + imm(8)
*/
end
// use 4 byte (32bit)
assign data = rom[addr[31:2]]; // 0, 4, 8 ...
endmodule
RV32I.sv
`timescale 1ns / 1ps
module RV32I(
input logic clk,
input logic reset
);
logic [31:0] w_InstrMemAddr, w_InstrMemData;
logic w_dataMemWe;
logic [31:0] w_dataMemRAddr, w_dataMemRData, w_dataMemWData;
CPU_Core U_CPU_Core(
.clk(clk),
.reset(reset),
.machineCode(w_InstrMemData),
.instrMemRAddr(w_InstrMemAddr),
.dataMemWe(w_dataMemWe),
.dataMemRAddr(w_dataMemRAddr),
.dataMemRData(w_dataMemRData),
.dataMemWData(w_dataMemWData)
);
DataMemory U_RAM(
.clk(clk),
.we(w_dataMemWe),
.addr(w_dataMemRAddr),
.wdata(w_dataMemWData),
.rdata(w_dataMemRData)
);
InstructionMemory U_ROM(
.addr(w_InstrMemAddr),
.data(w_InstrMemData)
);
endmodule
schematic
tb_RV32I.sv
`timescale 1ns / 1ps
module tb_RV32I();
logic clk;
logic reset;
RV32I dut(
.clk(clk),
.reset(reset)
);
always #5 clk = ~clk;
initial begin
clk = 0;
reset = 1'b1;
#40 reset = 1'b0;
end
endmodule
schematic
1) RegisterFile
2) RAM
Assmebly Language
Instruction Set
'[하만]세미콘 아카데미 > verilog' 카테고리의 다른 글
0604 RISC-v GPO GPI GPIO (0) | 2024.07.10 |
---|---|
0603 RISC-v GPI GPO (0) | 2024.07.09 |
0523 Team Project (0) | 2024.07.09 |
0529 DedicatedProcessor stackSum (0) | 2024.07.09 |
0529 Dedicated Processor ALU (0) | 2024.07.09 |