RV32I - Testbench 확인

손은상·2025년 12월 22일

0. Instroduction

구현한 RV32I verilog module들을 waveform으로 잘 작동하는 지 확인한다.

Module

크게 두가지 경우만 포스팅하겠다.
1. ImmGen
2. ALU_Control

사용 Testbench skeleton

`timescale 1ns/1ps

module tb_XXX; // XXX자리에 모듈 이름

	// Dut은 simulation target source code
    
	// 1) DUT port와 같은 타입/폭으로 reg/wire 선언
    // reg : TB에서 값을 넣어주는 쪽 (즉 DUT의 input)
    // wire : DUT에서 나오는 쪽 (즉 DUT의 output)
    
    // 2) DUT의 인스턴스
    // XXX DUT( ... );
			.a(A),...
       //a-> XXX모듈에 정의된 이름
       //A -> 현재 스코프(tb)에 선언된 변수명
	// 3) 파형 덤프
    initial begin
    	$dumpfile("waves.vcd"); // simv 작동한 wave.vcd 파일 생성 코드
        $dumpvars(0, tb_XXX);//모듈의 모든 신호 변화 기록
    end
    
    // 4) 자극주기 ( initial/awlays block)
    initial begin
    	//입력 변화 주고
        //#딜레이로 시간 흘러보내고
        $finish;
    end
endmodule
    	


1. ImmGen 확인

1) ImmGen.v source code

module ImmGen(
    input wire [31:0] instr,
    input wire [2:0] immSrc,


    output reg [31:0] Imm
);

/*
    immSrc
    000 : I-type

    001 : S-type

    010 : B-type

    011 : J-type
    
    100 : U-type

    101, 110, 111 : are not used
*/
wire [31:0] imm_i = {{20{instr[31]}},instr[31:20]};
wire [31:0] imm_s = {{20{instr[31]}},instr[31:25],instr[11:7]};
wire [31:0] imm_b = {{20{instr[31]}},instr[7], instr[30:25], instr[11:8], 1'b0};
wire [31:0] imm_j = {{12{instr[31]}},instr[19:12],instr[20],instr[30:21],1'b0};
wire [31:0] imm_u = {instr[31:12],12'b0};


always @(*) begin
    case(immSrc) 
        3'b000 : Imm = imm_i;
        3'b001 : Imm = imm_s;
        3'b010 : Imm = imm_b;
        3'b011 : Imm = imm_j;
        3'b100 : Imm = imm_u;
        default : Imm = 32'd0;
    endcase

end


endmodule

2) tb_ImmGen.v source code design

instr 값을 고정시키고, immSrc에 따라 각 type별 Imm값이 잘 도출되는지 확인한다.

  1. instr는 모든 타입을 구별할 수 있는 적당한 값으로 설정한다.
    (32'b 1010 1010 1010 1010 1010 1010 1010 1010)

  2. immSrc의 값만 변화를 주어 type별 Imm 값 확인한다. (3'b000 으로 초기값 설정 후 100ns 마다 1 씩 증가시켰다.

  3. ImmGen.v에 따라 각 type별 예상되는 값은 다음과 같다.

    I-type : FFFFFAAA (1111 1111 1111 1111 1111 1010 1010 1010)
    S-type : FFFFFAB5 (1111 1111 1111 1111 1111 1010 1011 0101)
    B-type : FFFFFAB4 (1111 1111 1111 1111 1111 1010 1011 0100)
    J-type : FFFAA2AA (1111 1111 1111 1010 1010 0010 1010 1010)
    U-type : AAAAA000 (1010 1010 1010 1010 1010 0000 0000 0000)


3) tb_ImmGen.v source code

`timescale 1ns/1ps

module tb_ImmGen;

reg [31:0] instr;
reg [2:0] immSrc;
wire [31:0] Imm;

integer i;

ImmGen DUT(
    .instr(instr),
    .immSrc(immSrc),
    .Imm(Imm)
);

initial begin
    $dumpfile("waves_ImmGen.vcd");
    $dumpvars(0,tb_ImmGen);
end

initial instr =32'b10101010101010101010101010101010;

initial begin
    immSrc =3'b000;
    for(i=0;i<4;i=i+1) begin
        #100
        immSrc=immSrc+1;
    end
end

initial begin
    #1000
    $finish;
end

endmodule


4) Result

예상대로 잘 도출되었음을 확인할 수 있다.



2. ALU_Control 확인

1) ALU_Control.v source code

  • Input : [31:0] Instr, [1:0] Alu_Op

  • output : [3:0] alu_op

  • Function : Instr의 fucnt 값과, Control unit으로 부터 받은 ALU_Op 값을 기반으로 ALU에 연산을 결정하는 alu_op를 결정한다.


2) tb_ALU_Control.v source code design

밑에 모든 경우는 동시에 일어나게 설계한다.

  1. *100 ns* 마다 [1:0] Alu_Op`를 1씩 증가시켜 업데이트 한다.
  1. Alu_op = 2'b10, 2'b11 일 경우, R-type과 I-type의 연산을 확인해야한다. 따라서 10 ns 마다 funct3값을 변화시킨다.

  2. 더불어, 5 ns 마다 funct7[5]의 값을 변화시켜 모든 경우의 연산을 확인한다.

  1. ALU_Control.v에 따라 각 type별 예상되는 값은 다음과 같다.
    1. Alu_Op = 00
      - alu_op = 1 (ADD)
    2. Alu_Op = 01
      - alu_op = 2 (SUB)
    3. Alu_Op = 10 // R-type
      1. funct3
        - 000 : (funct7[5]? 1 : 2)
        - 001 : 6
        - 010 : 9
        - 011 : A
        - 100 : 5
        - 101 : (funct7[5]? 8 : 7)
        - 110 : 4
        - 111 : 3
      2. Alu_Op = 11 // I-type
      3. funct3
        - 000 : 1
        - 001 : 6
        - 010 : 9
        - 011 : A
        - 100 : 5
        - 101 : (funct7[5]? 8 : 7)
        - 110 : 4
        - 111 : 3

3) tb_ImmGen.v source code

`timescale 1ns/1ps

module tb_ALU_Control;

reg [31:0] instr;
reg [1:0] in_alu_op;
wire [3:0] out_alu_op;

ALU_Control DUT(
    .Instr(instr),
    .ALU_Op(in_alu_op),
    .alu_op(out_alu_op)
);

initial begin
    $dumpfile("waves_ALU_Control.vcd");
    $dumpvars(0,tb_ALU_Control);
end

initial begin
    instr =32'h00000000;
    in_alu_op=2'b00;
end

initial begin
    forever begin
        #100;
        in_alu_op=in_alu_op+2'b01;
        
        instr[14:12] = 3'b111;
    end
end
initial begin
    forever begin
        #5;
        instr[30] = ~instr[30];
    end
end

initial begin
    forever begin
        #10;
        instr[14:12] = instr[14:12]+3'b001;
    end
end


initial begin
    #1000;
    $finish;
end

endmodule



4) Result

Figure 2. ALU_Op = 00 일 때 결과
Figure 3. ALU_Op = 01 일 때 결과 Figure 4. ALU_Op = 10 일 때 결과
Figure 5. ALU_Op = 11 일 때 결과

예상대로 잘 도출되었음을 확인할 수 있다.

profile
1렙 대학생

0개의 댓글