Data2mem and BRAM
This week I have started working on initializing the block ram (BRAM) with some content. There are so many ways to initialize your memory with. You can for example directly initialize it form your HDL code. But this way is inefficient and tiresome as you have to keep changing your code whenever a change needed. Luckily Xilinix provides a tool that can be used to initialize your RAM easily. This tool is called Data2mem. By using this tool the final bit stream can be updated with your desired memory content. In the project I’m working in we need to initialize the BRAM with certain processor instructions. These CPU instructions come from a compiled C++ user code, therefore using the data2mem tool is a necessity.
By referring to AESTE previous intern “Mostafa” blog entry it was quite easy for me to get my hand dirty with this tool. You can refer to his blog from here.
In this blog entry I’ll try to shed the light on things that he didn’t go through in details, problems I faced while I was playing with this tools and so on.
Inputs to data2mem
This tool basically takes three input files: the old bits stream file, the mem file or the elf file and finally .bmm file (block ram memory map) and the output of this tool is simply a new bitstreams with initialized BRAMs.
The old bit stream was a result of running certain Xilinx tools (xst,ngdbuid,…, bitgen). The second file is .bmm file. It took me a while to understand how to formulate this file. And I got so many errors before finally manage to get it right. This file describes how the individual block RAM map to contiguous memory address. You can refer to data2mem datasheet to know more information about it.
The first mistake I fell into while I was creating this file was when I had to declare the address space [start address and the end address]. The start address for my BRAM was simply 0x0000000 but when it came to the end address I thought that since our instruction BRAMs will have 32 bits width and 4096 or 2^12 depth so our address end will be 0x00000fff but this kept giving me errors. So latter by doing quick research I found out that this was not the proper way. Apparently you should calculate your total memory in byte first which in this case 16kbyte is and then use 16k as the depth of your memory… So the end address will be 0x0000003fff in this case.
Getting the names of the block ram primitive was troublesome as well, as I had to look at the output of the xst tools to get them. Plus the names of the Block ram primitive I had to get their location in the chip, for this I used the Xilinx XDL tool to transform the output of the place and route file .ncd to a readable text file. Later I discovered that there is an easy way to get the location without the need of reading .ncd file. Just feeding the ngdbuild with the .bmm file without the locations information and then when the bitgen tool runs, it will split out a new .bmm file with the locations information.
The third file could be either .mem or elf file. Although in our case we will be using the elf file but at the beginning I ran the tool using simple mem file just to make sure that I understand the whole process. The .mem file contains only the memory addresses and the information you want those address to contain. Running now the data2mem command I finally manage to get the new bitstream with the block ram memory initialized with the data written in the .mem file.
From dealing with data2mem, I’m really unsure about how this .bmm file would be created automatically later in the project because this file requires some information such as the place of the IRAM blocks and their names.
Do we have always to refer to some tool to see how the xst infers those rams primitive or will the names be constant? And can we make the tools to place the rams in certain places so their location will be constant? And what would be the case when the size of RAM changes meaning the number of rams primitive used would be change as well? Or is there a way to create this file automatically without the need for someone to interfere?!?!
I think I should find answers to those questions soon !
So after I played with the data2mem tool using simple .mem file now I had to replace it with elf file. First I had to write a simple C++ code that would be compiled. I found the gpio drivers and I wrote simple C++ code using the gpio class. I know this might sound so stupid but I was compiling it first using g++ and I kept getting error that the elf file is corrupted or something when I tried to use it with data2mem later I discovered that each compiler is used to produce certain binary file that compatible with certain microprocessor architecture. So AEMB should have its own compiler. And then I used the MICROBLAZE compiler as AEMB is binary compatible with it. I compiled the code and ran the data2mem tool and it worked.
But for now we don’t have a data memory to store the data of the program on it . So I think I should get back to my top module to include the 16kbyte data memory in order to be able to proceed.
P.S: I’m not really sure yet how our code will be compiled (using which compiler). Hopefully by next week I’ll have more details on this. And till that time… Stay well