Thứ Sáu, 12 tháng 7, 2019

[UVM] Bài 3 - Giải thích ngắn về Utility, Macro, UVM factory, TLM và các phase mô phỏng

Sau khi phân tích chi tiết các thành phần cần có của một môi trường mô phỏng UVM ở bài 2, bài này sẽ giải thích một số khái niệm và thuật ngữ cơ bản. Đồng thời, bài viết sẽ giải thích chức năng và ý nghĩa của các thành phần cần có trong một class mở rộng từ thư viện UVM. Nội dung bài này sẽ giúp việc hiểu môi trường UVM nhanh hơn và hỗ trợ cho bước "coding".
Chú ý, bài viết này không nhằm mục đích giải thích toàn bộ các thuật ngữ liên quan đến UVM mà chỉ tập trung vào một số điểm mà nhóm tác giả cho rằng cần phải được giải thích trước khi build môi trường.

1) Thư viện UVM
UVM là một phương pháp mô phỏng sử dụng một thư viện được xây dựng trên ngôn ngữ System Verilog. Đây là một khái niệm cơ bản nhất cần được nhắc lại để tạo một cái nhìn chung về UVM. Như vậy, các thành phần được viết bằng ngôn ngữ Verilog hoặc System Verilog có thể tích hợp dễ dàng với các thành phần của thư viện UVM trong một môi trường.
UVM là một thư viện mở với source code có thể được tải miễn phí tại trang của Accellera. Bất kỳ phần mềm mô phỏng nào hỗ trợ System Verilog đều có thể hỗ trợ thư viện UVM. Bạn chỉ cần include file top của thư viện UVM và khai báo (import) các thành phần UVM cần sử dụng trong code của mình là được. Điều này có thể được thực hiện bằng 2 dòng code sau đây:
`include "uvm.sv"
import uvm_pkg::*;
Thư viện UVM là một tập hợp các class, utility và macro được build sẵn giúp người dùng dễ dàng xây dựng môi trường mô phỏng của riêng mình.
Hình 1: Sơ đồ liên kết giữa các class trong thư viện UVM (tham khảo tái liệu số 1)
Cấu trúc, chức năng và hoạt động của các thành phần UVM được mô tả trong tài liệu tham khảo số 2 ở cuối bài viết.
2) Class
Một class trong thư viện UVM đơn giản là một định nghĩa class/endclass của System Verilog. Các class là thành phần chính và quan trọng nhất trong thư viện UVM. Một class chứa thành phần dữ liệu (data member) là các khai báo biến và kiểu dữ liệu, và các method (task hoặc function).
Một class có thể là:
  • Một class được mở rộng từ class khác, ví dụ như:
    • uvm_object được mở rộng từ class uvm_void  
    • uvm_transaction được mở rộng từ class uvm_object
    • ...
  • Một class gốc, ví dụ như uvm_void
Việc xây dựng thư viện bằng các class giúp phương pháp mô phỏng UVM có khả năng tái sử dụng (reusable) cao. Điều này có được là nhờ các đặc điểm linh động của class như tính kế thừa (inheritance), khả năng mở rộng (extension), khả năng ghi đè (override).
Như vậy, việc hiểu cấu trúc và thuộc tính của định nghĩa class là một điều rất quan trọng để hiểu về UVM. Nếu chư từng tìm hiểu về class của System Verilog, các bạn có thể đọc qua loạt bài trình bày ngắn gọn về class trong blog này.
Hình 2: Class và các thành phần của class 
3) Utility
Utility là "tiện ích". Đây là một thuật ngữ chỉ các công cụ, chức năng hoặc thành phần mà môi trường UVM hỗ trợ việc xây dựng môi trường mô phỏng UVM đơn giản hơn.
Một utility là có thể là các class, các macro, các kiểu dữ liệu, parameter định nghĩa sẵn phục vụ một mục đích cụ thể nào đó, ví dụ như:
  • Các tiện ích hỗ trợ cấu hình: cung cấp tài nguyên chuẩn cho việc chia sẻ dữ liệu
  • Các tiện ích hỗ trợ debug: cung cấp các thành phần hỗ trợ in các báo cáo, thông điệp mà người dùng mong muốn.
  • Các tiện ích hỗ trợ xây dựng testbench: cung cấp nền tảng thông tin giữa các thành phần như TLM và khả năng xây dựng môi trường mô phỏng linh động bằng UVM factory.
Utility là một khái niệm trừu tượng chỉ một "đặc điểm hữu ích" mà UVM hỗ trợ. Utility được cụ thể hóa thành các biến, class, method hay macro cụ thể trong thư viện UVM để hỗ trợ thực hiện "đặc điểm hữu ích" mà nó thể hiện.
Ví dụ, các tiện ích hỗ trợ debug được thể hiện ở các class, method  và macro phục vụ việc báo cáo các lỗi, in thông điệp và kết quả khi chạy mô phỏng như uvm_report, uvm_report_info, uvm_report_warning, uvm_report_error, uvm_report_fatal, ...
Hình 3: Ví dụ về utility hỗ trợ debug
4) Macro
Macro là một nhóm các loại cấu trúc của System Verilog hoặc UVM để thực thi hoặc đặc tả một chức năng nào đó. Thay vì dùng nhiều cấu trúc hoặc phát biểu khác nhau để thực hiện một chức năng mong muốn, người dùng chỉ cần dùng một macro tương ứng để mô tả.
Sau đây, chúng ta cùng tìm hiểu cấu trúc của một macro trong UVM để hiểu rõ hơn. Macro sử dụng trong ví dụ này là `uvm_info
`uvm_info(ID, MSG, VERBOSITY)
Macro này có chức năng "gọi uvm_report_info nếu VERBOSITY của `uvm_info thấp hơn VERBOSITY được cấu hình trong báo cáo liên quan". Trong câu định nghĩa chức năng của `uvm_info, chữ VERBOSITY đầu tiên là giá trị điền trong macro `uvm_info còn chữ VERBOSITY thứ hai là giá trị cấu hình chung (mức ngưỡng) cho các báo cáo (report) của UVM.
Trước hết, UVM định nghĩa sẵn một số mức VERBOSITY hỗ trợ việc lọc và in ra các thông điệp khi chạy mô phỏng.
UVM_NONE = 0 (highest priority messages)

