AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)

文章目录

  • 前言
  • 一、环境
  • 二、测试IP
  • 三、IP核封装
  • 四、SOC搭建
  • 五、引脚约束
  • 六、软件设计
  • 七、测试过程
  • 总结


前言

  在前一章中我们已经完成了从机接口模板代码的设计;在本篇中,我们将对设计的从机代码进行板级验证;


一、环境

  验证FPGA选用Xilinx的Zynq 7000,基于Vivado平台进行;
  认证过程将采用软硬协同验证,其中内核为MicroBlaze;


二、测试IP

  测试IP核将基于模板代码修改:
修改后的逻辑文件

//AXI Slave interface
module axi_lite_logic#(

	//axi-lite parameter definition start here
	//data width / address width
	parameter integer     C_AXI_SLV_REG_NUM = 8,
	parameter integer     C_AXI_DATA_WIDTH = 32,
	parameter integer     C_AXI_ADDR_WIDTH = $clog2(C_AXI_SLV_REG_NUM*4)+1
	)
(
	output wire   [3:0]                           led,
	input  wire   [3:0]                           key,
	//system signals definition
	input  wire  						 	      s_axi_aclk,
	input  wire  						 	  s_axi_aresentn,  
	//write address signals definition	  
	input  wire [C_AXI_ADDR_WIDTH - 1:0] 	    s_axi_awaddr,
	input  wire                          	   s_axi_awvalid,
	output wire                          	   s_axi_awready,
	//write data signals definition
	input  wire [C_AXI_DATA_WIDTH - 1:0]   		 s_axi_wdata,
	input  wire                            		s_axi_wvalid,
	output wire                            		s_axi_wready,   
	input  wire [(C_AXI_DATA_WIDTH/8) - 1:0]	 s_axi_wstrb,
	//write response signals definition
	output wire [1:0]                            s_axi_bresp,
	output wire                                 s_axi_bvalid,
	input  wire                                 s_axi_bready,
	//read address signals definition
	input  wire [C_AXI_ADDR_WIDTH - 1:0] 	     s_axi_araddr,
	input  wire                         	    s_axi_arvalid,
	output wire                                 s_axi_arready,
	//read data signals definition
	output wire [C_AXI_DATA_WIDTH - 1:0]   		 s_axi_rdata,
	output wire                            		s_axi_rvalid,
	input  wire                                 s_axi_rready,
	//read response signals definition
	output wire                                  s_axi_rresp,
	//protect signals definition
	input  wire                                 s_axi_arprot
);

	localparam integer     ADDR_SHIFT = C_AXI_DATA_WIDTH/16;


	reg [C_AXI_ADDR_WIDTH - 1:0]    axi_awaddr;
	reg                            axi_awready;
	reg							    axi_wready;
	reg [1:0]                        axi_bresp;
	reg                             axi_bvalid;
	reg                                  aw_en;
	reg [C_AXI_ADDR_WIDTH - 1:0]    axi_araddr;
	reg                            axi_arready;
	reg                             axi_rvalid;
	reg [C_AXI_DATA_WIDTH - 1:0]	 axi_rdata;
    reg [C_AXI_DATA_WIDTH - 1:0]  reg_data_out;


	wire                        register_wr_en;

	//register definition
	reg [(C_AXI_DATA_WIDTH - 1) : 0]  slv_reg[0:(C_AXI_SLV_REG_NUM-1)];

	assign led = slv_reg[0][3:0];

    //inner logic definition
    assign register_wr_en = axi_wready & s_axi_wvalid & axi_awready & s_axi_awvalid; 

    //inner signal connect
    assign s_axi_awready = axi_awready;
    assign s_axi_wready = axi_wready;
    assign s_axi_bresp = axi_bresp;
    assign s_axi_bvalid = axi_bvalid;
    assign s_axi_arready = axi_arready;
    assign s_axi_rdata = axi_rdata;
    assign s_axi_rvalid = axi_rvalid;
    assign s_axi_rresp = 2'b00;

	//---------------------------write address input logic--------------------------------//
	//transmit finish whe s_axi_awvalid=1 axi_awready = 1 s_axi_wvalid = 1
	always @(posedge s_axi_aclk) begin : address_input_proc_
		if(~s_axi_aresentn) begin
			axi_awaddr <= 'b0;
			axi_awready <= 1'b0;
			aw_en <= 1'b1;
		end 
		else begin
			if(aw_en && s_axi_awvalid && (~axi_awready) && (s_axi_wvalid))
			begin
				aw_en <= 1'b0;
			 	axi_awaddr <= s_axi_awaddr;
				axi_awready <= 1'b1;	
			end
			else if(axi_bvalid && s_axi_bready)
			begin
				aw_en <= 1'b1;
			end
			else
			begin
				axi_awready <= 1'b0;
			end
		end
	end
	//-------------------------write data logic------------------------------------//
	always @(posedge s_axi_aclk) begin : write_data_signal_proc_
		if(~s_axi_aresentn) begin
			axi_wready <= 1'b0;
		end 
		else begin
			if(aw_en && s_axi_awvalid && s_axi_wvalid && ~axi_wready)
			begin
				axi_wready <= 1'b1;
			end
			else
			begin
				axi_wready <= 1'b0;
			end
		end
	end
	//------------------------write back response logic--------------------------//
	always @(posedge s_axi_aclk) begin : wr_back_logic_proc_
		if(~s_axi_aresentn) begin
			axi_bresp <= 'b0;
			axi_bvalid <= 1'b0;
		end 
		else begin
			if(s_axi_awvalid & axi_awready & s_axi_wvalid & axi_wready & (~axi_bvalid))
			begin
				axi_bresp <= 'b0;
				axi_bvalid <= 1'b1;
			end
			else
			begin
				axi_bresp <= 'b0;
				axi_bvalid <= 1'b0;
			end
		end
	end
	//-----------------------read address logic---------------------------------//
	always @(posedge s_axi_aclk) begin : read_address_proc_
		if(~s_axi_aresentn) begin
			axi_araddr <= 'b0;
			axi_arready <= 1'b0;
		end else begin
			if(~axi_arready & s_axi_arvalid)begin
				axi_araddr <= s_axi_araddr;
				axi_arready <= 1'b1;
			end
			else
			begin
				axi_arready <= 1'b0;
			end
		end
	end
	//------------------------read data logic--------------------------------//
	always @(posedge s_axi_aclk) begin : read_data_proc_
		if(~s_axi_aresentn) begin
			axi_rdata <= 'b0;
			axi_rvalid <= 1'b0;
		end else begin
			if(axi_arready & s_axi_arvalid & ~axi_rvalid)
			begin
				axi_rvalid <= 1'b1;
				axi_rdata <= reg_data_out;
			end
			else
			begin
				axi_rvalid <= 1'b0;
			end
		end
	end

	//------------------------write register logic-------------------------------//
	integer byte_index;
	integer reg_index;
	always @(posedge s_axi_aclk) begin : register_write_proc_
		if(~s_axi_aresentn) begin
			for(reg_index = 0;reg_index<C_AXI_SLV_REG_NUM;reg_index=reg_index+1)
			begin
				slv_reg[reg_index] <= 'b0;
			end
		end 
		else begin
			if(register_wr_en)
			begin
				for(reg_index = 0;reg_index<C_AXI_SLV_REG_NUM;reg_index=reg_index+1)
				begin
					if(reg_index == (axi_awaddr >> ADDR_SHIFT))
					begin
						for(byte_index = 0;byte_index <= (C_AXI_DATA_WIDTH/8)-1;byte_index = byte_index + 1)
							begin
								if(s_axi_wstrb[byte_index] == 1'b1)
								begin
									slv_reg[reg_index][(byte_index*8)+:8] <= s_axi_wdata[(byte_index*8)+:8];
								end
							end
					end
				end
			end
		end
	end

	//------------------------read register logic-------------------------------//
	always @(*) begin : register_read_proc_
		if(~s_axi_aresentn) begin
			reg_data_out <= 'b0;
		end 
		else begin
			case(axi_araddr >> ADDR_SHIFT)
				'd0: reg_data_out <= slv_reg[0];
				'd1: reg_data_out <= key;
				'd2: reg_data_out <= slv_reg[2];
				'd3: reg_data_out <= slv_reg[3];
				'd4: reg_data_out <= slv_reg[4];
				'd5: reg_data_out <= slv_reg[5];
				'd6: reg_data_out <= slv_reg[6];
				'd7: reg_data_out <= slv_reg[7];
			endcase
		end
	end
endmodule

在逻辑文件中,我们增加了一组输入端口和一组输出端口,分别用来接收按键的电平和驱动LED亮灭;

output wire   [3:0]                           led,
input  wire   [3:0]                           key,

并且我们将第0寄存器的低四位赋值给led端口;

assign led = slv_reg[0][3:0];

在读逻辑中,第二个寄存器读出改为key;

always @(*) begin : register_read_proc_
		if(~s_axi_aresentn) begin
			reg_data_out <= 'b0;
		end 
		else begin
			case(axi_araddr >> ADDR_SHIFT)
				'd0: reg_data_out <= slv_reg[0];
				'd1: reg_data_out <= key;
				'd2: reg_data_out <= slv_reg[2];
				'd3: reg_data_out <= slv_reg[3];
				'd4: reg_data_out <= slv_reg[4];
				'd5: reg_data_out <= slv_reg[5];
				'd6: reg_data_out <= slv_reg[6];
				'd7: reg_data_out <= slv_reg[7];
			endcase
		end
	end

顶层文件

module axi_lite_logic_top#(
	parameter integer     C_AXI_SLV_REG_NUM = 8,
	parameter integer     C_AXI_DATA_WIDTH = 32,
	parameter integer     C_AXI_ADDR_WIDTH = $clog2(C_AXI_SLV_REG_NUM*4)+1
	) (
	output wire   [3:0]                           led,
	input  wire   [3:0]                           key,
	//system signals definition
	input  wire  						 	      S_AXI_ACLK,
	input  wire  						 	  S_AXI_ARESENTN,  
	//write address signals definition	  
	input  wire [C_AXI_ADDR_WIDTH - 1:0] 	    S_AXI_AWADDR,
	input  wire                          	   S_AXI_AWVALID,
	output wire                          	   S_AXI_AWREADY,
	//write data signals definition
	input  wire [C_AXI_DATA_WIDTH - 1:0]   		 S_AXI_WDATA,
	input  wire                            		S_AXI_WVALID,
	output wire                            		S_AXI_WREADY,   
	input  wire [(C_AXI_DATA_WIDTH/8) - 1:0]	 S_AXI_WSTRB,
	//write response signals definition
	output wire [1:0]                            S_AXI_BRESP,
	output wire                                 S_AXI_BVALID,
	input  wire                                 S_AXI_BREADY,
	//read address signals definition
	input  wire [C_AXI_ADDR_WIDTH - 1:0] 	    S_AXI_ARADDR,
	input  wire                         	   S_AXI_ARVALID,
	output wire                                S_AXI_ARREADY,
	//read data signals definition
	output wire [C_AXI_DATA_WIDTH - 1:0]   		 S_AXI_RDATA,
	output wire                            		S_AXI_RVALID,
	input  wire                                 S_AXI_RREADY,
	//read response signals definition
	output wire                                  S_AXI_RRESP,
	//protect signals definition
	input  wire                                 S_AXI_ARPROT
);

	axi_lite_logic#(

	//axi-lite parameter definition start here
	//data width / address width
	.C_AXI_SLV_REG_NUM (C_AXI_SLV_REG_NUM),
	.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
	.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH)
	)axi_lite_logic_inist0
