지노랩 /JinoLab
[UVM] 3.10.2 서브시퀀스 및 시퀀스 아이템 전송 (Sending Subsequences and Sequence Items) 본문
[UVM] 3.10.2 서브시퀀스 및 시퀀스 아이템 전송 (Sending Subsequences and Sequence Items)
지노랩/JinoLab 2025. 3. 19. 12:491. 개요
UVM의 **시퀀스(sequence)**는 **DUT(Device Under Test)**에 데이터를 전달하는 역할을 하며,
단순한 트랜잭션 스트림을 생성하는 것뿐만 아니라, DUT 인터페이스에서 특정 동작을 수행하는 흐름을 정의할 수도 있음.
또한, 시퀀스를 활용하여 DUT와 직접 연결되지 않은 정적인 데이터 아이템 리스트를 생성할 수도 있음.
2. 시퀀스를 활용한 데이터 및 액션 스트림
(1) 데이터 아이템 스트림 생성
- 시퀀스는 DUT로 전달할 트랜잭션(데이터 아이템)의 흐름을 정의할 수 있음.
- 예를 들어, 메모리 버스에 대한 읽기/쓰기 트랜잭션을 순차적으로 실행하는 시퀀스를 정의 가능.
(2) DUT 인터페이스에서의 액션 수행
- 시퀀스는 단순한 데이터 전송이 아니라 특정 프로토콜의 동작을 수행하는 흐름을 만들 수도 있음.
- 예를 들어, 특정한 제어 시그널을 활성화하는 시퀀스를 만들 수 있음.
(3) 정적인 데이터 리스트 생성
- 시퀀스를 활용하여 DUT와 직접적인 연결이 없는 정적인 트랜잭션 목록을 생성할 수도 있음.
- 예를 들어, 특정 패턴의 데이터를 사전에 정의하여 리스트 형태로 저장해두고, 필요한 시점에 이를 활용 가능.
3. 서브시퀀스(하위 시퀀스) 개념
(1) 서브시퀀스란?
- 하나의 시퀀스 안에서 다른 시퀀스를 호출하여 실행할 수 있음.
- 서브시퀀스를 활용하면 복잡한 트랜잭션 흐름을 보다 모듈화하여 재사용할 수 있음.
- 예를 들어, 기본적인 읽기/쓰기 트랜잭션을 수행하는 시퀀스를 생성한 뒤, 이를 조합하여 보다 복잡한 시퀀스를 구성 가능.
(2) 서브시퀀스 예제
아래 예제에서는 sub_seq라는 서브시퀀스를 정의하고, 이를 main_seq에서 호출하여 실행.
// 하위 시퀀스 정의
class sub_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(sub_seq)
function new(string name = "sub_seq");
super.new(name);
endfunction
virtual task body();
`uvm_info("SUB_SEQ", "Executing sub-sequence", UVM_LOW)
`uvm_do(req) // 단일 트랜잭션 실행
`uvm_do(req) // 두 번째 트랜잭션 실행
endtask
endclass
// 상위 시퀀스에서 하위 시퀀스를 실행
class main_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(main_seq)
function new(string name = "main_seq");
super.new(name);
endfunction
virtual task body();
`uvm_info("MAIN_SEQ", "Starting main sequence", UVM_LOW)
`uvm_do(req) // 첫 번째 트랜잭션 실행
sub_seq sub_seq_inst;
sub_seq_inst = sub_seq::type_id::create("sub_seq_inst");
sub_seq_inst.start(m_sequencer); // 서브시퀀스 실행
`uvm_do(req) // 마지막 트랜잭션 실행
endtask
endclass
(3) 실행 흐름
- main_seq가 실행되면 첫 번째 트랜잭션(req)을 실행.
- sub_seq를 생성하고 실행 (sub_seq.start(m_sequencer))
- sub_seq 내부에서 두 개의 트랜잭션(req)을 실행.
- sub_seq가 종료된 후 main_seq의 마지막 트랜잭션(req) 실행.
4. 시퀀스 아이템 개별 실행
(1) 단일 트랜잭션 실행 (req)
- req는 단일 트랜잭션을 의미하며, uvm_do(req) 매크로를 사용하여 실행 가능.
- 예제:
`uvm_do(req) // 단일 트랜잭션 실행
- req 객체가 자동 생성되어 실행됨.
(2) 명시적으로 트랜잭션 객체를 생성하여 실행
simple_item item;
item = simple_item::type_id::create("item");
start_item(item); // 시퀀서에 아이템 시작 알림
item.randomize(); // 랜덤화 수행
finish_item(item); // 트랜잭션 실행 완료 알림
- start_item() → 트랜잭션 실행 준비
- randomize() → 트랜잭션 변수 랜덤화
- finish_item() → 트랜잭션 실행 완료
(3) 여러 개의 트랜잭션을 반복 실행
- repeat(N)을 사용하여 트랜잭션을 여러 번 실행 가능.
repeat(5) begin
`uvm_do(req) // 5번 반복 실행
end
5. 서브시퀀스를 활용한 복잡한 시나리오
(1) 복합적인 서브시퀀스 실행
아래 예제에서는 sub_seq_A와 sub_seq_B 두 개의 서브시퀀스를 호출하여 실행.
class sub_seq_A extends uvm_sequence #(simple_item);
`uvm_object_utils(sub_seq_A)
function new(string name = "sub_seq_A");
super.new(name);
endfunction
virtual task body();
repeat(3) `uvm_do(req) // 3번 실행
endtask
endclass
class sub_seq_B extends uvm_sequence #(simple_item);
`uvm_object_utils(sub_seq_B)
function new(string name = "sub_seq_B");
super.new(name);
endfunction
virtual task body();
repeat(2) `uvm_do(req) // 2번 실행
endtask
endclass
class complex_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(complex_seq)
function new(string name = "complex_seq");
super.new(name);
endfunction
virtual task body();
`uvm_info("COMPLEX_SEQ", "Executing complex sequence", UVM_LOW)
sub_seq_A seqA = sub_seq_A::type_id::create("seqA");
sub_seq_B seqB = sub_seq_B::type_id::create("seqB");
seqA.start(m_sequencer);
seqB.start(m_sequencer);
`uvm_do(req) // 추가적인 트랜잭션 실행
endtask
endclass
(2) 실행 흐름
- sub_seq_A가 실행되며 req를 3번 실행.
- sub_seq_B가 실행되며 req를 2번 실행.
- 마지막으로 complex_seq에서 추가적인 req를 실행.
6. 요약
- 시퀀스는 단순한 트랜잭션의 연속 실행뿐만 아니라 특정 DUT 동작을 수행하는 흐름을 정의할 수 있음.
- 서브시퀀스를 활용하여 복잡한 트랜잭션 시나리오를 모듈화하고 재사용 가능.
- 트랜잭션은 개별 실행할 수도 있고, 반복 실행하거나, 명시적으로 생성 후 실행할 수도 있음.
- 다양한 서브시퀀스를 조합하여 복합적인 검증 시나리오를 구성할 수 있음.
7. 다음 단계
- 시퀀스와 서브시퀀스를 활용한 랜덤 트랜잭션 생성.
- 복합적인 시퀀스를 기반으로 한 테스트 시나리오 설계.
- 시퀀서와 드라이버의 동작을 최적화하여 보다 정교한 검증 환경 구축.
즉, 시퀀스를 활용하면 더욱 유연하고 체계적인 검증 환경을 구축할 수 있음.
3.10.2.1 시퀀스 및 시퀀스 아이템의 기본 흐름 (Basic Flow for Sequences and Sequence Items)
1. 개요
UVM에서 시퀀스(Sequence)와 시퀀스 아이템(Sequence Item)의 실행 흐름을 이해하는 것은 효과적인 검증 환경을 구축하는 데 매우 중요함.
시퀀스의 body()에서 시퀀스 아이템을 생성하고 실행하는 과정에는 객체의 생성, 초기화, 랜덤화, 실행, 완료 처리 등의 단계가 포함됨.
또한, **서브시퀀스(Subsequence)**를 실행할 경우 부모 시퀀스가 하위 시퀀스를 생성하고 실행하며, 필요하면 응답을 받을 수도 있음.
2. 시퀀스 아이템 전송 흐름

