HLS часть 2. BRAM.

Сегодня пример будет про BRAM и HLS, про BRAM было рассказано в предыдущих статьях, сегодня будем расширять знания по этой теме.

HLS. Часть 0.
HLS часть 1 . AXIS.
HLS часть 2. BRAM.

Vivado HLS (High Level Synthesis) — САПР Xilinx, предназначенная для создания цифровых устройств с применением языков высокого уровня C/C++.

Block Memory Generator — используется как элемент оперативного и постоянного хранения информации, данный элемент реализуется на основе блочной памяти FPGA. Запоминающее устройство, генерируемое с помощью настраиваемого модуля Block Memory Generator. Во всех элементах памяти, создаваемых с помощью генератора Block Memory Generator, для каждого порта запоминающего устройства можно задействовать входы управления режимами разрешения/запрета выполнения операций. Ядро Block Memory Generator использует встроенные примитивы Block Memory в FPGA Xilinx, чтобы расширить функциональность и возможности одного примитива для памяти произвольной ширины и глубины. Для сложных алгоритмов, в генераторе блочной памяти, ядро производит оптимизированные решения для обеспечения удобного доступа к памяти для широкого спектра конфигураций. Ядро ​​имеет два полностью независимых порта для доступа к общей памяти. И А, и Порты B имеют интерфейс записи и чтения. В архитектурах UltraScale, Zynq-7000 и 7 серий FPGA каждый из четырех интерфейсов может быть уникально сконфигурирован с различной шириной данных. Для Block Memory Generator вы можете выбрать упрощенную конфигурацию памяти (например, однопортовая память или простая двухпортовая память), чтобы уменьшить использование ресурсов FPGA.

1. Пример работы с BRAM на HLS, в массив b записываем элементы массива а умноженные на 2.

void bram_test(int matrix_a[256], int matrix_b[256]) {

#pragma HLS INTERFACE bram port=matrix_a
#pragma HLS INTERFACE bram port=matrix_b

	for(int i = 0; i < 256; i++){
		matrix_b[i] = matrix_a[i] * 2;
	}
}

2. Конфигурируем имя IP блока.

3. Собираем проект в Xilinx Vivado, так как на скриншоте ниже.

4. Основной код программы, который будет записывать значения в BRAM и вычитывать измененные значения.

/******************************************************************************
*
* Copyright (C) 2010 - 2014 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xbram_example.c
*
* This file contains a self test example using the BRAM driver (XBram).
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date	 Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a sa   05/11/10 Initial release.
* 3.01a sa   13/01/12 Changed XBram_SelfTest(InstancePtr) to
* 			 XBram_SelfTest(InstancePtr,0) as per
*			 new API (CR 639274)
* 4.1   ms   01/23/17 Modified xil_printf statement in main function to
*                     ensure that "Successfully ran" and "Failed" strings are
*                     available in all examples. This is a fix for CR-965028.
*</pre>
*
******************************************************************************/

/***************************** Include Files *********************************/

#include "xparameters.h"
#include "xbram.h"
#include <stdio.h>

/************************** Constant Definitions *****************************/

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define BRAM1_DEVICE_ID		XPAR_BRAM_0_DEVICE_ID
#define BRAM2_DEVICE_ID		XPAR_BRAM_0_DEVICE_ID


/************************** Function Prototypes ******************************/

int Bram1Example(u16 DeviceId);
int Bram2Example(u16 DeviceId);
static void InitializeECC(XBram_Config *ConfigPtr, u32 EffectiveAddr);


/************************** Variable Definitions *****************************/

/*
 * The following are declared globally so they are zeroed and so they are
 * easily accessible from a debugger
 */
XBram Bram1;	/* The Instance of the BRAM Driver */
XBram Bram2;	/* The Instance of the BRAM Driver */


