UVM: Implementing Interrupt in UVM - IKSciting
2295
post-template-default,single,single-post,postid-2295,single-format-standard,bridge-core-2.8.7,qodef-qi--no-touch,qi-addons-for-elementor-1.7.1,qode-page-transition-enabled,ajax_fade,page_not_loaded,,qode-title-hidden,qode_grid_1300,footer_responsive_adv,qode-content-sidebar-responsive,qode-theme-ver-27.1,qode-theme-bridge,qode_header_in_grid,wpb-js-composer js-comp-ver-6.6.0,vc_responsive,elementor-default,elementor-kit-838

Implementing Interrupt in UVM

SoC에서 CPU가 동작 중 예외 상황이 발생하거나, 우선순위가 높아 빠르게 처리되어야 하는 작업이 발생하는 경우 interrupt를 통해 CPU에게 알려준다. CPU는 interrupt를 받으면 interrupt service routine, 즉, ISR이라고 불리는 일련의 작업을 수행하고, 해당 작업이 완료되면 다시 기존 동작으로 되돌아간다. 이러한 interrupt를 UVM에서 구현하는 방법에 대해서 알아보자.

먼저 아래의 code는 interrupt를 처리하는 ISR sequence가 없다는 가정 하에 main sequence만을 수행하는 test를 나타낸다.

