오늘은 Driver에 대하여 알아보겠습니다.
Driver는 Sequence를 Sequencer로부터 받아 DUT에 전달하는 역할을 수행하는 컴포넌트입니다.
Sequence와 어떤 메카니즘으로 data packet들을 주고받는지는 Sequence 관련 글에서 확인하실 수 있습니다!
작성법은 어렵지 않습니다. 처음 작성하시는 분들을 위해서 하나하나 설명드리겠습니다.
1~4번까지는 대부분의 driver에서 같은 형태를 가질 것입니다.
class example_driver extends uvm_driver;
class example_driver extends uvm_driver;
`uvm_component_utils (example_driver)
Factory에 등록하는 macro에 관련한 내용은 Sequence를 참고해주세요.
class example_driver extends uvm_driver;
`uvm_component_utils (example_driver)
function new (string name = "example_driver", uvm_component parent = null);
super.new (name, parent);
endfunction
virtual example_if vif; //Interface에 대한 handle 선언
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
if (! uvm_config_db #(virtual if_name) :: get (this, "", "vif", vif)) begin
`uvm_fatal (get_type_name (), "Didn't get handle to virtual interface if_name")
end //vif를 get하지 못하면 fatal을 발생시켜라
endfunction
Driver는 미리 선언된 Interface를 사용하기 때문에, Build_phase에서 그러한 virtual interface(vif로 줄여 부르고는 합니다)를 get
해야합니다. 더 상위 하이라키에서 set
해줘야 하위 하이라키에서 get
할 수 있기 때문에 어디선가 set
해줬을 겁니다. 보통 인터넷의 예제에선 TEST component
에서 set
해줍니다.
uvm_config_db::get
: UVM Configuration Database를 통해 vif라는 이름의 가상 인터페이스를 가져옵니다.
this
: 이 코드가 작성된 객체.
""
: 경로를 지정하는 데 사용. 빈 문자열은 현재 범위를 의미.
"vif"
: 가상 인터페이스의 이름.
vif
: 가져온 값을 저장할 변수.
uvm_fatal
은 vif를 get하지 못했을 경우 발생하도록 작성되어있으며, fatal이 발생하면 시뮬레이션을 중단합니다.
여기까지는 거의 고정적으로 작성하게 됩니다.
run_phase에 원하는 시나리오를 작성하면 됩니다.
만약 item과 interface가 아래와 같다면,
////item////
class Item extends uvm_sequence_item;
`uvm_object_utils(Item)
rand bit in;
bit out;
function new(string name = "Item");
super.new(name);
endfunction
endclass
////interface////
interface example_if (input bit clk);
logic rstn;
logic in;
logic out;
clocking cb @(posedge clk);
default input #1step output #3ns;
input out;
output in;
endclocking
endinterface
아래처럼 driver를 작성할 수 있습니다.
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
Item m_item; //handle 생성
seq_item_port.get_next_item(m_item); //sequence와 handshake
drive_item(m_item); //아래에 정의된 task
seq_item_port.item_done();
end
endtask
virtual task drive_item(Item m_item);
@(vif.cb);
vif.cb.in <= m_item.in;
endtask
posedge clk
마다 in
값을 새롭게 넣어주네요. in
값은 매 클락 randomize될 것입니다(randomize 부분은 sequence에 작성되었을 것입니다).이게 전부입니다. 요약하자면,
- Sequence에서 온 data packet을 dut로 전달해주기 위해 interface에 값을 넣어주는 역할을 수행하며,
- sequence와는 handshake방식으로 소통한다.
- Build_phase에서 vif를 get해줘야하며,
- run_phase에서 시나리오를 작성한다.
이상입니다~~
읽어주셔서 감사합니다.
https://www.chipverify.com/uvm/uvm-verification-testbench-example
https://www.chipverify.com/uvm/uvm-driver