UVM_LOW = 100

UVM_MEDIUM = 200

UVM_HIGH = 300

UVM_FULL = 400

UVM_DEBUG = 500 (lowest priority messages) 
Ngưỡng mặc định của VERBOSITY khi chạy mô phỏng là UVM_MEDIUM, tất cả các thông điệp có VERBOSITY là UVM_MEDIUM hoặc thấp hơn như UVM_LOW và UVM_NONE sẽ được in ra khi chạy mô phỏng.
Nếu cần thay đổi ngưỡng của VERBOSITY khi chạy mô phỏng thì một cách đơn giản là chúng ta thêm tùy chọn sau vào lệnh chạy:
+UVM_VERBOSITY=<Verbosity_level>
Ví dụ, nếu lệnh chạy mô phỏng là (lệnh chạy cho QuestaSim):
vsim -novopt work.testTop +UVM_TESTNAME=cTest +UVM_VERBOSITY=UVM_LOW
Giả sử, chúng ta có các thông điệp như sau:
`uvm_info("MYINFO1", "", UVM_NONE)

`uvm_info("MYINFO2", "", UVM_LOW)

`uvm_info("MYINFO3", "", UVM_MEDIUM)

`uvm_info("MYINFO4", "", UVM_HIGH)

`uvm_info("MYINFO5", "", UVM_FULL)

`uvm_info("MYINFO6", "", UVM_DEBUG)
Với lệnh chạy mô phỏng đã cho, chỉ MYINFO1 và MYINFO2 được in ra vì VERBOSITY của chúng bằng và thấp hơn mức ngưỡng đã thiết lập ở lệnh chạy.
Quay lại với macro `uvm_info, macro này tương ứng với đoạn code sau:
begin
  if(uvm_report_enabled(VERBOSITY,UVM_INFO,ID))
    uvm_report_info (ID, MSG, VERBOSITY, `uvm_file, `uvm_line, "", 1);
end
Ý nghĩa của đoạn code trên như sau:
  • uvm_report_enabled: So sánh VERBOSITY với mức ngưỡng.
  • uvm_report_info: In thông điệp với ID, MSG và VERBOSITY được thiết lập trong macro `uvm_info.
  • `uvm_file là một macro ứng với đoạn code sau:
`ifdef UVM_REPORT_DISABLE_FILE
`define uvm_file ""
`else
`define uvm_file `__FILE__
`endif
  • `uvm_line là một macro ứng với đoạn code sau:
`ifdef UVM_REPORT_DISABLE_LINE
`define uvm_line 0
`else`define uvm_line `__LINE__`endif
Các bạn có thể thấy, macro `uvm_info thay thế cho một nhóm code để thực thi chức năng in thông điệp như mong muốn.
Hình 4: Các thành phần code tạo thanh macro `uvm_info
5) UVM Factory là gì?
UVM Factory là "nhà máy" sản xuất (tạo) ra các đối tượng (object) và thành phần (component) UVM. Đây là một đặc điểm quan trọng giúp việc xây dựng môi trường UVM trở nên linh động. Khi xây dựng các class cho môi trường UVM, chúng ta sẽ sử dụng chức năng này thường xuyên. Chú ý, nhóm tác giả không có tham vọng giải thích toàn bộ các đặc điểm, ý nghĩa và ứng dụng của UVM factory trong mục này. Mục này chỉ trình bày ngắn gọn để các bạn có thể hiểu "cơ bản về UVM factory" và "cách sử dụng UVM factory". Mục này sẽ giúp các bạn đọc code môi trường dễ dàng hơn ở những bài sau.
Một nhà máy sẽ sản xuất ra các sản phẩm dựa trên nguyên liệu được cung cấp. UVM factory cũng vậy, để vận hành nó, chúng ta cần:
  • Cung cấp nguyên liệu đầu vào: "Nguyên liệu đầu vào" của UVM factory là các class được viết bởi người build môi trường UVM. Các class cần được đăng ký (register) với UVM factory để UVM factory hiểu đâu là "nguyên liệu đầu vào" của nó.
  • Yêu cầu sản xuất sản phẩm: "Yêu cầu sản xuất" là lệnh tạo đối tượng hoặc thành phần từ một "nguyên liệu đầu vào" cụ thể.
Đăng ký một class với UVM factory có thể được thực hiện bằng một số cách sau:
  • Đối với class mở rộng hoặc kế thừa từ uvm_object:
    • `uvm_field_utils_begin(T) và `uvm_field_utils_end
    • `uvm_object_utils(T)
    • `uvm_object_param_utils(T) và `uvm_object_utils_begin
    • `uvm_object_param_utils_begin(T) và `uvm_object_utils_end
    • `uvm_field_utils_begin(T) và `uvm_field_utils_end
    • `uvm_object_registry(T,S) 
  • Đối với class mở rộng hoặc kế thừa từ uvm_component:
    • `uvm_field_utils_begin(T) và `uvm_field_utils_end
    • `uvm_component_utils(T)
    • `uvm_component_param_utils(T) và `uvm_component_utils_begin
    • `uvm_component_param_utils_begin(T) và `uvm_component_end
    • `uvm_component_registry(T,S)
Trong đó:
  • T là loại dữ liệu (type), là tên class cần đăng ký.
  • S là chuỗi ký tự (string), thường cũng là tên của class.
Yêu cầu sản xuất (tạo) một thành phần hoặc đối tượng từ UVM factory sử dụng function sau:
type_name::type_id::create (string name, uvm_component parent)
Trong đó:
  • type_name: là tên class đã đăng ký với UVM factory. Tên này ứng với thông số "T" khi đăng ký class với UVM factory.
  • type_id::create() là một method dùng để tạo thành phần hoặc đối tượng với loại type_name mong muốn.
  • name parent là hai đối số có ý nghĩa như constructor chuẩn. 

Hình 5: Minh họa về UVM factory
Sau đây là một ví dụ về việc đăng ký class và tạo đối tượng thông qua UVM factory:
  • Đăng ký class cApbMasterDriver đến UVM factory:
class cApbMasterDriver extends uvm_driver #(cApbTransaction);
  `uvm_component_utils(cApbMasterDriver)
  ...
endclass
  • Tạo đối tượng coApbMasterDriver của loại dữ liệu cApbMasterDriver từ UVM factory trong class cApbMasterAgent:
class cApbMasterAgent extends uvm_agent;
  cApbMasterDriver coApbMasterDriver;
  ...
  function void build_phase(uvm_phase phase);
    ...
  coApbMasterDriver    = cApbMasterDriver::type_id::create ("coApbMasterDriver",this);
    ...
  endfunctionendclass
6) TLM (Transaction Level Modeling)
TLM là mô hình hóa mức transaction. Đối với DUT, các thành phần kết nối và trao đổi dữ liệu qua các giao tiếp (interface) ở mức tín hiệu (signal). Trong quá trình hoạt động, các tín hiệu này sẽ thay đổi mức logic giữa "0" và  "1".
Đối với các thành phần khác trong môi trường mô phỏng, việc trao đổi thông tin và dữ liệu không cần ở mức tín hiệu. Nó cần một cách thức đơn giản và hiệu quả hơn giúp kết nối các thành phần môi trường dễ dàng, đó chính là TLM. Lúc này, các thành phần sẽ được kết nối thông qua các port (TLM1.x) hoặc các socket (TLM2.0).
Transaction là gói thông tin được transfer. TLM hỗ trợ việc chuyển transaction từ thành phần này đến thành phần khác.
Kết nối các thành phần mức transaction sử dụng TLM sẽ gồm các bước sau:
  • Kết nối TLM port: Khai báo port cho 2 thành phần và kết nối chúng lại.
  • Trao đổi transaction: Chuyển transaction từ một thành phần này đến thành phần khác.
Vì nhóm tác giả sẽ sử dụng analysis port để kết nối giữa Monitor và Scoreboard nên phần này trình bày về cách sử dụng của loại port này như một ví dụ. Loại kết nối khác, dùng TLM export và port, sẽ trình bày riêng trong bài sau vì nó có chút phức tạp hơn.
Hình 6: Minh họa kết nối giữa Monitor và Scoreboard thông qua analysis port
Hình trên minh họa cách kết nối Monitor và Scoreboard thông qua một analysis port. Phía gửi (Monitor) sẽ khai báo một analysis port và dùng method write() để gửi transaction. Phía nhận (Scoreboard) sẽ khai báo một analysis implementation, các bạn hãy xem nó như một port nhận, để nhận transaction. Bên cạnh đó, phía nhận còn xử lý transaction nhận thông qua code được mô tả trong method writesuffix(). Chú ý, suffix được khai báo bằng cách sử dụng macro `uvm_analysis_imp_decl. Macro này hỗ trợ việc thêm suffix để định nghĩa thêm các class mới, nó giúp phía nhận (Scoreboard) có thể nhận các transaction từ nhiều analysis port khác nhau.
Sau đây, nhóm tác giả sẽ hướng dẫn chi tiết cách tạo và chạy thử một kết nối TLM port giữa một Monitor và Scoreboard để bạn đọc có thể thử nghiệm. Hãy chú ý đến các dòng code được tô xanh, đây là các dòng code liên quan đến TLM port.
Khai báo analysis port cho Monitor gửi dữ liệu qua method write(). Chú ý, transaction ở đây là một dữ liệu kiểu int. Monitor sẽ gửi 3 gói transaction có giá trị lần lượt là 0, 1 và 2.
class my_monitor extends uvm_monitor;
`uvm_component_utils(my_monitor)

uvm_analysis_port #(int) my_ap;
function new (string name = "my_monitor", uvm_component parent = null);
  super.new(name,parent);
endfunction 
function void build_phase(uvm_phase phase);
           super.build_phase(phase);
           my_ap = new("my_ap", this); endfunction 
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
    for (int my_data = 0; my_data < 3; my_data++) begin
      $display("Monitor sends: %d", my_data);
  my_ap.write(my_data);
    end
  endtask


endclass
Khai báo một analysis implementation cho Scoreboard và xử lý transaction nhận được. Trong trường hợp này, transaction nhận được bởi Scoreboard chỉ được in ra khi chạy mô phỏng. Suffix được khai báo là _frmMonitor.
`uvm_analysis_imp_decl(_frmMonitor)
class my_scoreboard extends uvm_scoreboard;
  `uvm_component_utils(my_scoreboard)

  uvm_analysis_imp_frmMonitor #(int, my_scoreboard) imp_frmMonitor;

  function new (string name = "my_scoreboard", uvm_component parent);
    super.new(name, parent);
    imp_frmMonitor = new ("imp_frmMonitor", this);
  endfunction

 virtual function void write_frmMonitor (int in_frmMonitor);
    $display("Scoreboard receives: %d", in_frmMonitor);
  endfunction


endclass
Kết nối TLM port giữa Monitor và Scoreboard trong môi trường UVM. Một class cEnv được mở rộng từ uvm_env. Class này khai báo một đối tượng Monitor và một đối tượng Scoreboard. Hai đối tượng này được kết nối với nhau thông qua TLM port trong phase connect. Chi tiết về các phase trong môi trường mô phỏng UVM sẽ được trình bày sau.
class cEnv extends uvm_env;
  //Register to Factory
`uvm_component_utils_begin(cEnv)
`uvm_component_utils_end
  //Declare Agent, Scoreboard and Sequencer
my_scoreboard sb_inst;
my_monitor mon_inst;

  //Constructor
function new (string name = "cEnv", uvm_component parent = null);
super.new(name,parent);
endfunction
//Create the objects
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sb_inst = my_scoreboard::type_id::create("sb_inst",this);
mon_inst = my_monitor::type_id::create("mon_inst",this);
endfunction 
//Connect UVM components
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
    //Connect Monitor and Scoreboard by TLM port
mon_inst.my_ap.connect(sb_inst.imp_frmMonitor);
endfunction
endclass
Các bạn có thể tải file code với đầy đủ các thành phần cần thiết để chạy mô phỏng tại đây hoặc cuối bài viết. Sau đó chạy mô phỏng trên QuestaSim với các lệnh theo thứ tự sau:
  • Tổng hợp System Verilog code:
vlog -work work -sv tlm_test.sv +incdir+C:/questasim64_10.2c/uvm-1.2/src +define+UVM_CMDLINE_NO_DPI +define+UVM_REGEX_NO_DPI +define+UVM_NO_DPI
  • Thực thi mô phỏng với lệnh sau:
vsim -novopt work.tlm_test +UVM_TESTNAME=cTest
  • Chạy mô phỏng trong 1ns:
run 1ns
  • Kết quả:
#UVM_INFO C:/questasim64_10.2c/uvm-1.2/src/base/uvm_root.svh(392) @ 0: reporter [UVM/RELNOTES]
# ----------------------------------------------------------------
# UVM-1.2
# (C) 2007-2014 Mentor Graphics Corporation
# (C) 2007-2014 Cadence Design Systems, Inc.
# (C) 2006-2014 Synopsys, Inc.
# (C) 2011-2013 Cypress Semiconductor Corp.
# (C) 2013-2014 NVIDIA Corporation
# ----------------------------------------------------------------
#
#   ***********       IMPORTANT RELEASE NOTES         ************
#
#   You are using a version of the UVM library that has been compiled
#   with `UVM_NO_DEPRECATED undefined.
#   See http://www.eda.org/svdb/view.php?id=3313 for more details.
#
#   You are using a version of the UVM library that has been compiled
#   with `UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR undefined.
#   See http://www.eda.org/svdb/view.php?id=3770 for more details.
#
#       (Specify +UVM_NO_RELNOTES to turn off this notice)
#
# UVM_INFO C:/questasim64_10.2c/uvm-1.2/src/base/uvm_root.svh(453) @ 0: reporter [NO_DPI_TSTNAME] UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI
# UVM_INFO @ 0: reporter [RNTST] Running test cTest...
# UVM_INFO C:/questasim64_10.2c/uvm-1.2/src/base/uvm_traversal.svh(279) @ 0: reporter [UVM/COMP/NAMECHECK] This implementation of the component name checks requires DPI to be enabled
# Monitor sends:           0
# Scoreboard receives:           0
# Monitor sends:           1
# Scoreboard receives:           1
# Monitor sends:           2
# Scoreboard receives:           2
# UVM_INFO C:/questasim64_10.2c/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]
# --- UVM Report Summary ---
#
# ** Report counts by severity
# UVM_INFO :    4
# UVM_WARNING :    0
# UVM_ERROR :    0
# UVM_FATAL :    0
# ** Report counts by id
# [NO_DPI_TSTNAME]     1
# [RNTST]     1
# [UVM/COMP/NAMECHECK]     1
# [UVM/RELNOTES]     1
#
# ** Note: $finish    : C:/questasim64_10.2c/uvm-1.2/src/base/uvm_root.svh(517)
#    Time: 0 ns  Iteration: 260  Instance: /tlm_test
Các bạn có thể thấy gói transaction gửi qua analysis port ở phía Monitor và nhận ở Scoreboard.
7) Các giai đoạn (phase) chạy mô phỏng
Các thành phần UVM được mở rộng từ uvm_component hoặc các class con (child class) của uvm_component như uvm_driver, uvm_sequencer, uvm_monitor, ..., sẽ thực thi hành vi theo một thứ tự nghiêm ngặt. Thứ tự này được quy định bởi các phase đã được định nghĩa trong UVM. UVM có 9 phase lớn, trong đó run phase được chia thành 12 phase nhỏ.
UVM phase hoạt động như một cơ chế đồng bộ giúp các thành phần UVM hoạt động theo một trình tự thời gian nhất định trong suốt quá trình mô phỏng. Các thành phần UVM phải thực hiện xong phase hiện tại trước khi đến phase kế tiếp.
Đối với mục này, các bạn chỉ cần nắm về trình tự và ý nghĩa của các phase để hiểu code UVM ở những bài kế tiếp.
Hình 7: Các phase và method tương ứng để định nghĩa phase
Để xây dựng chức năng và hành vi thực thi ở mỗi phase, chúng ta sẽ sử dụng method tương ứng như hình trên.
  • build_phase(): build các thành phần và khởi tạo các đối tượng. Ví dụ, đoạn code sau đây khởi tạo 2 đối tượng, một đối tượng thuộc loại dữ liệu my_scoreboard và một đối tượng thuộc loại dữ liệu my_monitor, và gán handle của chúng đến sb_inst mon_inst.
