1 实验任务
本实验任务是PS将数据写入BRAM,然后从BRAM中读出数据,并通过串口打印出来;与此同时,PS控制PL从BRAM中读出数据,并通过ILA来观察读出的数据与PS侧串口打印的数据是否一致。
2 系统框图
3 硬件设计
3.1 Block Design
- 添加ZYNQ7 Processing System IP核
- (1)在PS-PL Configuration页面
- 1)勾选FCLK_RESET0_N
- 2)勾选M AXI GP0 interface
- (2)在Peripheral I/O页面
- 1)勾选UART
- 2)正确选择Bank 0和Bank 1的电压
- (3)在Clock Configuration页面
- 1)勾选FCLK_CLK0
- (4)在DDR Configuration页面
- 1)DDR Controller Configuration下,合理配置Memory Type、Memory Part和Bus Width等参数
- (1)在PS-PL Configuration页面
- 添加AXI BRAM Controller IP核
- 添加Block Memory Generator IP核
- 添加带有AXI4-Lite Slave接口的自定义AXI BRAM Read IP核
- 添加System ILA IP核
- 自动连线
3.2 IP核配置
- AXI BRAM Controller IP和Block Memory Generator IP配置
- (1)AXI BRAM Controller作为主设备
- 1)Data Width是可配置的
- 2)Memory Depth是Auto的,由Address Editor中指定的Address Range和Data Width共同决定
- (2)Block Memory Generator作为从设备
- 1)只有Mode和Memory Type可配置
- 2)其余参数都是在验证设计时通过参数传播自动设置的
- (1)AXI BRAM Controller作为主设备
3.3 注意事项
- AXI BRAM Controller和Block Memory Generator地址位宽
- (1)AXI BRAM Controller的S_AXI端口和BRAM_PORT A/B端口的地址位宽由Address Range决定(如下图所示,2^13=8KB)
- (2)Block Memory Generator的BRAM_PORT A/B端口的地址位宽固定为32-bit
3.4 自定义IP核源码
注意:Block Memory Generator在BRAM Controller模式下,其BRAM_PORT A/B端口的addra/addrb地址线上传输的是字节地址(所以,在bram_rd 模块中,数据位宽=32b=4B,地址以4为单位递增)。
`timescale 1ns/1ps
module bram_rd (
//
input wire i_clk,
input wire i_rst_n,
input wire i_bram_rd_ena,
input wire [31:0] i_bram_rd_adr,
input wire [31:0] i_bram_rd_len,
//
output wire o_bram_clk,
output wire o_bram_rst,
output wire o_bram_en,
output wire [ 3:0] o_bram_we,
output wire [31:0] o_bram_addr,
output wire [31:0] o_bram_din,
input wire [31:0] i_bram_dout
);
//***********************************************************************************************
// Constant Functions
//***********************************************************************************************
//***********************************************************************************************
// Parameter Definitions
//***********************************************************************************************
localparam BRAM_RD_IDL = 3'b001;
localparam BRAM_RD_JDG = 3'b010;
localparam BRAM_RD_ACT = 3'b100;
//***********************************************************************************************
// Signal Declarations
//***********************************************************************************************
reg bram_rd_ena_r1;
(* MARK_DEBUG = "TRUE" *) reg bram_rd_ena_r2;
(* MARK_DEBUG = "TRUE" *) reg bram_rd_ena_pos;
reg [31:0] bram_rd_adr_r1;
(* MARK_DEBUG = "TRUE" *) reg [31:0] bram_rd_adr_r2;
reg [31:0] bram_rd_len_r1;
(* MARK_DEBUG = "TRUE" *) reg [31:0] bram_rd_len_r2;
(* MARK_DEBUG = "TRUE" *) reg [ 1:0] flow_cnt;
(* MARK_DEBUG = "TRUE" *) reg bram_en;
(* MARK_DEBUG = "TRUE" *) reg [31:0] bram_addr;
(* MARK_DEBUG = "TRUE" *) reg [31:0] bram_din;
(* MARK_DEBUG = "TRUE" *) reg [31:0] bram_dout;
(* MARK_DEBUG = "TRUE" *) reg [ 2:0] bram_rd_st;
//***********************************************************************************************
// Pipeline Inputs
//***********************************************************************************************
always @ (posedge i_clk or negedge i_rst_n) begin
if (i_rst_n == 1'b0) begin
bram_rd_ena_r1 <= 1'b0;
bram_rd_ena_r2 <= 1'b0;
bram_rd_adr_r1 <= 32'd0;
bram_rd_adr_r2 <= 32'd0;
bram_rd_len_r1 <= 32'd0;
bram_rd_len_r2 <= 32'd0;
end
else begin
bram_rd_ena_r1 <= i_bram_rd_ena;
bram_rd_ena_r2 <= bram_rd_ena_r1;
bram_rd_adr_r1 <= i_bram_rd_adr;
bram_rd_adr_r2 <= bram_rd_adr_r1;
bram_rd_len_r1 <= i_bram_rd_len;
bram_rd_len_r2 <= bram_rd_len_r1;
end
end
always @ (posedge i_clk or negedge i_rst_n) begin
if (i_rst_n == 1'b0)
bram_dout <= 32'd0;
else
bram_dout <= i_bram_dout;
end
//***********************************************************************************************
// Code
//***********************************************************************************************
///=== bram_rd_ena_pos
always @ (posedge i_clk or negedge i_rst_n) begin
if (i_rst_n == 1'b0)
bram_rd_ena_pos <= 1'b0;
else if (bram_rd_ena_r2 == 1'b0 && bram_rd_ena_r1 == 1'b1)
bram_rd_ena_pos <= 1'b1;
else
bram_rd_ena_pos <= 1'b0;
end
///=== bram_rd_st
always @ (posedge i_clk or negedge i_rst_n) begin
if (i_rst_n == 1'b0)
bram_rd_st <= BRAM_RD_IDL;
else begin
case (bram_rd_st)
BRAM_RD_IDL : begin
bram_rd_st <= BRAM_RD_JDG;
end
BRAM_RD_JDG : begin
if (bram_rd_ena_pos == 1'b1)
bram_rd_st <= BRAM_RD_ACT;
else
bram_rd_st <= BRAM_RD_JDG;
end
BRAM_RD_ACT : begin
if((bram_addr - bram_rd_adr_r2) == (bram_rd_len_r2 - 4))
bram_rd_st <= BRAM_RD_IDL;
else
bram_rd_st <= BRAM_RD_ACT;
end
default : begin
bram_rd_st <= BRAM_RD_IDL;
end
endcase
end
end
///=== bram_en
always @ (posedge i_clk or negedge i_rst_n) begin
if (i_rst_n == 1'b0)
bram_en <= 1'b0;
else if(bram_rd_st == BRAM_RD_JDG && bram_rd_ena_pos == 1'b1)
bram_en <= 1'b1;
else if (bram_rd_st == BRAM_RD_ACT && (bram_addr - bram_rd_adr_r2) == (bram_rd_len_r2 - 4))
bram_en <= 1'b0;
else
bram_en <= bram_en;
end
///=== bram_addr
always @ (posedge i_clk or negedge i_rst_n) begin
if (i_rst_n == 1'b0)
bram_addr <= 32'd0;
else if(bram_rd_st == BRAM_RD_JDG && bram_rd_ena_pos == 1'b1)
bram_addr <= bram_rd_adr_r2;
else if(bram_rd_st == BRAM_RD_ACT)
bram_addr <= bram_addr + 4;
else
bram_addr <= 32'd0;
end
//***********************************************************************************************
// Outputs
//***********************************************************************************************
assign o_bram_clk = i_clk;
assign o_bram_rst = 1'b0;
assign o_bram_en = bram_en;
assign o_bram_we = 4'd0;
assign o_bram_addr = bram_addr;
assign o_bram_din = 32'd0;
endmodule
4 软件设计
4.1 注意事项
无。
4.2 工程源码
/***************************** Include Files *********************************/
#include "stdio.h"
#include "xbram_hw.h"
#include "xparameters.h"
#include "axi_bram_rd.h"
/************************** Constant Definitions *****************************/
#define AXI_BRAM_RD_ENA AXI_BRAM_RD_S00_AXI_SLV_REG0_OFFSET
#define AXI_BRAM_RD_ADR AXI_BRAM_RD_S00_AXI_SLV_REG1_OFFSET
#define AXI_BRAM_RD_LEN AXI_BRAM_RD_S00_AXI_SLV_REG2_OFFSET
#define AXI_BRAM_RD_BASEADDR XPAR_AXI_BRAM_RD_0_S00_AXI_BASEADDR
#define AXI_BRAM_CTRL_BASEADDR XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
/*****************************************************************************/
int main()
{
//
u32 TxDataBuffer[1024] = { 0 };
u32 RxDataBuffer[1024] = { 0 };
//
for(int i = 0; i < 1024; i++)
{
TxDataBuffer[i] = 0x400 + i;
}
//
while(1)
{
//
char Ch = 0;
int CmpErrFlag = 0;
//
printf("是否启动BRAM写数据操作:>\n");
scanf(" %c", &Ch);
//
if(Ch == 'c')
{
// PS写BRAM
for(int i = 0; i < 1024; i++)
{
XBram_WriteReg(AXI_BRAM_CTRL_BASEADDR, i * 4, TxDataBuffer[i]);
}
// PS读BRAM
for(int i = 0; i < 1024; i++)
{
RxDataBuffer[i] = XBram_ReadReg(AXI_BRAM_CTRL_BASEADDR, i * 4);
}
// 比较读写数据
for(int i = 0; i < 1024; i++)
{
if(TxDataBuffer[i]!=RxDataBuffer[i])
{
CmpErrFlag = 1;
break;
}
}
if(CmpErrFlag==0)
{
printf("BRAM read and write test succeeded!\n");
}
else
{
printf("BRAM read and write test failed!\n");
}
// PL读BRAM
AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_ADR, 1024);
AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_LEN, 1024);
AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_ENA, 1);
AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_ENA, 0);
}
else
{
break;
}
}
//
return 0;
}