Thứ Bảy, 14 tháng 9, 2019

[UVM] Bài 6 - Mô tả hoạt động của Monitor và Scoreboard

Bài viết này mô tả giao tiếp và chức năng của Monitor và Scoreboard trong môi trường UVM đã được build ở bài 5. Bài viết tập trung vào việc giải thích làm thế nào một transaction được truyền từ Monitor đến Scoreboard và làm thế nào Scoreboard kiểm tra dữ liệu truyền nhận giữa hai UART trong môi trường. Bên cạnh đó, chức năng chi tiết của Monitor cũng sẽ được trình bày.
Tham khảo các bài viết trước ở đây.

1) Kết nối của Monitor và Scoreboard
1.1) Các giao tiếp và ports
Trước khi đi vào chức năng chi tiết của Monitor và Scoreboard. Nội dung phần này mô tả chi tiết kết nối của Monitor và Scoreboard trong môi trường.
Hình 1: Sơ đồ khối của môi trường UVM
Trong môi trường này, uart_0, còn gọi là UART-TX, kết nối với Agent coApbMasterAgentTx còn uart_1, còn gọi là UART-RX, kết nối với Agent coApbMasterAgentRx. Chú ý, việc đặt tên -TX và -RX không có nghĩa là uart_0 chỉ truyền còn uart_1 chỉ nhận. Hai UART này có chức năng truyền và nhận như nhau.
Quan sát hình minh họa trên đây, bạn sẽ thấy Monitor có các kết nối sau:
  • APB interface có tên instance là vifApbMaster để giám sát tất cả các transaction đọc/ghi
  • Interrupt interface có tên instance là vifInterrupt để giám sát tất cả các tín hiệu interrupt
  • Analysis port có tên instance là ap_toScoreboard để gửi các transaction có kiểu dữ liệu là cApbTransaction trên APB interface đến Scoreboard
Bên cạnh đó, giữa Monitor và Scoreboard còn một analysis port khác tên preset_toScoreboard được dùng để gửi thông tin reset cho Scoreboard. Kiểu dữ liệu gửi trên port này là logic. Cái này không thể hiện trên hình minh họa nên các bạn chú ý khi đọc code.
Trong MonitorcApbMasterMonitor.sv, các thành phần kết nối trên được khai báo như sau:
//Declare analysis ports
uvm_analysis_port #(logic) preset_toScoreboard;
uvm_analysis_port #(cApbTransaction) ap_toScoreboard;
//Declare the monitored interfaces
virtual interface ifApbMaster vifApbMaster;
virtual interface ifInterrupt vifInterrupt;
Hai analysis port sẽ được tạo trong build_phase
ap_toScoreboard = new("ap_toScoreboard", this); preset_toScoreboard = new("preset_toScoreboard", this);
Scoreboard có các kết nối như sau:
  • Port tên aimp_frmMonitorTX để nối với analysis port ap_toScoreboard của Monitor trên Agent coApbMasterAgentTx.
  • Port tên aimp_frmMonitorRX để nối với analysis port ap_toScoreboard của Monitor trên Agent coApbMasterAgentRx.
  • Port tên aimp_resetfrmTX để nối với analysis port preset_toScoreboard của Monitor trên Agent coApbMasterAgentTx.
Scoreboard không có port kết nối với analysis port preset_toScoreboard của Monitor trên Agent coApbMasterAgentRx vì trong môi trường này, chân preset_n của hai UART được sử dụng chung một nguồn. Khi reset xảy ra, toàn bộ DUT sẽ được reset.
Trong ScoreboardcScoreboard.sv, các thành phần kết nối được khai báo như sau:
uvm_analysis_imp_frmMonitorTX #(cApbTransaction, cScoreboard) aimp_frmMonitorTX;
uvm_analysis_imp_frmMonitorRX #(cApbTransaction, cScoreboard) aimp_frmMonitorRX;
uvm_analysis_imp_resetfrmTX #(logic, cScoreboard) aimp_resetfrmTX;
Các port này sẽ được tạo trong build_phase của Scoreboard như sau:
imp_frmMonitorTX = new("aimp_frmMonitorTX", this);
aimp_frmMonitorRX = new("aimp_frmMonitorRX", this);
aimp_resetfrmTX = new("aimp_resetfrmTX", this);
Chú ý, phần hậu tố khi khai báo port (tô màu vàng) phải được đăng ký để sử dụng như sau:
`uvm_analysis_imp_decl(_frmMonitorTX)
`uvm_analysis_imp_decl(_frmMonitorRX)
`uvm_analysis_imp_decl(_resetfrmTX)
1.2) Kết nối
Monitor kết nối với đến APB interface và interrupt interface thông qua khai báo uvm_config_db testTop.sv.
//Connect APB interface
uvm_config_db#(virtual interface ifApbMaster)::set(null,"uvm_test_top.coEnv.coApbMasterAgentTx*","vifApbMaster",vifApbMaster_Tx);
uvm_config_db#(virtual interface ifApbMaster)::set(null,"uvm_test_top.coEnv.coApbMasterAgentRx*","vifApbMaster",vifApbMaster_Rx);
//Connect Interrupt interface
uvm_config_db#(virtual interface ifInterrupt)::set(null,"uvm_test_top.coEnv.coApbMasterAgentTx*","vifInterrupt",vifInterrupt_Tx);
uvm_config_db#(virtual interface ifInterrupt)::set(null,"uvm_test_top.coEnv.coApbMasterAgentRx*","vifInterrupt",vifInterrupt_Rx);
Các khai báo uvm_config_db giúp kết nối các instance của interface khai báo ở testTop.sv kết nối đến các thành phần UVM trong các Agent coApbMasterAgentTx và coApbMasterAgentRx.
Trong build_phase của Monitor, các kết nối sẽ được kiểm tra lại để đảm bảo các kết nối này đã tồn tại.
//Check the APB connection
if(!uvm_config_db#(virtual interface ifApbMaster)::get(this,"","vifApbMaster",vifApbMaster)) begin
  `uvm_error("cApbMasterDriver","Can NOT get vifApbMaster!!!")
end
//Check the interrupt connection
if(!uvm_config_db#(virtual interface ifInterrupt)::get(this,"","vifInterrupt",vifInterrupt)) begin
  `uvm_error("cVSequencer","Can NOT get vifInterrupt!!!")
end
Một thông điệp lỗi sẽ báo thông qua macro `uvm_error nếu kết nối với interface mong muốn không được tìm thấy.
2) Cấu trúc và chức năng của Monitor
Monitor (cApbMasterMonitor.sv) được mở rộng từ class uvm_monitor và xây dựng một số chức năng riêng trong hai phase:

  1. build_phase
    1. Kiếm tra kết nối của Monitor trong môi trường. Cụ thể, hai interface vifApbMaster và vifInterrupt được kiểm tra.
    2. Tạo đối tượng của các TLM analysis port. Cụ thể, hai port được tạo là ap_toScoreboard và preset_toScoreboard.
    3. Tạo đối tượng coApbTransaction để lưu lại các transaction trên APB interface. Chú ý, đối tượng này phải cùng kiểu dữ liệu với kiểu dữ liệu sẽ được gửi qua analysis port ap_toScoreboard , kiểu dữ liệu này là cApbTransaction.
  2. run_phase sẽ thực hiện các task sau song song 
    1. collect_data() giám sát APB interface, phát hiện read/write transfer trên APB interface và lưu lại trong đối tượng coApbTransaction. Sau đó, method write() được sử dụng để gửi gói coApbTransaction đến TLM analysis port ap_toScoreboard. Phía Scoreboard sẽ nhận và xử lý
    2. detect_reset() giám sát tín hiệu reset, preset_n trong testTop.sv, của môi trường, lưu lại trong biến preset_n và gửi giá trị này qua analysis port preset_toScoreboard bằng method write().
    3. monitor_ifEn() giám sát các APB transaction ghi vào thanh ghi interrupt enable của DUT, DUT gồm 2 UART là UART-TX và UART-RX. Nếu phát hiện transaction ghi vào thanh ghi interrtupt enable, địa chỉ offset 16'h0010, giá trị ghi vào các bit interrupt enable sẽ được lau lại trong biến ifEn[4:0]. Biến này sẽ được dùng để điều khiển task detect_intf() với mục đích xác định xem một tín hiệu interrupt tích cực, chuyển từ mức 0 sang mức 1, có đúng hay không.
    4. detect_intf() giám sát tất cả các tín hiệu interrupt thông qua interface vifInterrupt. Nếu một interrupt tích cực nhưng không được enable, `uvm_error sẽ thông báo. Nếu một interrupt tích cực và được enable, một `uvm_warning sẽ thông báo cho người test biết để kiểm tra lại xem có đúng như mong muốn hay không. Một biến ifSta được sử dụng để đảm bảo các thông điệp `uvm_error và `uvm_warning chỉ in ra một lần khi interrupt bắt đầu tích cực. Nếu không có biến này, các thông điệp sẽ được in liên tục trong suốt quá trình tín hiệu interrupt tích cực sau mỗi cạnh lên xung clock.
Hình 2: Cấu trúc và chức năng chính của Monitor (cApbMasterMonitor.sv)
3) Cấu trúc và chức năng của Scoreboard
Scoreboard (cScoreboard.sv) được mở rộng từ class uvm_scoreboard và thêm các chức năng riêng như sau:

  1. build_phase tạo ra các đối tượng của analysis implementation port gồm:
    1. aimp_frmMonitorTX kết nối với analysis port ap_toScoreboard của Monitor trong agent coApbMasterAgentTx, xem cEnv.sv.
    2. aimp_frmMonitorRX kết nối với analysis port ap_toScoreboard của Monitor trong agent coApbMasterAgentRx, xem cEnv.sv.
    3. aimp_resetfrmTX kết nối với analysis port preset_toScoreboard của Monitor trong agent coApbMasterAgentTx, xem cEnv.sv. Như đã trình bày ở trên, do reset của hệ thống là chung nên chỉ cần kết nối một port để giám sát trạng thái reset, không cần kết nối port đến agent coApbMasterAgentRx.
  2. run_phase thực thi các task write<suffix> với suffix được khai báo bởi `uvm_analysis_imp_decl. Các task này gọi là các "analysis implementation" dùng để xử lý các transaction nhận trên analysis implementation port. Các bạn xem lại mục TLM trong bài viết số 3.
    1. write_resetfrmTX() giám sát trạng thái reset được Monitor gửi đến là tích cực cờ trạng thái rst_flg=1 nếu reset tích cực mức 0.
    2. write_frmMonitorTX() giám sát việc đọc dữ liệu từ thanh ghi dữ liệu của UART-TX (uart_0), địa chỉ offset 16'h000C. Nếu có một tranasaction đọc thanh ghi dữ liệu, dữ liệu đọc trên prdata[7:0] sẽ so sánh với dữ liệu truyền phía UART-RX (uart_1). Nếu giá trị dữ liệu đọc trùng khớp thì thông điệp báo SUCCESS sẽ được in ra, nếu dữ liệu đọc bị sai thì thông điệp báo lỗi FAIL sẽ được in ra.
    3. write_frmMonitorRX() giám sát việc đọc dữ liệu từ thanh ghi dữ liệu của UART-RX (uart_1), địa chỉ offset 16'h000C. Nếu có một tranasaction đọc thanh ghi dữ liệu, dữ liệu đọc trên prdata[7:0] sẽ so sánh với dữ liệu truyền phía UART-TX (uart_0). Nếu giá trị dữ liệu đọc trùng khớp thì thông điệp báo SUCCESS sẽ được in ra, nếu dữ liệu đọc bị sai thì thông điệp báo lỗi FAIL sẽ được in ra.
  3. report_phase sẽ kiểm tra lại số lượng dữ liệu mong muốn truyền trên UART-TX và UART-RX. Nếu vẫn còn dữ liệu cần truyền ở UART-TX nhưng chưa được đọc và kiểm tra trên UART-RX hoặc ngược lại thì Scoreboard sẽ cảnh báo với `uvm_warning. Chú ý, đây không phải là một lỗi (error) vì nó phụ thuộc vào mục đích test của người viết testbench (testcase).
Hình 3: Cấu trúc và chức năng của Scoreboard (cScoreboard.sv)
Để kiểm tra dữ liệu truyền nhận giữa 2 UART, Scoreboard thực hiện như sau:
  1. Lưu lại dữ liệu cần truyền trên mỗi UART trong một hàng đợi (queue), nó tương tự như một FIFO
  2. Tại UART phía đối diện, UART nhận, mỗi dữ liệu đọc ra sẽ được so sánh với dữ liệu trong FIFO đã lưu ở bước trên.
  3. Sau mỗi lần so sánh, dữ liệu đã so sánh trong FIFO sẽ được xóa.
