使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附原始碼)

debug,尤其是通信芯片的debug,可以有很多的方法。一個數據幀從進入到輸出,可以在通路上的關鍵節點處設置監測如各種計數器等,可通過VIO(xilinx)定時上報實時狀態。可以把VIO的各個信號線設置成類似於CPU總線的結構,監測計數器或者狀態寄存器編成相應的地址,輪詢讀取回PC,在PC上通過TCL或者其它語言捕獲數據。甚至可以將多個FPGA芯片都通過VIO進行調試,遠程操作,效率也可以大大提升。另外,也可以設置專門的測試幀,在裡面打各種不同大小的閉環,層層檢測,發現問題。

這個VIO比chipscope有多大優勢?

原理是一樣的,不同的就是可以方便操控,可以寫腳本抓取數據,還可以遠程操控。VIO有輸入也有輸出,可以實時的配置寄存器。http://xilinx.eetrend.com/blog/11987,Vivado VIO (virtual input output)虛擬IO使用;

一、使用方法概述

一般情況下VIO用在設計中,可以提供模擬IO(我們主要用到模擬輸出接口的功能)。如圖1所示,紅框內vio_0模塊的兩個輸出probe_out[0:0]和probe_out[7:0]都可以接到其他模塊直接使用,但是我們不需要用到板子上的實際接口(比如按鍵)。那麼為什麼我們在電腦上點一點鼠標,就可以將數據傳遞到FPGA內部呢?數據是通過什麼傳輸到FPGA內部?答案是JTAG,電腦上的VIVADO軟件可以通過JTAG軟件與FPGA實現通信,這就是VIO模塊在FPGA內部模擬IO引腳的原理。

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖1 VIO IP核

1、VIO IP核的配置

下面用實際例子說明VIO IP核的配置過程:

在某設計中,需要使用按鍵出發,但是板子上沒有設計按鍵,所以需要使用VIO模擬按鍵輸入還有其他信號的輸出。具體過程如下:

(1)例化VIO IP核 ;

(2)參數配置,配置輸入探針數量和輸出探針數量,如圖2所示。分別可以設置0-256個。(一般輸入探針用不到,最常用的是輸出探針,在這裡這兩種探針都在圖裡體現了)。

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖2 探針數量設置

(3)配置輸出探針數據位寬及初始值

輸出探針的數據位寬,及初始化數據(in hex)配置如圖3所示

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖3配置輸出探針數據位寬及初始值

3、 VIO IP核的例化

VIO IP核代碼實例化如下圖所示。

ILA_wrapper ILA(

.clk ( ),

.probe0 (),

.probe1 (),

.probe_out0 (),

.probe_out1 (),

.probe_in0 ()

);

4、 VIO IP核的使用

在hw_vio界面加入輸出探針,並且配置對應的參數,此時FPGA內部的輸出探針就會相應地發出信號,如圖4所示。

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖4 VIO IP核的使用

二、使用VIO實現大量寄存器讀寫

1、背景

在FPGA調試中,如果沒有CPU接口及操作系統,但同時希望能夠有一種類似於有CPU且可以實時在線讀寫FPGA內部狀態寄存器或者配置FPGA內部寄存器的功能,就可以採用VIO來實現一個模擬的CPU接口,以下進行詳細的介紹。

2、 原理框圖及VIO字段定義

在Vivado 2016.2 軟件環境,Zedboard硬件平臺下,實現了一個示例工程,該工程的功能是,電腦運行Vivado軟件,並通過Jtag與zedboard相連,利用VIO模擬CPU接口,實現寄存器讀寫功能(寄存器數量為32個,位數為32位),如圖5所示。

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖5原理框圖

其參數配置說明如下:

如圖6所示,vio_out_1的前32位是寫地址,後32位是寫數據;

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖6 VIO 寫地址與寫數據

如圖7所示,vio_rd_addr代表讀地址;

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖7 VIO 讀地址

如圖8所示,vio_rd_data代表讀數據

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖8 VIO讀數據

3、操作示例

這裡給出一個寄存器讀寫的例子,在這裡不用tcl腳本,直接用圖形界面,使用更加方便。

(1)給地址為1的寄存器寫入數據32'hffff_ffff,即配置vio_out_1[63:0]為64'h0000_0001_FFFF_FFFF,如圖9所示。

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖9 VIO 寫入數據

(2) 將讀地址設置為1,觀察讀數據變化,如圖10所示。

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

圖10 VIO讀數據

觀察圖10可以發現,配置讀地址vio_rd_addr為32'h0000_0001後,讀數據vio_rd_data[31:0]由圖9中的32'h0000_0000變為圖10中的32'hffff_ffff,與寫入的數據相同,寄存器讀寫操作成功。

三、源代碼

1、VIO源碼

// **************************************************************

// COPYRIGHT(c)2018, Xidian University

// All rights reserved.

//

// IP LIB INDEX : VIO

// IP Name : VIO

// File name :

// Module name :

// Full name :

//

// Author : Liu-Huan

// Email : [email protected]

// Data :

// Version : V 1.0

//

// Abstract :

// Called by :

//

// Modification history

// -----------------------------------------------------------------

// *****************************************************************

// *******************

// TIMESCALE

// *******************

`timescale 1ns/1ps

//*******************

//DEFINE MODULE PORT

//*******************

module VIO_CPU_PORT (

input clk

) ;

//*********************

//INNER SIGNAL DECLARATION

//*********************

//REGS

reg [31:0] mod_reg_0 = 32'b0 ;

reg [31:0] mod_reg_1 = 32'b0 ;

reg [31:0] mod_reg_2 = 32'b0 ;

reg [31:0] mod_reg_3 = 32'b0 ;

reg [31:0] mod_reg_4 = 32'b0 ;

reg [31:0] mod_reg_5 = 32'b0 ;

reg [31:0] mod_reg_6 = 32'b0 ;

reg [31:0] mod_reg_7 = 32'b0 ;

reg [31:0] mod_reg_8 = 32'b0 ;

reg [31:0] mod_reg_9 = 32'b0 ;

reg [31:0] mod_reg_10 = 32'b0 ;

reg [31:0] mod_reg_11 = 32'b0 ;

reg [31:0] mod_reg_12 = 32'b0 ;

reg [31:0] mod_reg_13 = 32'b0 ;

reg [31:0] mod_reg_14 = 32'b0 ;

reg [31:0] mod_reg_15 = 32'b0 ;

reg [31:0] mod_reg_16 = 32'b0 ;

reg [31:0] mod_reg_17 = 32'b0 ;

reg [31:0] mod_reg_18 = 32'b0 ;

reg [31:0] mod_reg_19 = 32'b0 ;

reg [31:0] mod_reg_20 = 32'b0 ;

reg [31:0] mod_reg_21 = 32'b0 ;

reg [31:0] mod_reg_22 = 32'b0 ;

reg [31:0] mod_reg_23 = 32'b0 ;

reg [31:0] mod_reg_24 = 32'b0 ;

reg [31:0] mod_reg_25 = 32'b0 ;

reg [31:0] mod_reg_26 = 32'b0 ;

reg [31:0] mod_reg_27 = 32'b0 ;

reg [31:0] mod_reg_28 = 32'b0 ;

reg [31:0] mod_reg_29 = 32'b0 ;

reg [31:0] mod_reg_30 = 32'b0 ;

reg [31:0] mod_reg_31 = 32'b0 ;

reg [63:0] vio_out_1_ff = 63'b0 ;

reg [31:0] vio_rd_data = 32'b0 ;

//WIRES

wire [63:0] vio_out_1 ;

wire [31:0] vio_out_2 ;

wire [31:0] vio_rd_addr ;

wire [31:0] vio_wr_addr ;

wire [31:0] vio_wr_data ;

reg wr_en ;

//*********************

//MAIN CORE

//*********************

vio_0 your_instance_name (

.clk(clk), // input wire clk

.probe_in0(vio_rd_data), // input wire [31 : 0] probe_in0

.probe_out0(vio_out_1), // output wire [63 : 0] probe_out0

.probe_out1(vio_out_2) // output wire [31 : 0] probe_out1

);

assign vio_rd_addr = vio_out_2;

assign vio_wr_addr = vio_out_1[63:32];

assign vio_wr_data = vio_out_1[31:0] ;

always @(posedge clk )

begin

vio_out_1_ff <= vio_out_1 ;

end

always @(posedge clk )

begin

if ( vio_out_1_ff != vio_out_1 )

wr_en <= 1'b1 ;

else

wr_en <= 1'b0 ;

end

always @(posedge clk )

begin

if ( wr_en == 1'b1 ) begin

case ( vio_wr_addr )

32'd0 : mod_reg_0 <= vio_wr_data ;

32'd1 : mod_reg_1 <= vio_wr_data ;

32'd2 : mod_reg_2 <= vio_wr_data ;

32'd3 : mod_reg_3 <= vio_wr_data ;

32'd4 : mod_reg_4 <= vio_wr_data ;

32'd5 : mod_reg_5 <= vio_wr_data ;

32'd6 : mod_reg_6 <= vio_wr_data ;

32'd7 : mod_reg_7 <= vio_wr_data ;

32'd8 : mod_reg_8 <= vio_wr_data ;

32'd9 : mod_reg_9 <= vio_wr_data ;

32'd10 : mod_reg_10 <= vio_wr_data ;

32'd11 : mod_reg_11 <= vio_wr_data ;

32'd12 : mod_reg_12 <= vio_wr_data ;

32'd13 : mod_reg_13 <= vio_wr_data ;

32'd14 : mod_reg_14 <= vio_wr_data ;

32'd15 : mod_reg_15 <= vio_wr_data ;

32'd16 : mod_reg_16 <= vio_wr_data ;

32'd17 : mod_reg_17 <= vio_wr_data ;

32'd18 : mod_reg_18 <= vio_wr_data ;

32'd19 : mod_reg_19 <= vio_wr_data ;

32'd20 : mod_reg_20 <= vio_wr_data ;

32'd21 : mod_reg_21 <= vio_wr_data ;

32'd22 : mod_reg_22 <= vio_wr_data ;

32'd23 : mod_reg_23 <= vio_wr_data ;

32'd24 : mod_reg_24 <= vio_wr_data ;

32'd25 : mod_reg_25 <= vio_wr_data ;

32'd26 : mod_reg_26 <= vio_wr_data ;

32'd27 : mod_reg_27 <= vio_wr_data ;

32'd28 : mod_reg_28 <= vio_wr_data ;

32'd29 : mod_reg_29 <= vio_wr_data ;

32'd30 : mod_reg_30 <= vio_wr_data ;

32'd31 : mod_reg_31 <= vio_wr_data ;

default :

begin

end

endcase

end

else

begin

end

end

always @(posedge clk)

begin

case ( vio_rd_addr )

32'd0 : vio_rd_data <= mod_reg_0 ;

32'd1 : vio_rd_data <= mod_reg_1 ;

32'd2 : vio_rd_data <= mod_reg_2 ;

32'd3 : vio_rd_data <= mod_reg_3 ;

32'd4 : vio_rd_data <= mod_reg_4 ;

32'd5 : vio_rd_data <= mod_reg_5 ;

32'd6 : vio_rd_data <= mod_reg_6 ;

32'd7 : vio_rd_data <= mod_reg_7 ;

32'd8 : vio_rd_data <= mod_reg_8 ;

32'd9 : vio_rd_data <= mod_reg_9 ;

32'd10 : vio_rd_data <= mod_reg_10 ;

32'd11 : vio_rd_data <= mod_reg_11 ;

32'd12 : vio_rd_data <= mod_reg_12 ;

32'd13 : vio_rd_data <= mod_reg_13 ;

32'd14 : vio_rd_data <= mod_reg_14 ;

32'd15 : vio_rd_data <= mod_reg_15 ;

32'd16 : vio_rd_data <= mod_reg_16 ;

32'd17 : vio_rd_data <= mod_reg_17 ;

32'd18 : vio_rd_data <= mod_reg_18 ;

32'd19 : vio_rd_data <= mod_reg_19 ;

32'd20 : vio_rd_data <= mod_reg_20 ;

32'd21 : vio_rd_data <= mod_reg_21 ;

32'd22 : vio_rd_data <= mod_reg_22 ;

32'd23 : vio_rd_data <= mod_reg_23 ;

32'd24 : vio_rd_data <= mod_reg_24 ;

32'd25 : vio_rd_data <= mod_reg_25 ;

32'd26 : vio_rd_data <= mod_reg_26 ;

32'd27 : vio_rd_data <= mod_reg_27 ;

32'd28 : vio_rd_data <= mod_reg_28 ;

32'd29 : vio_rd_data <= mod_reg_29 ;

32'd30 : vio_rd_data <= mod_reg_30 ;

32'd31 : vio_rd_data <= mod_reg_31 ;

default :

begin

vio_rd_data <= vio_rd_data ;

end

endcase

end

endmodule

2、約束文件源碼

set_property PACKAGE_PIN Y9 [get_ports clk]

set_property IOSTANDARD LVCMOS33 [get_ports clk]

使用VIVADO中VIO模擬CPU接口進行在線寄存器讀寫調試(附源代碼)

上述源碼及約束文件適用於Xilinx的Zedboard開發板,已上板驗證。另外,上面僅是原理性的簡單演示,可以把寄存器應用於自己設計中的各個內部關鍵模塊中,調試的過程中,實時的從VIO接口獲取數據,或者動態的配置FPGA內部的寄存器,使其按照寄存器約定的功能運行。雖沒有CPU,卻等效有了CPU,可大大提高FPGA調試的效率。VIO佔用資源情況與chipscope類似。

在PC上通過TCL或者其它語言捕獲數據的功能在後續的文章中會陸續的公佈,歡迎留言討論。


分享到:


相關文章: