Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM

PS读写单端BRAM

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缓冲。
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第1张图片
使用BRAM进行PS-PL或者反向进行数据传输,是PS与PL进行互联的一种方法,实现较为简单。但是在实现双端通信之前,我们首先需要熟悉每个不同部分对应的通信方式。
今天我们主要研究的是PS端写入、读取PL端的BRAM。

在本例中,我们使用下图的第二种连接方式,虽然BLOCK RAM为双口RAM,但是我们仅使用其中一端。在图中可以看到,BRAM模块的端口B为OPEN状态。
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第2张图片

为了使用PS端调用PL端的BRAM,我们需要使用几个重要的IP核。

  1. Block RAM Controller
  2. Block Memory Generator

其block design如下。
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第3张图片
PS核心方面打开UART1作为debug Serial。
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第4张图片
在Block Memory Generator方面,将Memory类型设置为单口RAM。在other options中关闭Safety Circuit
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第5张图片
在这里插入图片描述

在Block RAM Controller方面,设置如下:
将BRAM interface数量调整为1。因为我们使用的是一个单口RAM。
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第6张图片
所有IP添加完成后,执行自动连接,并重新生成layout,即可得到一个清爽简洁的BD。
打开Address Editor,可以在这里对BRAM的起始地址、偏移、名称、范围等做手动修改。
Xilinx ZYNQ学习笔记(2)——PS端读写单口BRAM_第7张图片
接下来综合,并生成比特流文件,导出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的测试就完成了。

你可能感兴趣的:(FPGA,fpga,fpga/cpld)