(
	.led(led),
	.key(key),
	//system signals definition
	.s_axi_aclk(S_AXI_ACLK),
	.s_axi_aresentn(S_AXI_ARESENTN),  
	//write address signals definition	  
	.s_axi_awaddr(S_AXI_AWADDR),
	.s_axi_awvalid(S_AXI_AWVALID),
	.s_axi_awready(S_AXI_AWREADY),
	//write data signals definition
	.s_axi_wdata(S_AXI_WDATA),
	.s_axi_wvalid(S_AXI_WVALID),
	.s_axi_wready(S_AXI_WREADY),   
	.s_axi_wstrb(S_AXI_WSTRB),
	//write response signals definition
	.s_axi_bresp(S_AXI_BRESP),
	.s_axi_bvalid(S_AXI_BVALID),
	.s_axi_bready(S_AXI_BREADY),
	//read address signals definition
	.s_axi_araddr(S_AXI_ARADDR),
	.s_axi_arvalid(S_AXI_ARVALID),
	.s_axi_arready(S_AXI_ARREADY),
	//read data signals definition
	.s_axi_rdata(S_AXI_RDATA),
	.s_axi_rvalid(S_AXI_RVALID),
	.s_axi_rready(S_AXI_RREADY),
	//read response signals definition
	.s_axi_rresp(S_AXI_RRESP),
	//protect signals definition
	.s_axi_arprot(S_AXI_ARPROT)
);

