基於Axi4_lite協議的自定義IP模擬平臺的搭建
做FPGA開發離不開模擬,模擬對於FPGA的除錯開發起到了很好的輔助作用。對於新手而言模擬就更加重要了,老練的FPGA開發者時序瞭然於胸,對於簡單的IP核開發是可以省略模擬的步驟,但是對於絕大多數的情況而言,模擬不僅能提高工作效率,而且能夠提高開發者的時序分析能力。模擬是驗證最常用的手段,雖說現在很多FPGA裡頭集成了邏輯分析,但是直接上板除錯還是會損耗不少的時間,一方面是跑綜合需要足夠的時間,另一方面板上除錯的資源有限,很多的錯誤並不能合理的排查。以此在寫完程式碼後最好是先做模擬,模擬沒問題了再上板除錯。
正常情況下模擬都會用到模擬工具,我一般用的模擬工具是modelsim,vivavo雖說也有自帶的模擬,但是使用起來不僅麻煩,而且時序會跟modelsim的有些偏差。
下面的模擬平臺的搭建就是基於前面所講的axi4_lite協議,對自定義IP核GPIO進行模擬。模擬程式碼主要是用system Verilog語言來完成,學過C或C++的應該能比較容易看懂,會Verilog語言的看SV語言應該難度也不大。
一般封裝好的IP會在一個資料夾下:
資料夾下會放doc檔案及ip檔案,doc用來存放IP核的暫存器說明及操作文件,ip則用來放IP核的相關程式碼。
ip檔案下存放if,rtl,sim檔案,if放封裝時可能需自定義的介面,rtl放IP核原始碼,sim放模擬程式碼。
rtl:
sim:
使用的時候直接雙擊run.bat檔案即可,modelsim自動開啟並模擬。
run.bat程式碼:
1 modelsim -do sim.do
sim.do程式碼:
1 #刪除work工作目錄 2 file delete -force work 3 4 #設定uvm環境變數,指定uvm的dpi位置 5 set UVM_DPI_HOME D:/modeltech64_10.5/uvm-1.1d/win64 6 7 #建立work工作目錄 8 vlib work 9 10 #vlog表示編譯 *.sv表示do檔案同級路徑下所有.sv檔案 -L表示新增庫檔案 11 vlog -L mtiAvm -L mtiOvm -L mtiUvm -L mtiUPF *.sv12 13 #編譯原始檔,包含覆蓋率測試 14 vlog -cover sbctf -coveropt 3 ../rtl/*.v 15 16 #執行模擬,開啟覆蓋率視窗,不使能優化,呼叫uvm庫uvm_dpi,利用UVM_TEST_NAME從命令列中尋找測試用例的名字,建立它的例項並執行 17 vsim -coverage -novopt -c -sv_lib $UVM_DPI_HOME/uvm_dpi work.Gpio_sim +UVM_TESTNAME=case0 18 19 #觀察DUT的訊號波形 20 add wave -position insertpoint sim:/Gpio_sim/u_Axi4_Gpio/* 21 22 run 10ms
頂層模擬檔案Gpio_sim.sv:
1 //************************************************************************** 2 // *** file name : Gpio_sim.sv 3 // *** version : 1.0 4 // *** Description : Gpio IP core testbech 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.4.7 8 // *** Changes : 9 //************************************************************************** 10 `timescale 1ns/1ps 11 `define GPIO_NUM 32 12 13 module Gpio_sim(); 14 15 /******************************************************************************\ 16 Define AXI4-lite interface port 17 \******************************************************************************/ 18 wire w_axi_aclk ; 19 wire w_axi_aresetn ; 20 21 wire [31:0] w_axi_awaddr ; 22 wire w_axi_awvalid ; 23 wire w_axi_awready ; 24 25 wire [31:0] w_axi_wdata ; 26 wire [3:0] w_axi_wstrb ; 27 wire w_axi_wvalid ; 28 wire w_axi_wready ; 29 30 wire [1:0] w_axi_bresp ; 31 wire w_axi_bvalid ; 32 wire w_axi_bready ; 33 34 wire [31:0] w_axi_araddr ; 35 wire w_axi_arvalid ; 36 wire w_axi_arready ; 37 38 wire [31:0] w_axi_rdata ; 39 wire [1:0] w_axi_rresp ; 40 wire w_axi_rvalid ; 41 wire w_axi_rready ; 42 43 /******************************************************************************\ 44 Instantiate AXI4-lite master module 45 \******************************************************************************/ 46 m_axi4_lite_if u_m_axi4_lite_if 47 ( 48 .o_sys_clk (w_axi_aclk ), 49 .o_sys_rstn (w_axi_aresetn ), 50 .o_m_axi_awaddr (w_axi_awaddr ), 51 .o_m_axi_awvalid (w_axi_awvalid ), 52 .i_m_axi_awready (w_axi_awready ), 53 .o_m_axi_wdata (w_axi_wdata ), 54 .o_m_axi_wstrb (w_axi_wstrb ), 55 .o_m_axi_wvalid (w_axi_wvalid ), 56 .i_m_axi_wready (w_axi_wready ), 57 .i_m_axi_bresp (w_axi_bresp ), 58 .i_m_axi_bvalid (w_axi_bvalid ), 59 .o_m_axi_bready (w_axi_bready ), 60 .o_m_axi_araddr (w_axi_araddr ), 61 .o_m_axi_arvalid (w_axi_arvalid ), 62 .i_m_axi_arready (w_axi_arready ), 63 .i_m_axi_rdata (w_axi_rdata ), 64 .i_m_axi_rresp (w_axi_rresp ), 65 .i_m_axi_rvalid (w_axi_rvalid ), 66 .o_m_axi_rready (w_axi_rready ) 67 ); 68 69 /******************************************************************************\ 70 Instantiate AXI4-lite slave IP core 71 \******************************************************************************/ 72 reg [31:0] w_gpio_i; 73 Axi4_Gpio 74 #( 75 .IO_NUM (`GPIO_NUM) 76 ) 77 u_Axi4_Gpio 78 ( 79 .i_s_axi_aclk (w_axi_aclk ), 80 .i_s_axi_aresetn (w_axi_aresetn ), 81 .i_s_axi_awaddr (w_axi_awaddr ), 82 .i_s_axi_awprot ('d0 ), 83 .i_s_axi_awvalid (w_axi_awvalid ), 84 .o_s_axi_awready (w_axi_awready ), 85 .i_s_axi_wdata (w_axi_wdata ), 86 .i_s_axi_wstrb (w_axi_wstrb ), 87 .i_s_axi_wvalid (w_axi_wvalid ), 88 .o_s_axi_wready (w_axi_wready ), 89 .o_s_axi_bresp (w_axi_bresp ), 90 .o_s_axi_bvalid (w_axi_bvalid ), 91 .i_s_axi_bready (w_axi_bready ), 92 .i_s_axi_araddr (w_axi_araddr ), 93 .i_s_axi_arprot ('d0 ), 94 .i_s_axi_arvalid (w_axi_arvalid ), 95 .o_s_axi_arready (w_axi_arready ), 96 .o_s_axi_rdata (w_axi_rdata ), 97 .o_s_axi_rresp (w_axi_rresp ), 98 .o_s_axi_rvalid (w_axi_rvalid ), 99 .i_s_axi_rready (w_axi_rready ), 100 101 .i_gpio_if_i (w_gpio_i ), 102 .o_gpio_if_o ( ), 103 .o_gpio_if_t ( ) 104 ); 105 106 107 108 /******************************************************************************\ 109 Perform the steps of IP core in sequence 110 \******************************************************************************/ 111 reg [31:0] r_cpu_rd_data; 112 initial r_cpu_rd_data = 0; 113 114 115 initial 116 begin 117 $display("start"); 118 #2000; 119 u_m_axi4_lite_if.arm_write_data(32'h00000000,32'h5aa5a55a,4'hf); 120 #200; 121 u_m_axi4_lite_if.arm_write_data(32'h00000004,32'h5a00005a,4'hf); 122 #200; 123 u_m_axi4_lite_if.arm_read_data(32'h00000000,r_cpu_rd_data); 124 #200; 125 u_m_axi4_lite_if.arm_read_data(32'h00000004,r_cpu_rd_data); 126 #200; 127 w_gpio_i = 32'h1234567; 128 u_m_axi4_lite_if.arm_read_data(32'h00000008,r_cpu_rd_data); 129 $display("sim complete"); 130 end 131 132 endmodule
產生激勵模組m_axi4_lite_if.sv:
1 //************************************************************************** 2 // *** file name : m_axi4_lite_if.sv 3 // *** version : 1.0 4 // *** Description : axi4_lite_if master 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.4.7 8 // *** Changes : 9 //************************************************************************** 10 `timescale 1ns/1ps 11 12 module m_axi4_lite_if 13 ( 14 output reg o_sys_clk, 15 output reg o_sys_rstn, 16 17 output reg [31:0] o_m_axi_awaddr, 18 output reg o_m_axi_awvalid, 19 input i_m_axi_awready, 20 21 output reg [31:0] o_m_axi_wdata, 22 output reg [3:0] o_m_axi_wstrb, 23 output reg o_m_axi_wvalid, 24 input i_m_axi_wready, 25 26 input [1:0] i_m_axi_bresp, 27 input i_m_axi_bvalid, 28 output reg o_m_axi_bready, 29 30 output reg [31:0] o_m_axi_araddr, 31 output reg o_m_axi_arvalid, 32 input i_m_axi_arready, 33 34 input [31:0] i_m_axi_rdata, 35 input [1:0] i_m_axi_rresp, 36 input i_m_axi_rvalid, 37 output reg o_m_axi_rready 38 ); 39 40 parameter SYS_CLK = 100_000_000 , 41 TIME_1S = 1000_000_000 ; 42 43 44 real clk_cnt = TIME_1S/SYS_CLK; 45 /******************************************************************************\ 46 產生模擬環境需要的時鐘與復位訊號,這裡的時鐘訊號為125MHz 47 \******************************************************************************/ 48 initial//所有的initial模組都是並行的,initial模組的語句是按順序執行的。 49 begin 50 o_sys_clk = 0; 51 o_sys_rstn = 0; 52 #1000; 53 o_sys_rstn = 1; 54 end 55 56 always #(clk_cnt/2) o_sys_clk = ~o_sys_clk; 57 58 /******************************************************************************\ 59 先初始化axi4-lite的輸出量訊號 60 \******************************************************************************/ 61 initial 62 begin 63 o_m_axi_awaddr = 'd0; 64 o_m_axi_awvalid = 'd0; 65 o_m_axi_wdata = 'd0; 66 o_m_axi_wstrb = 'd0; 67 o_m_axi_wvalid = 'd0; 68 o_m_axi_bready = 'd0; 69 o_m_axi_araddr = 'd0; 70 o_m_axi_arvalid = 'd0; 71 o_m_axi_rready = 'd0; 72 end 73 /******************************************************************************\ 74 通過axi4-lite匯流排寫資料,寫task 75 \******************************************************************************/ 76 task arm_write_data 77 ( 78 input [31:0] i_addr , 79 input [31:0] i_data , 80 input [3:0] i_byte_en 81 ); 82 begin 83 @(posedge o_sys_clk) 84 begin 85 o_m_axi_awaddr = i_addr; 86 o_m_axi_awvalid = 1'b1; 87 o_m_axi_wdata = i_data; 88 o_m_axi_wstrb = i_byte_en; 89 o_m_axi_wvalid = 1'b1; 90 o_m_axi_bready = 1'b1; 91 end 92 @(posedge o_sys_clk); 93 begin 94 while(~(i_m_axi_awready & i_m_axi_wready)) // 95 begin 96 @(posedge o_sys_clk) 97 begin 98 o_m_axi_awvalid = 1'b0; 99 o_m_axi_wvalid = 1'b0; 100 end 101 end 102 end 103 104 @(posedge o_sys_clk) 105 begin 106 while(~i_m_axi_bvalid) 107 begin 108 @(posedge o_sys_clk) 109 begin 110 if(i_m_axi_bresp != 2'b00) 111 begin 112 $display("write fail"); 113 end 114 end 115 end 116 end 117 118 o_m_axi_bready = 1'b0; 119 end 120 endtask 121 122 123 /******************************************************************************\ 124 通過axi4-lite匯流排讀資料,讀task 125 \******************************************************************************/ 126 task arm_read_data 127 ( 128 input [31:0] i_addr, 129 output [31:0] o_rdata 130 ); 131 begin 132 @(posedge o_sys_clk) 133 begin 134 o_m_axi_araddr = i_addr; 135 o_m_axi_arvalid = 1'b1; 136 o_m_axi_rready = 1'b1; 137 end 138 139 @(posedge o_sys_clk) 140 begin 141 while(~i_m_axi_arready) 142 begin 143 @(posedge o_sys_clk) 144 begin 145 o_m_axi_arvalid = 1'b0; 146 end 147 end 148 end 149 @(posedge o_sys_clk) 150 begin 151 o_rdata = i_m_axi_rdata; 152 while(~i_m_axi_rvalid) 153 begin 154 if(i_m_axi_rresp!=2'b00) 155 $display("read fail"); 156 end 157 end 158 159 o_m_axi_rready = 1'b0; 160 end 161 endtask 162 163 endmodule
以上便是整個axi4_lite 的模擬平臺搭建,可以根據實際需要增加新的介面功能,比如axi4_stream介面這些。
模擬的結果如下圖: