지노랩 /JinoLab

[UVM] 5.7 특수 레지스터(Special Registers) ― “평범하지 않은 동작은 이렇게 모델링한다” 본문

UVM(Universal Verification Methodology)/5. Register Layer Class 사용하기

[UVM] 5.7 특수 레지스터(Special Registers) ― “평범하지 않은 동작은 이렇게 모델링한다”

지노랩/JinoLab 2025. 5. 14. 09:43

UVM 레지스터 라이브러리가 가정하는 기본 레지스터 특성

  • 고정된 유일 물리 주소
  • 한 값(value)만 보유
  • 어떤 인터페이스로 접근해도 행동이 동일

하지만 실제 설계에서는 다음과 같은 예외적 요구가 자주 등장합니다.

특수 사례 예시 필요 동작

멀티-어드레스 레지스터 동일 데이터가 AXI·APB 두 주소에 매핑 인터페이스별 주소 분기
뱅크 셀렉터 베이스 주소 + Bank 레지스터 값으로 실제 위치 결정 read/write 시 동적 주소 계산
윈도우(Window) 레지스터 인덱스 레지스터가 가리키는 영역을 동시에 노출 인덱스 값에 따라 다른 데이터 반환
데이터+상태 혼합 쓰면 FIFO에 push, 읽으면 status clear write 후 자동 트리거, read 후 clear
가상(Shadow) 레지스터 SW가 쓰면 내부 FSM이 다른 레지스터에 복사 post-write 콜백으로 추가 동작

UVM에서 특수 행동을 넣는 5가지 방법

방법 대상 한-줄 요약

1. 프런트도어(Front-door) 콜백uvm_reg_cbs 버스 트랜잭션 직전/후 pre_write에서 주소·데이터 수정, post_read에서 값 변환
2. 백도어(Back-door) 클래스uvm_reg_backdoor or uvm_mem_backdoor 직접 read/write 동적 주소 계산·암호화·ECC 등 구현
3. 사용자-정의 Front-dooruvm_reg_frontdoor 시퀀서 기반 커스텀 버스 액세스 멀티-버스트, 특수 핸드쉐이크 지원
4. 가상 함수 오버라이드 read() / write() 가장 강력하지만 마지막 수단 → 표준 API 계약 주의
5. 콜백 체인 + 상태 변수 레지스터/필드 클래스 확장 write-once, lock-bit, 동시 제약 등 구현

구현 예시 1 — 윈도우 레지스터 (INDEX + DATA)

class win_data_cb extends uvm_reg_cbs;
  uvm_reg_field  index_fld;
  uvm_mem        target_mem;

  // DATA 레지스터 읽기 전: 메모리 값 로드
  virtual task pre_read(uvm_reg_item rw);
    if ($cast(rw.element, DATA_REG_T)) begin
      int idx = index_fld.get();
      bit [31:0] val;
      target_mem.peek(.offset(idx), .value(val));
      rw.value[0] = val;       // 읽어올 값 덮어쓰기
    end
  endtask

  // DATA 레지스터 쓰기 후: 메모리에 반영
  virtual task post_write(uvm_reg_item rw);
    if ($cast(rw.element, DATA_REG_T)) begin
      int idx = index_fld.get();
      target_mem.poke(.offset(idx), .value(rw.value[0]));
    end
  endtask
endclass

구현 예시 2 — 동적 주소 계산 백도어

class banked_reg_bkdr extends uvm_reg_backdoor;
  uvm_reg_field bank_sel;   // BANK 필드 핸들
  string        base_path;  // "dut.core.regs"

  virtual task write(uvm_reg_item rw);
    int bank = bank_sel.get();
    string path = $sformatf("%s.bank[%0d].%s",
                            base_path, bank, rw.element.get_name());
    dpi_put(path, rw.value[0]);
  endtask

  virtual task read(uvm_reg_item rw);
    int bank = bank_sel.get();
    string path = $sformatf("%s.bank[%0d].%s",
                            base_path, bank, rw.element.get_name());
    dpi_get(path, rw.value[0]);
  endtask
endclass

요령 정리

  1. 가장 간단한 확장부터 적용
    • 비트-반전, CLR-on-Write 같은 단순 동작 → pre/post 콜백
  2. 버스 트랜잭션이 특수하면
    • 사용자-정의 Front-door로 시퀀서 제어
  3. RTL 경로가 복잡·암호화
    • 사용자-정의 Back-door로 전용 API 호출
  4. API 오버라이드는 최후
    • 표준 미러·커버리지 연동을 깨뜨릴 위험이 있으니 주의
  5. 제너레이터 단계에서 자동 삽입
    • 스펙에 “특수” 표기 → 코드 자동 생성하여 TB 유지보수 최소화


 

본 내용은
accellera에서 공개한
Universal Verification Methodology
(UVM) 1.2 User's Guide
를 바탕으로 작성된 글입니다.