endmodule

三、IP核封装

1.我们将修改后的文件添加到工程中来,然后点击Tools->creat and package new IPAMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第1张图片AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第2张图片2.绑定文件
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第3张图片
3.最后完成封装
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第4张图片


四、SOC搭建

1.新建一个Block Design;点击Setting->IP->Repository->+
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第5张图片我们找到刚刚封装的IP路径,把它添加到工程里面来;

2.添加测试IP,点击Block Design中的+号,找到测试IP,并添加进来
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第6张图片AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第7张图片3.添加AXI_Uart_Lite IP核;
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第8张图片4.添加microblaze软核,并点击Run Block Automation
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第9张图片选择Memory大小为128KB
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第10张图片5.再点击Run connection Automation,Vivado会自动完成连线
在这里插入图片描述6.这里需要注意reset复位信号和sys_clock系统时钟信号;复位信号选择的按键若常态低电平,则需要连一个反相器,sys_clock必须是FPGA的时钟引脚(这里因为我有板载文件,所以直接配置好了)
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第11张图片
7.整体SOC图AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第12张图片8.选中BD文件右击,选择Create HDL Wrapper,并将生成后的文件设置为顶层
在这里插入图片描述AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第13张图片在这里插入图片描述


五、引脚约束

新建一个约束文件
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第14张图片内容如下:

#led0   
set_property PACKAGE_PIN M14 [get_ports led[0]]
set_property IOSTANDARD LVCMOS33 [get_ports led[0]]
#led1   
set_property PACKAGE_PIN M15 [get_ports led[1]]
set_property IOSTANDARD LVCMOS33 [get_ports led[1]]
#led2   
set_property PACKAGE_PIN G14 [get_ports led[2]]
set_property IOSTANDARD LVCMOS33 [get_ports led[2]]
#led3   
set_property PACKAGE_PIN D18 [get_ports led[3]]
set_property IOSTANDARD LVCMOS33 [get_ports led[3]]

#key0   
set_property PACKAGE_PIN G15 [get_ports key[0]]
set_property IOSTANDARD LVCMOS33 [get_ports key[0]]
#key1   
set_property PACKAGE_PIN P15 [get_ports key[1]]
set_property IOSTANDARD LVCMOS33 [get_ports key[1]]
#key2   
set_property PACKAGE_PIN W13 [get_ports key[2]]
set_property IOSTANDARD LVCMOS33 [get_ports key[2]]
#key3   
set_property PACKAGE_PIN T16 [get_ports key[3]]
set_property IOSTANDARD LVCMOS33 [get_ports key[3]]

#reset_rtl BTN3
set_property PACKAGE_PIN Y16 [get_ports reset_rtl]
set_property IOSTANDARD LVCMOS33 [get_ports reset_rtl]


#The definition of  uart_rx_din
#JD2_N
set_property PACKAGE_PIN R14 [get_ports uart_rx_din]
set_property IOSTANDARD LVCMOS33 [get_ports uart_rx_din]
#The definition of  uart_tx_dout
#JD2_P
set_property PACKAGE_PIN P14 [get_ports uart_tx_dout]
set_property IOSTANDARD LVCMOS33 [get_ports uart_tx_dout]

保存后点击Generate Bitstream
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第15张图片

六、软件设计

点击File->Export->Export Hardware,导出硬件文件
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第16张图片然后点击File-> Launch SDK,新建一个空工程,在新工程中创建main.c文件;
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第17张图片我们还需要将user文件夹手动拷贝到目录下AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第18张图片然后编写main.c文件内容如下:

/*
 * main.c
 *
 *  Created on: 2023年3月19日
 *      Author: 93793
 */

#include "../user/headfile.h"

#define  BASE_ADDR 		0x44A00000


int main()
{
	AXI_Uart_Lite_reset(AXI_UART_Lite_0);
	AXI_Uart_Lite_Set_Baunds(AXI_UART_Lite_0,9600);
	AXI_Uart_Lite_enable(AXI_UART_Lite_0);

	AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"--------AXI TEST START!----------\n");

	Xil_Out32(BASE_ADDR|0x00,0x01);
	usleep(500000);
	Xil_Out32(BASE_ADDR|0x00,0x03);
	usleep(500000);
	Xil_Out32(BASE_ADDR|0x00,0x07);
	usleep(500000);
	Xil_Out32(BASE_ADDR|0x00,0x0f);

	Xil_Out32(BASE_ADDR|0x08,0xCC);
	if(Xil_In32(BASE_ADDR|0x08) == 0xCC)
	{
		AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"PASS!\n");
	}
	else
	{
		AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"FAIL!\n");
		while(1);
	}


	while(1)
	{
		unsigned char key = Xil_In32(BASE_ADDR|0x04);
		if(key&0x01)
		{
			AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"B0、");
		}
		if(key&0x02)
		{
			AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"B1、");
		}
		if(key&0x04)
		{
			AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"B2、");
		}
		if(key&0x08)
		{
			AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"B3、");
		}
		if(key&0xff)
		{
			AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"Down\n");
		}
		if(key == 0x0f)
		{
			Xil_Out32(BASE_ADDR|0x00,0x00);
			break;
		}
		sleep(1);
	}

	AXI_Uart_Lite_send_str(AXI_UART_Lite_0,"--------AXI TEST FINISH!----------\n");
	return 0;
}

板级验证过程

  1. 通过AXI_Lite总线,将地址为0x00的寄存器(id = 0)的第0~4比特位依次置位;对应的LED灯将依次亮起;
  2. 通过AXI_Lite总线,向地址为0x08的寄存器(id = 2)写入一个非0数,并读出判断读出和写入的数是否相等;
  3. 通过AXI_Lite总线,持续读出地址为0x04的寄存器(id = 1),判断按键的值,当全部按下时,熄灭所有LED;

七、测试过程

测试物理连接如下将USB转TTL连接电脑,配置SDK TerminalAMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第19张图片
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第20张图片
先下载硬件Xilinx -> Program FPGA

AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第21张图片右击工程,选择run as -> Launch on hardware下载程序AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第22张图片
下载程序等待亮灯
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第23张图片此时依次波动开关
AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第24张图片最终在终端打印的数据为

AMBA协议AXI-Lite(AXI-Lite从机代码板级验证)_第25张图片测试通过!


总结

  本篇基于AXI_Lite从机接口的模板文件,设计一验证SOC,最终完成了整个AXI_Lite从机接口的测试;

  工程源码:https://gitee.com/gewenjie_host/axi_lite_test

你可能感兴趣的:(AMBA协议,fpga开发)