Block RAM是PL部分的存储器阵列,为了与DRAM(分布式RAM)区分开,所以叫Block RAM。
ZYNQ的每一个BRAM大小为36KB,7020的BRAM有140个(4.9M),7030有265个(9.3M),7045有545个(19.2M)。每一个BRAM都有两个共享数据的独立端口,当然是可以配置的,可用于片内数据缓存、FIFO缓冲。
使用BRAM进行PS-PL或者反向进行数据传输,是PS与PL进行互联的一种方法,实现较为简单。但是在实现双端通信之前,我们首先需要熟悉每个不同部分对应的通信方式。
今天我们主要研究的是PS端写入、读取PL端的BRAM。
在本例中,我们使用下图的第二种连接方式,虽然BLOCK RAM为双口RAM,但是我们仅使用其中一端。在图中可以看到,BRAM模块的端口B为OPEN状态。
为了使用PS端调用PL端的BRAM,我们需要使用几个重要的IP核。
其block design如下。
PS核心方面打开UART1作为debug Serial。
在Block Memory Generator方面,将Memory类型设置为单口RAM。在other options中关闭Safety Circuit
在Block RAM Controller方面,设置如下:
将BRAM interface数量调整为1。因为我们使用的是一个单口RAM。
所有IP添加完成后,执行自动连接,并重新生成layout,即可得到一个清爽简洁的BD。
打开Address Editor,可以在这里对BRAM的起始地址、偏移、名称、范围等做手动修改。
接下来综合,并生成比特流文件,导出hardware,启动SDK。
我的代码如下:
/******************************************************************************
*
* Copyright (C) 2018 - 2020 TerayTech, Inc. All rights reserved.
*
******************************************************************************/
/*
* helloworld.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/
#include
#include "xil_io.h"
#include "platform.h"
#include "xil_printf.h"
int main(void)
{
unsigned int chara;
chara = 0;
printf("Welcome To TerayTech Enterprise 2020 XILINX FPGA BRAM Test DEMO\r\n");
//Write 200 words with Xil_Out8
for(int i = 0;i < 200; i++){
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + i, chara);
chara++;
}
//read 100 words with Xil_In16
for(int i = 0;i < 100; i++){
chara = Xil_In16(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + (i*2));
int ad = XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + (i*2);
printf("Address:0x%08x", ad);
printf(" Word%d = 0x%04x\n\r", i, chara);
}
return(0);
}
void tt_rw_test(){
//Write Progress
int word1,word2,word3,word4;
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 0, 0xAB);//Write first word, length 4 byte
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 1, 0xFF);
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 2, 0x34);
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 3, 0x8C);
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 4, 0xEF);//第二个字,4字节
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 5, 0xBE);
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 6, 0xAD);
Xil_Out8(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 7, 0xDE);
Xil_Out16(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 0x10, 0x1209);//第三个字,4字节
Xil_Out16(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 0x12, 0xFE31);
Xil_Out16(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 0x14, 0x6587);//第四个字,4字节
Xil_Out16(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 0x16, 0xAAAA);
Xil_Out32(0xE000A244, 0x0AAA); //第5个字,4字节
word1 = Xil_In32(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR);
word2 = Xil_In32(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 8);
word3 = Xil_In32(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR + 0x10);
word4 = Xil_In32(0xE000A244);
printf("Word1 = 0x%08x\n\r", word1);
printf("Word2 = 0x%08x\n\r", word2);
printf("Word3 = 0x%08x\n\r", word3);
printf("Word4 = 0x%08x\n\r", word4);
}
其运行结果如下:
Welcome To TerayTech Enterprise 2020 Xilinx FPGA BRAM Test DEMO
Address:0x40000000 Word0 = 0x0100
Address:0x40000002 Word1 = 0x0302
Address:0x40000004 Word2 = 0x0504
Address:0x40000006 Word3 = 0x0706
Address:0x40000008 Word4 = 0x0908
Address:0x4000000a Word5 = 0x0b0a
Address:0x4000000c Word6 = 0x0d0c
Address:0x4000000e Word7 = 0x0f0e
Address:0x40000010 Word8 = 0x1110
Address:0x40000012 Word9 = 0x1312
Address:0x40000014 Word10 = 0x1514
Address:0x40000016 Word11 = 0x1716
Address:0x40000018 Word12 = 0x1918
Address:0x4000001a Word13 = 0x1b1a
Address:0x4000001c Word14 = 0x1d1c
Address:0x4000001e Word15 = 0x1f1e
Address:0x40000020 Word16 = 0x2120
......
可以观察到,其通过从指定地址读取并返回从该地址读取的16位值,该值为我们刚才分两次写入的数据。
00地址的数据为00,01地址的数据为01,故一次性读取16位即为00-01地址的数据,随后地址偏移为2。
打开Xil_io.h,可以看到相关函数,注释清晰较容易理解含义。
/*****************************************************************************/
/**
*
* @brief Performs an input operation for a memory location by reading
* from the specified address and returning the 8 bit Value read from
* that address.
*
* @param Addr: contains the address to perform the input operation
*
* @return The 8 bit Value read from the specified input address.
*
******************************************************************************/
static INLINE u8 Xil_In8(UINTPTR Addr)
{
return *(volatile u8 *) Addr;
}
/*****************************************************************************/
/**
*
* @brief Performs an input operation for a memory location by reading from
* the specified address and returning the 16 bit Value read from that
* address.
*
* @param Addr: contains the address to perform the input operation
*
* @return The 16 bit Value read from the specified input address.
*
******************************************************************************/
static INLINE u16 Xil_In16(UINTPTR Addr)
{
return *(volatile u16 *) Addr;
}
至此,对于PS读写PL端BRAM的测试就完成了。