Altifigence Academy

24 / 37 · 실습

실습: 스스로 실패를 보고하는 테스트벤치

DUT·자극·참조 모델·판정을 분리하고 reset·enable·순환을 레이스 없는 관찰 시점에서 검사합니다.

구현과 검사기를 분리합니다

테스트벤치는 자극을 공급하고 기대 동작을 계산하며 불일치를 보고합니다. 합성할 회로가 아니라 시뮬레이션 코드입니다. 이 실습은 매개변수 강의의 modulo_tick을 사용합니다. 그 모듈을 modulo_tick.sv, 다음 완전한 테스트벤치를 tb.sv로 저장하세요.

명세는 동기 reset 우선, enable=0에서 count 유지와 pulse 해제, enable=1에서 modulo N 증가 및 순환 시 pulse=1입니다. DUT 내부 상태를 읽지 말고 정수 참조 count를 사용합니다.

SystemVerilog
`timescale 1ns/1ps
module tb #(parameter integer N = 5);
  localparam integer CW = (N <= 1) ? 1 : $clog2(N);
  logic clk = 1'b0;
  logic rst = 1'b0;
  logic enable = 1'b0;
  wire [CW-1:0] count;
  wire pulse;
  integer expected_count = 0;
  logic expected_pulse = 1'b0;
  integer checks = 0;
  modulo_tick #(.N(N)) dut (
    .clk(clk), .rst(rst), .enable(enable),
    .count(count), .pulse(pulse)
  );
  always #5 clk = ~clk;

  task automatic step(input logic reset_value, enable_value);
    begin
      @(negedge clk);
      rst = reset_value;
      enable = enable_value;
      if (reset_value) begin
        expected_count = 0;
        expected_pulse = 1'b0;
      end else begin
        expected_pulse = 1'b0;
        if (enable_value) begin
          expected_count = expected_count + 1;
          if (expected_count == N) begin
            expected_count = 0;
            expected_pulse = 1'b1;
          end
        end
      end
      @(posedge clk);
      #1;
      if (count !== CW'(expected_count) || pulse !== expected_pulse)
        $fatal(1, "Mismatch check=%0d count=%0d expected=%0d pulse=%b expected=%b",
          checks, count, expected_count, pulse, expected_pulse);
      checks = checks + 1;
    end
  endtask

  initial begin
    if (N < 1) $fatal(1, "N must be positive");
    step(1'b1, 1'b1);
    repeat (N-1) step(1'b0, 1'b1);
    step(1'b0, 1'b0);
    step(1'b0, 1'b1);
    step(1'b0, 1'b0);
    repeat (2*N+1) step(1'b0, 1'b1);
    step(1'b1, 1'b1);
    step(1'b0, 1'b0);
    $display("PASS N=%0d checks=%0d", N, checks);
    $finish;
  end
  initial begin
    #10000;
    $fatal(1, "Timeout");
  end
endmodule

활성 에지의 레이스를 피합니다

task는 캡처보다 반 클록 앞선 하강 에지에서 입력을 정하고 다음 상승 에지의 nonblocking 갱신 후 비교합니다. 여기서 #1은 timescale과 10ns 클록을 명시한 교육용 관찰 지연입니다. 물리적인 clock-to-Q·setup·hold 분석이 아닙니다. 재사용 검증 환경에서는 clocking block이나 이벤트 영역 규칙을 더 엄밀하게 사용할 수 있습니다.

첫 step의 reset이 DUT를 알려진 상태로 만듭니다. 참조값 초기화가 DUT까지 초기화하는 것은 아닙니다. !==는 알려진 기대값과 비교할 때 뜻하지 않은 X/Z 출력을 확실한 불일치로 처리합니다.

top을 명시해 컴파일·실행합니다

Icarus Verilog가 설치된 셸에서 다음을 실행합니다.

text
iverilog -g2012 -s tb -o sim.vvp modulo_tick.sv tb.sv
vvp sim.vvp

별도 컴파일 명령에 -P tb.N=1, -P tb.N=2, -P tb.N=5, -P tb.N=8을 넣어 설정 행렬을 확인하세요. Icarus 공식 명령행 문서는 언어 모드와 top 선택 옵션을 설명합니다. 시뮬레이터마다 지원하는 SystemVerilog 범위가 다를 수 있으므로 실제 버전을 기록합니다.

검사기를 의도적으로 실패시킵니다

DUT의 종료 비교를 바꿔 한 에지 일찍 순환하게 하거나 pulse 기본 해제를 제거하세요. 적어도 하나의 시나리오가 timeout 전에 0이 아닌 실패로 종료해야 합니다. 그 뒤 올바른 소스를 복원합니다. 관련 오류를 넣어도 잡지 못하는 검사기의 통과는 약한 근거입니다.

소스 해시·N·정확한 명령·종료 코드·PASS 출력과 의도적 실패의 불일치를 보관하세요. 이 로컬 테스트벤치를 DDS 실행으로 표시하면 안 됩니다. 범용 SystemVerilog의 테스트벤치 지연과 initial 블록은 제한된 단일 클록 제품 실습 인터페이스와 별개입니다.

선택은 이 브라우저에만 적용됩니다. 언제든 푸터에서 변경할 수 있습니다.