本小節通過使用XPS中的定制IP向導(ipwiz),為已經存在的ARM PS 系統添加用戶自定IP(Custom IP ),了解AXI Lite IP基本結構,并掌握AXI Lite IP的定制方法,為后續編寫復雜AXI IP打下基礎。同時本小節IP定制方法同樣適用于MicroBlaze處理系統。
本小節定制的是簡單LED的IP,只有一個數據寄存器,向其寫值就可以控制8個LED相應亮滅。
硬件平臺:Digilent ZedBoard
開發環境:Windows XP 32 bit
軟件: XPS 14.2 +SDK 14.2
一、創建ARM PS系統
同前面幾節一樣,首先使用XPS創建ARM PS系統。需要注意的是,在選擇外設時,同樣不要添加任何外設
二、定制AXI IP
ARM PS系統創建結束后,就可以開始定制用戶自定義IP。XPS提供了Create or Import Peripheral Wizward 向導,使得用戶自定義IP的創建變得非常簡單。當然在熟悉了AXI IP核結構和代碼編寫規則后,可以直接編寫自己的IP核而不使用向導。這里采用向導方式。
1、產生AXI IP外設模版
Hardware->Create or Import Peripheral Wizward ,啟動向導
歡迎界面
選擇從模板創建新外設
默認是將外設直接包含到當前XPS工程中
填入外設名。注意必須都是小寫。這里我們建立的是my_axi_ip。下面是版本控制,可以根據需要修改。同時面板的最下方還提示了將創建名為my_axi_ip_v1_00_a的庫(其實就是一個目錄),所有實現這個IP的HDL文件都在這個庫中。
接下來要選擇外設總線的類型。AXI4_Lite為最基本的AXI 總線,用于簡單處理,所有空間訪問都是通過地址/寄存器方式訪問,不支持突發;AXI4是標準AXI4總線標準,支持突然,支持高速;AXI4_Stream專門為數據流而設計。
在IPIF (IP 接口) 配置,這里配置接口的一些屬性,如是否是AXI 主/從設備等。我們所定制的IP是一個從設備,因而不需要使用主設備接口。
選擇需啊喲的寄存器數量。因為我們只需要一個數據寄存器,這里選1。
接下來就是IPIC(IP 互聯),也就是IP的接口信號。以BUS2開頭的信號,意味對IP來說,這些信號是輸入信號;同樣IP2BUS意味著輸出信號。
這里一些信號做一些說明。
BUS2IP_WrCE(Write Chip Enable,寫使能)
Active high chip enable bus to the user logic. These chip enables are asserted only during active write transaction requests with the target address space and in conjunction with the corresponding sub-address within the space. Typically used for user logic writable registers selection.
BUS2IP_Data(Write Data,寫數據)
Write data bus to the user logic. Write data is accepted by the user logic during a write operation by assertion of the write acknowledgement signal and the rising edge of the Bus2IP_Clk.
BUS2IP_BE(Byte Enable,字節使能)
Byte Enable qualifiers for the requested read or write operation to the user logic. A bit in the Bus2IP_BE set to '1' indicates that the associated byte lane contains valid data. For example, if Bus2IP_BE = 0011, this indicates that byte lanes 2 and 3 contain valid data.
IPBUS2_RdAck(Read Acknowledgement,讀反饋)
Active high read data qualifier providing the read acknowledgement from the user logic. Read data on the IP2Bus_Data bus is deemed valid at the rising edge of the Bus2IP_Clk and IP2Bus_RdAck asserted high by the user logic.
接下來需要使用需要使用BFM (Bus Functional Models, 總線功能模型)對外設進行仿真。本例IP很簡單,不要使用。
最后,需要選擇HDL類型、ISE工程支持和軟件驅動模板。因為我比較習慣使用verilog,因而使用verilog模板。需要說明的是,IP接口仍然是VHDL編寫,只是用戶邏輯改用verilog。如果不需要使用軟件驅動模板的話,可以不選上。這里選上了,但是后續編程的時候我并沒有用。
最后給出了外設的信息summary。支持,my_axi_ip"外殼"基本完成。后續我們只需要對user_logic進行編寫,并修改元件引腳即可。
2、編寫IP
修改.mpd文件,在目錄
Lab4pcoresmy_axi_ip_v1_00_adata
###################################################################
##
## Name : my_axi_ip
## Desc : Microprocessor Peripheral Description
## : Automatically generated by PsfUtility
##
###################################################################
BEGIN my_axi_ip
## Peripheral Options
OPTION IPTYPE = PERIPHERAL
OPTION IMP_NETLIST = TRUE
OPTION HDL = MIXED
OPTION IP_GROUP = MICROBLAZE:USER
OPTION DESC = MY_AXI_IP
OPTION ARCH_SUPPORT_MAP = (others=DEVELOPMENT)
## Bus Interfaces
BUS_INTERFACE BUS = S_AXI, BUS_STD = AXI, BUS_TYPE = SLAVE
## Generics for VHDL or Parameters for Verilog
PARAMETER C_S_AXI_DATA_WIDTH = 32, DT = INTEGER, BUS = S_AXI, ASSIGNMENT = CONSTANT
PARAMETER C_S_AXI_ADDR_WIDTH = 32, DT = INTEGER, BUS = S_AXI, ASSIGNMENT = CONSTANT
PARAMETER C_S_AXI_MIN_SIZE = 0x000001ff, DT = std_logic_vector, BUS = S_AXI
PARAMETER C_USE_WSTRB = 0, DT = INTEGER
PARAMETER C_DPHASE_TIMEOUT = 8, DT = INTEGER
PARAMETER C_BASEADDR = 0xffffffff, DT = std_logic_vector, MIN_SIZE = 0x100, PAIR = C_HIGHADDR, ADDRESS = BASE, BUS = S_AXI
PARAMETER C_HIGHADDR = 0x00000000, DT = std_logic_vector, PAIR = C_BASEADDR, ADDRESS = HIGH, BUS = S_AXI
PARAMETER C_FAMILY = virtex6, DT = STRING
PARAMETER C_NUM_REG = 1, DT = INTEGER
PARAMETER C_NUM_MEM = 1, DT = INTEGER
PARAMETER C_SLV_AWIDTH = 32, DT = INTEGER
PARAMETER C_SLV_DWIDTH = 32, DT = INTEGER
PARAMETER C_S_AXI_PROTOCOL = AXI4LITE, TYPE = NON_HDL, ASSIGNMENT = CONSTANT, DT = STRING, BUS = S_AXI
## Ports
PORT LED = "", DIR = O, VEC = [7:0]
PORT S_AXI_ACLK = "", DIR = I, SIGIS = CLK, BUS = S_AXI
PORT S_AXI_ARESETN = ARESETN, DIR = I, SIGIS = RST, BUS = S_AXI
PORT S_AXI_AWADDR = AWADDR, DIR = I, VEC = [(C_S_AXI_ADDR_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_AWVALID = AWVALID, DIR = I, BUS = S_AXI
PORT S_AXI_WDATA = WDATA, DIR = I, VEC = [(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_WSTRB = WSTRB, DIR = I, VEC = [((C_S_AXI_DATA_WIDTH/8)-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_WVALID = WVALID, DIR = I, BUS = S_AXI
PORT S_AXI_BREADY = BREADY, DIR = I, BUS = S_AXI
PORT S_AXI_ARADDR = ARADDR, DIR = I, VEC = [(C_S_AXI_ADDR_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_ARVALID = ARVALID, DIR = I, BUS = S_AXI
PORT S_AXI_RREADY = RREADY, DIR = I, BUS = S_AXI
PORT S_AXI_ARREADY = ARREADY, DIR = O, BUS = S_AXI
PORT S_AXI_RDATA = RDATA, DIR = O, VEC = [(C_S_AXI_DATA_WIDTH-1):0], ENDIAN = LITTLE, BUS = S_AXI
PORT S_AXI_RRESP = RRESP, DIR = O, VEC = [1:0], BUS = S_AXI
PORT S_AXI_RVALID = RVALID, DIR = O, BUS = S_AXI
PORT S_AXI_WREADY = WREADY, DIR = O, BUS = S_AXI
PORT S_AXI_BRESP = BRESP, DIR = O, VEC = [1:0], BUS = S_AXI
PORT S_AXI_BVALID = BVALID, DIR = O, BUS = S_AXI
PORT S_AXI_AWREADY = AWREADY, DIR = O, BUS = S_AXI
END
其中,第39行
PORT LED = "", DIR = O, VEC = [7:0]
是我們添加上的,表明我們為其添加了一個名為LED的端口,方向是輸出,長度是8位。其他行代碼為默認,不需要修改。
修改用戶邏輯,在
Lab4pcoresmy_axi_ip_v1_00_ahdlveriloguser_logic.v
//----------------------------------------------------------------------------
// user_logic.v - module
//----------------------------------------------------------------------------
//
// ***************************************************************************
// ** Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved. **
// ** **
// ** Xilinx, Inc. **
// ** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" **
// ** AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND **
// ** SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, **
// ** OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, **
// ** APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION **
// ** THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, **
// ** AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE **
// ** FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY **
// ** WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE **
// ** IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR **
// ** REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF **
// ** INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS **
// ** FOR A PARTICULAR PURPOSE. **
// ** **
// ***************************************************************************
//
//----------------------------------------------------------------------------
// Filename: user_logic.v
// Version: 1.00.a
// Description: User logic module.
// Date: Tue Oct 09 18:28:06 2012 (by Create and Import Peripheral Wizard)
// Verilog Standard: Verilog-2001
//----------------------------------------------------------------------------
// Naming Conventions:
// active low signals: "*_n"
// clock signals: "clk", "clk_div#", "clk_#x"
// reset signals: "rst", "rst_n"
// generics: "C_*"
// user defined types: "*_TYPE"
// state machine next state: "*_ns"
// state machine current state: "*_cs"
// combinatorial signals: "*_com"
// pipelined or register delay signals: "*_d#"
// counter signals: "*cnt*"
// clock enable signals: "*_ce"
// internal version of output port: "*_i"
// device pins: "*_pin"
// ports: "- Names begin with Uppercase"
// processes: "*_PROCESS"
// component instantiations: "I_<#|FUNC>"
//----------------------------------------------------------------------------
`uselib lib=unisims_ver
`uselib lib=proc_common_v3_00_a
module user_logic
(
// -- ADD USER PORTS BELOW THIS LINE ---------------
LED,
// -- ADD USER PORTS ABOVE THIS LINE ---------------
// -- DO NOT EDIT BELOW THIS LINE ------------------
// -- Bus protocol ports, do not add to or delete
Bus2IP_Clk, // Bus to IP clock
Bus2IP_Resetn, // Bus to IP reset
Bus2IP_Data, // Bus to IP data bus
Bus2IP_BE, // Bus to IP byte enables
Bus2IP_RdCE, // Bus to IP read chip enable
Bus2IP_WrCE, // Bus to IP write chip enable
IP2Bus_Data, // IP to Bus data bus
IP2Bus_RdAck, // IP to Bus read transfer acknowledgement
IP2Bus_WrAck, // IP to Bus write transfer acknowledgement
IP2Bus_Error // IP to Bus error response
// -- DO NOT EDIT ABOVE THIS LINE ------------------
); // user_logic
// -- ADD USER PARAMETERS BELOW THIS LINE ------------
// --USER parameters added here
// -- ADD USER PARAMETERS ABOVE THIS LINE ------------
// -- DO NOT EDIT BELOW THIS LINE --------------------
// -- Bus protocol parameters, do not add to or delete
parameter C_NUM_REG = 1;
parameter C_SLV_DWIDTH = 32;
// -- DO NOT EDIT ABOVE THIS LINE --------------------
// -- ADD USER PORTS BELOW THIS LINE -----------------
output [7:0] LED;
// -- ADD USER PORTS ABOVE THIS LINE -----------------
// -- DO NOT EDIT BELOW THIS LINE --------------------
// -- Bus protocol ports, do not add to or delete
input Bus2IP_Clk;
input Bus2IP_Resetn;
input [C_SLV_DWIDTH-1 : 0] Bus2IP_Data;
input [C_SLV_DWIDTH/8-1 : 0] Bus2IP_BE;
input [C_NUM_REG-1 : 0] Bus2IP_RdCE;
input [C_NUM_REG-1 : 0] Bus2IP_WrCE;
output [C_SLV_DWIDTH-1 : 0] IP2Bus_Data;
output IP2Bus_RdAck;
output IP2Bus_WrAck;
output IP2Bus_Error;
// -- DO NOT EDIT ABOVE THIS LINE --------------------
//----------------------------------------------------------------------------
// Implementation
//----------------------------------------------------------------------------
// --USER nets declarations added here, as needed for user logic
// Nets for user logic slave model s/w accessible register example
reg [C_SLV_DWIDTH-1 : 0] slv_reg0;
wire [0 : 0] slv_reg_write_sel;
wire [0 : 0] slv_reg_read_sel;
reg [C_SLV_DWIDTH-1 : 0] slv_ip2bus_data;
wire slv_read_ack;
wire slv_write_ack;
integer byte_index, bit_index;
// USER logic implementation added here
assign LED = slv_reg0[7:0];
// ------------------------------------------------------
// Example code to read/write user logic slave model s/w accessible registers
//
// Note:
// The example code presented here is to show you one way of reading/writing
// software accessible registers implemented in the user logic slave model.
// Each bit of the Bus2IP_WrCE/Bus2IP_RdCE signals is configured to correspond
// to one software accessible register by the top level template. For example,
// if you have four 32 bit software accessible registers in the user logic,
// you are basically operating on the following memory mapped registers:
//
// Bus2IP_WrCE/Bus2IP_RdCE Memory Mapped Register
// "1000" C_BASEADDR + 0x0
// "0100" C_BASEADDR + 0x4
// "0010" C_BASEADDR + 0x8
// "0001" C_BASEADDR + 0xC
//
// ------------------------------------------------------
assign
slv_reg_write_sel = Bus2IP_WrCE[0:0],
slv_reg_read_sel = Bus2IP_RdCE[0:0],
slv_write_ack = Bus2IP_WrCE[0],
slv_read_ack = Bus2IP_RdCE[0];
// implement slave model register(s)
always @( posedge Bus2IP_Clk )
begin
if ( Bus2IP_Resetn == 1'b0 )
begin
slv_reg0 <= 0;
end
else
case ( slv_reg_write_sel )
1'b1 :
for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 )
if ( Bus2IP_BE[byte_index] == 1 )
slv_reg0[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8];
default : begin
slv_reg0 <= slv_reg0;
end
endcase
end // SLAVE_REG_WRITE_PROC
// implement slave model register read mux
always @( slv_reg_read_sel or slv_reg0 )
begin
case ( slv_reg_read_sel )
1'b1 : slv_ip2bus_data <= slv_reg0;
default : slv_ip2bus_data <= 0;
endcase
end // SLAVE_REG_READ_PROC
// ------------------------------------------------------------
// Example code to drive IP to Bus signals
// ------------------------------------------------------------
assign IP2Bus_Data = (slv_read_ack == 1'b1) ? slv_ip2bus_data : 0 ;
assign IP2Bus_WrAck = slv_write_ack;
assign IP2Bus_RdAck = slv_read_ack;
assign IP2Bus_Error = 0;
endmodule
代碼中57、86行
LED,
output [7:0] LED;
表明在用戶邏輯中,定義了名為LED的端口,方向是輸出,長度為8。
代碼中119行
assign LED = slv_reg0[7:0];
表明將slv_reg0的低8位傳遞給輸出端口LED。其實就是實現了數據寄存器的值作用到輸出端口的功能。
需要將用戶邏輯和IPIF連接上,需要完成user_logic的例化
Lab4pcoresmy_axi_ip_v1_00_ahdlvhdlmy_axi_ip.vhd
------------------------------------------------------------------------------
-- my_axi_ip.vhd - entity/architecture pair
------------------------------------------------------------------------------
-- IMPORTANT:
-- DO NOT MODIFY THIS FILE EXCEPT IN THE DESIGNATED SECTIONS.
--
-- SEARCH FOR --USER TO DETERMINE WHERE CHANGES ARE ALLOWED.
--
-- TYPICALLY, THE ONLY ACCEPTABLE CHANGES INVOLVE ADDING NEW
-- PORTS AND GENERICS THAT GET PASSED THROUGH TO THE INSTANTIATION
-- OF THE USER_LOGIC ENTITY.
------------------------------------------------------------------------------
--
-- ***************************************************************************
-- ** Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved. **
-- ** **
-- ** Xilinx, Inc. **
-- ** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" **
-- ** AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND **
-- ** SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, **
-- ** OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, **
-- ** APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION **
-- ** THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, **
-- ** AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE **
-- ** FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY **
-- ** WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE **
-- ** IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR **
-- ** REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF **
-- ** INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS **
-- ** FOR A PARTICULAR PURPOSE. **
-- ** **
-- ***************************************************************************
--
------------------------------------------------------------------------------
-- Filename: my_axi_ip.vhd
-- Version: 1.00.a
-- Description: Top level design, instantiates library components and user logic.
-- Date: Tue Oct 09 18:28:06 2012 (by Create and Import Peripheral Wizard)
-- VHDL Standard: VHDL'93
------------------------------------------------------------------------------
-- Naming Conventions:
-- active low signals: "*_n"
-- clock signals: "clk", "clk_div#", "clk_#x"
-- reset signals: "rst", "rst_n"
-- generics: "C_*"
-- user defined types: "*_TYPE"
-- state machine next state: "*_ns"
-- state machine current state: "*_cs"
-- combinatorial signals: "*_com"
-- pipelined or register delay signals: "*_d#"
-- counter signals: "*cnt*"
-- clock enable signals: "*_ce"
-- internal version of output port: "*_i"
-- device pins: "*_pin"
-- ports: "- Names begin with Uppercase"
-- processes: "*_PROCESS"
-- component instantiations: "I_<#|FUNC>"
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
library proc_common_v3_00_a;
use proc_common_v3_00_a.proc_common_pkg.all;
use proc_common_v3_00_a.ipif_pkg.all;
library axi_lite_ipif_v1_01_a;
use axi_lite_ipif_v1_01_a.axi_lite_ipif;
------------------------------------------------------------------------------
-- Entity section
------------------------------------------------------------------------------
-- Definition of Generics:
-- C_S_AXI_DATA_WIDTH -- AXI4LITE slave: Data width
-- C_S_AXI_ADDR_WIDTH -- AXI4LITE slave: Address Width
-- C_S_AXI_MIN_SIZE -- AXI4LITE slave: Min Size
-- C_USE_WSTRB -- AXI4LITE slave: Write Strobe
-- C_DPHASE_TIMEOUT -- AXI4LITE slave: Data Phase Timeout
-- C_BASEADDR -- AXI4LITE slave: base address
-- C_HIGHADDR -- AXI4LITE slave: high address
-- C_FAMILY -- FPGA Family
-- C_NUM_REG -- Number of software accessible registers
-- C_NUM_MEM -- Number of address-ranges
-- C_SLV_AWIDTH -- Slave interface address bus width
-- C_SLV_DWIDTH -- Slave interface data bus width
--
-- Definition of Ports:
-- S_AXI_ACLK -- AXI4LITE slave: Clock
-- S_AXI_ARESETN -- AXI4LITE slave: Reset
-- S_AXI_AWADDR -- AXI4LITE slave: Write address
-- S_AXI_AWVALID -- AXI4LITE slave: Write address valid
-- S_AXI_WDATA -- AXI4LITE slave: Write data
-- S_AXI_WSTRB -- AXI4LITE slave: Write strobe
-- S_AXI_WVALID -- AXI4LITE slave: Write data valid
-- S_AXI_BREADY -- AXI4LITE slave: Response ready
-- S_AXI_ARADDR -- AXI4LITE slave: Read address
-- S_AXI_ARVALID -- AXI4LITE slave: Read address valid
-- S_AXI_RREADY -- AXI4LITE slave: Read data ready
-- S_AXI_ARREADY -- AXI4LITE slave: read addres ready
-- S_AXI_RDATA -- AXI4LITE slave: Read data
-- S_AXI_RRESP -- AXI4LITE slave: Read data response
-- S_AXI_RVALID -- AXI4LITE slave: Read data valid
-- S_AXI_WREADY -- AXI4LITE slave: Write data ready
-- S_AXI_BRESP -- AXI4LITE slave: Response
-- S_AXI_BVALID -- AXI4LITE slave: Resonse valid
-- S_AXI_AWREADY -- AXI4LITE slave: Wrte address ready
------------------------------------------------------------------------------
entity my_axi_ip is
generic
(
-- ADD USER GENERICS BELOW THIS LINE ---------------
--USER generics added here
-- ADD USER GENERICS ABOVE THIS LINE ---------------
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- Bus protocol parameters, do not add to or delete
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_ADDR_WIDTH : integer := 32;
C_S_AXI_MIN_SIZE : std_logic_vector := X"000001FF";
C_USE_WSTRB : integer := 0;
C_DPHASE_TIMEOUT : integer := 8;
C_BASEADDR : std_logic_vector := X"FFFFFFFF";
C_HIGHADDR : std_logic_vector := X"00000000";
C_FAMILY : string := "virtex6";
C_NUM_REG : integer := 1;
C_NUM_MEM : integer := 1;
C_SLV_AWIDTH : integer := 32;
C_SLV_DWIDTH : integer := 32
-- DO NOT EDIT ABOVE THIS LINE ---------------------
);
port
(
-- ADD USER PORTS BELOW THIS LINE ------------------
LED : out std_logic_vector(7 downto 0);
-- ADD USER PORTS ABOVE THIS LINE ------------------
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- Bus protocol ports, do not add to or delete
S_AXI_ACLK : in std_logic;
S_AXI_ARESETN : in std_logic;
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_BREADY : in std_logic;
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_RREADY : in std_logic;
S_AXI_ARREADY : out std_logic;
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_WREADY : out std_logic;
S_AXI_BRESP : out std_logic_vector(1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_AWREADY : out std_logic
-- DO NOT EDIT ABOVE THIS LINE ---------------------
);
attribute MAX_FANOUT : string;
attribute SIGIS : string;
attribute MAX_FANOUT of S_AXI_ACLK : signal is "10000";
attribute MAX_FANOUT of S_AXI_ARESETN : signal is "10000";
attribute SIGIS of S_AXI_ACLK : signal is "Clk";
attribute SIGIS of S_AXI_ARESETN : signal is "Rst";
end entity my_axi_ip;
------------------------------------------------------------------------------
-- Architecture section
------------------------------------------------------------------------------
architecture IMP of my_axi_ip is
constant USER_SLV_DWIDTH : integer := C_S_AXI_DATA_WIDTH;
constant IPIF_SLV_DWIDTH : integer := C_S_AXI_DATA_WIDTH;
constant ZERO_ADDR_PAD : std_logic_vector(0 to 31) := (others => '0');
constant USER_SLV_BASEADDR : std_logic_vector := C_BASEADDR;
constant USER_SLV_HIGHADDR : std_logic_vector := C_HIGHADDR;
constant IPIF_ARD_ADDR_RANGE_ARRAY : SLV64_ARRAY_TYPE :=
(
ZERO_ADDR_PAD & USER_SLV_BASEADDR, -- user logic slave space base address
ZERO_ADDR_PAD & USER_SLV_HIGHADDR -- user logic slave space high address
);
constant USER_SLV_NUM_REG : integer := 1;
constant USER_NUM_REG : integer := USER_SLV_NUM_REG;
constant TOTAL_IPIF_CE : integer := USER_NUM_REG;
constant IPIF_ARD_NUM_CE_ARRAY : INTEGER_ARRAY_TYPE :=
(
0 => (USER_SLV_NUM_REG) -- number of ce for user logic slave space
);
------------------------------------------
-- Index for CS/CE
------------------------------------------
constant USER_SLV_CS_INDEX : integer := 0;
constant USER_SLV_CE_INDEX : integer := calc_start_ce_index(IPIF_ARD_NUM_CE_ARRAY, USER_SLV_CS_INDEX);
constant USER_CE_INDEX : integer := USER_SLV_CE_INDEX;
------------------------------------------
-- IP Interconnect (IPIC) signal declarations
------------------------------------------
signal ipif_Bus2IP_Clk : std_logic;
signal ipif_Bus2IP_Resetn : std_logic;
signal ipif_Bus2IP_Addr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal ipif_Bus2IP_RNW : std_logic;
signal ipif_Bus2IP_BE : std_logic_vector(IPIF_SLV_DWIDTH/8-1 downto 0);
signal ipif_Bus2IP_CS : std_logic_vector((IPIF_ARD_ADDR_RANGE_ARRAY'LENGTH)/2-1 downto 0);
signal ipif_Bus2IP_RdCE : std_logic_vector(calc_num_ce(IPIF_ARD_NUM_CE_ARRAY)-1 downto 0);
signal ipif_Bus2IP_WrCE : std_logic_vector(calc_num_ce(IPIF_ARD_NUM_CE_ARRAY)-1 downto 0);
signal ipif_Bus2IP_Data : std_logic_vector(IPIF_SLV_DWIDTH-1 downto 0);
signal ipif_IP2Bus_WrAck : std_logic;
signal ipif_IP2Bus_RdAck : std_logic;
signal ipif_IP2Bus_Error : std_logic;
signal ipif_IP2Bus_Data : std_logic_vector(IPIF_SLV_DWIDTH-1 downto 0);
signal user_Bus2IP_RdCE : std_logic_vector(USER_NUM_REG-1 downto 0);
signal user_Bus2IP_WrCE : std_logic_vector(USER_NUM_REG-1 downto 0);
signal user_IP2Bus_Data : std_logic_vector(USER_SLV_DWIDTH-1 downto 0);
signal user_IP2Bus_RdAck : std_logic;
signal user_IP2Bus_WrAck : std_logic;
signal user_IP2Bus_Error : std_logic;
------------------------------------------
-- Component declaration for verilog user logic
------------------------------------------
component user_logic is
generic
(
-- ADD USER GENERICS BELOW THIS LINE ---------------
--USER generics added here
-- ADD USER GENERICS ABOVE THIS LINE ---------------
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- Bus protocol parameters, do not add to or delete
C_NUM_REG : integer := 1;
C_SLV_DWIDTH : integer := 32
-- DO NOT EDIT ABOVE THIS LINE ---------------------
);
port
(
-- ADD USER PORTS BELOW THIS LINE ------------------
LED : out std_logic_vector(7 downto 0);
-- ADD USER PORTS ABOVE THIS LINE ------------------
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- Bus protocol ports, do not add to or delete
Bus2IP_Clk : in std_logic;
Bus2IP_Resetn : in std_logic;
Bus2IP_Data : in std_logic_vector(C_SLV_DWIDTH-1 downto 0);
Bus2IP_BE : in std_logic_vector(C_SLV_DWIDTH/8-1 downto 0);
Bus2IP_RdCE : in std_logic_vector(C_NUM_REG-1 downto 0);
Bus2IP_WrCE : in std_logic_vector(C_NUM_REG-1 downto 0);
IP2Bus_Data : out std_logic_vector(C_SLV_DWIDTH-1 downto 0);
IP2Bus_RdAck : out std_logic;
IP2Bus_WrAck : out std_logic;
IP2Bus_Error : out std_logic
-- DO NOT EDIT ABOVE THIS LINE ---------------------
);
end component user_logic;
begin
------------------------------------------
-- instantiate axi_lite_ipif
------------------------------------------
AXI_LITE_IPIF_I : entity axi_lite_ipif_v1_01_a.axi_lite_ipif
generic map
(
C_S_AXI_DATA_WIDTH => IPIF_SLV_DWIDTH,
C_S_AXI_ADDR_WIDTH => C_S_AXI_ADDR_WIDTH,
C_S_AXI_MIN_SIZE => C_S_AXI_MIN_SIZE,
C_USE_WSTRB => C_USE_WSTRB,
C_DPHASE_TIMEOUT => C_DPHASE_TIMEOUT,
C_ARD_ADDR_RANGE_ARRAY => IPIF_ARD_ADDR_RANGE_ARRAY,
C_ARD_NUM_CE_ARRAY => IPIF_ARD_NUM_CE_ARRAY,
C_FAMILY => C_FAMILY
)
port map
(
S_AXI_ACLK => S_AXI_ACLK,
S_AXI_ARESETN => S_AXI_ARESETN,
S_AXI_AWADDR => S_AXI_AWADDR,
S_AXI_AWVALID => S_AXI_AWVALID,
S_AXI_WDATA => S_AXI_WDATA,
S_AXI_WSTRB => S_AXI_WSTRB,
S_AXI_WVALID => S_AXI_WVALID,
S_AXI_BREADY => S_AXI_BREADY,
S_AXI_ARADDR => S_AXI_ARADDR,
S_AXI_ARVALID => S_AXI_ARVALID,
S_AXI_RREADY => S_AXI_RREADY,
S_AXI_ARREADY => S_AXI_ARREADY,
S_AXI_RDATA => S_AXI_RDATA,
S_AXI_RRESP => S_AXI_RRESP,
S_AXI_RVALID => S_AXI_RVALID,
S_AXI_WREADY => S_AXI_WREADY,
S_AXI_BRESP => S_AXI_BRESP,
S_AXI_BVALID => S_AXI_BVALID,
S_AXI_AWREADY => S_AXI_AWREADY,
Bus2IP_Clk => ipif_Bus2IP_Clk,
Bus2IP_Resetn => ipif_Bus2IP_Resetn,
Bus2IP_Addr => ipif_Bus2IP_Addr,
Bus2IP_RNW => ipif_Bus2IP_RNW,
Bus2IP_BE => ipif_Bus2IP_BE,
Bus2IP_CS => ipif_Bus2IP_CS,
Bus2IP_RdCE => ipif_Bus2IP_RdCE,
Bus2IP_WrCE => ipif_Bus2IP_WrCE,
Bus2IP_Data => ipif_Bus2IP_Data,
IP2Bus_WrAck => ipif_IP2Bus_WrAck,
IP2Bus_RdAck => ipif_IP2Bus_RdAck,
IP2Bus_Error => ipif_IP2Bus_Error,
IP2Bus_Data => ipif_IP2Bus_Data
);
------------------------------------------
-- instantiate User Logic
------------------------------------------
USER_LOGIC_I : component user_logic
generic map
(
-- MAP USER GENERICS BELOW THIS LINE ---------------
--USER generics mapped here
-- MAP USER GENERICS ABOVE THIS LINE ---------------
C_NUM_REG => USER_NUM_REG,
C_SLV_DWIDTH => USER_SLV_DWIDTH
)
port map
(
-- MAP USER PORTS BELOW THIS LINE ------------------
LED => LED,
-- MAP USER PORTS ABOVE THIS LINE ------------------
Bus2IP_Clk => ipif_Bus2IP_Clk,
Bus2IP_Resetn => ipif_Bus2IP_Resetn,
Bus2IP_Data => ipif_Bus2IP_Data,
Bus2IP_BE => ipif_Bus2IP_BE,
Bus2IP_RdCE => user_Bus2IP_RdCE,
Bus2IP_WrCE => user_Bus2IP_WrCE,
IP2Bus_Data => user_IP2Bus_Data,
IP2Bus_RdAck => user_IP2Bus_RdAck,
IP2Bus_WrAck => user_IP2Bus_WrAck,
IP2Bus_Error => user_IP2Bus_Error
);
------------------------------------------
-- connect internal signals
------------------------------------------
ipif_IP2Bus_Data <= user_IP2Bus_Data;
ipif_IP2Bus_WrAck <= user_IP2Bus_WrAck;
ipif_IP2Bus_RdAck <= user_IP2Bus_RdAck;
ipif_IP2Bus_Error <= user_IP2Bus_Error;
user_Bus2IP_RdCE <= ipif_Bus2IP_RdCE(USER_NUM_REG-1 downto 0);
user_Bus2IP_WrCE <= ipif_Bus2IP_WrCE(USER_NUM_REG-1 downto 0);
end IMP;
137行
LED : out std_logic_vector(7 downto 0);
定義IP的端口為LED,這里需要和之前修改MPD文件一致。
232-268行為元件聲明
------------------------------------------
-- Component declaration for verilog user logic
------------------------------------------
component user_logic is
generic
(
-- ADD USER GENERICS BELOW THIS LINE ---------------
--USER generics added here
-- ADD USER GENERICS ABOVE THIS LINE ---------------
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- Bus protocol parameters, do not add to or delete
C_NUM_REG : integer := 1;
C_SLV_DWIDTH : integer := 32
-- DO NOT EDIT ABOVE THIS LINE ---------------------
);
port
(
-- ADD USER PORTS BELOW THIS LINE ------------------
LED : out std_logic_vector(7 downto 0);
-- ADD USER PORTS ABOVE THIS LINE ------------------
-- DO NOT EDIT BELOW THIS LINE ---------------------
-- Bus protocol ports, do not add to or delete
Bus2IP_Clk : in std_logic;
Bus2IP_Resetn : in std_logic;
Bus2IP_Data : in std_logic_vector(C_SLV_DWIDTH-1 downto 0);
Bus2IP_BE : in std_logic_vector(C_SLV_DWIDTH/8-1 downto 0);
Bus2IP_RdCE : in std_logic_vector(C_NUM_REG-1 downto 0);
Bus2IP_WrCE : in std_logic_vector(C_NUM_REG-1 downto 0);
IP2Bus_Data : out std_logic_vector(C_SLV_DWIDTH-1 downto 0);
IP2Bus_RdAck : out std_logic;
IP2Bus_WrAck : out std_logic;
IP2Bus_Error : out std_logic
-- DO NOT EDIT ABOVE THIS LINE ---------------------
);
end component user_logic;
323-352行為user_logic元件例化。VHDL是不區分大小寫的。
------------------------------------------
-- instantiate User Logic
------------------------------------------
USER_LOGIC_I : component user_logic
generic map
(
-- MAP USER GENERICS BELOW THIS LINE ---------------
--USER generics mapped here
-- MAP USER GENERICS ABOVE THIS LINE ---------------
C_NUM_REG => USER_NUM_REG,
C_SLV_DWIDTH => USER_SLV_DWIDTH
)
port map
(
-- MAP USER PORTS BELOW THIS LINE ------------------
LED => LED,
-- MAP USER PORTS ABOVE THIS LINE ------------------
Bus2IP_Clk => ipif_Bus2IP_Clk,
Bus2IP_Resetn => ipif_Bus2IP_Resetn,
Bus2IP_Data => ipif_Bus2IP_Data,
Bus2IP_BE => ipif_Bus2IP_BE,
Bus2IP_RdCE => user_Bus2IP_RdCE,
Bus2IP_WrCE => user_Bus2IP_WrCE,
IP2Bus_Data => user_IP2Bus_Data,
IP2Bus_RdAck => user_IP2Bus_RdAck,
IP2Bus_WrAck => user_IP2Bus_WrAck,
IP2Bus_Error => user_IP2Bus_Error
);
這幾個文件修改后保存。
Project->Rescan User Repositories(更新用戶倉庫?),讓XPS識別到對IP所做的修改
三、將自定義IP核添加到PS系統
同第三篇一樣,需要將IP添加到PS系統中。
在Ports標簽中,需要將我們定義的LED端口設置為外部端口,外部引腳名按照Zedboard的習慣,定義為LD
在Address標簽中,設定IP的地址。XPS支持自定義定制范圍、空間大小等??梢允褂媚J設置,也可以手動設置。這里我設置基地址為0x40000000,其實也就是我們設定的數據寄存器的地址為0x40000000。如果有更多的寄存器,會以4字節offset 地址的方式訪問即可。
最后一樣修改ucf文件,完成約束。
NET LD[0] LOC = T22 | IOSTANDARD=LVCMOS33; # "LD0"
NET LD[1] LOC = T21 | IOSTANDARD=LVCMOS33; # "LD1"
NET LD[2] LOC = U22 | IOSTANDARD=LVCMOS33; # "LD2"
NET LD[3] LOC = U21 | IOSTANDARD=LVCMOS33; # "LD3"
NET LD[4] LOC = V22 | IOSTANDARD=LVCMOS33; # "LD4"
NET LD[5] LOC = W22 | IOSTANDARD=LVCMOS33; # "LD5"
NET LD[6] LOC = U19 | IOSTANDARD=LVCMOS33; # "LD6"
NET LD[7] LOC = U14 | IOSTANDARD=LVCMOS33; # "LD7"
最后對這個系統編譯,生成bitstream文件,并將硬件配置導入到SDK,并啟動SDK。
四、使用SDK編寫IP核驅動程序和應用程序
打開SDK,可以從系統信息system.xml中看到我們的系統信息??梢钥吹轿覀儗嵗B接到系統的ip是my_axi_ip_0,基地址是0x4000000。
建立軟件工程后,修改main代碼,如下
//@超群天晴
#include
#include "xparameters.h"
#include "xil_types.h"
#include "xstatus.h"
#include "xil_io.h"http://包含xil_io頭文件,完成對絕對地址的訪問
#include "platform.h"
#define LED_DATA_REG 0x40000000
void print(char *ptr);
void delay(unsigned int delaytime);
void LED_Play(unsigned char led);
int main(void)
{
init_platform();
print("ZedBoard LAB4: MY_AXI_LEDs
");
print("超群天晴 2012年10月8日22:12:31
");
LED_Play(0x03);
while(1);
cleanup_platform();
return 0;
}
void delay(unsigned int delaytime)
{
int i;
for(i=0;i7);
Xil_Out32(LED_DATA_REG,led);
delay(50000000);
}
}
定義了兩個函數
void delay(unsigned int delaytime);
void LED_Play(unsigned char led);
其中delay()為延時函數,參數為延時時間,100000000大約延時1s;
LED_Play()為LED流水燈函數,參數是流水初始值。在程序里面設定的是0x2,也就LD0、LD1最開始亮,然后流水。
其中第8行
#define LED_DATA_REG 0x40000000
使用宏定義,定義LED_DATA_REG,實際上就是自定義IP的基地址。
第44行
Xil_Out32(LED_DATA_REG,led);
使用了xil_io.h提供的絕對地址訪問函數Xil_Out32(u32 OutAddress, u32 Value),定義如下
/*****************************************************************************/
/**
*
* Performs an output operation for a 32-bit memory location by writing the
* specified Value to the the specified address.
*
* @param OutAddress contains the address to perform the output operation
* at.
* @param Value contains the Value to be output at the specified address.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void Xil_Out32(u32 OutAddress, u32 Value)
{
/* write the contents of the I/O location and then synchronize the I/O
* such that the I/O operation completes before proceeding on
*/
*(volatile u32 *) OutAddress = Value;
SYNCHRONIZE_IO;
}
可以看出,其實現的功能就是向32位絕對地址OutAddress中寫入32位無符號值Value。參考這樣的寫法,可以將地址訪問修改
1 #define LED_DATA_ADDR 0x40000000
2 #define LED_DATA_REG(x) *(volatile unsigned int *) LED_DATA_ADDR = x
然后修改寄存器的值,只需要修改LED_DATA_REG(x)參數x的值即可。
四、運行結果
編譯下載之后,可以從超級終端看到調試信息
同時Zedboard上的 LD 流水
評論