지노랩 /JinoLab

[SystemVerilog] 1.12 계층형 테스트벤치 (Layered Testbench) 본문

SystemVerilog검증/1. 검증 가이드

[SystemVerilog] 1.12 계층형 테스트벤치 (Layered Testbench)

지노랩/JinoLab 2025. 2. 22. 11:46

현대적인 검증 방법론에서 중요한 개념 중 하나는 계층형 테스트벤치(layered testbench)이다. 처음에는 이러한 계층화 과정이 테스트벤치를 더 복잡하게 만들 것처럼 보일 수 있지만, 실제로는 코드를 더 작은 단위로 나누어 관리할 수 있도록 도와준다. 이러한 방식은 코드의 유지보수를 용이하게 만들고, 각 계층을 독립적으로 개발할 수 있도록 해준다.

단일 루틴에서 모든 종류의 자극(stimulus)을 무작위로 생성하도록 작성하는 것은 좋은 방법이 아니다. 합법적인 자극과 불법적인 자극을 모두 포함하며, 멀티 레이어 프로토콜을 사용하여 오류를 주입하는 기능까지 갖춘다면 코드가 지나치게 복잡해지고 유지보수가 어려워진다. 따라서 코드의 복잡성을 줄이고 관리가 용이하도록 계층을 나누어 설계하는 것이 바람직하다.


1.12.1 단순 테스트벤치 (Flat Testbench)

Verilog를 처음 배우고 테스트 코드를 작성할 때, 대부분 단순한 구조의 로우-레벨(low-level) 코드로 테스트벤치를 구성했을 것이다. 예를 들어, APB(AMBA Peripheral Bus)에서 데이터를 쓰는 단순한 코드가 이에 해당한다. VHDL을 사용하는 경우에도 유사한 방식으로 코드를 작성했을 것이다.

아래는 APB 버스에서 데이터를 쓰는 기본적인 Verilog 코드의 예제이다.

module test(PAddr, PWrite, PSel, PRData, Rst, clk);
// 포트 선언 생략

initial begin
    // 리셋 신호 구동
    Rst <= 0;
    #100 Rst <= 1;

    // 제어 버스 구동
    @(posedge clk)
    PAddr  <= 16’h50;
    PWData <= 32’h50;
    PWrite <= 1’b1;
    PSel   <= 1’b1;

    // PEnable 신호 토글
    @(posedge clk)
    PEnable <= 1’b1;
    @(posedge clk)
    PEnable <= 1’b0;

    // 결과 확인
    if (top.mem.memory[16’h50] == 32’h50)
        $display("Success");
    else
        $display("Error, wrong value in memory");

    $finish;
end
endmodule

이와 같은 코드를 작성하다 보면 동일한 동작을 반복해야 하는 경우가 많아 코드가 지나치게 중복되는 문제가 발생한다. 따라서 공통적인 동작을 함수 또는 태스크(task)로 정의하여 보다 효율적인 테스트벤치를 구성할 필요가 있다.


1.12.2 APB 핀을 구동하는 태스크 (A task to drive the APB pins)

테스트벤치에서 중복을 줄이기 위해, 특정한 기능(예: 버스 쓰기)을 수행하는 태스크를 정의할 수 있다. 아래는 APB 버스에 데이터를 쓰는 동작을 하나의 태스크로 정의한 예제이다.

task write(reg [15:0] addr, reg [31:0] data);
    // 제어 버스 구동
    @(posedge clk)
    PAddr  <= addr;
    PWData <= data;
    PWrite <= 1’b1;
    PSel   <= 1’b1;

    // PEnable 신호 토글
    @(posedge clk)
    PEnable <= 1’b1;
    @(posedge clk)
    PEnable <= 1’b0;
endtask

이제 테스트벤치는 태스크를 호출함으로써 보다 간결하게 구현될 수 있다.

module test(PAddr, PWrite, PSel, PRData, Rst, clk);
// 포트 선언 생략