/****************************************************************************/
/**
*
* This function is the main function of the BRAM example.
*
* @param	None.
*
* @return
*		- XST_SUCCESS to indicate success.
*		- XST_FAILURE to indicate failure.
*
* @note		None.
*
*****************************************************************************/
#ifndef TESTAPP_GEN
int main(void)
{
	static int bufRead[256] = {0};
	int Status;

	Status = Bram2Example(BRAM2_DEVICE_ID);
	if (Status != XST_SUCCESS ) {
		xil_printf("Bram Example Failed\r\n");
		return XST_FAILURE;
	}

	Status = Bram1Example(BRAM1_DEVICE_ID);
	if (Status != XST_SUCCESS ) {
		xil_printf("Bram Example Failed\r\n");
		return XST_FAILURE;
	}

    uint32_t i = 0;
	for ( uint32_t Addr = XPAR_BRAM_0_BASEADDR;
	     Addr < XPAR_BRAM_0_BASEADDR + sizeof(bufRead); Addr+=4) {
		XBram_Out32(Addr, i);
//		bufRead[i] = XBram_In32(Addr);
//		xil_printf("%d ", bufRead[i]);
		i++;
	}

    i = 0;
	for ( uint32_t Addr = XPAR_BRAM_1_BASEADDR;
	     Addr < XPAR_BRAM_1_BASEADDR + sizeof(bufRead); Addr+=4) {
//		XBram_Out32(Addr, i);
		bufRead[i] = XBram_In32(Addr);
		xil_printf("%d ", bufRead[i]);
		i++;
	}

	xil_printf("Successfully ran Bram Example\r\n");
	return XST_SUCCESS;
}
#endif

/*****************************************************************************/
/**
*
* This is the entry point for the BRAM example.
*
* @param	DeviceId is the XPAR_<BRAM_instance>_DEVICE_ID value from
*		xparameters.h
*
* @return
*		- XST_SUCCESS to indicate success.
*		- XST_FAILURE to indicate failure.
*
* @note		None.
*
******************************************************************************/
int Bram1Example(u16 DeviceId)
{
	int StatusBram1;
	XBram_Config *ConfigPtrBram1;

	/*
	 * Initialize the BRAM driver. If an error occurs then exit
	 */

	/*
	 * Lookup configuration data in the device configuration table.
	 * Use this configuration info down below when initializing this
	 * driver.
	 */
	ConfigPtrBram1 = XBram_LookupConfig(DeviceId);
	if (ConfigPtrBram1 == (XBram_Config *) NULL) {
		return XST_FAILURE;
	}

	StatusBram1 = XBram_CfgInitialize(&Bram1, ConfigPtrBram1,
				     ConfigPtrBram1->CtrlBaseAddress);
	if (StatusBram1 != XST_SUCCESS) {
		return XST_FAILURE;
	}

    InitializeECC(ConfigPtrBram1, ConfigPtrBram1->CtrlBaseAddress);

	return XST_SUCCESS;
}

int Bram2Example(u16 DeviceId)
{
	int StatusBram2;
	XBram_Config *ConfigPtrBram2;

	/*
	 * Initialize the BRAM driver. If an error occurs then exit
	 */

	/*
	 * Lookup configuration data in the device configuration table.
	 * Use this configuration info down below when initializing this
	 * driver.
	 */
	ConfigPtrBram2 = XBram_LookupConfig(DeviceId);
	if (ConfigPtrBram2 == (XBram_Config *) NULL) {
		return XST_FAILURE;
	}

	StatusBram2 = XBram_CfgInitialize(&Bram2, ConfigPtrBram2,
				     ConfigPtrBram2->CtrlBaseAddress);
	if (StatusBram2 != XST_SUCCESS) {
		return XST_FAILURE;
	}

    InitializeECC(ConfigPtrBram2, ConfigPtrBram2->CtrlBaseAddress);

	/*
	 * Execute the BRAM driver selftest.
	 */

	return XST_SUCCESS;
}


/****************************************************************************/
/**
*
* This function ensures that ECC in the BRAM is initialized if no hardware
* initialization is available. The ECC bits are initialized by reading and
* writing data in the memory. This code is not optimized to only read data
* in initialized sections of the BRAM.
*
* @param	ConfigPtr is a reference to a structure containing information
*		about a specific BRAM device.
* @param 	EffectiveAddr is the device base address in the virtual memory
*		address space.
*
* @return
*		None
*
* @note		None.
*
*****************************************************************************/
void InitializeECC(XBram_Config *ConfigPtr, u32 EffectiveAddr)
{
	u32 Addr;
	volatile u32 Data;

	if (ConfigPtr->EccPresent &&
	    ConfigPtr->EccOnOffRegister &&
	    ConfigPtr->EccOnOffResetValue == 0 &&
	    ConfigPtr->WriteAccess != 0) {
		for (Addr = ConfigPtr->MemBaseAddress;
		     Addr < ConfigPtr->MemHighAddress; Addr+=4) {
			Data = XBram_In32(Addr);
			XBram_Out32(Addr, Data);
		}
		XBram_WriteReg(EffectiveAddr, XBRAM_ECC_ON_OFF_OFFSET, 1);
	}
}

5. Результат записи и чтения данных в BRAM.