본문 바로가기

실전! Verilog HDL RTL Design

[Verilog HDL] 5. Testbench

반응형

module 설계가 끝나면 원하는 동작을 하는지 검증해야 한다. 이를 위해 적당한 입력을 가하고 출력을 모니터 해서 검사하는 코드를 만들어야 하는데 이를 testbench 라고 한다.

Testbench는 검증하고자 하는 기능에 따라 여러가지 형태로 코딩할 수 있는데 사용자가 입력을 명시적으로 정의하여 테스트 하는 기법을 direct test라고 하고 입력을 랜덤하게 정의하여 사용하는 것을 random test라고 한다. 일단은 기본적인 direct test의 한 가지 예를 아래에 코딩하였다.

`timescale 1ns/1ps                             // time unit / time resolution --------------(1) 
module test;                                   // module name 

reg  [7:0] a, b;                               // reg type input variable ------------------(2) 
wire [7:0] y;                                  // wire type output variable 

initial                                        // ------------------------------------------(3) 
begin 
        a = 5;                                 // ------------------------------------------(4) 
        b = 2; 
        #10;                                   // ------------------------------------------(5) 
        $display("A=%d, B= %d, Y=%d", a, b, y);// ------------------------------------------(6) 
        a = 2; 
        b = 10; 
        #10; 
        $display("A=%d, B= %d, Y=%d", a, b, y); 
        a = 9; 
        b = 23; 
        #10; 
        $display("A=%d, B= %d, Y=%d", a, b, y); 
        $finish();                             // ------------------------------------------(7)
end 
adder u_adder (                                // module instanciation ---------------------(8) 
        .A(a),                                 // named port mapping -----------------------(9)
        .B(b), 
        .Y(y) 
); 
endmodule

 

코드에 대한 설명은 아래와 같다.

(1) Time unit 정의

`timescale 1ns/1ps

simulator에서 사용하는 time unit과 resolution을 정의한다. 형식은 아래와 같다.

`timescale [time unit] / [time resolution]

위의 code에서 time unit은 1ns 이고 time resolution은 1ps이다. verilog에서 시간 지연 (delay)를 표시할 때는 #뒤에 지연 시간을 붙여서 사용한다. 예를 들어 #2는 time unit이 1ns일 때 2ns를 말한다.

time unit이 10ns이면 20ns가 되는 것이다. 소숫점 아래는 time resolution에서 지정한 정밀도로 지연시간을 표시할 수 있다. 예를 들어 #2.021 은 time unit이 1ns이고 time resolution이 1ps일 때 2.021 ns 가 된다. 하지만 time resolution이 10ps라면 소숫점 3자리인 0.001은 무시되고 2.02ns가 적용된다. time resolution에 대한 관계를 table로 정리하면 아래와 같다.

지연 시간 (delay)/Time resolution 1ps 10ps 100ps
#10.123 10.123 ns 10.12 ns 10.1 ns

(2) 신호 변수 선언

reg [7:0] a, b;

변수 a,b를 reg type으로 선언한다. reg type 변수는 begin/end block안에서만 사용할 수 있다.

wire [7:0] y;

변수 y를 wire type 으로 선언한다.  assign 문으로 값을 할당할 수 있고 module의 port간 연결할 때 매개 변수로 사용한다.

(3) initial

verilog에서 initial로 시작하는 begin/end block은 block안의  문장을 simulation시작 시점 부터 순차적으로 수행한다.

하나의 모듈안에 initial 구문을 여러개 사용 할 수 있고, 각 initial block은 서로 동시에 수행된다.

*verilog에서 동시 실행 (concurrent execution)에 대하여

verilog는 hw를 설계하기 위한 언어이기 때문에 동시성을 구현하기 위한 구조를 갖고 있다. 대표적으로 initial, always로 시작하는 begin/end block은 서로 동시 실행되는 hardware block을 의미한다.

(4) adder 입력 변수 a,b에 임의 값을 할당하면 이 값이 adder의 입력 port를 통해 전달 된다. 입력이 8bit이기 때문에 8bit를 초과하는 값은 LSB 8bit만 입력된다.

(5) 지연 시간 주기

#10;

입력 값을 주고 일정 시간 뒤에 출력 값을 모니터링 하면 더하기 결과가 출력 됨을 알 수 있다.

여기서는 10ns 지연 시간을 발생 시킨다. timescale에서 정의한 단위로 지연 시간을 표현한다.

(6) 변수 값을 출력 하기

$display는 C언어에서 printf문과 같이 문자열과 변수 값 등을 출력하는데 사용한다. 이 테스트벤치를 예로 들면 입력 변수 a,b와 출력 변수 y를 출력해서 결과가 맞게 나오는 지 확인하는 용도로 사용하고 있다. a,b,y 변수가 출력될 위치에 서식 문자 %d를 사용하여 십진수 로 출력한다.

기본적으로 따옴표 안에 문자열을 출력하는 데 %[문자] 형태의 서식 문자를 통해 변수 등을 대입하여 출력 할 수 있다. 사용되는 대표적인 서식 문자와 해당 형식은 아래의 표와 같다.

%b 2진수
%d 10진수
%h 16진수

$표기로 시작하는 이러한 함수를 system task라고 하는데 나중에 별도의 장을 통하여 자세히 알아보겠다.

(7) 시뮬레이션 끝내기

simulation을 끝내기 위해 $finish()라는 system task를 사용한다.

 

(8) instance 만들기

adder module을 사용하기 위하여  instance를 만드는 문장이다. 하나의 module을 설계하고 나서 그 module을 사용하려면 instance를 만들어야 한다. 이것을 사례화 (instanciation)이라고 한다. 사례화의 규칙은 아래와 같다.

'module name' 'instance name' '( port mapping );'

여기서는 adder module을 u_adder라는 이름의 instance를 만들어 사용하고 있다. 필요하면 같은 module을 다른 이름의 instance로 여러 개 만들어 사용할 수 있다. 예를 들어 아래와 같이 3개의 instance를 만들 수 있다.

adder u_adder_0 (...);
adder u_adder_1 (...);
adder u_adder_2 (...);

 

(9) port mapping

instance의 각 port를 외부 신호와 연결하는 것을 port mapping이라고 한다. port mapping에는 named mapping과 ordered mapping이 있는 데 휴먼 에러를 방지하기 위해 named mapping을 권장한다. named mapping은 '.' 뒤에 port 이름을 명기 하고 괄호안에 연결 할 신호를 써 주는 방법이다.

 

 

 

반응형