Thuật toán chi tiết để kiểm tra dữ liệu truyền từ UART-TX đến UART-RX sẽ được trình bày sau đây. Chiều từ UART-RX đến UART-TX thực hiện tương tự nên sẽ không trình bày chi tiết.
Đầu tiên, phần xử lý cập nhật dữ liệu truyền vào hàng đợi (FIFO) như sau:
1. Kiểm tra trạng thái reset thông qua cờ rst_flg Nếu cờ này bằng 1, tức là có reset, thì Scoreboard sẽ khởi động lại và xóa toàn bộ FIFO lưu dữ liệu truyền
queueTransTX.delete();
uartEnTX = 1'b0;
2. Nếu không phải trong trạng thái reset, rst_flg=0, bit báo trạng thái enable của UART-TX sẽ luôn được cập nhật đầu tiên nếu có bất cứ transaction ghi đến thanh ghi SE, offset là 16'h0004.
if (TransOnTX.pwrite && (TransOnTX.paddr[15:0] == 16'h0004)) begin
  uartEnTX = TransOnTX.pwdata[0];
end
 3. Nếu UART-TX được enable, uartEnTX=1, và có transaction ghi vào thanh ghi dữ liệu, địa chỉ offset là 16'h000C thì dữ liệu này là dữ liệu cần truyền nên sẽ lưu vào cuối FIFO. Chú ý, chỉ lưu 8 bit LSB, 24 bit đầu là 0.
else if (TransOnTX.pwrite && (TransOnTX.paddr[15:0] == 16'h000C) && uartEnTX) begin  queueTransTX.push_back(TransOnTX.pwdata & 32'h0000_00ff);
end
Phần xử lý lưu dữ liệu truyền vào FIFO của UART-TX được thực hiện bởi method write_frmMonitorTX. Method này lấy APB transaction từ Monitor cảu agent coApbMasterAgentTx.
Hình 4: Giai thuật cập nhật dữ liệu truyền của Scoreboard
Tiếp theo, phần xử lý kiểm tra dữ liệu đọc, dữ liệu truyền từ UART-TC đến UART-RX, trên UART-RX được thực hiện như sau:
1. Kiểm tra trạng thái reset thông qua cờ rst_flg Nếu cờ này bằng 1, tức là có reset, thì Scoreboard sẽ không thực thi quá trình kiểm tra dữ liệu đọc.
2. Nếu không phải trong trạng thái reset, rst_flg=0, bit báo trạng thái enable của UART-RX sẽ luôn được cập nhật đầu tiên nếu có bất cứ transaction ghi đến thanh ghi SE, offset là 16'h0004.
if (TransOnRX.pwrite && (TransOnRX.paddr[15:0] == 16'h04)) begin
  uartEnRX = TransOnRX.pwdata[0];
end
 3. Nếu UART-RX được enable, uartEnRX=1, và có transaction đọc từ thanh ghi dữ liệu, địa chỉ offset là 16'h000C thì dữ liệu này là dữ liệu sẽ được kiểm tra.
4. Lấy phần tử đầu tiên từ FIFO lưu dữ liệu truyền của UART-TX, queueTransTX.
queueCompRX = queueTransTX[0];
4. So sánh 8 bit dữ liệu đọc được với phần tử đầu tiên lấy từ FIFO.
  • Nếu hai giá trị bằng nhau, in ra thông điệp báo SUCCESS
  • Nếu hai giá trị khác nhau, in ra thông điệp báo FAIL
if ((TransOnRX.prdata & 32'h0000_00ff) == queueCompRX) begin  `uvm_info("SB INFO", $sformatf("[%t] SUCCESS on UART-RX: transfer data = %2h, queueTransTX size = %d", $time, TransOnRX.prdata, queueTransTX.size()), UVM_LOW);
endelse begin  `uvm_error("SB ERROR", $sformatf("[%t] FAIL on UART-RX: read data = %2h, expected data =%2h, queueTransTX size = %d", $time, TransOnRX.prdata, queueCompRX, queueTransTX.size()))
end
5. Kiểm tra lại số phần tử trong FIFO queueTransTX.
  • Nếu FIFO rỗng, in ra thông điệp báo dữ liệu đọc được không phải là dữ liệu được truyền từ UART-TX. Điều này xảy ra khi phát một transaction đọc thanh ghi dữ liệu khi nó rỗng.
  • Nếu FIFO không rỗng, thực hiện xóa phần tử đầu tiên của FIFO, phần tử vừa dùng để so sánh ở bước trên
if (queueTransTX.size() != 0) begin
  queueTransTX.delete(0);
endelse begin  uvm_warning("SB UNFINISH-RX", "Read data but do NOT have any transmitted data");
end
Phần xử lý kiểm tra dữ liệu đọc trên UART-RX được thực hiện trong method write_frmMonitorRX.
Hình 5: Giải thuật kiểm tra dữ liệu nhận trên UART của Scoreboard
Các bạn hãy tải source code trên Github để vừa đọc vừa so sánh. Mọi góp ý, các bạn có thể comment dưới bài viết.

Dữ liệu có thể dowload:
Môi trường UVM bản Draff trên Github

Lịch sử cập nhật:
1/ 2019.09.15 - 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

0 bình luận:

Đăng nhận xét