(1) 시퀀스 아이템 전송 과정
시퀀스에서 하나의 트랜잭션을 전송하는 기본적인 흐름은 다음과 같음.
- 아이템 생성 (create())
- UVM Factory를 사용하여 시퀀스 아이템을 생성.
- 아이템 실행 준비 (start_item())
- 시퀀스 아이템을 실행할 준비.
- 랜덤화 (Optional) (randomize())
- 트랜잭션 데이터가 랜덤화될 경우 실행.
- 아이템 실행 완료 (finish_item())
- 트랜잭션이 실행되었음을 시퀀서에 알림.
virtual task body();
simple_item item;
// 1. 아이템 생성
item = simple_item::type_id::create("item");
// 2. 아이템 실행 준비
start_item(item);
// 3. 랜덤화 (옵션)
if (!item.randomize())
`uvm_error("SEQ", "Randomization failed!");
// 4. 실행 완료
finish_item(item);
endtask
3. 서브시퀀스 전송 흐름

(1) 서브시퀀스 실행 과정
부모 시퀀스에서 서브시퀀스를 실행하는 과정은 다음과 같음.
- 서브시퀀스 생성 (create())
- UVM Factory를 사용하여 서브시퀀스를 생성.
- 서브시퀀스 실행 (start())
- 서브시퀀스를 실행.
(2) 서브시퀀스 실행 예제
아래 예제는 main_seq가 sub_seq라는 하위 시퀀스를 실행하는 과정.
class sub_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(sub_seq)
function new(string name = "sub_seq");
super.new(name);
endfunction
virtual task body();
`uvm_info("SUB_SEQ", "Executing sub-sequence", UVM_LOW)
`uvm_do(req) // 단일 트랜잭션 실행
`uvm_do(req) // 두 번째 트랜잭션 실행
endtask
endclass
class main_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(main_seq)
function new(string name = "main_seq");
super.new(name);
endfunction
virtual task body();
`uvm_info("MAIN_SEQ", "Starting main sequence", UVM_LOW)
// 1. 서브시퀀스 생성
sub_seq sub_seq_inst;
sub_seq_inst = sub_seq::type_id::create("sub_seq_inst");
// 2. 서브시퀀스 실행
sub_seq_inst.start(m_sequencer);
`uvm_do(req) // 추가적인 트랜잭션 실행
endtask
endclass
4. UVM 시퀀스 실행 흐름
UVM에서는 uvm_do 매크로를 사용하여 시퀀스 아이템 및 시퀀스를 자동 실행할 수 있음.
이 과정에서 여러 개의 콜백(callback) 메서드가 호출되는데, 그 흐름을 살펴보면 다음과 같음.
(1) 시퀀스 아이템 실행 흐름
- 객체 생성 → create()
- 사전 실행 콜백 호출 → pre_do()
- 랜덤화 실행 → randomize()
- 중간 실행 콜백 호출 → mid_do()
- 아이템 실행 준비 → start_item()
- 아이템 실행 완료 → finish_item()
- 후처리 콜백 호출 → post_do()
(2) 서브시퀀스 실행 흐름
- 객체 생성 → create()
- 랜덤화 실행 (필요한 경우)
- 서브시퀀스 실행 → start()
- 응답이 있을 경우 응답 수신 → get_response()
5. pre_do(), mid_do(), post_do() 콜백
(1) pre_do()
- start_item() 호출 직전에 실행됨.
- 특정 필드를 초기화하거나, 실행 전 설정할 것이 있다면 여기서 수행.
(2) mid_do()
- randomize()가 실행된 후 호출됨.
- 랜덤화 이후 특정 필드를 조정해야 할 경우 사용.
(3) post_do()
- finish_item() 호출 후 실행됨.
- 실행 후 추가적인 검증이나 로깅을 수행할 때 사용.
(4) 콜백을 활용한 예제
class my_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(my_seq)
function new(string name = "my_seq");
super.new(name);
endfunction
virtual task body();
simple_item item;
// 아이템 생성
item = simple_item::type_id::create("item");
// 실행 전 설정
pre_do(item);
// 아이템 실행 준비
start_item(item);
// 랜덤화 수행
if (!item.randomize())
`uvm_error("SEQ", "Randomization failed!");
// 실행 후 추가 검증
post_do(item);
// 실행 완료
finish_item(item);
endtask
virtual function void pre_do(ref simple_item item);
`uvm_info("SEQ", "Pre-processing before execution", UVM_LOW)
endfunction
virtual function void post_do(ref simple_item item);
`uvm_info("SEQ", "Post-processing after execution", UVM_LOW)
endfunction
endclass
6. 요약
- 시퀀스 아이템 실행 과정
- create() → start_item() → randomize() → finish_item()
- uvm_do(req) 매크로로 간단하게 실행 가능.
- 서브시퀀스 실행 과정
- create() → start()
- 서브시퀀스는 부모 시퀀스에서 실행하며, 필요하면 get_response()로 응답을 받을 수도 있음.
- 콜백 활용
- pre_do(), mid_do(), post_do() 메서드를 활용하여 실행 전후에 필요한 작업을 수행 가능.
- UVM 자동화 매크로
- uvm_do(req): 단일 트랜잭션 실행.
- uvm_do_with(req, {조건}): 특정 조건을 만족하는 트랜잭션 실행.
- uvm_do_on(sub_seq, target_sequencer): 특정 시퀀서에서 실행.
3.10.2.2 시퀀스 및 시퀀스 아이템 매크로 (Sequence and Sequence Item Macros)
1. 개요
UVM에서는 시퀀스와 시퀀스 아이템을 보다 간편하게 생성, 랜덤화, 실행할 수 있도록
uvm_do 및 uvm_do_with 매크로를 제공함.
이 매크로들을 사용하면 시퀀스를 작성할 때 코드가 간결해지고, 트랜잭션 실행 흐름이 명확해짐.
2. uvm_do 매크로
(1) 기본 개념
- uvm_do 매크로는 트랜잭션을 생성하고, 랜덤화하며, 실행하는 과정을 자동으로 처리해줌.
- pre_do() 메서드 실행 이후에 랜덤화가 수행되며,
드라이버가 준비되었다는 신호를 받은 후에야 트랜잭션이 랜덤화됨. - 트랜잭션을 실행하는 일반적인 흐름을 다음과 같이 자동으로 처리:
- 트랜잭션 객체 생성 (create())
- pre_do() 실행
- 랜덤화 (randomize())
- mid_do() 실행
- start_item() 실행
- finish_item() 실행
- post_do() 실행
(2) 기본 사용법
class my_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(my_seq)
function new(string name = "my_seq");
super.new(name);
endfunction
virtual task body();
`uvm_do(req) // req 트랜잭션 생성, 랜덤화, 실행
endtask
endclass
- uvm_do(req)를 호출하면 req 객체가 자동으로 생성되고 랜덤화된 후 실행됨.
- 위 코드는 다음과 같은 일반적인 시퀀스 실행 코드와 동일한 동작을 수행:
virtual task body();
req = simple_item::type_id::create("req");
start_item(req);
if (!req.randomize())
`uvm_error("SEQ", "Randomization failed!");
finish_item(req);
endtask
3. uvm_do_with 매크로
(1) 기본 개념
- uvm_do_with는 랜덤화 조건을 추가할 수 있는 매크로.
- 트랜잭션 객체를 생성하고, 지정된 제약 조건을 적용한 후 랜덤화하여 실행.
(2) 기본 사용법
class my_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(my_seq)
function new(string name = "my_seq");
super.new(name);
endfunction
virtual task body();
`uvm_do_with(req, {req.addr inside {[32'h1000:32'h1FFF]};})
endtask
endclass
- uvm_do_with(req, {조건})을 사용하면 특정 조건을 만족하는 값만 생성할 수 있음.
- 위 코드는 다음과 같은 일반적인 코드와 동일:
virtual task body();
req = simple_item::type_id::create("req");
start_item(req);
if (!req.randomize() with {req.addr inside {[32'h1000:32'h1FFF]};})
`uvm_error("SEQ", "Randomization failed!");
finish_item(req);
endtask
4. uvm_do_on 매크로
(1) 기본 개념
- uvm_do_on 매크로는 특정 시퀀서에서 시퀀스를 실행할 때 사용.
- 시퀀서가 여러 개 존재할 경우, 원하는 시퀀서에서 실행할 수 있음.
(2) 기본 사용법
class my_seq extends uvm_sequence #(simple_item);
`uvm_object_utils(my_seq)
function new(string name = "my_seq");
super.new(name);
endfunction
virtual task body();
`uvm_do_on(req, some_sequencer)
endtask
endclass
- 위 코드는 특정 시퀀서(some_sequencer)에서 트랜잭션을 실행하는 방식.
- 아래 일반 코드와 동일한 동작을 수행:
virtual task body();
req = simple_item::type_id::create("req");
start_item(req, some_sequencer);
if (!req.randomize())
`uvm_error("SEQ", "Randomization failed!");
finish_item(req);
endtask
5. 요약
| 매크로 | 기능 | 예제 |
| uvm_do(req) | 트랜잭션을 생성, 랜덤화, 실행 | uvm_do(req) |
| uvm_do_with(req, {조건}) | 특정 조건을 적용하여 랜덤화 실행 | uvm_do_with(req, {req.addr < 16'h2000;}) |
| uvm_do_on(req, sequencer) | 특정 시퀀서에서 실행 | uvm_do_on(req, my_sequencer) |
3.10.2.2.1 `uvm_do 매크로
1. 개요
- uvm_do 매크로는 트랜잭션(uvm_sequence_item)이나 시퀀스(uvm_sequence)를 생성하고 실행하는 매크로.
- UVM 팩토리 설정을 기반으로 객체를 생성한 후, 해당 변수에 할당.
- 드라이버가 시퀀서에서 트랜잭션을 요청할 때, uvm_do 매크로를 사용하면 자동으로 랜덤화된 트랜잭션이 제공됨.
2. uvm_do 매크로의 기본 동작
- uvm_do(req)가 실행될 때 수행되는 과정:
- 객체 생성 (팩토리 설정 사용)
- pre_do() 실행
- 랜덤화 수행 (randomize())
- mid_do() 실행
- start_item() 호출 (시퀀서에서 트랜잭션 요청)
- finish_item() 호출 (트랜잭션 전송 완료)
- post_do() 실행
3. uvm_do를 이용한 기본 시퀀스 예제
다음은 uvm_do 매크로를 사용한 간단한 시퀀스(simple_seq_do) 예제.
(1) simple_seq_do 클래스 정의
class simple_seq_do extends uvm_sequence #(simple_item);
`uvm_object_utils(simple_seq_do) // 팩토리에 등록
function new(string name="simple_seq_do");
super.new(name);
endfunction
virtual task body();
`uvm_do(req) // simple_item 타입의 트랜잭션 실행
endtask : body
endclass : simple_seq_do
(2) 설명
- simple_seq_do는 uvm_sequence를 상속받아 정의됨.
- body() 내부에서 uvm_do(req) 호출 → req 객체가 생성되고 랜덤화됨.
- req는 simple_item 타입의 트랜잭션으로, 드라이버에 의해 실행됨.
4. uvm_do를 이용한 서브 시퀀스 실행
- uvm_do는 트랜잭션뿐만 아니라 다른 시퀀스를 실행할 수도 있음.
- 다음 예제는 이전 예제에서 정의한 simple_seq_do를 서브 시퀀스로 실행하는 코드.
(1) simple_seq_sub_seqs 클래스 정의
class simple_seq_sub_seqs extends uvm_sequence #(simple_item);
`uvm_object_utils(simple_seq_sub_seqs) // 팩토리에 등록
simple_seq_do seq_do; // 서브 시퀀스 객체
function new(string name="simple_seq_sub_seqs");
super.new(name);
endfunction
virtual task body();
`uvm_do(seq_do) // simple_seq_do 실행
endtask : body
endclass : simple_seq_sub_seqs
(2) 설명
- simple_seq_sub_seqs는 simple_seq_do를 서브 시퀀스로 실행하는 예제.
- uvm_do(seq_do)를 호출하면 simple_seq_do가 실행되면서 내부적으로 트랜잭션을 발생시킴.
- 하나의 시퀀스가 다른 시퀀스를 호출하여 계층적 시퀀스를 구성하는 방식.
5. uvm_do와 일반 코드 비교
- uvm_do(req)는 아래 코드와 동일한 동작을 수행:
virtual task body();
req = simple_item::type_id::create("req"); // 객체 생성
start_item(req); // 시퀀서에서 아이템 요청
if (!req.randomize())
`uvm_error("SEQ", "Randomization failed!");
finish_item(req); // 아이템 실행 완료
endtask
- 차이점: uvm_do(req)를 사용하면 코드가 훨씬 간결해지고, UVM의 표준화된 방법을 따르게 됨.
6. 요약
매크로 기능 예제
| uvm_do(req) | 트랜잭션을 생성, 랜덤화, 실행 | uvm_do(req) |
| uvm_do(seq_do) | 서브 시퀀스를 실행 | uvm_do(seq_do) |
- uvm_do를 사용하면 시퀀스 및 트랜잭션 실행 코드가 간결해지고 가독성이 높아짐.
- 트랜잭션뿐만 아니라 서브 시퀀스도 실행할 수 있어 재사용성이 증가.
- UVM의 표준 매크로를 사용하면 유지보수성이 향상되고, 코드의 일관성이 유지됨.
3.10.2.2.2 `uvm_do_with 매크로
1. 개요
- uvm_do_with 매크로는 uvm_do 매크로와 유사하지만, 추가적으로 inline constraints(인라인 제약 조건)을 지정할 수 있음.
- 트랜잭션이나 시퀀스를 실행할 때, 특정 값이나 조건을 설정하고 싶을 때 사용.
- 첫 번째 인자는 uvm_sequence_item을 상속받은 객체, 두 번째 인자는 랜덤화에 적용할 인라인 제약 조건.
- randomize() 함수에서 사용할 수 있는 인라인 제약 조건이라면 모두 허용됨.
2. uvm_do_with 매크로의 기본 동작
- uvm_do_with(req, { req.addr == 16'h0120; req.data == 16'h0444; })
- req 객체를 생성.
- 제약 조건 { req.addr == 16'h0120; req.data == 16'h0444; }를 적용하여 랜덤화 수행.
- 랜덤화된 데이터를 시퀀서에서 드라이버로 전달.
3. uvm_do_with를 이용한 기본 시퀀스 예제
(1) 특정 주소 및 데이터 값을 설정하는 예제
class simple_seq_do_with extends uvm_sequence #(simple_item);
`uvm_object_utils(simple_seq_do_with) // 팩토리에 등록
function new(string name="simple_seq_do_with");
super.new(name);
endfunction
virtual task body();
`uvm_do_with(req, { req.addr == 16'h0120; req.data == 16'h0444; } ) // 첫 번째 트랜잭션
`uvm_do_with(req, { req.addr == 16'h0124; req.data == 16'h0666; } ) // 두 번째 트랜잭션
endtask : body
endclass : simple_seq_do_with
(2) 설명
- 두 개의 simple_item 트랜잭션을 실행하면서 주소(addr)와 데이터(data) 값을 각각 16'h0120, 16'h0124로 설정.
- 특정 값을 고정하는 대신, 각 실행마다 다른 조건을 적용할 수도 있음.
4. uvm_do_with와 일반 코드 비교
- uvm_do_with(req, { req.addr == 16'h0120; req.data == 16'h0444; })는 아래 코드와 동일한 동작을 수행:
virtual task body();
req = simple_item::type_id::create("req"); // 객체 생성
start_item(req); // 시퀀서에서 아이템 요청
if (!req.randomize() with { req.addr == 16'h0120; req.data == 16'h0444; })
`uvm_error("SEQ", "Randomization failed!");
finish_item(req); // 아이템 실행 완료
endtask
차이점
- uvm_do_with를 사용하면 코드가 간결해지고 가독성이 높아짐.
- 인라인 제약 조건을 쉽게 추가할 수 있어, 여러 개의 randomize() 호출을 줄일 수 있음.
5. uvm_do_with를 대체하는 사용자 정의 함수
- uvm_do_with는 특정 값을 설정하는데 유용하지만, 함수로 대체할 수도 있음.
- 아래 예제에서는 do_rw() 함수를 사용하여 uvm_do_with 없이 동일한 기능을 구현.
(1) 사용자 정의 함수(do_rw())를 이용한 트랜잭션 실행
class simple_seq_do_with extends uvm_sequence #(simple_item);
task do_rw(int addr, int data);
item = simple_item::type_id::create("item", get_full_name()); // 객체 생성
item.addr.rand_mode(0); // 랜덤화 비활성화
item.data.rand_mode(0); // 랜덤화 비활성화
item.addr = addr; // 주소 설정
item.data = data; // 데이터 설정
start_item(item);
randomize(item);
finish_item(item);
endtask
virtual task body();
repeat (num_trans)
do_rw($urandom(), $urandom()); // 랜덤한 주소 및 데이터 생성
endtask
endclass : simple_seq_do_with
(2) 설명
- do_rw() 함수는 트랜잭션의 주소(addr)와 데이터(data)를 직접 설정하고 실행.
- rand_mode(0)를 이용해 특정 필드를 랜덤화하지 않도록 설정.
- repeat (num_trans)를 사용하여 여러 개의 트랜잭션을 실행.
6. uvm_do vs. uvm_do_with 비교
매크로 기능 예제
| uvm_do(req) | 기본 랜덤화 트랜잭션 실행 | uvm_do(req) |
| uvm_do_with(req, { ... }) | 특정 제약 조건을 적용하여 트랜잭션 실행 | uvm_do_with(req, { req.addr == 16'h0120; }) |
본 내용은
accellera에서 공개한
Universal Verification Methodology
(UVM) 1.2 User's Guide
를 바탕으로 작성된 글입니다.
'UVM(Universal Verification Methodology) > 3. 재사용 가능한 검증 컴포넌트 개발(Developing Reusabl' 카테고리의 다른 글
| [UVM] 3.10.4 시퀀스 아이템 및 시퀀스 오버라이딩 (Overriding Sequence Items and Sequences) (0) | 2025.03.20 |
|---|---|
| [UVM] 3.10.3 Sequencer에서 Sequence 실행하기 (0) | 2025.03.19 |
| [UVM] 3.10.1 사용자 정의 시퀀스 선언 (Declaring User-Defined Sequences) (0) | 2025.03.18 |
| [UVM] 3.10 시나리오 생성 활성화 (Enabling Scenario Creation) (0) | 2025.03.18 |
| [UVM] 3.9 환경(Environment) 생성 (0) | 2025.03.17 |