SystemVerilog: Associative Array - IKSciting
1544
post-template-default,single,single-post,postid-1544,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

Associative Array

Memory controller를 검증해야 한다고 가정해 보자. Controller의 여러 동작을 검증하기 위해서 write, read 등 다양한 transaction을 생성하고 이에 대한 check를 하게 될 것이다. 그 중 write function에 대한 검증을 하는 경우라면 transaction은 간단하게는 address, data와 같은 정보가 포함되어 있을 것이다. Write transaction에 의해 memory의 해당 address에 원하는 data가 실제로 문제 없이 write 되었는지 check 하려면 어떻게 해야 할까?

UVM 기반 testbench일 경우 checking을 위해 scoreboard 내에서 memory 영역에 대한 reference array를 관리해야 한다. 만약 memory가 1024개의 address를 가지고, 각 address에 8-bit data를 저장한다면 다음과 같이 reference array를 선언할 수 있다.

logic [7:0] ref[1024];

Write transaction이 발생하면 그에 따라 아래와 같이 reference array를 업데이트 한다.

// tr: write transaction
// - tr.addr: write address (10-bit)
// - tr.data: write data (8-bit)
ref[tr.addr] = tr.data;

그리고 check phase 또는 적절한 시점에 reference array에 저장된 값과 실제 memory 값을 비교하여 error가 없는지 확인한다.

// iterate 1024 times
foreach (reference[i]) begin
  if (reference[i] !== memory.read(i)) begin
    `uvm_error(get_type_name(), $sformatf("reference[%d] = 0x%h, memory.read(%d) = 0x%h", i, ref[i], i, memory.read(i)))
  end
end

위 예제에서는 address가 1024개 밖에 되지 않는 아주 작은 memory를 사용하였지만, 실제 memory는 훨씬 더 크다. 만약 memory의 address가 1024*1024*1024개, 즉, 1,073,741,824개로 많아진다면 어떻게 될까? Memory의 크기가 커진 만큼 reference array의 크기도 커지고, checking을 위한 loop의 크기도 커진다. 이는 곧 simulation 성능 및 구현 상의 문제로 이어지기 때문에 주의해야 한다. SystemVerilog의 associative array는 이러한 경우 매우 유용하게 사용된다.

Associative Array

Associative array는 실제 사용되기 전까지는 memory를 할당하지 않기 때문에 array의 크기를 미리 알 수 없거나, array의 크기가 크지만 그 중 일부만 사용되는 경우 활용도가 특히 높다. Dynamic array와 개념을 혼동하지 말아야 한다.

Associative array 선언 시 array의 크기를 따로 지정하지 않으며, 대신 data type 또는 wildcard index인 *를 통해 index를 지정한다. 만약 index를 string으로 지정하여 선언했다면 해당 associative array는 string을 이용하여 접근하게 된다. Wildcard index는 SystemVerilog LRM 상으로는 가능하지만 잘못된 사용을 피하기 위하여 특정 data type을 지정하여 사용하는 것이 일반적으로 권장된다.

logic [7:0] reference[int]; // int-type index
logic [7:0] reference[*]; // wildcard index

Associative array는 그 크기가 지정되지 않았으므로 사용할 때마다 필요한 크기 만큼만 memory가 할당된다. 따라서 다음과 같은 경우 0번지부터 1,073,741,823번지까지 넓은 영역을 사용하고 있지만, 실제 할당되는 memory의 크기는 4 byte 뿐이다.

reference[0] = 0;
reference[1024-1] = 8'h55;
reference[1024*1024-1] = 8'hAA;
reference[1024*1024*1024-1] = 8'hFF;

이제 scoreboard도 이에 맞게 수정해 보자. 기존 loop처럼 foreach 등을 사용하지 않고, 아래와 같은 방식을 사용하여 훨씬 효율적인 구현이 가능하다. Associative array는 exists(), first(), last(), next(), prev() 등 여러 method를 제공하고 있으므로 필요에 맞게 사용하면 된다. 각 method에 대한 자세한 설명은 하단의 References 섹션을 참고하자.

if (reference.first(i)) begin
  do begin
    if (reference[i] !== memory.read(i)) begin
      `uvm_error(get_type_name(), $sformatf("reference[%d] = 0x%h, memory.read(%d) = 0x%h", i, reference[i], i, memory.read(i)))
    end
  end while (reference.next(i));
end

References

No Comments

Post A Comment