Sunday, March 22, 2020

使用Vivado Xilinx AXI verification IP進行AXI ip開發驗證

Xilinx AXI Verification IP tutorial

前情提要

一般來說開發Xilinx FPGA上的AXI master/slave ip都是透過C/C++ 轉成HLS或是直接撰寫Verilog。透過C/C++ 轉成的HLS可以自己寫簡單的C/C++ 程式作為testbench,驗證結果可以直接看C/C++ testbench的結果而定,Verilog細節、AXI操作等問題Vivado HLS會幫你完全處理(如果這些部份出現問題,你也沒輒了)。但是透過Verilog直接寫成的IP,通常需要CPU還有記憶體界面(eg. mig)之類的進行全系統測試,而獲取波形等資訊需要透過合成ILA在板子上實際測試。這流程十分繁瑣,合成ILA會浪費大量syntesis和implementation時間,而且可以debug的的訊號數量受限於晶片上的block ram以及LUT數量。然而很多人忽略了Xilinx其實提供了AXI verification IP,可以簡單快速撰寫testbench直接進行behavior simulation,這對於縮短演算法邏輯開發的時間有益。

本文主要以 CPU <-> AXI slave <=> AXI master <-> memory此模式為主。

完整文件請看AXI Verification IP v1.0

AXI Verification IP 簡介

Xilinx AXI Verification IP主要提供的功能為:

  •  產生AXI master command與資料(可自訂)
  • 產生AXI slave進行資料讀取與回覆(也可以模擬mig記憶體界面)
  • 檢查AXI protocol

而Xilinx AXI Verification IP (VIP)主要有三種模式:

  • 作為AXI master
    • 用來測試AXI slave ip
  • 作為AXI slave
    • 用來測試AXI master ip
  • 作為AXI pass-through 
    • (檢查兩個AXI IP之間的通訊)


AXI VIP提供SystemVerilog界面,透過SystemVerilog的OOP包裝一些AXI protocol操作與memory model。讓開發者可以專注在測試策略上。

flow

tools -> create and Package New IP -> choose Create AXI Peripheral
其他創造ip都按照基本流程。




這邊可以選取Verify Peripheral IP using AXI4 VIP,會建構完整的測試template。

完成後會產生如下block diagram

並且產生以下範例testbench,註解為程式區段用途。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
`timescale 1ns / 1ps
`include "my_dma_v1_0_tb_include.svh"
// 以下為必要package
import axi_vip_pkg::*;
import my_dma_v1_0_bfm_1_slave_0_0_pkg::*;
import my_dma_v1_0_bfm_1_master_0_0_pkg::*;
 
module my_dma_v1_0_tb();
 
// AXI slave VIP 參數宣告(以下省略部份程式碼)
xil_axi_uint                            error_cnt = 0;
xil_axi_uint                            comparison_cnt = 0;
axi_transaction                         wr_transaction;  
.......
xil_axi_uint                           mst_agent_verbosity = 0; 
xil_axi_uint                           slv_agent_verbosity = 0; 
// AXI Slave VIP with memory model (如果你的ip為AXI master full會自動產生對應VIP)
my_dma_v1_0_bfm_1_slave_0_0_slv_mem_t          slv_agent_0;
 
integer result_slave; 
bit [31:0] S00_AXI_test_data[3:0];
 localparam LC_AXI_BURST_LENGTH = 8;
 localparam LC_AXI_DATA_WIDTH = 32;
 