function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  sb_inst = my_scoreboard::type_id::create("sb_inst",this);
 mon_inst = my_monitor::type_id::create("mon_inst",this);
endfunction
  • connect_phase(): Kết nối các thành phần UVM. Ví dụ, đoạn code dưới đây thực hiện kết nối giữa instance mon_inst và sb_inst thông qua analysis port.
function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  //Connect Monitor and Scoreboard by TLM port
  mon_inst.my_ap.connect(sb_inst.imp_frmMonitor);
endfunction
  • end_of_elaboration_phase(): Thực thi các cấu hình cho các thành phần UVM sau khi kết nối nếu cần.
  • start_of_simulation_phase(): Khởi tạo các cấu hình trước khi chạy mô phỏng hoặc in các thông báo và thông tin về cấu trúc liên kết nếu cần.
  • run_phase(): Thực thi mô phỏng. Phần code chính của một test pattern sẽ được thực thi ở phase này. Ví dụ, đoạn code sau chỉ in một lỗi nếu thời gian chạy mô phỏng là 1ms.
task run_phase(uvm_phase phase);
  super.run_phase(phase);
  fork    begin      #1ms;
      `uvm_error("TEST SEQUENCE", "TIMEOUT!!!")
    end  join_any  disable fork;
endtask
  • extract_phase(): Thu thập tất cả các thông tin cần thiết.
  • check_phase(): So sánh và kiểm tra các kết quả.
  • report_phase(): Báo cáo kết quả PASS/FAIL. Ví dụ, đoạn code sau đây dùng để báo cáo kết quả mô phỏng là COMPLETED hoặc "NOT COMPLETED".
function void report_phase(uvm_phase phase);
  super.report_phase(phase);
  if (queue_transaction_1 == null) begin  `uvm_info("COMPLETED", "Write and Read transaction succesfull", UVM_LOW )
  end else     `uvm_info("NOT COMPLETED", "Write and Read transaction fail", UVM_LOW)
endfunction
  • final_phase(): Thực hiện một số xử lý, thao tác cuối cùng trước khi kết thúc mô phỏng.
Trên đây là một số khái niệm cơ bản mà nhóm tác giả thấy cần phải giải thích trước khi phân tích chi tiết các thành phần của môi trường UVM trên ví dụ UART-APB.

Tham khảo:
1/ Accellera; Universal Verification Methodology (UVM) 1.2 User’s Guide; October 8, 2015
2/ Accellera; Universal Verification Methodology (UVM) 1.2  Class ReferenceJune 2014
3/ IEEE; IEEE Std 1800™-2017; IEEE Standard for SystemVerilog -- Unified Hardware Design, Specification, and Verification Language; December 6, 2017

Lịch sử cập nhật:
1/ 2019.07.12 - Tạo lần đầu

Danh sách tác giả:
1. Phạm Thanh Trâm
2. Đoàn Đức Hoàng (email: hoangbk154@gmail.com)
3. Trương Công Hoàng Việt
4. Nguyễn Sinh Tơn
5. Nguyễn Hùng Quân

1 bình luận: