cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
cerilet
Explorer
Explorer
5,587 Views
Registered: ‎08-26-2014

I am not being able to write into DDR or OCM using a Vivado HLS IP

Hello,

 

I have been unable to perform data transfers to either the DDR or the OCM using a custom IP generated with Vivado HLS. This is the test IP I am using (AXI Master for the data transfer and AXI-Lite to control the IP):

 

 

#define MAX_TRANSFER_SIZE 200
const int max_depth = MAX_TRANSFER_SIZE;

int ddr_test(unsigned char value, volatile unsigned char *addr, int size)
{
#pragma HLS INTERFACE s_axilite port=return bundle=CTRL_BUS
#pragma HLS INTERFACE s_axilite port=value bundle=CTRL_BUS
#pragma HLS INTERFACE s_axilite port=size bundle=CTRL_BUS
#pragma HLS INTERFACE m_axi depth=max_depth port=addr offset=slave bundle=MASTER_BUS

	if(size<MAX_TRANSFER_SIZE)
	{
		for(int idxMem = 0; idxMem < size; idxMem++)
		{
#pragma HLS PIPELINE
			addr[idxMem] = value;
} return 0; } else { return -1; } }

 

I generate the IP and then I open Vivado and create this hardware design:

 

AXI_Master_ACP.png

 

And the address map is left like this:

 

AXI_Master_ACP addresses.png

 

Then, I create the HLD wrapper, generate the bitstream and launch SDK, where I run this code.

 

 

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h"
#include "xddr_test.h"
#include "xil_cache.h"
#include "xil_mmu.h"

#define SIZE_ARRAY 100
#define MEM_BASE_ADDR 0x00100000

/* Write to memory location or register */
#define X_mWriteReg(BASE_ADDRESS, RegOffset, data) \
           *(unsigned int *)(BASE_ADDRESS + RegOffset) = ((unsigned int) data);
/* Read from memory location or register */
#define X_mReadReg(BASE_ADDRESS, RegOffset) \
           *(unsigned int *)(BASE_ADDRESS + RegOffset);

XDdr_test doDdr_test;
XDdr_test_Config *doDdr_test_cfg;

unsigned char *someMem = (unsigned char *)MEM_BASE_ADDR;

int main()
{
	int status = 0, error = 0, value = 0;
	AxiTimerHelper timer;
	double timeWrite = 0, timeRead = 0;

	init_platform();

	doDdr_test_cfg = XDdr_test_LookupConfig(XPAR_DDR_TEST_0_DEVICE_ID);
	if(doDdr_test_cfg)
	{
		status = XDdr_test_CfgInitialize(&doDdr_test,doDdr_test_cfg);
		if(status != XST_SUCCESS)
			printf("Failed to initialize\n");
	}

	// Configuring MMU (Memory Management Unit)
	/* Shareable=b1
	 * TEX=b100: cached memory, outer policy non cachable
	 * AP=b11: full access,
	 * Domain=b0,
	 * C=b1, B=b1: inner policy write-back and no write-allocate*/
	Xil_SetTlbAttributes(0x00000000,0x14c0e);

	// OCM_CFG[3:0] = maps OCM RAM in High Addresses divided in 64K blocks
	// (0 = low address, 1 = high address)
	value = X_mReadReg(0xF8000910,0x0);
	printf("OCM_CFG (0x%x) = 0x%x\n",0xF8000910,value);
	// SCU_CONTROL_REGISTER. b1 = 1: Addres filtering on. b0 = 1: SCU enable
	value = X_mReadReg(0xF8F00000,0x0);
	printf("SCU_CONTROL_REGISTER (0x%x) = 0x%x\n",0xF8F00000,value);
	// mpcore filtering_start_address_register[31:20] = start address for use
	// with MP1 in a 2-master port configuration when address filtering is enabled
	value = X_mReadReg(0xF8F00040,0x0);
	printf("Filt_start_addr (0x%x) = 0x%x\n",0xF8F00040,value);
	// mpcore filtering_end_address_register[31:20] = end address for use
	// with MP1 in a 2-master port configuration when address filtering is enabled
	value = X_mReadReg(0xF8F00044,0x0);
	printf("Filt_end_addr (0x%x) = 0x%x\n",0xF8F00044,value);

	for(int idx=0;idx<SIZE_ARRAY;idx++)
		someMem[idx] = 0;

	// Configure the AXI Master to addres MEM_BASE_ADDR, value 0x55 and size 100
	XDdr_test_Set_addr(&doDdr_test,MEM_BASE_ADDR);
	XDdr_test_Set_size(&doDdr_test,SIZE_ARRAY);
	XDdr_test_Set_value_r(&doDdr_test,0x55);

	// Start and wait until it's done
	XDdr_test_Start(&doDdr_test);
	while(!XDdr_test_IsDone(&doDdr_test));
	error = XDdr_test_Get_return(&doDdr_test);
	printf("Test Axi master result: %d\n",error);

	// print results
	for(int idx=0;idx<SIZE_ARRAY;idx++)
		printf("Value someMem[%d] = %d\n",idx,someMem[idx]);

	printf("Test done\n");

	cleanup_platform();
	return 0;
}

 

I tried to program different regions of the memory (OCM and DDR) but I am always getting zeros, meaning that the IP is not writing to the specified address.

 

I tried to look for a solution and implement different versions of the code but I am always getting zeros. Actually, I could not find a good explanation of how to configure the SCU and translate tables. Does anyone know where it is properly explained? In the UG585 is not very clear for those who are not very familiar with this kind of processors.

 

Thanks for your help!

0 Kudos
3 Replies
muzaffer
Teacher
Teacher
5,581 Views
Registered: ‎03-31-2012

@cerilet did you go through simulation to verify that your master is generating the m_axi write transactions ? The second step would be to check if you are setting cache coherency settings on the ACP interface properly. If this is not done properly, the cpu/cache snoop doesn't notice that the ddr has been written to. One other thing is to replace the regular assignment with a memcpy. I hope it doesn't matter but that's what I have in my master which  works nicely (through an HP and with some linux kernel support for coherency)

- Please mark the Answer as "Accept as solution" if information provided is helpful.
Give Kudos to a post which you think is helpful and reply oriented.
cerilet
Explorer
Explorer
5,522 Views
Registered: ‎08-26-2014

Hi @muzaffer,

 

I have actually activated the S AXI ACP interface, tied off the AxUSER signals to high, and allowed access to high OCM in the processing_system7 in Vivado.

 

One thing I am not very familiar with is the MMU table. I want an space in the DDR and another in the OCM which both the CPU and the IP could write and read variables maintaining coherency. If I set the OCM high, setting the MMU table to this, I should get the lower part of the memory cached, shouldn't I?

 

 

/* Shareable=b1 TEX=b100 AP=b11, Domain=b0, Cacheable=b1, Bufferable=b1 */ 
Xil_SetTlbAttributes(0x00000000,0x14c0e);

However, I do not really get what all these parameters mean:

  • Shareable: translation for shareable memory. I suppose yes.
  • Access Permission  (AP): I suppose b11 = full access
  • Memory Attributes (TEX), Cacheable (C) and Bufferable (B): I have seen in many examples that it should be TEX = b100, C = b1 and B = b1.
  • Domains: I have seen that in most examples it is set to b0

But well, I actually by now I only need the proper commands to make the lower 4KB (DDR) and higher 4KB (OCM) coherent.

 

The other registers involved are set like this (I guess they are correct):

 

OCM_CFG (0xf8000910) = 0x1f
SCU_CONTROL_REGISTER (0xf8f00000) = 0x3
Filt_start_addr (0xf8f00040) = 0x0
Filt_end_addr (0xf8f00044) = 0xfff00000

 

Any help would be much appreciated.

0 Kudos
muzaffer
Teacher
Teacher
5,503 Views
Registered: ‎03-31-2012

@cerilet I am afraid I don't have much clue about mmu programming. We use linux on our system so I didn't get a change to fiddle with it. One thing I can say is that through the FSBL the size of the memory is known and how you want OCM to be mapped. If you enable caches, I am pretty sure these two blocks of memory will be coherent by design, i don't think you need to do anything else.

- Please mark the Answer as "Accept as solution" if information provided is helpful.
Give Kudos to a post which you think is helpful and reply oriented.
0 Kudos