// AXI master VIP 參數參數宣告
integer                                 i;
integer                                 j; 
xil_axi_uint                            trans_cnt_before_switch = 48; 
xil_axi_uint                            passthrough_cmd_switch_cnt = 0; 
......
axi_ready_gen                           arready_gen2; 
xil_axi_payload_byte                    data_mem[xil_axi_ulong]; 
//AXI master VIP
my_dma_v1_0_bfm_1_master_0_0_mst_t          mst_agent_0;
// Design under test
  `BD_WRAPPER DUT(
      .ARESETN(reset),
      .ACLK(clock)
    );
   
initial begin
    //基本AXI VIP agent初始設定
 slv_agent_0 = new("slave vip agent",DUT.`BD_INST_NAME.slave_0.inst.IF);
       slv_agent_0.set_agent_tag("Slave VIP");
    slv_agent_0.set_verbosity(slv_agent_verbosity);
    slv_agent_0.start_slave();
    mst_agent_0 = new("master vip agent",DUT.`BD_INST_NAME.master_0.inst.IF);//ms 
        mst_agent_0.set_agent_tag("Master VIP");
    mst_agent_0.set_verbosity(mst_agent_verbosity);
    mst_agent_0.start_master();
     $timeformat (-12, 1, " ps", 1);
  end
  initial begin
    reset <= 1'b0;
    #100ns;
    reset <= 1'b1;
    repeat (5) @(negedge clock);
  end
  always #5 clock <= ~clock;
  initial begin
      S_AXI_TEST ( );
 
    init_0 = 0;
    #200ns;
    init_0 =1'b1;
    #20ns;
    init_0 = 1'b0;
     
      #1ns;
      $finish;
  end
  initial begin
  #1;
    forever begin
      slv_agent_0.monitor.item_collected_port.get(slv_monitor_transaction);
      slave_moniter_transaction_queue.push_back(slv_monitor_transaction);
      slave_moniter_transaction_queue_size++;
    end
  end
//測試task範例
task automatic S_AXI_TEST; 
begin  
#1;
   $display("Sequential write transfers example similar to  AXI BFM WRITE_BURST method starts");
   mtestID = 0;
   mtestADDR = 64'h00000000;
   mtestBurstLength = 0;
   mtestDataSize = xil_axi_size_t'(xil_clog2(32/8));
   mtestBurstType = XIL_AXI_BURST_TYPE_INCR; 
   mtestLOCK = XIL_AXI_ALOCK_NOLOCK; 
   mtestCacheType = 0; 
   mtestProtectionType = 0; 
   mtestRegion = 0;
   mtestQOS = 0;
   result_slave = 1;
  mtestWDataL[31:0] = 32'h00000001;
  for(int i = 0; i < 4;i++) begin
     S00_AXI_test_data[i] <= mtestWDataL[31:0];  
   //AXI master write transaction
   mst_agent_0.AXI4LITE_WRITE_BURST(
   mtestADDR,
   mtestProtectionType,
   mtestWDataL,
   mtestBresp
   );  
   mtestWDataL[31:0] = mtestWDataL[31:0] + 1;
   mtestADDR = mtestADDR + 64'h4;
  end
 $display("Sequential write transfers example similar to  AXI BFM WRITE_BURST method completes");
 $display("Sequential read transfers example similar to  AXI BFM READ_BURST method starts");
 mtestID = 0;
 mtestADDR = 64'h00000000;
 mtestBurstLength = 0;
 mtestDataSize = xil_axi_size_t'(xil_clog2(32/8));
 mtestBurstType = XIL_AXI_BURST_TYPE_INCR; 
 mtestLOCK = XIL_AXI_ALOCK_NOLOCK; 
 mtestCacheType = 0; 
 mtestProtectionType = 0; 
 mtestRegion = 0;
 mtestQOS = 0;
 for(int i = 0; i < 4;i++) begin
   //AXI master產生read transaction
   mst_agent_0.AXI4LITE_READ_BURST(
        mtestADDR,
        mtestProtectionType,
        mtestRDataL,
        mtestRresp
      );
 
  end
endtask 
 
endmodule


  • 對於slave agent有兩種model,分別是:
    • <component_name>_slv_t
      • 必須自行在user environment(testbecnch)中補上write response與read response(response包含回傳訊息的內容等)
    • <component_name>_slv_mem_t
      • write response與read response會由agent自行處理
      • 帶有memory model
      • 對於AXI full master的ip,Vivado會預設使用此agent


Testbench、AXI VIP與DUT的關係



以此架構產生的目標測試環境如上所示。其中由於AXI VIP slave是使用memory mode,所以Slave write/read driver不需要user自己在testbench中補上處理程序。

在使用memory model版本的AXI VIP,可以透過blackdoor_memory_write與blackdoor_memory_read存取模擬出的data memory,而AXI master則可透過一般AXI transaction進行讀寫。memory model大小取決於AXI data width的定址空間大小。

blackdoor memory read範例:
1
2
3
xil_axi_ulong mem_rd_addr = 32'h00000000;
bit [32-1:0] mem_rd_data;
mem_rd_data = slv_agent_0.mem_model.backdoor_memory_read(mem_rd_addr);
blackdoor memory write範例:
1
2
3
4
bit [32-1:0] wr_data = 0;
xil_axi_ulong wr_addr = 0;
bit [(32/8)-1:0] wr_strb = 4'hf; //byte select
slv_agent_0.mem_model.backdoor_memory_write(wr_addr,wr_data,wr_strb);

memory model使用上可以透過以下code將memory給入預設值方便debug:
1
2
slv_agent_0.mem_model.set_memory_fill_policy(XIL_AXI_MEMORY_FILL_FIXED);
slv_agent_0.mem_model.set_default_memory_value(32'hdeadbeef);

AXI master VIP進行AXI4 lite read/write的讀寫方式可透過:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
xil_axi_ulong                           mtestADDR;
xil_axi_prot_t                          mtestProtectionType = 3'b000;
bit [63:0]                              mtestWDataL;
bit [63:0]                              mtestRDataL;
xil_axi_resp_t                          mtestBresp;
xil_axi_resp_t[255:0]                   mtestRresp;
mst_agent_0.AXI4LITE_WRITE_BURST(
        mtestADDR,
        mtestProtectionType,
        mtestWDataL,
        mtestBresp);
mst_agent_0.AXI4LITE_READ_BURST(
        mtestADDR,
        mtestProtectionType,
        mtestRDataL,
        mtestRresp);       

示範testbench code

在gist連結中:https://gist.github.com/Daichou/6b2e0a62bfc4eeb338e7f82fe40f0cc8

其他資源

Xilinx AXI VIP很多資訊只能透過從範例code看註解學習,開啟範例的方法為,先建立一個AXI VIP block design,在block diagram中點擊AXI VIP按右鍵然後會跳出選單,選取open IP example design。在該專案根目錄底下的imports就會含有所有範例testbench。

Reference




Friday, March 6, 2020

Verilog Diagram generator

Verilog Diagram generator

最近剛好看到chisel/FIRRTL專案下有一個子專案叫做diagrammer,可以把FIRRTL進行dependency分析後,產生graphiz的dot檔案,包括其中的submodule都可以一併產生,想說看一下verilog開源的專案有沒有類似的工具。後來找到yosys這個synthesis tool可以達到類似的功能。yosys主要針對verilog-2005,systemverilog之類的沒有支援有點可惜。
用法先去clone該專案,進行安裝。
$ git clone https://github.com/YosysHQ/yosys
安裝相依工具:
$ sudo apt-get install build-essential clang bison flex \
 libreadline-dev gawk tcl-dev libffi-dev git \
 graphviz xdot pkg-config python3 libboost-system-dev \
 libboost-python-dev libboost-filesystem-dev zlib1g-dev
進去yosys資料夾後,選擇compiler:
$ make config-clang
$ make config-gcc
然後make && make install
$ make
$ sudo make install
這些步驟都跟readme寫的一樣。
這工具的command和vcs蠻相似的,執行yosys會進到command shell,透過read_verilog載入verilog module,或是read -sv載入verilog module同時elaborate。之後指定top module。她會產生檔案的AST。
yosys> read -sv folder/*.v
yosys> hierarchy -top top_module
接下來可以用show指令顯示diagram。
yosys> show
如果多個module,需要指定顯示程式。(gv是一個程式,可以透過apt-get安裝,ps是postscript的縮寫)
yosys> show -format ps -viewer gv
多個檔案會顯示多組diagram。不過看起來不會寫入合併成一個diagram。他也會在家目錄產生.yosys_show.dotdot檔。可以透過dot程式轉成png或是svg。
其他像xilinx的tool可以產生RTL schematic也可以產生類似功能。而一些商用工具也有這些功能如Synopsys Synplify Pro看起來很完整。
ref

Thursday, July 4, 2019

Linux kernel: Energy Aware scheduling (EAS)

Energy Aware scheduling

之前寫的作業報告,我覺得可以分享出來
hackmd版:https://hackmd.io/@Daichou/ByzK-S60E
主要文章:https://www.linaro.org/blog/energy-aware-scheduling-eas-progress-update/

背景

本文主要以linaro 於2015年提出之EAS(Energy aware scheduling)框架看當今Linux kernel 5.0以後從EAS與Android端整合回kernel的EAS與EM(energy model)。
自從Arm big.LITTLE 從原本的硬體切換叢集大小核,到後來的HMP(heterogeneous multi-processing),傳統Linux的SMP排程方式不敷使用,由於傳統Linux kernel的CFS(Completely Fair Scheduler)是以吞吐量(throughput)為主,對於移動平台的功耗掌控不甚理想。因此Arm與Linaro團隊提出了EAS作為對於HMP下Linux CFS,cpuidle,cpufreq子系統的加強。後來導入EM 框架,作為EAS與driver與其他Linux子系統,如:device tree與Thermal(目前仍未連接)的介面。

Energy Model Framework

Interface

EM(energy model Framework)是Linux kernel特別抽出的介面,用來讓子系統或是driver可以透過em_register_perf_domain()函式註冊一個特別情況下的時脈與功耗的關係(performance domain)。

如上圖可見driver透過em_register_perf_domain註冊效能資料,Kernel透過em_pd_energy()取得功耗估計,而em_cpu_get()用以取得EM中的energy model table的資料。目前僅有Scheduler需要這些資料,不過Linux kernel預期會有更多子系統需要這些資料,因此將特別抽出建立一層抽象化。

OPP(operating performance points)

由於當前SOC盛行,SOC有許多子模塊(例如:CPU cluster),這些子模塊可以依照使用情境給予不同的頻率與電壓組合,並不一定需要整個SOC依照相同頻率運作,這些子模塊通常被分為domain,各domain可以有多組頻率與電壓組合被稱為operating performance points(OPP)。OPP透過device tree source(dts)由開發者建立,通常於開機時初始化。

(資料來源:https://www.linaro.org/assets/blog/EAS-image-11-f4a331f605b5adbd4d8330917f421070c2b0fc0e7d4fd2e22de1cbe2bf8e83c5.jpg)
以上圖為例由於CPU的算力與功率是曲線而非直線,因此透過OPP可以增加EM推算未來功耗的準確度,這項設計可讓EM預測功耗的線性內插運算更為精準。

Performance domain(perf_domain)


整個performance domain結構如上圖。每個cpu run queue會指向一個root_domain(用以表達一個cpu set),每個root_domain會用linked list儲存多個perf_domain,每個performace domain中的CPU必須是相同的microarchitecture(例如均為Cortex-A53)且當調整一個perf_domain的物理參數(如電壓等),整個perf_domain中的硬體均會一起被調整,每個perf_domain對應的em_perf_domain會透過em_register_perf_domain()與對應的callback function建立em_cap_state。以從device tree建立的方式為例,em_register_perf_domain()會透過OPP的_get_cpu_power()依照:
Power = Capacity * Voltage^2 * frequency
公式將OPP轉成mW、frequency以及cost組合存入em_cap_state,其中cost計算方式為:
Cost = max_cpu_frequency * em_cap_state.power/em_cap_state.frequency
perf_domain與root_domain對應到實際上的SOC的關係則是如下圖。通常一個root_domain對應到一個SOC,而perf_domain對應到其中的CPU cluster。如果cluster中的CPU可以特別調頻,則可以在拆分更多perf_domain。

Energy Aware Scheduler

EAS 基本上並非完全提出一個新的scheduler,而是在更改現有scheduler(CFS)在挑選指派cpu的方式。藉此調整HMP的功耗。

CPU capacity

CPU capacity是用以表達當CPU以最高頻率運行時的throughput。透過CPU capacity與scheduler 從Per-Entity Load Tracking(PELT)取得task運作數據了解該CPU的忙碌程度。CPU capacity是開機時在建立CPU topology時解析device tree建立。系統可以透過arch_scale_cpu_capacity()讀取該值。

policy

Energy aware scheduling透過選取CPU的方式,主要透過select_task_rq_fair這個函式將任務發配給cpu runqueue。而整個scheduler有兩個情境會需要執行此函式:
  1. execve -> sched_exec
  2. wake up一個task

task的能耗預測

透過Energy Model提供的em_pd_energy()預測,推算方式如下:
csdomain capacity state

透過頻率與CPU utilization的關係我們可以找到大於當前CPU uilization最小的cs。

由於
cs powerCPU max freqcs frequency=cs cost(em_cap_state.cost)

所以
Predict CPU energy=CPU utilizationcs costCPU max capacity

Linux kernel中使用化約過的(2)式做運算,而我們以下範例使用直觀的(1)式。範例:
當前狀況CPU01為同perf_domain,CPU23為同perf_domain,若P1(平均util=200):

CPU0: 400 / 512 * 300 = 234
CPU1: 100 / 512 * 300 = 58
CPU2: 600 / 768 * 800 = 625
CPU3: 500 / 768 * 800 = 520
共1437
若P1移到CPU1
CPU0: 200 / 341 * 150 = 88
CPU1: 300 / 341 * 150 = 131
CPU2: 600 / 768 * 800 = 625
CPU3: 500 / 768 * 800 = 520
共1364
若P1移到CPU3(無法移到2除非調整OPP)
CPU0: 200 / 341 * 150 = 88
CPU1: 100 / 341 * 150 = 43
CPU2: 600 / 768 * 800 = 625
CPU3: 700 / 768 * 800 = 729
共1485
透過此方式可知將task放到CPU1有最佳功耗。

EAS 時間複雜度

由上的運算可知每次運算(select_task_rq_fair)需要遍歷root_domain下所有的perf_domain,並且需要計算每個CPU與其OPP是落在哪個效能區間,依照kernel文件給出的時間複雜度如下:
此對於task wake up的情況來說,此情況對於時間複雜度很敏感,如果EAS(EM)複雜度過高會導致OS反應不佳,因此EM設立了EM_MAX_COMPLEXITY門檻(預設2048),若Complexity數值高過此數值則不啟用EAS,一般開發人員也可以透過:
  1. 分隔root_domain減少domain中的CPU數量降低複雜度
  2. 減少EAS task wake up的複雜度(需要自己上patch),不過難度很高
來減少task wake-up的延遲。

EAS成立假設

EAS要能夠成功在不影響效能運作,且達成能耗最佳化必須建立在以下三個假設:
  1. 所有CPU都有足夠的idle時間:確保task可以不受效能限制的運行,使PELT計量的task utilization為正確的。
  2. 每個task都被供給足夠的CPU capacity:原因同上。
  3. 每個CPU都有足夠的剩餘capacity,以滿足task wake-up且task的blocking/sleeping愈規律愈好
這些假設必須在CPU低於80% capacity情況下才可以成立,當高於此值稱為over-utilization,此狀況下EAS的會無法得到足夠的選擇,導致效能損失。

Over-utilization

為了確保EAS不要在效能吃緊時影響效能,EAS建立了一個狀態 “over-utilization” 。當CPU使用了超過 80% 的capacity時,SG_OVERUTILIZED這個flag會被設立,這時scheduler會放棄使用EAS的指派CPU機制,而改用原先CFS的指派方式:選擇同一schedule domain下負載最小的CPU(最idle的CPU)或是相鄰schedule domain下覆載最小的CPU。
此機制的檢查是在:
1.透過SCHED_SOFRIRQ發生時,透過update_sg_lb_stats()檢查並更新sched_group的統計數據
2.新的task被放入CFS的紅黑樹時檢查。

load balance

Linux kernel 透過SCHED_SOFTIRQ這個softirq對應的action函式驅動scheduler檢查是否需要進行load balance,然而在EAS啟動時(sched_energy_enabled()回傳值為真)情況下,會直接將當前情況視為沒有負載不均衡(find_busiedt_group()會清除imbalance flag並回傳NULL)。因為EAS很容易造成大小核任務分配不均的情況。然而只要root domain中其中個CPU發生over-utilization的情況,即便EAS啟動,load balance仍會進行。

Dependency

EAS需要以下滿足以下相依性:
  1. 非對稱CPU架構(即SD_ASYM_CPUCAPACITY flag必須開啟),Ex: big.LITTLE架構。
  2. Energy model:用來提供效能參數。
  3. EM複雜度低於門檻。
  4. Schedutil governor:為Linux 4.7以後新增的governor,用以動態根據utilization調節CPU freqency,EAS只能使用這個governor。
  5. Scale-invariant utilization signals:PELT必須能夠給出frequency-invariant and CPU-invariant PELT訊號以給出正確的功耗預測。
綜合5.與6.由於必須要提供frequency-invariant訊號,因此系統的util必須是frequency-invariant。因此在Schedutil governor中使用:

作為調整公式(若為variant,max_freq項需替換成cur_freq)。當CFS的run queue中的utilization改變時會觸發cpufreq_update_util(),由於在EAS情況下會使用SchedUtil governor,會對應到sugov_update_single()或是sugov_update_shared()進行頻率更新。

在linaro文章中提到的是cpufreq governor,其已經被SchedUtil governor正式取代。

效能數據

可以發現負載愈小節能效果愈好,因為task可以指派的選項比較多,可以找到更好的結果。但是EAS仍會造成一些效能損失。
image alt
資料來源:ARM

未來發展

1.EM是否該包含GPU等其他運算單元。
目前移動裝置中仍未出現異質的GPU設計,所以仍未限包含GPU的需求
2.是否有其他子系統需要EM的參數。

其他資料

精選文章

使用Ardunio Atmega2560 連接 nRF24L01+

使用Ardunio Atmega2560 連接 nRF24L01+ 關於library 目前主流有 https://github.com/maniacbug/RF24 與 https://github.com/TMRh20/RF24 這兩個。 其中TMRh20大大做...