Systemverilog -> force, release, deposit 기능에 대하여

SystemVerilog force, release, deposit 완벽 가이드: 테스트벤치 시그널 제어의 모든 것

🎮 SystemVerilog force, release, deposit 완벽 가이드

테스트벤치 시그널 제어의 모든 것 — 검증 엔지니어를 위한 실전 레퍼런스

검증 중 특정 시그널을 강제로 제어하거나, 에러를 주입하거나, DUT 내부 상태를 조작해야 할 때가 있습니다. force, release, deposit은 이런 상황에서 강력한 도구입니다. 이 글에서는 각 명령어의 동작 원리부터 실전 활용 패턴까지, 파형 시각화와 함께 상세히 설명합니다.

🎯 1. 개요 및 사용 목적

검증 과정에서 시그널 제어가 필요한 상황들입니다.

📌 언제 사용하는가?

• 에러 주입 (Error Injection): 정상 동작 중 강제로 에러 상태 만들기
• 코너 케이스 테스트: 특정 조건을 강제로 생성
• 초기화 우회: 긴 초기화 시퀀스를 건너뛰기
• 디버깅: 특정 값에서 동작 관찰
• X 상태 제거: 시뮬레이션 초기 X 값 해결

DUT 정상 동작
force로 제어
테스트 수행
release로 복원

💪 2. force 명령어

force 시그널 강제 제어

force는 시그널의 모든 드라이버를 무시하고 지정한 값을 강제합니다.

⚠️ 핵심 특성

최고 우선순위: 어떤 드라이버보다 우선
영구 지속: release 전까지 유지
대상: wire, reg, logic 모두 가능

기본 문법

📄 SystemVerilog: force 기본 사용법
// 기본 문법 force signal_name = value; // 계층적 경로로 DUT 내부 시그널 접근 force tb_top.dut.u_core.rst_n = 1'b0; // 다중 비트 force tb_top.dut.data_bus = 32'hDEAD_BEEF; // 표현식도 가능 force tb_top.dut.enable = (mode == 2'b01);

실전 예제: 리셋 강제

📄 SystemVerilog: 리셋 시퀀스 제어
module tb_top; logic clk, rst_n; // DUT 인스턴스 my_dut dut ( .clk(clk), .rst_n(rst_n) ); initial begin // 정상적으로 rst_n 드라이브 rst_n = 1'b1; // 시뮬레이션 중간에 강제 리셋 #100; $display("[%0t] Forcing reset...", $time); force dut.rst_n = 1'b0; // DUT 내부 rst_n 강제 #50; $display("[%0t] Releasing reset...", $time); release dut.rst_n; // 제어권 반환 #100; $finish; end endmodule

🔓 3. release 명령어

release 강제 제어 해제

releaseforce의 효과를 제거하고, 원래 드라이버에게 제어권을 반환합니다.

💡 핵심 포인트

반드시 짝으로 사용: force 후 release 필수!
즉시 효과: release 순간 원래 드라이버 값으로 복귀
force 없이 release: 아무 효과 없음 (에러 아님)

기본 문법

📄 SystemVerilog: release 사용법
// 기본 문법 release signal_name; // 계층적 경로 release tb_top.dut.u_core.rst_n; // 다중 비트 (전체 해제) release tb_top.dut.data_bus;

force/release 짝 패턴

📄 SystemVerilog: 안전한 force/release 패턴
task inject_error(); // 에러 주입 force dut.u_mem.parity_error = 1'b1; $display("[%0t] Error injected", $time); // 에러 상태에서 DUT 반응 관찰 @(posedge clk); @(posedge clk); // 반드시 해제! release dut.u_mem.parity_error; $display("[%0t] Error released", $time); endtask // 안전한 try-finally 스타일 (fork-join_any 활용) task safe_force_pattern(); force dut.sig = 1'b1; fork begin // 테스트 로직 #100; end join // 무조건 실행되는 cleanup release dut.sig; endtask

📥 4. deposit 명령어

$deposit 값 주입 (드라이버 유지)

$deposit은 값을 주입하지만 원래 드라이버를 제거하지 않습니다.

📌 force와의 핵심 차이

일시적 효과: 다음 드라이버 이벤트에서 덮어씌워짐
드라이버 유지: 원래 드라이버가 계속 동작
release 불필요: 자동으로 원래 값으로 복귀
주 용도: X 상태 초기화, 일시적 값 설정

기본 문법

📄 SystemVerilog: $deposit 사용법
// 시스템 태스크로 사용 ($ 붙음!) $deposit(signal_name, value); // 계층적 경로 $deposit(tb_top.dut.counter, 8'd100); // X 상태 초기화 $deposit(dut.u_fsm.state, 3'b000);

X 상태 제거 예제

📄 SystemVerilog: X 상태 초기화
initial begin // 시뮬레이션 시작 시 X 상태인 메모리 초기화 for (int i = 0; i < 256; i++) begin $deposit(dut.u_sram.mem[i], 32'h0); end $display("Memory initialized to 0"); // FSM 상태 초기화 $deposit(dut.u_ctrl.state, 3'b000); // IDLE 상태로 // 주의: 다음 클럭에서 DUT 로직이 값을 변경할 수 있음! end

⚖️ 5. force vs deposit 비교

특성 force $deposit
동작 드라이버 완전 무시 값만 주입, 드라이버 유지
우선순위 최고 (모든 드라이버보다 우선) 낮음 (드라이버가 즉시 덮어씀)
지속 시간 release 전까지 영구 다음 드라이버 이벤트까지
해제 필요 ✅ release 필수 ❌ 불필요
주 용도 에러 주입, 상태 강제 X 초기화, 일시적 값 설정
문법 force sig = val; $deposit(sig, val);

💪 force 사용 시점

• 특정 값을 유지해야 할 때
• DUT 로직을 무시해야 할 때
• 에러 상태를 지속시킬 때
• 긴 시간 동안 제어할 때

📥 $deposit 사용 시점

• X 상태 초기화할 때
• 일시적 값 주입할 때
• DUT 로직 흐름을 유지할 때
• 메모리 프리로드할 때

🔗 6. 계층적 경로 접근

DUT 내부 시그널에 접근하려면 계층적 경로(Hierarchical Path)를 사용합니다.

📊 계층 구조 예시 tb_top ← 테스트벤치 최상위 │ ├── dut (my_soc) ← DUT 인스턴스 │ │ │ ├── u_cpu (cpu_core) ← CPU 코어 │ │ │ │ │ ├── pc ← tb_top.dut.u_cpu.pc │ │ ├── state ← tb_top.dut.u_cpu.state │ │ └── u_alu (alu) │ │ └── result ← tb_top.dut.u_cpu.u_alu.result │ │ │ ├── u_mem (memory_ctrl) │ │ ├── mem[0:255] ← tb_top.dut.u_mem.mem[0] │ │ └── busy ← tb_top.dut.u_mem.busy │ │ │ └── rst_n ← tb_top.dut.rst_n │ └── clk ← tb_top.clk
📄 SystemVerilog: 계층적 경로 사용
// 전체 경로 사용 (권장) force tb_top.dut.u_cpu.pc = 32'h0000_1000; // 상대 경로 (tb_top 모듈 내부에서) force dut.u_cpu.pc = 32'h0000_1000; // 배열 요소 접근 force dut.u_mem.mem[0] = 32'hCAFE_BABE; // 비트 슬라이스 (일부 시뮬레이터) force dut.data[7:0] = 8'hFF; // generate 블록 내부 접근 force dut.gen_block[0].u_inst.sig = 1'b1;
⚠️ 경로 접근 주의사항

private 시그널: 합성 후 최적화로 사라질 수 있음
generate 블록: 인덱스 포함 경로 사용
시뮬레이터 차이: VCS, Xcelium, Questa 동작이 다를 수 있음

📈 7. 타이밍 다이어그램

force/release의 동작을 시각적으로 이해합니다.

📊 force/release 타이밍 다이어그램 0 10 20 30 40 50 60 70 80 90 100 │ │ │ │ │ │ │ │ │ │ │ clk ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ │ 원래 드라이버 (DUT 내부 로직) driver ────0────────1────────0────────1────────0────────1─── ▲ ▲ │ │ 드라이버가 1로 변경 드라이버가 0으로 변경 force 적용 시 실제 시그널 값 signal ────0──┃══════════1══════════┃──0────────1─── ▲ ▲ │ │ force sig = 1 release sig (t=15) (t=55) ═══ force 구간: 드라이버 무시, 강제값 유지 ─── 정상 구간: 드라이버 값 반영
📊 $deposit 타이밍 다이어그램 0 10 20 30 40 50 60 70 80 │ │ │ │ │ │ │ │ │ clk ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ │ 원래 드라이버 driver ────0────────0────────1────────1────────0─── ▲ │ 드라이버가 1로 변경 $deposit 적용 시 실제 시그널 값 signal ────0──│1│────0────────1────────1────────0─── ▲ ▲ │ │ $deposit=1 다음 드라이버 이벤트에서 (t=15) 원래 값(0)으로 복귀 │1│ deposit 순간만 값 변경, 즉시 드라이버 값으로 복귀

🔧 8. 실전 활용 패턴

패턴 1: Error Injection

📄 SystemVerilog: 에러 주입 테스트
// AXI 프로토콜 에러 주입 task inject_axi_error(); // RESP를 SLVERR로 강제 @(posedge clk); force dut.u_axi.BRESP = 2'b10; // SLVERR force dut.u_axi.BVALID = 1'b1; // DUT의 에러 핸들링 관찰 @(posedge clk); if (dut.error_flag !== 1'b1) $error("Error flag not asserted!"); // 복원 release dut.u_axi.BRESP; release dut.u_axi.BVALID; endtask