task my_test::run_phase(uvm_phase phase);
  super.run_phase(phase);
  
  phase.raise_objection(this);
  
  if (!main_seq.randomize()) begin
    `uvm_fatal(get_type_name(), "randomization fail")
  end
  
  main_seq.start(env.agent.sequencer);
  
  phase.drop_objection(this);
endtask: run_phase

Main sequence 내에서는 아래와 같이 10개의 transaction을 보내는 동작을 한다고 가정하자. 단, 구분을 쉽게 하기 위하여 main sequence에서 보내는 transaction의 data는 항상 4'hF 보다 작은 값을 갖도록 constraint를 준다.

task my_main_sequence::body();  
  for (int i = 0; i < n; i ++) begin    
    start_item(req);

    if (!req.randomize() with { data < 4'hF; }) begin
      `uvm_fatal(get_name(), "randomization fail");
    end
  
    `uvm_info(get_type_name(), $sformatf("data = 0x%h", req.data), UVM_MEDIUM)

    finish_item(req);
  end
endtask: body

이제 test에 interrupt를 처리하기 위한 ISR sequence를 추가해보자. ISR은 main sequence가 진행되는 도중, interrupt event가 발생할 경우 동작해야 하므로 forkjoin_none 구문을 이용하여 background에서 진행되도록 한다.

task my_test::run_phase(uvm_phase phase);
  // ...

  // ISR sequence
  fork
    isr_seq.start(env.agent.sequencer);
  join_none
  
  // main sequence
  main_seq.start(env.agent.sequencer);
  
  // ...
endtask: run_phase

ISR sequence는 interrupt event가 발생할 때마다 동작해야 하므로 forever 구문을 이용하여 반복할 수 있도록 하고, 반복문 내에서 interrupt event를 polling 하도록 한다. Interrupt event가 trigger 되면 3개의 transaction을 보내되, 구분을 쉽게 하기 위하여 data는 항상 4'hF 값을 갖도록 constraint를 준다.

task my_isr_sequence::body();  
  uvm_event e;

  e = uvm_event_pool::get_global("INT");

  forever begin
    e.wait_trigger();
    
    `uvm_info(get_type_name(), "ISR started", UVM_MEDIUM)
    
    repeat (3) begin
      start_item(req);

      if (!req.randomize() with { data == 4'hF; }) begin
        `uvm_fatal(get_name(), "randomization fail");
      end
  
      `uvm_info(get_type_name(), $sformatf("data = 0x%h", req.data), UVM_MEDIUM)

      finish_item(req);
    end
    
    `uvm_info(get_type_name(), "ISR finished", UVM_MEDIUM)

    e.reset();
  end
endtask: body

Interrupt event를 polling 하는 부분이 구현되었으므로, 이제 interrupt event를 trigger 하는 부분을 구현해야 한다. 일반적으로 monitor가 이러한 역할을 수행하게 된다. 아래 code에서는 virtual interface를 통해 DUT의 interrupt pin을 monitor 하다가 rising edge가 detect 되면 interrupt event를 trigger 하도록 구현하고 있다.

task my_monitor::run_phase(uvm_phase phase);
  uvm_event e;
  
  e = uvm_event_pool::get_global("INT");
  
  forever begin
    @(posedge vif.interrupt);
    e.trigger();
  end
endtask: run_phase   

이제 simulation을 통해 원하는 결과가 출력되는지 확인해보자. DUT가 interrupt pin을 50 ns에 assert 한다고 가정하고, virtual interface를 임의로 control 하였음에 유의하자. Log를 보면 main sequence가 transaction을 4개까지 처리한 이후 interrupt에 의해 ISR sequence가 동작하기 시작하는 것을 확인할 수 있다. 일단 ISR 진입까지는 문제가 없는 셈이다. 하지만 그 이후의 log를 보면 ISR sequence와 main sequence가 번갈아가면서 수행되고 있다. ISR sequence는 main sequence보다 우선하여 처리가 완료되어야 하므로 아직 code 수정이 더 필요하다는 것을 알 수 있다.

UVM_INFO @ 20000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x1
UVM_INFO @ 25000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x9
UVM_INFO @ 35000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0xa
UVM_INFO @ 45000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x4
UVM_INFO @ 50000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] ISR started
UVM_INFO @ 55000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] data = 0xf
UVM_INFO @ 65000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x5
UVM_INFO @ 75000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] data = 0xf
UVM_INFO @ 85000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x0
UVM_INFO @ 95000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] data = 0xf
UVM_INFO @ 105000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] ISR finished
UVM_INFO @ 105000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x3
UVM_INFO @ 115000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0xe
UVM_INFO @ 125000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x2
UVM_INFO @ 135000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0xe

ISR 진입 이후 ISR sequence가 모두 처리되기 전까지 main sequence가 끼어들지 않도록 보장하기 위해서는 grab, ungrab method를 활용할 수 있다. Interrupt event가 detect 된 이후 grab method를 이용해 해당 sequencer에 대한 exclusive access 권한을 획득한다. 또한 ISR sequence 처리가 완료되면 ungrab method를 이용하여 다른 sequence가 해당 sequencer를 사용할 수 있도록 풀어준다.

task my_isr_sequence::body();  
  forever begin
    e.wait_trigger();
    
    `uvm_info(get_type_name(), "ISR started", UVM_MEDIUM)
    
    grab();
    
    repeat (3) begin
      start_item(req);

      if (!req.randomize() with { data == 4'hF; }) begin
        `uvm_fatal(get_name(), "randomization fail");
      end
  
      `uvm_info(get_type_name(), $sformatf("data = 0x%h", req.data), UVM_MEDIUM)

      finish_item(req);
    end
    
    ungrab();
    
    `uvm_info(get_type_name(), "ISR finished", UVM_MEDIUM)
    
    e.reset();
  end
endtask: body

다시 한 번 simulation log를 확인해보자. 이제 ISR sequence가 모두 처리된 이후 비로소 main sequence로 복귀함을 확인할 수 있다.

UVM_INFO @ 20000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x1
UVM_INFO @ 25000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x9
UVM_INFO @ 35000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0xa
UVM_INFO @ 45000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x4
UVM_INFO @ 50000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] ISR started
UVM_INFO @ 55000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] data = 0xf
UVM_INFO @ 65000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] data = 0xf
UVM_INFO @ 75000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] data = 0xf
UVM_INFO @ 85000: uvm_test_top.env.agent.sequencer@@isr_seq [my_isr_sequence] ISR finished
UVM_INFO @ 85000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x5
UVM_INFO @ 95000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x0
UVM_INFO @ 105000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x3
UVM_INFO @ 115000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0xe
UVM_INFO @ 125000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0x2
UVM_INFO @ 135000: uvm_test_top.env.agent.sequencer@@main_seq [my_main_sequence] data = 0xe

참고로 grab, ungrab method 외에 lock, unlock method도 존재하는데, grab은 sequence arbitration 시 queue의 가장 앞(front)에 해당 sequence를 위치시키는 반면 lock은 queue의 가장 뒤(back)에 해당 sequence를 위치시키는 차이가 있다. 따라서 ISR sequence 작성 시 요구사항에 맞게 적절한 method를 사용하도록 주의해야 한다. 참고로 위 예제와 같이 ISR이 하나만 존재하는 경우는 grab 동작과 lock 동작에 차이가 없다.

마지막으로 UVM register model을 이용하여 ISR sequence를 작성하는 경우 한 가지 유의해야 할 점이 있다. write, read와 같은 UVM register method를 사용할 때 반드시 아래와 같이 parent argument를 설정해야 한다는 점이다. parent argument는 설정하지 않는 경우 기본적으로 null 값을 가지게 되고, parent sequence로부터 grab 또는 lock에 대한 status를 inherit 받을 수 없기 때문이다.

task my_isr_sequence::body();  
  forever begin
    e.wait_trigger();
    
    grab();

    regmodel.r0.write(
      .status(status),
      .value(value),
      .parent(this) // required!
    );
    
    ungrab();
    
    e.reset();
  end
endtask: body

References

4 Comments
  • puravive weight loss review
    Posted at 17:02h, 27 February Reply

    This stage is incredible. The magnificent information uncovers the administrator’s excitement. I’m shocked and anticipate additional such astonishing presents.

  • puravive reviews
    Posted at 11:08h, 03 March Reply

    This webpage is outstanding. The site owner’s passion is evident in the excellent content. I’m in awe and anticipate reading more amazing pieces like this one.

  • https://medium.com/@serkan.koca.1071/
    Posted at 22:46h, 12 April Reply

    hello!,I really like your writing verry much!
    proporton wwe communicate more about your
    post on AOL? I require an expert in this house to solve my problem.
    May be that iss you! Takong a look ahead to see you.

  • medium.com
    Posted at 02:09h, 22 April Reply

    Excellent website you hzve here bbut I was wondering if
    you knew of anny user discussion forums that cover the same topics talked about in this article?
    I’d realy like to bee a part of community where I can gget opinions from other experienced individuals that share the samke interest.
    If yoou have any recommendations, pldase let me know.
    Thankss a lot!

Post A Comment