initial begin
    reset();             // 디바이스 리셋
    write(16’h50, 32’h50);  // 메모리에 데이터 쓰기

    // 결과 확인
    if (top.mem.memory[16’h50] == 32’h50)
        $display("Success");
    else
        $display("Error, wrong value in memory");

    $finish;
end
endmodule

공통적인 동작을 태스크로 분리함으로써 코드의 효율성이 증가하고, 실수 발생 가능성이 줄어든다. 이러한 방식으로 신호 계층(signal layer)과 명령 계층(command layer)을 구성하는 것이 계층형 테스트벤치의 첫 단계이다.


1.12.3 신호 계층과 명령 계층 (The Signal and Command Layers)

테스트벤치의 가장 기본적인 계층은 신호 계층(signal layer)이다. 신호 계층은 설계 대상(DUT, Design Under Test)을 감싸며, 테스트벤치와 DUT 사이에서 신호의 흐름을 관리한다.

그 위에는 명령 계층(command layer)이 존재하며, 이 계층에서는 DUT의 입력을 직접 제어하는 드라이버(driver)가 동작한다. 드라이버는 특정한 명령(예: 버스 읽기, 버스 쓰기)을 수행하며, DUT의 출력을 모니터(monitor)가 감시하여 신호의 변화와 명령의 실행을 추적할 수 있도록 한다. 또한, 어설션(assertion) 기능을 추가하여 신호의 상태를 확인하고 특정 조건이 충족되었는지 검사할 수 있다.


1.12.4 기능 계층 (The Functional Layer)

기능 계층(functional layer)은 명령 계층을 제어하는 역할을 한다. 이 계층에서는 트랜잭션을 다루는 에이전트(agent)가 동작하며, 예를 들어, DMA 읽기 또는 쓰기와 같은 고수준의 트랜잭션을 개별 명령으로 변환하여 전달한다. 또한, 이 계층에서는 스코어보드(scoreboard)와 체커(checker)를 사용하여 트랜잭션의 결과를 예상하고, 실제 DUT의 동작과 비교하여 검증을 수행한다.


1.12.5 시나리오 계층 (The Scenario Layer)

시나리오 계층(scenario layer)은 테스트의 최상위 계층으로, 기능 계층을 구동하는 역할을 한다. 시나리오는 DUT가 수행해야 하는 일련의 작업들을 의미한다. 예를 들어, MP3 플레이어라면 음악을 저장소에서 재생하고, 새로운 음악을 다운로드하며, 사용자 입력을 처리하는 일련의 작업이 시나리오가 될 수 있다.

시나리오 계층에서는 이러한 작업들을 조합하여 다양한 검증 시나리오를 만들고, 제약 조건이 적용된 랜덤 값을 이용하여 다양한 변수(예: 트랙 크기, 메모리 위치)를 설정할 수 있다.


1.12.6 테스트 계층과 기능 커버리지 (The Test Layer and Functional Coverage)

테스트 계층(test layer)은 테스트벤치의 최상위 계층으로, 실제로 검증을 수행하는 역할을 한다. 이 계층에서는 각 테스트 시나리오를 실행하고, 기능 커버리지(functional coverage)를 측정하여 검증이 얼마나 진행되었는지를 평가한다.

기능 커버리지는 테스트가 검증 계획에서 요구하는 모든 조건을 충족하고 있는지를 판단하는 지표로 사용된다. 검증이 진행됨에 따라 커버리지 코드는 지속적으로 변경될 수 있으며, 따라서 검증 환경(environment)과는 별도로 관리된다.

또한, 테스트 계층에서는 "지시적 테스트(directed test)"를 생성하여 랜덤 테스트 환경에서 특정한 시나리오를 추가적으로 검증할 수 있다. 지시적 테스트는 특정한 동작을 유도할 수 있으며, 예상하지 못한 블록에서 버그가 발생할 가능성을 높일 수도 있다.

 

 

 

 

Chris Spear 저자님의

SystemVerilog For Verification

A Guide to Learning the Testbench Language Features

내용을 기본으로 작성되었습니다.

 

 

 

 

#노진호의SECA #SECA #Academy #SystemVerilog #Verification