패턴 2: 초기화 우회

📄 SystemVerilog: 긴 초기화 시퀀스 건너뛰기
// PLL Lock 대기 시간 단축 task skip_pll_lock(); // PLL lock 시그널 강제 활성화 force dut.u_clk_gen.pll_locked = 1'b1; $display("PLL lock forced - skipping 1ms wait"); // FSM이 IDLE에서 READY로 전환될 때까지 대기 wait (dut.u_ctrl.state == READY); // 정상 동작 확인 후 해제 #100; release dut.u_clk_gen.pll_locked; endtask

패턴 3: 코너 케이스 테스트

📄 SystemVerilog: 카운터 오버플로우 테스트
// 카운터를 최대값 직전으로 설정하여 오버플로우 테스트 task test_counter_overflow(); // 카운터를 MAX-2로 강제 설정 force dut.u_timer.counter = 32'hFFFF_FFFD; @(posedge clk); release dut.u_timer.counter; // 3 클럭 후 오버플로우 발생 확인 repeat(3) @(posedge clk); if (dut.overflow_irq !== 1'b1) $error("Overflow IRQ not triggered!"); endtask

패턴 4: 메모리 프리로드

📄 SystemVerilog: 메모리 초기화
// 부트 ROM에 테스트 코드 로드 task preload_boot_rom(string filename); int fd; logic [31:0] data; int addr = 0; fd = $fopen(filename, "r"); while (!$feof(fd)) begin $fscanf(fd, "%h", data); // deposit으로 메모리 초기화 (드라이버 없는 경우) $deposit(dut.u_rom.mem[addr], data); addr++; end $fclose(fd); $display("Loaded %0d words to boot ROM", addr); endtask

🏗️ 9. UVM에서의 활용

📄 SystemVerilog: UVM 시퀀스에서 force 사용
class error_injection_seq extends uvm_sequence#(my_txn); `uvm_object_utils(error_injection_seq) virtual my_if vif; task body(); // Config DB에서 Virtual Interface 가져오기 if (!uvm_config_db#(virtual my_if)::get( null, "*", "vif", vif)) `uvm_fatal("SEQ", "Cannot get VIF") // 정상 트랜잭션 전송 `uvm_do(req) // 에러 주입 force tb_top.dut.error_flag = 1'b1; // 에러 상태에서 트랜잭션 `uvm_do(req) // 복원 release tb_top.dut.error_flag; endtask endclass
💡 UVM에서의 모범 사례

Virtual Interface 활용: 계층 경로 대신 vif 사용 권장
Config DB: 경로를 하드코딩하지 않고 Config DB로 관리
Sequence 내 force: 시퀀스 종료 전 반드시 release
Reset Phase: reset_phase에서 초기화 용도로 활용

🎯 10. 모범 사례 및 주의사항

✅ 모범 사례

1. 항상 force/release 짝으로: force 후 반드시 release

2. 로깅 추가: force/release 시점 기록
$display("[%0t] Force applied", $time);

3. Task로 캡슐화: 재사용성 향상

4. 조건부 해제: 시뮬레이션 종료 시에도 해제되도록

5. 명확한 네이밍: force용 task에 명확한 이름 사용

❌ 안티패턴 (피해야 할 것)

1. release 누락: 시뮬레이션 전체에 영향

2. 하드코딩 경로: 구조 변경 시 모든 경로 수정 필요

3. 타이밍 고려 안 함: 클럭 에지 정렬 없이 force

4. 과도한 사용: 실제 DUT 동작 검증이 아닌 우회로 전락

5. 문서화 없음: 왜 force가 필요한지 주석 없음

시뮬레이터별 주의사항

시뮬레이터 주의사항
VCS 비트 슬라이스 force 지원, generate 경로 주의
Xcelium $deposit 동작이 다를 수 있음, 로그 레벨 확인
Questa force 충돌 시 경고 메시지, GUI 디버깅 지원
Verilator force/deposit 미지원! PLI 사용 필요

📌 핵심 요약

명령어 동작 해제 용도
force 드라이버 완전 무시 release 필수 에러 주입, 상태 강제
release force 해제 - 원래 드라이버로 복귀
$deposit 일시적 값 주입 불필요 X 초기화, 메모리 로드

황금률: force는 강력하지만 위험합니다. 항상 release와 짝으로, 최소한으로, 문서화와 함께 사용하세요!

📚 참고 자료

• IEEE 1800-2017 SystemVerilog LRM, Section 10.6 (force/release)
• Synopsys VCS User Guide - Signal Force Commands
• Cadence Xcelium User Guide - Simulation Control
• UVM Cookbook - Debugging Techniques

댓글

이 블로그의 인기 게시물

📚 SDC 마스터 클래스 시리즈 | Chapter 1

📚 SDC 마스터 클래스 시리즈 | Chapter 2

📚 SDC 마스터 클래스 시리즈 | Chapter 3